示例:将 OpenTelemetry 与 OTLP 和独立 Aspire 仪表板配合使用

这是一系列示例之一,用于说明 OpenTelemetry 的 .NET 可观测性

除了作为 .NET Aspire 的标准部分外,Aspire 仪表板还可用作独立的 Docker 容器,该容器提供可以发送遥测数据的 OTLP 终结点,它将可视化日志、指标和跟踪。 以这种方式使用仪表板不依赖于 .NET Aspire,它将可视化通过 OTLP 发送遥测数据的任何应用程序的遥测数据。 它同样适用于用 Java、GoLang、Python 等编写的应用程序。 前提是它们可以将其遥测数据发送到 OTLP 终结点。

与使用 Prometheus、Grafana 和 Jaeger 等开源解决方案相比,使用 Aspire 仪表板的配置和设置步骤更少,但与这些工具不同,Aspire 仪表板旨在用作开发人员可视化工具,而不是用于生产监视。

1.创建项目

使用 Visual Studio 中的 ASP.NET Core 空模板或以下 .NET CLI 命令创建简单的 Web API 项目:

dotnet new web

2. 添加指标和活动定义

下面的代码为调用 API 的次数定义了新的指标 (greetings.count) 和新活动源 (Otel.Example)。

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

3. 创建 API 端点

builder.Build();app.Run() 之间插入以下内容

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

注意

终结点定义不使用特定于 OpenTelemetry 的任何内容。 它使用 .NET API 实现可观测性。

4. 引用 OpenTelemetry 包

使用 NuGet 包管理器或命令行添加以下 NuGet 包:

  <ItemGroup>
    <PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" 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>

注意

使用最新版本,因为 OTel API 不断发展。

5. 使用正确的提供程序配置 OpenTelemetry

builder.Build(); 之前插入以下代码:

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

var otel = builder.Services.AddOpenTelemetry();

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

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

// Export OpenTelemetry data via OTLP, using env vars for the configuration
var OtlpEndpoint = builder.Configuration["OTEL_EXPORTER_OTLP_ENDPOINT"];
if (OtlpEndpoint != null)
{
    otel.UseOtlpExporter();
}

此代码使用不同的遥测源设置 OpenTelemetry:

  • 它将 OTel 提供程序添加到 ILogger 以收集日志记录。
  • 它为 ASP.NET 和自定义计量设置指标、注册检测提供程序和计量。
  • 它设置跟踪、注册检测提供程序和自定义 ActivitySource。

然后,它将使用环境变量注册 OTLP 导出程序进行配置。

6. 配置 OTLP 环境变量

OTLP 导出程序可以通过代码中的 API 进行配置,但通过环境变量对其进行配置更为常见。 将以下内容添加到 AppSettings.Development.json

"OTEL_EXPORTER_OTLP_ENDPOINT": "http://localhost:4317",
"OTEL_SERVICE_NAME": "OTLP-Example"

可以为 .NET OTLP 导出程序添加其他环境变量或常见的 OTel 变量(例如 OTEL_RESOURCE_ATTRIBUTES),以定义资源属性

注意

常见问题是混合 AppSettings.jsonAppSettings.Development.json,如果后者存在,则会在 Visual Studio 中按 F5 时使用,并且将忽略 AppSettings.json 中的任何设置。

7. 启动 Aspire 仪表板容器

使用 docker 下载并运行仪表板容器。

docker run --rm -it `
-p 18888:18888 `
-p 4317:18889 `
--name aspire-dashboard `
mcr.microsoft.com/dotnet/aspire-dashboard:latest

仪表板中显示的数据可能是敏感数据。 默认情况下,仪表板受身份验证保护,需要令牌才能登录。 运行容器时,令牌会显示在生成的输出中。

[Aspire 仪表板]

复制显示的 URL,并将 0.0.0.0 替换为 localhost(例如 http://localhost:18888/login?t=123456780abcdef123456780),并在浏览器中打开该 URL,也可以在显示登录对话框时将密钥粘贴到 /login?t= 之后。 每次启动容器时,令牌都会更改。

8. 运行项目

运行项目,然后使用浏览器或 curl 访问 API。

curl -k http://localhost:7275

每次请求页面时,它都会增加已发出问候语的数量。

8.1 日志输出

代码中的日志记录语句使用 ILogger 输出。 默认情况下,将启用控制台提供程序,以便将输出定向到控制台。

关于如何从 .NET 中注销日志,有几个选项:

  • stdoutstderr 输出由容器系统(如 Kubernetes)重定向到日志文件。
  • 使用将与 ILogger 集成的日志记录库,这些库包括 SerilogNLog
  • 为 OTel 使用日志记录提供程序(如 OTLP)。 步骤 5 代码中的日志记录部分添加了 OTel 提供程序。

日志以结构化日志的形式显示在仪表板中 - 日志消息中设置的任何属性都将提取为日志记录中的字段。

独立仪表板中的日志

8.2 查看指标

Aspire 仪表板显示每个资源的指标(资源是 OTel 谈论遥测源(例如进程)的方式)。 选择资源后,仪表板将枚举资源发送到其 OTLP 终结点的每个指标。 指标列表呈动态,将在收到新指标时更新。

独立仪表板中的指标

指标的视图将取决于正在使用的指标类型:

  • 计数器将直接显示。
  • 跟踪每个请求的值(例如每个请求发送的时间范围或字节)的直方图将收集到一系列存储桶中。 仪表板将绘制 P50、P90 和 P99 百分位数的图形。 直方图结果可以包括示例,这些示例是单个数据点,以及该请求的 trace/spanId。 这些将显示为图形上的点。 选择一项将导航到相应的跟踪,以便查看导致该值的情况。 这可用于诊断离群值。
  • 指标可以包含维度,这些维度是与单个值关联的键/值对。 这些值按维度聚合。 使用视图中的下拉列表,可以筛选结果以查看特定维度,例如仅 GET 请求或 ASP.NET 中特定 URL 路由的请求。

8.3 查看跟踪

跟踪视图将显示跟踪列表 - 每个跟踪都是共享同一 traceId 的一组活动。 使用表示工作单位的范围跟踪工作。 处理 ASP.NET 请求将创建范围。 发出 HttpClient 请求将是一个范围。 通过跟踪范围的父级,可以可视化跨度的层次结构。 通过从每个资源(进程)收集范围,可以跟踪一系列服务中发生的工作。 Http 请求有一个标头,用于将 traceId 和父 spanId 传递给下一个服务。 每个资源都需要收集遥测数据并将其发送到同一收集器。 然后,它将聚合并呈现范围的层次结构。

独立仪表板中的跟踪

仪表板将显示包含摘要信息的跟踪列表。 每当看到具有新 traceId 的范围时,它们都会在表中获取一行。 单击视图将显示跟踪中的所有范围。

独立仪表板中的范围

选择范围将显示其详细信息,包括范围的任何属性,例如我们在步骤 3 中设置的 greeting 标记。