Skip to main content

Integração com Sentry no ASP.NET Core | Dia a Dia | CSharp

  • Integração com Sentry no ASP.NET Core | Dia a Dia | CSharp

Visão geral

No ASP.NET Core, a integração padrão do mercado com Sentry é feita com o pacote Sentry.AspNetCore e a inicialização via builder.WebHost.UseSentry(). A própria documentação do Sentry trata esse como o caminho mais simples para inicializar o SDK no ASP.NET Core, e informa que as opções podem vir de appsettings.json, variáveis de ambiente ou código. O pacote Sentry.AspNetCore também inclui a integração de logging do ecossistema Microsoft.Extensions.Logging. (Sentry Docs)

O que o pacote entrega

Ao instalar Sentry.AspNetCore, você ganha:

  • captura de exceções não tratadas na pipeline do ASP.NET Core
  • integração com Microsoft.Extensions.Logging
  • suporte a configuração pelo sistema padrão do ASP.NET Core
  • suporte a tracing
  • opções de filtragem e enriquecimento como BeforeSend, BeforeBreadcrumb e processadores por DI. (Sentry Docs)

Pacote necessário

dotnet add package Sentry.AspNetCore

A página do ASP.NET Core no Sentry mostra a instalação do pacote Sentry.AspNetCore e indica que ele estende Sentry.Extensions.Logging e o SDK principal do Sentry. (Sentry Docs)

Padrão de configuração

O padrão mais limpo é:

  • deixar a maior parte das opções no appsettings.json
  • usar UseSentry() no Program.cs
  • sobrescrever em código apenas o que depende de lógica, como filtros e callbacks

A documentação diz explicitamente que as opções do appsettings.json são aplicadas antes do callback do UseSentry(). (Sentry Docs)


Estrutura recomendada

appsettings.json

Exemplo base e seguro para produção:

{
"Sentry": {
"Dsn": "https://SEU_DSN@sentry.io/PROJETO",
"Debug": false,
"DiagnosticLevel": "Error",
"SendDefaultPii": false,
"AttachStackTrace": true,
"MinimumBreadcrumbLevel": "Information",
"MinimumEventLevel": "Error",
"MaxBreadcrumbs": 50,
"TracesSampleRate": 0.1,
"EnableLogs": false
}
}

Esse formato é suportado oficialmente. A documentação mostra exemplos com Dsn, SendDefaultPii, MaxRequestBodySize, MinimumBreadcrumbLevel, MinimumEventLevel, AttachStackTrace, Debug, DiagnosticLevel e TracesSampleRate, além de informar que EnableLogs pode ser configurado em appsettings.json. (Sentry Docs)

Program.cs

using Sentry;

var builder = WebApplication.CreateBuilder(args);

builder.WebHost.UseSentry(options =>
{
options.SetBeforeSend((@event, hint) =>
{
// Exemplo: remover nome do servidor
@event.ServerName = null;
return @event;
});
});

builder.Services.AddControllers();

var app = builder.Build();

app.MapControllers();

app.Run();

A documentação mostra UseSentry() sem parâmetros como forma mínima de inicialização e também mostra o padrão com callback para BeforeSend. (Sentry Docs)


O que colocar no appsettings.json e o que deixar no UseSentry

Normalmente fica no appsettings.json

  • Dsn
  • Debug
  • DiagnosticLevel
  • SendDefaultPii
  • AttachStackTrace
  • MinimumBreadcrumbLevel
  • MinimumEventLevel
  • MaxBreadcrumbs
  • TracesSampleRate
  • EnableLogs

Essas opções são mapeadas pelo sistema de configuração do ASP.NET Core. (Sentry Docs)

Normalmente fica no UseSentry

  • SetBeforeSend
  • SetBeforeSendLog
  • callbacks e filtros
  • lógica condicional por ambiente
  • enriquecimento que depende de decisão de runtime

A documentação cita BeforeSend como exemplo de opção que só faz sentido configurar em código, e cita SetBeforeSendLog para filtrar logs antes do envio. (Sentry Docs)


Opções mais importantes

Dsn

"Sentry": {
"Dsn": "https://SEU_DSN@sentry.io/PROJETO"
}

O DSN define para onde os eventos serão enviados. Se ele não for fornecido, o SDK tenta ler SENTRY_DSN; se continuar ausente, o SDK simplesmente não envia eventos. (Sentry Docs)

Environment

Você pode configurar:

"Sentry": {
"Environment": "Production"
}

Ou deixar o ASP.NET Core preencher a partir do ambiente. O Sentry informa que o nome do ambiente pode vir de configuração, de SENTRY_ENVIRONMENT ou do ambiente do ASP.NET Core. (Sentry Docs)

Release

"Sentry": {
"Release": "meu-servico@1.2.3"
}

O Sentry lê SENTRY_RELEASE automaticamente, e a documentação recomenda informar release para habilitar recursos de releases e health. (Sentry Docs)

SendDefaultPii

"Sentry": {
"SendDefaultPii": false
}

Quando ativado, no contexto do ASP.NET Core isso permite ao SDK ler o usuário a partir de HttpContext.User, além de incluir dados como URL e headers da requisição. É um opt-in explícito e deve ser avaliado com cuidado por motivos de privacidade. (Sentry Docs)

MaxRequestBodySize

"Sentry": {
"MaxRequestBodySize": "Small"
}

Valores aceitos:

  • None
  • Small
  • Medium
  • Always

Essa opção controla se o corpo HTTP da request pode ser capturado. O Sentry documenta exatamente esses valores e o comportamento esperado. (Sentry Docs)

MinimumBreadcrumbLevel

"Sentry": {
"MinimumBreadcrumbLevel": "Information"
}

Controla a partir de qual nível de log o Sentry guarda breadcrumbs. A integração de logging do Sentry usa níveis mínimos configuráveis. (Sentry Docs)

MinimumEventLevel

"Sentry": {
"MinimumEventLevel": "Error"
}

Controla a partir de qual nível um log pode virar evento no Sentry. A integração de logging do Sentry informa que os níveis mínimos são configuráveis e que logs de erro entram como eventos. (Sentry Docs)

AttachStackTrace

"Sentry": {
"AttachStackTrace": true
}

Essa opção permite anexar stack trace a mensagens capturadas. A documentação lista AttachStackTrace entre as opções configuráveis. (Sentry Docs)

Debug e DiagnosticLevel

"Sentry": {
"Debug": false,
"DiagnosticLevel": "Error"
}

Debug habilita diagnósticos mais verbosos do SDK. DiagnosticLevel controla a verbosidade desses diagnósticos, com níveis como debug, info, warning, error e fatal. Em produção, faz sentido manter Debug=false e subir DiagnosticLevel para Error ou Fatal. (Sentry Docs)

MaxBreadcrumbs

"Sentry": {
"MaxBreadcrumbs": 50
}

Define quantos breadcrumbs o SDK mantém antes do evento. A documentação usa MaxBreadcrumbs em seus exemplos oficiais. (Sentry Docs)

TracesSampleRate

"Sentry": {
"TracesSampleRate": 0.1
}

Controla a amostragem de transações para tracing. A própria documentação usa 1.0 apenas como exemplo e recomenda ajustar esse valor em produção. A página de sampling também informa que as taxas de amostragem devem ficar entre 0 e 1. (Sentry Docs)

EnableLogs

"Sentry": {
"EnableLogs": true
}

Isso habilita o envio de logs estruturados para o Sentry usando ILogger<T>. A documentação afirma que, sem EnableLogs=true, os logs não serão enviados ao produto de logs do Sentry. (Sentry Docs)


Variáveis de ambiente

Além de appsettings.json, o Sentry lê automaticamente:

  • SENTRY_DSN
  • SENTRY_ENVIRONMENT
  • SENTRY_RELEASE

E também aceita bind do estilo ASP.NET Core, por exemplo Sentry__Debug=true. (Sentry Docs)

Exemplo:

SENTRY_DSN=https://SEU_DSN@sentry.io/PROJETO
SENTRY_ENVIRONMENT=Production
SENTRY_RELEASE=meu-servico@1.2.3

Integração com ILogger

Comportamento padrão da integração

O pacote Sentry.AspNetCore inclui a integração com Microsoft.Extensions.Logging. Historicamente, o Sentry documenta que:

  • LogInformation ou acima pode virar breadcrumb
  • LogError ou acima pode capturar evento
  • os níveis mínimos são configuráveis. (Sentry Docs)

Logs estruturados do Sentry

Para enviar logs para a área de logs do Sentry, é preciso habilitar EnableLogs=true. Depois disso, os logs enviados por ILogger<T> passam a ser aceitos pelo pipeline de logs do Sentry. A documentação também mostra o mapeamento entre LogLevel e a severidade do Sentry. (Sentry Docs)

Mapeamento documentado:

  • Tracetrace
  • Debugdebug
  • Informationinfo
  • Warningwarn
  • Errorerror
  • Criticalfatal (Sentry Docs)

Exemplo prático com ILogger

public sealed class ComandoService(ILogger<ComandoService> logger)
{
public void Executar(string cnpj)
{
logger.LogInformation("Iniciando envio de comando para {Cnpj}", cnpj);
logger.LogWarning("Tentativa de envio para grupo {Cnpj}", cnpj);
}
}

A documentação mostra o uso de ILogger com mensagens simples, parâmetros formatados e EventId, e informa que o CategoryName e o EventId são anexados como atributos no log. (Sentry Docs)


Filtrando logs antes do envio

Se você habilitar logs no Sentry, é comum cortar ruído com SetBeforeSendLog.

builder.WebHost.UseSentry(options =>
{
options.EnableLogs = true;

options.SetBeforeSendLog(log =>
{
if (log.Level == Sentry.SentryLogLevel.Info)
{
return null;
}

log.SetAttribute("app.layer", "api");
return log;
});
});

A documentação mostra SetBeforeSendLog(Func<SentryLog, SentryLog?>) como o ponto de filtragem e enriquecimento de logs antes do envio. (Sentry Docs)


Filtrando eventos e removendo dados sensíveis

BeforeSend

O padrão mais útil é usar BeforeSend para:

  • remover dados sensíveis
  • eliminar ruído técnico
  • descartar eventos conhecidos, como health checks

A documentação do Sentry recomenda usar BeforeSend e BeforeSendTransaction para scrub de dados antes do envio. (Sentry Docs)

Exemplo:

builder.WebHost.UseSentry(options =>
{
options.SetBeforeSend((@event, hint) =>
{
if (@event.Request?.Url?.Contains("/health") == true)
{
return null;
}

@event.ServerName = null;
return @event;
});
});

O próprio Sentry mostra BeforeSend modificando o evento antes do envio. (Sentry Docs)

BeforeBreadcrumb

O Sentry também suporta BeforeBreadcrumb, útil quando você quer podar breadcrumbs ruidosos antes que entrem no evento. A lista de recursos da documentação de migração cita explicitamente BeforeBreadcrumb. (Sentry Docs)


Captura manual: quando usar e quando evitar

Quando usar

Use SentrySdk.CaptureException(ex) quando:

  • você tratou a exceção e ela não vai mais subir
  • quer reportar um erro de domínio que foi consumido pela aplicação
  • precisa anexar contexto adicional antes de enviar

Exemplo:

catch (Exception ex)
{
SentrySdk.ConfigureScope(scope =>
{
scope.SetTag("cnpj", cnpj);
scope.SetExtra("requestId", dto.RequestId?.ToString());
});

SentrySdk.CaptureException(ex);

return Results.Problem(
title: "Erro ao enviar comando.",
statusCode: StatusCodes.Status500InternalServerError);
}

A documentação mostra captura manual de exceção com SentrySdk.CaptureException(ex) como forma de validar e enviar erros. (Sentry Docs)

Quando evitar

Evite capturar manualmente em todo try/catch se você já tem:

  • UseSentry() ativo
  • pipeline padrão do ASP.NET Core
  • logging adequado

Nesse caso, o SDK já captura exceções não tratadas na pipeline, inclusive erros tratados pelo framework como UseExceptionHandler. (Sentry Docs)

Sobre CaptureMessage

CaptureMessage existe, mas o uso deve ser mais raro que CaptureException. O próprio material do Sentry destaca que AttachStackTrace para mensagens é opt-in, o que reforça que mensagem solta não deve virar substituto de tratamento de erro real. (Sentry Docs)


Exemplo prático para Minimal API

Exemplo alinhado com uso real em produção:

app.MapPost("/envio-comando/{cnpj}", async (
string cnpj,
RequisicaoConteudoDto dto,
IHubContext<ComandoHub> hubContext,
ILogger<Program> logger,
CancellationToken ct) =>
{
if (string.IsNullOrWhiteSpace(cnpj))
{
logger.LogWarning("CNPJ inválido recebido no endpoint de envio de comando");
return Results.BadRequest("CNPJ inválido");
}

try
{
dto.CriarIdentificadorRequest();

logger.LogInformation(
"Enviando comando para o grupo {Cnpj} com requestId {RequestId}",
cnpj,
dto.RequestId);

await hubContext.Clients
.Group(cnpj)
.SendAsync("receber-comando", dto, ct);

return Results.Ok(new { requestId = dto.RequestId });
}
catch (Exception ex)
{
logger.LogError(
ex,
"Erro ao enviar comando para o grupo {Cnpj} com requestId {RequestId}",
cnpj,
dto.RequestId);

SentrySdk.ConfigureScope(scope =>
{
scope.SetTag("cnpj", cnpj);
scope.SetTag("feature", "envio-comando");
scope.SetExtra("requestId", dto.RequestId?.ToString());
});

SentrySdk.CaptureException(ex);

return Results.Problem(
title: "Erro ao enviar comando para o cliente.",
statusCode: StatusCodes.Status500InternalServerError);
}
});

Esse padrão faz sentido porque:

  • usa ILogger para trilha operacional
  • captura manualmente apenas porque a exceção foi consumida
  • evita expor ex.Message ao cliente
  • anexa contexto útil no evento

Enriquecimento por escopo

Você pode enriquecer eventos com:

  • tags
  • extras
  • usuário
  • contexto temporário por request

O Sentry documenta o uso de scopes e também informa que, quando a integração de logging está ativa, dados de BeginScope podem ser enviados com eventos. (Sentry Docs)

Exemplo:

using (logger.BeginScope(new Dictionary<string, object>
{
["cnpj"] = cnpj,
["requestId"] = dto.RequestId
}))
{
logger.LogInformation("Preparando envio de comando");
}

Usuário autenticado

Se SendDefaultPii=true, o SDK pode montar usuário automaticamente a partir de HttpContext.User. A documentação informa isso explicitamente e também diz que esse comportamento pode ser customizado registrando um ISentryUserFactory no container. (Sentry Docs)

Exemplo de customização via DI:

builder.Services.AddSingleton<ISentryUserFactory, MeuSentryUserFactory>();

Processadores por DI

A integração ASP.NET Core do Sentry aceita processadores por DI, o que é muito útil para padronizar tags, scrubbing e enriquecimento de todos os eventos. A documentação mostra ISentryEventProcessor e ISentryEventExceptionProcessor registrados no container. (Sentry Docs)

Exemplo:

builder.Services.AddTransient<ISentryEventProcessor, MeuEventProcessor>();
builder.Services.AddScoped<ISentryEventExceptionProcessor, MeuExceptionProcessor>();

Activity, tracing e OpenTelemetry

IncludeActivityData

Se você usa System.Diagnostics.Activity, pode optar por capturar esses valores com IncludeActivityData. O Sentry documenta essa opção como opt-in. (Sentry Docs)

Exemplo:

"Sentry": {
"IncludeActivityData": true
}

Bridge com OpenTelemetry

Se você quer que o Sentry consuma spans do OpenTelemetry, a documentação mostra o uso de:

SentrySdk.Init(options =>
{
options.TracesSampleRate = 1.0;
options.UseOpenTelemetry();
});

A documentação explica que, nesse modo, spans do OpenTelemetry são transformados em transações e spans do Sentry. (Sentry Docs)

Cuidado importante

O Sentry documenta que, com OpenTelemetry em .NET, não é recomendado usar Activity.RecordException ou Activity.AddException, porque isso pode remover informações valiosas antes da captura pelo Sentry. A recomendação oficial é usar ILogger ou SentrySdk.CaptureException. (Sentry Docs)


Configuração recomendada por ambiente

Desenvolvimento

{
"Sentry": {
"Dsn": "https://SEU_DSN@sentry.io/PROJETO",
"Debug": true,
"DiagnosticLevel": "Debug",
"SendDefaultPii": false,
"AttachStackTrace": true,
"MinimumBreadcrumbLevel": "Debug",
"MinimumEventLevel": "Error",
"MaxBreadcrumbs": 100,
"TracesSampleRate": 1.0,
"EnableLogs": true
}
}

Útil para validar setup e troubleshooting do SDK. Debug e DiagnosticLevel mais altos produzem mais diagnóstico do próprio Sentry SDK. (Sentry Docs)

Produção

{
"Sentry": {
"Dsn": "https://SEU_DSN@sentry.io/PROJETO",
"Environment": "Production",
"Release": "meu-servico@1.2.3",
"Debug": false,
"DiagnosticLevel": "Error",
"SendDefaultPii": false,
"AttachStackTrace": true,
"MinimumBreadcrumbLevel": "Information",
"MinimumEventLevel": "Error",
"MaxBreadcrumbs": 50,
"TracesSampleRate": 0.05,
"EnableLogs": false
}
}

Isso reduz ruído, custo e risco de vazamento desnecessário de dados.


Erros comuns

Duplicar eventos

Evite fazer isto:

logger.LogError(ex, "Erro");
SentrySdk.CaptureException(ex);

Se os dois caminhos estiverem gerando evento, você corre risco de duplicidade. O Sentry documenta integração automática com logging e captura de exceções da pipeline, então convém escolher conscientemente quando fazer captura manual. (Sentry Docs)

Expor ex.Message ao cliente

Em APIs, prefira Results.Problem(...) ou outro payload neutro. Use o Sentry para detalhes internos.

Ligar SendDefaultPii=true sem avaliação

Isso pode enviar dados que você não quer compartilhar por padrão, especialmente em ambientes regulados. O Sentry trata essa opção como opt-in. (Sentry Docs)

TracesSampleRate=1.0 em produção sem necessidade

A documentação usa 1.0 apenas como exemplo e recomenda ajustar em produção. (Sentry Docs)

Ativar logs no Sentry sem filtro

Se você usar EnableLogs=true, normalmente vale combinar com SetBeforeSendLog para evitar custo e ruído excessivos. (Sentry Docs)


Exemplo completo recomendado

appsettings.json

{
"Sentry": {
"Dsn": "https://SEU_DSN@sentry.io/PROJETO",
"Environment": "Production",
"Release": "comandos-api-orquestracao@1.0.0",
"Debug": false,
"DiagnosticLevel": "Error",
"SendDefaultPii": false,
"AttachStackTrace": true,
"MinimumBreadcrumbLevel": "Information",
"MinimumEventLevel": "Error",
"MaxBreadcrumbs": 50,
"MaxRequestBodySize": "Small",
"IncludeActivityData": true,
"TracesSampleRate": 0.1,
"EnableLogs": true
}
}

Program.cs

using Sentry;

var builder = WebApplication.CreateBuilder(args);

builder.WebHost.UseSentry(options =>
{
options.SetBeforeSend((@event, hint) =>
{
if (@event.Request?.Url?.Contains("/health") == true ||
@event.Request?.Url?.Contains("/alive") == true)
{
return null;
}

@event.ServerName = null;
return @event;
});

options.SetBeforeSendLog(log =>
{
if (log.Level == Sentry.SentryLogLevel.Info)
{
return null;
}

log.SetAttribute("system", "comandos");
return log;
});
});

builder.Services.AddControllers();

var app = builder.Build();

app.MapControllers();

app.Run();

Esse modelo combina:

  • configuração declarativa
  • filtros em código
  • logs habilitados no Sentry
  • scrubbing básico
  • suporte a tracing

Referência rápida

Setup mínimo

builder.WebHost.UseSentry();

Log estruturado no Sentry

"Sentry": {
"EnableLogs": true
}

Captura manual de exceção

SentrySdk.CaptureException(ex);

Filtro de evento

options.SetBeforeSend((@event, hint) => @event);

Filtro de log

options.SetBeforeSendLog(log => log);

OpenTelemetry

options.UseOpenTelemetry();