mcpField
O
opentelemetry-net-instrumentation

opentelemetry-net-instrumentation

github.com/aaronontheweb开发1.2k418 次安装今天更新
代码仓库

关于 opentelemetry-net-instrumentation

面向 .NET 的 Claude Code 技能,用于添加、审查和优化 OpenTelemetry 埋点。它强调使用 .NET 内置诊断 API,并区分库代码埋点与应用级采集、导出配置。

主要功能

  1. 01跟踪、指标与日志指导
  2. 02ActivitySource 和 Meter 模式
  3. 03SDK、导出器与采样设置
  4. 04弹性与语义约定检查

适用场景

  1. 01为 .NET 库埋点且不添加 OTel 包
  2. 02配置应用遥测导出
  3. 03审查 Span 错误和属性

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/aaronontheweb/dotnet-skills --skill opentelemetry-net-instrumentation

安装后在 Claude Code 中输入/opentelemetry-net-instrumentation确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

metrics-and-instruments-reference.md
sdk-resources-and-logs-reference.md
traces-and-propagation-reference.md

详细介绍

OpenTelemetry .NET 埋点技能

使用场景

  • 为 .NET 代码添加 OpenTelemetry 埋点(跟踪、指标、日志)
  • 创建或修改 ActivitySources、Meters 或 ILogger 用法
  • 配置 OpenTelemetry SDK、资源、导出器或采样
  • 审查遥测实现是否符合规范
  • 优化埋点性能
  • 设计将成为公共接口一部分的遥测 API
  • 实现跨服务边界的上下文传播

架构:.NET 与众不同

重要:.NET 的 OpenTelemetry 实现与其他平台有根本区别。.NET 在框架本身中提供跟踪、指标和日志 API。 这意味着 OTel 不提供独立的埋点 API——它使用内置的 .NET API,并充当数据收集与导出层。

.NET 内置的三种 API(主要方式——零依赖)
信号.NET 框架 API命名空间
跟踪ActivitySource / ActivitySystem.Diagnostics
指标Meter / Counter<T> / Histogram<T> / 等System.Diagnostics.Metrics
日志ILogger<T>Microsoft.Extensions.Logging

这些是库作者进行埋点时应使用的主要且唯一的 API。 它们随 .NET 运行时提供——无需 NuGet 包。

OTel 数据收集与导出层(次要——仅用于应用程序根项目)

OTel NuGet 包是数据收集与导出层,仅添加到应用程序组合根项目中(不添加到库中):

包用途添加时机
OpenTelemetry.Extensions.Hosting为 ASP.NET Core / 通用主机提供 DI 集成仅应用程序
OpenTelemetry.Exporter.Console控制台导出器(开发/测试)仅应用程序
OpenTelemetry.Exporter.OpenTelemetryProtocolOTLP 导出器(生产环境)仅应用程序
OpenTelemetry.Exporter.Prometheus*Prometheus 指标端点仅应用程序
OpenTelemetry.Instrumentation.AspNetCore自动为 ASP.NET Core 请求添加埋点仅应用程序
OpenTelemetry.Instrumentation.Http自动为 HttpClient 调用添加埋点仅应用程序
OpenTelemetry.Instrumentation.SqlClient自动为 SQL 调用添加埋点仅应用程序
包选择指南

添加任何 OpenTelemetry NuGet 包之前,请先与用户讨论其中的权衡:

“你即将添加一个 OTel NuGet 包。你是在开发需要将遥测数据导出到可观测性后端(Jaeger、Prometheus、OTLP collector)的应用程序吗? 如果你正在编写库,很可能不需要任何 OTel 包——只需使用 System.Diagnostics.ActivitySource / System.Diagnostics.Metrics.Meter,并让使用该库的应用程序配置导出管道。要继续吗?”

库作者:什么都不添加。只使用 System.Diagnostics.* 和 ILogger。 使用该库的应用程序负责接入 SDK 和导出器。

应用程序作者:添加 OpenTelemetry.Extensions.Hosting,以及所需的导出器和埋点库。完整配置模式请参见 sdk-resources-and-logs-reference.md。

切勿在库中添加 OpenTelemetry.Api——System.Diagnostics.* 就是 API。

有关 SDK 配置、资源配置、导出器、采样和日志集成,请参见 sdk-resources-and-logs-reference.md。

核心原则

弹性优先

重要:诊断/跟踪/指标逻辑中的异常绝不能影响应用程序处理。

  • 假设 Activity 实例可能为 null。始终防范 Activity 引用为 null 的情况,但 Activity 扩展方法除外(使用 activity?.ExtensionMethod())
  • 对所有埋点代码添加适当的 null 检查
API 表面认知
  • 发出的任何遥测数据都会成为公共 API 表面的一部分
  • 变更受破坏性变更指南约束
  • 默认应发出遥测数据(用户通过 OpenTelemetry 扩展选择加入数据收集)
  • 例外:高基数指标维度可能需要显式选择加入
标准合规性
  • 遵循 Microsoft 关于分布式跟踪插桩的最佳实践
  • 遵循 OpenTelemetry 语义约定
  • 属性值支持:字符串、布尔值、double(IEEE 754)、int64、字节数组,以及由这些基本类型构成的同质数组。根据 OTel AnyValue 规范,Null/空值有效且有意义——必须存储并传递给导出器。
  • 属性键必须是非 null、非空字符串

跟踪 / Span(Activity)

ActivitySource 设置
// ✅ CORRECT: Use ActivitySource, not DiagnosticSource
public class MyFeature
{
    // Primary ActivitySource - name typically matches the component or NuGet package name
    private static readonly ActivitySource ActivitySource = new("MyApp.MyComponent", "1.0.0");

    // Specialized ActivitySource for opt-in scenarios
    private static readonly ActivitySource DetailedActivitySource = new("MyApp.MyComponent.Detailed", "1.0.0");
}

规则:

  • 每个组件都为主流 Activity 定义一个主要的 ActivitySource
  • 名称通常与组件或 NuGet 包相匹配(例如,"MyCompany.MyLibrary")
  • 使用 SemVer 为 ActivitySource 设置版本
  • 为专用或选择加入的场景创建单独的 ActivitySource。使用分层的源名称,例如 MyCompany.MyLibrary 和 MyCompany.MyLibrary.Detailed,这样使用方应用就能通过 AddSource(...) 仅订阅所需的源,后端也能按插桩范围进行筛选。
创建 Activity
// ✅ Check HasListeners, null-check, then guard expensive work behind IsAllDataRequested
if (ActivitySource.HasListeners())
{
    using var activity = ActivitySource.StartActivity("ProcessItem", ActivityKind.Internal);
    if (activity != null && activity.IsAllDataRequested)
    {
        activity.DisplayName = "Processing order #12345";
        activity.SetTag("app.item_id", itemId);
        activity.SetTag("app.item_type", itemType);
    }
}

// ❌ WRONG: Don't start activities in fire-and-forget tasks where the
// using scope ends before the async work completes (AsyncLocal context is lost)
async Task HelperAsync()
{
    using var activity = ActivitySource.StartActivity("Helper");
    _ = Task.Run(() => DoWorkAsync()); // ❌ activity disposed before task completes
}

规则:

  • 创建前检查 ActivitySource.HasListeners()(零分配快速路径)
  • 创建后始终检查 Activity 是否为 null(监听器可能会筛选掉它或不对其采样)
  • 切勿在异步辅助方法中启动 Activity(Activity.Current 使用 AsyncLocal)
  • 使用 activity.IsAllDataRequested 对开销较大的标签计算进行保护
  • 使用 W3C TraceContext。.NET Core 3.0+ / .NET 5+ 默认使用该格式;较旧的 TFM 或 .NET Framework 应用可在启动时设置 Activity.DefaultIdFormat = ActivityIdFormat.W3C,并使用 Activity.ForceDefaultIdFormat = true 覆盖分层父级。
Activity 命名
// ✅ Unique operation name, friendly display name (null-check before accessing)
using var activity = ActivitySource.StartActivity(
    name: "ProcessItem",              // Unique, identifies class of spans
    kind: ActivityKind.Internal
);
if (activity != null)
    activity.DisplayName = "Processing order #12345"; // User-friendly, can be specific

// ❌ WRONG: Don't include runtime data in operation name
using var badActivity = ActivitySource.StartActivity($"Process_{itemId}"); // ❌

规则:

  • 每种 Span 类型都有唯一的 OperationName(用于标识具有统计意义的一类 Span)
  • 操作名称不应包含运行时数据(仅包含编译时或配置时信息)
  • 使用易于理解的 DisplayName 表示具体信息
  • 遵循 OpenTelemetry Span 命名约定
SpanKind 选择

选择正确的 ActivityKind,以明确 Span 在分布式跟踪中的作用:

ActivityKindOTel SpanKind使用场景
InternalINTERNAL默认——不跨越远程边界的进程内操作
ServerSERVER处理传入的请求/响应调用(HTTP 服务端、gRPC 服务端、RPC 服务端)
ClientCLIENT发起传出的请求/响应调用(HTTP 客户端、数据库客户端、RPC 调用)
ProducerPRODUCER将延迟执行的工作入队/发布(发布到消息队列、发出事件、作业入队)
ConsumerCONSUMER将延迟执行的工作出队/处理(接收消息队列消息、处理事件、作业出队)

规则:

  • 单个 Span 不应承担多种用途
  • 在将其 SpanContext 注入请求之前,创建传出的 Span。如果先注入,传播的将是父级的上下文,传出的 Span 最终会成为悬空 Span(与下游调用没有关联)。
  • 详细的 SpanKind 指南及示例,请参阅 traces-and-propagation-reference.md
Span 属性(标签)
// ✅ Application code: use your own namespace
activity?.SetTag("myapp.order_id", orderId);
activity?.SetTag("myapp.payment.status", "confirmed");

// ✅ Manual infrastructure instrumentation: use semantic conventions
// activity?.SetTag("db.system.name", "postgresql"); // custom database client
// activity?.SetTag("http.request.method", "GET"); // custom HTTP transport

// Values can be strings, numbers, booleans, or homogeneous arrays
activity?.SetTag("app.item_count", 42);
activity?.SetTag("app.related_ids", new int[] { 1, 2, 3 });

// ❌ WRONG: PascalCase, hyphen delimiter, plural, or unrelated namespace
activity?.SetTag("MyApp.OrderId", orderId);     // ❌ Wrong case
activity?.SetTag("myapp.order-id", orderId);    // ❌ Wrong delimiter

规则:

  • 命名空间前缀应与组件匹配:myapp.*、myapp.db.*
  • 全部使用小写字母,以下划线(_)分隔,并采用单数形式
  • 属性值:字符串、布尔值、双精度浮点数、int64、字节数组、同质数组(根据 AnyValue 规范,null/空值有效)
  • 业务/领域属性:使用自己的命名空间(myapp.*)。
  • 手动埋点的 HTTP、数据库、消息传递或 RPC 概念:使用语义约定。请勿重复记录自动埋点已发出的属性。请勿使用 OTel 命名空间作为自定义属性的前缀。
Activity 状态和错误
try
{
    await ProcessItemAsync(); // ✅ success: leave status Unset, do not call SetStatus(Ok) — see rules below
}
catch (Exception ex)
{
    if (activity != null)
    {
        activity.SetStatus(ActivityStatusCode.Error, ex.Message); // modern API
        activity.SetTag("error.type", ex.GetType().FullName);
    }
    throw;
}

规则(依据记录错误和设置状态 API 规范):

  • 操作成功时,将 span 状态保持为 Unset——不要调用 SetStatus(ActivityStatusCode.Ok)。
  • Ok 适用于应用程序代码,不适用于埋点库。Trace API 规范规定:“除非经过明确配置,否则埋点库不应将状态码设为 Ok (...) 应用程序开发人员和运维人员可以将状态码设为 Ok”——通常用于覆盖他们认定并非真实故障的库报告的 Error(例如,抑制频繁出现的 404)。一旦设置 Ok,状态即为最终状态;后续调用会被忽略。”
  • 发生故障时:应设置 ActivityStatusCode.Error,应设置 error.type 标签,应将状态描述设为异常消息。
  • 使用 SetStatus——不再需要旧版 otel.status_code/otel.status_description 标签。
  • 对于经过重试或处理后已恢复、并顺利完成操作的错误,不要记录错误——Error 状态和 error.type 用于描述失败的操作,而非已恢复的操作。
记录异常 — 继续发出 Span 事件,并添加日志启用选项

exceptions-spans——即 Activity.AddEvent(new ActivityEvent("exception", ...)) 背后的约定——已被标记为已弃用,建议改用 exceptions-logs,但 .NET 生态尚未跟进:没有任何 OpenTelemetry.* .NET 包实现规范中的 OTEL_SEMCONV_EXCEPTION_SIGNAL_OPT_IN 启用选项(已针对 OpenTelemetry.Api 1.17.0 验证),而 OpenTelemetry.Instrumentation.AspNetCore 1.17.0 本身仍通过 Activity.AddException 记录异常,也就是记录为 Span 事件。这意味着,典型 .NET 用户如今配置的导出器、后端和仪表板都能读取异常 Span 事件,而不是基于日志的异常。继续默认实现 Span 事件——仅仅因为底层规范文档标记为“已弃用”就移除它们,会导致仍在使用当前工具的用户无法看到异常,且不会收到任何提示。按照规范自身对从 Span 事件迁移的检测工具所给出的过渡指导,在此基础上添加基于日志的新路径,并将其设为启用选项:

// Mirrors the spec's OTEL_SEMCONV_EXCEPTION_SIGNAL_OPT_IN values: unset/anything else → spans only (today's default), "logs/dup" → both, "logs" → logs only.
private static readonly string? ExceptionSignalOptIn = Environment.GetEnvironmentVariable("OTEL_SEMCONV_EXCEPTION_SIGNAL_OPT_IN");
private static readonly bool EmitSpanEvents = ExceptionSignalOptIn != "logs";
private static readonly bool EmitLogs = ExceptionSignalOptIn is "logs" or "logs/dup";

try
{
    await ProcessItemAsync();
}
catch (Exception ex)
{
    activity?.SetStatus(ActivityStatusCode.Error, ex.Message);
    activity?.SetTag("error.type", ex.GetType().FullName);

    if (EmitSpanEvents) // ✅ default — what current .NET tooling and dashboards actually consume today
    {
        activity?.AddEvent(new ActivityEvent("exception", tags: new ActivityTagsCollection
        {
            ["exception.type"] = ex.GetType().FullName,
            ["exception.message"] = ex.Message,
            ["exception.stacktrace"] = ex.ToString()
        }));
    }

    if (EmitLogs) // opt-in — the spec's forward direction; pass the exception instance while `activity` is still Activity.Current so the SDK derives trace_id/span_id and exception.type/message/stacktrace from it
    {
        logger.LogError(ex, "Item processing failed");
    }

    throw;
}

规则:

  • 不要在 Span 事件上设置 exception.escaped——它已被明确弃用:“不再建议记录已处理且未逸出 Span 作用域的异常。”
  • 支持 OTEL_SEMCONV_EXCEPTION_SIGNAL_OPT_IN(logs / logs/dup),让已准备就绪的使用者可以选择日志或双重发出,但默认仅发出 Span 事件——这是规范自身的过渡指导,并非可有可无的优化;它的存在正是为了让任何人都不必在准备就绪之前被迫二选一。
  • 发出日志时(无论是启用日志还是双重发出),按照 exceptions-logs 选择严重性:未处理异常使用 ERROR(尤其是 SERVER / CONSUMER Span 上的异常),预期由调用方处理的异常使用 WARN(尤其是 CLIENT / PRODUCER Span 上的异常),不代表实际问题的异常使用 DEBUG(例如在客户端取消请求),只有异常导致应用程序关闭时才使用 FATAL。
  • 日志调用必须在其关联的 Span 仍为当前 Span 时发生——规范要求:“同时为同一操作记录 Span 的检测工具所发出的异常事件,必须与相应的 Span 上下文关联。”在 using Activity 作用域结束后,通过已脱离上下文的错误报告回调记录日志,会导致日志错误地关联到其他 Span,或者完全无法关联。请参阅下文的访问 Activity。
  • 只有在稳定的主版本上保持双重发出至少六个月(规范自身规定的最短期限),并且确认实际使用者会读取基于日志的异常后,才能改为仅使用 logs——不能仅凭固定时间表迁移。

完整模式请参阅 traces-and-propagation-reference,其中包括没有日志依赖的核心库如何仍能公开回调,以便独立的 OTel 集成包在正确的 Span 仍处于活动状态时捕获异常详情。

访问 Activity
var current = Activity.Current; // ❌ may be a user-created ambient span
using var ownedActivity = ActivitySource.StartActivity("MyOperation"); // ✅ captured reference
ownedActivity?.SetTag("myapp.key", value);

规则:对于自己拥有的 Span,不要依赖 Activity.Current;用户代码可以通过 AsyncLocal 替换它。仅在 Activity 仍有效时传递或存储捕获的 Activity。传播标识时存储 ActivityContext。

Span 链接

链接用于将一个 Span 与其他具有因果关系、但不处于直接父子关系的 Span 关联起来——例如批处理、分发/汇聚以及跨越 Trace 边界。

var links = new List<ActivityLink>
{
    new(activityContext1),
    new(activityContext2),
};

var activity = ActivitySource.StartActivity(
    ActivityKind.Internal, name: "batch-process", links: links);

完整的链接模式请参阅 traces-and-propagation-reference.md,其中包括批处理、分发/汇聚以及跨越 Trace 边界。

上下文传播

分布式追踪需要使用 W3C traceparent 标头跨进程边界(HTTP 调用、消息队列等)传播追踪上下文。在 .NET 中,这由 DistributedContextPropagator 负责处理。OTel SDK 默认配置 W3C TraceContext 传播。

有关传播模式、自定义传播器,以及针对非标准传输方式的手动注入/提取,请参阅 traces-and-propagation-reference.md。

指标

Meter 和 Metrics 类设置
public sealed class OrderProcessingMetrics : IDisposable
{
    private readonly Meter meter = new("MyApp.OrderProcessing", "1.0.0");
    private readonly Histogram<double> processingDuration =
        meter.CreateHistogram<double>("myapp.order.processing.duration", unit: "s");
    private readonly Counter<long> itemsProcessed =
        meter.CreateCounter<long>("myapp.order.processing.count", unit: "{order}");

    public void Dispose() => meter.Dispose();
}

命名约定(遵循 OTel 语义约定):

  • 使用单数名称和嵌套层级:myapp.order.processing.duration
  • 定义单位(s、ms、{item}、{connection});避免使用技术后缀(_counter、_histogram)
  • 在采用情况得到验证之前,使用 pre-1.0.0 版本
仪表类型概览

.NET 提供 7 种指标仪表类型。请根据测量内容选择合适的类型:

仪表.NET API行为典型用途
CounterCreateCounter<T>单调递增请求计数、错误计数
UpDownCounterCreateUpDownCounter<T>可增可减队列大小、活动连接数
HistogramCreateHistogram<T>值的分布持续时间、响应大小
GaugeCreateGauge<T> (.NET 9+)同步瞬时值记录当前测量值
ObservableCounterCreateObservableCounter<T>异步回调,单调递增定期轮询的总计数
ObservableGaugeCreateObservableGauge<T>异步回调,非单调CPU/内存使用量
ObservableUpDownCounterCreateObservableUpDownCounter<T>异步回调,双向变化按优先级统计的活动任务数

有关完整的创建/记录示例和可观测回调模式,请参阅 metrics-and-instruments-reference.md。

指标记录方法命名
// ✅ Action/outcome-based naming, separate methods per outcome
public void OrderProcessingSucceeded(string orderType, TimeSpan duration) { /* Record */ }
public void OrderProcessingFailed(string orderType, Exception ex, TimeSpan duration) { /* Record */ }
public void ConnectionOpened() => connectionsOpen.Add(1);
public void ConnectionClosed() => connectionsOpen.Add(-1);

// ❌ WRONG: Name after metric, confusing signature
public void RecordOrderProcessingDuration(...) { } // ❌ don't name after metric
public void RecordError(bool succeeded, Exception? ex) { } // ❌ confusing signature

规则:

  • 根据操作/结果命名(OrderProcessingSucceeded),而不是根据指标命名(RecordXxx)
  • 针对不同结果使用独立的方法(避免使用布尔标志和可选异常)
  • 状态变化采用基于事件的命名:ConnectionOpened()、ItemQueued()
指标维度
// ✅ Low-cardinality, predefined dimensions
processingDuration.Record(duration.TotalSeconds,
    new KeyValuePair<string, object?>("myapp.order_type", orderType),  // bounded set
    new KeyValuePair<string, object?>("outcome", "success"));         // bounded set

// ❌ High-cardinality: unbounded values cause cardinality explosion
failureCount.Add(1, new KeyValuePair<string, object?>("order_id", orderId)); // ❌ unbounded

规则:

  • 维度 MUST 预先定义且基数较低(项目类型、队列名称、结果)
  • 避免使用无界值(每个唯一值都会新增一行时间序列 → 基数爆炸)
  • 高基数维度 MUST 通过可选配置启用
  • 各组件使用一致的名称:myapp.region 在所有地方都表示相同含义
  • 用户可以启用 exemplars 以关联追踪(而非通过维度关联)

性能要求

默认情况下,插桩 MUST 开销低。请遵循以下规则以尽量减少开销:

零分配快速路径
// ✅ CORRECT: Guard with cheap checks
if (ActivitySource.HasListeners())
{
    using var activity = ActivitySource.StartActivity("Operation");
    // ... expensive work
}

// ✅ CORRECT: Use TagList (struct) for metrics
var tags = new TagList
{
    { "myapp.order_type", orderType },
    { "outcome", "success" }
};
counter.Add(1, tags);
计时
// ✅ Timestamp math (no allocation)
var startTime = Stopwatch.GetTimestamp();
try { await ProcessAsync(); }
finally { var duration = Stopwatch.GetElapsedTime(startTime); metrics.OrderProcessingSucceeded(orderType, duration); }

// ❌ Allocates: Stopwatch.StartNew() or IDisposable timing wrappers
避免隐式分配
// ❌ Allocates: string interpolation without IsAllDataRequested guard
activity?.SetTag("item", $"Processing {itemId}"); // ❌

// ✅ Guard expensive work behind IsAllDataRequested
if (activity?.IsAllDataRequested == true)
    activity.SetTag("item", $"Processing {itemId}");

规则:

  • 不要使用 Stopwatch.StartNew()(请使用 Stopwatch.GetTimestamp()/GetElapsedTime)
  • 优先使用 TagList(结构体),而非数组/字典
  • 热路径中不要使用 LINQ、字符串插值或异步状态机,除非有保护措施

测试要求

Span 测试
[Test]
public async Task Should_create_processing_span_with_correct_parent()
{
    // Arrange
    using var parent = new Activity("Parent").Start();

    // Act
    await handler.Handle(item);

    // Assert
    var processingSpan = recordedActivities.Single(a => a.OperationName == "ProcessItem");
    Assert.AreEqual(parent.Id, processingSpan.ParentId);
    Assert.AreEqual("myapp.item_type", processingSpan.Tags.First().Key);
}

[Test]
public void Should_not_introduce_breaking_changes_to_span_names()
{
    // Ensures string values in span names are under test
    Assert.AreEqual("ProcessItem", MyFeature.SpanName);
}

规则:

  • 测试哪些 span 与哪些活动关联
  • 测试字符串值(span 名称、标签名称),以防止出现破坏性变更
  • 请记住:遥测是公共 API 的一部分

版本控制

  • 遥测版本与包版本解耦
  • 使用 SemVer 语义
  • Trace 和 Metrics 使用独立版本(各自演进)
  • 在采用情况/实用性得到验证之前,使用 pre-1.0.0 版本
private static readonly ActivitySource ActivitySource = new("MyApp.MyComponent", "0.9.0");
private readonly Meter meter = new("MyApp.MyComponent", "0.8.0");

日志

.NET 日志通过内置的 ILogger API 与 OpenTelemetry 集成。OTel SDK 在日志构建器上提供 AddOpenTelemetry(),用于收集、处理和导出日志。日志记录会通过 TraceId/SpanId 自动与跟踪关联。

有关完整的日志集成模式,包括关联、脱敏、结构化日志和严重性筛选,请参阅 sdk-resources-and-logs-reference.md。

参考文件

  • traces-and-propagation-reference.md:深入介绍 SpanKind 并提供示例、Span Links(批处理、散射/收集、跟踪边界)、上下文传播(W3C traceparent、DistributedContextPropagator、自定义传播器)、Baggage,以及完整的现代异常记录模式。
  • metrics-and-instruments-reference.md:全部 7 种度量仪器类型及其创建/记录代码和使用场景指南、可观察仪器回调模式、维度深入介绍、示例数据、聚合默认值和单位。
  • sdk-resources-and-logs-reference.md:SDK 初始化(ASP.NET Core + Console)、资源配置(ResourceBuilder、AddService、AddDetector、自定义检测器)、导出器(OTLP、Console、Jaeger、Zipkin、Prometheus)、检测库、采样(内置、自定义、环境变量、头部/尾部采样)、日志集成(ILogger、关联、脱敏、结构化日志)和环境变量配置。

参考资料

评论

支持 Markdown