Search code examples
c#asp.net-coreopen-telemetryjaeger

.Net 7 WebAPI with OpenTelemetry error : "The name 'JaegerExportProtocol' does not exist in the current context"


I am encountering an error in customizing the Jaeger instance in my .NET WebAPI app that uses the OpenTelemetry library for tracing. The error message reads "The name 'JaegerExportProtocol' does not exist in the current context". I am able to obtain traces successfully with the default Jaeger instance. Below is the full error log when I try to customize the instance:

C:\Users\user\..\src\Program.cs(79,26): error CS0029: 
 Cannot implicitly convert type 'string' to 'System.Uri' [C:\Users\user\..\src\CustomerAPI.csproj]
C:\Users\user\..\src\Program.cs(80,26): error CS0103: 
 The name 'JaegerExportProtocol' does not exist in the current context [C:\Users\user\..\src\CustomerAPI.csproj]
The build failed. Fix the build errors and run again.

WORKING

This is the default configuration without any customizations:

// Program.cs

using System.Reflection;
using OpenTelemetry;
using OpenTelemetry.Trace;
using OpenTelemetry.Resources;
using OpenTelemetry.Metrics;
using OpenTelemetry.Instrumentation.Http;
using OpenTelemetry.Exporter.Jaeger;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

var appBuilder = WebApplication.CreateBuilder(args);

appBuilder.Services.AddOpenTelemetry()
    .ConfigureResource(builder => builder.AddService(serviceName: "CustomerAPI"))
    .WithTracing(builder => builder
        .AddAspNetCoreInstrumentation()
        .AddHttpClientInstrumentation()
        .AddConsoleExporter()
        .AddJaegerExporter())
    .WithMetrics(builder => builder.AddConsoleExporter());

appBuilder.Services.AddControllers();
appBuilder.Services.AddHttpClient();
appBuilder.Services.AddEndpointsApiExplorer();
appBuilder.Services.AddSwaggerGen();

var app = appBuilder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();

This development configuration uses a docker instance of Jaeger:

docker run -d --name jaeger -p 16686:16686 -p 6831:6831/udp jaegertracing/all-in-one:1.22

For this configuration, the WebAPI generates traces, and the traces are visible in the corresponding (docker) Jaeger UI.

NOT WORKING

For production, the WebAPI will run in Kubernetes and will use a Jaeger instance running in Kubernetes. The K8s Jaeger instance is deployed successfully and exposed via a LoadBalancer service:

kubectl -n jaeger get services
NAME               TYPE           CLUSTER-IP       EXTERNAL-IP  PORT(S)           AGE
jaeger-agent       ClusterIP      None             <none>       5775/UDP,6831/UDP,6832/UDP,5778/TCP  8d
jaeger-collector   ClusterIP      10.XX.XXX.XX     <none>       14267/TCP,14268/TCP,9411/TCP         8d
jaeger-query       LoadBalancer   10.XXX.XXX.XXX   10.X.XX.XX   80:XXXXX/TCP            8d
zipkin             ClusterIP      None             <none>       9411/TCP                             8d

Because this setup requires explicitly specifying the Jaeger instance, I have tried customizing the values first on the development instance itself as below:

using System.Reflection;
using OpenTelemetry;
using OpenTelemetry.Trace;
using OpenTelemetry.Resources;
using OpenTelemetry.Metrics;
using OpenTelemetry.Instrumentation.Http;
using OpenTelemetry.Exporter.Jaeger;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

var appBuilder = WebApplication.CreateBuilder(args);
var url = "http://localhost:14268";
var endpoint = Convert.ToString(url);

appBuilder.Services.AddOpenTelemetry()
    .ConfigureResource(builder => builder.AddService(serviceName: "CustomerAPI"))
    .WithTracing(builder => builder
        .AddAspNetCoreInstrumentation()
        .AddHttpClientInstrumentation()
        .AddConsoleExporter()
        .AddJaegerExporter(o =>
        {
            o.AgentHost = "localhost";
            o.AgentPort = 6831;
            o.Endpoint = endpoint;
            o.Protocol = JaegerExportProtocol.UdpCompactThrift;
        }))
    .WithMetrics(builder => builder.AddConsoleExporter());

appBuilder.Services.AddControllers();
appBuilder.Services.AddHttpClient();
appBuilder.Services.AddEndpointsApiExplorer();
appBuilder.Services.AddSwaggerGen();

var app = appBuilder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();

This is where I am facing the error "The name 'JaegerExportProtocol' does not exist in the current context". Similarly, it appears I cannot even set the Jaeger host also.

My expectation is that JaegerExportProtocol should be available already via using OpenTelemetry.Exporter.Jaeger;

Both configurations use the same set of libraries which I have installed as below :

<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
    <TargetFramework>net7.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="7.0.2" />
    <PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.5" />
    <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="7.0.0" />
    <PackageReference Include="Microsoft.Extensions.Logging" Version="7.0.0" />
    <PackageReference Include="OpenTelemetry" Version="1.5.0" />
    <PackageReference Include="OpenTelemetry.Exporter.Console" Version="1.5.0" />
    <PackageReference Include="OpenTelemetry.Exporter.Jaeger" Version="1.5.0" />
    <PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.5.0" />
    <PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.5.0-beta.1" />
    <PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.5.0-beta.1" />
    <PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
    <PackageReference Include="System.Net.Http" Version="4.3.4" />
  </ItemGroup>
</Project>

What am I missing ?

Do the options only work with using var tracerProvider = Sdk.CreateTracerProviderBuilder() as used here or I am missing something else obvious ?


Solution

  • My expectation is that JaegerExportProtocol should be available already via using OpenTelemetry.Exporter.Jaeger;

    Not exactly. It's defined in the OpenTelemetry.Exporter namespace, and thus it's available via using OpenTelemetry.Exporter;.