1. Introducción
En programación el logging no es simplemente "imprimir algo en la consola". El logging es tu caja negra, GPS-tracker e indicador en uno. Sin logs, una aplicación grande se convierte en una caja negra misteriosa: "¿por qué el servicio se colgó?", "¿por qué el usuario no recibió el correo?", "¿alguien había ejecutado este módulo en los últimos 3 meses?" — a todas esas preguntas muchas veces solo se puede responder si los logs se almacenan y están accesibles.
¿Para qué sirve el logging en la práctica?
Búsqueda y diagnóstico de errores
Si la aplicación se cayó — los logs dirán dónde y por qué. Si no se cayó pero funciona raro — los logs indicarán los pasos que llevaron a eso.
Monitorización del estado
Con los logs puedes saber si el sistema está funcionando ahora, cuántas peticiones recibe el servidor, si aparecen errores, quién y qué está haciendo.
Seguridad
Registrar intentos de acceso no autorizado, actividad sospechosa, errores de autenticación.
Auditoría
Quién, qué y cuándo hizo algo. Si un admin malintencionado se fue y borró datos, por los logs se puede reconstruir todo (o al menos entender qué hizo).
Soporte en desarrollo y operaciones
Los logs no son solo para el programador, también para QA, operadores y admins. Dentro de seis meses te vas a agradecer a ti mismo: '¡Gracias por añadir logs!'
De Console.WriteLine al logging industrial
La reacción inicial del novato: "¿No basta con hacer Console.WriteLine?". Para programas pequeños de aprendizaje eso puede ser suficiente. Pero cuando la app corre en servidor, es concurrente, o la usan decenas o cientos de usuarios, la consola ya no ayuda. Necesitas:
- Separar información importante y debug.
- Enviar logs no solo a la consola, sino a archivos, bases de datos, sistemas centralizados.
- Cambiar el nivel de detalle de los logs (mínimo — solo errores, máximo — todo).
- Añadir automáticamente fecha, hora y metadata a las entradas.
- Configurar de forma flexible.
- Y lo principal — no tener que cambiar el código para redirigir logs a otro lugar.
Aquí empieza la era de los "loggers" de verdad.
2. Fundamentos de un sistema moderno de logging en .NET
En el ecosistema .NET existe un framework estándar, potente y flexible para logging — Microsoft.Extensions.Logging. Es parte de la "nueva ola" de librerías .NET que aparecieron con ASP.NET Core, pero hoy se usa en todas partes: servidor, desktop e incluso móvil.
¿Qué hace bueno a este framework?
- Abstracción — no te ata a una implementación concreta (el logger puede escribir en archivo, consola, cloud o en todo a la vez).
- Soporte de niveles de logging (Trace, Debug, Information, Warning, Error, Critical).
- Integración con el contenedor DI y en todas las apps .NET modernas.
- Ecosistema rico: logging estructurado, formatters avanzados e integraciones.
Conceptos y clases principales
Conozcamos los objetos clave que necesitaremos para trabajar con Microsoft.Extensions.Logging:
| Clase/Interfaz | Propósito |
|---|---|
|
Interfaz para logging, tipada por clase |
|
Interfaz genérica del logger |
|
Fábrica para crear instancias de loggers |
|
Permite configurar el logging en la aplicación |
|
Enumeración de niveles de logs (Trace, Debug, Information, ...) |
Niveles de logging
Separar mensajes por nivel de importancia permite filtrar el "ruido" y encontrar lo necesario:
| Nivel (LogLevel) | ¿Para qué usar? |
|---|---|
|
Trazas extremadamente detalladas, "ruido", datos temporales |
|
Información principal de debugging |
|
Mensajes clave de eventos para funcionamiento normal |
|
Advertencias sobre posibles problemas, pero el sistema sigue |
|
Errores que requieren atención, pero la app está viva |
|
Fallos críticos que amenazan todo el sistema |
3. Práctica: añadimos logging a nuestra aplicación
No vamos a escribir código abstracto; continuamos con nuestra app demo. Supongamos que ya tenemos una clase Calculator sencilla que vamos ampliando durante el curso.
Ejemplo: calculadora básica
public class Calculator
{
public int Add(int a, int b)
{
return a + b;
}
// Resto de métodos...
}
Ahora integremos logging en ella. Para eso necesitamos la interfaz ILogger<Calculator>, que recibiremos desde afuera (por ejemplo, via Dependency Injection, DI).
using Microsoft.Extensions.Logging;
public class Calculator
{
private readonly ILogger<Calculator> _logger;
public Calculator(ILogger<Calculator> logger)
{
_logger = logger;
}
public int Add(int a, int b)
{
int result = a + b;
_logger.LogInformation("Se realizó una suma: {A} + {B} = {Result}", a, b, result);
return result;
}
}
Dato interesante:
En lugar de concatenar strings, los loggers soportan plantillas y parámetros nombrados ({A}, {B}, {Result}), lo que permite logs estructurados y más fáciles de procesar y buscar automáticamente.
4. Cómo crear y configurar un logger en una app de consola
1. Añadir paquetes NuGet
En tu proyecto necesitarás:
- Microsoft.Extensions.Logging
- Microsoft.Extensions.Logging.Console (si quieres escribir en consola)
- (opcional) otros providers según necesidad
2. Configurar el logger
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
// Creamos el contenedor DI
var serviceProvider = new ServiceCollection()
.AddLogging(builder => {
builder.AddConsole(); // Salida a consola
builder.SetMinimumLevel(LogLevel.Debug); // Nivel mínimo de logs
})
.BuildServiceProvider();
// Obtenemos el logger del tipo necesario
var logger = serviceProvider.GetRequiredService<ILogger<Calculator>>();
var calculator = new Calculator(logger);
calculator.Add(5, 3); // El mensaje irá a los logs
Error típico de novatos
"¿Por qué el log no aparece en la consola?" — revisa si añadiste el provider correcto (.AddConsole()) y si el nivel mínimo está bien configurado (SetMinimumLevel). Si el nivel es superior, ¡los mensajes pueden simplemente filtrarse!
5. Novedades útiles
Registrando errores y situaciones anómalas
Supongamos que queremos loggear una división por cero. Añadimos el método correspondiente:
public int Divide(int a, int b)
{
if (b == 0)
{
_logger.LogError("Intento de división por cero! a={A}", a);
throw new DivideByZeroException();
}
int result = a / b;
_logger.LogInformation("Se realizó una división: {A} / {B} = {Result}", a, b, result);
return result;
}
¿Por qué es útil?
En una app real, cuando algo sale mal, los logs con nivel Error suelen llamar atención: se envían a admins, se resaltan en monitorización y se usan para alertas/notificaciones.
Uso de categorías y etiquetas (scopes)
El logger en .NET soporta los llamados scopes — metadatos adicionales que se añaden automáticamente a todos los logs dentro de un bloque de código. Por ejemplo, al procesar una petición web o una sesión de usuario, puedes añadir su id al scope.
using (_logger.BeginScope("UserId: {UserId}", 42))
{
_logger.LogInformation("Comenzó el procesamiento de los datos del usuario");
// ...
}
Todos los mensajes dentro del bloque recibirán la etiqueta adicional UserId: 42, lo que ayuda a filtrar logs por usuario u operación.
Ejemplo: niveles de logging en acción
_logger.LogTrace("Esto es Trace — casi nadie lo verá");
_logger.LogDebug("Esto es Debug — para desarrolladores");
_logger.LogInformation("Esto es Information — para eventos de funcionamiento normal");
_logger.LogWarning("Esto es Warning — advertencia sobre posible problema");
_logger.LogError("Esto es Error — error que requiere atención");
_logger.LogCritical("Esto es Critical — ¡el sistema arde, llama a los bomberos!");
Si configuraste SetMinimumLevel(LogLevel.Information), verás solo mensajes de niveles Information, Warning, Error, Critical.
Consejo:
Deja Trace y Debug para diagnóstico detallado en desarrollo; en producción normalmente activan solo Information y superiores para no inflar los logs y no perder lo importante entre el "ruido".
Esquema visual: arquitectura del logging moderno
graph TD
A[Código de la aplicación] --ILogger<YourClass>--> B[Microsoft.Extensions.Logging]
B --> C1[Console Provider]
B --> C2[File Provider]
B --> C3[Cloud/Database Provider]
C1 -.-> D1[Logs en consola]
C2 -.-> D2[Logs en archivo]
C3 -.-> D3[Logs en sistema de monitorización]
subgraph Providers
C1
C2
C3
end
6. Funcionalidades adicionales y extensiones
Logging estructurado:
Los valores de los parámetros se pueden almacenar no solo en la cadena, sino como pares clave-valor, lo que permite buscar y agregar por esos parámetros (por ejemplo con Seq, ELK/ElasticSearch o Application Insights).
Providers de logging:
Puedes añadir muchos providers: archivo, Windows EventLog, Azure, etc.
Configurar logging vía appsettings.json:
En ASP.NET Core el logging se configura fácilmente desde el archivo de configuración sin recompilar la app.
Ejemplo de configuración de niveles mínimos via config (appsettings.json):
{
"Logging": {
"LogLevel": {
"Default": "Information",
"MyApp.Calculator": "Debug",
"Microsoft": "Warning"
}
}
}
7. Errores típicos al trabajar con Microsoft.Extensions.Logging
Error #1: Elección incorrecta del nivel de logging.
Usar LogInformation para errores en vez de LogError o LogCritical dificulta encontrar problemas en producción.
Error #2: Ignorar el logging estructurado.
Concatenar strings en vez de usar plantillas con placeholders ({Parameter}) te hace perder ventajas del logging estructurado, como buscar por parámetros.
Error #3: Configurar mal los niveles de logging.
Si el nivel mínimo está demasiado alto (por ejemplo Warning en vez de Debug), mensajes importantes pueden filtrarse.
Error #4: Logging excesivo o insuficiente.
Logs demasiado detallados (por ejemplo Trace en producción) crean "ruido", y la falta de logs dificulta el diagnóstico.
GO TO FULL VERSION