Exemplo: use o OpenTelemetry com OTLP e o painel de controle independente Aspire

Este artigo é um de uma série de exemplos para ilustrar a observabilidade do .NET com o OpenTelemetry.

Além de ser parte integrante do Aspire, o painel Aspire está disponível como um contêiner Docker independente, que fornece um ponto de extremidade OTLP para o qual a telemetria pode ser enviada. O painel visualiza os logs, as métricas e os rastreamentos. Usar o painel dessa forma não depende do Aspire e visualiza a telemetria de qualquer aplicativo que a envie via OTLP. Ele funciona igualmente bem para aplicativos escritos em Java, GoLang ou Python, desde que possam enviar sua telemetria para um ponto de extremidade OTLP.

O uso do Aspire Painel tem menos etapas de configuração e instalação do que usar soluções de software de código aberto, como Prometheus, Grafana e Jaeger. Mas, ao contrário dessas ferramentas, o Aspire Painel destina-se como uma ferramenta de visualização do desenvolvedor e não para monitoramento de produção.

1. Criar o projeto

Crie um projeto simples de API Web usando o modelo ASP.NET Core Vazio no Visual Studio ou o seguinte comando da CLI do .NET:

dotnet new web

2. Adicionar definições de métricas e atividades

O código a seguir define uma nova métrica (greetings.count) para o número de vezes que a API foi chamada e uma nova fonte de atividade (Otel.Example).

// Custom metrics for the application
var greeterMeter = new Meter("OTel.Example", "1.0.0");
var countGreetings = greeterMeter.CreateCounter<int>("greetings.count", description: "Counts the number of greetings");

// Custom ActivitySource for the application
var greeterActivitySource = new ActivitySource("OTel.Example");

3. Criar um endpoint de API

Inserir o código a seguir entre builder.Build(); e app.Run()

app.MapGet("/", SendGreeting);

Inserir a seguinte função no final do arquivo:

async Task<string> SendGreeting(ILogger<Program> logger)
{
    // Create a new Activity scoped to the method
    using var activity = greeterActivitySource.StartActivity("GreeterActivity");

    // Log a message
    logger.LogInformation("Sending greeting");

    // Increment the custom counter
    countGreetings.Add(1);

    // Add a tag to the Activity
    activity?.SetTag("greeting", "Hello World!");

    return "Hello World!";
}

Observação

A definição de ponto de extremidade não usa nada específico para OpenTelemetry. Usa apenas as APIs do .NET para observabilidade.

4. Referencie os pacotes do OpenTelemetry

Use o Gerenciador de Pacotes NuGet ou a linha de comando para adicionar os seguintes pacotes NuGet:

  <ItemGroup>
    <PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.9.0" />
    <PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.9.0" />
    <PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.9.0" />
    <PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.9.0" />
  </ItemGroup>

Observação

Use as versões mais recentes, pois as APIs do OTel estão em constante evolução.

5. Configurar o OpenTelemetry com os provedores corretos

Inserir o seguinte código antes de builder.Build();:

// Setup logging to be exported via OpenTelemetry
builder.Logging.AddOpenTelemetry(logging =>
{
    logging.IncludeFormattedMessage = true;
    logging.IncludeScopes = true;
});

var otel = builder.Services.AddOpenTelemetry();

// Add Metrics for ASP.NET Core and our custom metrics and export via OTLP
otel.WithMetrics(metrics =>
{
    // Metrics provider from OpenTelemetry
    metrics.AddAspNetCoreInstrumentation();
    //Our custom metrics
    metrics.AddMeter(greeterMeter.Name);
    // Metrics provides by ASP.NET Core in .NET 8
    metrics.AddMeter("Microsoft.AspNetCore.Hosting");
    metrics.AddMeter("Microsoft.AspNetCore.Server.Kestrel");
});

// Add Tracing for ASP.NET Core and our custom ActivitySource and export via OTLP
otel.WithTracing(tracing =>
{
    tracing.AddAspNetCoreInstrumentation();
    tracing.AddHttpClientInstrumentation();
    tracing.AddSource(greeterActivitySource.Name);
});

// Export OpenTelemetry data via OTLP, using env vars for the configuration
var OtlpEndpoint = builder.Configuration["OTEL_EXPORTER_OTLP_ENDPOINT"];
if (OtlpEndpoint != null)
{
    otel.UseOtlpExporter();
}

Este código configura o OpenTelemetry com as diferentes fontes de telemetria:

  • Ele adiciona um provedor OTel ao ILogger para coletar registros de log.
  • Ele configura métricas, registrando provedores de instrumentação e medidores para ASP.NET e nosso medidor personalizado.
  • Ele configura o rastreamento, o registro de provedores de instrumentação e nosso ActivitySource personalizado.

Em seguida, ele registra o exportador OTLP usando env vars para sua configuração.

6. Configurar variáveis ​​de ambiente OTLP

O exportador OTLP pode ser configurado por meio de APIs no código, mas é mais comum configurá-lo por meio de variáveis de ambiente. Adicione o seguinte a AppSettings.Development.json

"OTEL_EXPORTER_OTLP_ENDPOINT": "http://localhost:4317",
"OTEL_SERVICE_NAME": "OTLP-Example"

Você pode adicionar variáveis de ambiente adicionais para o Exportador de OTLP do .NET ou variáveis OTel comuns, como OTEL_RESOURCE_ATTRIBUTES para definir atributos de recurso.

Observação

Um gotcha comum é misturar AppSettings.json e AppSettings.Development.json. Se este último estiver presente, ele será usado quando você pressionar F5 no Visual Studio, e todas as configurações no AppSettings.json serão ignoradas.

7. Iniciar o contêiner do Aspire Dashboard

Use docker para baixar e executar o contêiner do painel.

docker run --rm -it `
-p 18888:18888 `
-p 4317:18889 `
--name aspire-dashboard `
mcr.microsoft.com/dotnet/aspire-dashboard:latest

Os dados exibidos no painel podem ser confidenciais. Por padrão, o painel é protegido com autenticação que requer um token para fazer logon. O token é exibido na saída resultante ao executar o contêiner.

Aspire Painel

Copie a URL mostrada e substitua 0.0.0.0localhostpor, por exemplo, http://localhost:18888/login?t=123456780abcdef123456780e abra-a no navegador. Ou você também pode colar a chave depois de /login?t= quando a caixa de diálogo de login for exibida. O token é alterado sempre que você inicia o contêiner.

8. Executar o projeto

Execute o projeto e acesse a API com o navegador ou curl.

curl -k http://localhost:7275

Cada vez que você solicita a página, ela incrementa a contagem do número de saudações que foram feitas.

8.1 Saída dos logs

As instruções de registro em log do código são geradas usando ILogger. Por padrão, o Provedor de Console está habilitado para que a saída seja direcionada para o console.

Há algumas opções de como os logs podem ser retirados do .NET:

  • As saídas stdout e stderr são redirecionadas para arquivos de log por sistemas de contêiner, como o Kubernetes.
  • Usando bibliotecas de log que se integram ao ILogger. Essas bibliotecas incluem Serilog e NLog.
  • Usando provedores de log para OTel, como OTLP. A seção de log no código da etapa 5 adiciona o provedor OTel.

Os logs são mostrados no painel como logs estruturados — todas as propriedades definidas na mensagem de log são extraídas como campos no registro de log.

Logs no painel de controle autônomo

8.2 Visualizando as métricas

No Aspire painel, as métricas são exibidas por recurso (sendo um recurso a maneira como o OTel se refere a fontes de telemetria, como um processo). Quando um recurso é selecionado, o painel enumera cada métrica que foi enviada pelo recurso ao endpoint OTLP. A lista de métricas é dinâmica e é atualizada à medida que novas métricas são recebidas.

Métricas no painel autônomo

A exibição das métricas depende do tipo de métrica que está sendo usada:

  • Os contadores são mostrados diretamente.
  • Os histogramas que rastreiam um valor por solicitação, como um período de tempo ou bytes enviados por solicitação, são coletados em uma série de buckets. O painel grafa os percentis P50, P90 e P99. Os resultados do histograma podem incluir exemplares, que são pontos de dados individuais junto com o trace/spanId para essa solicitação. Eles são mostrados como ponto no grafo. Selecionar um rastreamento leva você ao respectivo rastreamento, permitindo que você veja o que aconteceu para causar esse valor. Isso é útil para diagnosticar valores discrepantes.
  • As métricas podem incluir dimensões, que são pares de chave/valor associados a valores individuais. Os valores são agregados por dimensão. Usando os menus suspensos na visualização, você pode filtrar os resultados para analisar dimensões específicas, como apenas solicitações GET ou aquelas para uma rota de URL específica no ASP.NET.

8.3 Visualizando o rastreamento

A visualização de rastreamento mostra uma lista de rastreamentos. Cada traço é um conjunto de atividades que compartilham o mesmo ID de traço. O trabalho é monitorado com segmentos, que representam uma unidade de operação. O processamento de uma solicitação ASP.NET cria um intervalo. Fazer uma requisição HttpClient é um intervalo (span). Ao rastrear o pai do intervalo, uma hierarquia de intervalos pode ser visualizada. Ao coletar intervalos de cada recurso (processo), você pode acompanhar o trabalho que acontece em uma série de serviços. As solicitações HTTP contam com um cabeçalho que é usado para passar o traceId e o spanId do serviço pai para o próximo serviço. Cada recurso precisa coletar telemetria e enviá-la para o mesmo coletor. Em seguida, ele agregará e apresentará uma hierarquia dos intervalos.

Rastreamentos no painel autônomo

O painel mostra uma lista de rastreamentos com informações resumidas. Sempre que segmentos com um novo traceId são identificados, eles recebem uma linha na tabela. Clicar em "Visualizar" mostra todos os spans no rastreamento.

Extensões no painel autônomo

Selecionar um intervalo mostra seus detalhes, incluindo quaisquer propriedades no intervalo, como a greeting marca que você definiu na etapa 3.