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 shows you how to use Jaeger to report the data of .NET applications. The method also applies 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

Use ASP.NET Core to instrument a .NET application

Use ASP.NET Core to instrument an application by performing the following steps:

Note Download the demo project. Go to the webapi.dotnetcore directory and run the program as instructed in the README.md file.

Jaeger 0.2.2 and NETCore.App 2.1.0 are required to run the demo.

  1. Install NuGet packages.
    // Add the following components: 
    // OpenTracing.Contrib.NetCore: the ASP.NET Core middleware
    // Jaeger: an implementation component of OpenTracing
    // Microsoft.Extensions.Logging.Console: a log component
    
    dotnet add  package OpenTracing.Contrib.NetCore
    dotnet add  package Jaeger
    dotnet add  package Microsoft.Extensions.Logging.Console
  2. Use the Configure method in the Startup.cs file of the project to register the middleware.
    // Register OpenTracing.Contrib.NetCore to instrument the application. 
    services.AddOpenTracing();
    // Filter requests that are collected by HttpClient to obtain requests for using Jaeger to report data. 
    var httpOption = new HttpHandlerDiagnosticOptions();
    httpOption.IgnorePatterns.Add(req => req.RequestUri.AbsolutePath.Contains("/api/traces"));
    services.AddSingleton(Options.Create(httpOption));
  3. Initialize and register Jaeger.
    // Add a Jaeger tracer. 
    services.AddSingleton<ITracer>(serviceProvider =>
    {
        string serviceName = serviceProvider.GetRequiredService<IHostingEnvironment>().ApplicationName;
        ILoggerFactory loggerFactory = serviceProvider.GetRequiredService<ILoggerFactory>();
         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");
    
          // This will log to a default localhost installation of Jaeger.
          var tracer = new Tracer.Builder(serviceName)
              .WithSampler(new ConstSampler(true))
              .WithReporter(new RemoteReporter.Builder().WithSender(senderConfiguration.GetSender()).Build())
               .Build();
    
          // Allows code that can't use DI to also access the tracer.
          GlobalTracer.Register(tracer);
    
          return tracer;
    });

Use gRPC to instrument a .NET application

Use gRPC to instrument an application by performing the following steps:

Note Download the demo project and run the program as instructed in the README.md file.
  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)
                        // 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. 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));

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.

Note Download the demo project. Go to the ManualDemo directory and run the program as instructed in the README.md file.
  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 must configure the 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 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 need to record the previous and next operations of the request, call the AsChildOf method.

    Sample code:

    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 record the return value of a request or check whether an error occurs.
    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 example shows the entire process:
       Client Span                                                Server Span
    ┌──────────────────┐                                       ┌──────────────────┐
    │                  │                                       │                  │
    │   TraceContext   │           Http Request Headers        │   TraceContext   │
    │ ┌──────────────┐ │          ┌───────────────────┐        │ ┌──────────────┐ │
    │ │ TraceId      │ │          │ X-B3-TraceId      │        │ │ TraceId      │ │
    │ │              │ │          │                   │        │ │              │ │
    │ │ ParentSpanId │ │ Inject   │ X-B3-ParentSpanId │Extract │ │ ParentSpanId │ │
    │ │              ├─┼─────────>│                   ├────────┼>│              │ │
    │ │ SpanId       │ │          │ X-B3-SpanId       │        │ │ SpanId       │ │
    │ │              │ │          │                   │        │ │              │ │
    │ │ Sampled      │ │          │ X-B3-Sampled      │        │ │ Sampled      │ │
    │ └──────────────┘ │          └───────────────────┘        │ └──────────────┘ │
    │                  │                                       │                  │
    └──────────────────┘                                       └──────────────────┘
    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);

FAQ

Q: What can I do if no data is reported to the console after I run the demo program?

A: 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");