Condividi tramite


Osservabilità di .NET con OpenTelemetry

Quando si esegue un'applicazione, si vuole sapere quanto questa sia efficace e rilevare potenziali problemi prima che si amplifichino. A tale scopo, è possibile generare dati di telemetria, ad esempio log o metriche dall'app, quindi monitorare e analizzare tali dati.

Che cos'è l'osservabilità?

L'osservabilità nel contesto di un sistema distribuito è la possibilità di monitorare e analizzare i dati di telemetria sullo stato di ciascun componente, di poter osservare le modifiche nelle prestazioni e di diagnosticare il motivo per cui si verificano tali modifiche. A differenza del debug, che è invasivo e può influire sul funzionamento dell'applicazione, l'osservabilità è progettata per essere trasparente per l'operazione primaria e avere un impatto sufficientemente ridotto sulle prestazioni, tanto che può essere usata in modo continuato.

L'osservabilità viene in genere eseguita usando una combinazione di:

  • Log, che registrano singole operazioni, ad esempio una richiesta in ingresso, un errore in un componente specifico o un ordine da effettuare.
  • Metriche, che misurano contatori e misuratori, ad esempio il numero di richieste completate, le richieste attive, i widget venduti, o un istogramma che riporta la latenza della richiesta.
  • Traccia distribuita, che traccia le richieste e le attività in essere tra i componenti in un sistema distribuito, in modo da poter vedere dove viene impiegato il tempo e tenere traccia di errori specifici.

Insieme, log, metriche e traccia distribuita sono noti come i tre pilastri dell'osservabilità.

Ogni pilastro può includere dati di telemetria da:

  • Runtime .NET, come Garbage Collector o il compilatore JIT.
  • Librerie, ad esempio da Kestrel (il server Web ASP.NET) e HttpClient.
  • Telemetria specifica dell'applicazione generata dal codice.

Approcci di osservabilità in .NET

Esistono diversi modi per ottenere l'osservabilità nelle applicazioni .NET:

  • In modo esplicito nel codice, facendo riferimento a e usando una libreria come OpenTelemetry. Se si ha accesso al codice sorgente ed è possibile ricompilare l'app, questo è il meccanismo più potente e configurabile.
  • Out-of-process attraverso l’utilizzo di EventPipe. Strumenti come dotnet-monitor possono “ascoltare” i log e le metriche e quindi elaborarli senza influire sul codice.
  • Usando un hook di avvio, gli assembly possono essere inseriti nel processo che può quindi raccogliere la strumentazione. Un esempio di tale approccio è OpenTelemetry .NET Automatic Instrumentation.

Che cos'è OpenTelemetry?

OpenTelemetry (OTel) è uno standard multipiattaforma aperto per la raccolta e la generazione di dati di telemetria. OpenTelemetry include:

  • API per le librerie utilizzabili per registrare i dati di telemetria durante l'esecuzione del codice.
  • API che gli sviluppatori di applicazioni usano per configurare la parte dei dati registrati che verranno inviati in rete, dove verranno inviati e come potranno essere filtrati, memorizzati nel buffer, arricchiti e trasformati.
  • Le convenzioni semantiche forniscono indicazioni sulla denominazione e sul contenuto dei dati di telemetria. È importante che le app che producono dati di telemetria e gli strumenti che ricevono tali dati concordino sul significato dei diversi tipi di dati e su quali tipi di dati sono utili, in modo che gli strumenti possano fornire un'analisi efficace.
  • Interfaccia per gli esportatori. Gli esportatori sono plug-in che consentono la trasmissione dei dati di telemetria in formati specifici a back-end di telemetria diversi.
  • Il protocollo di collegamento OTLP è un'opzione di protocollo di rete indipendente dal fornitore finalizzato alla trasmissione dei dati di telemetria. Alcuni strumenti e fornitori supportano questo protocollo oltre ai protocolli proprietari preesistenti di cui potrebbero essere dotati.

L'impiego di OTel consente l'uso di un'ampia gamma di sistemi APM, tra cui sistemi open source come Prometheus e Grafana, Monitoraggio di Azure, il prodotto APM di Microsoft in Azure o dei numerosi fornitori di APM che collaborano con OpenTelemetry.

Sono disponibili implementazioni di OpenTelemetry per la maggior parte dei linguaggi e delle piattaforme, tra cui .NET.

Implementazione .NET di OpenTelemetry

L'implementazione di .NET di OpenTelemetry è leggermente diversa da altre piattaforme, perché .NET fornisce le API di registrazione, di metriche e attività nel framework. Ciò significa che OTel non deve fornire API che gli autori di librerie sono tenuti a utilizzare. L'implementazione OTel di .NET usa queste API della piattaforma per la strumentazione:

Architettura OTel di .NET

OTel entra in gioco nel momento in cui raccoglie i dati di telemetria da tali API e da altre origini (tramite librerie di strumentazione) per poi esportarli in un sistema di monitoraggio delle prestazioni dell'applicazione (APM) per archiviazione e analisi. Il vantaggio offerto da OTel come standard di settore è un meccanismo comune per la raccolta, gli schemi comuni e la semantica per i dati di telemetria e un'API per il modo in cui le API possono integrarsi con OTel. L'uso di OTel significa che le applicazioni non devono usare API o strutture di dati specifiche di APM, ma funzionano secondo lo standard OTel. Le API possono indifferentemente implementare un componente di esportazione specifico di APM o usare OTLP, un nuovo standard di trasmissione per l'esportazione dei dati di telemetria nei sistemi APM.

Pacchetti OpenTelemetry

OpenTelemetry in .NET viene implementato come una serie di pacchetti NuGet che formano un paio di categorie:

  • API Core
  • Strumentazione: questi pacchetti raccolgono la strumentazione dal runtime e dalle librerie comuni.
  • Utilità di esportazione: queste si interfacciano con sistemi APM come Prometheus, Jaeger e OTLP.

Nella tabella seguente vengono descritti i pacchetti principali.

Nome pacchetto Descrizione
OpenTelemetry Libreria principale che fornisce la funzionalità OTEL di base
OpenTelemetry.Instrumentation.AspNetCore Strumentazione per ASP.NET Core e Kestrel
OpenTelemetry.Instrumentation.GrpcNetClient Strumentazione per il client gRPC per tenere traccia delle chiamate gRPC in uscita
OpenTelemetry.Instrumentation.Http Strumentazione per HttpWebRequest e HttpClient finalizzata a tenere traccia delle chiamate HTTP in uscita
OpenTelemetry.Instrumentation.SqlClient Strumentazione per il SqlClient utilizzato per tracciare le operazioni del database
OpenTelemetry.Exporter.Console Utilità di esportazione per la console, comunemente usata per diagnosticare i dati di telemetria da esportare
OpenTelemetry.Exporter.OpenTelemetryProtocol Esportazione tramite il protocollo OTLP
OpenTelemetry.Exporter.Prometheus.AspNetCore Utilità di esportazione per Prometheus implementata con un endpoint ASP.NET Core
OpenTelemetry.Exporter.Zipkin Utilità di esportazione per la traccia Zipkin

Esempio: usare Prometheus, Grafana e Jaeger

Questo esempio utilizza Prometheus per la raccolta di metriche, Grafana per la creazione di una dashboard e Jaeger per visualizzare la traccia distribuita.

1. Creare il progetto

Creare un semplice progetto API Web usando il modello ASP.NET Core Empty in Visual Studio o il comando dell'interfaccia della riga di comando .NET CLI seguente:

dotnet new web

2. Aggiungere metriche e definizioni di attività

Il codice seguente definisce una nuova metrica (greetings.count) per il numero di chiamate ricevute dall'API e una nuova origine attività (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. Creare un endpoint API

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

Nota

La definizione dell'API non usa elementi specifici di OpenTelemetry. Usa le API .NET per l'osservabilità.

4. Fare riferimento ai pacchetti OpenTelemetry

Usare Gestione pacchetti NuGet o la riga di comando per aggiungere i pacchetti NuGet seguenti:

<ItemGroup>
   <PackageReference Include="OpenTelemetry.Exporter.Console" Version="1.5.0" />
   <PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.5.0" />
   <PackageReference Include="OpenTelemetry.Exporter.Prometheus.AspNetCore" Version="1.5.0-rc.1" />
   <PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.5.0" />
   <PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.5.0-beta.1" />
   <PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.5.0-beta.1" />
</ItemGroup>

Nota

Usare le versioni più recenti, perché le API OTel sono in continua evoluzione.

5. Configurare OpenTelemetry con i provider corretti

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")
    .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();
    }
});

Questo codice usa strumentazione ASP.NET Core per ottenere metriche e attività da ASP.NET Core. Registra anche i provider Metrics e ActivitySource rispettivamente per le metriche e la traccia.

Il codice usa l'utilità di esportazione Prometheus per le metriche, che a sua volta usa ASP.NET Core per ospitare l'endpoint, quindi è necessario aggiungere:

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

6. Eseguire il progetto

Eseguire il progetto e quindi accedere all'API con il browser o il curl.

curl -k http://localhost:7275

Ogni volta che si richiede la pagina, il conteggio verrà incrementato per il numero di messaggi di saluto che sono stati effettuati. È possibile accedere all'endpoint delle metriche usando lo stesso URL di base, con il percorso /metrics.

6.1 Output del log

Le istruzioni di registrazione del codice vengono restituite usando ILogger. Per impostazione predefinita, il Provider console è abilitato in modo che l'output venga indirizzato alla console.

Sono disponibili due opzioni per la modalità di uscita dei log da .NET:

  • L’output stdout e stderr viene reindirizzato ai file di log dai sistemi contenitore, ad esempio Kubernetes.
  • Usando le librerie di registrazione che si integreranno con ILogger, queste includono Serilog o NLog.
  • Uso di provider di registrazione per OTel, ad esempio OTLP o l'utilità di esportazione di Monitoraggio di Azure, illustrata più avanti.

6.2 Accedere alle metriche

È possibile accedere alle metriche usando l'endpoint /metrics.

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
...

L'output delle metriche è uno snapshot delle metriche effettuato al momento della richiesta dell'endpoint. I risultati vengono forniti in formato di esposizione Prometheus, un formato leggibile ma meglio compreso da Prometheus. Questo argomento viene trattato nella fase successiva.

6.3 Accedere alla traccia

Se si esamina la console per il server, verrà visualizzato l'output dell'utilità di esportazione di traccia della console, che restituisce le informazioni in un formato leggibile. Verranno visualizzate due attività, una dall'oggetto personalizzato ActivitySource e l'altra da 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

La prima è l'attività personalizzata interna creata. La seconda viene creata da ASP.NET per la richiesta e include tag per le proprietà della richiesta HTTP. Si noterà che entrambe hanno lo stesso TraceId, che identifica una singola transazione e in un sistema distribuito può essere usato per correlare le tracce di ogni servizio coinvolto in una transazione. Gli ID vengono trasmessi come intestazioni HTTP. ASP.NET Core assegna un valore TraceId se non ne è presente uno al momento della ricezione di una richiesta. HttpClient include le intestazioni per impostazione predefinita nelle richieste in uscita. Ogni attività ha un SpanId, che è la combinazione di TraceId e SpanId che identifica in modo univoco ogni attività. L'attività Greeter è padre dell'attività HTTP tramite ParentSpanId, che esegue il mapping all'oggetto SpanId dell'attività HTTP.

In una fase successiva questi dati verranno inseriti in Jaeger per visualizzare le tracce distribuite.

7. Raccogliere metriche con Prometheus

Prometheus è una raccolta, un'aggregazione e un sistema di database a serie temporale di metriche. Viene configurato con gli endpoint delle metriche per ciascun servizio e archivia periodicamente i valori nel database a serie temporale. È quindi possibile analizzarli ed elaborarli in base alle esigenze.

I dati delle metriche esposti in formato Prometheus sono un’istantanea puntuale delle metriche del processo. Ogni volta che viene effettuata una richiesta all'endpoint delle metriche, verranno riportati i valori correnti. Pur essendo i valori correnti interessanti, essi acquistano maggiore importanza se confrontati con i valori nel tempo per vedere le tendenze e rilevare se vi sono anomalie. In genere, i servizi hanno picchi di utilizzo in base all'ora del giorno o agli eventi mondiali, ad esempio il boom di shopping in occasione del Black Friday. Confrontando i valori con le tendenze temporali, è possibile rilevare se vi sono anomalie o se una metrica sta lentamente peggiorando nel tempo.

Il processo non archivia alcuna cronologia di queste istantanee delle metriche. L'aggiunta di tale funzionalità al processo potrebbe comportare un uso intensivo delle risorse. Inoltre, in un sistema distribuito si hanno comunemente più istanze di ogni nodo, quindi si vuole poter raccogliere le metriche da ciascuna di esse per poi aggregarle e confrontarle con i loro valori storici.

7.1 Installare e configurare Prometheus

Scaricare Prometheus nella versione adatta per la propria piattaforma da https://prometheus.io/download/ ed estrarre il contenuto del download.

Esaminare la parte superiore dell'output del server in esecuzione per ottenere il numero di porta per l'endpoint http. Ad esempio:

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

Modificare il file di configurazione YAML di Prometheus per specificare la porta per l'endpoint di scorporo HTTP e impostare un intervallo di scorporo inferiore. Ad esempio:

  scrape_configs:
  # The job name is added as a label `job=<job_name>` to any timeseries scraped from this config.
  - job_name: "prometheus"
    - scrape_interval: 1s # poll very quickly for a more responsive demo

    # 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"]

Avviare Prometheus e cercare nell'output la porta in cui è in esecuzione, in genere è 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

Aprire questo URL nel browser. Nell'interfaccia utente di Prometheus dovrebbe ora essere possibile eseguire query per le metriche. Usare il pulsante evidenziato nell'immagine seguente per aprire Esplora metriche, che mostra tutte le metriche disponibili.

Esplora metriche Prometheus

Selezionare la metrica greetings_count per visualizzare un grafico di valori.

Grafico delle greetings_count

8. Usare Grafana per creare una dashboard delle metriche

Grafana è un prodotto di dashboarding grado di creare dashboard e avvisi basati su Prometheus o altre origini dati.

Scaricare e installare la versione OSS di Grafana da https://grafana.com/oss/grafana/ seguendo le istruzioni per la propria piattaforma. Una volta installato, Grafana viene in genere eseguito sulla porta 3000, quindi aprire http://localhost:3000 nel browser. Sarà necessario effettuare l'accesso; il nome utente e la password predefiniti sono entrambi admin.

Dal menu hamburger scegliere le connessioni, quindi immettere il testo prometheus per selezionare il tipo di endpoint. Selezionare Crea un'origine dati Prometheus per aggiungere una nuova origine dati.

Connessione Grafana a Prometheus

È necessario impostare le proprietà seguenti:

  • URL del server Prometheus: http://localhost:9090/ modifica della porta in base alle esigenze

Selezionare Salva e test per verificare la configurazione.

Dopo aver visualizzato un messaggio di operazione riuscita, è possibile configurare una dashboard. Fare clic sul collegamento compilazione di una dashboard visualizzato nella finestra popup per il messaggio di operazione riuscita.

Selezionare Aggiungi una visualizzazione, quindi scegliere l'origine dati Prometheus appena aggiunta come origine dati.

Verrà visualizzata la finestra di progettazione del pannello della dashboard. Nella metà inferiore dello schermo è possibile definire la query.

Query Grafana con greetings_count

Selezionare la metrica greetings_count, quindi selezionare Esegui query per visualizzare i risultati.

Con Grafana è possibile progettare dashboard sofisticate che tengono traccia di qualsiasi numero di metriche.

Ogni metrica in .NET può avere dimensioni aggiuntive, ovvero coppie chiave-valore che possono essere usate per partizionare i dati. Le metriche ASP.NET dispongono tutte di una serie di dimensioni applicabili al contatore. Ad esempio, il contatore current-requests di Microsoft.AspNetCore.Hosting ha le dimensioni seguenti:

Attributo Tipo Descrizione Esempi Presenza
method string Metodo della richiesta HTTP. GET; POST; HEAD Sempre
scheme string Schema URI che identifica il protocollo usato. http; https Sempre
host string Nome del server HTTP locale che ha ricevuto la richiesta. localhost Sempre
port int Porta del server HTTP locale che ha ricevuto la richiesta. 8080 Aggiunta se non è predefinita (80 per http o 443 per https)

I grafici in Grafana vengono in genere partizionati in base a ogni combinazione univoca di dimensioni. Le dimensioni possono essere usate nelle query Grafana per filtrare o aggregare i dati. Ad esempio, se si esegue un grafico current_requests, si vedranno i valori suddivisi in base a ciascuna combinazione di dimensioni. Per filtrare solo in base all'host, aggiungere un'operazione di Sum e usare host come valore dell'etichetta.

Grafana current_requests dall'host

9. Traccia distribuita con Jaeger

Nel passaggio 6 si è visto che le informazioni di traccia distribuite sono state esposte alla console. Tali informazioni tengono traccia delle unità di lavoro con le attività. Alcune attività vengono create automaticamente dalla piattaforma, ad esempio quella di ASP.NET per rappresentare la gestione di una richiesta, e le librerie e il codice dell'applicazione possono anch’esse creare delle attività. L'esempio di saluto ha un'attività Greeter. Le attività vengono correlate usando i tag TraceId, SpanId e ParentId.

Ogni processo in un sistema distribuito produce un proprio flusso di informazioni sulle attività e, al pari delle metriche, è necessario un sistema che raccolga, archivi e correli le attività per poter visualizzare il lavoro svolto per ogni singola transazione. Jaeger è un progetto open source in grado di abilitare questa raccolta e visualizzazione.

Scaricare l'archivio di distribuzione binaria più recente di Jaeger per la propria piattaforma da https://www.jaegertracing.io/download/.

Estrarre quindi il download in un percorso locale accessibile facilmente. Eseguire il file eseguibile jaeger-all-in-one(.exe):

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

Esaminare l'output della console per trovare la porta in cui è in ascolto del traffico OTLP tramite gRPC. Ad esempio:

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

Questo output indica che è in ascolto su 0.0.0.0:4317: in questo modo è possibile configurare tale porta come destinazione per l'utilità di esportazione OTLP.

Aprire il file AppSettings.json dedicato al progetto e aggiungere la riga seguente, modificando la porta, se del caso.

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

Riavviare il processo greeter in modo che possa raccogliere la modifica della proprietà e iniziare a indirizzare le informazioni di traccia a Jaeger.

A questo punto, dovrebbe essere possibile visualizzare l'interfaccia utente Jaeger in http://localhost:16686/ da un browser Web.

Query Jaeger per le tracce

Per visualizzare un elenco di tracce, selezionare OTel-Prometheus-grafana-Jaeger dall'elenco a discesa Servizio. La selezione di una traccia dovrebbe mostrare un grafico gant delle attività come parte di tale traccia. Facendo clic su ognuna delle operazioni vengono visualizzati altri dettagli sull'attività.

Dettagli operazione Jaeger

In un sistema distribuito si vogliono inviare tracce da tutti i processi alla stessa installazione di Jaeger in modo che possa correlare le transazioni nel sistema.

È possibile rendere l'app un po' più interessante facendo in modo che faccia chiamate HTTP a se stessa.

  • Aggiungere una factory HttpClient all'applicazione

    builder.Services.AddHttpClient();
    
  • Aggiungere un nuovo endpoint per effettuare chiamate di saluto annidate

    app.MapGet("/NestedGreeting", SendNestedGreeting);
    
  • Implementare l'endpoint in modo da effettuare chiamate HTTP che possano essere anche tracciate. In questo caso, richiama se stessa in un ciclo artificiale (applicabile solo agli scenari demo).

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

Ciò comporta un grafico più interessante con una forma a piramide per le richieste, in quanto ogni livello attende la risposta dalla chiamata precedente.

Risultati delle dipendenze annidate Jaeger

Esempio: usare Monitoraggio di Azure e Application Insights

Nell'esempio precedente sono state usate applicazioni open source separate per le metriche e la traccia. Sono disponibili molti sistemi APM commerciali tra cui scegliere. In Azure il prodotto principale di monitoraggio delle applicazioni è Application Insights, che fa parte di Monitoraggio di Azure.

Uno dei vantaggi di un prodotto APM integrato è che può correlare le diverse origini dati di osservabilità. Per semplificare l'esperienza di ASP.NET con Monitoraggio di Azure, viene fornito un pacchetto wrapper che esegue la maggior parte della configurazione di OpenTelemetry.

Prendere lo stesso progetto dal Passaggio 5 e sostituire i riferimenti NuGet con un singolo pacchetto:

<ItemGroup>
  <PackageReference Include="Azure.Monitor.OpenTelemetry.AspNetCore" Version="1.0.0-beta.4" />
</ItemGroup>

Sostituire quindi il codice di inizializzazione OTel con:

var otel = builder.Services.AddOpenTelemetry();
otel.UseAzureMonitor();
otel.WithMetrics(metrics => metrics
    .AddMeter(greeterMeter.Name)
    .AddMeter("Microsoft.AspNetCore.Hosting")
    .AddMeter("Microsoft.AspNetCore.Server.Kestrel"));
otel.WithTracing(tracing =>
{
    tracing.AddSource(greeterActivitySource.Name);
});

UseAzureMonitor() è il tocco magico che aggiungerà le librerie di strumentazione e gli esportatori comuni per Application Insights. È sufficiente aggiungere i nomi Meter e ActivitySource personalizzati alla registrazione.

Se non si è già un clienti di Azure, è possibile creare un account gratuito all'indirizzo https://azure.microsoft.com/free/. Accedere al portale di Azure e selezionare una risorsa di Application Insights esistente o crearne una nuova con https://ms.portal.azure.com/#create/Microsoft.AppInsights.

Application Insights identifica l'istanza da usare per archiviare ed elaborare i dati tramite una chiave di strumentazione e una stringa di connessione disponibili in alto a destra nell'interfaccia utente del portale.

Stringa di connessione nel portale di Azure

Se si usa il servizio app di Azure, questa stringa di connessione viene trasmessa automaticamente all'applicazione come variabile di ambiente. Per altri servizi o durante l'esecuzione in locale, è necessario trasmetterla usando la variabile di ambiente APPLICATIONINSIGHTS_CONNECTION_STRING o in appsettings.json. Per l'esecuzione in locale, è più semplice aggiungere il valore a appsettings.json:

"AzureMonitor": {
    "ConnectionString": "InstrumentationKey=12345678-abcd-abcd-abcd-12345678..."
}

Nota

Sostituire il valore con quello dell'istanza.

Quando si esegue l'applicazione, i dati di telemetria verranno inviati ad Application Insights. Ora si dovrebbero ottenere log, metriche e tracce distribuite per la propria applicazione.

Registri

Visualizzazione dei log di App Insights

Metriche

Visualizzazione delle metriche di App Insights

Traccia distribuita

Visualizzazione delle transazioni di App Insights