报告异常

了解如何在 OpenTelemetry .NET 跟踪中报告异常

本指南介绍在手动创建活动(span)时如何将异常报告给 OpenTelemetry 跟踪。如果您使用的是其中一个程序集库,它可能会自动提供这些功能。

理解跟踪中的异常处理

在 OpenTelemetry 中,报告跟踪中的异常非常重要,可以提供应用程序中发生的错误的上下文。有几种方法可以处理此问题,从基本的状1态报告到完整的异常详细信息。

用户处理的异常

用户处理的异常是指被应用程序捕获并处理的异常

try
{
    Func();
}
catch (SomeException ex)
{
    DoSomething();
}
catch (Exception ex)
{
    DoSomethingElse();
    throw;
}

OpenTelemetry .NET 提供了几种选项来在跟踪中报告这些异常。

选项 1:手动设置活动状态

最基本选项是将活动状态设置为“错误”(Error),以指示发生了异常

using (var activity = MyActivitySource.StartActivity("Foo"))
{
    try
    {
        Func();
    }
    catch (SomeException ex)
    {
        activity?.SetStatus(ActivityStatusCode.Error);
        DoSomething();
    }
    catch (Exception ex)
    {
        activity?.SetStatus(ActivityStatusCode.Error);
        throw;
    }
}

选项 2:使用 SetErrorStatusOnException 功能

如果您有深度嵌套的活动或由第三方库创建的活动,手动设置状态可能会很困难。但是,您可以配置 SDK 以自动检测异常并设置活动状态

Sdk.CreateTracerProviderBuilder()
    .SetErrorStatusOnException()
    // other configuration...
    .Build();

通过此配置,在活动激活期间发生的任何异常都会自动将该活动的活动状态设置为“错误”(Error)。

选项 3:包含错误描述

您可以将异常消息作为状态描述包含在内,以提供更多上下文

using (var activity = MyActivitySource.StartActivity("Foo"))
{
    try
    {
        Func();
    }
    catch (SomeException ex)
    {
        activity?.SetStatus(ActivityStatusCode.Error, ex.Message);
    }
}

选项 4:记录完整异常

为了获得最丰富的调试体验,请使用 Activity.RecordException() 将异常作为事件存储在活动中

using (var activity = MyActivitySource.StartActivity("Foo"))
{
    try
    {
        Func();
    }
    catch (SomeException ex)
    {
        activity?.SetStatus(ActivityStatusCode.Error, ex.Message);
        activity?.RecordException(ex);
    }
}

这将捕获异常类型、消息和堆栈跟踪,并将其提供给您的跟踪后端。

未处理的异常

未处理的异常是指未被应用程序捕获和处理的异常。它们通常会导致进程崩溃或终止线程。

您可以通过使用 AppDomain.UnhandledException 事件处理程序来捕获未处理的异常并将其记录在活动活动中

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

public class Program
{
    private static readonly ActivitySource MyActivitySource = new ActivitySource("MyCompany.MyProduct.MyLibrary");

    public static void Main()
    {
        AppDomain.CurrentDomain.UnhandledException += UnhandledExceptionHandler;

        using var tracerProvider = Sdk.CreateTracerProviderBuilder()
            .AddSource("MyCompany.MyProduct.MyLibrary")
            .SetSampler(new AlwaysOnSampler())
            .SetErrorStatusOnException()
            .AddConsoleExporter()
            .Build();

        using (MyActivitySource.StartActivity("Foo"))
        {
            using (MyActivitySource.StartActivity("Bar"))
            {
                throw new Exception("Oops!");
            }
        }
    }

    private static void UnhandledExceptionHandler(object source, UnhandledExceptionEventArgs args)
    {
        var ex = (Exception)args.ExceptionObject;

        var activity = Activity.Current;

        while (activity != null)
        {
            activity.RecordException(ex);
            activity.Dispose();
            activity = activity.Parent;
        }
    }
}

最佳实践

在 OpenTelemetry 跟踪中报告异常时

  1. 始终将状态设置为错误:至少,当发生异常时,将活动状态设置为错误。

  2. 包含异常详细信息:尽可能使用 RecordException() 捕获完整的异常信息。

  3. 处理未处理的异常:考虑设置一个全局的未处理异常处理程序,以确保它们被捕获在跟踪中。

  4. 考虑自动化:使用 SetErrorStatusOnException() SDK 选项来自动化异常状态的设置。

  5. 注意基数:请谨慎将高度可变的异常消息直接包含在状态描述中,因为它们会增加 span 的基数。

了解更多