Usa OpenTelemetry com OTLP e o Aspire Dashboard

Este artigo mostra-lhe como instrumentar uma API web .NET com OpenTelemetry e enviar os seus logs, métricas e rastreios para o Aspire Dashboard usando OTLP. Adiciona-se os pacotes OpenTelemetry, configura-se métricas e traços personalizados, e vê-se os resultados no dashboard.

O Aspire Dashboard é uma parte padrão do Aspire, mas também está disponível como um contentor Docker autónomo que fornece um endpoint OTLP para enviar telemetria. O painel visualiza registos, métricas e traços. Usar o dashboard desta forma não depende de Aspire, e visualiza a telemetria de qualquer aplicação que envie telemetria usando OTLP. Funciona igualmente bem para aplicações escritas em Java, Go ou Python, desde que consigam enviar a sua telemetria para um endpoint OTLP.

O Aspire Dashboard requer menos configuração e menos passos de configuração do que soluções open-source como Prometheus, Grafana e Jaeger. Mas, ao contrário dessas ferramentas, o Aspire Dashboard é uma ferramenta de visualização para programadores, não uma ferramenta de monitorização de produção.

1. Crie o projeto

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

dotnet new web

2. Consultar os pacotes OpenTelemetry

Para adicionar os pacotes OpenTelemetry, utilize o NuGet Gestor de Pacotes ou execute os seguintes dotnet add package comandos:

dotnet add package OpenTelemetry.Exporter.OpenTelemetryProtocol
dotnet add package OpenTelemetry.Extensions.Hosting
dotnet add package OpenTelemetry.Instrumentation.AspNetCore
dotnet add package OpenTelemetry.Instrumentation.Http

Em alternativa, adicione os seguintes PackageReference itens diretamente ao ficheiro do projeto:

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

Nota

Como as APIs OTel estão em constante evolução, use as versões mais recentes.

3. Adicionar usando diretivas

Adicione as seguintes using diretivas no topo do ficheiro:

using System.Diagnostics;
using System.Diagnostics.Metrics;
using OpenTelemetry.Exporter;
using OpenTelemetry.Logs;
using OpenTelemetry.Metrics;
using OpenTelemetry.Resources;
using OpenTelemetry.Trace;

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

O código seguinte define uma nova métrica (greetings.count) que conta quantas vezes um cliente chama a API, e uma nova fonte de atividade (Otel.Example). Insira este código antes de builder.Build:

// 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");

5. Configure o OpenTelemetry com os provedores corretos

Insira o seguinte código antes de builder.Build:

// Configure the shared OTLP connection used by logs, metrics, and traces.
var otlpEndpoint = new Uri(builder.Configuration["OTEL_EXPORTER_OTLP_ENDPOINT"]!);
Action<OtlpExporterOptions> configureOtlp = options =>
{
    options.Endpoint = otlpEndpoint;
    options.Protocol = OtlpExportProtocol.Grpc;
    options.Headers = builder.Configuration["OTEL_EXPORTER_OTLP_HEADERS"]; // To secure endpoint (not in this example)
};

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

var otel = builder.Services.AddOpenTelemetry();

// Identify this application as a single service in the Aspire dashboard.
otel.ConfigureResource(resource => resource.AddService(builder.Configuration["OTEL_SERVICE_NAME"]!));

// 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 provided by ASP.NET Core in .NET
    metrics.AddMeter("Microsoft.AspNetCore.Hosting");
    metrics.AddMeter("Microsoft.AspNetCore.Server.Kestrel");

    // Export the metrics via OTLP
    metrics.AddOtlpExporter(configureOtlp);
});

// 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);
    tracing.AddOtlpExporter(configureOtlp);
});

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

  • Adiciona um provedor OTel a ILogger para recolher registos.
  • Define métricas, registando fornecedores de instrumentação e contadores para ASP.NET e o contador personalizado.
  • Configura o rastreamento, registando os fornecedores de instrumentação e o ActivitySource personalizado.

Depois, regista o exportador OTLP, usando variáveis de ambiente para a sua configuração.

6. Configurar definições OTLP

Pode configurar o exportador OTLP através de APIs no código, variáveis de ambiente ou configuração da aplicação. Para este exemplo, adicione as definições OTLP na raiz de appsettings.Development.json, após a Logging secção:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "OTEL_EXPORTER_OTLP_ENDPOINT": "http://localhost:4317",
  "OTEL_SERVICE_NAME": "OTLP-Example"
}

Adicione outras definições para o exportador OTLP .NET ou definições OTel comuns, como OTEL_RESOURCE_ATTRIBUTES definir atributos de recursos.

Nota

ASP.NET Core carrega tanto appsettings.json como appsettings.Development.json. As definições em appsettings.Development.json substituem as definições duplicadas em appsettings.json quando a aplicação é executada no ambiente de Desenvolvimento.

7. Criar um ponto final de API

Insira o seguinte código entre builder.Build e app.Run():

app.MapGet("/", SendGreeting);

Insira a seguinte função na parte inferior do ficheiro:

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!";
}

Nota

A definição do endpoint não usa nada específico do OpenTelemetry. Ele usa as APIs do .NET para observabilidade.

8. Iniciar o Aspire contentor do Dashboard

Uso docker para descarregar e executar o contentor do dashboard.

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 defeito, o dashboard requer um token de autenticação para iniciar sessão. O contentor mostra este token na sua saída.

Aspire Painel de instrumentos

Copie a URL, substitua-a 0.0.0.0 por localhost, por exemplo, http://localhost:18888/login?t=123456780abcdef123456780, e abra-a no seu navegador. Ou cole a chave depois de /login?t= na caixa de diálogo de início de sessão. O token muda cada vez que inicias o contentor.

9. Gerir o projeto

Executa o projeto com dotnet run. A saída da consola mostra os URLs que a aplicação escuta, por exemplo:

info: Microsoft.Hosting.Lifetime[14]
      Now listening on: http://localhost:5086

Usa a porta mostrada na tua própria saída de consola, porque pode diferir dos exemplos deste artigo. Use um navegador ou curl para aceder à API nessa porta:

curl -k http://localhost:5086

Cada vez que solicitas a página, o número de cumprimentos aumenta.

9.1 Saída de log

O código regista as instruções usando ILogger. Por defeito, o .NET ativa o Fornecedor da Consola, que direciona a saída para a consola.

Pode exportar registos do .NET de várias formas:

  • Sistemas de contentores como Kubernetes redirecionam a saída de stdout e stderr para ficheiros de registo.
  • Use bibliotecas de registo que se integrem com ILogger, como Serilog e NLog.
  • Utilize fornecedores de registo para OTel, como o OTLP. A secção de registo do código no passo 5 adiciona o fornecedor OTel.

O painel mostra os registos como registos estruturados. Quaisquer propriedades que definas na mensagem de log tornam-se campos no registo de log.

Efetua login no painel autônomo

9.2 Vista de métricas

O Aspire painel mostra métricas por recurso. Um recurso é o termo OTel para uma fonte de telemetria, como um processo. Quando selecionas um recurso, o painel lista cada métrica que o recurso enviou para o seu endpoint OTLP. A lista de métricas é dinâmica e atualiza-se à medida que o painel recebe novas métricas.

Métricas em painel autônomo

A visualização das métricas depende do tipo de métrica que utiliza:

  • O painel mostra os contadores diretamente.
  • Para histogramas que acompanham um valor por pedido, como um intervalo de tempo ou bytes enviados por pedido, o painel recolhe os valores numa série de intervalos e representa graficamente os percentis P50, P90 e P99. Os resultados do histograma podem incluir exemplos, que são pontos de dados individuais juntamente com o ID de trace/span dessa solicitação. O painel mostra estes pontos no gráfico. Selecione um para navegar até ao respetivo traço, assim pode ver o que causou esse valor. Esta funcionalidade ajuda-o a diagnosticar exceções.
  • As métricas podem incluir dimensões, que são pares chave/valor associados a valores individuais. O painel agrega valores por dimensão. Use os dropdowns na vista para filtrar resultados por dimensões específicas, como GET apenas pedidos, ou uma rota URL específica no ASP.NET.

9.3 Vista de rastreio

A vista de rastreamento lista os traços. Cada traço é um conjunto de atividades que partilham o mesmo ID de traço. Os spans monitorizam o trabalho, e cada span representa uma unidade de trabalho. Processar um pedido de ASP.NET cria um intervalo. Fazer um pedido HttpClient é um intervalo de tempo. Ao rastrear o span principal de cada span, constrói-se uma hierarquia de spans que pode ser visualizada. Quando recolhe intervalos de cada recurso (processo), pode acompanhar o trabalho através de uma série de serviços. Os pedidos HTTP incluem um cabeçalho que transmite o ID de rastreio e o ID do span principal para o serviço seguinte. Cada recurso deve recolher telemetria e enviá-la para o mesmo coletor, que depois agrega e apresenta uma hierarquia dos intervalos.

Rastreamentos em painel independente

O painel mostra uma lista de rastreios com informação resumida. Sempre que o painel detetar spans com um novo ID de traço, adiciona uma linha à tabela. Selecione View para mostrar todos os spans no rastreio.

Espaços no painel autónomo

Selecione um vão para mostrar os seus detalhes, incluindo quaisquer propriedades do vão, como a greeting etiqueta que definiu no passo 7.