Cursos
Módulo
Aplicación de formato a datos alfanuméricos para su presentación en C# - Training
Explore los métodos básicos de C# para dar formato a datos alfanuméricos.
Este explorador ya no se admite.
Actualice a Microsoft Edge para aprovechar las características y actualizaciones de seguridad más recientes, y disponer de soporte técnico.
.NET admite un registro estructurado de alto rendimiento a través de la API ILogger para ayudar a supervisar el comportamiento de la aplicación y diagnosticar problemas. Los registros se pueden escribir en distintos destinos mediante la configuración de diferentes proveedores de registro. Los proveedores de registro básicos están integrados y también hay muchos proveedores de terceros disponibles.
En este primer ejemplo, se muestran los aspectos básicos, pero esto solo es adecuado para una aplicación de consola básica. Esta aplicación de consola de ejemplo se basa en los siguientes paquetes NuGet:
En la siguiente sección verá cómo mejorar el código teniendo en cuenta la escala, el rendimiento, la configuración y los patrones de programación típicos.
using Microsoft.Extensions.Logging;
using ILoggerFactory factory = LoggerFactory.Create(builder => builder.AddConsole());
ILogger logger = factory.CreateLogger("Program");
logger.LogInformation("Hello World! Logging is {Description}.", "fun");
Ejemplo anterior:
ILoggerFactory
almacena toda la configuración que determina dónde se envían los mensajes de registro. En este caso, se configura el proveedor de registro de la consola para que los mensajes de registro se escriban en la consola.string
asociado a cada mensaje registrado por el objeto ILogger
. Se usa para agrupar los mensajes de registro de la misma clase (o categoría) al buscar o filtrar registros.Information
. El nivel de registro indica la gravedad del evento registrado y se usa para filtrar los mensajes de registro menos importantes. La entrada de registro también incluye una plantilla de mensaje "Hello World! Logging is {Description}."
y un par clave-valor Description = fun
. El nombre de clave (o marcador de posición) procede de la palabra dentro de las llaves de la plantilla y el valor procede del argumento del método restante.El archivo de proyecto de este ejemplo incluye dos paquetes NuGet:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging" Version="9.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="9.0.0" />
</ItemGroup>
</Project>
Sugerencia
Todo el código fuente del ejemplo de registro está disponible en el Explorador de ejemplos para su descarga. Para obtener más información, consulte Examinación de ejemplos de código: registro en .NET.
Hay varios cambios que debería considerar hacer en el ejemplo anterior cuando se registre en un escenario menos trivial:
Si su aplicación usa Inserción de dependencias (ID) o un host como WebApplication de ASP.NET o Generic Host de ASP.NET, deberá usar ILoggerFactory
y objetos ILogger
de sus respectivos contenedores de DI en lugar de crearlos directamente. Para obtener más información, consulte Integración con DI y hosts.
El registro de generación de origen en tiempo de compilación suele ser una alternativa mejor a los métodos de extensión ILogger
, como LogInformation
. La generación de orígenes de registro ofrece un mejor rendimiento, una tipificación más fuerte y evita la propagación de constantes string
en todos los métodos. El inconveniente es que el uso de esta técnica requiere un poco más de código.
using Microsoft.Extensions.Logging;
internal partial class Program
{
static void Main(string[] args)
{
using ILoggerFactory factory = LoggerFactory.Create(builder => builder.AddConsole());
ILogger logger = factory.CreateLogger("Program");
LogStartupMessage(logger, "fun");
}
[LoggerMessage(Level = LogLevel.Information, Message = "Hello World! Logging is {Description}.")]
static partial void LogStartupMessage(ILogger logger, string description);
}
Type
para que la nomenclatura sea fácil de hacer.using Microsoft.Extensions.Logging;
internal class Program
{
static void Main(string[] args)
{
using ILoggerFactory factory = LoggerFactory.Create(builder => builder.AddConsole());
ILogger logger = factory.CreateLogger<Program>();
logger.LogInformation("Hello World! Logging is {Description}.", "fun");
}
}
using Microsoft.Extensions.Logging;
using OpenTelemetry.Logs;
using ILoggerFactory factory = LoggerFactory.Create(builder =>
{
builder.AddOpenTelemetry(logging =>
{
logging.AddOtlpExporter();
});
});
ILogger logger = factory.CreateLogger("Program");
logger.LogInformation("Hello World! Logging is {Description}.", "fun");
Si su aplicación usa Inserción de dependencias (ID) o un host como WebApplication de ASP.NET o Generic Host de ASP.NET, deberá usar ILoggerFactory
y objetos ILogger
del contenedor de DI en lugar de crearlos directamente.
En este ejemplo se obtiene un objeto ILogger en una aplicación hospedada mediante ASP.NET Minimal API mínimas:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddSingleton<ExampleHandler>();
var app = builder.Build();
var handler = app.Services.GetRequiredService<ExampleHandler>();
app.MapGet("/", handler.HandleRequest);
app.Run();
partial class ExampleHandler(ILogger<ExampleHandler> logger)
{
public string HandleRequest()
{
LogHandleRequest(logger);
return "Hello World";
}
[LoggerMessage(LogLevel.Information, "ExampleHandler.HandleRequest was called")]
public static partial void LogHandleRequest(ILogger logger);
}
Ejemplo anterior:
ExampleHandler
y asignado solicitudes web entrantes para ejecutar la función ExampleHandler.HandleRequest
.ILogger<ExampleHandler>
. ILogger<TCategoryName> deriva de ILogger e indica la categoría que tiene el objeto ILogger
. El contenedor de inserción de dependencias busca una ILogger
con la categoría correcta y la proporciona como argumento constructor. Si aún no existe ninguna ILogger
con esa categoría, el contenedor de inserción de dependencias lo crea automáticamente desde el ILoggerFactory
en el proveedor de servicios.logger
recibido en el constructor se usó para iniciar sesión en la función HandleRequest
.Los generadores de hosts inicializan configuración predeterminada y, a continuación, agregan un objeto ILoggerFactory
configurado al contenedor de inserción de dependencias del host cuando se compila el host. Antes de compilar el host, puede ajustar la configuración de registro a través HostApplicationBuilder.Logging, WebApplicationBuilder.Loggingo API similares en otros hosts. Los hosts también aplican la configuración de registro de orígenes de configuración predeterminados como appsettings.json y variables de entorno. Para obtener más información, vea Configuración en .NET.
Este ejemplo amplía el anterior para personalizar el ILoggerFactory
proporcionado por WebApplicationBuilder
. Agrega OpenTelemetry como proveedor de registro que transmite los registros a través del OTLP (protocolo OpenTelemetry):
var builder = WebApplication.CreateBuilder(args);
builder.Logging.AddOpenTelemetry(logging => logging.AddOtlpExporter());
builder.Services.AddSingleton<ExampleHandler>();
var app = builder.Build();
Si usa un contenedor de inserción de dependencias sin un host, use AddLogging para configurar y agregue ILoggerFactory
al contenedor.
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
// Add services to the container including logging
var services = new ServiceCollection();
services.AddLogging(builder => builder.AddConsole());
services.AddSingleton<ExampleService>();
IServiceProvider serviceProvider = services.BuildServiceProvider();
// Get the ExampleService object from the container
ExampleService service = serviceProvider.GetRequiredService<ExampleService>();
// Do some pretend work
service.DoSomeWork(10, 20);
class ExampleService(ILogger<ExampleService> logger)
{
public void DoSomeWork(int x, int y)
{
logger.LogInformation("DoSomeWork was called. x={X}, y={Y}", x, y);
}
}
Ejemplo anterior:
ILoggerFactory
configurado para escribir en la consolaExampleService
al contenedorExampleService
desde el contenedor de inserción de dependencias que también creó automáticamente un ILogger<ExampleService>
que se usará como argumento constructor.ExampleService.DoSomeWork
que usó el ILogger<ExampleService>
para registrar un mensaje en la consola.La configuración de registro se establece en código o a través de orígenes externos, como archivos de configuración y variables de entorno. El uso de la configuración externa es beneficioso siempre que sea posible porque se puede cambiar sin volver a compilar la aplicación. Sin embargo, algunas tareas, como establecer proveedores de registro, solo se pueden configurar desde el código.
En el caso de las aplicaciones que usan un host, la configuración de registro se proporciona normalmente en la sección "Logging"
de appsettings.{Environment}
archivos .json. En el caso de las aplicaciones que no usan un host, los orígenes de configuración externos se configuran explícitamente o se configuran en el código en su lugar.
El siguiente archivo appsettings.Development.json se genera mediante las plantillas de servicio de trabajo de .NET:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
}
}
En el código JSON anterior:
"Default"
, "Microsoft"
y "Microsoft.Hosting.Lifetime"
."Default"
se aplica a todas las categorías que no se especifican de otro modo, convirtiendo de hecho todos los valores predeterminados de todas las categorías en "Information"
. Puede invalidar este comportamiento especificando un valor para una categoría."Microsoft"
se aplica a todas las categorías que comienzan por "Microsoft"
."Microsoft"
se registra en el nivel de registro Warning
y superiores."Microsoft.Hosting.Lifetime"
es más específica que la categoría "Microsoft"
, por lo que la categoría "Microsoft.Hosting.Lifetime"
se registra en el nivel de registro "Information"
y superiores.LogLevel
se aplica a todos los proveedores de registro habilitados, excepto Windows EventLog.La propiedad Logging
puede tener LogLevel y registrar propiedades del proveedor de registro. LogLevel
especifica el nivel mínimo que se va a registrar para las categorías seleccionadas. En el código JSON anterior, se especifican los niveles de registro Information
y Warning
. LogLevel
indica la gravedad del registro y los valores están entre 0 y 6:
Trace
= 0, Debug
= 1, Information
= 2, Warning
= 3, Error
= 4, Critical
= 5 y None
= 6.
Cuando se especifica LogLevel
, el registro está habilitado para los mensajes tanto en el nivel especificado como en los superiores. En el código JSON anterior, se registra la categoría Default
para Information
y los niveles posteriores. Por ejemplo, se registran los mensajes Information
, Warning
, Error
y Critical
. Si no se especifica LogLevel
, el nivel predeterminado del registro es Information
. Para obtener más información, consulte Niveles de registro.
Una propiedad de proveedor puede especificar una propiedad de LogLevel
. LogLevel
en un proveedor especifica los niveles que se van a registrar para ese proveedor, e invalida la configuración de registro que no es de proveedor. Fíjese en el siguiente archivo appsettings.json:
{
"Logging": {
"LogLevel": {
"Default": "Error",
"Microsoft": "Warning"
},
"Debug": {
"LogLevel": {
"Default": "Information",
"Microsoft.Hosting": "Trace"
}
},
"EventSource": {
"LogLevel": {
"Default": "Warning"
}
}
}
}
La configuración de Logging.{ProviderName}.LogLevel
invalida la configuración de Logging.LogLevel
. En el código JSON anterior, el nivel de registro predeterminado del proveedor Debug
se establece en Information
:
Logging:Debug:LogLevel:Default:Information
La configuración anterior especifica el nivel de registro Information
para cada categoría de Logging:Debug:
, excepto Microsoft.Hosting
. Cuando se muestra una categoría específica, esa categoría invalida la categoría predeterminada. En el JSON anterior, las categorías de Logging:Debug:LogLevel
"Microsoft.Hosting"
y "Default"
invalidan la configuración de Logging:LogLevel
Se puede especificar el nivel de registro mínimo para:
Logging:EventSource:LogLevel:Default:Information
.Logging:LogLevel:Microsoft:Warning
.Logging:LogLevel:Default:Warning
Los registros situados por debajo del nivel mínimo no hacen lo siguiente:
Para suprimir todos los registros, especifique LogLevel.None. LogLevel.None
tiene un valor de 6, que es mayor que LogLevel.Critical
(5).
Si un proveedor admite ámbitos de registro, IncludeScopes
indica si están habilitados. Para obtener más información, consulte Ámbitos de registro.
El siguiente archivo appsettings.json contiene la configuración de todos los proveedores integrados:
{
"Logging": {
"LogLevel": {
"Default": "Error",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Warning"
},
"Debug": {
"LogLevel": {
"Default": "Information"
}
},
"Console": {
"IncludeScopes": true,
"LogLevel": {
"Microsoft.Extensions.Hosting": "Warning",
"Default": "Information"
}
},
"EventSource": {
"LogLevel": {
"Microsoft": "Information"
}
},
"EventLog": {
"LogLevel": {
"Microsoft": "Information"
}
},
"AzureAppServicesFile": {
"IncludeScopes": true,
"LogLevel": {
"Default": "Warning"
}
},
"AzureAppServicesBlob": {
"IncludeScopes": true,
"LogLevel": {
"Microsoft": "Information"
}
},
"ApplicationInsights": {
"LogLevel": {
"Default": "Information"
}
}
}
}
En el ejemplo anterior:
Logging.{ProviderName}.LogLevel
invalida la configuración de Logging.LogLevel
. Por ejemplo, el nivel de Debug.LogLevel.Default
invalida el nivel de LogLevel.Default
.Console
Debug
EventSource
EventLog
AzureAppServicesFile
AzureAppServicesBlob
ApplicationInsights
El nivel de registro se puede establecer con cualquiera de los proveedores de configuración. Por ejemplo, puede crear una variable de entorno persistente denominada Logging:LogLevel:Microsoft
con un valor de Information
.
Cree y asigne una variable de entorno persistente según el valor de nivel de registro.
:: Assigns the env var to the value
setx "Logging__LogLevel__Microsoft" "Information" /M
En una nueva instancia del símbolo del sistema, lea la variable de entorno.
:: Prints the env var value
echo %Logging__LogLevel__Microsoft%
La configuración del entorno anterior se conserva en el entorno. Para probar la configuración cuando se usa una aplicación creada con las plantillas de servicio de trabajo de .NET, use el comando dotnet run
en el directorio del proyecto después de asignar la variable de entorno.
dotnet run
Sugerencia
Después de establecer una variable de entorno, reinicie su entorno de desarrollo integrado (IDE) para asegurarse de que las variables de entorno recién agregadas están disponibles.
En Azure App Service, seleccione Nueva configuración de la aplicación en la página Configuración > Configuración. Los ajustes de configuración de Azure App Service:
Para más información sobre cómo establecer los valores de configuración de .NET mediante variables de entorno, vea Variables de entorno.
Para configurar el registro en el código, use la API ILoggingBuilder. Se puede acceder desde diferentes lugares:
ILoggerFactory
, configure en LoggerFactory.Create.En este ejemplo se muestra cómo establecer el proveedor de registro de la consola y varios filtros.
using Microsoft.Extensions.Logging;
using var loggerFactory = LoggerFactory.Create(static builder =>
{
builder
.AddFilter("Microsoft", LogLevel.Warning)
.AddFilter("System", LogLevel.Warning)
.AddFilter("LoggingConsoleApp.Program", LogLevel.Debug)
.AddConsole();
});
ILogger logger = loggerFactory.CreateLogger<Program>();
logger.LogDebug("Hello {Target}", "Everyone");
En el ejemplo AddFilter anterior se usa para ajustar el nivel de registro que está habilitado para varias categorías. AddConsole se usa para agregar el proveedor de registro de consola. De forma predeterminada, los registros con gravedad Debug
no están habilitados, pero como la configuración ajusta los filtros, el mensaje de depuración "Hola" se muestra en la consola.
Cuando se crea un objeto ILogger<TCategoryName>, el objeto ILoggerFactory selecciona una sola regla por proveedor para aplicar a ese registrador. Todos los mensajes escritos por una instancia ILogger
se filtran según las reglas seleccionadas. De las reglas disponibles, se selecciona la más específica para cada par de categoría y proveedor.
Cuando se crea un ILogger
para una categoría determinada, se usa el algoritmo siguiente para cada proveedor:
Cuando se crea un objeto ILogger
, se especifica una categoría. Esa categoría se incluye con cada mensaje de registro creado por esa instancia de ILogger
. La cadena de categoría es arbitraria, pero la convención es usar el nombre de clase completo. Por ejemplo, en una aplicación con un servicio definido como el objeto siguiente, la categoría podría ser "Example.DefaultService"
:
namespace Example
{
public class DefaultService : IService
{
private readonly ILogger<DefaultService> _logger;
public DefaultService(ILogger<DefaultService> logger) =>
_logger = logger;
// ...
}
}
Si se desea una categorización adicional, la convención consiste en usar un nombre jerárquico anexando una subcategoría al nombre de clase completo y especificando explícitamente la categoría mediante LoggerFactory.CreateLogger:
namespace Example
{
public class DefaultService : IService
{
private readonly ILogger _logger;
public DefaultService(ILoggerFactory loggerFactory) =>
_logger = loggerFactory.CreateLogger("Example.DefaultService.CustomCategory");
// ...
}
}
La llamada a CreateLogger
con un nombre fijo puede ser útil cuando se usa en varias clases o tipos, por lo que los eventos se pueden organizar por categoría.
ILogger<T>
es equivale a llamar a CreateLogger
con el nombre de tipo completo de T
.
En la tabla siguiente se enumeran los valores de LogLevel, el método de extensión Log{LogLevel}
oportuno y el uso sugerido:
LogLevel | Valor | Método | Descripción |
---|---|---|---|
Seguimiento | 0 | LogTrace | Contienen los mensajes más detallados. Estos mensajes pueden contener datos confidenciales de la aplicación. Están deshabilitados de forma predeterminada y no se deben habilitar en un entorno de producción. |
Depurar | 1 | LogDebug | Para depuración y desarrollo. Debido al elevado volumen, tenga precaución cuando lo use en producción. |
Información | 2 | LogInformation | Realiza el seguimiento del flujo general de la aplicación. Puede tener un valor a largo plazo. |
Advertencia | 3 | LogWarning | Para eventos anómalos o inesperados. Normalmente incluye errores o estados que no provocan un error en la aplicación. |
Error | 4 | LogError | Para los errores y excepciones que no se pueden controlar. Estos mensajes indican un error en la operación o solicitud actual, no un error de toda la aplicación. |
Critical) (Crítico) | 5 | LogCritical | Para los errores que requieren atención inmediata. Ejemplos: escenarios de pérdida de datos, espacio en disco insuficiente. |
Ninguno | 6 | Especifica que no se debe escribir ningún mensaje. |
En la tabla anterior, LogLevel
aparece de menor a mayor gravedad.
El primer parámetro del método Log, LogLevel, indica la gravedad del registro. En lugar de llamar a Log(LogLevel, ...)
, la mayoría de los desarrolladores llaman a los métodos de extensión Log{LogLevel}. Los métodos de extensiónLog{LogLevel}
llaman al método Log
y especifican LogLevel
. Por ejemplo, las dos llamadas de registro siguientes son funcionalmente equivalentes y generan el mismo registro:
public void LogDetails()
{
var logMessage = "Details for log.";
_logger.Log(LogLevel.Information, AppLogEvents.Details, logMessage);
_logger.LogInformation(AppLogEvents.Details, logMessage);
}
AppLogEvents.Details
es el identificador del evento y se representa implícitamente mediante un valor Int32 de constante. AppLogEvents
es una clase que expone varias constantes de identificador con nombre y se muestra en la sección Id. de evento del registro.
El siguiente código crea los registros Information
y Warning
:
public async Task<T> GetAsync<T>(string id)
{
_logger.LogInformation(AppLogEvents.Read, "Reading value for {Id}", id);
var result = await _repository.GetAsync(id);
if (result is null)
{
_logger.LogWarning(AppLogEvents.ReadNotFound, "GetAsync({Id}) not found", id);
}
return result;
}
En el código anterior, el primer Log{LogLevel}
parámetro, AppLogEvents.Read
, es el identificador de evento de registro. El segundo parámetro es una plantilla de mensaje con marcadores de posición para los valores de argumento proporcionados por el resto de parámetros de método. Los parámetros de método se explican detalladamente en la sección de la plantilla de mensaje más adelante en este artículo.
Configure el nivel de registro adecuado y llame a los métodos Log{LogLevel}
correctos para controlar el volumen de resultados del registro que se escriben en un soporte de almacenamiento determinado. Por ejemplo:
Trace
o Debug
genera un gran volumen de mensajes de registro detallados. Para controlar los costos y no superar los límites de almacenamiento de datos, registre los mensajes de nivel Trace
a Debug
en un almacén de datos de alto volumen y bajo costo. Considere la posibilidad de limitar Trace
y Debug
a categorías específicas.Warning
y Critical
debe generar pocos mensajes de registro.
Warning
.Trace
oDebug
al solucionar problemas. Para limitar la salida, establezca Trace
o Debug
solo para las categorías que se están investigando.El siguiente JSON establece Logging:Console:LogLevel:Microsoft:Information
:
{
"Logging": {
"LogLevel": {
"Microsoft": "Warning"
},
"Console": {
"LogLevel": {
"Microsoft": "Information"
}
}
}
}
Cada registro puede especificar un identificador de evento; EventId es una estructura con Id
y propiedades opcionales Name
de solo lectura. El código fuente de ejemplo usa la clase AppLogEvents
para definir los identificadores de evento:
using Microsoft.Extensions.Logging;
internal static class AppLogEvents
{
internal static EventId Create = new(1000, "Created");
internal static EventId Read = new(1001, "Read");
internal static EventId Update = new(1002, "Updated");
internal static EventId Delete = new(1003, "Deleted");
// These are also valid EventId instances, as there's
// an implicit conversion from int to an EventId
internal const int Details = 3000;
internal const int Error = 3001;
internal static EventId ReadNotFound = 4000;
internal static EventId UpdateNotFound = 4001;
// ...
}
Sugerencia
Para más información sobre la conversión de un int
en un EventId
, consulte Operador EventId.Implicit(Int32 to EventId).
Un id. de evento asocia un conjunto de eventos. Por ejemplo, todos los registros relacionados con la lectura de valores de un repositorio pueden ser 1001
.
El proveedor de registro puede registrar el id. de evento en un campo de identificador, en el mensaje de registro o no almacenarlo. El proveedor de depuración no muestra los identificadores de evento. El proveedor de consola muestra los identificadores de evento entre corchetes después de la categoría:
info: Example.DefaultService.GetAsync[1001]
Reading value for a1b2c3
warn: Example.DefaultService.GetAsync[4000]
GetAsync(a1b2c3) not found
Algunos proveedores de registro almacenan el identificador de evento en un campo, lo que permite filtrar por el id.
Cada API de registro usa una plantilla de mensaje. La plantilla de mensaje puede contener marcadores de posición para los que se proporcionan argumentos. Use los nombres de los marcadores de posición, no números. El orden de los marcadores de posición, no sus nombres, determina qué parámetros se usan para proporcionar sus valores. En el código siguiente, los nombres de parámetro están fuera de la secuencia en la plantilla de mensaje:
string p1 = "param1";
string p2 = "param2";
_logger.LogInformation("Parameter values: {p2}, {p1}", p1, p2);
El código anterior crea un mensaje de registro con los valores de parámetro en secuencia:
Parameter values: param1, param2
Nota
Hay que tener cuidado al usar varios marcadores de posición dentro de una sola plantilla de mensajes, ya que están basados en ordinales. Los nombres no se usan para alinear los argumentos con los marcadores de posición.
Este enfoque permite a los proveedores de registro implementar registro semántico o estructurado. Los propios argumentos se pasan al sistema de registro, no solo a la plantilla de mensaje con formato. Esto permite a los proveedores de registro almacenar los valores de parámetro como campos. Observe el siguiente método de registrador:
_logger.LogInformation("Getting item {Id} at {RunTime}", id, DateTime.Now);
Por ejemplo, al registrar en Azure Table Storage:
ID
y RunTime
.RunTime
determinado sin necesidad de analizar el tiempo de espera del mensaje de texto.Las plantillas de mensajes de registro admiten el formato de marcadores de posición. Las plantillas pueden especificar cualquier formato válido para el argumento del tipo especificado. Por ejemplo, fíjese en la siguiente plantilla de mensajes del registrador Information
:
_logger.LogInformation("Logged on {PlaceHolderName:MMMM dd, yyyy}", DateTimeOffset.UtcNow);
// Logged on January 06, 2022
En el ejemplo anterior, la instancia DateTimeOffset
es el tipo que corresponde a PlaceHolderName
en la plantilla de mensajes del registrador. Este nombre puede ser cualquier cosa, ya que los valores están basados en ordinales. El formato MMMM dd, yyyy
es válido para el tipo DateTimeOffset
.
Para más información sobre el formato de DateTime
y DateTimeOffset
, consulte Cadenas de formato de fecha y hora personalizadas.
En los ejemplos siguientes se muestra cómo dar formato a una plantilla de mensajes mediante la sintaxis del marcador de posición {}
. Además, se muestra un ejemplo de escape de la sintaxis del marcador de posición {}
con su salida. Por último, también se muestra la interpolación de cadenas con marcadores de posición de plantillas:
logger.LogInformation("Number: {Number}", 1); // Number: 1
logger.LogInformation("{{Number}}: {Number}", 3); // {Number}: 3
logger.LogInformation($"{{{{Number}}}}: {{Number}}", 5); // {Number}: 5
Sugerencia
Los métodos de registrador tienen sobrecargas que toman un parámetro de excepción:
public void Test(string id)
{
try
{
if (id is "none")
{
throw new Exception("Default Id detected.");
}
}
catch (Exception ex)
{
_logger.LogWarning(
AppLogEvents.Error, ex,
"Failed to process iteration: {Id}", id);
}
}
El registro de excepciones es específico del proveedor.
Si no se establece el nivel de registro predeterminado, su valor será Information
.
Por ejemplo, observe la siguiente aplicación de servicio de trabajo:
Con la configuración anterior, al navegar a la página de privacidad o de inicio, se generan muchos mensajes de Trace
, Debug
y Information
con Microsoft
en el nombre de la categoría.
El código siguiente establece el nivel de registro predeterminado cuando este no se establece en la configuración:
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
builder.Logging.SetMinimumLevel(LogLevel.Warning);
using IHost host = builder.Build();
await host.RunAsync();
Se invoca una función de filtro para todos los proveedores y las categorías que no tienen reglas asignadas mediante configuración o código:
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
builder.Logging.AddFilter((provider, category, logLevel) =>
{
return provider.Contains("ConsoleLoggerProvider")
&& (category.Contains("Example") || category.Contains("Microsoft"))
&& logLevel >= LogLevel.Information;
});
using IHost host = builder.Build();
await host.RunAsync();
El código anterior muestra los registros de la consola cuando la categoría contiene Example
o Microsoft
y el nivel de registro es Information
o superior.
Un ámbito agrupa un conjunto de operaciones lógicas. Esta agrupación se puede utilizar para adjuntar los mismos datos para cada registro que se crea como parte de un conjunto. Por ejemplo, cada registro creado como parte del procesamiento de una transacción puede incluir el identificador de dicha transacción.
Un ámbito:
Los siguientes proveedores admiten ámbitos:
Use un ámbito encapsulando las llamadas de registrador en un bloque using
:
public async Task<T> GetAsync<T>(string id)
{
T result;
var transactionId = Guid.NewGuid().ToString();
using (_logger.BeginScope(new List<KeyValuePair<string, object>>
{
new KeyValuePair<string, object>("TransactionId", transactionId),
}))
{
_logger.LogInformation(
AppLogEvents.Read, "Reading value for {Id}", id);
var result = await _repository.GetAsync(id);
if (result is null)
{
_logger.LogWarning(
AppLogEvents.ReadNotFound, "GetAsync({Id}) not found", id);
}
}
return result;
}
El JSON siguiente habilita ámbitos para el proveedor de la consola:
{
"Logging": {
"Debug": {
"LogLevel": {
"Default": "Information"
}
},
"Console": {
"IncludeScopes": true,
"LogLevel": {
"Microsoft": "Warning",
"Default": "Information"
}
},
"LogLevel": {
"Default": "Debug"
}
}
}
El código siguiente permite ámbitos para el proveedor de la consola:
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
builder.Logging.ClearProviders();
builder.Logging.AddConsole(options => options.IncludeScopes = true);
using IHost host = builder.Build();
await host.RunAsync();
El código siguiente registra en Main
mediante la obtención de una instancia de ILogger
de inserción de dependencias después de compilar el host:
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using IHost host = Host.CreateApplicationBuilder(args).Build();
var logger = host.Services.GetRequiredService<ILogger<Program>>();
logger.LogInformation("Host created.");
await host.RunAsync();
El código anterior se basa en dos paquetes NuGet:
El archivo del proyecto sería similar a este:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.1" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="7.0.0" />
</ItemGroup>
</Project>
El registro debe ser tan rápido que no merezca la pena el costo de rendimiento del código asincrónico. Si un almacén de datos de registro es lento, no escriba directamente en él. Considere la posibilidad de escribir primero los mensajes de registro en un almacén rápido y, después, moverlos al almacén lento. Por ejemplo, al iniciar sesión en SQL Server, no lo haga directamente en un método Log
, ya que los métodos Log
son sincrónicos. En su lugar, agregue sincrónicamente mensajes de registro a una cola en memoria y haga que un trabajo en segundo plano extraiga los mensajes de la cola para realizar el trabajo asincrónico de insertar datos en SQL Server.
La API de registro no incluye un escenario que permita cambiar los niveles de registro mientras se ejecuta una aplicación. No obstante, algunos proveedores de configuración pueden volver a cargar la configuración, lo que tiene efecto inmediato en la configuración del registro. Por ejemplo, el Proveedor de configuración de archivo vuelve a cargar la configuración de registro de forma predeterminada. Si se cambia la configuración en el código mientras se ejecuta una aplicación, la aplicación puede llamar a IConfigurationRoot.Reload para actualizar la configuración de registro de la aplicación.
Las interfaces e implementaciones ILogger<TCategoryName> y ILoggerFactory se incluyen en la mayoría de los SDK de .NET como referencia implícita del paquete. También están disponibles explícitamente en los siguientes paquetes NuGet cuando no se hace referencia implícitamente a ellos:
Para obtener más información sobre qué SDK de .NET incluye referencias de paquete implícitas, consulte SDK de .NET: tabla en espacio de nombres implícito.
Comentarios de .NET
.NET es un proyecto de código abierto. Seleccione un vínculo para proporcionar comentarios:
Cursos
Módulo
Aplicación de formato a datos alfanuméricos para su presentación en C# - Training
Explore los métodos básicos de C# para dar formato a datos alfanuméricos.
Documentación
Formato de registro de la consola - .NET
Aprenda a usar e implementar el formato de registro de consola personalizado en las aplicaciones .NET. Registre y cree nuevos formateadores de registro para mejorar el registro de aplicaciones.
Implementación de un proveedor de registro personalizado - .NET
Descubra cómo implementar un proveedor de registro personalizado con registros coloreados, escribiendo implementaciones personalizadas de ILogger e ILoggerProvider en C#.
Registros en .NET Core y ASP.NET Core
Obtenga información sobre cómo usar la plataforma de registro proporcionada por el paquete NuGet Microsoft.Extensions.Logging.