Before you can view the trace data of your application in the Tracing Analysis console, you must use a client to report the trace data to Tracing Analysis. This topic describes how to use Jaeger to report the data of .NET applications. The methods also apply to C# applications.

Prerequisites

  1. Log on to the Tracing Analysis console. In the left-side navigation pane, click Cluster Configurations.
  2. On the Cluster Configurations tab, click the Access point information tab. Then, turn on Show Token for the Cluster Information parameter.
  3. Set the Client parameter to the client that you want to use to collect trace data.
  4. In the Related Information column of the table in the lower part, click the copy icon next to the endpoint that you want to use.

Tracing Analysis Endpoint Section

Note: If you deploy your application in an Alibaba Cloud production environment, select a Virtual Private Cloud (VPC) endpoint. Otherwise, select 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 at Uber. Jaeger is compatible with the OpenTracing API and is a member of the Cloud Native Computing Foundation (CNCF). Jaeger is used to aggregate real-time monitoring data that is collected from multiple heterogeneous systems.

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

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

Report Tracing Data Directly

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

Report Tracing Data By Jaeger Agent

Sample code

Download the sample code from dotnet-demo.

Instrument a .NET application in .NET 6.0

Use an OpenTracing component to instrument a .NET application

Requirements for the runtime environment of the sample code:
  • Jaeger 1.0.2
  • .NET 6.0
  1. Go to the dotnet-demo/net6.0/Shared directory of the sample project. In the JaegerServiceCollectionExtensions.cs file, specify the Jaeger endpoint and the name of the service whose data you want to report. This is used to initialize and register an ITracer object.
    public static class JaegerServiceCollectionExtensions
    {
        // Specify the Jaeger endpoint. For more information about how to obtain the Jaeger endpoint, see Prerequisites.
        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 name of your service.
                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 then run the following command:
    dotnet run --framework:net6.0
  3. Start your service and access the following URL:
    http://localhost:5001/health
  4. In the Tracing Analysis console, search for the application by service name and then view the data that is reported by the application.

Instrument a .NET application in .NET Core 3.1

Requirements for the runtime environment of the sample code:
  • Jaeger 1.0.2
  • .NET Core 3.1

Use ASP.NET Core to instrument a .NET application

  1. Go to the dotnet-demo/netcoreapp3.1/Shared directory of the sample project. In the JaegerServiceCollectionExtensions.cs file, specify the Jaeger endpoint and the name of the service whose data you want to report. This is used to initialize and register an ITracer object.
    public static class JaegerServiceCollectionExtensions
    {
        // Specify the Jaeger endpoint. For more information about how to obtain the Jaeger endpoint, see Prerequisites.
        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 name of your service.
                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 then run the following command:
    // Add the ASP.NET Core middleware.
    dotnet add  package OpenTracing.Contrib.NetCore
  3. Go to the dotnet-demo/netcoreapp3.1/CustomersApi directory of the sample project, and then run the following commands:
    // Add the ASP.NET Core middleware.
    dotnet add  package OpenTracing.Contrib.NetCore
    // Run the demo program.
    dotnet run --framework:netcoreapp3.1
  4. Start your service and access the following URL:
    http://localhost:5001/health
  5. In the Tracing Analysis console, search for the application by service name and then view the data that is reported by the application.

Use gRPC to instrument a .NET application

  1. Install 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. Create an 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 Prerequisites.
                       .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. Create the ServerTracingInterceptor object that is used to add instrumentation and bind the ServerTracingInterceptor object to the specified service.
    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. Create the ClientTracingInterceptor object that is used to add instrumentation and bind the ClientTracingInterceptor 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 then run the following command on a 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 then run the following command on another terminal to start the gRPC client:
    dotnet run --framework:netcoreapp3.1

    If this terminal returns Greeting: Hello you, the communication between the server and the client is successful. In the Tracing Analysis console, you can view the data that is reported by the dotnetGrpcServer and dotnetGrpcClient applications.

Manually instrument a .NET application

The preceding sections describe how to use existing components to instrument .NET applications. You can also manually instrument .NET applications. In this case, you can use Jaeger to report the data of the applications to the Tracing Analysis console.

  1. Install 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. Create an ITracer object. The ITracer object is an object defined by OpenTracing. You can use Jaeger to create this object. When you create this object, you can configure the object to specify the Jaeger endpoint and set the 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 Tracing Analysis 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: Add custom tags to a span for quick troubleshooting. For example, you can add a custom tag to check whether an error occurs or to record the return value of a 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 specify data in HTTP request headers. The following figure shows the entire process.
    Flowchart
    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 sample project, and then run the following command. The demo program reports data.
    dotnet run --framework:netcoreapp3.1

    In the Tracing Analysis console, you can view the data that is reported by the dotnetManualDemo application.

FAQ

Q1: What can I do if no data is reported to the 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 Tracing Analysis console. 
          .WithEndpoint("http://tracing-analysis-dc-sz.aliyuncs.com/adapt_your_token/api/traces");

Q2: How do I set the sample rate?

A2: For more information, visit the Sampling page on GitHub.