Журнал событий Windows и ETW: как вывести логи бизнес-приложения в стандартные механизмы ОС

· Обновлено: · · CSharp, .NET, журнал событий, ETW, EventSource, проектирование логов, расследование сбоев, разработка под Windows

История изменений (1 обновлений, последнее 30 Aug 2026)

Журнал изменений этой статьи. Там, где версия до правки была заархивирована, она остаётся доступной для чтения по постоянной ссылке с DOI.

Русский текст переписан как полноценный технический перевод, а не калька с японского. Утверждения статьи не менялись.
Первая публикация
Цитирование статьи(DOI (зарегистрированный архив): 10.5281/zenodo.21619988)

Приведённые ниже DOI относятся к ранее зарегистрированным архивным версиям, которые могут отличаться от текущего текста. Для ссылки на текущий текст используйте URL этой страницы.

Го Комура (2026). Журнал событий Windows и ETW: как вывести логи бизнес-приложения в стандартные механизмы ОС. KomuraSoft LLC. https://comcomponent.com/ru/blog/windows-eventlog-etw-structured-logging/

DOI (зарегистрированный архив)
10.5281/zenodo.21619988
DOI (последняя зарегистрированная версия)
10.5281/zenodo.21619989

Когда на C# пишут бизнес-приложение или службу Windows, повседневные логи почти всегда уже идут в собственный файловый логгер или в библиотеку вроде Serilog и NLog. Значит ли это, что журнал событий Windows и ETW (Event Tracing for Windows) больше не нужны? Нет. Это не замена файловому логу, а отдельный слой записей, который видят специалисты по эксплуатации и стандартные средства ОС.

Ниже — как разделить роли файлового лога, журнала событий и ETW, как это реализовать в .NET, какой минимум ETW действительно нужен, как собирать и разбирать записи на практике и куда чаще всего наступают.

Целевые версии. Примеры в статье рассчитаны на .NET 8 (Windows). От .NET Framework 4.8 отличаются в основном два момента. Первый: System.Diagnostics.EventLog в .NET Framework входит в BCL, а в .NET (линейка Core) одноимённый пакет NuGet нужно подключать явно. Второй — куда доходят события EventSource. В .NET Framework это только ETW; в .NET (Core) они идут ещё и в EventPipe, встроенный механизм трассировки рантайма, поэтому инструменты вроде dotnet-trace могут собирать их без прав администратора.12

1. Сначала выводы

  • Три механизма не заменяют друг друга, а делят роли. Файловый лог — запись, по которой разработчик потом разбирает детали. Журнал событий — запись, по которой специалисты по эксплуатации, Просмотр событий и средства мониторинга замечают сбой. ETW — высокочастотная трассировка, которую включают по необходимости, когда разбирают производительность или плохо воспроизводимую ошибку. Обычно используют все три и меняют объём информации в каждом.
  • В журнал событий пишите только запуск, остановку и фатальные ошибки. Если туда же гнать все логи, аномалии, которые должна видеть эксплуатация, утонут. Файловый лог оставляйте подробным, журнал событий сужайте.
  • Регистрация источника событий требует прав администратора. Начиная с Windows Vista EventLog.CreateEventSource без прав администратора вызвать нельзя. Не регистрируйте источник при первом обращении во время работы: зарегистрируйте его заранее в установщике.3
  • ETW — это не «постоянный сбор». Даже если события описаны через EventSource, без подписчика (dotnet-trace, PerfView, инструмент на базе ETW) ничего не записывается. Базовый сценарий — указать нужный поставщик и собирать только при разборе производительности или конкретной ошибки.4
  • Пишите сообщения шаблоном, а не конкатенацией или интерполяцией. Запись вида logger.LogInformation("Order {OrderId} failed", orderId) позволяет искать в структурированном логе по имени заполнителя OrderId. Конкатенация и интерполяция эту структуру теряют.5
  • Разрастание журнала часто начинается с малого значения по умолчанию. Максимальный размер журнала событий по умолчанию — всего 512 КБ. Если бизнес-приложение пользуется журналом событий регулярно, размер нужно явно увеличить и на этапе проектирования решить, что делать при заполнении: перезаписывать старое или отбрасывать новое.6

Таблица для выбора.

Аспект Файловый лог Журнал событий ETW
Основной читатель Разработчики и сопровождение Специалисты по эксплуатации, средства мониторинга, стандартный Просмотр событий Те, кто разбирает производительность; инженеры поддержки
Ориентир по объёму Подробный: Trace/Debug допустимы Мало: только запуск, остановка и фатальные ошибки Много только когда включили; по умолчанию ничего не пишется
Срок жизни / хранение При настроенной ротации легко хранить долго По достижении лимита старое перезаписывается или новое отбрасывается В рамках сеанса; после сбора сохраняют как .etl/.nettrace
Связь со стандартными средствами ОС Нет (нужен свой просмотрщик) Смотрят в Просмотре событий, wevtutil, Get-WinEvent Смотрят через dotnet-trace, PerfView, WPR/WPA
Права Достаточно права записи у пользователя, под которым работает приложение Для регистрации источника нужны права администратора; писать в уже зарегистрированный источник может и обычный пользователь Чтобы начать сбор, права администратора часто нужны

На схеме сплошная линия обозначает отношение, которое выполняется всегда, а пунктирная — условное отношение (условия указаны в пояснении к каждому отношению на странице сведений). Полный список отношений (всего 18, с доказательствами и степенью уверенности) и определения основных понятий собраны на странице сведений карты знаний (на японском). Данные: JSON-LD / Turtle

2. Основы журнала событий Windows

В Windows по умолчанию три журнала: Application, System и Security. Security доступен только на чтение. Бизнес-приложения и службы пишут в Application или в собственный журнал (канал). Драйверы устройств по соглашению пишут в System.7

Единица записи — источник событий. Источник — имя, по которому опознают приложение; его заранее регистрируют через EventLog.CreateEventSource. Начиная с Windows Vista регистрация источника требует прав администратора. Чтобы проверить уникальность имени, нужно просмотреть все журналы, включая Security, а у обычного пользователя доступа к Security нет.3

using System.Diagnostics;

// Выполняйте из установщика или процедуры настройки, пока есть права администратора
const string SourceName = "KomuraSoft.OrderService";
const string LogName = "Application";

if (!EventLog.SourceExists(SourceName))
{
    EventLog.CreateEventSource(SourceName, LogName);
}

Если создавать источник при первом обращении уже в работающем приложении, вызов сорвётся в любой среде, где программа идёт от обычного пользователя. Когда права администратора действительно нужны — в общем виде разобрано в статье «Когда Windows действительно требует прав администратора». Регистрация источника событий — как раз такой случай. Безопасная схема: зарегистрировать источник в установщике, а самому приложению только писать в уже зарегистрированный источник.

У события два идентификатора: уровень и идентификатор события. Уровень — это EventLogEntryType (Information, Warning, Error, SuccessAudit, FailureAudit); по нему Просмотр событий ставит значок и применяет стандартные фильтры. Идентификатор события — целое число, которое задаёт приложение; позже по нему ищут и считают однотипные случаи.

3. Как писать в журнал событий из .NET

Из .NET в журнал событий ведут два основных пути. Сначала — чем они отличаются по предпосылкам.

Аспект 3.1 Напрямую System.Diagnostics.EventLog 3.2 ILogger + AddEventLog
Нужна ли регистрация источника Да. Имя, которое передаёте в WriteEntry, установщик должен заранее зарегистрировать через CreateEventSource3 Да. Имя в SourceName так же регистрирует установщик. Если его не указать, получится общее имя .NET Runtime8
Права на регистрацию Права администратора (только на регистрацию; писать в уже зарегистрированный источник может обычный пользователь) То же
Дополнительные ссылки В .NET (линейка Core) — пакет System.Diagnostics.EventLog Пакет Microsoft.Extensions.Logging.EventLog (в Generic Host на Windows включён по умолчанию)9
Что можно задать Уровень и идентификатор события, плюс категория и вложение двоичных данных Уровень, идентификатор события, шаблон сообщения. Категорию и двоичные данные задать нельзя
Как сузить объём Решаете на каждом месте вызова Через settings.Filter можно поднять уровень только для журнала событий
Где уместно Небольшой сервис без своей инфраструктуры логов, перенос с Win32-подобного кода Приложение, где структурированные логи уже идут через ILogger

В обоих путях заранее зарегистрированное имя источника — обязательная предпосылка. Если писать под незарегистрированным именем, само событие попадёт в журнал Application, но без соответствующего ресурса сообщений Просмотр событий не сможет показать текст описания.10

3.1 Напрямую через System.Diagnostics.EventLog

Это низкоуровневый API: он уместен, когда нужен тонкий контроль (категория, вложение двоичных данных и т. п.). В .NET (не .NET Framework) нужен пакет NuGet System.Diagnostics.EventLog.

using System.Diagnostics;

public sealed class OrderServiceEventLog
{
    private const string SourceName = "KomuraSoft.OrderService";

    public void WriteServiceStarted()
    {
        EventLog.WriteEntry(SourceName, "OrderService запущен.",
            EventLogEntryType.Information, eventID: 1000);
    }

    public void WriteFatalError(Exception ex)
    {
        EventLog.WriteEntry(SourceName,
            $"Произошла фатальная ошибка, обработка не может быть продолжена. Подробности см. в файловом логе. {ex.GetType().Name}: {ex.Message}",
            EventLogEntryType.Error, eventID: 1999);
    }
}

3.2 Через ILogger + AddEventLog

Если структурированные логи уже построены вокруг ILogger, AddEventLog из пакета Microsoft.Extensions.Logging.EventLog спокойно встаёт в существующий конвейер. В ASP.NET Core и в Worker Service на Generic Host провайдер EventLog на Windows включён по умолчанию.9

using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.EventLog;

HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);

builder.Logging.AddEventLog(settings =>
{
    settings.SourceName = "KomuraSoft.OrderService";
    settings.LogName = "Application";
    // Поверх стандартного фильтра категорий в журнал событий
    // пускаем только Warning и выше (подробности оставляем файловому логу)
    settings.Filter = (_, level) => level >= LogLevel.Warning;
});

using IHost host = builder.Build();
await host.RunAsync();

Если EventLogSettings не задавать, LogName по умолчанию — "Application", а SourceName — ".NET Runtime".8 Общее имя .NET Runtime в Просмотре событий почти не отличить от логов других .NET-приложений, поэтому SourceName всегда задавайте явно под своё приложение.

Для пакетной обработки в службе Windows или в Планировщике заданий практичный баланс такой: в журнал событий — только «запуск», «остановка» и «фатальная ошибка», всё остальное — в файловый лог. Как делать службу и как её эксплуатировать — в «Как создавать службы Windows и как их эксплуатировать», сбои запуска через Планировщик заданий — в «Задача Планировщика заданий не запускается или завершается с 0x1». В обоих случаях журнал событий часто первое, куда смотрит эксплуатация; есть ли там суть, напрямую влияет на скорость первого разбора.

3.3 Как убедиться, что события записались

После того как код написан, хотя бы раз дойдите до того, что события видны в Просмотре событий. Порядок такой.

  1. Win + R, выполните eventvwr.msc — откроется Просмотр событий.
  2. В левой панели откройте Просмотр событий (локальный) > Журналы Windows > Application (в русской среде журнал может называться «Приложение»). Если сделали свой журнал, его имя будет в разделе Журналы приложений и служб.
  3. Если записей много и нужные тонут, справа откройте Фильтр текущего журнала и сузьте по «Источнику событий» (своё имя источника) и по нужному идентификатору в поле всех кодов событий.

Как значения из кода попадают в поля Просмотра событий — в таблице ниже. Если «писали, но не находим», по ней видно, куда смотреть.

Что задано в коде Где видно в Просмотре событий
Первый аргумент WriteEntry / settings.SourceName Столбец «Источник»
Аргумент eventID / EventId у ILogger Столбец «Код события»
EventLogEntryType (Information, Warning, Error) / LogLevel Столбец «Уровень» (Сведения, Предупреждение, Ошибка)
Строка, переданная в WriteEntry / сообщение после подстановки шаблона Текст описания внизу списка, на вкладке «Общие»
LogName (по умолчанию Application) В каком журнале появится запись

Из командной строки удобнее PowerShell и Get-WinEvent. В -FilterHashtable передайте имя журнала и имя поставщика (= имя источника) — вернутся только события этого источника.11

# Последние 10 событий своего источника: только время, идентификатор, уровень и текст
Get-WinEvent -FilterHashtable @{ LogName = 'Application'; ProviderName = 'KomuraSoft.OrderService' } -MaxEvents 10 |
    Select-Object TimeCreated, Id, LevelDisplayName, Message

Если не вернулось ни одной записи, причина почти всегда одна из трёх: опечатка в имени источника, источник не зарегистрирован, запись сорвалась, а исключение проглотили. Зарегистрирован ли источник, проверяют так: [System.Diagnostics.EventLog]::SourceExists('KomuraSoft.OrderService').

4. Что такое ETW — сквозная трассировка всей ОС

Event Tracing for Windows (ETW) — механизм трассировки, которым одинаково инструментируют и ядро, и приложения пользовательского режима. Главное свойство: события ядра (дисковый ввод-вывод, создание процесса и т. п.) и собственные события приложения можно писать и разбирать на одной шкале времени.12

В .NET собственный поставщик ETW описывают классом, который наследует System.Diagnostics.Tracing.EventSource.1 ETW работает по модели publish-subscribe: без подписчика события не записываются. То есть один только класс EventSource ничего не делает — запись начинается, только когда сбор явно включают инструментом.4

Разница из таблицы в главе 1 — «журнал событий = постоянно, для эксплуатации» против «ETW = по необходимости, для разбора» — как раз из-за наличия или отсутствия подписчика. На схеме это выглядит так.

только запуск, остановка, фатальные ошибкиинструментирование через EventSourceнет подписчикакогда сбор запущенБизнес-приложениеЖурнал событийпишется постоянно, ОС сохраняетПросмотр событийwevtutil / Get-WinEventэксплуатация смотрит в любой моментПоставщикописывает высокочастотные событияНикуда не пишетсястоимость почти нулеваяСеансвключают только на время разбораПотребительdotnet-trace / PerfView / WPAразбирают за ограниченный период

Рис. 1: Журнал событий пишется постоянно и сохраняется; ETW записывается, только когда есть поставщик, сеанс и потребитель.

using System.Diagnostics.Tracing;

[EventSource(Name = "KomuraSoft-OrderService")]
internal sealed class OrderServiceEventSource : EventSource
{
    public static readonly OrderServiceEventSource Log = new();

    [Event(1, Level = EventLevel.Informational, Message = "Начата обработка заказа. OrderId={0}")]
    public void OrderProcessingStart(string orderId)
    {
        if (IsEnabled())
        {
            WriteEvent(1, orderId);
        }
    }

    [Event(2, Level = EventLevel.Informational, Message = "Обработка заказа завершена. OrderId={0}")]
    public void OrderProcessingStop(string orderId)
    {
        if (IsEnabled())
        {
            WriteEvent(2, orderId);
        }
    }
}

Вызывающий код использует его так. Проверка IsEnabled() до фактической записи позволяет не платить лишнее, пока никто не собирает события.

OrderServiceEventSource.Log.OrderProcessingStart(order.Id);
try
{
    ProcessOrder(order);
}
finally
{
    OrderServiceEventSource.Log.OrderProcessingStop(order.Id);
}

Самый простой способ собрать эти события — кроссплатформенный инструмент dotnet-trace.13

dotnet-trace collect --providers KomuraSoft-OrderService -- OrderService.exe

Здесь важно вот что: dotnet-trace идёт не через сам ETW, а через другой путь — EventPipe. EventPipe встроен в рантайм .NET и, как и ETW, умеет собирать события EventSource. Различий три. EventPipe одинаково работает на всех платформах, которые поддерживает .NET, а ETW — только на Windows. Чтобы начать сбор ETW, часто нужны права администратора; EventPipe этого не требует, если запускать его от того же пользователя, что и целевое приложение. И EventPipe видит только управляемый код и рантайм: события ОС и ядра и нативный стек вызовов он не берёт.2 Именно из-за третьего ограничения, когда нужно дойти до ядра, берут ETW (PerfView, WPR/WPA).

Собранный файл .nettrace открывают в Visual Studio или PerfView. Для более серьёзного разбора производительности — например, вместе с событиями ядра — используют Windows Performance Recorder (WPR) из Windows Assessment and Deployment Kit (ADK) и смотрят результат в Windows Performance Analyzer (WPA).14 Но рамки этой статьи — «что умеет ETW и когда его применять»; в подробную процедуру разбора в PerfView и WPA мы не заходим. Для разработки и сопровождения бизнес-приложения достаточно уметь описать свой поставщик через EventSource и собрать его через dotnet-trace.

5. Практика структурированного логирования

Шаблон сообщения ILogger пишут как фиксированную строку с именованными заполнителями вида {PlaceHolder}. Это не вопрос внешнего вида: пока шаблон не меняется, а аргументы передаются отдельно, инфраструктура логов сохраняет соответствие имён заполнителей и значений как структурированные данные.15

// Рекомендуется: шаблон фиксированный, аргументы передаются отдельно
logger.LogWarning("Не удалось зарезервировать запас для заказа {OrderId}. Склад={WarehouseId}", orderId, warehouseId);

// Не рекомендуется: конкатенация и интерполяция ломают соответствие шаблона и значений
logger.LogWarning("Заказ " + orderId + ": не удалось зарезервировать запас. Склад=" + warehouseId);
logger.LogWarning($"Не удалось зарезервировать запас для заказа {orderId}. Склад={warehouseId}");

Правило анализатора CA2254 как раз ловит этот нежелательный вариант, когда шаблон меняется от вызова к вызову.5 На горячем пути с частыми вызовами можно пойти дальше и через LoggerMessageAttribute включить генерацию кода: тогда не платите за boxing и разбор шаблона.16

using Microsoft.Extensions.Logging;

internal static partial class Log
{
    [LoggerMessage(
        EventId = 2001,
        Level = LogLevel.Warning,
        Message = "Не удалось зарезервировать запас для заказа {OrderId}. Склад={WarehouseId}")]
    public static partial void StockReservationFailed(
        this ILogger logger, string orderId, string warehouseId);
}

// Вызывающий код
logger.StockReservationFailed(orderId, warehouseId);

При такой схеме один и тот же вызов лога можно развести: подробности — в файловый лог через sink Serilog/NLog, урезанное — в журнал событий, дешёвую трассировку — в ETW через EventSourceLoggerProvider. Базовая форма: зарегистрировать несколько ILoggerProvider и через Filter задать разный уровень каждому. Минимальные требования к собственному логгеру — в «Минимальные требования к собственному логгеру и чек-лист интеграционных тестов», как связать логи и дамп при сбое — в «Как проектировать Windows-приложение так, чтобы при сбое оставались логи и дамп».

6. Сбор и разбор: сторона тех, кто читает логи

В Просмотре событий из списка журнала через «Фильтр» или «Настраиваемые представления» можно оставить только нужный источник, уровень или идентификатор события. Часто используемые условия сохраняйте как настраиваемое представление — следующий разбор пойдёт быстрее. Представление задаётся XPath-запросом; например, выбрать события конкретного источника можно так.17

<QueryList>
  <Query Id="0" Path="Application">
    <Select Path="Application">
      *[System[Provider[@Name='KomuraSoft.OrderService'] and (Level=2 or Level=3)]]
    </Select>
  </Query>
</QueryList>

Куда вставлять этот XML: справа в Просмотре событий «Создание настраиваемого представления» > вкладка «XML» > флажок «Изменить запрос вручную». После сохранения представление появится слева в «Настраиваемых представлениях»; дальше достаточно щелчка, и откроется список только ошибок (Level=2) и предупреждений (Level=3), которые написал KomuraSoft.OrderService. Level в схеме события — то же значение, что столбец «Уровень» в Просмотре событий; если нужны ещё сведения, добавьте в условие Level=4. Сужение, собранное в диалоге фильтра, на той же вкладке «XML» видно как XPath, поэтому короткий путь — сначала сузить в GUI, потом скопировать XML.

Из командной строки wevtutil экспортирует журналы и меняет настройки. Им же при разборе сбоя выгружают журнал вокруг момента инцидента и отправляют в поддержку.18

:: Экспортировать весь журнал Application в файл evtx
wevtutil epl Application C:\logs\application_20260707.evtx

:: Показать только события указанного источника (10 последних)
wevtutil qe Application /q:"*[System[Provider[@Name='KomuraSoft.OrderService']]]" /c:10 /rd:true /f:text

То, что передаётся в /q:, — содержимое элемента Select из XPath настраиваемого представления выше. /f: задаёт формат вывода: для чтения глазами берите text, для разбора скриптом — xml. В xml схема та же, что у XML настраиваемого представления, поэтому Provider и EventID можно брать по имени элемента. Экспортированный .evtx на другом компьютере открывают через «Открыть сохранённый журнал» в Просмотре событий.

При разборе сбоя базовый приём — сопоставить по времени три вещи: журнал событий, файловый лог и аварийный дамп. От метки времени «фатальной ошибки» в журнале событий смотрят подробности файлового лога в тот же момент и дамп, снятый WER/ProcDump. Как снимать дампы — в «Сбор аварийных дампов Windows: введение — WER, ProcDump, WinDbg», как разбирать уже снятый дамп — в «Как читать аварийный дамп в WinDbg + SOS».

7. Типичные ошибки

  • Пишут, не зарегистрировав источник. Вызов, эквивалентный RegisterEventSource, с незарегистрированным именем всё же кладёт событие в Application, но без DLL ресурса сообщений Просмотр событий не показывает описание и рисует ошибку.10 Если к тому же пытаться регистрировать источник через CreateEventSource при запуске, процесс под обычным пользователем часто падает исключением уже при первом старте. Регистрацию источника всегда заканчивайте в установщике.
  • Путаница «можно писать под чужим именем источника». При наличии права записи журнал событий позволяет писать и под именем источника, которое приложение само не регистрировало. Имена источников должны быть уникальны на компьютере, но ОС это не обеспечивает — дисциплина целиком на стороне приложений.7 Слишком общее короткое имя без компании или продукта легко столкнётся с приложением другого поставщика или нечаянно займёт его источник.
  • Разрастание журнала и политика хранения. Максимальный размер по умолчанию — всего 512 КБ.6 Если бизнес-приложение пользуется журналом событий регулярно, явно увеличьте размер через wevtutil sl или установщик и сознательно выберите: перезаписывать самое старое или отбрасывать новое. Учтите и то, что OverwriteOlder помечен как устаревший: даже если его указать, фактически может получиться режим «не перезаписывать».19
  • Отображение сообщений в многоязычной среде. Если настроены локализованные ресурсы сообщений (MessageResourceFile), просмотр лога в среде без этой DLL или с другой версией даёт текст вроде «Не удается найти описание для события с кодом XX». Так бывает, когда перенаправленный журнал смотрят на другом сервере или когда приложение уже удалили, а события остались. Если писать строки напрямую через WriteEntry (без файла ресурсов), эту проблему вы просто не заносите.
  • Случаи, когда писать нельзя из-за прав. Часто думают, что без администратора ничего не работает. На деле права администратора нужны для регистрации источника, а писать в уже зарегистрированный источник может обычный пользователь. Прежде чем поднимать всё приложение с правами администратора из-за «без администратора не работает», отделите операцию, которой эти права действительно нужны.

8. Кратко

Каркас статьи сводится к трём пунктам.

  • Три механизма делят роли. Файловый лог — чтобы разработчик разбирал детали; журнал событий — чтобы эксплуатация и стандартные средства ОС замечали сбой; ETW/EventPipe — чтобы копать производительность и плохо воспроизводимые ошибки. В журнал событий пишите только запуск, остановку и фатальные ошибки, подробности оставляйте файловому логу (глава 1).
  • Регистрация источника событий — работа установщика. На регистрацию нужны права администратора, писать в уже зарегистрированный источник может обычный пользователь. Попытка регистрировать источник через CreateEventSource во время работы как раз и даёт сбой при первом запуске под обычным пользователем (главы 2, 3 и 7).
  • ETW записывается, только когда есть подписчик. Один EventSource ничего не делает. Обратная сторона: стоимость заранее заложенного инструментирования почти нулевая, и в нужный момент события можно снять dotnet-trace (глава 4).

Если переходить к практике, разумный порядок такой.

  1. Просмотрите, что существующее приложение уже пишет в журнал событий, и убедитесь, что туда идут только запуск, остановка и фатальные ошибки. Если утекают и подробные логи, сузьте через Filter у AddEventLog (глава 3).
  2. Зафиксируйте правила нумерации идентификаторов (диапазоны по функциональным областям; выданный идентификатор не менять по смыслу) и оставьте это в документации (глава 2).
  3. Проверьте, есть ли в установщике регистрация источника событий и увеличен ли максимальный размер журнала относительно 512 КБ по умолчанию (глава 7).
  4. Если при каждом разборе сбоя вы сужаете журнал одинаково, сохраните этот XPath как настраиваемое представление (глава 6).
  5. В обработку, по которой могут спросить про производительность, заранее заложите через EventSource хотя бы события начала и конца. Пока сбор выключен, стоимость почти нулевая (глава 4).

Связанные статьи

Смежные темы консультаций

KomuraSoft LLC консультирует по проектированию логирования, журнала событий и ETW для Windows-бизнес-приложений, а также по точкам наблюдения, которые пригодятся при расследовании сбоев.

Справочные ссылки

  1. Microsoft Learn, EventSource. О EventSource как встроенном в .NET механизме быстрого структурированного логирования с поддержкой ETW и EventPipe. ↩ ↩2

  2. Microsoft Learn, EventPipe. О том, что EventPipe — встроенный в рантайм .NET механизм трассировки, похожий на ETW и perf_events; что он умеет собирать события EventSource; что ETW только для Windows и часто требует прав администратора, а EventPipe кроссплатформенный и без них; что область EventPipe ограничена управляемым кодом и рантаймом и не включает события ядра и нативный стек вызовов. ↩ ↩2

  3. Microsoft Learn, EventLog.CreateEventSource Method. Почему начиная с Windows Vista создание источника событий требует прав администратора: нужен поиск по всем журналам, включая Security. ↩ ↩2 ↩3

  4. Microsoft Learn, Getting Started with EventSource. О модели publish-subscribe у EventSource: без подписчика (ETW или EventPipe) события не записываются; о сборе через dotnet-trace collect. ↩ ↩2

  5. Microsoft Learn, CA2254: Template should be a static expression. О том, что конкатенация и интерполяция в шаблоне лог-сообщения теряют соответствие имён заполнителей и значений. ↩ ↩2

  6. Microsoft Learn, EventLog.MaximumKilobytes Property. О том, что максимальный размер журнала событий по умолчанию — 512 килобайт. ↩ ↩2

  7. Microsoft Learn, EventLog Class. О трёх журналах по умолчанию (Application/System/Security), о том, что источник должен быть уникален на компьютере, и о механизме, по которому при наличии права записи можно писать под любым уже зарегистрированным именем источника. ↩ ↩2

  8. Microsoft Learn, EventLogSettings Class. О значениях по умолчанию AddEventLog: LogName — "Application", SourceName — ".NET Runtime". ↩ ↩2

  9. Microsoft Learn, Logging providers in .NET. О том, что стандартные провайдеры логирования Generic Host включают Console, Debug, EventSource и EventLog (только Windows). ↩ ↩2

  10. Microsoft Learn, Event Sources. О том, что запись под незарегистрированным именем попадает в Application, но без файла сообщений Просмотр событий не может показать описание и сообщает ошибку. ↩ ↩2

  11. Microsoft Learn, Get-WinEvent. О том, что в -FilterHashtable можно передать ключи вроде LogName и ProviderName и сузить выборку, а у полученных событий есть свойства TimeCreated, Id, LevelDisplayName, Message. ↩

  12. Microsoft Learn, Event Tracing. О Event Tracing for Windows (ETW) как механизме запуска, остановки, инструментирования и потребления событий трассировки приложений. ↩

  13. Microsoft Learn, dotnet-trace performance analysis utility. О dotnet-trace — кроссплатформенном инструменте сбора трасс на базе EventPipe — и команде collect. ↩

  14. Microsoft Learn, Introduction to WPR. О Windows Performance Recorder (WPR) как инструменте, который расширяет ETW и даёт подробную запись системы и приложений. ↩

  15. Microsoft Learn, Logging in C# and .NET. О синтаксисе {PlaceHolder} в шаблонах сообщений и о том, что ключи шаблона становятся именами свойств лога. ↩

  16. Microsoft Learn, High-performance logging in .NET. О том, что логирование с генерацией кода через LoggerMessageAttribute позволяет не платить за boxing и разбор шаблона. ↩

  17. Microsoft Learn, Comparison of ETW and EventLog logger functionality. О создании настраиваемого представления в Просмотре событий XPath-запросом, в том числе по имени события. ↩

  18. Microsoft Learn, wevtutil. О командной работе с журналом событий: экспорт (epl), запрос (qe), смена настроек (sl). ↩

  19. Microsoft Learn, OverflowAction Enum. О поведении при достижении максимального размера журнала (перезапись или отбрасывание) и об устаревании OverwriteOlder. ↩

Недавние статьи с теми же тегами помогут подробнее изучить близкие темы.

Эти страницы показывают тему статьи в более широком контексте услуг и решений.

Статья напрямую связана со следующими услугами.

Частые вопросы

Вопросы, которые часто возникают при консультациях по теме статьи.

Если уже есть файловые логи, журнал событий не нужен?
Для подробного разбора часто хватает файлового лога. Но если специалисты по эксплуатации должны замечать сбой приложения в стандартных средствах ОС — Просмотре событий или системах мониторинга (уведомления о сбое в Планировщике заданий, SCOM и т. п.) — на практике в журнал событий выводят только ключевые точки. Это не замена одного другим: у записей разные читатели и разный слой.
Как задать правила нумерации идентификаторов событий?
Единственно верного ответа нет, но на практике меньше путаницы, если держать три правила: выделять диапазоны по функциональным областям (например, 1000-е — запуск, 2000-е — связь); выданный идентификатор не менять по смыслу и не использовать повторно; допускать пропуски в нумерации. EventId в ILogger ещё и ключ поиска в структурированных логах, поэтому схему, которую потом легко описать в документации, проще сопровождать.
Я использую Serilog или NLog. Как это соотносится со статьёй?
Serilog и NLog — одна из реализаций под ILogger: они направляют одни и те же записи в несколько sink — файл, журнал событий, ETW, внешний SaaS и т. д. Принципы статьи — в журнал событий только главное, шаблон сообщения не ломать — одинаково работают и при прямом ILogger, и через Serilog/NLog. Брать sink для журнала событий (например Serilog.Sinks.EventLog) или стандартный AddEventLog — уже выбор реализации.
Насколько глубоко нужно изучать ETW?
Если цель — разработка и сопровождение бизнес-приложения, достаточно уметь описать свой поставщик через EventSource и собирать его события через dotnet-trace. Разбор стека вызовов в PerfView и сбор событий ядра через WPR имеет смысл осваивать, когда производительность становится отдельной специальностью; в этой статье мы сознательно оставляем это за рамками.

Об авторе

Страница с профилем автора статьи.

Го Комура

Представитель KomuraSoft LLC

Специализируется на разработке программного обеспечения для Windows, техническом консалтинге и расследовании сбоев, особенно в проектах с унаследованными системами и трудно воспроизводимыми ошибками.

Публичные ссылки

Вернуться в блог