Como Criar um Projeto com .NET, OpenTelemetry e Docker Usando .NET Aspire para Logs

Introdução

Olá, devs! Vamos embarcar em uma jornada empolgante: criar um projeto simples utilizando .NET 8, configurar OpenTelemetry para instrumentar nosso ASP.NET Core e HTTP, e finalmente, subir nossa aplicação em um ambiente Docker.

Além disso, vamos usar o .NET Aspire para monitorar os logs da nossa aplicação.

Esse tutorial é ideal tanto para quem está começando quanto para desenvolvedores mais experientes que querem explorar novas ferramentas e práticas.

Bora?

Open Telemetry Aspire Docker .net

Configuração Inicial do Projeto com .NET 8

Para começar, vamos criar um novo projeto ASP.NET Core utilizando o .NET 8. Abra seu terminal e execute os seguintes comandos:

dotnet new webapi -n MeuProjetoAspNet
cd MeuProjetoAspNet
dotnet add package OpenTelemetry --version 1.9.0
dotnet add package OpenTelemetry.Extensions.Hosting --version 1.9.0
dotnet add package OpenTelemetry.Instrumentation.AspNetCore --version 1.9.0
dotnet add package OpenTelemetry.Instrumentation.Http --version 1.9.0
dotnet add package OpenTelemetry.Exporter.OpenTelemetryProtocol --version 1.9.0

Esses comandos criam um novo projeto Web API e adicionam os pacotes necessários do OpenTelemetry.

Implementação do OpenTelemetry no ASP.NET Core

Agora, vamos configurar o OpenTelemetry no nosso projeto.

No arquivo Program.cs, adicione o seguinte código:

using OpenTelemetry.Resources;
using OpenTelemetry.Metrics;
using OpenTelemetry.Trace;

var builder = WebApplication.CreateBuilder(args);

// Adiciona serviços ao contêiner
builder.Services.AddControllers();

// Configura o OpenTelemetry
builder.Services.AddOpenTelemetry()
    .ConfigureResource(resource => resource.AddService("MeuProjetoAspNet"))
    .WithMetrics(metrics =>
    {
        metrics
            .AddAspNetCoreInstrumentation()
            .AddHttpClientInstrumentation()
            .AddOtlpExporter();
    })
    .WithTracing(tracing =>
    {
        tracing
            .AddAspNetCoreInstrumentation()
            .AddHttpClientInstrumentation()
            .AddOtlpExporter();
    });

builder.Logging.ClearProviders();
builder.Logging.AddOpenTelemetry(logging =>
{
    logging.IncludeScopes = true;
    logging.IncludeFormattedMessage = true;
    logging.AddOtlpExporter();
});

var app = builder.Build();

// Configura o pipeline HTTP
if (app.Environment.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
}

app.UseRouting();

app.UseEndpoints(endpoints =>
{
    endpoints.MapControllers();
});

app.Run();

Esse código configura o OpenTelemetry para instrumentar ASP.NET Core e HTTP, e exportar as informações para o OTLP (OpenTelemetry Protocol).

Criação de um endpoint de exemplo

Para instrumentar chamadas HTTP, precisamos adicionar a instrumentação do HttpClient. A configuração já foi feita no passo anterior, mas vamos garantir que as chamadas HTTP também sejam monitoradas.

Crie uma controller de exemplo e adicione um endpoint que verifica se um número é primo:

using Microsoft.AspNetCore.Mvc;

[ApiController]
[Route("primes")]
public class PrimeController : ControllerBase
{
    [HttpGet("{number:int}")]
    public IActionResult IsPrime(int number)
    {
        if (number < 1)
            return BadRequest("O número deve ser maior ou igual a 1.");

        bool isPrime = IsPrimeNumber(number);

        return Ok(new { Number = number, IsPrime = isPrime });
    }

    private bool IsPrimeNumber(int number)
    {
        if (number < 2)
            return false;

        for (int i = 2; i <= Math.Sqrt(number); i++)
        {
            if (number % i == 0)
                return false;
        }

        return true;
    }
}

As chamadas para este endpoint que serão exportadas para o OTLP (OpenTelemetry Protocol).

Dockerizando a Aplicação

Para dockerizar a aplicação, crie um arquivo Dockerfile na raiz do projeto:

# Use uma imagem base do .NET
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
WORKDIR /app
EXPOSE 80

FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
COPY ["MeuProjetoAspNet/MeuProjetoAspNet.csproj", "MeuProjetoAspNet/"]
RUN dotnet restore "MeuProjetoAspNet/MeuProjetoAspNet.csproj"
COPY . .
WORKDIR "/src/MeuProjetoAspNet"
RUN dotnet build "MeuProjetoAspNet.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "MeuProjetoAspNet.csproj" -c Release -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "MeuProjetoAspNet.dll"]

E um arquivo docker-compose.yml:

version: '3.4'

services:
  open-telemetry-aspire:
    image: ${DOCKER_REGISTRY-}meu-projeto-aspnet
    container_name: api
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - "8080:8080"
    environment:
      - OTEL_EXPORTER_OTLP_ENDPOINT=http://aspire.dashboard:18889
    networks:
      - otel

  aspire.dashboard:
    image: mcr.microsoft.com/dotnet/nightly/aspire-dashboard:latest
    container_name: dashboard
    ports:
      - "18888:18888"
    networks:
      - otel

networks:
  otel:

Para construir e rodar o container, execute:

docker-compose up --build

Testando e Verificando os Logs no .NET Aspire

Com a aplicação rodando em Docker, podemos testá-la e verificar se os logs estão sendo enviados corretamente para o .NET Aspire. Faça algumas requisições à API e depois acesse o painel do .NET Aspire para visualizar os logs:

curl http://localhost:8080/primes/7
curl http://localhost:8080/primes/-1

No painel do .NET Aspire, você deverá ver os logs das requisições, incluindo detalhes sobre a instrumentação do OpenTelemetry.

Conclusão e Próximos Passos

Parabéns, devs! Vocês configuraram um projeto ASP.NET Core com .NET 8, adicionaram instrumentação com OpenTelemetry, dockerizaram a aplicação e configuraram o monitoramento de logs com o .NET Aspire.

Esse setup proporciona uma visão abrangente do comportamento da sua aplicação, facilitando o monitoramento e a resolução de problemas.

Explore mais sobre o OpenTelemetry e o .NET Aspire para tirar o máximo proveito dessas ferramentas e me escreva nos comentários o que achou.

E aqui vai um projeto de exemplo com tudo isso: [GitHub]

Até!