1. Introdução
Em programação logging não é só "mostrar algo no console". Logging é sua caixa-preta, GPS-tracker e indicador tudo-em-um. Sem logs um grande programa vira uma caixa-preta-mistério: "por que o serviço travou?", "por que o usuário não recebeu o e-mail?", "alguém ao menos rodou esse módulo nos últimos 3 meses?" — muitas vezes só dá pra responder essas perguntas se os logs estiverem armazenados e acessíveis.
Por que o logging é necessário na prática?
Busca e diagnóstico de erros
Se o programa caiu — os logs vão contar onde e por quê. Se não caiu, mas está se comportando de forma estranha — os logs vão mostrar os passos que levaram a isso.
Monitoramento do estado
Pelos logs dá pra saber se o sistema está funcionando agora, quantas requisições chegam ao servidor, se erros aparecem, quem e o que está fazendo.
Segurança
Log de tentativas de acesso não autorizado, atividade suspeita, falhas de autenticação.
Auditoria
Quem fez o quê e quando. Se um admin mal-intencionado saiu e apagou dados, pelos logs dá pra reconstruir tudo (ou pelo menos entender o que ele fez).
Suporte no desenvolvimento e operação
Logs não são só para o desenvolvedor, mas também para o tester, operador, admin. Depois de seis meses você vai se agradecer: 'Obrigado por ter adicionado logs!'
De Console.WriteLine ao logging industrial
A reação inicial de quem está começando: "Sério, não basta só Console.WriteLine?". Para programas pequenos de estudo isso realmente é suficiente. Mas quando a aplicação roda no servidor, trabalha em paralelo, ou é usada por dezenas ou centenas de usuários, o console já não ajuda. É preciso:
- Separar informação importante da informação de debug.
- Enviar logs não só ao console, mas também para arquivos, bancos de dados, sistemas centralizados.
- Alterar o nível de verbosidade dos logs (mínimo — só erros, máximo — tudo mesmo).
- Complementar automaticamente as entradas com data, hora e metadata adicional.
- Configurar de forma flexível.
- E o mais importante — não ficar mudando o código só pra redirecionar os logs pra outro lugar.
Aí começa a era dos "loggers de verdade".
2. Fundamentos de um sistema moderno de logging no .NET
No ecossistema .NET existe um framework padrão, poderoso e flexível para logging — Microsoft.Extensions.Logging. Faz parte da "nova onda" de bibliotecas .NET que vieram com o ASP.NET Core, mas hoje é usado em todo lugar: servidor, desktop e até mobile.
O que torna esse framework bom?
- Abstração — não te prende a uma implementação específica (o logger pode escrever em arquivo, console, cloud ou em todos ao mesmo tempo).
- Suporte a níveis de logging (Trace, Debug, Information, Warning, Error, Critical).
- Integração com o DI-container e suporte em todas as aplicações .NET modernas.
- Ecossistema rico de extensões: suporte a logging estruturado, formatters avançados e integrações.
Conceitos e classes principais
Vamos conhecer os objetos-chave que vamos usar com Microsoft.Extensions.Logging:
| Classe/Interface | Finalidade |
|---|---|
|
Interface para logging, tipada pelo tipo |
|
Interface genérica de logger |
|
Fábrica para criar instâncias de loggers |
|
Permite configurar logging na aplicação |
|
Enumeração de níveis de log (Trace, Debug, Information, ...) |
Níveis de logging
Separar mensagens por nível de importância permite filtrar o "ruído" e achar o que importa:
| Nível (LogLevel) | Quando usar? |
|---|---|
|
Debug super detalhado, "ruído", dados temporários |
|
Informação principal para depuração |
|
Mensagens de eventos chaves para funcionamento normal |
|
Avisos sobre possíveis problemas, mas o sistema continua |
|
Erros que exigem atenção, mas a aplicação ainda está viva |
|
Falhas críticas que ameaçam todo o sistema |
3. Prática: adicionando logging na nossa aplicação
Vamos evitar código abstrato e continuar desenvolvendo nossa aplicação de demonstração. Suponha que já temos uma classe Calculator simples, que vamos expandir ao longo do curso.
Exemplo: calculadora básica
public class Calculator
{
public int Add(int a, int b)
{
return a + b;
}
// Outros métodos...
}
Agora vamos embutir logging nela. Para isso precisamos da interface ILogger<Calculator>, que iremos receber de fora (por exemplo, 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("Execução de adição: {A} + {B} = {Result}", a, b, result);
return result;
}
}
Curiosidade:
Em vez de concatenar strings, os loggers suportam templates e parâmetros nomeados ({A}, {B}, {Result}), o que permite logs estruturados e fáceis de processar e buscar automaticamente depois.
4. Como criar e configurar um logger em um aplicativo de console
1. Adicionando pacotes NuGet
No seu projeto você vai precisar de:
- Microsoft.Extensions.Logging
- Microsoft.Extensions.Logging.Console (se quiser escrever no console)
- (opcional) outros providers, se precisar
2. Configurando o logger
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
// Criamos o DI-container
var serviceProvider = new ServiceCollection()
.AddLogging(builder => {
builder.AddConsole(); // Saída para o console
builder.SetMinimumLevel(LogLevel.Debug); // Nível mínimo de logs
})
.BuildServiceProvider();
// Pegamos a instância do logger do tipo necessário
var logger = serviceProvider.GetRequiredService<ILogger<Calculator>>();
var calculator = new Calculator(logger);
calculator.Add(5, 3); // A mensagem vai para os logs
Erro típico de quem está começando
"Por que o log não aparece no console?" — verifique se o provider necessário foi adicionado (.AddConsole()) e se o nível mínimo de logging foi corretamente definido (SetMinimumLevel). Se o nível estiver mais alto, as mensagens podem simplesmente ser "filtradas"!
5. Dicas úteis
Logando erros e situações anômalas
Suponha que queremos logar divisão por zero. Vamos adicionar o método correspondente:
public int Divide(int a, int b)
{
if (b == 0)
{
_logger.LogError("Tentativa de divisão por zero! a={A}", a);
throw new DivideByZeroException();
}
int result = a / b;
_logger.LogInformation("Execução de divisão: {A} / {B} = {Result}", a, b, result);
return result;
}
Por que isso é importante?
Em aplicações reais, quando algo dá errado, logs com nível Error normalmente chamam atenção especial: eles são enviados automaticamente para admins, aparecem em monitoramento e acionam alerts/notificações.
Uso de categorias e tags (scopes)
O logger no .NET suporta os chamados scopes — metadados adicionais que são automaticamente adicionados a todos os logs durante um bloco de código. Por exemplo, ao processar uma requisição web ou uma sessão de usuário, você pode adicionar o identificador ao scope.
using (_logger.BeginScope("UserId: {UserId}", 42))
{
_logger.LogInformation("Iniciou o processamento dos dados do usuário");
// ...
}
Todas as mensagens dentro do bloco receberão a tag adicional UserId: 42, o que ajuda depois a localizar logs por usuário ou operação.
Exemplo: níveis de logging em ação
_logger.LogTrace("Isso é Trace — quase ninguém vai ver");
_logger.LogDebug("Isso é Debug — para desenvolvedores");
_logger.LogInformation("Isso é Information — para eventos de funcionamento normal");
_logger.LogWarning("Isso é Warning — aviso sobre possível problema");
_logger.LogError("Isso é Error — erro que exige atenção");
_logger.LogCritical("Isso é Critical — O sistema está pegando fogo, precisa de bombeiro!");
Se você configurou SetMinimumLevel(LogLevel.Information), verá apenas mensagens dos níveis Information, Warning, Error, Critical.
Truque:
Deixe logs Trace e Debug para diagnóstico detalhado durante o desenvolvimento, e em produção geralmente habilite só Information e acima, pra não inflar os logs e não perder o que é importante no meio do "ruído".
Diagrama visual: arquitetura do logging moderno
graph TD
A[Código da aplicação] --ILogger<YourClass>--> B[Microsoft.Extensions.Logging]
B --> C1[Console Provider]
B --> C2[File Provider]
B --> C3[Cloud/Database Provider]
C1 -.-> D1[Logs no console]
C2 -.-> D2[Logs em arquivo]
C3 -.-> D3[Logs no sistema de monitoramento]
subgraph Providers
C1
C2
C3
end
6. Funcionalidades adicionais e extensões
Logging estruturado:
Os valores dos parâmetros podem ser armazenados não só como string, mas como chave-valor, permitindo buscas e agregações por esses parâmetros (por exemplo, via Seq, ELK/ElasticSearch ou Application Insights).
Providers de logging:
Você pode adicionar dezenas de providers diferentes: arquivo, Windows EventLog, Azure, etc.
Configurar logging via appsettings.json
No ASP.NET Core o logging pode ser configurado via arquivo de configuração, sem recompilar a aplicação.
Exemplo de configuração de nível mínimo via config (appsettings.json):
{
"Logging": {
"LogLevel": {
"Default": "Information",
"MyApp.Calculator": "Debug",
"Microsoft": "Warning"
}
}
}
7. Erros típicos ao trabalhar com Microsoft.Extensions.Logging
Erro nº1: Escolha errada do nível de logging.
Usar LogInformation para erros em vez de LogError ou LogCritical dificulta encontrar problemas em produção.
Erro nº2: Ignorar logging estruturado.
Concatenar strings em vez de usar templates com placeholders ({Parameter}) tira proveito do logging estruturado, como buscas por parâmetros.
Erro nº3: Configurar níveis de logging incorretamente.
Se o nível mínimo estiver configurado acima do necessário (por exemplo, Warning em vez de Debug), mensagens importantes podem ser filtradas.
Erro nº4: Logging excessivo ou insuficiente.
Logs muito verbosos (por exemplo, Trace em produção) geram "ruído", e ausência de logs dificulta diagnóstico.
GO TO FULL VERSION