创建跨追踪的链接

了解如何使用 OpenTelemetry .NET 创建跨追踪的链接

本指南将介绍如何在 OpenTelemetry .NET 中创建跨追踪的链接,这在扇出操作、批处理处理或关联不同追踪中的相关活动时非常有用。

在 OpenTelemetry 中,链接允许您在 span(或 .NET 中的 activity)之间建立关联,这些 span 是相关的,但可能没有直接的父子关系。这在分布式系统中尤其有用,您需要关联可能属于不同追踪的多个操作。

使用链接的常见场景包括:

  • 扇出操作:当单个请求触发多个并行操作时
  • 批量处理:当多个传入请求在单个批次中进行处理时
  • 异步处理:当操作在不同追踪中异步处理时
  • 跨服务关联:当连接不同服务中的相关操作时

以下示例演示了如何创建新的根活动,并链接到现有活动。

using System.Diagnostics;
using OpenTelemetry;
using OpenTelemetry.Trace;

// Create an activity source
var activitySource = new ActivitySource("MyCompany.MyApplication");

// Configure OpenTelemetry
using var tracerProvider = Sdk.CreateTracerProviderBuilder()
    .AddSource("MyCompany.MyApplication")
    .AddConsoleExporter()
    .Build();

// Start a parent activity
using (var orchestratingActivity = activitySource.StartActivity("OrchestratingActivity"))
{
    orchestratingActivity?.SetTag("operation", "main-process");

    // Fan out to multiple operations with linked activities
    await DoFanoutAsync(activitySource, 3);

    // Continue with the original activity
    using (var nestedActivity = activitySource.StartActivity("WrapUp"))
    {
        nestedActivity?.SetTag("status", "completed");
    }
}

// Method that creates new root activities with links
async Task DoFanoutAsync(ActivitySource source, int operationCount)
{
    // Store the current activity to restore it later
    var previous = Activity.Current;

    // Get the context of the current activity for linking
    var activityContext = Activity.Current!.Context;
    var links = new List<ActivityLink>
    {
        new ActivityLink(activityContext),
    };

    var tasks = new List<Task>();

    // Create multiple new root activities that link to the original activity
    for (int i = 0; i < operationCount; i++)
    {
        int operationIndex = i;

        var task = Task.Run(() =>
        {
            // Set the current activity to null to create a new root activity
            Activity.Current = null;

            // Create a new root activity with a link to the original activity
            using var newRootActivity = source.StartActivity(
                ActivityKind.Internal,
                name: $"FannedOutActivity {operationIndex + 1}",
                links: links);

            // Perform work for this operation...
        });

        tasks.Add(task);
    }

    // Wait for all fanned-out operations to complete
    await Task.WhenAll(tasks);

    // Restore the original activity context
    Activity.Current = previous;
}

理解输出

运行此代码后,您将在输出中看到多个活动。

  1. 一个追踪用于 OrchestratingActivity(原始活动)
  2. 多个独立的追踪,每个 FannedOutActivity 一个
  3. 每个 FannedOutActivity 都链接到 OrchestratingActivity

输出将类似于:

Activity.TraceId:            5ce4d8ad4926ecdd0084681f46fa38d9
Activity.SpanId:             8f9e9441f0789f6e
Activity.TraceFlags:         Recorded
Activity.ActivitySourceName: MyCompany.MyApplication
Activity.DisplayName:        FannedOutActivity 1
Activity.Kind:               Internal
Activity.StartTime:          2023-10-17T01:24:40.4957326Z
Activity.Duration:           00:00:00.0008656
Activity.Links:
    2890476acefb53b93af64a0d91939051 16b83c1517629363

请注意,此活动具有:

  • 新的追踪 ID(5ce4d8ad4926ecdd0084681f46fa38d9
  • 链接到原始活动的追踪和 span ID(2890476acefb53b93af64a0d91939051 16b83c1517629363

考虑在以下场景中使用链接:

  1. 高基数操作:当单个操作会生成数千个 span 时,创建具有链接的独立追踪可以使可视化和分析更易于管理。

  2. 并行处理:当并行处理项目时,您希望独立跟踪每个项目的处理,同时保持与原始请求的连接。

  3. 异步工作流:当操作异步发生并且可能不在同一追踪生命周期内完成时。

虽然链接提供了灵活性,但也有一些需要考虑的地方:

  • 多个追踪:您将拥有多个相关的追踪,而不是一个连贯的追踪。
  • 可视化复杂性:某些可观测性工具可能对可视化链接追踪的支持有限。
  • 分析复杂性:跨链接追踪分析数据需要更复杂的查询。

最佳实践

  1. 使用有意义的活动名称:选择清晰的名称,表明每个链接活动的用途。
  2. 添加上下文标签:包含有助于识别活动为何链接的标签。
  3. 恢复原始上下文:在创建链接活动后,始终恢复原始的 Activity.Current
  4. 谨慎使用:仅在必要时创建新的根活动,以避免碎片化您的追踪数据。

了解更多