Compartir vía


Observabilidad de .NET con OpenTelemetry

Cuando ejecute una aplicación, querrá saber su rendimiento y detectar posibles problemas antes de que se agraven. Puede hacerlo emitiendo datos de telemetría como registros o métricas de la aplicación y, a continuación, supervisando y analizando esos datos.

¿Qué es la observabilidad?

La observabilidad en el contexto de un sistema distribuido es la capacidad de supervisar y analizar la telemetría sobre el estado de cada componente, para poder observar los cambios en el rendimiento y diagnosticar por qué se producen esos cambios. A diferencia de la depuración, que es invasiva y puede afectar al funcionamiento de la aplicación, la observabilidad pretende ser transparente para el funcionamiento principal y tener un impacto en el rendimiento lo suficientemente pequeño como para que pueda utilizarse de forma continua.

La observabilidad se realiza normalmente mediante una combinación de:

  • Registros, que registran operaciones individuales, como una solicitud entrante, un error en un componente específico o un pedido que se realiza.
  • Métricas, que miden contadores y medidores, como el número de solicitudes completadas, solicitudes activas, widgets que se han vendido; o un histograma de la latencia de la solicitud.
  • Seguimiento distribuido, que realiza un seguimiento de las solicitudes y actividades entre componentes de un sistema distribuido para que pueda ver dónde se invierte el tiempo y realizar un seguimiento de errores específicos.

Juntos, los registros, las métricas y el seguimiento distribuido se conocen como los 3 pilares de observabilidad.

Cada pilar puede incluir datos de telemetría de:

  • El entorno de ejecución de .NET, como el recolector de elementos no utilizados o el compilador JIT.
  • Bibliotecas, como desde Kestrel (el servidor web de ASP.NET) y HttpClient.
  • Telemetría específica de la aplicación emitida por el código.

Enfoques de observabilidad en .NET

Hay varias maneras diferentes de lograr la observabilidad en las aplicaciones de .NET:

  • Explícitamente en el código, consultando y utilizando una biblioteca como OpenTelemetry. Si tiene acceso al código fuente y puede recompilar la aplicación, este es el mecanismo más eficaz y configurable.
  • Fuera de proceso mediante EventPipe. Las herramientas como dotnet-monitor pueden escuchar registros y métricas y, a continuación, procesarlos sin afectar al código.
  • Usando un gancho de inicio, se pueden inyectar montajes en el proceso que luego pueden recopilar instrumentación. Un ejemplo de este enfoque es la Instrumentación automática de OpenTelemetry .NET.

¿Qué es OpenTelemetry?

OpenTelemetry (OTel) es un estándar multiplataforma abierto para recopilar y emitir datos de telemetría. OpenTelemetry incluye:

  • API para bibliotecas que se pueden utilizar para registrar datos de telemetría mientras se ejecuta el código.
  • APIs que los desarrolladores de aplicaciones utilizan para configurar qué parte de los datos registrados se enviarán a través de la red, a dónde se enviarán y cómo pueden filtrarse, almacenarse en búfer, enriquecerse y transformarse.
  • Las convenciones semánticas proporcionan orientación sobre la denominación y el contenido de los datos telemétricos. Es importante que las aplicaciones que producen datos telemétricos y las herramientas que reciben los datos se pongan de acuerdo sobre lo que significan los distintos tipos de datos y qué clase de datos son útiles para que las herramientas puedan proporcionar un análisis eficaz.
  • Una interfaz para exportadores. Los exportadores son complementos que permiten transmitir datos de telemetría en formatos específicos a diferentes back-end de telemetría.
  • El protocolo de conexión OTLP es una opción de protocolo de red neutral del proveedor para transmitir datos de telemetría. Algunas herramientas y proveedores admiten este protocolo además de los protocolos propietarios preexistentes que pueden tener.

El uso de OTel permite el uso de una amplia variedad de sistemas APM, incluidos sistemas de código abierto como Prometheus y Grafana, Azure Monitor: producto de APM de Microsoft en Azure o de muchos proveedores de APM que se asocian con OpenTelemetry.

Hay implementaciones de OpenTelemetry para la mayoría de lenguajes y plataformas, incluido .NET.

Implementación de .NET de OpenTelemetry

La implementación de OpenTelemetry de .NET es un poco diferente de otras plataformas, ya que .NET proporciona las API de registro, métricas y actividad en el marco. Eso significa que OTel no necesita proporcionar API para que las utilicen los autores de bibliotecas. La implementación de OTel de .NET usa estas API de plataforma para la instrumentación:

 Arquitectura OTel de .NET

Donde OTel entra en juego es que recoge telemetría de esas API y otras fuentes (a través de bibliotecas de instrumentación) y luego las exporta a un sistema de monitorización del rendimiento de las aplicaciones (APM) para su almacenamiento y análisis. La ventaja que OTel aporta como estándar del sector es un mecanismo común para la recopilación, los esquemas comunes y la semántica de los datos de telemetría, y una API para cómo se pueden integrar las API con OTel. El uso de OTel significa que las aplicaciones no necesitan usar API o estructuras de datos específicas de APM; funcionan con el estándar OTel. Las API pueden implementar un componente de exportador específico de APM o usar OTLP, que es un nuevo estándar de conexión para exportar datos de telemetría a los sistemas APM.

Paquetes de OpenTelemetry

OpenTelemetry en .NET se implementa como una serie de paquetes NuGet que forman un par de categorías:

  • Core API
  • Instrumentación: estos paquetes recopilan instrumentación de las bibliotecas comunes y en tiempo de ejecución.
  • Exportadores: estas interfaces con sistemas APM como Prometheus, Jaeger y OTLP.

La siguiente tabla describe los principales paquetes.

Nombre del paquete Descripción
OpenTelemetry Biblioteca principal que proporciona la funcionalidad principal de OTEL
OpenTelemetry.Instrumentation.AspNetCore Instrumentación para ASP.NET Core y Kestrel
OpenTelemetry.Instrumentation.GrpcNetClient Instrumentación para el cliente gRPC para realizar un seguimiento de las llamadas gRPC salientes
OpenTelemetry.Instrumentation.Http Instrumentación para HttpClient y HttpWebRequest para el seguimiento de las llamadas HTTP salientes
OpenTelemetry.Instrumentation.SqlClient Instrumentación para SqlClient utilizada para rastrear las operaciones de la base de datos
OpenTelemetry.Exporter.Console Exportador de la consola, que se usa normalmente para diagnosticar qué telemetría se está exportando
OpenTelemetry.Exporter.OpenTelemetryProtocol Exportador que usa el protocolo OTLP
OpenTelemetry.Exporter.Prometheus.AspNetCore Exportador de Prometheus implementado mediante un punto de conexión de ASP.NET Core
OpenTelemetry.Exporter.Zipkin Exportador para el seguimiento de Zipkin

Ejemplo: Usar Prometheus, Grafana y Jaeger

En este ejemplo se usa Prometheus para la recopilación de métricas, Grafana para crear un panel y Jaeger para mostrar el seguimiento distribuido.

1. Creación del proyecto

Cree un proyecto de API web sencillo utilizando la plantilla ASP.NET Core Vacía en Visual Studio o el siguiente comando de la CLI de .NET:

dotnet new web

2. Agregar métricas y definiciones de actividad

El código siguiente define una nueva métrica (greetings.count) para el número de veces que se ha llamado a la API y un nuevo origen de actividad (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. Creación de un punto de conexión de 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 definición de API no usa nada específico para OpenTelemetry. Usa las API de .NET para la observabilidad.

4. Referencia a los paquetes de OpenTelemetry

Use el Administrador de paquetes NuGet o la línea de comandos para agregar los siguientes paquetes NuGet:

<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

Use las versiones más recientes, ya que las API de OTel evolucionan constantemente.

5. Configuración de OpenTelemetry con los proveedores correctos

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

Este código utiliza la instrumentación de ASP.NET Core para obtener métricas y actividades de ASP.NET Core. También registra los proveedores Metrics y ActivitySource para métricas y seguimiento respectivamente.

El código usa el exportador de Prometheus para las métricas, que usa ASP.NET Core para hospedar el punto de conexión, por lo que también debe agregar:

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

6. Ejecución el proyecto

Ejecute el proyecto y acceda a la API con el explorador o curl.

curl -k http://localhost:7275

Cada vez que solicite la página, incrementará el recuento del número de saludos que se han realizado. Puede acceder al punto de conexión de métricas mediante la misma dirección URL base, con la ruta de acceso /metrics.

6.1 Salida del registro

Las instrucciones de registro del código se generan mediante ILogger. De forma predeterminada, el proveedor de consola está habilitado para que la salida se dirija a la consola.

Existen un par de opciones para la salida de registros desde .NET:

  • La salida de stdout y stderr se redirige a archivos de registro por sistemas de contenedores como Kubernetes.
  • Con bibliotecas de registro que se integrarán con ILogger, se incluyen Serilog o NLog.
  • El uso de proveedores de registro para OTel, como OTLP o el exportador de Azure Monitor, se muestra más adelante.

6.2 Acceso a las métricas

Puede acceder a las métricas mediante el punto de conexión /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
...

La salida de las métricas es una instantánea de las métricas en el momento en que se solicita el punto de conexión. Los resultados se proporcionan en formato de exposición Prometheus, que es legible pero mejor comprendido por Prometheus. Ese tema se trata en la siguiente fase.

6.3 Acceso al seguimiento

Si observa la consola del servidor, verá la salida del exportador de seguimiento de la consola, que genera la información en un formato legible. Esto debería mostrar dos actividades, una de la ActivitySource personalizada y la otra de 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 primera es la actividad personalizada interna que creó. La segunda se crea mediante ASP.NET para la solicitud e incluye etiquetas para las propiedades de la solicitud HTTP. Verá que ambos tienen el mismo TraceId, que identifica una sola transacción y en un sistema distribuido se puede usar para correlacionar los seguimientos de cada servicio implicado en una transacción. Los identificadores se transmiten como encabezados HTTP. ASP.NET Core asigna un TraceId si no hay ninguno cuando recibe una solicitud. HttpClient incluye los encabezados de forma predeterminada en las solicitudes salientes. Cada actividad tiene una SpanId, que es la combinación de TraceId y SpanId que identifican de forma única cada actividad. La actividad Greeter está emparentada con la actividad HTTP a través de su ParentSpanId, que se asigna a la SpanId de la actividad HTTP.

En una fase posterior, distribuirá estos datos en Jaeger para visualizar los seguimientos distribuidos.

7. Recopilación de métricas con Prometheus

Prometheus es un sistema de bases de datos de series temporales, agregación y recopilación de métricas. Puede configurarlo con los puntos de conexión de métricas para cada servicio y extrae periódicamente los valores y los almacena en su base de datos de serie temporal. Después, puede analizarlos y procesarlos según sea necesario.

Los datos de métricas que se exponen en formato Prometheus son una instantánea a un momento dado de las métricas del proceso. Cada vez que se realiza una solicitud al punto de conexión de métricas, notificará los valores actuales. Aunque los valores actuales son interesantes, se vuelven más valiosos en comparación con los valores históricos para ver tendencias y detectar si los valores son anómalos. Habitualmente, los servicios tienen picos de uso en función de la hora del día o de acontecimientos mundiales, como una oleada de compras el Black Friday. Al comparar los valores con respecto a las tendencias históricas, puede detectar si son anómalos o si una métrica se empeora lentamente con el tiempo.

El proceso no almacena ningún historial de estas instantáneas de métricas. Añadir esa capacidad al proceso podría requerir muchos recursos. Además, en un sistema distribuido es habitual tener varias instancias de cada nodo, por lo que conviene poder recopilar las métricas de todos ellos y luego agregarlas y compararlas con sus valores históricos.

7.1 Instalación y configuración de Prometheus

Descargue Prometheus para su plataforma desde https://prometheus.io/download/ y extraiga el contenido de la descarga.

Examine la parte superior de la salida del servidor en ejecución para obtener el número de puerto del punto de conexión http . Por ejemplo:

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

Modifique el archivo de configuración de YAML de Prometheus para especificar el puerto del punto de conexión de extracción HTTP y establezca un intervalo de extracción inferior. Por ejemplo:

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

Inicie Prometheus y busque en la salida el puerto en el que se ejecuta, normalmente 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

Abra esta dirección URL en el explorador. En la interfaz de usuario de Prometheus, ahora debería poder consultar las métricas. Use el botón resaltado en la imagen siguiente para abrir el explorador de métricas, que muestra todas las métricas disponibles.

Explorador de métricas Prometheus

Seleccione la métrica greetings_count para ver un gráfico de valores.

Gráfico de greetings_count

8. Uso de Grafana para crear un panel de métricas

Grafana es un producto de paneles que puede crear paneles y alertas basados en Prometheus u otros orígenes de datos.

Descargue e instale la versión del sistema operativo de Grafana de https://grafana.com/oss/grafana/ siguiendo las instrucciones de su plataforma. Una vez instalado, Grafana se ejecuta normalmente en el puerto 3000, por lo que se abre http://localhost:3000 en el explorador. Tendrá que iniciar sesión; el nombre de usuario y la contraseña predeterminados son admin.

En el menú de hamburguesa, elija conexiones y escriba el texto prometheus para seleccionar el tipo de punto de conexión. Seleccione Crear un origen de datos de Prometheus para agregar un nuevo origen de datos.

Conexión de Grafana con Prometheus

Debe establecer las siguientes propiedades:

  • Dirección URL del servidor de Prometheus: http://localhost:9090/ cambiando el puerto según corresponda

Seleccione Guardar y probar para comprobar la configuración.

Una vez que reciba un mensaje de confirmación, puede configurar un panel. Haga clic en el vínculo de creación de un panel que se muestra en la ventana emergente para el mensaje de confirmación.

Seleccione Agregar una visualización y elija el origen de datos de Prometheus que acaba de agregar como origen de datos.

Debería aparecer el diseñador del panel. En la mitad inferior de la pantalla, puede definir la consulta.

Consulta de Grafana usando greetings_count

Seleccione la métrica greetings_count y seleccione Ejecutar consultas para ver los resultados.

Con Grafana, puede diseñar paneles sofisticados que realizarán un seguimiento de cualquier número de métricas.

Cada métrica de .NET puede tener dimensiones adicionales, que son pares clave-valor que se pueden usar para particionar los datos. Todas las métricas de ASP.NET presentan una serie de dimensiones aplicables al contador. Por ejemplo, el contador current-requests de Microsoft.AspNetCore.Hosting tiene las siguientes dimensiones:

Atributo Tipo Descripción Ejemplos Presencia
method string Método de solicitud HTTP. GET; POST; HEAD Siempre
scheme string Esquema de URI que identifica el protocolo usado. http; https Siempre
host string Nombre del servidor HTTP local que recibió la solicitud. localhost Siempre
port int Puerto del servidor HTTP local que recibió la solicitud. 8080 Se agregó si no es el valor predeterminado (80 para http o 443 para https)

Los gráficos de Grafana suelen particionarse en función de cada combinación única de dimensiones. Las dimensiones se pueden usar en las consultas de Grafana para filtrar o agregar los datos. Por ejemplo, si representa un gráfico de current_requests, verá los valores particionados en función de cada combinación de dimensiones. Para filtrar solo en función del host, agregue una operación de Sum y use host como valor de etiqueta.

current_requests de Grafana por host

9. Seguimiento distribuido con Jaeger

En el paso 6, vio que la información de seguimiento distribuido se estaba exponiendo a la consola. Esta información realiza un seguimiento de las unidades de trabajo con actividades. La plataforma crea automáticamente algunas actividades, como la de ASP.NET para representar el control de una solicitud, y las bibliotecas y el código de la aplicación también pueden crear actividades. El ejemplo de saludos tiene una actividad Greeter. Las actividades se correlacionan mediante las etiquetas TraceId, SpanId y ParentId.

Cada proceso de un sistema distribuido genera su propio flujo de información de actividad y, al igual que las métricas, necesita un sistema para recopilar, almacenar y correlacionar las actividades para poder visualizar el trabajo realizado para cada transacción. Jaeger es un proyecto de código abierto para habilitar esta colección y visualización.

Descargue el archivo de distribución binaria más reciente de Jaeger para su plataforma desde https://www.jaegertracing.io/download/.

A continuación, extraiga la descarga en una ubicación local a la que sea fácil acceder. Ejecute el ejecutable jaeger-all-in-one(.exe):

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

Examine la salida de la consola para buscar el puerto donde escucha el tráfico de OTLP a través de gRPC. Por ejemplo:

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

Esta salida indica que está escuchando en 0.0.0.0:4317, por lo que puede configurar ese puerto como destino para el exportador de OTLP.

Abra el archivo AppSettings.json de nuestro proyecto y agregue la siguiente línea, cambiando el puerto si procede.

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

Reinicie el proceso de saludo para que pueda recoger el cambio de propiedad y empezar a dirigir la información de seguimiento a Jaeger.

Ahora, debería poder ver la interfaz de usuario de Jaeger en http://localhost:16686/ desde un explorador web.

Consulta Jaeger para seguimientos

Para ver una lista de seguimientos, seleccione OTel-Prometheus-grafana-Jaeger en la lista desplegable Servicio . La selección de un seguimiento debe mostrar un gráfico gant de las actividades como parte de ese seguimiento. Al hacer clic en cada una de las operaciones se muestran más detalles sobre la actividad.

Detalles de la operación Jaeger

En un sistema distribuido, es conveniente enviar las trazas de todos los procesos a la misma instalación de Jaeger para que pueda correlacionar las transacciones en todo el sistema.

Puede hacer que la aplicación sea un poco más interesante teniendo que realizar llamadas HTTP a sí misma.

  • Adición de una fábrica HttpClient a la aplicación

    builder.Services.AddHttpClient();
    
  • Agregar un nuevo punto de conexión para realizar llamadas de saludo anidadas

    app.MapGet("/NestedGreeting", SendNestedGreeting);
    
  • Implemente el punto de conexión para que realice llamadas HTTP de las que también se puedan realizar seguimientos. En este caso, llama a sí mismo en un bucle artificial (realmente solo se aplica a escenarios de demostración).

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

Esto da como resultado un gráfico más interesante con una forma piramidal para las solicitudes, ya que cada nivel espera la respuesta de la llamada anterior.

Resultados de dependencia anidada Jaeger

Ejemplo: Uso de Azure Monitor y Application Insights

En el ejemplo anterior, usó aplicaciones de código abierto independientes para métricas y seguimiento. Hay muchos sistemas APM comerciales disponibles para elegir. En Azure, el producto principal de supervisión de aplicaciones es Application Insights, que forma parte de Azure Monitor.

Una de las ventajas de un producto APM integrado es que puede correlacionar los diferentes orígenes de datos de observabilidad. Para facilitar la experiencia de ASP.NET con Azure Monitor, se proporciona un paquete contenedor que realiza la mayor parte del trabajo pesado de la configuración de OpenTelemetry.

Tome el mismo proyecto del paso 5 y reemplace las referencias de NuGet por un único paquete:

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

A continuación, reemplace el código de inicialización de OTel por:

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() es la magia que agregará las bibliotecas de instrumentación comunes y los exportadores de Application Insights. Sólo tiene que añadir sus nombres Meter y ActivitySource personalizados al registro.

Si aún no es un cliente de Azure, puede crear una cuenta gratuita en https://azure.microsoft.com/free/. Inicie sesión en Azure Portal y seleccione un recurso de Application Insights existente o cree uno con https://ms.portal.azure.com/#create/Microsoft.AppInsights.

Application Insights identifica la instancia que se va a usar para almacenar y procesar datos a través de una clave de instrumentación y una cadena de conexión que se encuentran en la parte superior derecha de la interfaz de usuario del portal.

Cadena de conexión en Azure Portal

Si usa Azure App Service, esta cadena de conexión se pasa automáticamente a la aplicación como una variable de entorno. Para otros servicios o cuando se ejecute localmente, deberá pasarlo utilizando la variable de entorno APPLICATIONINSIGHTS_CONNECTION_STRING o en appsettings.json. Para ejecutar localmente, es más fácil agregar el valor a appsettings.json:

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

Nota

Reemplace el valor por el de la instancia.

Al ejecutar la aplicación, la telemetría se enviará a Application Insights. Ahora debería obtener registros, métricas y seguimientos distribuidos para la aplicación.

Registros

Vista de registros de App Insights

Métricas

Vista de métricas de App Insights

Seguimiento distribuido

Vista de transacciones de App Insights