Logs em aplicações .NET: como deixar sua aplicação realmente observável

Logs em aplicações .NET: como deixar sua aplicação realmente observável
Publicado em 02/11/2026 por Admin

Imagine que sua aplicação .NET está funcionando normalmente há semanas. De repente, um cliente abre um chamado informando que determinada operação está demorando muito para ser concluída.

Você acessa os logs, mas encontra apenas algumas mensagens genéricas:

  • Erro ao processar requisição.
  • Operação concluída.
  • Falha inesperada.
  • Erro interno do servidor.

Agora surge a pergunta: qual componente apresentou problema? Quanto tempo a operação demorou? A falha aconteceu no banco de dados ou em uma API externa? Outros usuários foram afetados?

Esse é um dos problemas mais comuns em aplicações que não possuem uma estratégia adequada de observabilidade.

Registrar mensagens em arquivos ou no console é importante, mas isso representa apenas uma parte da solução.

Em aplicações modernas, especialmente aquelas construídas com ASP.NET Core, APIs REST, microsserviços e integrações externas, precisamos ir além dos logs tradicionais.

Neste artigo, vamos entender como estruturar logs em aplicações .NET, utilizar logging estruturado, trabalhar com correlação de requisições e conhecer o papel do OpenTelemetry na construção de aplicações realmente observáveis.

1. Logging e observabilidade são coisas diferentes

É comum encontrar desenvolvedores utilizando os termos logging e observabilidade como se fossem sinônimos.

Entretanto, existe uma diferença importante.

Logging consiste em registrar acontecimentos durante a execução de uma aplicação.

Observabilidade é a capacidade de compreender o comportamento interno de um sistema a partir dos dados que ele disponibiliza.

Uma estratégia completa de observabilidade normalmente trabalha com três pilares:

Logs

Registram eventos específicos que aconteceram durante a execução.

Exemplos:

  • Uma requisição HTTP foi recebida.
  • Um usuário realizou uma operação.
  • Uma integração externa retornou erro.
  • Uma transação no banco de dados falhou.

Métricas

Representam informações quantitativas sobre o comportamento da aplicação.

Exemplos:

  • Quantidade de requisições por minuto.
  • Tempo médio de resposta.
  • Número de erros HTTP 500.
  • Consumo de memória.
  • Quantidade de conexões ativas.

Distributed Tracing

Permite acompanhar uma operação enquanto ela percorre diferentes componentes de um sistema.

Imagine uma requisição que passa por:

  1. API principal.
  2. Serviço de autenticação.
  3. Microsserviço de pagamentos.
  4. Banco de dados.
  5. Serviço externo de notificações.

Com distributed tracing, podemos acompanhar essa jornada e identificar exatamente onde ocorreu uma lentidão.

A combinação desses três elementos oferece uma visão muito mais completa do sistema.

2. Utilize ILogger em vez de implementar logging manualmente

O .NET disponibiliza uma infraestrutura de logging por meio do namespace Microsoft.Extensions.Logging.

A principal interface utilizada é ILogger<T>.

Ela permite registrar mensagens sem acoplar diretamente a aplicação a uma ferramenta específica de logging.

Exemplo:

 
public class OrderService
{
    private readonly ILogger<OrderService> _logger;

    public OrderService(
        ILogger<OrderService> logger)
    {
        _logger = logger;
    }

    public void ProcessOrder(int orderId)
    {
        _logger.LogInformation(
            "Processing order {OrderId}",
            orderId);

        // Business logic
    }
}
 

Nesse exemplo, o logger recebe a categoria associada à classe OrderService.

Isso facilita a identificação da origem das mensagens e permite configurar filtros específicos para diferentes componentes.

Uma das grandes vantagens é que podemos trocar ou adicionar provedores de logging sem precisar modificar toda a lógica da aplicação.

3. Prefira logging estruturado

Um erro bastante comum é utilizar interpolação de strings para registrar mensagens.

Por exemplo:

 
_logger.LogInformation(
    $"Order {orderId} processed successfully");
 

Embora funcione, essa abordagem não aproveita adequadamente os recursos de logging estruturado.

Prefira:

 
_logger.LogInformation(
    "Order {OrderId} processed successfully",
    orderId);
 

A diferença é importante.

Na segunda abordagem, OrderId é registrado como uma propriedade estruturada.

Isso permite realizar consultas e filtros diretamente sobre os campos armazenados pela plataforma de observabilidade.

Imagine procurar todas as operações relacionadas ao pedido 1250.

Com logs estruturados, essa pesquisa se torna muito mais simples do que procurar textos dentro de mensagens.

Outra recomendação é utilizar templates de mensagens estáticos, principalmente em caminhos de execução frequentes.

Isso também ajuda a evitar trabalho desnecessário de formatação.

4. Utilize corretamente os níveis de log

O .NET disponibiliza diferentes níveis para classificar a importância dos eventos.

Os principais são:

Nível Quando utilizar
Trace Informações extremamente detalhadas de execução
Debug Informações úteis durante desenvolvimento e diagnóstico
Information Eventos normais e relevantes da aplicação
Warning Situações inesperadas que não interrompem necessariamente o fluxo
Error Falhas que impedem uma operação específica
Critical Problemas graves que comprometem o funcionamento do sistema

Exemplo:

 
_logger.LogInformation(
    "Starting payment processing");

_logger.LogWarning(
    "Payment provider response time is high");

_logger.LogError(
    exception,
    "Payment processing failed");

_logger.LogCritical(
    exception,
    "Unable to connect to the primary database");
 

Um cuidado importante: não transforme todos os acontecimentos em erros.

Se uma operação de negócio for recusada por uma regra válida, isso não significa necessariamente que ocorreu uma falha técnica.

Uma boa classificação reduz ruídos e facilita a identificação de problemas reais.

5. Utilize Exception Logging corretamente

Outro problema recorrente é registrar apenas a mensagem da exceção.

Veja:

 
catch (Exception ex)
{
    _logger.LogError(
        "Error: {Message}",
        ex.Message);
}
 

Essa implementação perde informações importantes, como stack trace e detalhes da exceção original.

Prefira:

 
catch (Exception ex)
{
    _logger.LogError(
        ex,
        "Error processing order {OrderId}",
        orderId);

    throw;
}
 

Dessa maneira, a exceção é registrada com seus detalhes e continua sendo propagada.

Naturalmente, a decisão de propagar ou tratar a exceção depende da responsabilidade daquele componente.

O importante é não esconder falhas inesperadamente.

6. Utilize um identificador para correlacionar requisições

Em aplicações distribuídas, identificar uma mensagem isoladamente nem sempre é suficiente.

Imagine que um cliente realizou uma operação que passou por três APIs diferentes.

Cada serviço registrou seus próprios logs.

Como descobrir quais mensagens pertencem à mesma operação?

Uma solução é utilizar identificadores de correlação.

No ASP.NET Core, podemos trabalhar com identificadores de requisição e também com o contexto de tracing disponibilizado por System.Diagnostics.Activity.

Por exemplo:

 
using System.Diagnostics;

public class PaymentService
{
    private readonly ILogger<PaymentService> _logger;

    public PaymentService(
        ILogger<PaymentService> logger)
    {
        _logger = logger;
    }

    public void ProcessPayment()
    {
        var traceId = Activity.Current?.TraceId;

        _logger.LogInformation(
            "Processing payment. TraceId: {TraceId}",
            traceId);
    }
}
 

Quando existe uma atividade ativa, o TraceId permite relacionar eventos associados à mesma operação distribuída.

Essa abordagem se torna especialmente importante em arquiteturas baseadas em microsserviços.

7. Conheça o OpenTelemetry no ecossistema .NET

Se existe uma tecnologia que merece atenção quando falamos sobre observabilidade, é o OpenTelemetry.

O OpenTelemetry é um padrão aberto para instrumentação, coleta e exportação de dados de telemetria.

Ele permite trabalhar com logs, métricas e traces utilizando uma abordagem independente de fornecedor.

No ecossistema .NET, existem bibliotecas específicas para integrar o OpenTelemetry aos recursos nativos da plataforma.

Alguns pacotes importantes são:

  • OpenTelemetry.Extensions.Hosting
  • OpenTelemetry.Instrumentation.AspNetCore
  • OpenTelemetry.Instrumentation.Http
  • OpenTelemetry.Exporter.OpenTelemetryProtocol

Um exemplo simplificado de configuração em uma aplicação ASP.NET Core:

 
var builder = WebApplication.CreateBuilder(args);

builder.Services
    .AddOpenTelemetry()
    .WithTracing(tracing =>
    {
        tracing
            .AddAspNetCoreInstrumentation()
            .AddHttpClientInstrumentation()
            .AddOtlpExporter();
    });

var app = builder.Build();

app.MapGet("/", () => "Application running");

app.Run();
 

Esse exemplo configura instrumentação para requisições ASP.NET Core e chamadas HTTP realizadas pela aplicação.

O exportador OTLP permite encaminhar os dados para uma infraestrutura compatível com o protocolo OpenTelemetry.

Para uma implementação completa, também precisamos configurar métricas, logs, recursos da aplicação e o destino de exportação.

É importante lembrar que os pacotes necessários e suas versões devem ser compatíveis com o projeto.

8. Não transforme seus logs em um problema de segurança

Logs também podem representar riscos.

Uma aplicação pode acabar registrando informações que não deveriam estar disponíveis em arquivos ou plataformas de monitoramento.

Evite registrar:

  • Senhas.
  • Tokens de autenticação.
  • Chaves de API.
  • Dados completos de cartões.
  • Informações pessoais desnecessárias.
  • Conteúdo sensível de requisições.

Também é importante avaliar quem pode acessar a plataforma de logs e por quanto tempo os dados serão armazenados.

Uma boa estratégia de observabilidade precisa considerar segurança, privacidade, retenção e custos.

9. Boas práticas para aplicações .NET

Para deixar sua aplicação realmente observável, considere implementar as seguintes práticas:

  1. Utilize ILogger<T> em seus componentes.
  2. Prefira logging estruturado.
  3. Defina níveis de log coerentes.
  4. Registre exceções com seus detalhes.
  5. Utilize identificadores de correlação.
  6. Implemente métricas para operações importantes.
  7. Utilize distributed tracing quando trabalhar com múltiplos serviços.
  8. Considere OpenTelemetry como padrão de instrumentação.
  9. Evite registrar informações sensíveis.
  10. Configure alertas para situações críticas.

Conclusão

Uma aplicação que funciona corretamente não é necessariamente uma aplicação fácil de diagnosticar.

À medida que os sistemas crescem, aumentam também as dependências, integrações e possibilidades de falhas.

Por isso, investir em observabilidade desde o início pode reduzir significativamente o tempo necessário para identificar e resolver problemas.

No ecossistema .NET, temos ferramentas muito interessantes para construir essa estrutura, começando pelo ILogger, passando por métricas e tracing com System.Diagnostics e chegando ao OpenTelemetry.

O objetivo não deve ser simplesmente registrar mais informações, mas produzir dados que realmente ajudem a entender o comportamento da aplicação.

Afinal, uma aplicação bem desenvolvida também precisa ser uma aplicação que conseguimos monitorar, investigar e manter.