Today in this article, we will see how to achieve File-based logging in Windows Forms Application using .NET Core application.
As we know .NET Core has introduced ILogger as a generic interface for logging purposes. This framework supported interface ILogger can be used across different types of applications like ASP.NET Core API logging, Console App logging or Windows Form app logging using built-in providers.
Today in this article, we will cover below aspects,
- Implement DI in Windows Forms
- Getting started
- DI Container
- NLog Configuration
- Summary
We also discovered that the File-based logging provider is still not available through the .NET Core framework and we need to rely on external solutions.
Microsoft recommends using a third-party logger framework like a Serilog or NLog for other high-end logging requirements like Database or File/Rolling File logging.
Implement DI in Windows Forms
Before we start adding NLog logging in the Windows forms app, we need to understand how to add DI framework in Windows Forms.
As we know , unlike ASP.NET Core the Windows Forms app doesn’t have dependency injection built into the framework but using few approaches like as discussed in the article Using Service provider for DI in Windows Forms App or using Generic HostBuilder for DI in Windows Forms App we can very much achieve the same.
Getting started
Here I am using a Forms/Windows .NET Core 3.1 application.
Please add below Nuget Packages.
PM> Install-Package NLog.Extensions.Logging
PM> Install-Package Microsoft.Extensions.Hosting
DI Container
Please create Generic HosBuilder and register the dependencies that need to injected. These changes can be done in the Main() method.
Class HosBuilder is available through a namespace Microsoft.Extensions.Hosting
I have added my custom BusinessLayer and DataAccessLayer objects below and registered in the container.
var builder = new HostBuilder() .ConfigureServices((hostContext, services) => { services.AddScoped<Form1>(); services.AddScoped<IBusinessLayer, BusinessLayer>(); services.AddSingleton<IDataAccessLayer, CDataAccessLayer>(); });
NLog Configuration
NLog configuration can be enabled as below,
services.AddLogging(option => { option.SetMinimumLevel(LogLevel.Information); option.AddNLog("nlog.config"); });
Here nlog.cofig file contains the log properties and configuration for the logging file.
Sample nlog.config as below,
<?xml version="1.0" encoding="utf-8"?> <configuration> <nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" autoReload="true" internalLogLevel="Info"> <!-- enable asp.net core layout renderers --> <extensions> <add assembly="NLog.Web.AspNetCore"/> </extensions> <!-- the targets to write to --> <targets> <!-- write logs to file --> <target xsi:type="File" name="allfile" fileName="thecodebuzz-${shortdate}.log" layout="${longdate}|${event-properties:item=EventId_Id}|${uppercase:${level}}|${logger}|${message} ${exception:format=tostring}" /> </targets> <!-- rules to map from logger name to target --> <rules> <!--All logs, including from Microsoft--> <logger name="*" minlevel="Trace" writeTo="allfile" /> </rules> </nlog> </configuration>
Here code can be added in the Main() methods as below ,
///Generate Host Builder and Register the Services for DI var builder = new HostBuilder() .ConfigureServices((hostContext, services) => { services.AddScoped<Form1>(); services.AddScoped<IBusinessLayer, BusinessLayer>(); services.AddSingleton<IDataAccessLayer, CDataAccessLayer>(); services.AddLogging(option => { option.SetMinimumLevel(LogLevel.Information); option.AddNLog("nlog.config"); }); }); var host = builder.Build(); using (var serviceScope = host.Services.CreateScope()) { var services = serviceScope.ServiceProvider; try { var form1 = services.GetRequiredService<Form1>(); Application.Run(form1); Console.WriteLine("Success"); } catch (Exception ex) { Console.WriteLine("Error Occured"); } }
Implementation for class ‘Form1’ with DI of Logger and business objects as below.
Let’s run the application and check the log details captured in a file.
That’s all! Happy Coding.
Summary
File logging provider is not yet available through the .NET Core framework. However, NLog helps us enabling logging in a few simple steps and addresses the file-logging requirement easily in .NET Core based Desktop or Windows Forms application.
Please bookmark this page and share it with your friends. Please Subscribe to the blog to receive notifications on freshly published(2024) best practices and guidelines for software design and development.
Please share this article with your friends and subscribe to the blog to get a notification on freshly published best practices of software development.
What’s more annoying than a bug in your code? Not knowing why there’s a bug in your code! I’ve worked in code bases before that have little to no logging, and it’s awful. When an exception is thrown, .NET tells us what and where, including the long chain of method calls (stack trace) all the way back to the origin. To not make a note of that somewhere is a shame.. and a waste of everyone’s time! Some people love debugging. I’m not one of them.
Even when your code is running perfectly, sometimes it’s handy to be able to log informational messages, especially during testing. Or maybe there’s no exception but something still seems «off». How convenient it is to write logs, and see what unexpected paths the system is going down!
Even in a monolithic WinForms app that has no logging, it’s possible to add it — a little at a time. Now if you’re on a team, don’t try to fix the whole app and issue the Guinness book of world records sized PR. It’s not going to garner the praise and admiration of your peers.. or management…. or customers. Just keep telling yourself things like «Rome wasn’t built in a day» and «the road to hell is paved with good intentions». 😂
Configure a tool like NLog, use it in whatever code you’re touching at the moment, and go from there!
Install NLog
There’s different kinds of tools to do this, and you could even roll your own if you’re a glutton for punishment, but NLog is a tried and true library, so we’ll just use that.
Open your solution, go to «Manage NuGet Packages», and search for NLog. You should see a few items. You could just install the first one, but I’d recommend the fourth instead (NLog.Config), which installs NLog, and a sample NLog.config
file to start with, and some helpful intellisense for the config file (that’s the NLog.Schema one).
What’s the NLog.Extensions.Logging one that I glossed over? Something to do with new features in .NET Core and .NET Standard, and probably not something you’re worried about in a WinForms app.
Configure NLog
Everything’s driven off the NLog.config file, so open that up and check it out. You should see some boilerplate stuff, a few links, and intellisense if you hover over the different elements. Pretty exciting. (But then, I spent Friday evening writing this, so my judgement’s probably off.)
There are so many configuration options you can choose from, and you can see them all by visiting those links! And get overwhelmed to your heart’s content. For now though, let’s just focus on writing to a file, which is documented here.
Skip down to the section on «simple logging» and replace everything in the NLog.config file with the contents of that section. That’ll get you up and running quickly, and it’ll write log files to wherever your app is running. Maybe not ideal in production, but you can adjust that later.
- Remove «fileName» and «keepFileOpen».
- Replace «Debug» with «Trace» in «minLevel».
- Skip further down in the docs to «archive old log files» and copy «fileName» and the two lines below it. Paste them into the «target» section.
You should end up with something like this:
<?xml version="1.0" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<targets>
<target name="file" xsi:type="File"
layout="${longdate} ${logger} ${message}${exception:format=ToString}"
fileName="${basedir}/logs/AppLog.${shortdate}.txt"
maxArchiveFiles="4"
archiveAboveSize="10240"
encoding="utf-8" />
</targets>
<rules>
<logger name="*" minlevel="Trace" writeTo="file" />
</rules>
</nlog>
Those lines about archiving aren’t strictly needed for this basic demo, but I think they’re important to call out. You don’t want a log file that grows too large, so this will archive old files. It also hangs on to 4, although maybe you want to hang on to a month, or even several months. But log files from several years ago just aren’t necessary.
Use NLog
To use it, just create a new instance of the logger. Since we didn’t give it a name in the config file, it doesn’t matter what name you specify here — even an empty string works. Then write whatever you want, and check for the file in the «bin» folder where ${basedir}
points to.
That’s it!
A more interesting example
NLog can do a lot more, way more than I could cover here. Before wrapping things up though, let’s try a slightly more interesting example. It’ll probably be easier if you just grab the code, but I made a couple changes in the config file — it logs everything (including trace messages), and the message will include the «level» (info, warning, etc).
<targets>
<target name="file" xsi:type="File"
layout="${longdate}|${level:uppercase=true}|${message} ${exception:format=ToString}${newline}"
fileName="${basedir}/logs/AppLog.txt"
maxArchiveFiles="10"
archiveAboveSize="10240"
archiveFileName="${basedir}/logs/archive/AppLog.{####}.txt"
archiveNumbering="Sequence"
encoding="utf-8" />
</targets>
<rules>
<logger name="app_logger" minlevel="Trace" writeTo="file" />
</rules>
I wrote a little UI that logs a few different types of messages, and you can see the result here. If this is new to you, get the code, play around with it, change it, break it, revert the code.. lol.
The NLog wiki on GitHub is really comprehensive too — hundreds of pages on there covering everything imaginable. And if you’re interested in logging to several targets at once, check this out.
Good luck! Feel free to reach out and let me know how it goes…
Последнее обновление: 31.10.2015
TrackBar
TrackBar представляет собой элемент, который с помощью перемещения ползунка позволяет вводить числовые значения.
Некоторые важные свойства TrackBar:
-
Orientation: задает ориентацию ползунка — расположение по горизонтали или по вертикали
-
TickStyle: задает расположение делений на ползунке
-
TickFrequency: задает частоту делений на ползунке
-
Minimum: минимальное возможное значение на ползунке (по умолчанию 0)
-
Maximum: максимальное возможное значение на ползунке (по умолчанию 10)
-
Value: текущее значение ползунка. Должно находиться между Minimum и Maximum
Свойство TickStyle
может принимать ряд значений:
-
None
: деления отсутствуют -
Both
: деления расположены по обеим сторонам ползунка -
BottomRight
: у вертикального ползунка деления находятся справа, а у горизонтального — снизу -
TopLeft
: у вертикального ползунка деления находятся слева, а у горизонтального — сверху (применяется по умолчанию)
К наиболее важным событиям элемента следует отнести событие Scroll, которое позволяет обработать перемещение
ползунка от одного деления к другому. Что может быть полезно, если нам надо, например, устанавливать соответствующую громкость звука в
зависимости от значения ползунка, либо какике-нибудь другие настройки:
public partial class Form1 : Form { public Form1() { InitializeComponent(); // установка обработчика события Scroll trackBar1.Scroll+=trackBar1_Scroll; } private void trackBar1_Scroll(object sender, EventArgs e) { label1.Text = String.Format("Текущее значение: {0}", trackBar1.Value); } }
Timer
Timer является компонентом для запуска действий, повторяющихся через определенный промежуток времени. Хотя он не является
визуальным элементом, но его аткже можно перетащить с Панели Инструментов на форму:
Наиболее важные свойства и методы таймера:
-
Свойство Enabled: при значении true указывает, что таймер будет запускаться вместе с запуском формы
-
Свойство Interval: указывает интервал в миллисекундах, через который будет срабатывать обработчик события Tick, которое есть у таймера
-
Метод Start(): запускает таймер
-
Метод Stop(): останавливает таймер
Для примера определим простую форму, на которую добавим кнопку и таймер. В файле кода формы определим следующий код:
public partial class Form1 : Form { int koef = 1; public Form1() { InitializeComponent(); this.Width = 400; button1.Width = 40; button1.Left = 40; button1.Text = ""; button1.BackColor = Color.Aqua; timer1.Interval = 500; // 500 миллисекунд timer1.Enabled = true; button1.Click += button1_Click; timer1.Tick += timer1_Tick; } // обработчик события Tick таймера void timer1_Tick(object sender, EventArgs e) { if (button1.Left == (this.Width-button1.Width-10)) { koef=-1; } else if (button1.Left == 0) { koef = 1; } button1.Left += 10 *koef; } // обработчик нажатия на кнопку void button1_Click(object sender, EventArgs e) { if(timer1.Enabled==true) { timer1.Stop(); } else { timer1.Start(); } } }
Здесь в конструкторе формы устанавливаются начальные значения для таймера, кнопки и формы.
Через каждый интервал таймера будет срабатывать обработчик timer1_Tick
, в котором изменяется положение
кнопки по горизонтали с помощью свойства button1.Left
. А с помощью дополнительной переменной koef
можно управлять направлением движения.
Кроме того, с помощью обраотчика нажатия кнопки button1_Click
можно либо остановить таймер (и вместе с ним движение
кнопки), либо опять его запустить.
Индикатор прогресса ProgressBar
Элемент ProgressBar служит для того, чтобы дать пользователю информацию о ходе выполнения какой-либо задачи.
Наиболее важые свойства ProgressBar:
-
Minimum: минимальное возможное значение
-
Maximum: максимальное возможное значение
-
Value: текущее значение элемента
-
Step: шаг, на который изменится значение Value при вызове метода
PerformStep
Для имитации работы прогрессбара поместим на форму таймер и в коде формы определим следующий код:
public partial class Form1 : Form { public Form1() { InitializeComponent(); timer1.Interval = 500; // 500 миллисекунд timer1.Enabled = true; timer1.Tick += timer1_Tick; } // обработчик события Tick таймера void timer1_Tick(object sender, EventArgs e) { progressBar1.PerformStep(); } }
Логирование в современных .NET-приложениях часто недооценивают, хотя именно оно спасает нас, когда всё идет наперекосяк. Помню случай, когда мы неделю искали причину странного поведения микросервиса в продакшне — и только благодаря грамотно настроенным логам удалось поймать редкую гонку условий, возникавшую раз в несколько тысяч запросов.
Основные принципы современного логирования
Эффективное логирование строится на нескольких принципах:
Контекстуальность — логи должны содержать достаточный контекст для понимания ситуации. Запись «Ошибка подключения к базе данных» малоинформативна. Гораздо полезнее знать какое именно подключение, с какими параметрами, при выполнении какой операции и с каким пользователем произошла ошибка.
Структурированность — современный подход к логированию не просто записывает текстовые сообщения, а формирует структурированные данные с метаинформацией, которые потом можно фильтровать, группировать и анализировать.
Избирательность — нет смысла логировать абсолютно все, это создает информационный шум и снижает производительность. Следует четко определять, какая информация действительно важна.
Уровни критичности — разделение логов по уровням позволяет гибко настраивать вывод в зависимости от среды (dev, staging, production) и быстро находить важные сообщения.
Централизация — в распределенных системах логи должны быть собраны в одном месте с возможностью корреляции событий между разными компонентами.
Вывод диалога исключения в лог
Привет! у меня следующий вопрос — возможно ли вывести текст из диалога исключения например в лог? Если можно то как?
Как программно записывать лог в RichTextBox
Как программно записывать совершенные программой действия (лог) в RichTextBox. что-то типа того, как на рисунке: . Посоветуйте, как лучше всего это…
Лог вызовов для unity3d
Есть желание иметь в своем проекте лог вызовов для отладки. Пробовал использовать log4net с patternLayout = "… %M", но скорость подобного…
Regex для лог файла веб-сервера
Есть две строки (которые повторяются 10 000 раз) но дело не в том
//string string1 = @"2010-06-25 20:58:11 fe80::a4a1:7534:68bd:251%10 POST…
Уровни логирования в контексте .NET
Фреймворк .NET предлагает стандартные уровни логирования, которыми стоит руководствоваться. Правильное использование этих уровней значительно облегчает последующий анализ:
Trace — предельно подробные сообщения для диагностики, используемые только в процессе отладки и практически никогда не включаемые в продакшн.
C# | ||
|
Debug — диагностическая информация, полезная разработчикам. Также обычно отключается в производственной среде.
C# | ||
|
Information — штатные события приложения, которые стоит отслеживать даже в продакшне: запуск сервисов, успешное выполнение важных бизнес-операций, плановые действия.
C# | ||
|
Warning — потенциально проблемные ситуации, которые не нарушают работу, но могут привести к ошибкам: приближение к лимитам ресурсов, необработанные ветки кода, устаревшие API.
C# | ||
|
Error — ошибки, которые нарушают текущую операцию, но не весь процесс работы.
C# | ||
|
Critical — критические ошибки, которые могут привести к аварийному завершению работы приложения.
C# | ||
|
Многие команды используют уровни неправильно, злоупотребляя Warning (когда на самом деле ситуация требует Error) или, наоборот, помечая все ошибки как Critical, что вызывает «усталость от алертов» и в конечном итоге снижает эффективность мониторинга.
Встроенные возможности .NET для логирования
Начиная с .NET Core, экосистема получила мощный встроенный механизм логирования — Microsoft.Extensions.Logging. Эта абстракция позволяет единообразно настраивать разные провайдеры логов (консоль, файлы, базы данных) и интегрировать их с DI-контейнером. Базовая настройка выглядит так:
C# | ||
|
Интерфейс ILogger<T>
из этого пространства имен стал стандартом для логирования в .NET. Пример использования в контроллере:
C# | ||
|
Важным преимуществом встроенного механизма логирования является его масштабируемость и расширяемость. Вы можете начать с простой консольной конфигурации, а затем, когда приложение вырастет, добавить более сложные провайдеры без изменения кода логирования.
Ещё одна полезная концепция — категории логов. Когда вы используете ILogger<T>
, имя типа T автоматически становится категорией. Это позволяет фильтровать логи по компонентам системы и устанавливать для них разные уровни детализации.
C# | ||
|
Особенно удобно, что этим можно управлять через конфигурацию в appsettings.json:
JSON | ||
|
Такой подход позволяет динамически менять уровни логирования в продакшне без перезапуска приложения, что бывает неоценимо при расследовании проблем.
Особенности логирования в асинхронных операциях
Асинхронное программирование стало стандартом в .NET, особенно в веб-приложениях и микросервисах. Однако оно создаёт определённые сложности для системы логирования. Основная проблема — сохранение контекста между асинхронными операциями. В многопоточной среде вызовы часто переключаются между разными потоками, что может привести к потере связи между логами, относящимися к одному бизнес-процессу. Представьте: пользователь нажал кнопку, запустив цепочку из десятка асинхронных операций. Как отследить весь этот путь в логах? Решением стал механизм AsyncLocal<T>
и контексты логирования. Вот пример применения этой концепции:
C# | ||
|
В этом примере мы создаём идентификатор корреляции и добавляем его в контекст логирования. Теперь все логи, созданные внутри этого контекста (даже из других потоков), будут содержать один и тот же correlationId, что позволит легко отследить путь обработки запроса.
Для многопоточных приложений также важно убедиться, что ваш логгер поддерживает потокобезопасность. Большинство современных фреймворков логирования в .NET (Serilog, NLog) имеют встроенную поддержку многопоточности, но при создании собственных решений это нужно учитывать.
Контекстное логирование: когда и какую информацию фиксировать
Контекстное логирование — это подход, при котором логи обогащаются дополнительной информацией о контексте выполнения операций. Это позволяет отвечать не только на вопрос «что произошло?», но и «при каких условиях?», «с какими данными?» и «кто инициировал?».
В .NET можно выделить несколько типов контекстной информации:
1. Информация о запросе — HTTP-метод, путь, IP-адрес, User-Agent
2. Информация о пользователе — идентификатор, роль, иногда email или имя
3. Бизнес-контекст — идентификаторы бизнес-сущностей (заказ, клиент, продукт)
4. Технический контекст — версия приложения, имя сервера, окружение
5. Временные характеристики — длительность операции, временные метки
Пример обогащения логов контекстом с помощью Serilog:
C# | ||
|
А вот пример обогащения логов бизнес-контекстом в рамках конкретного метода:
C# | ||
|
Один из интересных приемов — использование логических областей (scopes) для группировки логов. В Microsoft.Extensions.Logging это выглядит так:
C# | ||
|
Этот подход особенно полезен при отладке сложных бизнес-процессов, так как позволяет быстро визуализировать иерархию вызовов и отношения между разными операциями.
Популярные библиотеки и фреймворки
В экосистеме .NET существует несколько зрелых решений для логирования, каждое со своими особенностями и преимуществами. Выбор конкретного инструмента может существенно повлиять на удобство разработки, производительность и возможности мониторинга приложения.
Serilog: мощь структурированного логирования
Serilog стал одним из самых популярных решений благодаря проработанному API и мощной поддержке структурированного логирования. Его главное преимущество — это «sinks» (приемники), позволяющие направлять логи в различные хранилища: от обычных файлов до специализированных систем анализа логов.
Настройка Serilog обычно выглядит так:
C# | ||
|
Главная особенность Serilog — шаблоны сообщений с именованными плейсхолдерами:
C# | ||
|
Эти значения не просто подставляются в строку, но и сохраняются как отдельные свойства в структурированном логе. Позже это позволяет делать поиск по конкретным полям, например, найти все платежи с суммой больше определенного значения. Serilog также предлагает много дополнительных пакетов: десятки разных приемников (от Amazon CloudWatch до Elasticsearch), обогатителей контекста и настраиваемые форматировщики.
NLog: гибкость и производительность
NLog — другой популярный фреймворк, существующий в экосистеме .NET намного дольше других. Его главные преимущества — детальная настройка через конфигурационные файлы и высокая производительность. Типичная настройка NLog через nlog.config:
XML | ||
|
Особенно примечательна возможность настройки сложной маршрутизации логов в NLog. Вы можете создавать правила, отправляющие определённые типы сообщений в разные приёмники в зависимости от категории, уровня или даже содержимого сообщения.
В коде интеграция c ASP.NET Core выглядит следующим образом:
C# | ||
|
NLog, в отличие от Serilog, изначально больше ориентирован на текстовый формат логов, хотя в последних версиях добавлена хорошая поддержка структурированного логирования.
Интересный паттерн использования — комбинация NLog с другими инструментами мониторинга:
C# | ||
|
Парсеры логов могут считывать такие маркеры и автоматически строить метрики производительности даже без специальных APM-решений.
Log4net: проверенный временем стандарт
Log4net — порт классического Java-фреймворка, который всё ещё используется во многих .NET-проектах, особенно legacy-системах. Он был стандартом до появления более современных альтернатив. Несмотря на возраст, log4net предлагает гибкую систему аппендеров (аналог sinks в Serilog), иерархическую систему логгеров и возможность перезагрузки конфигурации во время работы приложения.
Настройка log4net через XML-конфигурацию:
XML | ||
|
Использование log4net в коде:
C# | ||
|
Log4net сегодня не лучший выбор для нового проекта, но для поддержки существующих систем он вполне адекватен. Многие команды успешно мигрируют с log4net на Serilog или NLog, часто это можно сделать с минимальными изменениями в коде благодаря совместимости с Microsoft.Extensions.Logging.
Microsoft.Extensions.Logging: встроенное решение
Как уже упоминалось ранее, в .NET Core и более новых версиях фреймворка Microsoft представила свою абстракцию для логирования. Она не является полноценным фреймворком, скорее это интерфейс, под который можно подключать разные провайдеры, включая Serilog, NLog и другие. Ценность этого подхода в стандартизации — все библиотеки и фреймворки .NET используют этот интерфейс, что упрощает их интеграцию в ваш проект:
C# | ||
|
Интересно, что Microsoft.Extensions.Logging не имеет нативной поддержки структурированного логирования, но может использовать его через провайдеры вроде Serilog:
C# | ||
|
Преимущество Microsoft.Extensions.Logging в том, что вы можете начать с базовой функциональности, а по мере роста проекта подключать более продвинутые провайдеры без изменения кода логирования.
Производительность и бенчмарки
Производительность систем логирования часто недооценивают, но в высоконагруженных приложениях это может стать узким местом. Особенно критичны сценарии, когда приложение генерирует тысячи логов в секунду. Согласно независимым бенчмаркам, NLog обычно показывает наилучшую производительность при синхронном логировании, а Serilog лидирует при асинхронном подходе. Вот примерные показатели из одного из недавних тестов:
NLog (синхронно): ~1.2 млн операций/сек
Serilog (синхронно): ~0.9 млн операций/сек
Log4net: ~0.6 млн операций/сек
Однако эти цифры сильно зависят от конфигурации, типа приёмников и формата логов. Структурированное логирование обычно требует больше ресурсов, чем простое текстовое. При включении асинхронной записи все эти фреймворки могут обрабатывать десятки миллионов сообщений в секунду, перемещая запись на диск в фоновый поток:
C# | ||
|
Для оптимизации производительности логирования существуют дополнительные техники. Например, фильтрация сообщений на ранних этапах:
C# | ||
|
Такой подход помогает избежать лишних операций, когда данный уровень логирования отключен.
Интеграция с облачными сервисами мониторинга
Современные приложения редко существуют в вакууме. Большинство .NET-систем интегрируются с облачными платформами мониторинга для улучшения наблюдаемости. Популярные варианты включают:
- Azure Application Insights
- AWS CloudWatch
- DataDog
- New Relic
- Elasticsearch + Kibana (ELK stack)
- Grafana + Loki
Serilog особенно хорошо подходит для интеграции с облачными сервисами благодаря структурированности логов и наличию готовых приёмников. Например, интеграция с Azure Application Insights:
C# | ||
|
Для ELK-стека, который часто используется в контейнеризированных средах:
C# | ||
|
При отправке логов в облачные сервисы стоит учитывать дополнительные факторы:
1. Буферизация — накапливание логов перед отправкой для уменьшения числа запросов
2. Политика повторных попыток — как поступать при недоступности сервиса
3. Локальный резервный вывод — куда писать логи, если облако недоступно
4. Регулирование трафика — предотвращение чрезмерной нагрузки на сеть
Пример реализации с буферизацией и локальным резервным выводом:
C# | ||
|
Выбор оптимального решения для логирования
Выбор между Serilog, NLog, log4net и другими решениями зависит от множества факторов:
Тип приложения:
Микросервисы и контейнеризированные приложения — Serilog
Монолитные enterprise-приложения — NLog или Serilog
Legacy-системы — log4net или переход на NLog
Требования к производительности:
Критическая производительность — NLog с асинхронными обертками
Высоконагруженные системы с аналитикой логов — Serilog
Стандартные веб-приложения — подходит любой, включая Microsoft.Extensions.Logging
Аналитические возможности:
Продвинутая аналитика и поиск — Serilog с Elasticsearch или Seq
Базовый мониторинг — NLog с построением графиков
Интеграция с APM — любой через Microsoft.Extensions.Logging
Экосистема:
Azure — Microsoft.Extensions.Logging + ApplicationInsights
AWS — Serilog с CloudWatch sink
Kubernetes — Serilog с Elasticsearch или Grafana Loki
Из своей практики могу отметить, что Serilog стал фактическим стандартом в новых .NET-проектах благодаря отличной поддержке структурированного логирования и богатой экосистеме. NLog остается хорошим выбором для высоконагруженных систем с простыми требованиями. Microsoft.Extensions.Logging же лучше всего подходит для стандартных ASP.NET Core приложений без специфических требований.
Критерий, который часто упускают из виду — удобство для команды разработки. Простота конфигурации и понятное API могут существенно уменьшить количество ошибок логирования, особенно в больших командах.
Практический совет: начинайте с Microsoft.Extensions.Logging со стандартными провайдерами, а по мере роста проекта подключайте специализированные решения через соответствующие адаптеры:
C# | ||
|
Такой эволюционный подход позволяет гибко адаптироваться к изменяющимся требованиям без необходимости переписывать код логирования.
Ещё одна рекомендация — использовать абстракцию Microsoft.Extensions.Logging в публичном API вашей библиотеки, даже если внутренне вы применяете другое решение:
C# | ||
|
Это обеспечит совместимость с разными системами логирования у потребителей вашего API.
Существует интересное гибридное решение — использование разных систем логирования для разных целей в одном приложении:
C# | ||
|
Я видел такой подход в высоконагруженных системах, где технические логи требуют максимальной производительности, а бизнес-логи — лучшей структурированности и анализируемости.
Если ваше приложение работает в контейнерной среде вроде Kubernetes, есть дополнительные нюансы — например, все контейнеры в кластере обычно настроены на запись логов в stdout/stderr вместо файлов, а специальные агенты собирают эти логи и отправляют в центральное хранилище:
C# | ||
|
В таком случае важно, чтобы логи были в формате JSON для последующего парсинга и индексации. Популярная инфраструктура логирования в Kubernetes включает Fluentd или Fluent Bit для сбора логов, Elasticsearch для хранения и Kibana для визуализации.
Наконец, не забывайте о безопасности логов — они могут содержать чувствительную информацию. Все современные библиотеки логирования предлагают механизмы маскирования или исключения конфиденциальных данных:
C# | ||
|
Структурированное логирование
Традиционный подход к логированию, основанный на текстовых сообщениях, постепенно уступает место структурированному логированию. Это существенный сдвиг парадигмы — от простых строк текста к набору структурированных данных с богатым контекстом.
Концепция и преимущества структурированного подхода
Структурированное логирование рассматривает каждую запись лога не как простой текст, а как объект с набором свойств. В отличие от обычного текстового сообщения:
C# | ||
|
Структурированный лог представляет собой набор именованных полей:
JSON | ||
|
Такой подход даёт ряд критических преимуществ:
1. Улучшенная аналитика — возможность фильтровать, группировать и агрегировать логи по конкретным полям.
2. Контекстуальность — каждая запись содержит исчерпывающую информацию о событии.
3. Машинная обработка — логи можно эффективно анализировать автоматическими системами.
4. Гибкость представления — один и тот же лог может быть отображен по-разному в зависимости от контекста (как JSON, XML, таблица).
На практике это означает возможность делать запросы типа «покажи все ошибки для клиента CUST-789» или «найди все заказы с ошибкой нехватки товара за последний час» без парсинга текстовых строк. Пример структурированного логирования с Serilog:
C# | ||
|
Обратите внимание на использование {@Order}
вместо {Order}
. Символ @
указывает Serilog, что нужно сериализовать объект order как структурированное свойство, а не просто вызвать его метод ToString().
Реализация с использованием современных инструментов
В .NET экосистеме Serilog является флагманом структурированного логирования, но и другие библиотеки тоже поддерживают этот подход:
Serilog:
C# | ||
|
NLog:
C# | ||
|
Microsoft.Extensions.Logging с Serilog:
C# | ||
|
Важно отметить, что не все приёмники логов одинаково поддерживают структурированный формат. Например, консольный вывод по умолчанию может отображать только текстовое сообщение, игнорируя структуру. Для полноценного использования преимуществ структурированного логирования необходимо использовать специализированные хранилища и инструменты анализа, такие как:
Seq — специализированный сервер для хранения и анализа структурированных логов
Elasticsearch + Kibana — мощный стек для индексации и визуализации
Splunk — enterprise-решение для анализа логов и мониторинга
Application Insights — облачное решение от Microsoft
При этом в промежуточном хранилище (например, файлы) структурированные логи обычно хранятся в JSON-формате:
C# | ||
|
Семантическое логирование: возможности и ограничения
Семантическое логирование — эволюция структурированного подхода, где акцент делается на значении события, а не просто на его структуре. Термин был популяризирован Microsoft с их библиотекой Semantic Logging Application Block (SLAB), хотя сама концепция шире.
Основное отличие семантического подхода — это определение конкретных типов событий, а не просто сообщений с контекстом:
C# | ||
|
Где LogUserLoggedIn
— специализированный метод для конкретного типа события:
C# | ||
|
Преимущество такого подхода в том, что типы событий становятся частью вашего API. Это обеспечивает лучшую расширяемость, консистентность и позволяет инструментам строить более точные метрики. Однако у семантического подхода есть и ограничения:
- Требуется больше начального кодирования для определения всех типов событий.
- Может усложнить поддержку при частых изменениях в требованиях к логированию.
- Нужна дисциплина со стороны команды, чтобы использовать специализированные методы, а не просто вызывать logger.Info().
В практических реализациях часто используется гибридный подход — определяются специализированные методы для критически важных и часто используемых событий, но при этом сохраняется возможность использовать общие методы логирования для менее формализованных случаев.
Примеры эффективных паттернов структурированного логирования
В процессе работы с многими проектами сформировались несколько эффективных паттернов структурированного логирования, которые стоит применять в своих системах:
1. Контексты выполнения для группировки связанных логов:
C# | ||
|
2. Выделенные объекты метрик для стандартизации:
C# | ||
|
3. Шаблоны нестандартных операций с атрибутами:
C# | ||
|
Реализация такого логирования через middleware:
C# | ||
|
4. Разметка потенциально чувствительных данных:
C# | ||
|
5. Вложенные объекты с контролем глубины:
C# | ||
|
Самым важным аспектом структурированного логирования является последовательность и договорённость в команде. Целесообразно создать набор соглашений или даже внутреннюю библиотеку которая стандартизирует подход к логированию во всех компонентах системы:
C# | ||
|
Такой унифицированный подход позволяет создавать автоматизированные дашборды, системы алертинга и отчёты на основе логов без дополнительной обработки данных.
Практическая реализация и лучшие практики
Здесь мы рассмотрим примеры настройки и распространённые антипаттерны, которых следует избегать.
Конфигурирование многоуровневого логирования
Правильное конфигурирование логирования может существенно упростить как разработку, так и последующую эксплуатацию приложения. Рассмотрим подробно, как создать гибкую и масштабируемую конфигурацию для разных окружений.
Один из самых эффективных подходов — использовать комбинацию нескольких приёмников с разными уровнями детализации:
C# | ||
|
Важно различать конфигурацию для разных окружений. В ASP.NET Core это можно реализовать так:
C# | ||
|
Конфигурация через appsettings.json позволяет менять настройки логирования без перекомпиляции:
JSON | ||
|
Интересный приём, который я часто использую в продакшн-системах — динамическое изменение уровня логирования через API:
C# | ||
|
Такой подход позволяет временно увеличить детализацию логирования при расследовании проблем без необходимости перезапуска приложения.
Обработка исключений и контекст ошибок
Одна из главных целей логирования — отслеживание и диагностика ошибок. Недостаточно просто записать факт исключения, важно сохранить максимум контекста:
C# | ||
|
Заметьте использование паттерна when
для избирательного логирования определённых типов исключений. Это может быть особенно полезно для игнорирования ожидаемых исключений:
C# | ||
|
Один из наиболее полезных паттернов — глобальная обработка необработанных исключений для аварийного логирования:
C# | ||
|
Оптимизация производительности логирования
При высокой нагрузке логирование может стать узким местом. Вот несколько приёмов оптимизации:
1. Асинхронная запись логов — не блокирует основной поток выполнения:
C# | ||
|
2. Буферизация — накапливает сообщения и записывает их батчами:
C# | ||
|
3. Проверка уровня перед формированием сообщений — экономит на создании строк:
C# | ||
|
4. Оптимизация параметров в сообщениях — правильное использование интерполяции:
C# | ||
|
Также важно соблюдать баланс между информативностью и объёмом данных:
C# | ||
|
Для оценки производительности логирования можно использовать бенчмарки:
C# | ||
|
В результатах таких тестов часто обнаруживаются неочевидные узкие места. Например, логирование в JSON может быть значительно медленнее текстового формата, а консольный вывод намного медленнее файлового.
Типичные ошибки при настройке логирования
За годы работы с .NET-проектами я наблюдал несколько типичных ошибок, которые регулярно повторяются в разных командах:
1. Логирование чувствительных данных — персональной информации, паролей, токенов:
C# | ||
|
2. Игнорирование параллельного и асинхронного контекста — потеря следа выполнения:
C# | ||
|
3. Несистематические уровни логирования — всё становится Critical или Info:
C# | ||
|
4. Отсутствие ротации логов — диск заполняется, приложение падает:
C# | ||
|
5. Избыточное логирование — проблема «информационного шума»:
C# | ||
|
6. Текстовые шаблоны вместо структурированного логирования:
C# | ||
|
7. Отсутствие управления размером JSON:
C# | ||
|
8. Забывание о транзакционности — когда часть логов не попадает на диск при сбое:
C# | ||
|
9. Использование логирования на уровне метаданных без соответствующего контекста:
C# | ||
|
Продвинутые техники и нестандартные решения
Помимо стандартных подходов существует ряд продвинутых техник, которые могут значительно улучшить экосистему логирования в сложных приложениях.
Профилирование участков кода через аспекты логирования
Один из моих любимых подходов — создание атрибутов для автоматического логирования производительности методов:
C# | ||
|
Применение:
C# | ||
|
Создание собственного middleware для обогащения логов
Ещё одна техника — создание специализированных middleware для автоматического обогащения всех логов в приложении:
C# | ||
|
Условное логирование с помощью фильтров
Вместо статических уровней логирования иногда полезно использовать динамические фильтры:
C# | ||
|
Такой подход позволяет выборочно увеличивать детализацию для определённых компонентов системы, не влияя на остальные.
Логирование в микросервисной архитектуре с распределенным трейсингом
В распределенных системах особенно важно трассировать запросы через множество микросервисов. Для этого можно комбинировать логирование с OpenTelemetry:
C# | ||
|
Генерация документации на основе логов
Необычное, но полезное применение логирования — автоматическая генерация документации на основе структурированных логов:
C# | ||
|
Специальное расширение для генерации документации парсит логи и строит API-документацию, включая примеры запросов и ответов.
Логирование состояния системы при завершении работы
Полезная техника — специальное логирование при остановке приложения:
C# | ||
|
Такой подход помогает диагностировать проблемы при внезапных остановках контейнеров или перезапусках серверов в облачной среде.
Проверять, какие программы запускаются, вести лог
Здравствуйте, нужно сделать программу которая проверяет какие программы запускаются и записывать сколько раз.
Допустим запускается program.exe и…
При изменениях в DGW нужно ведение лог-файла
надо чтобы вёлся лог файл.На форме datagridview изменяющийся каждые 5 сек.надо чтобы при изменении записывалось в лог файл.Я пытаюсь так.но…
Система лог — пас)
Всем привет)
Пишу прогу для учительницы по английскому языку) С# изучала на курсах, так что сейчас уже пытаюсь что-то самопознать)
В общем, нужна…
Чтение из лог-файла
Здравствуйте! Есть задача — отследить запись в лог файл и проверить, какой именно текст записался. Для отслеживания изменения лога использовала…
Лог приложения.
Подскажите пожалуйста, как можно организовать создание лога приложения? Желательно с наименьшим падением производительности :).
Чтение лог-файла, когда он занят
Здравствуйте.
Есть лог файл, который постоянно пишеться (может быть по 5-6 записей за 1 мс.) Задача прочитать файл.
Но вот он занят. Уже…
Запись в лог данных, собираемых с нескольких потоков
есть нужда вести лог многопоточной программы.
есть концепция: потоки заносят инфу в некую переменную, форма тянет ее по таймеру.
есть наброски:…
Создание лог файла в ASP чате.
Вобщем проблемса в следуещем, есть некий приметивный чатик, хотелось бы в нем вести лог файл. Тобиш, есть апликашка с описаными событиями…
Как организовать лог файл на ASP
У меня почему то файл создается каждый раз заново, а мне нужно открывать лог файл и записат в конец, как это сделать?
Класс лог-файла, как лучше осуществить запись в файл
Здравствуйте!
Хочу создать класс лог-файла с конструктором, в котором передаваемое значение — путь к файлу. Связь с файлом хотел сделать через…
Можно ли вести подробный лог ошибок в приложении
Всем привет!
Возник такой вопрос. Вот мы пишем какой то проект, во время его отладки и т.д. сообщения о ошибках выдает нам среда к примеру. Когда…
Проверка на существование строки, запись в лог-файл
Здравствуйте!
Имеется файл excel и база данных, перебрасываю из файла в таблицу базы.
Делаю запись в лог-файл строк, которые были добавлены.
…
LogParser is a free log analysis software for Microsoft. ) Files, and event logs, registry, file system, and Active Directory. It can query these data like using SQL statements, and even display the results in various charts.
download link:
http://www.microsoft.com/en-us/download/details.aspx?id=24659
Log Parser
- C # + logparser implementation of Windows Log Analysis
- Write your own log analysis software
-
- C # code
-
- system.cs
- security.cs
- Visual output
- Write query statements in our C # program
- Reference article
Write your own log analysis software
Use C # to call LogParser.dll to implement the GUI interface of the LogParser tool, accumulate safety scenarios during log analysis, and improve efficiency for our emergency response.
C # code
system.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using LogQuery = MSUtil.LogQueryClassClass;
using LogRecordSet = MSUtil.ILogRecordset;
using tsvinputformat = MSUtil.COMTSVInputContextClassClass;
using EventLogInputFormat = MSUtil.COMEventLogInputContextClassClass;
using DataGridOutput = MSUtil.COMDataGridOutputContextClassClass;
using MSUtil;
namespace logparserGUI
{
public partial class system : Form
{
public system()
{
InitializeComponent();
}
private void system_Load(object sender, EventArgs e)
{
comboBox1.Items.Add("Boot / shutdown / restart");
}
private void button1_Click(object sender, EventArgs e)
{
if (comboBox1.Text.Length == 0)
{
MessageBox.Show("Please select the log type");
}
else
{
switch (comboBox1.Text)
{
case "Boot / shutdown / restart":
security sec = new security();
this.Hide();// Hide now this window
sec.ShowDialog();
break;
case "application":
application app = new application();
this.Hide();// Hide now this window
app.ShowDialog();
break;
case "system":
system sys = new system();
this.Hide();// Hide now this window
sys.ShowDialog();
break;
}
// String SQL = @ "SELECT EVENTID, TIMEGENERATED, SOURCENAME, Message from E: \ TOPSEC \ YJ \ Galaxy \ Yinghang \ 155system.evtx"; // This is the system log file path
string sql = @ "Select EventID, TimeGenerated, SourceName, Message from E: \ TOPSEC \ YJ \ Galaxy \ Yinghang \ 155System.evtx";// This is the system log file path
DataTable dt = ReadFromEvt(sql);
//writeToDataBase(dt);
dataGridView1.DataSource = dt;
MessageBox.Show("Read it!");
}
}
public DataTable ReadFromEvt(string sql)
{
try
{
DataTable datat = new DataTable();
datat.Columns.Add("Event ID", typeof(string));
datat.Columns.Add("date", typeof(string));
datat.Columns.Add("source", typeof(string));
datat.Columns.Add("description", typeof(string));
// Instantiate the LogQuery object
LogQuery oLogQuery = new LogQuery();
// Instantiate the Event Log Input Format object
EventLogInputFormat oEvtInputFormat = new EventLogInputFormat();
// Set its "direction" parameter to "BW"
oEvtInputFormat.direction = "BW";
// Create the query
string query = sql;
// Execute the query
LogRecordSet oRecordSet = oLogQuery.Execute(query, oEvtInputFormat);
while (!oRecordSet.atEnd())
{
var itemData = oRecordSet.getRecord();
DataRow dr = datat.NewRow();
dr["Event ID"] = itemData.getValue("EventID").ToString();
dr["date"] = itemData.getValue("TimeGenerated").ToString();
dr["source"] = itemData.getValue("SourceName").ToString();
dr["description"] = itemData.getValue("Message").ToString();
datat.Rows.Add(dr);
oRecordSet.moveNext();
}
// Close the recordset
oRecordSet.close();
return datat;
}
catch (System.Runtime.InteropServices.COMException exc)
{
MessageBox.Show("Unexpected error: " + exc.Message);
return null;
}
}
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
}
private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
}
}
}
security.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using LogQuery = MSUtil.LogQueryClassClass;
using LogRecordSet = MSUtil.ILogRecordset;
using tsvinputformat = MSUtil.COMTSVInputContextClassClass;
using EventLogInputFormat = MSUtil.COMEventLogInputContextClassClass;
using DataGridOutput = MSUtil.COMDataGridOutputContextClassClass;
using MSUtil;
namespace logparserGUI
{
public partial class security : Form
{
public security()
{
InitializeComponent();
}
public void eventlog()
{
try
{
LogQuery oLogQuery = new LogQuery();
EventLogInputFormat oEVTInputFormat = new EventLogInputFormat();
oEVTInputFormat.direction = "BW";
// string query = @ "SELECT TimeGenerated as LoginTime, EXTRACT_TOKEN (Strings, 5, '|') as username, EXTRACT_TOKEN (Strings, 8, '|') as LogonType, EXTRACT_TOKEN (Strings, 17, '|') AS ProcessName , Extract_token (Strings, 18, '|') AS Sourceip from D: \ Users \ Tenon \ Desktop \ Taihu Bureau \ 11.135 \ 11.135safe.evtx where eventid = 4624 "
// String query = @ "SELECT * from D: \ users \ Tenon \ Desktop \ Taihu Bureau \ Log \ 11.99app.evtx";
string query = @"SELECT * FROM E:\hack\anfu\yj\security.evtx";
//string query = @"SELECT TimeGenerated as LoginTime,EXTRACT_TOKEN(Strings,5,'|') as username,EXTRACT_TOKEN(Strings,6,'|') as AAA,EXTRACT_TOKEN(Strings,7,'|') as BBB,EXTRACT_TOKEN(Strings,8, '|') as LogonType,EXTRACT_TOKEN(Strings,9, '|') as CCC,EXTRACT_TOKEN(Strings, 10, '|') as DDD,EXTRACT_TOKEN(Strings, 11, '|') as EEE,EXTRACT_TOKEN(Strings, 12, '|') as FFF,EXTRACT_TOKEN(Strings, 13, '|') as GGG,EXTRACT_TOKEN(Strings, 14, '|') as HHH,EXTRACT_TOKEN(Strings, 15, '|') as III,EXTRACT_TOKEN(Strings, 16, '|') as JJJ,EXTRACT_TOKEN(Strings, 17, '|') AS ProcessName,EXTRACT_TOKEN(Strings, 18, '|') AS SourceIP FROM D:\Users\TenOn\Desktop\log20190629\log\security.evtx where EventID=4625";
//string query = @"SELECT TimeGenerated as LoginTime,EXTRACT_TOKEN(Strings,5,'|') as username,EXTRACT_TOKEN(Strings,6,'|') as AAA,EXTRACT_TOKEN(Strings,7,'|') as BBB,EXTRACT_TOKEN(Strings,8, '|') as LogonType,EXTRACT_TOKEN(Strings,9, '|') as CCC,EXTRACT_TOKEN(Strings, 10, '|') as DDD,EXTRACT_TOKEN(Strings, 11, '|') as EEE,EXTRACT_TOKEN(Strings, 12, '|') as FFF,EXTRACT_TOKEN(Strings, 13, '|') as GGG,EXTRACT_TOKEN(Strings, 14, '|') as HHH,EXTRACT_TOKEN(Strings, 15, '|') as III,EXTRACT_TOKEN(Strings, 16, '|') as JJJ,EXTRACT_TOKEN(Strings, 17, '|') AS ProcessName,EXTRACT_TOKEN(Strings, 18, '|') AS SourceIP FROM D:\Users\TenOn\Desktop\log20190629\log\security.evt where EventTypeName='Warning event'";
// String query = @ "SETRINGENERATED AS Logintime, Extract_token (Strings, 5, '|') AS UserName, Extract_token (Strings, 8, '|') As Logontype, Extract_token (Strings, 9, '|') AAA , Extract_token (Strings, 10, '|') AS BBBBBB, EXTRACT_TOKEN (Strings, 17, '|') As ProcessName, Extract_token (Strings, 18, '|') AS Sourceip from D: \ Users \ Tenon \ Desktop \ Taihu Lake Bureau \ Log \ 11.99.Evtx where EventId = 4624 ";
//Logparser.exe –i:EVT –o:DATAGRID "SELECT * FROM E:\study\yj\security.evtx where EventID=4625"
// String query = @ "SELECT * from D: \ Users \ Tenon \ Desktop \ Taihu Bureau \ 11.135 \ 11.135safe.evtx";
LogRecordSet oRecordSet = oLogQuery.Execute(query, oEVTInputFormat);// Execute a statement
DataGridOutput oEVTOutputFormat = new DataGridOutput();
MessageBox.Show("oLogQuery.ToString");
oLogQuery.ExecuteBatch(query, oEVTInputFormat, oEVTOutputFormat);
if (oLogQuery.errorMessages != null)
{
MessageBox.Show(oLogQuery.errorMessages.ToString());
}
}
catch (System.Runtime.InteropServices.COMException exc)
{
Console.WriteLine("Unexpected error: " + exc.Message);
}
}
private void security_Load(object sender, EventArgs e)
{
}
private void button1_Click(object sender, EventArgs e)
{
string sql = @ "Select EventID, TimeGenerated, SourceName, Message from E: \ TOPSEC \ YJ \ Galaxy \ Yinghang \ 155System.evtx";// This is the system log file path
DataTable dt = ReadFromEvt(sql);
//writeToDataBase(dt);
dataGridView1.DataSource = dt;
MessageBox.Show("Read it!");
}
public DataTable ReadFromEvt(string sql)
{
try
{
DataTable datat = new DataTable();
datat.Columns.Add("Event ID", typeof(string));
datat.Columns.Add("date", typeof(string));
datat.Columns.Add("source", typeof(string));
datat.Columns.Add("description", typeof(string));
// Instantiate the LogQuery object
LogQuery oLogQuery = new LogQuery();
// Instantiate the Event Log Input Format object
EventLogInputFormat oEvtInputFormat = new EventLogInputFormat();
// Set its "direction" parameter to "BW"
oEvtInputFormat.direction = "BW";
// Create the query
string query = sql;
// Execute the query
LogRecordSet oRecordSet = oLogQuery.Execute(query, oEvtInputFormat);
while (!oRecordSet.atEnd())
{
var itemData = oRecordSet.getRecord();
DataRow dr = datat.NewRow();
dr["Event ID"] = itemData.getValue("EventID").ToString();
dr["date"] = itemData.getValue("TimeGenerated").ToString();
dr["source"] = itemData.getValue("SourceName").ToString();
dr["description"] = itemData.getValue("Message").ToString();
datat.Rows.Add(dr);
oRecordSet.moveNext();
}
// Close the recordset
oRecordSet.close();
return datat;
}
catch (System.Runtime.InteropServices.COMException exc)
{
MessageBox.Show("Unexpected error: " + exc.Message);
return null;
}
}
private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
}
}
}
Visual output
–o:DATAGRID
Windows log strings field extraction
Other relatively simple in the extracted project, but String is very complicated, but it is more important.
Use functions extract_token (strings, num, ‘|’)
Strings Use | Split extract_token (strings, 0, ‘|’) extract S-1-5-18, extract_token (strings, 1, ‘|’) extract Desktop-Kjihhdo $ with this class
(Here, use the next picture.
https://blog.csdn.net/qq_29647709)
For example: Strings field, according to the fifth value of the | segment, turn the head header UserName
EXTRACT_TOKEN(Strings,5,'|') as username
For example: Analysis Successful Login Event 4624 We filth our data you want to extract:
These include, the 5th user, the 8th login type, the 17th program path, and the 18th source IP address we care about.
LogParser.exe -i:EVT -o:DATAGRID "SELECT TimeGenerated as LoginTime,EXTRACT_TOKEN(Strings,5,'|') as username,EXTRACT_TOKEN(Strings, 8, '|') as LogonType,EXTRACT_TOKEN(Strings, 17, '|') AS ProcessName,EXTRACT_TOKEN(Strings, 18, '|') AS SourceIP FROM E:\study\yj\security.evtx where EventID=4624"
Write query statements in our C # program
Such as: Analysis Successful Login Event 4624
We filled out our data you want to extract:
These include, the 5th user, the 8th login type, the 17th program path, and the 18th source IP address we care about.
LogParser.exe -i:EVT -o:DATAGRID "SELECT TimeGenerated as LoginTime,EXTRACT_TOKEN(Strings,5,'|') as username,EXTRACT_TOKEN(Strings, 8, '|') as LogonType,EXTRACT_TOKEN(Strings, 17, '|') AS ProcessName,EXTRACT_TOKEN(Strings, 18, '|') AS SourceIP FROM
View and login event
Logparser -i:evt –o:DATAGRID “SELECT * FROM E:\study\yj\security.evtx WHERE Strings LIKE '%logon%'”
View all fields for login audit failed logs and visual output
Logparser.exe –i:EVT –o:DATAGRID "SELECT * FROM E:\study\yj\security.evtx where EventID=4625"
Reference article
https://www.jianshu.com/p/d325b4b1169c
http://blog.sina.com.cn/s/blog_54b976460100o8qt.html
https://blog.csdn.net/qq_29647709/article/details/85124105
https://www.t00ls.net/viewthread.php?tid=48067&highlight=%E5%BA%94%E6%80%A5%E5%93%8D%E5%BA%94