本指南提供关于集成和自定义 OpenTelemetry(OTel)工具至 Azure Monitor Application Insights 的说明。
将 Microsoft OpenTelemetry 发行版用于 .NET、Node.js和 Python。 Java继续使用 Azure Monitor OpenTelemetry 发行版及其代理或本机映像集成。 首先,为你的编程语言启用 OpenTelemetry。 将基本初始化替换为相关示例;不要为同一信号初始化第二个分发器或提供程序。
Microsoft OpenTelemetry 发行版包标识符和安装命令包括:
| 语言 |
Package |
安装命令 |
| Python |
microsoft-opentelemetry |
pip install microsoft-opentelemetry |
| Node.js |
@microsoft/opentelemetry |
npm install @microsoft/opentelemetry |
| .NET |
Microsoft.OpenTelemetry |
dotnet add package Microsoft.OpenTelemetry |
在启动未在代码中设置它的示例之前,先设置 APPLICATIONINSIGHTS_CONNECTION_STRING。 使提供程序在应用程序生存期内保持活动状态,并在关闭时刷新遥测数据。 在加载应用程序库之前初始化 Node.js 插桩;ESM 应用程序必须预加载 Microsoft OpenTelemetry 发行版加载程序。
若要了解有关 OpenTelemetry 概念的详细信息,请参阅 OpenTelemetry 概述。
有关每个分发版随附的库,请参阅 自动数据收集和资源检测器。
当您使用 OpenTelemetry 社区的工具库时,可以自动收集更多数据。
注意
我们不支持也不保证社区检测库的质量。 要为我们的发行版推荐一个,请在反馈社区中发帖或投票。 请注意,某些检测基于实验性的 OpenTelemetry 规范,未来可能会引入中断性变更。
若要添加社区库,请在为库添加 NuGet 包后使用 ConfigureOpenTelemetryMeterProvider 或 ConfigureOpenTelemetryTracerProvider 方法。
以下示例演示如何添加 运行时检测 以收集额外的指标:
dotnet add package OpenTelemetry.Instrumentation.Runtime
// Import the Microsoft OpenTelemetry Distro and supporting APIs.
using Microsoft.OpenTelemetry;
using OpenTelemetry.Metrics;
// Create a new ASP.NET Core web application builder.
var builder = WebApplication.CreateBuilder(args);
// Configure the OpenTelemetry meter provider to add runtime instrumentation.
builder.Services.ConfigureOpenTelemetryMeterProvider((sp, builder) =>
builder.AddRuntimeInstrumentation());
// Configure the Microsoft OpenTelemetry Distro.
// Export collected telemetry to Azure Monitor.
builder.Services.AddOpenTelemetry().UseMicrosoftOpenTelemetry(options =>
options.Exporters = ExportTarget.AzureMonitor);
// Build the ASP.NET Core web application.
var app = builder.Build();
// Start the ASP.NET Core web application.
app.Run();
若要在控制台或其他非托管应用程序中收集可选的运行时指标,请安装 OpenTelemetry.Instrumentation.Runtime 并扩展现有的计量提供程序配置,如下所示。 基本发行版(distro)设置不需要此步骤。 不要初始化第二个 SDK 实例:
// Import the Microsoft OpenTelemetry Distro and supporting APIs.
using Microsoft.OpenTelemetry;
using OpenTelemetry;
using OpenTelemetry.Metrics;
// Create the SDK and keep its providers alive until application shutdown.
using var sdk = OpenTelemetrySdk.Create(telemetry =>
{
// Configure the Microsoft OpenTelemetry Distro.
telemetry.UseMicrosoftOpenTelemetry(options =>
options.Exporters = ExportTarget.AzureMonitor)
// Collect runtime metrics through the distro meter provider.
.WithMetrics(metrics => metrics.AddRuntimeInstrumentation());
});
不能将社区检测库与 GraalVM Java 原生应用程序一起使用。
export class RegisterExpressInstrumentationSample {
static async run() {
// Import the Microsoft OpenTelemetry Distro and Express instrumentation
const { useMicrosoftOpenTelemetry } = await import("@microsoft/opentelemetry");
const { registerInstrumentations } = await import(
"@opentelemetry/instrumentation"
);
const { ExpressInstrumentation } = await import(
"@opentelemetry/instrumentation-express"
);
// Initialize the Microsoft OpenTelemetry Distro using the environment settings
useMicrosoftOpenTelemetry({
azureMonitor: {},
});
// Register the Express instrumentation
registerInstrumentations({
instrumentations: [new ExpressInstrumentation()],
});
console.log("Express instrumentation registered");
}
}
要添加社区仪器库,请直接使用仪器进行操作。 可以在 GitHub 上找到社区检测库的列表。
注意
不要手动插桩 use_microsoft_opentelemetry() 已经插桩的受支持插桩库。 不支持重复插桩,可能会影响遥测数据。
# Import the `use_microsoft_opentelemetry()`, `SQLAlchemyInstrumentor`, `create_engine`,
# and `text` functions from the appropriate packages.
from microsoft.opentelemetry import use_microsoft_opentelemetry
from opentelemetry.instrumentation.sqlalchemy import SQLAlchemyInstrumentor
from sqlalchemy import create_engine, text
# Configure OpenTelemetry to use Azure Monitor.
use_microsoft_opentelemetry(
enable_azure_monitor=True,
)
# Create a SQLAlchemy engine.
engine = create_engine("sqlite:///:memory:")
# SQLAlchemy instrumentation is not officially supported by this package, however, you can
# use the OpenTelemetry `instrument()` method manually in conjunction with
# `use_microsoft_opentelemetry()`.
SQLAlchemyInstrumentor().instrument(
engine=engine,
)
# Database calls using the SQLAlchemy library will be automatically captured.
with engine.connect() as conn:
result = conn.execute(text("select 'hello world'"))
print(result.all())
收集自定义遥测数据
本部分介绍如何从应用程序收集自定义遥测数据。
根据语言和信号类型,可以通过不同的方式收集自定义遥测数据,包括:
下表显示了目前支持的自定义遥测类型:
| 语言 |
自定义事件 |
自定义指标 |
依赖项 |
异常 |
页面视图 |
请求 |
痕迹 |
|
ASP.NET Core |
|
|
|
|
|
|
|
| 开放遥测 API |
|
是 |
是 |
是 |
|
是 |
|
ILogger 应用程序接口 |
是 |
|
|
|
|
|
是 |
|
|
|
|
|
|
|
|
|
Java |
|
|
|
|
|
|
|
| 开放遥测 API |
是 |
是 |
是 |
是 |
|
是 |
|
Logback,Log4j,JUL |
|
|
|
是 |
|
|
是 |
| Micrometer 指标 |
|
是 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Node.js |
|
|
|
|
|
|
|
| 开放遥测 API |
是 |
是 |
是 |
是 |
|
是 |
|
|
|
|
|
|
|
|
|
|
Python |
|
|
|
|
|
|
|
| 开放遥测 API |
|
是 |
是 |
是 |
|
是 |
|
| Python日志记录模块 |
|
|
|
|
|
|
是 |
| 事件扩展模块 |
是 |
|
|
|
|
|
是 |
添加自定义指标
在此上下文中,自定义指标术语是指手动检测代码以收集超出 OpenTelemetry Instrumentation 库自动收集的额外指标。 要详细了解如何使用指标,请参阅 Application Insights 中的指标。
OpenTelemetry API 提供六种度量工具,以涵盖各种度量方案。当在指标资源管理器中可视化指标时,需要选取正确的聚合类型。 使用 OpenTelemetry 指标 API 发送指标和使用检测库时,此要求是正确的。
下表显示了每个 OpenTelemetry 度量工具的建议聚合类型。
| OpenTelemetry 工具 |
Azure Monitor聚合类型 |
| 计数器 |
总和 |
| 异步计数器 |
总和 |
| 直方图 |
最小值、最大值、平均值、总和和计数 |
| 异步仪表 |
平均值 |
| UpDownCounter |
总和 |
| 异步增减计数器 |
总和 |
OpenTelemetry 规范介绍了这些工具,并提供了每种工具使用的示例。
提示
直方图是用于记录分布的最通用的 OpenTelemetry 指标工具。 Azure Monitor目前将直方图工具展平为五种聚合类型,并且对百分位数的支持正在开发中。 虽然通用性较低,但其他 OpenTelemetry 仪器对应用程序性能的影响较小。
直方图示例
应用程序启动时必须按名称订阅仪表:
// Import the Microsoft OpenTelemetry Distro and supporting APIs.
using Microsoft.OpenTelemetry;
using OpenTelemetry.Metrics;
// Create a new ASP.NET Core web application builder.
var builder = WebApplication.CreateBuilder(args);
// Configure the OpenTelemetry meter provider to add a meter named
// "OTel.AzureMonitor.Demo".
builder.Services.ConfigureOpenTelemetryMeterProvider((sp, builder) => builder.AddMeter(
"OTel.AzureMonitor.Demo"));
// Configure the Microsoft OpenTelemetry Distro.
// Export collected telemetry to Azure Monitor.
builder.Services.AddOpenTelemetry().UseMicrosoftOpenTelemetry(options =>
options.Exporters = ExportTarget.AzureMonitor);
// Build the ASP.NET Core web application.
var app = builder.Build();
// Start the ASP.NET Core web application.
app.Run();
Meter 必须使用同一名称初始化:
using System.Diagnostics.Metrics;
// Create a new meter named "OTel.AzureMonitor.Demo".
var meter = new Meter("OTel.AzureMonitor.Demo");
// Create a new histogram metric named "FruitSalePrice".
Histogram<long> myFruitSalePrice = meter.CreateHistogram<long>("FruitSalePrice");
// Create a new Random object.
var rand = new Random();
// Record a few random sale prices for apples and lemons, with different colors.
myFruitSalePrice.Record(rand.Next(1, 1000), new("name", "apple"), new("color", "red"));
myFruitSalePrice.Record(rand.Next(1, 1000), new("name", "lemon"), new("color", "yellow"));
myFruitSalePrice.Record(rand.Next(1, 1000), new("name", "lemon"), new("color", "yellow"));
myFruitSalePrice.Record(rand.Next(1, 1000), new("name", "apple"), new("color", "green"));
myFruitSalePrice.Record(rand.Next(1, 1000), new("name", "apple"), new("color", "red"));
myFruitSalePrice.Record(rand.Next(1, 1000), new("name", "lemon"), new("color", "yellow"));
记录直方图指标
// Import the Microsoft OpenTelemetry Distro and supporting APIs.
using Microsoft.OpenTelemetry;
using OpenTelemetry;
using OpenTelemetry.Metrics;
using System.Diagnostics.Metrics;
public class Program
{
// Create a static readonly Meter object named "OTel.AzureMonitor.Demo".
// This meter will be used to track metrics about the application.
private static readonly Meter meter = new("OTel.AzureMonitor.Demo");
public static void Main()
{
// Create a new MeterProvider object using the OpenTelemetry SDK.
// The MeterProvider object is responsible for managing meters and sending
// metric data to exporters.
// It is important to keep the MetricsProvider instance active
// throughout the process lifetime.
//
// The MeterProviderBuilder is configured to add a meter named
// "OTel.AzureMonitor.Demo" and an Azure Monitor metric exporter.
using var sdk = OpenTelemetrySdk.Create(telemetry =>
{
// Configure the Microsoft OpenTelemetry Distro.
telemetry.UseMicrosoftOpenTelemetry(options =>
options.Exporters = ExportTarget.AzureMonitor)
// Collect measurements from the application meter.
.WithMetrics(metrics => metrics.AddMeter("OTel.AzureMonitor.Demo"));
});
// Create a new Histogram metric named "FruitSalePrice".
// This metric will track the distribution of fruit sale prices.
Histogram<long> myFruitSalePrice = meter.CreateHistogram<long>("FruitSalePrice");
// Create a new Random object. This object will be used to generate random sale
// prices.
var rand = new Random();
// Record a few random sale prices for apples and lemons, with different colors.
// Each record includes a timestamp, a value, and a set of attributes.
// The attributes can be used to filter and analyze the metric data.
myFruitSalePrice.Record(rand.Next(1, 1000), new("name", "apple"), new("color",
"red"));
myFruitSalePrice.Record(rand.Next(1, 1000), new("name", "lemon"), new("color",
"yellow"));
myFruitSalePrice.Record(rand.Next(1, 1000), new("name", "lemon"), new("color",
"yellow"));
myFruitSalePrice.Record(rand.Next(1, 1000), new("name", "apple"), new("color",
"green"));
myFruitSalePrice.Record(rand.Next(1, 1000), new("name", "apple"), new("color",
"red"));
myFruitSalePrice.Record(rand.Next(1, 1000), new("name", "lemon"), new("color",
"yellow"));
// Display a message to the user and wait for them to press Enter.
// This allows the user to see the message and the console before the
// application exits.
System.Console.WriteLine("Press Enter key to exit.");
System.Console.ReadLine();
}
}
import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.api.metrics.DoubleHistogram;
import io.opentelemetry.api.metrics.Meter;
public class Program {
public static void main(String[] args) {
Meter meter = GlobalOpenTelemetry.getMeter("OTEL.AzureMonitor.Demo");
DoubleHistogram histogram = meter.histogramBuilder("histogram").build();
histogram.record(1.0);
histogram.record(100.0);
histogram.record(30.0);
}
}
注入 OpenTelemetry:
春天
import io.opentelemetry.api.OpenTelemetry;
import org.springframework.beans.factory.annotation.Autowired;
@Autowired
OpenTelemetry openTelemetry;
Quarkus
import io.opentelemetry.api.OpenTelemetry;
import jakarta.inject.Inject;
@Inject
OpenTelemetry openTelemetry;
创建直方图:
import io.opentelemetry.api.metrics.DoubleHistogram;
import io.opentelemetry.api.metrics.Meter;
Meter meter = openTelemetry.getMeter("OTEL.AzureMonitor.Demo");
DoubleHistogram histogram = meter.histogramBuilder("histogram").build();
histogram.record(1.0);
histogram.record(100.0);
histogram.record(30.0);
注意
Quarkus 社区支持和维护 Quarkus 扩展。 寻求帮助,请使用 Quarkus 社区支持渠道。 Azure不提供对此集成的技术支持。
export class HistogramSample {
static async run() {
// Import the Microsoft OpenTelemetry Distro and metrics API
const { useMicrosoftOpenTelemetry } = await import("@microsoft/opentelemetry");
const { metrics } = await import("@opentelemetry/api");
// Initialize the Microsoft OpenTelemetry Distro
useMicrosoftOpenTelemetry({
azureMonitor: {
azureMonitorExporterOptions: {
connectionString:
process.env.APPLICATIONINSIGHTS_CONNECTION_STRING ||
"<ConnectionString>",
},
},
});
// Create a histogram and record values
const meter = metrics.getMeter("testMeter");
const histogram = meter.createHistogram("histogram");
histogram.record(1, { testKey: "testValue" });
histogram.record(30, { testKey: "testValue2" });
histogram.record(100, { testKey2: "testValue" });
console.log("Histogram metrics recorded");
}
}
记录直方图指标
# Import the `use_microsoft_opentelemetry()` and `metrics` functions from the appropriate
# packages.
from microsoft.opentelemetry import use_microsoft_opentelemetry
from opentelemetry import metrics
import os
# Configure OpenTelemetry to use Azure Monitor with the specified connection string.
use_microsoft_opentelemetry(
enable_azure_monitor=True,
azure_monitor_connection_string="<ConnectionString>",
)
# Opt in to allow grouping of your metrics via a custom metrics namespace in app insights
# metrics explorer.
# Specify the namespace name using get_meter("namespace-name")
os.environ["APPLICATIONINSIGHTS_METRIC_NAMESPACE_OPT_IN"] = "true"
# Get a meter provider and a meter with the name "otel_azure_monitor_histogram_demo".
meter = metrics.get_meter_provider().get_meter("otel_azure_monitor_histogram_demo")
# Record three values to the histogram.
histogram = meter.create_histogram("histogram")
histogram.record(1.0, {"test_key": "test_value"})
histogram.record(100.0, {"test_key2": "test_value"})
histogram.record(30.0, {"test_key": "test_value2"})
# Wait for background execution.
input()
反例
应用程序启动时必须按名称订阅仪表:
// Import the Microsoft OpenTelemetry Distro and supporting APIs.
using Microsoft.OpenTelemetry;
using OpenTelemetry.Metrics;
// Create a new ASP.NET Core web application builder.
var builder = WebApplication.CreateBuilder(args);
// Configure the OpenTelemetry meter provider to add a meter named
// "OTel.AzureMonitor.Demo".
builder.Services.ConfigureOpenTelemetryMeterProvider((sp, builder) => builder.AddMeter(
"OTel.AzureMonitor.Demo"));
// Configure the Microsoft OpenTelemetry Distro.
// Export collected telemetry to Azure Monitor.
builder.Services.AddOpenTelemetry().UseMicrosoftOpenTelemetry(options =>
options.Exporters = ExportTarget.AzureMonitor);
// Build the ASP.NET Core web application.
var app = builder.Build();
// Start the ASP.NET Core web application.
app.Run();
Meter 必须使用同一名称初始化:
using System.Diagnostics.Metrics;
// Create a new meter named "OTel.AzureMonitor.Demo".
var meter = new Meter("OTel.AzureMonitor.Demo");
// Create a new counter metric named "MyFruitCounter".
Counter<long> myFruitCounter = meter.CreateCounter<long>("MyFruitCounter");
// Record the number of fruits sold, grouped by name and color.
myFruitCounter.Add(1, new("name", "apple"), new("color", "red"));
myFruitCounter.Add(2, new("name", "lemon"), new("color", "yellow"));
myFruitCounter.Add(1, new("name", "lemon"), new("color", "yellow"));
myFruitCounter.Add(2, new("name", "apple"), new("color", "green"));
myFruitCounter.Add(5, new("name", "apple"), new("color", "red"));
myFruitCounter.Add(4, new("name", "lemon"), new("color", "yellow"));
记录计数器指标
// Import the Microsoft OpenTelemetry Distro and supporting APIs.
using Microsoft.OpenTelemetry;
using OpenTelemetry;
using OpenTelemetry.Metrics;
using System.Diagnostics.Metrics;
public class Program
{
// Create a static readonly Meter object named "OTel.AzureMonitor.Demo".
// This meter will be used to track metrics about the application.
private static readonly Meter meter = new("OTel.AzureMonitor.Demo");
public static void Main()
{
// Create a new MeterProvider object using the OpenTelemetry SDK.
// The MeterProvider object is responsible for managing meters and sending
// metric data to exporters.
// It is important to keep the MetricsProvider instance active
// throughout the process lifetime.
//
// The MeterProviderBuilder is configured to add a meter named
// "OTel.AzureMonitor.Demo" and an Azure Monitor metric exporter.
using var sdk = OpenTelemetrySdk.Create(telemetry =>
{
// Configure the Microsoft OpenTelemetry Distro.
telemetry.UseMicrosoftOpenTelemetry(options =>
options.Exporters = ExportTarget.AzureMonitor)
// Collect measurements from the application meter.
.WithMetrics(metrics => metrics.AddMeter("OTel.AzureMonitor.Demo"));
});
// Create a new counter metric named "MyFruitCounter".
// This metric will track the number of fruits sold.
Counter<long> myFruitCounter = meter.CreateCounter<long>("MyFruitCounter");
// Record the number of fruits sold, grouped by name and color.
myFruitCounter.Add(1, new("name", "apple"), new("color", "red"));
myFruitCounter.Add(2, new("name", "lemon"), new("color", "yellow"));
myFruitCounter.Add(1, new("name", "lemon"), new("color", "yellow"));
myFruitCounter.Add(2, new("name", "apple"), new("color", "green"));
myFruitCounter.Add(5, new("name", "apple"), new("color", "red"));
myFruitCounter.Add(4, new("name", "lemon"), new("color", "yellow"));
// Display a message to the user and wait for them to press Enter.
// This allows the user to see the message and the console before the
// application exits.
System.Console.WriteLine("Press Enter key to exit.");
System.Console.ReadLine();
}
}
记录计数器指标
import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.metrics.LongCounter;
import io.opentelemetry.api.metrics.Meter;
public class Program {
public static void main(String[] args) {
Meter meter = GlobalOpenTelemetry.getMeter("OTEL.AzureMonitor.Demo");
LongCounter myFruitCounter = meter
.counterBuilder("MyFruitCounter")
.build();
myFruitCounter.add(1, Attributes.of(AttributeKey.stringKey("name"), "apple",
AttributeKey.stringKey("color"), "red"));
myFruitCounter.add(2, Attributes.of(AttributeKey.stringKey("name"), "lemon",
AttributeKey.stringKey("color"), "yellow"));
myFruitCounter.add(1, Attributes.of(AttributeKey.stringKey("name"), "lemon",
AttributeKey.stringKey("color"), "yellow"));
myFruitCounter.add(2, Attributes.of(AttributeKey.stringKey("name"), "apple",
AttributeKey.stringKey("color"), "green"));
myFruitCounter.add(5, Attributes.of(AttributeKey.stringKey("name"), "apple",
AttributeKey.stringKey("color"), "red"));
myFruitCounter.add(4, Attributes.of(AttributeKey.stringKey("name"), "lemon",
AttributeKey.stringKey("color"), "yellow"));
}
}
注入 OpenTelemetry:
春天
import io.opentelemetry.api.OpenTelemetry;
import org.springframework.beans.factory.annotation.Autowired;
@Autowired
OpenTelemetry openTelemetry;
Quarkus
import io.opentelemetry.api.OpenTelemetry;
import jakarta.inject.Inject;
@Inject
OpenTelemetry openTelemetry;
创建计数器:
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.metrics.LongCounter;
import io.opentelemetry.api.metrics.Meter;
Meter meter = openTelemetry.getMeter("OTEL.AzureMonitor.Demo");
LongCounter myFruitCounter = meter.counterBuilder("MyFruitCounter")
.build();
myFruitCounter.add(1, Attributes.of(AttributeKey.stringKey("name"), "apple",
AttributeKey.stringKey("color"), "red"));
myFruitCounter.add(2, Attributes.of(AttributeKey.stringKey("name"), "lemon",
AttributeKey.stringKey("color"), "yellow"));
myFruitCounter.add(1, Attributes.of(AttributeKey.stringKey("name"), "lemon",
AttributeKey.stringKey("color"), "yellow"));
myFruitCounter.add(2, Attributes.of(AttributeKey.stringKey("name"), "apple",
AttributeKey.stringKey("color"), "green"));
myFruitCounter.add(5, Attributes.of(AttributeKey.stringKey("name"), "apple",
AttributeKey.stringKey("color"), "red"));
myFruitCounter.add(4, Attributes.of(AttributeKey.stringKey("name"), "lemon",
AttributeKey.stringKey("color"), "yellow"));
注意
Quarkus 社区支持和维护 Quarkus 扩展。 寻求帮助,请使用 Quarkus 社区支持渠道。 Azure不提供对此集成的技术支持。
记录计数器指标
export class CounterSample {
static async run() {
// Import the Microsoft OpenTelemetry Distro and metrics API
const { useMicrosoftOpenTelemetry } = await import("@microsoft/opentelemetry");
const { metrics } = await import("@opentelemetry/api");
// Initialize the Microsoft OpenTelemetry Distro
useMicrosoftOpenTelemetry({
azureMonitor: {
azureMonitorExporterOptions: {
connectionString:
process.env.APPLICATIONINSIGHTS_CONNECTION_STRING ||
"<ConnectionString>",
},
},
});
// Create a counter and add some sample values
const meter = metrics.getMeter("otel_azure_monitor_counter_demo");
const counter = meter.createCounter("MyFruitCounter");
counter.add(1, { name: "apple", color: "red" });
counter.add(2, { name: "lemon", color: "yellow" });
counter.add(1, { name: "lemon", color: "yellow" });
counter.add(2, { name: "apple", color: "green" });
counter.add(5, { name: "apple", color: "red" });
counter.add(4, { name: "lemon", color: "yellow" });
console.log("Counter metrics recorded");
}
}
记录计数器指标
# Import the `use_microsoft_opentelemetry()` and `metrics` functions from the appropriate
# packages.
from microsoft.opentelemetry import use_microsoft_opentelemetry
from opentelemetry import metrics
import os
# Configure OpenTelemetry to use Azure Monitor with the specified connection string.
use_microsoft_opentelemetry(
enable_azure_monitor=True,
azure_monitor_connection_string="<ConnectionString>",
)
# Opt in to allow grouping of your metrics via a custom metrics namespace in app insights
# metrics explorer.
# Specify the namespace name using get_meter("namespace-name")
os.environ["APPLICATIONINSIGHTS_METRIC_NAMESPACE_OPT_IN"] = "true"
# Get a meter provider and a meter with the name "otel_azure_monitor_counter_demo".
meter = metrics.get_meter_provider().get_meter("otel_azure_monitor_counter_demo")
# Create a counter metric with the name "counter".
counter = meter.create_counter("counter")
# Add three values to the counter.
# The first argument to the `add()` method is the value to add.
# The second argument is a dictionary of dimensions.
# Dimensions are used to group related metrics together.
counter.add(1.0, {"test_key": "test_value"})
counter.add(5.0, {"test_key2": "test_value"})
counter.add(3.0, {"test_key": "test_value2"})
# Wait for background execution.
input()
量表示例
应用程序启动时必须按名称订阅仪表:
// Import the Microsoft OpenTelemetry Distro and supporting APIs.
using Microsoft.OpenTelemetry;
using OpenTelemetry.Metrics;
// Create a new ASP.NET Core web application builder.
var builder = WebApplication.CreateBuilder(args);
// Configure the OpenTelemetry meter provider to add a meter named
// "OTel.AzureMonitor.Demo".
builder.Services.ConfigureOpenTelemetryMeterProvider((sp, builder) => builder.AddMeter(
"OTel.AzureMonitor.Demo"));
// Configure the Microsoft OpenTelemetry Distro.
// Export collected telemetry to Azure Monitor.
builder.Services.AddOpenTelemetry().UseMicrosoftOpenTelemetry(options =>
options.Exporters = ExportTarget.AzureMonitor);
// Build the ASP.NET Core web application.
var app = builder.Build();
// Start the ASP.NET Core web application.
app.Run();
Meter 必须使用同一名称初始化:
using System.Diagnostics;
using System.Diagnostics.Metrics;
// Get the current process.
var process = Process.GetCurrentProcess();
// Create a new meter named "OTel.AzureMonitor.Demo".
var meter = new Meter("OTel.AzureMonitor.Demo");
// Create a new observable gauge metric named "Thread.State".
// This metric will track the state of each thread in the current process.
ObservableGauge<int> myObservableGauge = meter.CreateObservableGauge("Thread.State", (
) => GetThreadState(process));
static IEnumerable<Measurement<int>> GetThreadState(Process process)
{
// Iterate over all threads in the current process.
foreach (ProcessThread thread in process.Threads)
{
// Create a measurement for each thread, including the thread state, process ID,
// and thread ID.
yield return new((int)thread.ThreadState, new("ProcessId", process.Id), new(
"ThreadId", thread.Id));
}
}
记录可观测 gauge 指标
// Import the Microsoft OpenTelemetry Distro and supporting APIs.
using Microsoft.OpenTelemetry;
using OpenTelemetry;
using OpenTelemetry.Metrics;
using System.Diagnostics.Metrics;
using System.Diagnostics;
public class Program
{
// Create a static readonly Meter object named "OTel.AzureMonitor.Demo".
// This meter will be used to track metrics about the application.
private static readonly Meter meter = new("OTel.AzureMonitor.Demo");
public static void Main()
{
// Create a new MeterProvider object using the OpenTelemetry SDK.
// The MeterProvider object is responsible for managing meters and sending
// metric data to exporters.
// It is important to keep the MetricsProvider instance active
// throughout the process lifetime.
//
// The MeterProviderBuilder is configured to add a meter named
// "OTel.AzureMonitor.Demo" and an Azure Monitor metric exporter.
using var sdk = OpenTelemetrySdk.Create(telemetry =>
{
// Configure the Microsoft OpenTelemetry Distro.
telemetry.UseMicrosoftOpenTelemetry(options =>
options.Exporters = ExportTarget.AzureMonitor)
// Collect measurements from the application meter.
.WithMetrics(metrics => metrics.AddMeter("OTel.AzureMonitor.Demo"));
});
// Get the current process.
var process = Process.GetCurrentProcess();
// Create a new observable gauge metric named "Thread.State".
// This metric will track the state of each thread in the current process.
ObservableGauge<int> myObservableGauge = meter.CreateObservableGauge(
"Thread.State", () => GetThreadState(process));
// Display a message to the user and wait for them to press Enter.
// This allows the user to see the message and the console before the
// application exits.
System.Console.WriteLine("Press Enter key to exit.");
System.Console.ReadLine();
}
private static IEnumerable<Measurement<int>> GetThreadState(Process process)
{
// Iterate over all threads in the current process.
foreach (ProcessThread thread in process.Threads)
{
// Create a measurement for each thread, including the thread state, process
// ID, and thread ID.
yield return new((int)thread.ThreadState, new("ProcessId", process.Id), new(
"ThreadId", thread.Id));
}
}
}
import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.metrics.Meter;
public class Program {
public static void main(String[] args) {
Meter meter = GlobalOpenTelemetry.getMeter("OTEL.AzureMonitor.Demo");
meter.gaugeBuilder("gauge")
.buildWithCallback(
observableMeasurement -> {
double randomNumber = Math.floor(Math.random() * 100);
observableMeasurement.record(randomNumber, Attributes.of(
AttributeKey.stringKey("testKey"), "testValue"));
});
}
}
注入 OpenTelemetry:
春天
import io.opentelemetry.api.OpenTelemetry;
import org.springframework.beans.factory.annotation.Autowired;
@Autowired
OpenTelemetry openTelemetry;
Quarkus
import io.opentelemetry.api.OpenTelemetry;
import jakarta.inject.Inject;
@Inject
OpenTelemetry openTelemetry;
创建仪表:
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.metrics.Meter;
Meter meter = openTelemetry.getMeter("OTEL.AzureMonitor.Demo");
meter.gaugeBuilder("gauge")
.buildWithCallback(
observableMeasurement -> {
double randomNumber = Math.floor(Math.random() * 100);
observableMeasurement.record(randomNumber, Attributes.of(
AttributeKey.stringKey("testKey"), "testValue"));
});
注意
Quarkus 社区支持和维护 Quarkus 扩展。 寻求帮助,请使用 Quarkus 社区支持渠道。 Azure不提供对此集成的技术支持。
export class GaugeSample {
static async run() {
// Import the Microsoft OpenTelemetry Distro and metrics API
const { useMicrosoftOpenTelemetry } = await import("@microsoft/opentelemetry");
const { metrics } = await import("@opentelemetry/api");
// Initialize the Microsoft OpenTelemetry Distro
useMicrosoftOpenTelemetry({
azureMonitor: {
azureMonitorExporterOptions: {
connectionString:
process.env.APPLICATIONINSIGHTS_CONNECTION_STRING ||
"<ConnectionString>",
},
},
});
// Create an observable gauge and register a callback
const meter = metrics.getMeter("testMeter");
const gauge = meter.createObservableGauge("gauge");
gauge.addCallback((observableResult) => {
const randomNumber = Math.floor(Math.random() * 100);
observableResult.observe(randomNumber, { testKey: "testValue" });
});
console.log("Observable gauge registered");
}
}
记录可观测 gauge 指标
# Import the necessary packages.
from typing import Iterable
import os
from microsoft.opentelemetry import use_microsoft_opentelemetry
from opentelemetry import metrics
from opentelemetry.metrics import CallbackOptions, Observation
# Configure OpenTelemetry to use Azure Monitor with the specified connection string.
use_microsoft_opentelemetry(
enable_azure_monitor=True,
azure_monitor_connection_string="<ConnectionString>",
)
# Opt in to allow grouping of your metrics via a custom metrics namespace in app insights
# metrics explorer.
# Specify the namespace name using get_meter("namespace-name")
os.environ["APPLICATIONINSIGHTS_METRIC_NAMESPACE_OPT_IN"] = "true"
# Get a meter provider and a meter with the name "otel_azure_monitor_gauge_demo".
meter = metrics.get_meter_provider().get_meter("otel_azure_monitor_gauge_demo")
# Define two observable gauge generators.
# The first generator yields a single observation with the value 9.
# The second generator yields a sequence of 10 observations with the value 9 and a
# different dimension value for each observation.
def observable_gauge_generator(options: CallbackOptions) -> Iterable[Observation]:
yield Observation(9, {"test_key": "test_value"})
def observable_gauge_sequence(options: CallbackOptions) -> Iterable[Observation]:
observations = []
for i in range(10):
observations.append(
Observation(9, {"test_key": i})
)
return observations
# Create two observable gauges using the defined generators.
gauge = meter.create_observable_gauge("gauge", [observable_gauge_generator])
gauge2 = meter.create_observable_gauge("gauge2", [observable_gauge_sequence])
# Wait for background execution.
input()
添加自定义异常
选择的检测库会自动将异常情况报告给 Application Insights。
不过,你可能希望手动报告一些仪器库未报告的例外情况。
例如,通常不会报告代码捕获的异常。 你可能希望报告这些问题,以便在相关体验中引起注意,尤其是在故障部分和端到端事务视图中。
.NET 示例是已插桩的应用程序的片段。 对于活动示例,请使用在activitySource中注册的。
对于日志记录示例,请使用应用程序配置的 ILoggerFactory 作为 loggerFactory。
要使用活动记录异常事件:
using System.Diagnostics;
using OpenTelemetry.Trace;
// Start a new activity named "ExceptionExample".
using (var activity = activitySource.StartActivity("ExceptionExample"))
{
// Try to execute some code.
try
{
throw new Exception("Test exception");
}
// If an exception is thrown, catch it and set the activity status to "Error".
catch (Exception ex)
{
activity?.SetStatus(ActivityStatusCode.Error);
activity?.RecordException(ex);
}
}
要使用 ILogger 记录异常:
// Create a logger using the logger factory. The logger category name is used to filter
// and route log messages.
var logger = loggerFactory.CreateLogger("ExceptionExample");
// Try to execute some code.
try
{
throw new Exception("Test Exception");
}
catch (Exception ex)
{
// Log an error message with the exception. The log level is set to "Error" and the
// event ID is set to 0.
// The log message includes a template and a parameter. The template will be replaced
// with the value of the parameter when the log message is written.
logger.Log(
logLevel: LogLevel.Error,
eventId: 0,
exception: ex,
message: "Hello {name}.",
args: new object[] { "World" });
}
要使用活动记录异常事件:
using System.Diagnostics;
using OpenTelemetry.Trace;
// Start a new activity named "ExceptionExample".
using (var activity = activitySource.StartActivity("ExceptionExample"))
{
// Try to execute some code.
try
{
throw new Exception("Test exception");
}
// If an exception is thrown, catch it and set the activity status to "Error".
catch (Exception ex)
{
activity?.SetStatus(ActivityStatusCode.Error);
activity?.RecordException(ex);
}
}
要使用 ILogger 记录异常:
// Create a logger using the logger factory. The logger category name is used to filter
// and route log messages.
var logger = loggerFactory.CreateLogger("ExceptionExample");
try
{
// Try to execute some code.
throw new Exception("Test Exception");
}
catch (Exception ex)
{
// Log an error message with the exception. The log level is set to "Error" and the
// event ID is set to 0.
// The log message includes a template and a parameter. The template will be replaced
// with the value of the parameter when the log message is written.
logger.Log(
logLevel: LogLevel.Error,
eventId: 0,
exception: ex,
message: "Hello {name}.",
args: new object[] { "World" });
}
可以使用 opentelemetry-api 来更新跨度的状态并记录异常。
将 opentelemetry-api-1.0.0.jar(或更高版本)添加到应用程序:
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-api</artifactId>
<version>1.0.0</version>
</dependency>
将状态设置为 error,并记录代码中的异常:
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.StatusCode;
Span span = Span.current();
span.setStatus(StatusCode.ERROR, "errorMessage");
span.recordException(e);
将状态设置为 error,并记录代码中的异常:
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.StatusCode;
Span span = Span.current();
span.setStatus(StatusCode.ERROR, "errorMessage");
span.recordException(e);
仅当记录在顶级跨度或远程或内部跨度的子级时,Node.js SDK 才会将基于跨度的手动记录异常导出到 Application Insights。
记录自定义异常
export class CustomExceptionSample {
static async run() {
// Import the Microsoft OpenTelemetry Distro and tracing API
const { useMicrosoftOpenTelemetry } = await import("@microsoft/opentelemetry");
const { trace } = await import("@opentelemetry/api");
// Initialize the Microsoft OpenTelemetry Distro
useMicrosoftOpenTelemetry({
azureMonitor: {
azureMonitorExporterOptions: {
connectionString:
process.env.APPLICATIONINSIGHTS_CONNECTION_STRING ||
"<ConnectionString>",
},
},
});
// Create a span and record an exception
const tracer = trace.getTracer("testTracer");
const span = tracer.startSpan("hello");
try {
throw new Error("Test Error");
}
catch (error) {
span.recordException(error as Error);
}
finally {
span.end();
}
console.log("Exception recorded on span");
}
}
OpenTelemetry Python SDK 以自动捕获和记录引发的异常的方式实现。 有关此行为的示例,请参阅以下代码示例:
# Import the necessary packages.
from microsoft.opentelemetry import use_microsoft_opentelemetry
from opentelemetry import trace
# Configure OpenTelemetry to use Azure Monitor with the specified connection string.
use_microsoft_opentelemetry(
enable_azure_monitor=True,
azure_monitor_connection_string="<ConnectionString>",
)
# Get a tracer for the current module.
tracer = trace.get_tracer("otel_azure_monitor_exception_demo")
# Exception events
try:
# Start a new span with the name "hello".
with tracer.start_as_current_span("hello") as span:
# This exception will be automatically recorded
raise Exception("Custom exception message.")
except Exception:
print("Exception raised")
如果要手动记录异常,可以在上下文管理器中禁用该选项,并直接使用 record_exception(),如下例所示:
...
# Start a new span with the name "hello" and disable exception recording.
with tracer.start_as_current_span("hello", record_exception=False) as span:
try:
# Raise an exception.
raise Exception("Custom exception message.")
except Exception as ex:
# Manually record exception
span.record_exception(ex)
...
添加自定义范围
你可能想要在两种情况下添加自定义跨度。 首先,当存在仪器库尚未收集的依赖请求时。 其次,当你希望在端到端事务视图上将应用程序进程建模为跨度时。
注意
Activity 命名空间中的 ActivitySource 和 System.Diagnostics 类分别代表 Span 和 Tracer 的 OpenTelemetry 概念。 可以通过使用其构造函数而不是使用 ActivitySource 来直接创建 TracerProvider。 每个 ActivitySource 类都必须显式地通过 TracerProvider 来连接到 AddSource()。 这是因为 OpenTelemetry 跟踪 API 的某些部分直接合并到.NET运行时中。 若要了解详细信息,请参阅 OpenTelemetry .NET 跟踪 API 的简介。
添加自定义跨度
// Import the Microsoft OpenTelemetry Distro and supporting APIs.
using Microsoft.OpenTelemetry;
using System.Diagnostics;
using OpenTelemetry.Trace;
// Define an activity source named "ActivitySourceName". This activity source will be used
// to create activities for all requests to the application.
using var activitySource = new ActivitySource("ActivitySourceName");
// Create an ASP.NET Core application builder.
var builder = WebApplication.CreateBuilder(args);
// Configure the OpenTelemetry tracer provider to add a source named "ActivitySourceName".
// This will ensure that all activities created by the activity source are traced.
builder.Services.ConfigureOpenTelemetryTracerProvider((sp, builder) =>
builder.AddSource("ActivitySourceName"));
// Configure the Microsoft OpenTelemetry Distro. This service will collect
// and send telemetry data to Azure Monitor.
builder.Services.AddOpenTelemetry().UseMicrosoftOpenTelemetry(options =>
options.Exporters = ExportTarget.AzureMonitor);
// Build the ASP.NET Core application.
var app = builder.Build();
// Map a GET request to the root path ("/") to the specified action.
app.MapGet("/", () =>
{
// Start a new activity named "CustomActivity". This activity will be traced and the
// trace data will be sent to Azure Monitor.
using (var activity = activitySource.StartActivity("CustomActivity"))
{
// your code here
}
// Return a response message.
return $"Hello World!";
});
// Start the ASP.NET Core application.
app.Run();
StartActivity 默认为 ActivityKind.Internal,但你可以提供任何其他 ActivityKind。
ActivityKind.Client、ActivityKind.Producer、ActivityKind.Internal 映射到 Application Insights dependencies。
ActivityKind.Server、ActivityKind.Consumer 映射到 Application Insights requests。
注意
Activity 命名空间中的 ActivitySource 和 System.Diagnostics 类分别代表 Span 和 Tracer 的 OpenTelemetry 概念。 可以通过使用其构造函数而不是使用 ActivitySource 来直接创建 TracerProvider。 每个 ActivitySource 类都必须显式地通过 TracerProvider 来连接到 AddSource()。 这是因为 OpenTelemetry 跟踪 API 的某些部分直接合并到.NET运行时中。 若要了解详细信息,请参阅 OpenTelemetry .NET 跟踪 API 的简介。
// Import the Microsoft OpenTelemetry Distro and supporting APIs.
using Microsoft.OpenTelemetry;
using OpenTelemetry;
using OpenTelemetry.Trace;
using System.Diagnostics;
// Create the SDK and keep its providers alive until application shutdown.
using var sdk = OpenTelemetrySdk.Create(telemetry =>
{
// Configure the Microsoft OpenTelemetry Distro.
telemetry.UseMicrosoftOpenTelemetry(options =>
options.Exporters = ExportTarget.AzureMonitor)
.WithTracing(tracing => tracing.AddSource("ActivitySourceName"));
});
// Create an activity source named "ActivitySourceName".
var activitySource = new ActivitySource("ActivitySourceName");
// Start a new activity named "CustomActivity". This activity will be traced and the trace
// data will be sent to Azure Monitor.
using (var activity = activitySource.StartActivity("CustomActivity"))
{
// your code here
}
StartActivity 默认为 ActivityKind.Internal,但你可以提供任何其他 ActivityKind。
ActivityKind.Client、ActivityKind.Producer、ActivityKind.Internal 映射到 Application Insights dependencies。
ActivityKind.Server、ActivityKind.Consumer 映射到 Application Insights requests。
使用 OpenTelemetry 注解
添加自己的范围的最简单方法是使用 OpenTelemetry 的 @WithSpan 注释。
范围会填充 Application Insights 中的 requests 和 dependencies 表。
将 opentelemetry-instrumentation-annotations-1.32.0.jar(或更高版本)添加到应用程序:
<dependency>
<groupId>io.opentelemetry.instrumentation</groupId>
<artifactId>opentelemetry-instrumentation-annotations</artifactId>
<version>1.32.0</version>
</dependency>
使用 @WithSpan 标记,每次执行你的方法时发出一个范围:
import io.opentelemetry.instrumentation.annotations.WithSpan;
@WithSpan(value = "your span name")
public void yourMethod() {
}
默认情况下,跨度会显示在 dependencies 表中,依赖项类型为 InProc。
对于表示自动仪表化未捕获的后台作业的方法,我们建议将 kind = SpanKind.SERVER 属性应用于 @WithSpan 注释,以确保它们会显示在 Application Insights requests 表中。
使用 OpenTelemetry API
如果上述 OpenTelemetry @WithSpan 注释不能满足你的需求,可使用 OpenTelemetry API 添加范围。
将 opentelemetry-api-1.0.0.jar(或更高版本)添加到应用程序:
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-api</artifactId>
<version>1.0.0</version>
</dependency>
使用 GlobalOpenTelemetry 类创建 Tracer:
import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.api.trace.Tracer;
static final Tracer tracer = GlobalOpenTelemetry.getTracer("com.example");
创建一个范围,使其成为当前范围,然后结束该范围:
Span span = tracer.spanBuilder("my first span").startSpan();
try (Scope ignored = span.makeCurrent()) {
// do stuff within the context of this
} catch (Throwable t) {
span.recordException(t);
} finally {
span.end();
}
注入 OpenTelemetry:
春天
import io.opentelemetry.api.OpenTelemetry;
import org.springframework.beans.factory.annotation.Autowired;
@Autowired
OpenTelemetry openTelemetry;
Quarkus
import io.opentelemetry.api.OpenTelemetry;
import jakarta.inject.Inject;
@Inject
OpenTelemetry openTelemetry;
在框架注入 Tracer 后,在检测方法中创建一个 OpenTelemetry:
import io.opentelemetry.api.trace.Tracer;
Tracer tracer = openTelemetry.getTracer("com.example");
创建一个范围,使其成为当前范围,然后结束该范围:
Span span = tracer.spanBuilder("my first span").startSpan();
try (Scope ignored = span.makeCurrent()) {
// do stuff within the context of this
} catch (Throwable t) {
span.recordException(t);
} finally {
span.end();
}
注意
Quarkus 社区支持和维护 Quarkus 扩展。 寻求帮助,请使用 Quarkus 社区支持渠道。 Azure不提供对此集成的技术支持。
添加自定义跨度
export class CustomTraceSample {
static async run() {
// Import the Microsoft OpenTelemetry Distro and tracing API
const { useMicrosoftOpenTelemetry } = await import("@microsoft/opentelemetry");
const { trace } = await import("@opentelemetry/api");
// Initialize the Microsoft OpenTelemetry Distro
useMicrosoftOpenTelemetry({
azureMonitor: {
azureMonitorExporterOptions: {
connectionString:
process.env.APPLICATIONINSIGHTS_CONNECTION_STRING ||
"<ConnectionString>",
},
},
});
// Create a custom span, add attributes/events, then end
const tracer = trace.getTracer("otel_azure_monitor_custom_trace_demo");
const span = tracer.startSpan("doWork");
try {
span.setAttribute("component", "worker");
span.setAttribute("operation.id", "42");
span.addEvent("invoking doWork");
for (let i = 0; i < 1000000; i++) {
/* simulate work */
}
} catch (err) {
span.recordException(err as Error);
}
finally {
span.end();
}
console.log("Custom span recorded");
}
}
OpenTelemetry API 可用于添加你自己的跨度,它们会显示在 Application Insights 的 requests 和 dependencies 表中。
代码示例演示如何使用 tracer.start_as_current_span() 方法在其上下文中启动跨度、将跨度设为当前,以及结束跨度。
...
# Import the necessary packages.
from opentelemetry import trace
# Get a tracer for the current module.
tracer = trace.get_tracer(__name__)
# Start a new span with the name "my first span" and make it the current span.
# The "with" context manager starts, makes the span current, and ends the span within it's
# context
with tracer.start_as_current_span("my first span") as span:
try:
# Do stuff within the context of this span.
# All telemetry generated within this scope will be attributed to this span.
...
except Exception as ex:
# Record the exception on the span.
span.record_exception(ex)
...
默认情况下,跨度位于 dependencies 表中,依赖项类型为 InProc。
如果您的方法代表自动化检测尚未捕获的某个后台作业,我们建议设置特性 kind = SpanKind.SERVER,以确保它出现在 Application Insights requests 表中。
...
# Import the necessary packages.
from opentelemetry import trace
from opentelemetry.trace import SpanKind
# Get a tracer for the current module.
tracer = trace.get_tracer(__name__)
# Start a new span with the name "my request span" and the kind set to SpanKind.SERVER.
with tracer.start_as_current_span("my request span", kind=SpanKind.SERVER) as span:
# Do stuff within the context of this span.
...
...
发送自定义事件
Application Insights 将自定义事件 customEvents 存储在表中。
分析、筛选和可视化它们的一种方法是使用 Application Insights 使用情况体验。
如果要自动收集客户端交互事件,可以在 JavaScript SDK 中使用插件。
用于 .NET 的 Microsoft OpenTelemetry Distro 通过 Azure Monitor 日志记录导出程序发送自定义事件。
若要使用 CustomEvent 发送 ILogger,请设置消息模板中的 "microsoft.custom_event.name" 属性。
// Import the Microsoft OpenTelemetry Distro and supporting APIs.
using Microsoft.OpenTelemetry;
// Create the application builder.
var builder = WebApplication.CreateBuilder(args);
// Configure the Microsoft OpenTelemetry Distro.
builder.UseMicrosoftOpenTelemetry(options =>
{
options.Exporters = ExportTarget.AzureMonitor;
});
// Build the application with the configured telemetry services.
var app = builder.Build();
// Use the message-template attribute to name the custom event.
app.Logger.LogInformation("{microsoft.custom_event.name} {additional_attrs}",
"test-event-name", "val1");
// Run the application and its telemetry providers.
app.Run();
用于 .NET 的 Microsoft OpenTelemetry Distro 通过 Azure Monitor 日志记录导出程序发送自定义事件。 此控制台示例使用 .NET 泛型主机来管理日志记录管道和 SDK 生存期。
若要使用 CustomEvent 发送 ILogger,请设置消息模板中的 "microsoft.custom_event.name" 属性。
发送自定义事件
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
// Import the Microsoft OpenTelemetry Distro and supporting APIs.
using Microsoft.OpenTelemetry;
// Create the application host builder.
var builder = Host.CreateApplicationBuilder(args);
// Configure the Microsoft OpenTelemetry Distro.
builder.UseMicrosoftOpenTelemetry(options =>
{
options.Exporters = ExportTarget.AzureMonitor;
});
// Keep the host alive until shutdown; disposal flushes pending telemetry.
using var host = builder.Build();
// Start telemetry collection before recording events.
await host.StartAsync();
// Create a logger for the custom-events category.
var logger = host.Services.GetRequiredService<ILoggerFactory>().CreateLogger(
"custom-events");
// Use the message-template attribute to name the custom event.
logger.LogInformation("{microsoft.custom_event.name} {additional_attrs}",
"test-event-name", "val1");
await host.StopAsync();
若要使用 Java 代理发送 customEvent,请在 OpenTelemetry 日志记录上设置 "microsoft.custom_event.name" 属性。
根据是否启用了 Application Insights Java 代理或自动配置 SDK,获取 OpenTelemetry 记录器的方式略有不同。 以下示例进一步介绍了此详细信息。
对于 Application Insights Java 代理:
import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.api.logs.Logger;
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.logs.Severity;
Logger logger = GlobalOpenTelemetry.get().getLogsBridge().get("opentelemetry-logger");
logger.logRecordBuilder()
.setAttribute(AttributeKey.stringKey("microsoft.custom_event.name"),
"test-event-name")
.setSeverity(Severity.INFO)
.emit();
对于自动配置 SDK:
import com.azure.monitor.opentelemetry.autoconfigure.AzureMonitorAutoConfigure;
import com.azure.monitor.opentelemetry.autoconfigure.AzureMonitorAutoConfigureOptions;
import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.logs.Logger;
import io.opentelemetry.api.logs.Severity;
import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk;
import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdkBuilder;
AutoConfiguredOpenTelemetrySdkBuilder sdkBuilder =
AutoConfiguredOpenTelemetrySdk.builder();
AzureMonitorAutoConfigureOptions options = new AzureMonitorAutoConfigureOptions();
options.connectionString("<ConnectionString>");
AzureMonitorAutoConfigure.customize(sdkBuilder, options);
OpenTelemetry openTelemetry = sdkBuilder.build().getOpenTelemetrySdk();
Logger logger = openTelemetry.getLogsBridge().get("opentelemetry-logger");
logger.logRecordBuilder()
.setAttribute(AttributeKey.stringKey("microsoft.custom_event.name"),
"test-event-name")
.setSeverity(Severity.INFO)
.emit();
若要可靠地发出自定义事件,请直接使用 OpenTelemetry API。 某些日志记录框架不支持追加或分析自定义事件属性。
在Java native中无法使用 customEvent 属性发送 "microsoft.custom_event.name"。
若要使用customEvent发送logger.emit,请在日志"microsoft.custom_event.name"对象中设置attributes属性。 还可以根据需要包含其他属性。
发送自定义事件
export class CustomEventSample {
static async run() {
// Import the Microsoft OpenTelemetry Distro and the OpenTelemetry logs API
const { useMicrosoftOpenTelemetry } = await import("@microsoft/opentelemetry");
const { logs, SeverityNumber } = await import("@opentelemetry/api-logs");
// Initialize the Microsoft OpenTelemetry Distro with logging enabled
useMicrosoftOpenTelemetry({
azureMonitor: {},
});
// Get a logger and emit a customEvent by setting the microsoft attribute key
const logger = logs.getLogger("my-app-logger");
logger.emit({
body: "Hello World!",
severityNumber: SeverityNumber.INFO,
attributes: {
"microsoft.custom_event.name": "test-event-name",
"additional_attrs": "val1",
},
});
// Example: populate client_IP via attribute 'client.address'
logger.emit({
body: "This entry will have a custom client_IP",
severityNumber: SeverityNumber.INFO,
attributes: {
"microsoft.custom_event.name": "test_event",
"client.address": "192.168.1.1",
},
});
console.log("Custom events emitted");
}
}
若要在 Python 中发送 customEvent,请将日志记录库与 "microsoft.custom_event.name" 参数中的 extra 属性一起使用。
发送自定义事件
import logging
from microsoft.opentelemetry import use_microsoft_opentelemetry
# Set up your application logger
logger = logging.getLogger("my-app-logger")
# Configure Azure Monitor to collect logs from the specified logger name
use_microsoft_opentelemetry(
enable_azure_monitor=True,
logger_name="my-app-logger", # Collect logs from your namespaced logger
)
# Log a custom event with a custom name and additional attribute
# The 'microsoft.custom_event.name' value will be used as the name of the customEvent
logger.warning(
"Hello World!",
extra={
"microsoft.custom_event.name": "test-event-name",
"additional_attrs": "val1"
},
)
# You can also populate fields like client_IP with attribute `client.address`
logger.info(
"This entry will have a custom client_IP",
extra={
"microsoft.custom_event.name": "test_event",
"client.address": "192.168.1.1"
},
)
修改遥测
本部分介绍如何修改遥测。
添加范围属性
这些属性可能包括向遥测添加自定义属性。 还可以使用属性来设置 Application Insights 架构中的可选字段,如客户端 IP。
将自定义属性添加到 Span
你添加到范围的任何属性都将导出为自定义属性。 它们将填充请求、依赖项、跟踪或异常表中的 customDimensions 字段。
若要添加范围属性,请使用以下两种方法之一:
许多检测库都提供扩充选项。 有关指南,请参阅各个检测库的自述文件:
使用自定义处理器:
提示
添加此处显示的处理器之前添加Azure Monitor。
// Import the Microsoft OpenTelemetry Distro and supporting APIs.
using Microsoft.OpenTelemetry;
using OpenTelemetry.Trace;
// Create an ASP.NET Core application builder.
var builder = WebApplication.CreateBuilder(args);
// Configure the OpenTelemetry tracer provider to add a new processor named
// ActivityEnrichingProcessor.
builder.Services.ConfigureOpenTelemetryTracerProvider((sp, builder) =>
builder.AddProcessor(new ActivityEnrichingProcessor()));
// Configure the Microsoft OpenTelemetry Distro. This service will collect
// and send telemetry data to Azure Monitor.
builder.Services.AddOpenTelemetry().UseMicrosoftOpenTelemetry(options =>
options.Exporters = ExportTarget.AzureMonitor);
// Build the ASP.NET Core application.
var app = builder.Build();
// Start the ASP.NET Core application.
app.Run();
使用以下代码将 ActivityEnrichingProcessor.cs 添加到你的项目:
using System.Diagnostics;
using OpenTelemetry;
public class ActivityEnrichingProcessor : BaseProcessor<Activity>
{
public override void OnEnd(Activity activity)
{
// The updated activity will be available to all processors which are called after
// this processor.
activity.DisplayName = "Updated-" + activity.DisplayName;
activity.SetTag("CustomDimension1", "Value1");
activity.SetTag("CustomDimension2", "Value2");
}
}
若要添加范围属性,请使用以下两种方法之一:
提示
使用检测库提供的选项(当它们可用时)的优点是整个上下文都可用。 因此,用户可以选择添加或筛选更多属性。 例如,HttpClient 检测库中的扩展功能让用户可以访问 httpRequestMessage 自身。 他们可以从中选择任何内容并将其存储为属性。
许多检测库都提供扩充选项。 有关指南,请参阅各个检测库的自述文件:
使用自定义处理器:
提示
添加此处显示的处理器之前Azure Monitor导出程序。
// Import the Microsoft OpenTelemetry Distro and supporting APIs.
using Microsoft.OpenTelemetry;
using OpenTelemetry;
using OpenTelemetry.Trace;
// Create the SDK and keep its providers alive until application shutdown.
using var sdk = OpenTelemetrySdk.Create(telemetry =>
{
telemetry.WithTracing(tracing => tracing
// Collect spans from the application activity source.
.AddSource("OTel.AzureMonitor.Demo")
// Run the custom processor before exporting spans.
.AddProcessor(new ActivityEnrichingProcessor()))
// Configure the Microsoft OpenTelemetry Distro.
.UseMicrosoftOpenTelemetry(options =>
options.Exporters = ExportTarget.AzureMonitor);
});
使用以下代码将 ActivityEnrichingProcessor.cs 添加到你的项目:
using System.Diagnostics;
using OpenTelemetry;
public class ActivityEnrichingProcessor : BaseProcessor<Activity>
{
// The OnEnd method is called when an activity is finished. This is the ideal place to
// enrich the activity with additional data.
public override void OnEnd(Activity activity)
{
// Update the activity's display name.
// The updated activity will be available to all processors which are called after
// this processor.
activity.DisplayName = "Updated-" + activity.DisplayName;
// Set custom tags on the activity.
activity.SetTag("CustomDimension1", "Value1");
activity.SetTag("CustomDimension2", "Value2");
}
}
可以使用 opentelemetry-api 向范围中添加属性。
添加一个或多个范围属性会填充 customDimensions、requests、dependencies 或 traces 表中的 exceptions 字段。
将 opentelemetry-api-1.0.0.jar(或更高版本)添加到应用程序:
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-api</artifactId>
<version>1.0.0</version>
</dependency>
在代码中添加自定义维度:
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.common.AttributeKey;
AttributeKey attributeKey = AttributeKey.stringKey("mycustomdimension");
Span.current().setAttribute(attributeKey, "myvalue1");
在代码中添加自定义维度:
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.common.AttributeKey;
AttributeKey attributeKey = AttributeKey.stringKey("mycustomdimension");
Span.current().setAttribute(attributeKey, "myvalue1");
添加自定义范围属性
export class SpanAttributeEnrichmentSample {
static async run() {
// Import the Microsoft OpenTelemetry Distro
const { useMicrosoftOpenTelemetry } = await import("@microsoft/opentelemetry");
// Create a SpanEnrichingProcessor to add custom dimensions
class SpanEnrichingProcessor {
forceFlush() {
return Promise.resolve();
}
shutdown() {
return Promise.resolve();
}
onStart() {}
onEnd(span: any) {
(span as any).attributes = (span as any).attributes || {};
(span as any).attributes["CustomDimension1"] = "value1";
(span as any).attributes["CustomDimension2"] = "value2";
}
}
// Initialize the Microsoft OpenTelemetry Distro with the custom processor
useMicrosoftOpenTelemetry({
azureMonitor: {},
spanProcessors: [new SpanEnrichingProcessor()],
});
console.log("Span enrichment processor registered");
}
}
将下面显示的处理器另存为 span_enriching_processor.py,然后注册它:
...
# Import the necessary packages.
from microsoft.opentelemetry import use_microsoft_opentelemetry
from opentelemetry import trace
from span_enriching_processor import SpanEnrichingProcessor
# Create a SpanEnrichingProcessor instance.
spanEnrichProcessor = SpanEnrichingProcessor()
# Configure OpenTelemetry to use Azure Monitor with the specified connection string.
use_microsoft_opentelemetry(
enable_azure_monitor=True,
azure_monitor_connection_string="<ConnectionString>",
# Configure the custom span processors to include span enrich processor.
span_processors=[spanEnrichProcessor],
)
...
使用以下代码 span_enriching_processor.py:
# Import the SpanProcessor class from the opentelemetry.sdk.trace module.
from opentelemetry.sdk.trace import SpanProcessor
class SpanEnrichingProcessor(SpanProcessor):
def on_start(self, span, parent_context=None):
# Prefix the span name with the string "Updated-".
span.update_name("Updated-" + span.name)
# Add the custom dimension "CustomDimension1" with the value "Value1".
span.set_attribute("CustomDimension1", "Value1")
# Add the custom dimension "CustomDimension2" with the value "Value2".
span.set_attribute("CustomDimension2", "Value2")
设置用户 IP
可以通过在 span 上设置属性来填充请求的 client_IP 字段。 Application Insights 使用 IP 地址生成用户位置属性,然后默认放弃它。
使用自定义属性示例,但替换 ActivityEnrichingProcessor.cs 中的以下代码行:
// Add the client IP address to the activity as a tag.
// only applicable in case of activity.Kind == Server
activity.SetTag("client.address", "<IpAddress>");
使用自定义属性示例,但替换 ActivityEnrichingProcessor.cs 中的以下代码行:
// Add the client IP address to the activity as a tag.
// only applicable in case of activity.Kind == Server
activity.SetTag("client.address", "<IpAddress>");
使用自定义属性示例,但替换以下代码行:
设置用户 IP 地址
export class SetUserIpSample {
static async run() {
// Import the Microsoft OpenTelemetry Distro and tracing API
const { useMicrosoftOpenTelemetry } = await import("@microsoft/opentelemetry");
const { trace } = await import("@opentelemetry/api");
// Initialize the Microsoft OpenTelemetry Distro
useMicrosoftOpenTelemetry({
azureMonitor: {},
});
// Framework-agnostic helper to set client IP on the active server span
const setIpForRequest = (clientIp: string) => {
const span = trace.getActiveSpan();
if (span) {
// Preferred attribute for client IP
span.setAttribute("client.address", clientIp);
// Optional: legacy/alternate attribute
span.setAttribute("http.client_ip", clientIp);
}
};
// Call setIpForRequest("<IpAddress>") from within your web framework's request
// pipeline
console.log(
"Use setIpForRequest('<IpAddress>') inside your request handler " +
"to stamp the active span.",
);
}
}
使用自定义属性示例,但替换 SpanEnrichingProcessor.py 中的以下代码行:
# Set the `http.client_ip` attribute of the span to the specified IP address.
span.set_attribute("http.client_ip", "<IpAddress>")
设置用户 ID 或经过身份验证的用户 ID
可以使用以下指南为请求填充 user_Id 或 user_AuthenticatedId 字段。 用户 ID 是匿名用户标识符。 经过身份验证的用户 ID 是已知的用户标识符。
重要
在设置经过身份验证的用户 ID 之前,请参考适用的隐私法律。
使用自定义属性示例:
// Add the user ID to the activity as a tag, but only if the activity is not null.
activity?.SetTag("enduser.id", "<UserId>");
使用自定义属性示例:
// Add the user ID to the activity as a tag, but only if the activity is not null.
activity?.SetTag("enduser.id", "<UserId>");
填充 user ID、requests 或 dependencies 表中的 exceptions 字段。
将 opentelemetry-api-1.0.0.jar(或更高版本)添加到应用程序:
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-api</artifactId>
<version>1.0.0</version>
</dependency>
在代码中设置 user_Id:
import io.opentelemetry.api.trace.Span;
// (user_AuthenticatedId)
Span.current().setAttribute("enduser.id", "<AuthenticatedUserId>");
// (user_Id)
Span.current().setAttribute("enduser.pseudo.id", "<AnonymousUserId>");
填充 user ID、requests 或 dependencies 表中的 exceptions 字段。
在代码中设置 user_Id:
import io.opentelemetry.api.trace.Span;
// (user_AuthenticatedId)
Span.current().setAttribute("enduser.id", "<AuthenticatedUserId>");
// (user_Id)
Span.current().setAttribute("enduser.pseudo.id", "<AnonymousUserId>");
使用自定义属性示例,但替换以下代码行:
在活动 span 上设置用户标识符
export class SetUserIdSample {
static async run() {
// Import the Microsoft OpenTelemetry Distro and tracing API
const { useMicrosoftOpenTelemetry } = await import("@microsoft/opentelemetry");
const { trace } = await import("@opentelemetry/api");
// Initialize the Microsoft OpenTelemetry Distro
useMicrosoftOpenTelemetry({
azureMonitor: {},
});
// Framework-agnostic helper to set user identifiers on the active server span
const setUserForRequest = (authenticatedId?: string, anonymousId?: string) => {
const span = trace.getActiveSpan();
if (span) {
if (authenticatedId) {
// user_AuthenticatedId
span.setAttribute("enduser.id", authenticatedId);
}
if (anonymousId) {
span.setAttribute("enduser.pseudo.id", anonymousId); // user_Id
}
}
};
// Call setUserForRequest("<AuthenticatedUserId>", "<AnonymousUserId>") inside
// your request handler
console.log(
"Use setUserForRequest('<AuthenticatedUserId>', '<AnonymousUserId>') " +
"inside your request handler to stamp the active span.",
);
}
}
使用自定义属性示例,但替换以下代码行:
# Set the `enduser.id` attribute of the span to the specified user ID.
span.set_attribute("enduser.id", "<UserId>")
添加日志属性
OpenTelemetry 使用 .NET 的 ILogger。
可以使用消息模板将自定义维度附加到日志。
OpenTelemetry 使用 .NET 的 ILogger。
可以使用消息模板将自定义维度附加到日志。
会自动检测 Logback、Log4j 和 java.util.logging。 可通过以下方式将自定义维度附加到日志:
对于 Spring Boot 原生应用程序,Logback 是开箱即用的。
export class BunyanLogAttributesSample {
static async run() {
// Import the Microsoft OpenTelemetry Distro
const { useMicrosoftOpenTelemetry } = await import("@microsoft/opentelemetry");
// Enable Azure Monitor integration and bunyan instrumentation
useMicrosoftOpenTelemetry({
azureMonitor: {},
instrumentationOptions: { bunyan: { enabled: true } },
});
const bunyanMod = await import("bunyan");
const bunyan = (bunyanMod as any).default ?? bunyanMod;
// Emit a log with custom attributes
const log = (bunyan as any).createLogger({ name: "testApp" });
log.info({ key1: "value1", feature: "demo" }, "Warning log with properties");
console.log("Bunyan log with attributes emitted");
}
}
Python logging 库autoinstrumented。 通过将一个字典传递到日志的 extra 参数,可以将自定义维度附加到日志中:
...
# Create a warning log message with the properties "key1" and "value1".
logger.warning("WARNING: Warning log with properties", extra={"key1": "value1"})
...
覆盖 HTTP 4xx 响应中的请求错误状态
可以阻止 Application Insights 将 4xx 响应计数为错误。
以下代码显示了将 HTTP 4xx 响应标记为成功的自定义活动处理器。
处理器:
using System.Diagnostics;
using OpenTelemetry;
public class Http4xxSuccessProcessor : BaseProcessor<Activity>
{
public override void OnEnd(Activity activity)
{
if (activity.Kind == ActivityKind.Server)
{
var statusCodeTag = activity.GetTagItem("http.response.status_code");
if (statusCodeTag is int statusCode && statusCode >= 400 && statusCode < 500)
{
// Set status to Ok to bypass the Azure Monitor exporter's default logic
// which treats any HTTP 4xx as failure when status is Unset.
// The response code tag (e.g., 400) remains unchanged — only the
// success field in Application Insights is affected.
activity.SetStatus(ActivityStatusCode.Ok);
}
}
base.OnEnd(activity);
}
}
注册:
// Import the Microsoft OpenTelemetry Distro and supporting APIs.
using Microsoft.OpenTelemetry;
using OpenTelemetry.Trace;
// Create the application builder.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddOpenTelemetry()
.WithTracing(tracing => tracing.AddProcessor<Http4xxSuccessProcessor>())
// Configure the Microsoft OpenTelemetry Distro.
.UseMicrosoftOpenTelemetry(options =>
{
options.Exporters = ExportTarget.AzureMonitor;
// Set the connection string for Azure Monitor export.
options.AzureMonitor.ConnectionString = "<ConnectionString>";
});
// Build the application with the configured telemetry services.
var app = builder.Build();
// Run the application and its telemetry providers.
app.Run();
以下代码适用于将 HTTP 4xx 响应标记为成功的自定义活动处理器。
处理器:
using System.Diagnostics;
using OpenTelemetry;
public class Http4xxSuccessProcessor : BaseProcessor<Activity>
{
public override void OnEnd(Activity activity)
{
if (activity.Kind == ActivityKind.Server)
{
var statusCodeTag = activity.GetTagItem("http.response.status_code");
if (statusCodeTag is int statusCode && statusCode >= 400 && statusCode < 500)
{
// Set status to Ok to bypass the Azure Monitor exporter's default logic
// which treats any HTTP 4xx as failure when status is Unset.
// The response code tag (e.g., 400) remains unchanged — only the
// success field in Application Insights is affected.
activity.SetStatus(ActivityStatusCode.Ok);
}
}
base.OnEnd(activity);
}
}
注册:
// Import the Microsoft OpenTelemetry Distro and supporting APIs.
using Microsoft.OpenTelemetry;
using System.Diagnostics;
using OpenTelemetry;
using OpenTelemetry.Trace;
// Create the SDK and keep its providers alive until application shutdown.
using var sdk = OpenTelemetrySdk.Create(telemetry =>
{
telemetry.WithTracing(tracing => tracing.AddProcessor(new Http4xxSuccessProcessor()))
// Configure the Microsoft OpenTelemetry Distro.
.UseMicrosoftOpenTelemetry(options =>
{
options.Exporters = ExportTarget.AzureMonitor;
// Set the connection string for Azure Monitor export.
options.AzureMonitor.ConnectionString = "<ConnectionString>";
});
});
注意
此功能从 Java 代理版本 3.3.0 开始可用。
默认情况下,代理将捕获导致 4xx 响应代码为错误的 HTTP 服务器请求。 可以更改此行为,使其视为成功:
{
"preview": {
"captureHttpServer4xxAsError": false
}
}
处理器:
覆盖 HTTP 4xx 响应的请求错误状态
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.trace.SpanKind;
import io.opentelemetry.api.trace.StatusCode;
import io.opentelemetry.context.Context;
import io.opentelemetry.sdk.common.CompletableResultCode;
import io.opentelemetry.sdk.trace.ReadWriteSpan;
import io.opentelemetry.sdk.trace.ReadableSpan;
import io.opentelemetry.sdk.trace.internal.ExtendedSpanProcessor;
import java.util.Set;
public class Http4xxAsSuccessProcessor implements ExtendedSpanProcessor {
private static final AttributeKey<Long> HTTP_RESPONSE_STATUS_CODE =
AttributeKey.longKey("http.response.status_code");
// Deprecated semconv attribute that some libraries may still emit
private static final AttributeKey<Long> HTTP_STATUS_CODE =
AttributeKey.longKey("http.status_code");
private static final AttributeKey<Boolean> MODIFIED_FLAG =
AttributeKey.booleanKey("ai.modified.http4xx.success");
private final Set<Long> keepAsFailure = Set.of(429L);
@Override
public void onStart(Context parentContext, ReadWriteSpan span) {
// No-op
}
@Override
public boolean isStartRequired() {
return false;
}
@Override
public void onEnding(ReadWriteSpan span) {
if (span.getKind() != SpanKind.SERVER) {
return;
}
Long statusCode = span.getAttribute(HTTP_RESPONSE_STATUS_CODE);
if (statusCode == null) {
statusCode = span.getAttribute(HTTP_STATUS_CODE);
}
if (statusCode != null
&& statusCode >= 400
&& statusCode < 500
&& !keepAsFailure.contains(statusCode)) {
// Keep the HTTP status code attribute unchanged, but mark the span as OK
// so downstream backends such as Application Insights don't count it as a
// failure.
span.setStatus(StatusCode.OK);
span.setAttribute(MODIFIED_FLAG, true);
}
}
@Override
public boolean isOnEndingRequired() {
return true;
}
@Override
public void onEnd(ReadableSpan span) {
// No-op
}
@Override
public boolean isEndRequired() {
return false;
}
@Override
public CompletableResultCode shutdown() {
return CompletableResultCode.ofSuccess();
}
@Override
public CompletableResultCode forceFlush() {
return CompletableResultCode.ofSuccess();
}
}
注册(Spring Boot):
import com.azure.monitor.opentelemetry.autoconfigure.AzureMonitorAutoConfigure;
import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk;
import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdkBuilder;
public class TelemetryConfiguration {
public static OpenTelemetry configureOpenTelemetry() {
AutoConfiguredOpenTelemetrySdkBuilder sdkBuilder =
AutoConfiguredOpenTelemetrySdk.builder();
AzureMonitorAutoConfigure.customize(sdkBuilder, "<ConnectionString>");
sdkBuilder.addTracerProviderCustomizer(
(tracerProviderBuilder, configProperties) ->
tracerProviderBuilder.addSpanProcessor(new Http4xxAsSuccessProcessor())
);
return sdkBuilder.build().getOpenTelemetrySdk();
}
}
注册(夸库斯):
将共享处理器另存为 Http4xxAsSuccessProcessor.java,然后在 QuarkusHttp4xxAsSuccessProcessor.java 中添加此 Bean:
import jakarta.enterprise.context.ApplicationScoped;
@ApplicationScoped
public class QuarkusHttp4xxAsSuccessProcessor extends Http4xxAsSuccessProcessor {
}
覆盖 HTTP 4xx 响应的请求错误状态
import { SpanKind, SpanStatusCode } from "@opentelemetry/api";
import { SpanProcessor, ReadableSpan } from "@opentelemetry/sdk-trace-base";
import { ATTR_HTTP_RESPONSE_STATUS_CODE } from "@opentelemetry/semantic-conventions";
// Deprecated semconv attribute; not exported from the stable entry point.
const ATTR_HTTP_STATUS_CODE = "http.status_code";
export class Http4xxAsSuccessProcessor implements SpanProcessor {
private keepAsFailure = new Set<number>(/* [429] */);
onStart(): void {}
onEnd(span: ReadableSpan): void {
if (span.kind !== SpanKind.SERVER) return;
const attrs = span.attributes;
const sc =
(attrs[ATTR_HTTP_RESPONSE_STATUS_CODE] as number | undefined) ??
(attrs[ATTR_HTTP_STATUS_CODE] as number | undefined);
if (
typeof sc === "number" &&
sc >= 400 &&
sc < 500 &&
!this.keepAsFailure.has(sc)
) {
// By onEnd the span is ended, so setStatus()/setAttribute() are no-ops.
// Directly mutate the backing fields so the exporter sees the change.
(span as any).status = { code: SpanStatusCode.OK };
(span as any).attributes = {
...attrs,
"ai.modified.http4xx.success": true,
};
console.log(`[Processor] Rewrote ${sc} span to OK`);
}
}
shutdown(): Promise<void> {
return Promise.resolve();
}
forceFlush(): Promise<void> {
return Promise.resolve();
}
}
处理器:
覆盖 HTTP 4xx 响应的请求错误状态
from __future__ import annotations
from typing import Iterable, Optional
from opentelemetry.trace import SpanKind, Status, StatusCode
from opentelemetry.sdk.trace import ReadableSpan, SpanProcessor
# Current HTTP semconv attribute
ATTR_HTTP_RESPONSE_STATUS_CODE = "http.response.status_code"
# Older / deprecated attribute that some instrumentations may still emit
ATTR_HTTP_STATUS_CODE = "http.status_code"
class Http4xxAsSuccessProcessor(SpanProcessor):
def __init__(self, keep_as_failure: Optional[Iterable[int]] = None) -> None:
# Example: keep 429 as a failure if you want throttling to remain visible
self._keep_as_failure = set(keep_as_failure or ())
def on_start(self, span, parent_context=None) -> None:
# No-op
return
def on_end(self, span: ReadableSpan) -> None:
if span.kind is not SpanKind.SERVER:
return
attrs = span.attributes
statusCode = attrs.get(
ATTR_HTTP_RESPONSE_STATUS_CODE,
attrs.get(ATTR_HTTP_STATUS_CODE),
)
if (
isinstance(statusCode, int)
and 400 <= statusCode < 500
and statusCode not in self._keep_as_failure
):
# ReadableSpan.status is read-only, so in current released SDKs
# we mutate the private backing field that the exporter reads.
span._status = Status(StatusCode.OK) # pylint: disable=protected-access
# Optional diagnostic marker so you can tell the processor rewrote it.
# ReadableSpan.attributes returns a read-only MappingProxyType, so we
# update the private backing store instead.
if getattr(span, "_attributes", None) is None:
span._attributes = {} # pylint: disable=protected-access
try:
span._attributes["ai.modified.http4xx.success"] = (
True # pylint: disable=protected-access
)
except TypeError:
# Fallback if the backing store is not directly writable
span._attributes = dict(
span.attributes
) # pylint: disable=protected-access
span._attributes["ai.modified.http4xx.success"] = (
True # pylint: disable=protected-access
)
def shutdown(self) -> None:
return
def force_flush(self, timeout_millis: int = 30000) -> bool:
return True
注册:
from microsoft.opentelemetry import use_microsoft_opentelemetry
# Initialize the Microsoft OpenTelemetry Distro with Azure Monitor export.
use_microsoft_opentelemetry(
enable_azure_monitor=True,
azure_monitor_connection_string="<ConnectionString>",
span_processors=[Http4xxAsSuccessProcessor()],
)
获取追踪 ID 或跨度 ID
要获取当前处于活动状态的跨度中的Trace ID和Span ID,请使用以下步骤。
注意
Activity 命名空间中的 ActivitySource 和 System.Diagnostics 类分别代表 Span 和 Tracer 的 OpenTelemetry 概念。 这是因为 OpenTelemetry 跟踪 API 的某些部分直接合并到.NET运行时中。 若要了解详细信息,请参阅 OpenTelemetry .NET 跟踪 API 的简介。
using System.Diagnostics;
// Get the current activity.
Activity activity = Activity.Current;
// Get the trace ID of the activity.
string traceId = activity?.TraceId.ToHexString();
// Get the span ID of the activity.
string spanId = activity?.SpanId.ToHexString();
注意
Activity 命名空间中的 ActivitySource 和 System.Diagnostics 类分别代表 Span 和 Tracer 的 OpenTelemetry 概念。 这是因为 OpenTelemetry 跟踪 API 的某些部分直接合并到.NET运行时中。 若要了解详细信息,请参阅 OpenTelemetry .NET 跟踪 API 的简介。
using System.Diagnostics;
// Get the current activity.
Activity activity = Activity.Current;
// Get the trace ID of the activity.
string traceId = activity?.TraceId.ToHexString();
// Get the span ID of the activity.
string spanId = activity?.SpanId.ToHexString();
可以使用 opentelemetry-api 获取跟踪 ID 或范围 ID。
将 opentelemetry-api-1.0.0.jar(或更高版本)添加到应用程序:
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-api</artifactId>
<version>1.0.0</version>
</dependency>
在代码中获取请求跟踪 ID 和跨度 ID。
import io.opentelemetry.api.trace.Span;
Span span = Span.current();
String traceId = span.getSpanContext().getTraceId();
String spanId = span.getSpanContext().getSpanId();
在代码中获取请求跟踪 ID 和跨度 ID。
import io.opentelemetry.api.trace.Span;
Span span = Span.current();
String traceId = span.getSpanContext().getTraceId();
String spanId = span.getSpanContext().getSpanId();
在代码中获取请求跟踪 ID 和跨度 ID。
export class GetTraceAndSpanIdSample {
static async run() {
// Dynamically import tracing API
const { trace } = await import("@opentelemetry/api");
// Read the span/trace id from the active span (if any)
const activeSpan = trace.getActiveSpan();
const spanId = activeSpan?.spanContext().spanId;
const traceId = activeSpan?.spanContext().traceId;
console.log("SpanId:", spanId, "TraceId:", traceId);
}
}
在代码中获取请求跟踪 ID 和跨度 ID。
# Import the necessary libraries.
from opentelemetry import trace
# Get the trace ID and span ID of the current span.
traceId = trace.get_current_span().get_span_context().trace_id
spanId = trace.get_current_span().get_span_context().span_id
故障排除、反馈和支持
提示
以下部分适用于所有 OpenTelemetry 发行版文章。
故障排除
OpenTelemetry 反馈
若要提供反馈,请查看以下内容:
支持
选择所选语言的选项卡,以发现支持选项。
注意
Quarkus 社区支持和维护 Quarkus 扩展。 寻求帮助,请使用 Quarkus 社区支持渠道。 Azure不提供对此集成的技术支持。
后续步骤