All Products
Search
Document Center

Managed Service for OpenTelemetry:Use Jaeger to report the trace data of .NET applications

Last Updated:Feb 22, 2024

After you use Jaeger to instrument a .NET application and report the trace data to Managed Service for OpenTelemetry, Managed Service for OpenTelemetry starts to monitor the .NET application. You can view the monitoring data of the application such as application topology, traces, abnormal transactions, slow transactions, and SQL analysis. This topic describes how to use the OpenTracing, .NET Core, and gRPC components to automatically or manually instrument a .NET application and report the trace data of the .NET application.

Important

The Jaeger client for C# is no longer maintained. We recommend that you use OpenTelemetry SDK for .NET to report trace data. For more information, see Use OpenTelemetry to report the trace data of .NET applications.

Prerequisites

To obtain an endpoint of Jaeger or Zipkin, perform the following steps:

  1. Log on to the Managed Service for OpenTelemetry console.

  2. In the left-side navigation pane, click Cluster Configurations. Then, click the Access point information tab.

  3. In the top navigation bar, select a region. In the Cluster Information section, turn on Show Token.

  4. In the Client section, click Jaeger or Zipkin.

    Obtain an endpoint of Jaeger or Zipkin in the Related Information column of the table in the lower part.

    Jaeger/Zipkin接入点信息

    Note

    If your application is deployed in an Alibaba Cloud production environment, use a VPC endpoint. Otherwise, use a public endpoint. Generally, use the endpoint of v2 for Zipkin. Use the endpoint of v1 only if you know Zipkin well.

Background information

Jaeger is an open source distributed tracing system, which is created and used by Uber. Jaeger is compatible with the OpenTracing API and is a member of the Cloud Native Computing Foundation (CNCF). Jaeger gathers real-time monitoring data from various heterogeneous systems.

The OpenTracing community provides multiple components that support the following .NET frameworks:

How is data reported?

  • The following figure shows how to report data without using the Jaeger agent. 不通过Jaeger Agent而直接上报

  • The following figure shows how to report data by using the Jaeger agent.

    通过Jaeger Agent上报数据

Sample code

Download the sample code from dotnet-demo.

Instrument a .NET 6.0 application

Use an OpenTracing component to automatically instrument a .NET application

To run the sample code, the following requirements must be met:

  • Jaeger 1.0.2 is installed.

  • .NET 6.0 is installed.

  1. In the dotnet-demo/net6.0/Shared/JaegerServiceCollectionExtensions.cs file of the sample project, specify the Jaeger endpoint that is used to report trace data and the name of the application of which you want to report the trace data to initialize and register the ITracer object.

    public static class JaegerServiceCollectionExtensions
    {
        // Specify the Jaeger endpoint. For more information about how to obtain the Jaeger endpoint, see the "Prerequisites" section of this topic.
        private static readonly Uri _jaegerUri = new Uri("http://tracing-analysis-dc-sz.aliyuncs.com/adapt_your_token/api/traces");
    
        public static IServiceCollection AddJaeger(this IServiceCollection services)
        {
            if (services == null)
                throw new ArgumentNullException(nameof(services));
    
            services.AddSingleton<ITracer>(serviceProvider =>
            {
                // Specify the application name.
                string serviceName = Assembly.GetEntryAssembly().GetName().Name;
    
                ILoggerFactory loggerFactory = serviceProvider.GetRequiredService<ILoggerFactory>();
    
                ISampler sampler = new ConstSampler(sample: true);
    
                IReporter reporter = new RemoteReporter.Builder()
                    .WithSender(new HttpSender.Builder(_jaegerUri.ToString()).Build())
                    .Build();
    
                ITracer tracer = new Tracer.Builder(serviceName)
                    .WithLoggerFactory(loggerFactory)
                    .WithSampler(sampler)
                    .WithReporter(reporter)
                    .Build();
    
                GlobalTracer.Register(tracer);
    
                return tracer;
            });
    
            // Prevent endless loops when OpenTracing is tracking HTTP requests to Jaeger.
            services.Configure<HttpHandlerDiagnosticOptions>(options =>
            {
                options.IgnorePatterns.Add(request => _jaegerUri.IsBaseOf(request.RequestUri));
            });
    
            return services;
        }
    }
  2. Go to the dotnet-demo/net6.0/CustomersApi directory of the sample project and run the following command:

    dotnet run --framework:net6.0
  3. Start your application and access the following URL:

    http://localhost:5001/health
  4. On the Applications page of the Managed Service for OpenTelemetry console, search for the application by application name to view the reported data.

Instrument a .NET Core 3.1 application

To run the sample code, the following requirements must be met:

  • Jaeger 1.0.2 is installed.

  • .NET Core 3.1 is installed.

Use ASP.NET Core to automatically instrument a .NET application

  1. In the dotnet-demo/netcoreapp3.1/Shared/JaegerServiceCollectionExtensions.cs file of the sample project, specify the Jaeger endpoint that is used to report trace data and the name of the application of which you want to report the trace data to initialize and register the ITracer object.

    public static class JaegerServiceCollectionExtensions
    {
        // Specify the Jaeger endpoint. For more information about how to obtain the Jaeger endpoint, see the "Prerequisites" section of this topic.
        private static readonly Uri _jaegerUri = new Uri("http://tracing-analysis-dc-sz.aliyuncs.com/adapt_your_token/api/traces");
    
        public static IServiceCollection AddJaeger(this IServiceCollection services)
        {
            if (services == null)
                throw new ArgumentNullException(nameof(services));
    
            services.AddSingleton<ITracer>(serviceProvider =>
            {
                // Specify the application name.
                string serviceName = Assembly.GetEntryAssembly().GetName().Name;
    
                ILoggerFactory loggerFactory = serviceProvider.GetRequiredService<ILoggerFactory>();
    
                ISampler sampler = new ConstSampler(sample: true);
    
                IReporter reporter = new RemoteReporter.Builder()
                    .WithSender(new HttpSender.Builder(_jaegerUri.ToString()).Build())
                    .Build();
    
                ITracer tracer = new Tracer.Builder(serviceName)
                    .WithLoggerFactory(loggerFactory)
                    .WithSampler(sampler)
                    .WithReporter(reporter)
                    .Build();
    
                GlobalTracer.Register(tracer);
    
                return tracer;
            });
    
            // Prevent endless loops when OpenTracing is tracking HTTP requests to Jaeger.
            services.Configure<HttpHandlerDiagnosticOptions>(options =>
            {
                options.IgnorePatterns.Add(request => _jaegerUri.IsBaseOf(request.RequestUri));
            });
    
            return services;
        }
    }
  2. Go to the dotnet-demo/netcoreapp3.1/Shared directory of the sample project and run the following command:

    // Add the ASP.NET Core 3.1 middleware.
    dotnet add  package OpenTracing.Contrib.NetCore
  3. Go to the dotnet-demo/netcoreapp3.1/CustomersApi directory of the sample project and run the following commands:

    // Add the ASP.NET Core 3.1 middleware.
    dotnet add  package OpenTracing.Contrib.NetCore
    // Run the demo program.
    dotnet run --framework:netcoreapp3.1
  4. Start your application and access the following URL:

    http://localhost:5001/health
  5. On the Applications page of the Managed Service for OpenTelemetry console, search for the application by application name to view the reported data.

Use gRPC to automatically instrument a .NET application

  1. Install the NuGet packages.

    // Add the following components: 
    // OpenTracing.Contrib.Grpc: the gRPC middleware.
    // Jaeger: an implementation component of OpenTracing.
    // Microsoft.Extensions.Logging.Console: a log component.
    
    dotnet add  package OpenTracing.Contrib.grpc
    dotnet add  package Jaeger
  2. Initialize the ITracer object.

    public static Tracer InitTracer(string serviceName, ILoggerFactory loggerFactory)
            {
                Configuration.SamplerConfiguration samplerConfiguration = new Configuration.SamplerConfiguration(loggerFactory)
                    .WithType(ConstSampler.Type)
                    .WithParam(1);
                Configuration.SenderConfiguration senderConfiguration = new Configuration.SenderConfiguration(loggerFactory)
                        // Specify the Jaeger endpoint. For more information about how to obtain the Jaeger endpoint, see the "Prerequisites" section of this topic.
                       .WithEndpoint("http://tracing-analysis-dc-sz.aliyuncs.com/adapt_your_token/api/traces");
                Configuration.ReporterConfiguration reporterConfiguration = new Configuration.ReporterConfiguration(loggerFactory)
                    .WithSender(senderConfiguration);
    
                return (Tracer)new Configuration(serviceName, loggerFactory)
                    .WithSampler(samplerConfiguration)
                    .WithReporter(reporterConfiguration)
                    .GetTracer();
            }
  3. Add instrumentation on the server. Build the ServerTracingInterceptor object and bind the object to the application.

    ILoggerFactory loggerFactory = new LoggerFactory().AddConsole();
    ITracer tracer = TracingHelper.InitTracer("dotnetGrpcServer", loggerFactory);
    ServerTracingInterceptor tracingInterceptor = new ServerTracingInterceptor(tracer);
    Server server = new Server
     {
        Services = { Greeter.BindService(new GreeterImpl()).Intercept(tracingInterceptor) },
         Ports = { new ServerPort("localhost", Port, ServerCredentials.Insecure) }
     };
  4. Add instrumentation on the client. Build the ServerTracingInterceptor object and bind the object to the specified channel.

    ILoggerFactory loggerFactory = new LoggerFactory().AddConsole();
    ITracer tracer = TracingHelper.InitTracer("dotnetGrpcClient", loggerFactory);
    ClientTracingInterceptor tracingInterceptor = new ClientTracingInterceptor(tracer);
    Channel channel = new Channel("127.0.0.1:50051", ChannelCredentials.Insecure);
    
    var client = new Greeter.GreeterClient(channel.Intercept(tracingInterceptor));
  5. Go to the dotnet-demo/netcoreapp3.1/GreeterServer directory of the sample project and run the following command on the terminal to start the gRPC server:

    dotnet run --framework:netcoreapp3.1
  6. Go to the dotnet-demo/netcoreapp3.1/GreeterClient directory of the sample project and run the following command on another terminal to start the gRPC client:

    dotnet run --framework:netcoreapp3.1

    If the message Greeting: Hello you is returned, the server and client are connected. You can view the trace data of the sample application that are reported by the dotnetGrpcServer and dotnetGrpcClient in the console.

Manually instrument a .NET application

You can instrument a .NET application by using existing plug-ins. Alternatively, you can use Jaeger to manually instrument a .NET application and report the trace data of the application to the Managed Service for OpenTelemetry console.

  1. Install the NuGet packages.

    // Jaeger: an implementation component of OpenTracing.
    // Microsoft.Extensions.Logging.Console: a log component.
    
    dotnet add  package Microsoft.Extensions.Logging.Console
    dotnet add  package Jaeger
  2. Build an ITracer object. The ITracer object is an object defined by OpenTracing. You can use Jaeger to build this object. When you build this object, you can configure the object to specify the Jaeger endpoint and sample rate.

    public static ITracer InitTracer(string serviceName, ILoggerFactory loggerFactory)
     {
        Configuration.SamplerConfiguration samplerConfiguration = new Configuration.SamplerConfiguration(loggerFactory)
              .WithType(ConstSampler.Type)
              .WithParam(1);
        Configuration.SenderConfiguration senderConfiguration = new Configuration.SenderConfiguration(loggerFactory)
               // Obtain the Jaeger endpoint in the Managed Service for OpenTelemetry console. 
              .WithEndpoint("http://tracing-analysis-dc-sz.aliyuncs.com/adapt_your_token/api/traces");
    
       Configuration.ReporterConfiguration reporterConfiguration = new Configuration.ReporterConfiguration(loggerFactory)
              .WithSender(senderConfiguration);
    
       return (Tracer)new Configuration(serviceName, loggerFactory)
              .WithSampler(samplerConfiguration)
              .WithReporter(reporterConfiguration)
            .GetTracer();
    }
  3. Register the ITracer object with GlobalTracer to facilitate code calling.

    GlobalTracer.Register(InitTracer("dotnetManualDemo", loggerFactory ));
  4. Record the request data.

    ITracer tracer = GlobalTracer.Instance;
    ISpan span = tracer.BuildSpan("parentSpan").WithTag("mytag","parentSapn").Start();
    tracer.ScopeManager.Activate(span, false);
    // ... do something
    span.Finish();
    Note

    You can run the preceding code to record the root operation of a request. If you want to record the previous and next operations of the request, call the AsChildOf method.

    The following sample code provides an example:

    ITracer tracer = GlobalTracer.Instance;
    ISpan parentSpan = tracer.ActiveSpan;
    ISpan childSpan =tracer.BuildSpan("childSpan").AsChildOf(parentSpan).WithTag("mytag", "spanSecond").Start();
    tracer.ScopeManager.Activate(childSpan, false);
    // ... do something
    childSpan.Finish();
  5. Optional: To troubleshoot issues in an efficient manner, you can add custom tags to a record. For example, you can add custom tags to a request to indicate whether an error occurs or describe the returned values of the request.

    tracer.activeSpan().setTag("http.status_code", "200");
  6. In a distributed system, remote procedure call (RPC) requests are sent together with trace data. Trace data contains the values of the TraceId, ParentSpanId, SpanId, and Sampled parameters. You can call the Extract or Inject method to pass through trace data in HTTP request headers. The following figure shows the entire process.

    流程图

    1. Call the Inject method on the client to specify the context information.

      Tracer.Inject(span.Context, BuiltinFormats.HttpHeaders, new HttpHeadersInjectAdapter(request.Headers));
    2. Call the Extract method on the server to extract the context information.

      ISpanContext extractedSpanContext = _tracer.Extract(BuiltinFormats.HttpHeaders, new RequestHeadersExtractAdapter(request.Headers));
      ISpan childSpan = _tracer.BuildSpan(operationName).AsChildOf(extractedSpanContext);
  7. Go to the dotnet-demo/netcoreapp3.1/ManualDemo directory of the project and run the following command. The sample program starts to report trace data.

    dotnet run --framework:netcoreapp3.1

    In the Managed Service for OpenTelemetry console, you can view the reported trace data of the sample application dotnetManualDemo that is manually instrumented.

FAQ

Q1: What do I do if no trace data is reported to the Managed Service for OpenTelemetry console after I run the demo program?

A1: Check whether the endpoint in senderConfiguration is valid.

Configuration.SenderConfiguration senderConfiguration = new Configuration.SenderConfiguration(loggerFactory)
           // Obtain the Jaeger endpoint in the Managed Service for OpenTelemetry console. 
          .WithEndpoint("http://tracing-analysis-dc-sz.aliyuncs.com/adapt_your_token/api/traces");

Q2: How do I specify the sample rate?

A2: For more information, visit the jaeger-client-csharp page on GitHub.