C
C#8mo ago
Hejle

Manual setup of OpenTelemetry with/without Microsoft.Extensions.Hosting in a Console application

After seeing Aspire I have decided to see how OpenTelemetry, and i first created a console application following the docs on https://opentelemetry.io/docs/instrumentation/net/manual/. However, when I tried to move it into an easier setup using the extensionsmethod available in OpenTelemetry.Extensions.Hosting i could not get it to work. I think I might just misunderstand something about how it works. So I have this working console application, which outputs the Actitivy in the console:
public static class Program
{
public const string SERVICE_NAME = "MyService";
public const string SERVICE_VERSION = "1.0.0";

public static async Task Main(string[] args)
{
var serviceCollection = new ServiceCollection();

serviceCollection.AddSingleton(new ActivitySource(SERVICE_NAME));
serviceCollection.AddSingleton<TestLogic>();

var tracerProvider = Sdk.CreateTracerProviderBuilder().AddSource(SERVICE_NAME)
.ConfigureResource(resource => resource.AddService(serviceName: SERVICE_NAME, serviceVersion: SERVICE_VERSION))
.AddConsoleExporter()
.Build();
serviceCollection.AddSingleton(tracerProvider);

var services = serviceCollection.BuildServiceProvider();

var helloWorld = await services.GetRequiredService<TestLogic>().HelloWorldMethod();
Console.WriteLine(helloWorld);
Console.WriteLine("Program ended");
}
}

public class TestLogic(ActivitySource activitySource)
{
private readonly ActivitySource _activitySource = activitySource;

public async Task<string> HelloWorldMethod()
{
using var activity = _activitySource.StartActivity("HelloWorldMethod");
await Task.Delay(1000);
return "Hello World";
}
}
public static class Program
{
public const string SERVICE_NAME = "MyService";
public const string SERVICE_VERSION = "1.0.0";

public static async Task Main(string[] args)
{
var serviceCollection = new ServiceCollection();

serviceCollection.AddSingleton(new ActivitySource(SERVICE_NAME));
serviceCollection.AddSingleton<TestLogic>();

var tracerProvider = Sdk.CreateTracerProviderBuilder().AddSource(SERVICE_NAME)
.ConfigureResource(resource => resource.AddService(serviceName: SERVICE_NAME, serviceVersion: SERVICE_VERSION))
.AddConsoleExporter()
.Build();
serviceCollection.AddSingleton(tracerProvider);

var services = serviceCollection.BuildServiceProvider();

var helloWorld = await services.GetRequiredService<TestLogic>().HelloWorldMethod();
Console.WriteLine(helloWorld);
Console.WriteLine("Program ended");
}
}

public class TestLogic(ActivitySource activitySource)
{
private readonly ActivitySource _activitySource = activitySource;

public async Task<string> HelloWorldMethod()
{
using var activity = _activitySource.StartActivity("HelloWorldMethod");
await Task.Delay(1000);
return "Hello World";
}
}
I then tried using the Generic Host builder and it does not write the activity to the console:
public static class Program
{
public const string SERVICE_NAME = "MyService";
public const string SERVICE_VERSION = "1.0.0";

public static async Task Main(string[] args)
{
var builder = Host.CreateApplicationBuilder();
builder.Services.AddSingleton<TestLogic>();
builder.Services.AddOpenTelemetry()
.ConfigureResource(resourceBuilder => resourceBuilder.AddService(serviceName: SERVICE_NAME, serviceVersion: SERVICE_VERSION))
.WithTracing(tracerProviderBuilder => tracerProviderBuilder.AddConsoleExporter());
builder.Services.AddSingleton(new ActivitySource(SERVICE_NAME));

var host = builder.Build();
await host.StartAsync(); //Used as OpenTelemetry adds the HostedService "TelemetryHostedService"

var helloWorld = await host.Services.GetRequiredService<TestLogic>().HelloWorldMethod();
Console.WriteLine(helloWorld);
Console.WriteLine("Program ended");
await host.StopAsync();
}
}
public class TestLogic(ActivitySource activitySource)
{
private readonly ActivitySource _activitySource = activitySource;

public async Task<string> HelloWorldMethod()
{
using var activity = _activitySource.StartActivity("HelloWorldMethod");
await Task.Delay(1000);
return "Hello World";
}
}
public static class Program
{
public const string SERVICE_NAME = "MyService";
public const string SERVICE_VERSION = "1.0.0";

public static async Task Main(string[] args)
{
var builder = Host.CreateApplicationBuilder();
builder.Services.AddSingleton<TestLogic>();
builder.Services.AddOpenTelemetry()
.ConfigureResource(resourceBuilder => resourceBuilder.AddService(serviceName: SERVICE_NAME, serviceVersion: SERVICE_VERSION))
.WithTracing(tracerProviderBuilder => tracerProviderBuilder.AddConsoleExporter());
builder.Services.AddSingleton(new ActivitySource(SERVICE_NAME));

var host = builder.Build();
await host.StartAsync(); //Used as OpenTelemetry adds the HostedService "TelemetryHostedService"

var helloWorld = await host.Services.GetRequiredService<TestLogic>().HelloWorldMethod();
Console.WriteLine(helloWorld);
Console.WriteLine("Program ended");
await host.StopAsync();
}
}
public class TestLogic(ActivitySource activitySource)
{
private readonly ActivitySource _activitySource = activitySource;

public async Task<string> HelloWorldMethod()
{
using var activity = _activitySource.StartActivity("HelloWorldMethod");
await Task.Delay(1000);
return "Hello World";
}
}
Does anyone know why I don't see the Activity in the console output? Or maybe know how I should set the Generic Host example up?
1 Reply
Hejle
Hejle8mo ago
Note: It does not seem to matter if I StartAsync or not, but I feel like that could be related to the issue I have. I am also using the following imports: <PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" /> <PackageReference Include="OpenTelemetry" Version="1.7.0-alpha.1" /> <PackageReference Include="OpenTelemetry.Exporter.Console" Version="1.7.0-alpha.1" /> <PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.7.0-alpha.1" /> Alright, I actually found the solution myself catthinking I had forgotten to register my actitivy-source with the AddSource-method. So it should have looked like this:
builder.Services.AddOpenTelemetry()
.ConfigureResource(resourceBuilder =>
resourceBuilder.AddService(serviceName: SERVICE_NAME, serviceVersion: SERVICE_VERSION))
.WithTracing(tracerProviderBuilder =>
tracerProviderBuilder
.AddSource(SERVICE_NAME) //Forgot this ;(
.AddConsoleExporter());
builder.Services.AddOpenTelemetry()
.ConfigureResource(resourceBuilder =>
resourceBuilder.AddService(serviceName: SERVICE_NAME, serviceVersion: SERVICE_VERSION))
.WithTracing(tracerProviderBuilder =>
tracerProviderBuilder
.AddSource(SERVICE_NAME) //Forgot this ;(
.AddConsoleExporter());
And It does apear to be neccesary to call StartAsync for OTL to listen to the Acitivy. But if anyone has any suggestions to things I can improve / look into I would of course not mind that :)