DEV Community

Cover image for Integrando Sentry com .NET
Danilo O. Pinheiro, dopme.io
Danilo O. Pinheiro, dopme.io

Posted on

Integrando Sentry com .NET

📖 Introdução

O desenvolvimento de aplicações .NET modernas exige não apenas código funcional, mas também visibilidade completa sobre o comportamento do sistema em produção. Monitoramento, rastreamento de erros e observabilidade tornaram-se componentes essenciais para garantir a confiabilidade e a capacidade de resposta de aplicações críticas.

Este artigo apresenta uma abordagem prática para integrar o Sentry em uma aplicação .NET 8, utilizando Vertical Slice Architecture e padrões modernos como CQRS e MediatR. Demonstraremos como implementar monitoramento robusto, captura automática de exceções e rastreamento contextualizado de eventos.

O projeto dopNetSentry serve como exemplo prático, mostrando como combinar arquitetura limpa, padrões de design e ferramentas de observabilidade para criar soluções profissionais e sustentáveis.


🧱 Visão Geral do Projeto

O dopNetSentry é uma aplicação .NET 8 que demonstra a integração completa do SDK do Sentry para monitoramento e rastreamento automático de erros e exceções. O projeto utiliza uma arquitetura em camadas bem definida:

  • Api: Camada de apresentação com Minimal APIs
  • Application: Lógica de aplicação com CQRS (Commands e Queries)
  • Domain: Entidades de domínio puras
  • Infrastructure: Persistência e integrações externas

Essa organização permite separação clara de responsabilidades, facilitando testes, manutenção e evolução do sistema.

Características Principais

  • .NET 8: Utilizando a versão mais recente do framework
  • Sentry SDK 6.0.0: Monitoramento em tempo real de erros e exceções
  • Vertical Slice Architecture: Organização por funcionalidade
  • CQRS com MediatR: Separação entre leitura e escrita
  • Entity Framework Core: ORM para persistência de dados
  • FluentValidation: Validação robusta de entrada
  • Swagger/OpenAPI: Documentação automática da API

🛠️ Componentes Fundamentais

🔹 Arquitetura em Camadas

A aplicação segue o princípio de dependência unidirecional:

Api → Application + Infrastructure
Application → Domain
Infrastructure → Domain + Application
Enter fullscreen mode Exit fullscreen mode

Domain é a camada mais pura, sem dependências externas. Application contém a lógica de negócio e depende apenas de Domain. Infrastructure implementa detalhes técnicos e depende de Domain e Application. Api é a camada de apresentação que orquestra tudo.

🔹 Padrão CQRS (Command Query Responsibility Segregation)

O projeto utiliza MediatR para implementar CQRS:

  • Commands: Operações de escrita (Create, Update, Delete)
  • Queries: Operações de leitura (Get, List)
  • Handlers: Processam Commands e Queries de forma isolada

Essa separação permite otimizações independentes, escalabilidade e clareza no código.

🔹 Vertical Slice Architecture

Ao invés de organizar por camadas técnicas (Controllers, Services, Repositories), o projeto organiza por funcionalidade:

├── src/
│   ├── netsentry.Api/                    # Camada de Apresentação
│   │   ├── Endpoints/
│   │   │   ├── WeatherForecastEndpoints.cs
│   │   │   └── SentryExamplesEndpoints.cs (comentado)
│   │   ├── Exceptions/
│   │   │   └── MyRpcException.cs
│   │   ├── Services/
│   │   │   └── SentryService.cs
│   │   ├── Program.cs
│   │   └── appsettings.json
│   ├── netsentry.Application/            # Camada de Aplicação
│   │   ├── Commands/                     # (vazio - pronto para uso)
│   │   ├── Interfaces/
│   │   │   └── IApplicationDbContext.cs
│   │   ├── Models/
│   │   │   └── WeatherForecastDto.cs
│   │   └── Queries/
│   │       ├── GetWeatherForecastQuery.cs
│   │       └── GetWeatherForecastQueryHandler.cs
│   ├── netsentry.Domain/                 # Camada de Domínio
│   │   └── Entities/
│   │       └── WeatherForecast.cs
│   └── netsentry.Infrastructure/         # Camada de Infraestrutura
│       └── Persistence/
│           └── ApplicationDbContext.cs
Enter fullscreen mode Exit fullscreen mode

Cada funcionalidade contém tudo necessário para sua implementação, promovendo coesão e reduzindo acoplamento.


🔄 Integração com Sentry

Configuração do Sentry

O Sentry é configurado no Program.cs usando o método UseSentry no WebHost:

builder.WebHost.UseSentry(options =>
{
    options.Dsn = builder.Configuration["Sentry:Dsn"];
    options.Debug = true; // Para ver o que o SDK está fazendo
    options.SendDefaultPii = true; // Inclui headers, IP, etc.
    options.TracesSampleRate = 1.0; // 100% das transações
    options.Environment = builder.Environment.EnvironmentName;

    // Filtro de exceções
    options.AddExceptionFilterForType<OperationCanceledException>();

    // Customização de eventos
    options.SetBeforeSend(@event =>
    {
        // Lógica de customização
        return @event;
    });
});
Enter fullscreen mode Exit fullscreen mode

Funcionalidades Implementadas

1. Captura Automática de Exceções

O Sentry captura automaticamente todas as exceções não tratadas. Para exceções tratadas, podemos usar:

try
{
    // Código que pode falhar
}
catch (Exception ex)
{
    SentrySdk.CaptureException(ex);
}
Enter fullscreen mode Exit fullscreen mode

2. Captura de Mensagens

Para registrar eventos informativos:

SentrySdk.CaptureMessage("Operação iniciada", SentryLevel.Info);
Enter fullscreen mode Exit fullscreen mode

3. Configuração de Contexto

Adicionar informações contextuais aos eventos:

SentrySdk.ConfigureScope(scope =>
{
    scope.SetTag("endpoint", "weatherforecast");
    scope.SetTag("method", "GET");
    scope.SetExtra("request-time", DateTime.UtcNow.ToString("O"));
});
Enter fullscreen mode Exit fullscreen mode

4. Filtros de Exceção

Ignorar tipos específicos de exceções:

options.AddExceptionFilterForType<OperationCanceledException>();
Enter fullscreen mode Exit fullscreen mode

5. Customização com SetBeforeSend

Modificar eventos antes de enviar ao Sentry:

options.SetBeforeSend(@event =>
{
    if (@event.Exception is MyRpcException rpcEx)
    {
        @event.SetFingerprint(new[]
        {
            "{{ default }}",
            rpcEx.Function,
            rpcEx.Code.ToString(),
        });
    }
    return @event;
});
Enter fullscreen mode Exit fullscreen mode

Exemplo Prático: Endpoint WeatherForecast

O endpoint /weatherforecast demonstra a integração completa:

group.MapGet("/", async (IMediator mediator, CancellationToken cancellationToken) =>
{
    try
    {
        // Configurar contexto
        SentrySdk.ConfigureScope(scope =>
        {
            scope.SetTag("endpoint", "weatherforecast");
            scope.SetTag("method", "GET");
        });

        // Log de início
        SentrySdk.CaptureMessage("Iniciando busca de previsão do tempo", SentryLevel.Info);

        var query = new GetWeatherForecastQuery();
        var result = await mediator.Send(query, cancellationToken);

        return Results.Ok(result);
    }
    catch (Exception ex)
    {
        // Captura com contexto adicional
        SentrySdk.ConfigureScope(scope =>
        {
            scope.SetTag("error-type", ex.GetType().Name);
            scope.SetExtra("error-message", ex.Message);
            scope.Level = SentryLevel.Error;
        });

        SentrySdk.CaptureException(ex);
        return Results.Problem(statusCode: 500);
    }
});
Enter fullscreen mode Exit fullscreen mode

🧪 Testes e Qualidade

A arquitetura implementada facilita a criação de testes:

  • Testes Unitários: Handlers podem ser testados isoladamente com mocks
  • Testes de Integração: Endpoints podem ser testados com banco em memória
  • Testes de Observabilidade: Verificar se eventos são enviados corretamente ao Sentry

A separação de responsabilidades permite isolar dependências e criar testes rápidos e confiáveis.


📊 Observabilidade e Operação

O Sentry fornece:

  • Monitoramento de Erros em Tempo Real: Notificações instantâneas quando erros ocorrem
  • Stack Traces Completos: Veja exatamente onde e por que os erros acontecem
  • Contexto Rico: Informações sobre usuários afetados, ambiente, versão da aplicação
  • Performance Insights: Identifique gargalos e otimize a performance
  • Dashboard Interativo: Visualize estatísticas e tendências

Como Obter o DSN do Sentry

Para utilizar o Sentry em sua aplicação, você precisa criar uma conta no Sentry.io e obter o DSN (Data Source Name) do seu projeto. Siga os passos abaixo:

  1. Criar uma Conta no Sentry.io

    • Acesse https://sentry.io/signup/
    • Crie uma conta gratuita (o plano gratuito oferece recursos suficientes para começar)
    • Confirme seu email se necessário
  2. Criar uma Organização e Projeto

    • Após fazer login, você será direcionado para criar uma organização
    • Escolha um nome para sua organização
    • Crie um novo projeto selecionando a plataforma .NET
    • Escolha um nome para o projeto (ex: "dopNetSentry")
  3. Obter o DSN

    • Após criar o projeto, o Sentry exibirá uma tela de configuração
    • O DSN estará visível no formato: https://[chave]@[organização].ingest.sentry.io/[projeto-id]
    • Você também pode encontrar o DSN posteriormente em: Settings → Projects → [Seu Projeto] → Client Keys (DSN)
  4. Copiar o DSN

    • Copie o DSN completo fornecido pelo Sentry
    • Este será o valor que você configurará no appsettings.json

Nota: O DSN é uma chave pública que identifica seu projeto no Sentry. Embora seja seguro incluí-lo no código-fonte, é recomendado usar variáveis de ambiente ou Azure Key Vault em produção.

Configuração via appsettings.json

Após obter o DSN, configure-o no arquivo appsettings.json:

{
  "Sentry": {
    "Dsn": "https://[sua-chave]@[seu-org].ingest.sentry.io/[projeto-id]",
    "Debug": true,
    "SendDefaultPii": true,
    "TracesSampleRate": 1.0,
    "Environment": "Development"
  }
}
Enter fullscreen mode Exit fullscreen mode

Substitua o valor de Dsn pelo DSN real obtido na sua conta do Sentry.

Boas Práticas

  • Não inclua dados sensíveis nos logs ou contexto do Sentry
  • Use filtros para ignorar exceções esperadas (como OperationCanceledException)
  • Configure ambientes diferentes (Development, Staging, Production)
  • Ajuste TracesSampleRate em produção para controlar volume
  • Desative Debug em produção para melhor performance

🔐 Segurança

O projeto implementa várias práticas de segurança:

  • Validação de Entrada: FluentValidation valida todos os dados de entrada
  • Parameterized Queries: Entity Framework Core usa queries parametrizadas automaticamente
  • Object Level Authorization: Verificação de permissões em endpoints
  • Logging Seguro: Não inclui dados sensíveis nos logs
  • Configuração Segura: DSN do Sentry via configuração, não hardcoded

Essas práticas garantem que a aplicação seja robusta e segura.


🚧 Evolução e Sustentabilidade

A arquitetura escolhida permite:

  • Evolução Incremental: Adicionar novas funcionalidades sem impactar existentes
  • Manutenibilidade: Código organizado e fácil de entender
  • Escalabilidade: Estrutura preparada para crescimento
  • Testabilidade: Fácil de testar e validar

A Vertical Slice Architecture promove coesão alta e acoplamento baixo, facilitando a evolução contínua do sistema.


✅ Conclusão

A integração do Sentry em aplicações .NET 8, combinada com uma arquitetura bem definida, proporciona:

  • Visibilidade Completa: Entenda o que acontece em produção
  • Resposta Rápida: Identifique e corrija problemas rapidamente
  • Confiança: Monitore a saúde da aplicação continuamente
  • Melhoria Contínua: Use dados reais para otimizar o sistema

O projeto dopNetSentry demonstra como combinar tecnologias modernas (.NET 8, Sentry) com padrões arquiteturais sólidos (Vertical Slice, CQRS) para criar aplicações profissionais, observáveis e sustentáveis.

Tecnologias mudam, mas bons fundamentos permanecem.


📚 Recursos Adicionais

🤝 Conecte-se Comigo

Se você trabalha com .NET moderno e quer dominar arquitetura, C#, DevOps ou interoperabilidade, vamos conversar:

💼 LinkedIn

💻 DEV Community

✍️ Medium

📰 Substack

📧 Email


Projeto: dopNetSentry

Versão: 1.0.0

Data: Janeiro 2025

³ Porque assim diz o Senhor aos homens de Judá e a Jerusalém: Preparai para vós o campo de lavoura, e não semeeis entre espinhos. Jeremias 4:3

Top comments (0)