Dela via


Exempel: Använda OpenTelemetry med Prometheus, Grafana och Jaeger

I det här exemplet används Prometheus för måttsamling, Grafana för att skapa en instrumentpanel och Jaeger för att visa distribuerad spårning.

1. Skapa projektet

Skapa ett enkelt webb-API-projekt med hjälp av mallen ASP.NET Core Empty i Visual Studio eller följande .NET CLI-kommando:

dotnet new web

2. Lägg till mått och aktivitetsdefinitioner

Följande kod definierar ett nytt mått (greetings.count) för hur många gånger API:et har anropats och en ny aktivitetskälla (OtPrGrYa.Example).

// Custom metrics for the application
var greeterMeter = new Meter("OtPrGrYa.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("OtPrGrJa.Example");

3. Skapa en API-slutpunkt

app.MapGet("/", SendGreeting);
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!";
}

Kommentar

API-definitionen använder inte något specifikt för OpenTelemetry. Den använder .NET-API:erna för observerbarhet.

4. Referera till OpenTelemetry-paketen

Använd NuGet Package Manager eller kommandoraden för att lägga till följande NuGet-paket:

<ItemGroup>
    <PackageReference Include="OpenTelemetry.Exporter.Console" Version="1.9.0" />
    <PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.9.0" />
    <PackageReference Include="OpenTelemetry.Exporter.Prometheus.AspNetCore" Version="1.9.0-beta.2" />
    <PackageReference Include="OpenTelemetry.Exporter.Zipkin" 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>

Kommentar

Använd de senaste versionerna eftersom OTel-API:erna ständigt utvecklas.

5. Konfigurera OpenTelemetry med rätt leverantörer

var tracingOtlpEndpoint = builder.Configuration["OTLP_ENDPOINT_URL"];
var otel = builder.Services.AddOpenTelemetry();

// Configure OpenTelemetry Resources with the application name
otel.ConfigureResource(resource => resource
    .AddService(serviceName: builder.Environment.ApplicationName));

// Add Metrics for ASP.NET Core and our custom metrics and export to Prometheus
otel.WithMetrics(metrics => metrics
    // Metrics provider from OpenTelemetry
    .AddAspNetCoreInstrumentation()
    .AddMeter(greeterMeter.Name)
    // Metrics provides by ASP.NET Core in .NET 8
    .AddMeter("Microsoft.AspNetCore.Hosting")
    .AddMeter("Microsoft.AspNetCore.Server.Kestrel")
    // Metrics provided by System.Net libraries
    .AddMeter("System.Net.Http")
    .AddMeter("System.Net.NameResolution")
    .AddPrometheusExporter());

// Add Tracing for ASP.NET Core and our custom ActivitySource and export to Jaeger
otel.WithTracing(tracing =>
{
    tracing.AddAspNetCoreInstrumentation();
    tracing.AddHttpClientInstrumentation();
    tracing.AddSource(greeterActivitySource.Name);
    if (tracingOtlpEndpoint != null)
    {
        tracing.AddOtlpExporter(otlpOptions =>
         {
             otlpOptions.Endpoint = new Uri(tracingOtlpEndpoint);
         });
    }
    else
    {
        tracing.AddConsoleExporter();
    }
});

Den här koden använder ASP.NET Core-instrumentation för att hämta mått och aktiviteter från ASP.NET Core. Den registrerar även leverantörerna Metrics och ActivitySource för mått respektive spårning.

Koden använder Prometheus-exportören för mått, som använder ASP.NET Core som värd för slutpunkten, så du måste också lägga till:

// Configure the Prometheus scraping endpoint
app.MapPrometheusScrapingEndpoint();

6. Kör projektet

Kör projektet och få sedan åtkomst till API:et med webbläsaren eller curl.

curl -k http://localhost:7275

Varje gång du begär sidan ökar antalet hälsningar som har gjorts. Du kan komma åt måttslutpunkten med samma bas-URL med sökvägen /metrics.

6.1 Loggutdata

Loggningsinstruktionerna från koden matas ut med .ILogger Som standard är konsolprovidern aktiverad så att utdata dirigeras till konsolen.

Det finns ett par alternativ för hur loggar kan tas ut från .NET:

  • stdout och stderr utdata omdirigeras till loggfiler av containersystem som Kubernetes.
  • Med hjälp av loggningsbibliotek som ska integreras med ILogger inkluderar dessa Serilog eller NLog.
  • Använda loggningsproviders för OTel, till exempel OTLP eller Azure Monitor-exportören som visas längre ned.

6.2 Få åtkomst till måtten

Du kan komma åt måtten med hjälp av /metrics slutpunkten.

curl -k https://localhost:7275/
Hello World!

curl -k https://localhost:7275/metrics
# TYPE greetings_count counter
# HELP greetings_count Counts the number of greetings
greetings_count 1 1686894204856

# TYPE current_connections gauge
# HELP current_connections Number of connections that are currently active on the server.
current_connections{endpoint="127.0.0.1:7275"} 1 1686894204856
current_connections{endpoint="[::1]:7275"} 0 1686894204856
current_connections{endpoint="[::1]:5212"} 1 1686894204856
...

Måttutdata är en ögonblicksbild av måtten när slutpunkten begärs. Resultaten tillhandahålls i Prometheus expositionsformat, vilket är mänskligt läsbart men bättre förstått av Prometheus. Det ämnet beskrivs i nästa steg.

6.3 Få åtkomst till spårningen

Om du tittar på konsolen för servern ser du utdata från konsolens spårningsexportör, som matar ut informationen i ett läsbart format. Detta bör visa två aktiviteter, en från din anpassade ActivitySourceoch den andra från ASP.NET Core:

Activity.TraceId:            2e00dd5e258d33fe691b965607b91d18
Activity.SpanId:             3b7a891f55b97f1a
Activity.TraceFlags:         Recorded
Activity.ParentSpanId:       645071fd0011faac
Activity.ActivitySourceName: OtPrGrYa.Example
Activity.DisplayName:        GreeterActivity
Activity.Kind:               Internal
Activity.StartTime:          2023-06-16T04:50:26.7675469Z
Activity.Duration:           00:00:00.0023974
Activity.Tags:
    greeting: Hello World!
Resource associated with Activity:
    service.name: OTel-Prometheus-Grafana-Jaeger
    service.instance.id: e1afb619-bc32-48d8-b71f-ee196dc2a76a
    telemetry.sdk.name: opentelemetry
    telemetry.sdk.language: dotnet
    telemetry.sdk.version: 1.5.0

Activity.TraceId:            2e00dd5e258d33fe691b965607b91d18
Activity.SpanId:             645071fd0011faac
Activity.TraceFlags:         Recorded
Activity.ActivitySourceName: Microsoft.AspNetCore
Activity.DisplayName:        /
Activity.Kind:               Server
Activity.StartTime:          2023-06-16T04:50:26.7672615Z
Activity.Duration:           00:00:00.0121259
Activity.Tags:
    net.host.name: localhost
    net.host.port: 7275
    http.method: GET
    http.scheme: https
    http.target: /
    http.url: https://localhost:7275/
    http.flavor: 1.1
    http.user_agent: curl/8.0.1
    http.status_code: 200
Resource associated with Activity:
    service.name: OTel-Prometheus-Grafana-Jaeger
    service.instance.id: e1afb619-bc32-48d8-b71f-ee196dc2a76a
    telemetry.sdk.name: opentelemetry
    telemetry.sdk.language: dotnet
    telemetry.sdk.version: 1.5.0

Den första är den inre anpassade aktiviteten som du skapade. Den andra skapas av ASP.NET för begäran och innehåller taggar för HTTP-begärandeegenskaperna. Du ser att båda har samma TraceId, som identifierar en enskild transaktion och i ett distribuerat system kan användas för att korrelera spårningarna från varje tjänst som ingår i en transaktion. ID:erna överförs som HTTP-huvuden. ASP.NET Core tilldelar en TraceId om ingen finns när den tar emot en begäran. HttpClient innehåller rubrikerna som standard för utgående begäranden. Varje aktivitet har en SpanId, som är kombinationen av TraceId och SpanId som unikt identifierar varje aktivitet. Aktiviteten Greeter är överordnad till HTTP-aktiviteten via dess ParentSpanId, som mappar till SpanId HTTP-aktiviteten.

I ett senare skede matar du in dessa data i Jaeger för att visualisera de distribuerade spårningarna.

7. Samla in mått med Prometheus

Prometheus är ett databassystem för måttsamling, aggregering och tidsserier. Du konfigurerar den med måttslutpunkterna för varje tjänst och den skrapar regelbundet värdena och lagrar dem i sin tidsseriedatabas. Du kan sedan analysera och bearbeta dem efter behov.

De måttdata som exponeras i Prometheus-format är en ögonblicksbild av processens mått. Varje gång en begäran görs till måttslutpunkten rapporterar den aktuella värden. Även om aktuella värden är intressanta blir de mer värdefulla jämfört med historiska värden för att se trender och identifiera om värdena är avvikande. Vanligtvis har tjänster användningstoppar baserat på tid på dagen eller världshändelser, till exempel en semester shoppingrunda. Genom att jämföra värdena med historiska trender kan du identifiera om de är onormala eller om ett mått långsamt blir sämre med tiden.

Processen lagrar ingen historik över dessa måttögonblicksbilder. Att lägga till den funktionen i processen kan vara resurskrävande. I ett distribuerat system har du dessutom ofta flera instanser av varje nod, så du vill kunna samla in måtten från dem alla och sedan aggregera och jämföra med deras historiska värden.

7.1 Installera och konfigurera Prometheus

Ladda ned Prometheus för din plattform från https://prometheus.io/download/ och extrahera innehållet i nedladdningen.

Titta längst upp i utdata från servern som körs för att hämta portnumret för http-slutpunkten . Till exempel:

info: Microsoft.Hosting.Lifetime[14]
      Now listening on: https://localhost:7275
info: Microsoft.Hosting.Lifetime[14]
      Now listening on: http://localhost:5212

Ändra Prometheus YAML-konfigurationsfilen för att ange porten för HTTP-skrapningsslutpunkten och ange ett lägre skrapningsintervall. Till exempel:

  scrape_configs:
  # The job name is added as a label `job=<job_name>` to any timeseries scraped from this config.
  - job_name: "prometheus"

    # metrics_path defaults to '/metrics'
    # scheme defaults to 'http'.

    scrape_interval: 1s # poll very quickly for a more responsive demo
    static_configs:
      - targets: ["localhost:5212"]

Starta Prometheus och titta i utdata för porten som körs på, vanligtvis 9090:

>prometheus.exe
...
ts=2023-06-16T05:29:02.789Z caller=web.go:562 level=info component=web msg="Start listening for connections" address=0.0.0.0:9090

Öppna den här URL:en i webbläsaren. I Användargränssnittet för Prometheus bör du nu kunna fråga efter dina mått. Använd den markerade knappen i följande bild för att öppna metrics Explorer, som visar alla tillgängliga mått.

Prometheus Metrics Explorer

Välj måttet greetings_count för att se ett diagram med värden.

Diagram över greetings_count

8. Använd Grafana för att skapa en instrumentpanel för mått

Grafana är en instrumentpanelsprodukt som kan skapa instrumentpaneler och aviseringar baserat på Prometheus eller andra datakällor.

Ladda ned och installera OSS-versionen av Grafana genom https://grafana.com/oss/grafana/ att följa anvisningarna för din plattform. När grafana har installerats körs det vanligtvis på port 3000, så öppna http://localhost:3000 i webbläsaren. Du måste logga in. standardanvändarnamnet och lösenordet är båda admin.

På hamburgermenyn väljer du anslutningar och anger sedan texten prometheus för att välja din slutpunktstyp. Välj Skapa en Prometheus-datakälla för att lägga till en ny datakälla.

Grafana-anslutning till prometheus

Du måste ange följande egenskaper:

  • Prometheus-server-URL: http://localhost:9090/ ändra porten efter behov

Välj Spara och testa för att verifiera konfigurationen.

När du får ett meddelande om att det har lyckats kan du konfigurera en instrumentpanel. Klicka på länken skapa en instrumentpanel som visas i popup-fönstret för meddelandet om att det lyckades.

Välj Lägg till en visualisering och välj sedan den Prometheus-datakälla som du precis lade till som datakälla.

Designern för instrumentpanelen bör visas. På den nedre halvan av skärmen kan du definiera frågan.

Grafana-fråga med hjälp av greetings_count

Välj måttet greetings_count och välj sedan Kör frågor för att se resultatet.

Med Grafana kan du utforma avancerade instrumentpaneler som spårar valfritt antal mått.

Varje mått i .NET kan ha ytterligare dimensioner, som är nyckel/värde-par som kan användas för att partitioneras data. Alla ASP.NET mått har ett antal dimensioner som gäller för räknaren. Räknaren current-requests från Microsoft.AspNetCore.Hosting har till exempel följande dimensioner:

Attribut Typ Beskrivning Exempel Närvaro
method string HTTP-begärandemetod. GET; POST; HEAD Alltid
scheme string URI-schemat som identifierar det använda protokollet. http; https Alltid
host string Namnet på den lokala HTTP-server som tog emot begäran. localhost Alltid
port int Port för den lokala HTTP-server som tog emot begäran. 8080 Har lagts till om inte standard (80 för http eller 443 för https)

Graferna i Grafana partitioneras vanligtvis baserat på varje unik kombination av dimensioner. Dimensionerna kan användas i Grafana-frågorna för att filtrera eller aggregera data. Om du till exempel ritar current_requestsvisas värden partitionerade baserat på varje kombination av dimensioner. Om du bara vill filtrera baserat på värden lägger du till en åtgärd för Sum och använder host som etikettvärde.

Grafana current_requests efter värd

9. Distribuerad spårning med Jaeger

I steg 6 såg du att distribuerad spårningsinformation exponerades för konsolen. Den här informationen spårar arbetsenheter med aktiviteter. Vissa aktiviteter skapas automatiskt av plattformen, till exempel den av ASP.NET för att representera hanteringen av en begäran, och bibliotek och appkod kan också skapa aktiviteter. Hälsningsexemplet har en Greeter aktivitet. Aktiviteterna korreleras med taggarna TraceId, SpanIdoch ParentId .

Varje process i ett distribuerat system skapar en egen ström av aktivitetsinformation, och precis som mått behöver du ett system för att samla in, lagra och korrelera aktiviteterna för att kunna visualisera det arbete som utförs för varje transaktion. Jaeger är ett projekt med öppen källkod för att aktivera den här samlingen och visualiseringen.

Ladda ned det senaste binära distributionsarkivet för Jaeger för din plattform från https://www.jaegertracing.io/download/.

Extrahera sedan nedladdningen till en lokal plats som är enkel att komma åt. Kör körbara jaeger-all-in-one(.exe) :

./jaeger-all-in-one --collector.otlp.enabled

Titta igenom konsolens utdata för att hitta porten där den lyssnar efter OTLP-trafik via gRPC. Till exempel:

{"level":"info","ts":1686963686.3854616,"caller":"otlpreceiver@v0.78.2/otlp.go:83","msg":"Starting GRPC server","endpoint":"0.0.0.0:4317"}

Det här utdata visar att den lyssnar på 0.0.0.0:4317, så att du kan konfigurera porten som mål för OTLP-exportören.

AppSettings.json Öppna filen för vårt projekt och lägg till följande rad och ändra porten om det är tillämpligt.

"OTLP_ENDPOINT_URL" :  "http://localhost:4317/"

Starta om välkomstprocessen så att den kan hämta egenskapsändringen och börja dirigera spårningsinformation till Jaeger.

Nu bör du kunna se Jaeger-användargränssnittet från http://localhost:16686/ en webbläsare.

Jaeger-fråga för spårningar

Om du vill se en lista över spårningar väljer du OTel-Prometheus-grafana-Jaeger i listrutan Tjänst . Om du väljer en spårning bör ett gantt-schema över aktiviteterna visas som en del av spårningen. Om du klickar på var och en av åtgärderna visas mer information om aktiviteten.

Information om Jaeger-åtgärder

I ett distribuerat system vill du skicka spårningar från alla processer till samma Jaeger-installation så att den kan korrelera transaktionerna i hela systemet.

Du kan göra din app lite mer intressant genom att låta den göra HTTP-anrop till sig själv.

  • Lägga till en HttpClient fabrik i programmet

    builder.Services.AddHttpClient();
    
  • Lägg till en ny slutpunkt för att göra kapslade hälsningsanrop

    app.MapGet("/NestedGreeting", SendNestedGreeting);
    
  • Implementera slutpunkten så att den gör HTTP-anrop som också kan spåras. I det här fallet anropar den tillbaka till sig själv i en artificiell loop (gäller egentligen bara för demoscenarier).

    async Task SendNestedGreeting(int nestlevel, ILogger<Program> logger, HttpContext context, IHttpClientFactory clientFactory)
    {
        // Create a new Activity scoped to the method
        using var activity = greeterActivitySource.StartActivity("GreeterActivity");
    
        if (nestlevel <= 5)
        {
            // Log a message
            logger.LogInformation("Sending greeting, level {nestlevel}", nestlevel);
    
            // Increment the custom counter
            countGreetings.Add(1);
    
            // Add a tag to the Activity
            activity?.SetTag("nest-level", nestlevel);
    
            await context.Response.WriteAsync($"Nested Greeting, level: {nestlevel}\r\n");
    
            if (nestlevel > 0)
            {
                var request = context.Request;
                var url = new Uri($"{request.Scheme}://{request.Host}{request.Path}?nestlevel={nestlevel - 1}");
    
                // Makes an http call passing the activity information as http headers
                var nestedResult = await clientFactory.CreateClient().GetStringAsync(url);
                await context.Response.WriteAsync(nestedResult);
            }
        }
        else
        {
            // Log a message
            logger.LogError("Greeting nest level {nestlevel} too high", nestlevel);
            await context.Response.WriteAsync("Nest level too high, max is 5");
        }
    }
    

Detta resulterar i ett mer intressant diagram med en pyramidform för begäranden, eftersom varje nivå väntar på svaret från föregående anrop.

Resultat av kapslade Jaeger-beroenden