Search code examples
c#traceopen-telemetry

Activity is null when using Microsoft Hosting Extensions and net472


I am trying to use OpenTelemetry with my net472 app that uses Microsoft.Extensions.Hosting.

I create my host like this:

Host.CreateDefaultBuilder()
                .ConfigureServices((hostContext, services) =>
                {
                    services.AddOpenTelemetry().WithTracing(tracerProviderBuilder =>
                    {
                        tracerProviderBuilder
                            .SetResourceBuilder(ResourceBuilder.CreateDefault().AddService("MySample"))
                            .AddConsoleExporter()
                            .AddSource(serviceName);
                    }).StartWithHost();
                })
                .Build();

If I then try to create a new activity like this, it is null:

var activitySource = new ActivitySource(serviceName);
using var activity = activitySource.StartActivity("Hello");

If instead I register OpenTelemetry like this, it works just fine:


using var tracerProvider = Sdk.CreateTracerProviderBuilder()
                .SetResourceBuilder(ResourceBuilder.CreateDefault().AddService("MySample"))
                .AddSource(serviceName)
                .AddConsoleExporter()
                .Build();

How can I get an ActivitySource that has the configured listener using the first approach of creating a Host?


Solution

  • The solution that worked for me is to resolve the TracerProvider using the ServiceCollection. That way the listener gets subscribed and ActivitySource is able to start activities.

    This is how I register the services.

    Host.CreateDefaultBuilder()
                    .ConfigureServices((hostContext, services) =>
                    {
                        services.AddSingleton(new ActivitySource(serviceName));
                        services.AddOpenTelemetry().WithTracing(tracerProviderBuilder =>
                        {
                            tracerProviderBuilder
                                .SetResourceBuilder(ResourceBuilder.CreateDefault().AddService("MySample"))
                                .AddConsoleExporter()
                                .AddSource(serviceName);
                        });
                    })
                    .Build();
    

    And then when TracerProvider is resolved, it's build using the configured TracerProvider:

    using var tracerProvider = ServiceLocator.GetService<TracerProvider>();
    var activitySource = ServiceLocator.GetService<ActivitySource>();
    
    // Now this doesn't provide a null object
    using var activity = activitySource.StartActivity("Hello");
    

    Just for reference, this is ServiceLocator:

    public static class ServiceLocator
        {
            internal static IHost Host { get; set; }
    
            public static T GetService<T>() where T : class
            {
                return (T)Host.Services.GetService(typeof(T));
            }
        }