All Products
Search
Document Center

Application Real-Time Monitoring Service:Report .NET application data through Zipkin

Last Updated:Mar 11, 2026

Zipkin is an open source distributed tracing system originally developed by Twitter. It aggregates real-time monitoring data from multiple heterogeneous systems. You can use the zipkin4net library to instrument .NET applications and report trace data to Application Real-Time Monitoring Service (ARMS) Tracing Analysis.

This topic covers three instrumentation methods for .NET and C# applications.

Choose an instrumentation method

Select the method that matches your application framework.

MethodBest forRequired NuGet packages
ASP.NET CoreCross-platform web apps built on ASP.NET Corezipkin4net.middleware.aspnetcore, zipkin4net
OWIN.NET Framework web apps using OWIN middlewarezipkin4net.middleware.aspnetcore, zipkin4net
ManualBackground jobs, message consumers, or custom protocols that need fine-grained span controlzipkin4net

Prerequisites

Before you begin, make sure that you have:

  • An Alibaba Cloud account with ARMS activated

  • A .NET development environment

  • The Zipkin endpoint for your ARMS Tracing Analysis instance (see Get a Zipkin endpoint)

Get a Zipkin endpoint

  1. Log on to the Tracing Analysis 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.

  5. In the Related Information column, copy the endpoint URL.

Endpoint of Jaeger or Zipkin
Note

If your application runs in an Alibaba Cloud production environment, use a VPC access point. Otherwise, use a public endpoint. Use the v2 endpoint unless you have a specific reason to use v1.

Instrument with ASP.NET Core

Note

Download the complete demo project and follow the instructions in its README.md.

Step 1: Install NuGet packages

dotnet add package zipkin4net.middleware.aspnetcore
dotnet add package zipkin4net
PackagePurpose
zipkin4netCore tracing library. Creates spans, manages sampling, and reports trace data to a Zipkin-compatible backend.
zipkin4net.middleware.aspnetcoreASP.NET Core middleware. Automatically creates a server span for each incoming HTTP request.

Step 2: Register and start the tracer

Add the following code to your application startup logic to configure zipkin4net and connect it to your ARMS Tracing Analysis endpoint.

lifetime.ApplicationStarted.Register(() => {
    TraceManager.SamplingRate = 1.0f;
    var logger = new TracingLogger(loggerFactory, "zipkin4net");

    // Replace with your Zipkin endpoint from the Tracing Analysis console.
    // Do not append /api/v2/spans to the URL.
    var httpSender = new HttpZipkinSender("<your-zipkin-endpoint>", "application/json");

    var tracer = new ZipkinTracer(httpSender, new JSONSpanSerializer());
    TraceManager.RegisterTracer(tracer);
    TraceManager.Start(logger);
});
lifetime.ApplicationStopped.Register(() => TraceManager.Stop());
app.UseTracing(applicationName);

Replace the following placeholder with your actual value:

PlaceholderDescriptionExample
<your-zipkin-endpoint>Zipkin endpoint from the Tracing Analysis consolehttp://tracing-analysis-dc-hz.aliyuncs.com/adapt_your_token

Step 3: Trace outgoing HTTP requests

Add TracingHandler to your HttpClient pipeline so that outgoing HTTP calls are automatically traced and correlated with the parent span.

public override void ConfigureServices(IServiceCollection services)
{
    services.AddHttpClient("Tracer").AddHttpMessageHandler(provider =>
        TracingHandler.WithoutInnerHandler(provider.GetService<IConfiguration>()["applicationName"]));
}

Instrument with OWIN

Open Web Interface for .NET (OWIN) is a middleware specification for .NET Framework web applications.

Note

Download the complete demo project and follow the instructions in its README.md.

Step 1: Install NuGet packages

dotnet add package zipkin4net.middleware.aspnetcore
dotnet add package zipkin4net
PackagePurpose
zipkin4netCore tracing library.
zipkin4net.middleware.aspnetcoreASP.NET Core middleware. Automatically creates a server span for each incoming HTTP request.

Step 2: Register and start the tracer

// Configure tracing.
TraceManager.SamplingRate = 1.0f;
var logger = new ConsoleLogger();

// Replace with your Zipkin endpoint from the Tracing Analysis console.
// Do not append /api/v2/spans to the URL.
var httpSender = new HttpZipkinSender("<your-zipkin-endpoint>", "application/json");

var tracer = new ZipkinTracer(httpSender, new JSONSpanSerializer());
TraceManager.RegisterTracer(tracer);
TraceManager.Start(logger);

// Stop TraceManager when the application shuts down.
var properties = new AppProperties(appBuilder.Properties);
var token = properties.OnAppDisposing;

if (token != CancellationToken.None)
{
    token.Register(() =>
    {
        TraceManager.Stop();
    });
}

// Register OWIN middleware.
appBuilder.UseZipkinTracer(System.Configuration.ConfigurationManager.AppSettings["applicationName"]);

Step 3: Trace outgoing HTTP requests

Wrap your HttpClient with TracingHandler to propagate trace context across service boundaries.

using (var httpClient = new HttpClient(new TracingHandler(applicationName)))
{
    var response = await httpClient.GetAsync(callServiceUrl);
    var content = await response.Content.ReadAsStringAsync();

    await context.Response.WriteAsync(content);
}

Instrument manually

Use manual instrumentation for full control over span creation -- for example, tracing background jobs, message consumers, or custom protocols.

Note

Download the complete demo project and follow the instructions in its README.md.

Step 1: Install the NuGet package

Only the core tracing library is required for manual instrumentation.

dotnet add package zipkin4net

Step 2: Register and start the tracer

TraceManager.SamplingRate = 1.0f;
var logger = new ConsoleLogger();

// Replace with your Zipkin endpoint from the Tracing Analysis console.
// Do not append /api/v2/spans to the URL.
var httpSender = new HttpZipkinSender("<your-zipkin-endpoint>", "application/json");

var tracer = new ZipkinTracer(httpSender, new JSONSpanSerializer());
TraceManager.RegisterTracer(tracer);
TraceManager.Start(logger);

Step 3: Create and record spans

Create a root span for each request or operation, then record its lifecycle events.

var trace = Trace.Create();

Trace.Current = trace;
trace.Record(Annotations.ClientSend());

trace.Record(Annotations.Rpc("client"));
trace.Record(Annotations.Tag("mytag", "spanFrist"));
trace.Record(Annotations.ServiceName("dotnetManual"));
// ... perform your operation here
testCall();

trace.Record(Annotations.ClientRecv());

To record a child span (for example, a downstream call within the same request), call Child() on the current trace:

var trace = Trace.Current.Child();
Trace.Current = trace;
trace.Record(Annotations.ServerRecv());
trace.Record(Annotations.Rpc("server"));
trace.Record(Annotations.Tag("mytag", "spanSecond"));
trace.Record(Annotations.ServiceName("dotnetManual"));
// ... perform your operation here
trace.Record(Annotations.ServerSend());

(Optional) Step 4: Add custom tags

Attach custom tags to spans for easier troubleshooting. For example, record the HTTP status code or flag errors.

tracer.activeSpan().setTag("http.status_code", "200");

Step 5: Propagate trace context across services

In a distributed system, trace context travels with each RPC request so that spans from different services are correlated into a single trace. The zipkin4net library uses B3 propagation, passing four values through HTTP headers:

Trace fieldHTTP header
TraceIdX-B3-TraceId
ParentSpanIdX-B3-ParentSpanId
SpanIdX-B3-SpanId
SampledX-B3-Sampled
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      │ │
│ └──────────────┘ │          └───────────────────┘        │ └──────────────┘ │
│                  │                                       │                  │
└──────────────────┘                                       └──────────────────┘

Client side -- inject trace context into outgoing request headers:

_injector.Inject(clientTrace.Trace.CurrentSpan, request.Headers);

Server side -- extract trace context from incoming request headers:

var traceContext = traceExtractor.Extract(context.Request.Headers);
var trace = traceContext == null ? Trace.Create() : Trace.CreateFromId(traceContext);

When no trace context exists in the incoming headers, a new root trace is created. Otherwise, the existing trace continues.

FAQ

Q: Why does no data appear in the Tracing Analysis console after I run the demo?

A: Verify that the Zipkin endpoint URL in your HttpZipkinSender configuration is correct. Copy the endpoint directly from the Tracing Analysis console. The URL must not include /api/v2/spans.

// Correct: use the base endpoint without /api/v2/spans
var httpSender = new HttpZipkinSender("http://tracing-analysis-dc-hz.aliyuncs.com/adapt_your_token", "application/json");