Skip to content

Latest commit

 

History

History
113 lines (91 loc) · 3.24 KB

File metadata and controls

113 lines (91 loc) · 3.24 KB

Exception Handling

User-handled Exception

The term User-handled Exception is used to describe exceptions that are handled by the application.

While using Activity API, the common pattern would be:

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

The above approach could become hard to manage if there are deeply nested Activity objects, or there are activities created in a 3rd party library.

The following configuration will automatically detect exception and set the activity status to Error:

Sdk.CreateTracerProviderBuilder()
    .SetErrorStatusOnException()
    // ...

A complete example can be found here.

Note: this feature is platform dependent as it relies on System.Runtime.InteropServices.Marshal.GetExceptionPointers.

Unhandled Exception

The term Unhandled Exception is used to describe exceptions that are not handled by the application. When an unhandled exception happened, the behavior will depend on the presence of a debugger:

  • If there is no debugger, the exception will normally crash the process or terminate the thread.
  • If a debugger is attached, the debugger will be notified that an unhandled exception happened.
  • In case a postmortem debugger is configured, the postmortem debugger will be activited and normally it will collect a crash dump.

It might be useful to automatically capture the unhandled exceptions, travel through the unfinished activities and export them for troubleshooting. Here goes one possible way of doing this:

WARNING: Use AppDomain.UnhandledException with caution. A throw in the handler puts the process into an unrecoverable state.

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