Olá! Bem-vindo de volta à nossa exploração sobre observabilidade no .NET Aspire.
Na lição anterior, focamos nos logs estruturados, aprendendo a gerar dados ricos em contexto e a usar o Aspire Dashboard para filtrar e correlacionar esses logs através de um TraceId. Vimos como isso é fundamental para entender o que aconteceu durante uma operação específica.
Hoje, vamos dar um passo adiante e focar no TraceId em si. Nosso objetivo de aprendizagem é: Analisar distributed traces (rastreamentos distribuídos) em múltiplos serviços para diagnosticar latência e erros no Aspire Dashboard. Vamos aprender a visualizar a jornada completa de uma requisição, da entrada à saída, através de todos os microsserviços que ela percorre. Esta é uma das ferramentas mais poderosas para depurar sistemas distribuídos.
O Que é um Distributed Trace?
Enquanto os logs nos dão snapshots de eventos em pontos específicos do nosso código, um trace nos conta a história completa de uma única requisição. Ele visualiza o caminho e o tempo que uma operação leva para atravessar os diferentes componentes do seu sistema (APIs, bancos de dados, filas de mensagens, etc.).
Para entender isso, precisamos de dois conceitos-chave do OpenTelemetry:
- Trace: Pense nisso como a jornada inteira. Cada jornada tem um identificador único, o
TraceId, que é o mesmo para cada passo daquela requisição específica. - Span: Pense nisso como uma etapa ou um trecho da jornada. Cada span representa uma unidade de trabalho discreta, como uma chamada HTTP, uma consulta ao banco de dados ou um método de negócio específico. Cada span tem seu próprio
SpanIde uma referência aoTraceIdda jornada. Crucialmente, os spans podem ter relações de pai-filho, o que nos permite construir uma árvore de causalidade.
Para uma explicação mais detalhada sobre esses conceitos, o vídeo a seguir é excelente.
Practical OpenTelemetry in .NET 8 - Martin Thwaites - NDC London 2024
No vídeo 'Practical OpenTelemetry in .NET 8', Martin Thwaites, da Honeycomb, explica de forma clara o que são traces e spans.
Assista do timestamp 09:30 até 12:22. Foque em como ele define um trace como um 'caminho através do seu sistema' e um span como um 'bloco estruturado de dados' com propriedades essenciais como ID, duração e, mais importante, um 'causality ID' (ID de causalidade), que é o que nos permite construir a visualização em cascata.
Em resumo, o .NET Aspire usa o OpenTelemetry para, automaticamente:
- Iniciar um novo trace para cada requisição que entra no seu sistema.
- Criar spans para operações conhecidas (como chamadas HTTP de entrada e saída, e consultas a bancos de dados).
- Propagar o contexto do trace (o
TraceId) entre os serviços, geralmente através de cabeçalhos HTTP, para que a jornada possa ser reconstruída.
Analisando Traces no Aspire Dashboard
O Aspire Dashboard é onde essas jornadas ganham vida. Ele coleta todos os spans de todos os seus serviços e os monta em visualizações coesas.
A documentação oficial do Aspire fornece uma ótima introdução à página de Traces.
Vamos explorar a documentação oficial para nos familiarizarmos com a interface de traces do dashboard.
Leia as seções 'Traces page', 'Trace details' e 'Trace examples'. Preste atenção nas screenshots que mostram a lista de traces, a visualização em cascata (waterfall) dos detalhes de um trace e como os erros são destacados.
A visualização mais importante é a de "detalhes do trace", frequentemente chamada de waterfall chart (gráfico de cascata).

Este gráfico nos permite responder a duas perguntas críticas instantaneamente:
- Onde ocorreu um erro? Spans com erro são geralmente destacados em vermelho.
- O que está demorando? A barra mais longa no gráfico é o seu gargalo de desempenho (latência).
Cenário Prático: Depurando um Bug de Cache
Vamos aplicar esse conhecimento em um cenário real. Imagine que você está investigando um bug onde novas avaliações de clientes não aparecem imediatamente no site. Você suspeita de um problema de cache, um bug notoriamente difícil de rastrear em sistemas distribuídos.
O artigo a seguir o guiará por uma sessão de depuração passo a passo usando o Aspire Dashboard para resolver exatamente esse problema.
Debug Distributed Systems in Minutes Using .NET Aspire
O artigo 'Debug Distributed Systems in Minutes Using .NET Aspire' de Julio Casal é um excelente caso de estudo prático.
Leia atentamente as seções 'Tracing the issue', 'Understanding the root cause', e 'Verifying the fix'. Siga a linha de raciocínio do autor: Ele reproduz o bug localmente. Ele examina os traces para a requisição GET (que busca dados) e POST (que cria dados). Ele nota uma discrepância: o trace do GET interage com o Redis, mas o trace do POST não o invalida. Essa observação o leva diretamente à causa raiz no código. Após a correção, ele usa o mesmo trace para verificar se o comportamento está correto. Preste muita atenção em como a análise visual dos traces tornou o problema óbvio.
Este exemplo demonstra perfeitamente como o distributed tracing transforma a depuração. Em vez de adivinhar e espalhar _logger.LogDebug("Estou aqui") pelo código, você obtém um mapa visual do comportamento real da sua aplicação.
Cenário Prático 2: Encontrando a Causa de um Erro
E se o problema não for latência, mas uma falha explícita? O vídeo a seguir mostra James Newton-King (um dos principais arquitetos do .NET na Microsoft) depurando uma falha ao vivo.
ASP.NET Community Standup - Behind the Scenes: Building the .NET Aspire Dashboard
Na 'ASP.NET Community Standup', James Newton-King demonstra como usar o trace para diagnosticar uma falha de conectividade.
Assista do timestamp 44:46 até 48:07. Ele intencionalmente para um contêiner do PostgreSQL e, em seguida, mostra a página de Traces no dashboard. Observe como: O trace da requisição falha é claramente visível. A visualização em cascata mostra as tentativas de retry que foram configuradas. Ele clica em 'View logs' diretamente do trace para ir aos logs já filtrados, encontrando a exceção exata de conectividade com o banco de dados.
Este fluxo de trabalho — ir de um trace falho para os logs correlacionados — é uma das técnicas de depuração mais eficientes para sistemas distribuídos e conecta perfeitamente o que aprendemos nesta lição com a anterior.
Teste seu entendimento!
Você está analisando o trace de uma requisição GET /products/{id} que está levando 2 segundos para ser concluída, o que é inaceitavelmente lento. A visualização em cascata no Aspire Dashboard mostra o seguinte:
- Span A:
GET /products/{id}(Total: 2000ms) - O span principal da API Gateway.- Span B:
HTTP: GET user-service/user/profile(Duração: 50ms) - Uma chamada para obter o perfil do usuário. - Span C:
HTTP: GET inventory-service/stock/{id}(Duração: 1900ms) - Uma chamada para o serviço de inventário.- Span D:
DB: SELECT * FROM stock WHERE...(Duração: 1850ms) - Uma consulta ao banco de dados dentro doinventory-service.
- Span D:
- Span E: Processamento final (Duração: 50ms) - Lógica de negócio após as chamadas.
- Span B:
Com base nesta estrutura de trace, qual é a causa mais provável da latência e em qual serviço o problema reside? Como você confirmaria sua suspeita?
Show answer
-
Causa da Latência: A causa mais provável da latência é a chamada para o serviço de inventário (Span C), que leva 1900ms dos 2000ms totais. Dentro desse serviço, a operação de banco de dados (Span D) é a principal culpada, consumindo 1850ms.
-
Serviço Problemático: O problema reside no
inventory-service. -
Confirmação: Para confirmar, eu clicaria no Span D dentro do Aspire Dashboard para ver seus detalhes. Eu procuraria por atributos (tags) como
db.statement, que me mostraria a query SQL exata que foi executada. Com a query em mãos, eu poderia executá-la diretamente no banco de dados com umEXPLAIN(ou ferramenta similar) para analisar seu plano de execução e descobrir por que ela está tão lenta (por exemplo, falta de um índice, uma varredura completa da tabela, etc.).
Conclusão
Nesta lição, desvendamos o poder dos distributed traces para a depuração de sistemas complexos. Vimos que eles não são apenas uma ferramenta, mas uma nova maneira de visualizar e entender o fluxo de trabalho em nossas aplicações.
Principais Pontos:
- Um Trace representa a jornada completa de uma requisição, enquanto um Span é uma única etapa nessa jornada.
- A relação pai-filho entre os spans cria um gráfico de cascata (waterfall chart), que é a ferramenta visual principal para diagnóstico.
- Analisando o gráfico de cascata no Aspire Dashboard, podemos identificar rapidamente gargalos de latência (spans longos) e a localização de erros (spans marcados como falhos).
- A capacidade de navegar de um trace para seus logs correlacionados cria um fluxo de trabalho de depuração extremamente eficiente, combinando a visão geral (trace) com os detalhes granulares (logs).
Próxima Lição:
Até agora, focamos em eventos individuais: logs para momentos específicos e traces para requisições específicas. Na próxima lição, vamos subir um nível de abstração para o terceiro pilar da observabilidade: Métricas. Aprenderemos como expor e monitorar métricas agregadas, que nos dão uma visão macro da saúde e do desempenho do nosso sistema ao longo do tempo, como "qual é a taxa de erro média da minha API nos últimos 30 minutos?" ou "qual é o consumo de CPU do meu serviço de pedidos?".