Introducción al registro de eventos de Windows y ETW — llevar los registros de aplicaciones de negocio al mecanismo estándar del sistema operativo

· · CSharp, .NET, Registro de eventos, ETW, EventSource, Diseño de registros, Investigación de fallos, Desarrollo de Windows

Al desarrollar aplicaciones de negocio o servicios Windows en C#, normalmente se emiten registros diarios con un registrador de archivos propio o bibliotecas como Serilog y NLog. Pero eso no vuelve innecesarios al registro de eventos de Windows ni a ETW (Event Tracing for Windows). No sustituyen al archivo: son una capa de registro distinta, visible para operaciones y para las herramientas estándar del sistema operativo.

Este artículo organiza la distribución entre archivo, registro de eventos y ETW; la implementación en .NET; los puntos mínimos de ETW; la recogida e investigación; y las trampas habituales en el trabajo real.

1. La conclusión primero

  • Las tres opciones no son alternativas: se reparten funciones. El archivo permite a desarrollo y mantenimiento seguir detalles después; el registro de eventos permite a operaciones, al Visor de eventos y a herramientas de supervisión detectar anomalías; ETW es una traza de alta frecuencia que se activa bajo demanda para rendimiento o fallos difíciles de reproducir. Se suelen combinar, cambiando la cantidad de información que escribe cada una.
  • Escriba en Event Log solo inicio, parada y errores fatales. Si se vuelcan todos los registros allí, las anomalías importantes se ocultan. Mantenga el detalle en el archivo y filtre el registro de eventos.
  • Registrar una fuente de eventos requiere administrador. Desde Windows Vista, EventLog.CreateEventSource no se puede llamar sin privilegios de administrador. Evite registrarla en el primer acceso durante la ejecución; regístrela por adelantado en el instalador.1
  • ETW no es recogida permanente. Aunque se definan eventos con EventSource, no se registra nada si no hay un suscriptor —dotnet-trace, PerfView u otra herramienta basada en ETW—. Se recoge indicando el proveedor solo para análisis de rendimiento o una investigación concreta.2
  • Escriba mensajes como plantillas, no con concatenación ni interpolación. Con logger.LogInformation("Order {OrderId} failed", orderId), OrderId puede buscarse como dato estructurado. Concatenar o interpolar hace perder esa estructura.3
  • El crecimiento del registro suele deberse a un valor predeterminado pequeño. El tamaño máximo predeterminado de Event Log es solo 512 KB. Si una aplicación de negocio lo usa a diario, amplíelo explícitamente y decida qué ocurre al alcanzar el límite: sobrescribir o descartar.4
Aspecto Registro en archivo Registro de eventos ETW
Lectores principales Desarrollo y mantenimiento Operaciones, supervisión y Visor de eventos Investigación de rendimiento y soporte
Volumen orientativo Detallado; puede incluir Trace/Debug Bajo; solo inicio, parada y errores fatales Alto solo al activarlo; predeterminado sin registros
Vida y retención Fácil retención larga según rotación Al alcanzar el límite se sobrescriben o descartan entradas antiguas Por sesión; al terminar se guarda como .etl / .nettrace
Integración con herramientas estándar Ninguna; necesita visor propio Visor de eventos, wevtutil, Get-WinEvent dotnet-trace, PerfView, WPR/WPA
Privilegios Permiso de escritura del usuario de la aplicación Administrador para registrar fuente; un usuario estándar puede escribir en una fuente registrada A menudo se necesita administrador para iniciar la recogida

2. Bases del registro de eventos de Windows

Windows tiene por defecto Application, System y Security; Security es de solo lectura. Una aplicación o servicio de negocio escribe en Application o en un registro/canal personalizado; los controladores de dispositivos suelen escribir en System.5

La unidad de escritura es la «fuente de eventos». La fuente es el nombre que identifica a una aplicación y se registra antes con EventLog.CreateEventSource. Desde Windows Vista, registrar una fuente exige administrador. Para comprobar que el nombre es único se deben buscar todos los registros, incluido Security, y un usuario estándar no puede acceder a Security.1

using System.Diagnostics;

// Ejecútelo desde el instalador o el proceso de configuración mientras aún se tengan privilegios de administrador
const string SourceName = "KomuraSoft.OrderService";
const string LogName = "Application";

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

Si intenta crear la fuente en el primer acceso en tiempo de ejecución, la llamada falla cuando la aplicación opera como usuario estándar. Se trata del mismo patrón descrito en Cuándo se necesitan privilegios de administrador en Windows: registre la fuente en el instalador y limite la aplicación a escribir en una fuente ya registrada.

Cada evento tiene dos identificadores: nivel e ID de evento. El nivel es EventLogEntryType —Information, Warning, Error, SuccessAudit, FailureAudit— y sirve para iconos y filtros predeterminados del Visor de eventos. El ID de evento es un entero definido por la aplicación, clave para buscar y agregar el mismo tipo de suceso después.

3. Escribir en el registro de eventos desde .NET

Hay dos caminos principales desde .NET.

3.1 Usar System.Diagnostics.EventLog directamente

Es la API de bajo nivel, adecuada cuando se necesita control detallado, como categoría o adjuntar datos binarios. Fuera de .NET Framework se debe referenciar el paquete NuGet System.Diagnostics.EventLog.

using System.Diagnostics;

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

    public void WriteServiceStarted()
    {
        EventLog.WriteEntry(SourceName, "OrderService se ha iniciado.",
            EventLogEntryType.Information, eventID: 1000);
    }

    public void WriteFatalError(Exception ex)
    {
        EventLog.WriteEntry(SourceName,
            $"Se produjo un error crítico y no se puede continuar el procesamiento. Consulte el registro de archivos para obtener más detalles. {ex.GetType().Name}: {ex.Message}",
            EventLogEntryType.Error, eventID: 1999);
    }
}

3.2 Usar ILogger + AddEventLog

Si ya se estructura el registro con ILogger, AddEventLog de Microsoft.Extensions.Logging.EventLog encaja naturalmente en la canalización existente. En Worker Service basados en ASP.NET Core o Generic Host, el proveedor EventLog se habilita de manera predeterminada cuando se ejecuta en Windows.6

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";
    // Además del filtro de categorías predeterminado, envíe al registro de eventos
    // solo Warning y niveles superiores (deje los detalles al registro de archivos)
    settings.Filter = (_, level) => level >= LogLevel.Warning;
});

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

Si se omite EventLogSettings, LogName vale por defecto "Application" y SourceName, ".NET Runtime".7 Con una fuente genérica como .NET Runtime resulta difícil distinguir en el Visor de eventos si se trata de su aplicación u otra .NET; indique siempre SourceName para la aplicación.

En servicios Windows y procesos por lotes ejecutados por el Programador de tareas, el equilibrio práctico es escribir en Event Log solo «inicio», «parada» y «error fatal» y dejar los detalles al archivo. Consulte Cómo crear y operar servicios Windows y Cuando una tarea del Programador no se ejecuta o termina con 0x1. En ambos casos el registro de eventos es a menudo lo primero que mira operaciones, y que queden allí los puntos esenciales cambia la velocidad de la primera investigación.

4. Qué es ETW — infraestructura de trazas que atraviesa todo el sistema operativo

Event Tracing for Windows (ETW) es un mecanismo de trazas que permite instrumentar desde el kernel hasta aplicaciones de modo usuario sobre una base común. Su mayor característica es poder registrar y analizar en la misma línea temporal eventos del kernel —E/S de disco, creación de procesos, etc.— y eventos propios de la aplicación.8

En .NET se define un proveedor ETW propio creando una clase que herede de System.Diagnostics.Tracing.EventSource. ETW opera con publicación-suscripción: si no hay suscriptor, no se registra el evento. Implementar EventSource por sí solo no hace nada; se registra solo al activarlo explícitamente con una herramienta.2

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 = "Se inició el procesamiento del pedido. OrderId={0}")]
    public void OrderProcessingStart(string orderId)
    {
        if (IsEnabled())
        {
            WriteEvent(1, orderId);
        }
    }

    [Event(2, Level = EventLevel.Informational, Message = "Se completó el procesamiento del pedido. OrderId={0}")]
    public void OrderProcessingStop(string orderId)
    {
        if (IsEnabled())
        {
            WriteEvent(2, orderId);
        }
    }
}

El lado que llama se usa así. Comprobar IsEnabled() antes de escribir evita coste adicional cuando no se está recogiendo.

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

La forma más sencilla de recoger este evento es dotnet-trace, herramienta multiplataforma.9

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

Abra el .nettrace recogido en Visual Studio o PerfView. Para investigación de rendimiento más profunda, por ejemplo incluyendo eventos del kernel, se utiliza Windows Performance Recorder (WPR), incluido en Windows ADK, y se ve con Windows Performance Analyzer (WPA).10 Aquí nos detenemos en qué permite ETW y cuándo usarlo. Para desarrollar y mantener aplicaciones de negocio, basta primero con poder definir el proveedor propio mediante EventSource y recogerlo con dotnet-trace.

5. Trabajo práctico con registros estructurados

La plantilla de mensaje de ILogger se escribe como una cadena fija con marcadores con nombre {PlaceHolder}. No es una simple convención visual: al pasar solo argumentos sin cambiar la plantilla, la infraestructura de registro conserva la relación entre el nombre del marcador y el valor como datos estructurados.11

// Recomendado: mantenga fija la plantilla y pase los argumentos por separado
logger.LogWarning("No se pudo reservar el inventario para el pedido {OrderId}. Almacén={WarehouseId}", orderId, warehouseId);

// No recomendado: la concatenación o interpolación rompe la relación entre la plantilla y los valores
logger.LogWarning("Pedido " + orderId + ": no se pudo reservar el inventario. Almacén=" + warehouseId);
logger.LogWarning($"No se pudo reservar el inventario para el pedido {orderId}. Almacén={warehouseId}");

La regla de analizador CA2254 detecta este patrón no recomendado, en el que la plantilla cambia en cada llamada.3 En rutas críticas de llamadas frecuentes, LoggerMessageAttribute con generación de código evita el coste de boxing y de analizar la plantilla.12

using Microsoft.Extensions.Logging;

internal static partial class Log
{
    [LoggerMessage(
        EventId = 2001,
        Level = LogLevel.Warning,
        Message = "No se pudo reservar el inventario para el pedido {OrderId}. Almacén={WarehouseId}")]
    public static partial void StockReservationFailed(
        this ILogger logger, string orderId, string warehouseId);
}

// Llamada
logger.StockReservationFailed(orderId, warehouseId);

Con esta estructura, la misma llamada de registro puede enviar detalle al archivo —sinks de Serilog/NLog—, contenido filtrado al registro de eventos y trazas de bajo coste a ETW mediante EventSourceLoggerProvider. La forma básica es registrar varios ILoggerProvider y variar el nivel por proveedor con Filter. Para requisitos mínimos de un registrador propio, consulte Requisitos mínimos y lista de pruebas de integración para un registrador propio; para relacionar registros y volcados en un bloqueo, Diseño para conservar registros y volcados cuando una aplicación Windows se bloquea.

6. Recogida e investigación — el lado que lee los registros

En el Visor de eventos se pueden extraer solo fuente, nivel o ID de evento concretos mediante «Filtrar» o «Vista personalizada». Guardar las condiciones usadas con frecuencia como vista personalizada acelera la siguiente investigación. Las vistas se definen con consultas XPath; por ejemplo, para extraer una fuente y niveles concretos:13

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

Desde línea de comando, wevtutil permite exportar registros y cambiar su configuración. También puede formar parte de la operación de exportar los eventos alrededor del momento de la incidencia y enviarlos a soporte.14

:: Exportar todo el registro Application a un archivo evtx
wevtutil epl Application C:\logs\application_20260707.evtx

:: Mostrar solo los eventos de una fuente concreta (los 10 más recientes)
wevtutil qe Application /q:"*[System[Provider[@Name='KomuraSoft.OrderService']]]" /c:10 /rd:true /f:text

En una investigación de bloqueo, lo básico es cotejar por hora tres cosas: Event Log, archivo de registro y volcado. Parta de la marca de tiempo del «error fatal» en Event Log, compare el detalle del archivo de la misma hora y el volcado recogido con WER/ProcDump. Los métodos de recogida están en Introducción a la recogida de volcados de Windows — WER/ProcDump/WinDbg y el análisis en Leer volcados de bloqueo con WinDbg + SOS.

7. Trampas

  • Fallar al escribir con una fuente no registrada. Si se realiza una llamada equivalente a RegisterEventSource con una fuente no registrada, el evento se escribe en Application, pero como no existe la DLL de recursos de mensajes correspondiente, el Visor de eventos no puede mostrar la descripción y muestra un error.15 Si además se intenta registrar automáticamente con CreateEventSource en tiempo de ejecución, el primer inicio de un proceso sin administrador suele caer con una excepción. Termine siempre el registro en el instalador.
  • La confusión de poder escribir con otra fuente. Si se tiene permiso de escritura, Event Log puede permitir escribir incluso con otro nombre de fuente que la aplicación no haya registrado. El nombre debe ser único en el equipo, pero el sistema operativo no hace cumplir esa disciplina; queda del lado de la aplicación.5 Elegir un nombre demasiado genérico y sin empresa o producto puede chocar con aplicaciones de otros proveedores o reutilizar involuntariamente su fuente.
  • Crecimiento de registro y política de retención. El máximo predeterminado es solo 512 KB.4 Si la aplicación lo usa a diario, amplíe explícitamente el tamaño con wevtutil sl o el instalador y decida si, al llenarse, se sobrescriben las entradas antiguas o se descartan las nuevas. OverwriteOlder está obsoleto y puede comportarse de hecho como «no sobrescribir», incluso si se especifica.16
  • Visualización de mensajes en entornos multilingües. Si se usa MessageResourceFile con recursos localizados, ver el registro en una máquina donde la DLL no existe o difiere de versión produce «No se puede encontrar la descripción del identificador de evento …». Es frecuente al ver en otro servidor un registro transferido o cuando queda el registro después de desinstalar la aplicación. Si se escribe directamente con WriteEntry, sin archivo de recursos, no se introduce este problema.
  • No poder escribir por falta de permiso. Registrar la fuente requiere administrador, pero escribir en una fuente ya registrada puede hacerlo un usuario estándar. Antes de ejecutar toda la aplicación como administrador por asumir que no funciona sin él, separe qué operación requiere realmente el privilegio.

Artículos relacionados

Ámbitos de consulta relacionados

Enlaces de referencia

  1. Microsoft Learn, EventLog.CreateEventSource Method. Sobre el motivo por el que crear fuentes exige administrador desde Windows Vista: se deben buscar todos los registros, incluido Security.  2

  2. Microsoft Learn, Getting Started with EventSource. Sobre el modelo publicación-suscripción, que sin suscriptor no se registra evento y cómo recoger con dotnet-trace collect.  2

  3. Microsoft Learn, CA2254: Template should be a static expression. Sobre que usar concatenación o interpolación en plantillas de mensajes pierde la relación entre el nombre de marcador y el valor.  2

  4. Microsoft Learn, EventLog.MaximumKilobytes Property. Sobre que el tamaño máximo predeterminado de Event Log es 512 KB.  2

  5. Microsoft Learn, EventLog Class. Sobre los tres registros predeterminados Application/System/Security, la necesidad de unicidad de la fuente en un equipo y el mecanismo por el que se puede escribir con cualquier fuente registrada si se tiene permiso.  2

  6. Microsoft Learn, Logging providers in .NET. Sobre los proveedores predeterminados de Generic Host: Console, Debug, EventSource y EventLog en Windows. 

  7. Microsoft Learn, EventLogSettings Class. Sobre los valores predeterminados de AddEventLog: LogName Application y SourceName .NET Runtime

  8. Microsoft Learn, Event Tracing. Sobre ETW como mecanismo para iniciar, detener, instrumentar y consumir eventos de traza de aplicaciones. 

  9. Microsoft Learn, dotnet-trace performance analysis utility. Introducción a dotnet-trace como herramienta de recogida multiplataforma basada en EventPipe y a collect

  10. Microsoft Learn, Introduction to WPR. Sobre Windows Performance Recorder como herramienta que amplía ETW y proporciona registros detallados del sistema y aplicaciones. 

  11. Microsoft Learn, Logging in C# and .NET. Sobre la sintaxis {PlaceHolder} de las plantillas y cómo el nombre se convierte en propiedad de registro. 

  12. Microsoft Learn, High-performance logging in .NET. Sobre que los registros generados con LoggerMessageAttribute evitan costes de boxing y análisis de plantilla. 

  13. Microsoft Learn, Comparison of ETW and EventLog logger functionality. Sobre crear vistas personalizadas con consultas XPath en el Visor de eventos para extraer nombre de evento y otros elementos. 

  14. Microsoft Learn, wevtutil. Sobre exportar (epl), consultar (qe) y cambiar configuración (sl) de Event Log desde línea de comando. 

  15. Microsoft Learn, Event Sources. Sobre que escribir con una fuente no registrada recurre a Application, pero sin archivo de mensajes el Visor de eventos no puede mostrar la descripción y da error. 

  16. Microsoft Learn, OverflowAction Enum. Sobre comportamientos al alcanzar el máximo —sobrescribir o descartar— y la obsolescencia de OverwriteOlder. 

Artículos recientes con las mismas etiquetas para profundizar en temas cercanos.

Estas páginas sitúan el tema en un contexto más amplio de servicios y decisiones.

El artículo está directamente relacionado con los siguientes servicios.

Preguntas frecuentes

Preguntas habituales en las consultas sobre el tema del artículo.

¿Si tengo registros en archivo, no necesito el registro de eventos?
Para una investigación detallada, muchas veces basta con archivos. Sin embargo, si desea que el personal de operaciones detecte anomalías de la aplicación mediante el Visor de eventos estándar o herramientas de supervisión —notificaciones de fallo del Programador de tareas, SCOM, etc.—, es práctico combinarlo con una salida al registro de eventos que contenga solo los puntos esenciales. No son sustitutos: son capas de registro distintas para lectores diferentes.
¿Cómo debo definir la numeración de ID de evento?
No hay una única respuesta correcta, pero en la práctica se reducen accidentes si se respetan tres puntos: separar rangos por área funcional —inicio en la serie 1000, comunicaciones en la 2000, por ejemplo—, no cambiar el significado ni reutilizar un ID asignado y permitir huecos. EventId de ILogger también se utiliza como clave de búsqueda de registros estructurados, por lo que una numeración fácil de documentar ayuda al mantenimiento.
Uso Serilog o NLog; ¿cómo se relaciona esto con el artículo?
Serilog y NLog son una forma de distribuir, bajo ILogger, el mismo registro a varios sinks, como archivos, registro de eventos, ETW o SaaS externo. El criterio de diseño tratado aquí, «solo lo esencial en el registro de eventos» y «no romper las plantillas de mensajes», se aplica tanto al uso directo de ILogger como al uso a través de Serilog/NLog. Elegir un sink para EventLog, como Serilog.Sinks.EventLog, o AddEventLog estándar es una decisión de implementación.
¿Hasta dónde necesito aprender ETW?
Si el objetivo principal es desarrollar y mantener aplicaciones de negocio, basta con poder crear un proveedor propio con EventSource y recoger sus eventos con dotnet-trace. El análisis de pilas en PerfView o la recogida de eventos del kernel con WPR pertenecen a la etapa de especialización en investigación de rendimiento y se dejan deliberadamente fuera de este artículo.

Perfil del autor

Página de presentación del autor del artículo.

Go Komura

Representante de KomuraSoft LLC

Especializado en desarrollo de software para Windows, consultoría técnica e investigación de fallos, sobre todo en proyectos con sistemas existentes y errores difíciles de reproducir.

Volver al blog