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,BeforeBreadcrumbe 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()noProgram.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
DsnDebugDiagnosticLevelSendDefaultPiiAttachStackTraceMinimumBreadcrumbLevelMinimumEventLevelMaxBreadcrumbsTracesSampleRateEnableLogs
Essas opções são mapeadas pelo sistema de configuração do ASP.NET Core. (Sentry Docs)
Normalmente fica no UseSentry
SetBeforeSendSetBeforeSendLog- 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:
NoneSmallMediumAlways
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_DSNSENTRY_ENVIRONMENTSENTRY_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:
LogInformationou acima pode virar breadcrumbLogErrorou 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:
Trace→traceDebug→debugInformation→infoWarning→warnError→errorCritical→fatal(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
ILoggerpara trilha operacional - captura manualmente apenas porque a exceção foi consumida
- evita expor
ex.Messageao 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();