La clase LoggerMessage expone la funcionalidad para crear delegados almacenables en caché que requieren menos asignaciones de objetos y una menor sobrecarga computacional en comparación con los métodos de extensión del registrador, como LogInformation y LogDebug. Para escenarios de registro de alto rendimiento, use el patrón LoggerMessage.
LoggerMessage proporciona las siguientes ventajas de rendimiento frente a los métodos de extensión del registrador:
Los métodos de extensión del registrador requieren la conversión boxing de tipos de valor, como int, en object. El patrón LoggerMessage impide la conversión boxing mediante métodos de extensión y campos Action estáticos con parámetros fuertemente tipados.
Los métodos de extensión del registrador deben analizar la plantilla de mensaje (cadena de formato con nombre) cada vez que se escribe un mensaje de registro. LoggerMessage solo necesita analizar una vez una plantilla cuando se define el mensaje.
En la aplicación de ejemplo se muestran características LoggerMessage con un servicio de trabajo de procesamiento de cola prioritario. La aplicación procesa los elementos de trabajo por orden de prioridad. A medida que se producen estas operaciones, se generan mensajes de registro mediante el patrón LoggerMessage.
Use Define(LogLevel, EventId, String) para crear un delegado Action para registrar un mensaje. Las sobrecargas Define permiten pasar hasta seis parámetros de tipo a una cadena de formato con nombre (plantilla).
La cadena proporcionada al método Define es una plantilla y no una cadena interpolada. Los marcadores de posición se rellenan en el orden en que se especifican los tipos. Los nombres de los marcadores de posición en la plantilla deben ser descriptivos y coherentes entre las plantillas. Sirven como nombres de propiedad en los datos estructurados del registro. Se recomienda el uso de la grafía Pascal para los nombres de los marcadores de posición. Por ejemplo: {Item}, {DateTime}.
Cada mensaje de registro es un delegado Action que se mantiene en un campo estático creado por LoggerMessage.Define. Por ejemplo, la aplicación de ejemplo crea un campo para describir un mensaje de registro para procesar los elementos de trabajo:
El método LoggerMessage.Define se usa para configurar y definir un delegado Action, que representa un mensaje de registro.
Los almacenes de registro estructurado pueden usar el nombre de evento cuando se suministra con el identificador de evento para enriquecer el registro. Por ejemplo, Serilog usa el nombre de evento.
El delegado Action se invoca mediante un método de extensión fuertemente tipado. El método PriorityItemProcessed registra un mensaje cada vez que se procesa un elemento de trabajo. A FailedToProcessWorkItem se llama cuando produce una excepción:
Inspeccione la salida de la consola de la aplicación:
Consola
crit: WorkerServiceOptions.Example.Worker[13]
Epic failure processing item!
System.Exception: Failed to verify communications.
at WorkerServiceOptions.Example.Worker.ExecuteAsync(CancellationToken stoppingToken) in
..\Worker.cs:line 27
Para pasar parámetros a un mensaje de registro, defina hasta seis tipos al crear el campo estático. La aplicación de ejemplo registra los detalles del elemento de trabajo al procesar los elementos definiendo un tipo WorkItem para el campo Action:
La plantilla de mensaje de registro del delegado recibe sus valores de marcador de posición a partir de los tipos proporcionados. La aplicación de ejemplo define un delegado para agregar un elemento de trabajo cuando el parámetro del elemento es WorkItem:
El método de extensión estático para registrar que se está procesando un elemento de trabajo, PriorityItemProcessed, recibe el valor de argumento del elemento de trabajo y lo pasa al delegado Action:
Al igual que sucede con el método Define, la cadena proporcionada al método DefineScope es una plantilla y no una cadena interpolada. Los marcadores de posición se rellenan en el orden en que se especifican los tipos. Los nombres de los marcadores de posición en la plantilla deben ser descriptivos y coherentes entre las plantillas. Sirven como nombres de propiedad en los datos estructurados del registro. Se recomienda el uso de la grafía Pascal para los nombres de los marcadores de posición. Por ejemplo: {Item}, {DateTime}.
Defina un ámbito de registro para aplicarlo a una serie de mensajes de registro mediante el método DefineScope. Habilite IncludeScopes en la sección del registrador de la consola de appsettings.json:
Para crear un ámbito de registro, agregue un campo para que contenga un delegado Func<TResult> para el ámbito. La aplicación de ejemplo crea un campo denominado s_processingWorkScope (Internal/LoggerExtensions.cs):
Use DefineScope para crear el delegado. Pueden especificarse hasta seis tipos para usarlos como argumentos de plantilla cuando se invoca el delegado. La aplicación de ejemplo usa una plantilla de mensaje que incluye la fecha y hora en que se inició el procesamiento:
C#
s_processingWorkScope =
LoggerMessage.DefineScope<DateTime>(
"Processing scope, started at: {DateTime}");
Proporcione un método de extensión estático para el mensaje de registro. Incluya todos los parámetros de tipo para propiedades con nombre que aparezcan en la plantilla de mensaje. La aplicación de ejemplo adopta DateTime para una marca de tiempo personalizada para el registro y devuelve _processingWorkScope:
Inspeccione los mensajes de registro en la salida de la consola de la aplicación. El resultado siguiente muestra el orden de prioridad de los mensajes de registro con el mensaje de ámbito de registro incluido:
Optimizaciones de nivel de registro con protección
Se puede realizar otra optimización de rendimiento mediante la comprobación de LogLevel, con ILogger.IsEnabled(LogLevel) antes de una invocación al método Log* correspondiente. Cuando el registro no está configurado para el valor LogLevel proporcionado, las afirmaciones siguientes son ciertas:
El origen de este contenido se puede encontrar en GitHub, donde también puede crear y revisar problemas y solicitudes de incorporación de cambios. Para más información, consulte nuestra guía para colaboradores.
Comentarios de .NET
.NET es un proyecto de código abierto. Seleccione un vínculo para proporcionar comentarios:
Únase a la serie de reuniones para crear soluciones de inteligencia artificial escalables basadas en casos de uso reales con compañeros desarrolladores y expertos.