All Products
Search
Document Center

Managed Service for OpenTelemetry:Report Java application data with Jaeger

Last Updated:Mar 11, 2026

Jaeger provides distributed tracing for Java applications running across multiple services. After you instrument your application and report trace data to Managed Service for OpenTelemetry, the console displays application topology, traces, abnormal and slow transactions, and SQL analysis.

This guide covers three instrumentation approaches:

  • Manual instrumentation -- Full control over span creation and context propagation

  • Spring Cloud auto-instrumentation -- Automatic tracing for Spring-based components

  • gRPC auto-instrumentation -- Automatic tracing for gRPC server and client calls

Important

We recommend that you connect your application to Managed Service for OpenTelemetry by using OpenTelemetry Protocol (OTLP), which provides more features, more advanced tracing capabilities, and the best user experience. For more information, see Preparations.

Jaeger and supported frameworks

Jaeger is a CNCF-hosted, open source distributed tracing system compatible with the OpenTracing API. It collects real-time monitoring data from heterogeneous systems.

The OpenTracing community provides instrumentation components for these Java frameworks:

CategoryFrameworks
HTTP clientsApache HttpClient, OkHttp
DataElasticsearch, JDBC, Mongo, Redis
MessagingKafka, Memcached
SpringSpring Boot, Spring Cloud

Data reporting architecture

Jaeger supports two reporting modes:

  • Direct reporting -- The application sends trace data straight to the Managed Service for OpenTelemetry backend, without a local agent.

    image

  • Agent-based reporting -- The application sends trace data to a local Jaeger agent, which forwards it to the backend.

    image

Get a reporting endpoint

Before you begin, obtain a reporting endpoint from the Managed Service for OpenTelemetry console. Choose the tab that matches your console version.

New console

  1. Log on to the Managed Service for OpenTelemetry console. In the left-side navigation pane, click Integration Center.

  2. On the Integration Center page, click the Jaeger card in the Open Source Frameworks section.

  3. In the Jaeger panel, click the Start Integration tab and select the region where you want to report data.

    Note

    Resources are automatically initialized the first time you access a region.

  4. Set Connection Type and Export Protocol, then copy the endpoint.

    ParameterRecommended valueWhen to use
    Connection TypeAlibaba Cloud VPC NetworkYour service runs on Alibaba Cloud in the selected region
    Connection TypePublic NetworkYour service runs outside Alibaba Cloud or in a different region
    Export ProtocolgRPCAll Jaeger integrations

    New console endpoint configuration

Old console

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

  2. In the left-side navigation pane, click Cluster Configurations. On the page that appears, 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. Set Client to Jaeger and copy the endpoint from the Related Information column.

    Note

    Use a VPC endpoint if your application runs in an Alibaba Cloud production environment. Otherwise, use a public endpoint.

    Old console endpoint configuration

Instrument a Java application manually

Use the Jaeger client library to create spans and propagate trace context manually. This approach gives you full control over what gets traced.

Note

A complete working example is available in the demo project under the manualDemo directory. Follow README.md to run it.

Step 1: Add the Jaeger client dependency

Add the following dependency to your pom.xml:

<dependency>
    <groupId>io.jaegertracing</groupId>
    <artifactId>jaeger-client</artifactId>
    <version>0.31.0</version>
</dependency>

Step 2: Initialize the tracer

Create a tracer that manages span lifecycle and context propagation. The configuration specifies the reporting endpoint, sampling rate, and service identity.

Note

Replace <endpoint> with the endpoint obtained in the "Get a reporting endpoint" section.

// Replace manualDemo with your application name.
io.jaegertracing.Configuration config = new io.jaegertracing.Configuration("manualDemo");
io.jaegertracing.Configuration.SenderConfiguration sender = new io.jaegertracing.Configuration.SenderConfiguration();
// Replace <endpoint> with the endpoint obtained in "Get a reporting endpoint".
sender.withEndpoint("<endpoint>");
config.withSampler(new io.jaegertracing.Configuration.SamplerConfiguration().withType("const").withParam(1));
config.withReporter(new io.jaegertracing.Configuration.ReporterConfiguration().withSender(sender).withMaxQueueSize(10000));
// Set resource tags such as the application version and deployment environment.
Map<String, String> map = new HashMap<>();
map.put("service.version", "1.0.0");
map.put("deployment.environment", "test");
config.withTracerTags(map);
GlobalTracer.register(config.getTracer());
PlaceholderDescriptionExample
<endpoint>Reporting endpoint from the consolehttp://tracing-analysis-dc-hz.aliyuncs.com/...
manualDemoYour application nameorder-service

Sampling configuration:

Sampler typeParamBehavior
const1Sample all traces (development, debugging)
const0Sample no traces
probabilistic0.1Sample 10% of traces (production)

Step 3: Record requests with spans

Create a span to trace a request. Each span captures the operation name, timing, and custom tags:

Tracer tracer = GlobalTracer.get();
// Create a span.
Span span = tracer.buildSpan("parentSpan").withTag("myTag", "spanFirst").start();
tracer.scopeManager().activate(span, false);
tracer.activeSpan().setTag("methodName", "testTracing");
// Business logic
secondBiz();
span.finish();

Step 4 (optional): Create child spans

To trace sub-operations within a request, create child spans that reference the parent span:

Tracer tracer = GlobalTracer.get();
Span parentspan = tracer.activeSpan();
Tracer.SpanBuilder spanBuilder = tracer.buildSpan("childSpan").withTag("myTag", "spanSecond");
if (parentspan != null) {
    spanBuilder.asChildOf(parentspan).start();
}
Span childSpan = spanBuilder.start();
Scope scope = tracer.scopeManager().activate(childSpan); // Activate at request start.
// Business logic. Call buildSpan multiple times as needed.
childSpan.finish();
tracer.activeSpan().setTag("methodName", "testCall");

// Close the scope at request end.
scope.close();

Step 5 (optional): Add custom tags

Add custom tags to spans for easier troubleshooting. For example, record error states or return values:

tracer.activeSpan().setTag("methodName", "testCall");

Step 6: Propagate trace context across services

In a distributed system, Remote Procedure Call (RPC) requests carry trace context -- including TraceId, ParentSpanId, SpanId, and Sampled -- in HTTP headers. Use the Inject and Extract methods to pass this context between services.

1.jpg

On the client, inject the span context into the outgoing request:

private void attachTraceInfo(Tracer tracer, Span span, final Request request) {
    tracer.inject(span.context(), Format.Builtin.TEXT_MAP, new TextMap() {
        @Override
        public void put(String key, String value) {
            request.setHeader(key, value);
        }
        @Override
        public Iterator<Map.Entry<String, String>> iterator() {
            throw new UnsupportedOperationException("TextMapInjectAdapter should only be used with Tracer.inject()");
        }
    });
}

On the server, extract the span context from the incoming request:

protected Span extractTraceInfo(Request request, Tracer tracer) {
    Tracer.SpanBuilder spanBuilder = tracer.buildSpan("/api/xtrace/test03");
    try {
        SpanContext spanContext = tracer.extract(Format.Builtin.TEXT_MAP, new TextMapExtractAdapter(request.getAttachments()));
        if (spanContext != null) {
            spanBuilder.asChildOf(spanContext);
        }
    } catch (Exception e) {
        spanBuilder.withTag("Error", "extract from request fail, error msg:" + e.getMessage());
    }
    return spanBuilder.start();
}

Instrument with Spring Cloud

Spring Cloud auto-instrumentation traces a wide range of components without manual span creation.

Note

A complete working example is available in the demo project under the springMvcDemo/webmvc4-boot directory. Follow README.md to run it.

Supported components:

CategoryComponents
Async@Async, @Scheduled, Executors
HTTP clientsFeign, HystrixFeign, Spring Web (RestControllers, RestTemplates, WebAsyncTask)
ResilienceHystrix
DataJDBC, Mongo, Redis
MessagingJMS, RabbitMQ, Spring Messaging, WebSocket STOMP
ReactiveRxJava
LoggingStandard Logging (adds logs to the current span)
GatewayZuul

Step 1: Add dependencies

Add the following dependencies to your pom.xml:

<dependency>
   <groupId>io.opentracing.contrib</groupId>
  <artifactId>opentracing-spring-cloud-starter</artifactId>
  <version>0.5.8</version>
</dependency>
<dependency>
  <groupId>io.jaegertracing</groupId>
  <artifactId>jaeger-client</artifactId>
  <version>1.4.0</version>
</dependency>

Step 2: Register the tracer bean

Register an OpenTracing Tracer bean in your Spring configuration. After registration, Spring Cloud auto-instrumentation handles span creation and context propagation for all supported components.

Note

Replace <endpoint> with the endpoint obtained in the "Get a reporting endpoint" section.

@Bean
public io.opentracing.Tracer tracer() {
    io.jaegertracing.Configuration config = new io.jaegertracing.Configuration("springFrontend");
    io.jaegertracing.Configuration.SenderConfiguration sender = new io.jaegertracing.Configuration.SenderConfiguration();
    sender.withEndpoint("<endpoint>");
    config.withSampler(new io.jaegertracing.Configuration.SamplerConfiguration().withType("const").withParam(1));
    config.withReporter(new io.jaegertracing.Configuration.ReporterConfiguration().withSender(sender).withMaxQueueSize(10000));
    return config.getTracer();
}

Instrument with gRPC

gRPC instrumentation uses interceptors to trace server and client calls automatically.

Note

A complete working example is available in the demo project under the grpcDemo directory. Follow README.md to run it.

Step 1: Add the gRPC tracing dependency

Add the following dependency to your pom.xml:

<dependency>
    <groupId>io.opentracing.contrib</groupId>
    <artifactId>opentracing-grpc</artifactId>
    <version>0.2.3</version>
</dependency>

Step 2: Add a tracing interceptor to the server

Initialize the tracer, create a ServerTracingInterceptor, and attach it to the gRPC server:

import io.opentracing.Tracer;

public class YourServer {

    private int port;
    private Server server;
    private final Tracer tracer;

    private void start() throws IOException {
        ServerTracingInterceptor tracingInterceptor = new ServerTracingInterceptor(this.tracer);

        // If GlobalTracer is used:
        // ServerTracingInterceptor tracingInterceptor = new ServerTracingInterceptor();

        server = ServerBuilder.forPort(port)
            .addService(tracingInterceptor.intercept(someServiceDef))
            .build()
            .start();
    }
}

Step 3: Add a tracing interceptor to the client

Initialize the tracer, create a ClientTracingInterceptor, and attach it to the gRPC channel:

import io.opentracing.Tracer;

public class YourClient {

    private final ManagedChannel channel;
    private final GreeterGrpc.GreeterBlockingStub blockingStub;
    private final Tracer tracer;

    public YourClient(String host, int port) {

        channel = ManagedChannelBuilder.forAddress(host, port)
            .usePlaintext(true)
            .build();

        ClientTracingInterceptor tracingInterceptor = new ClientTracingInterceptor(this.tracer);

        // If GlobalTracer is used:
        // ClientTracingInterceptor tracingInterceptor = new ClientTracingInterceptor();

        blockingStub = GreeterGrpc.newBlockingStub(tracingInterceptor.intercept(channel));
    }
}

Verify the integration

After starting the instrumented application:

  1. Send a few requests to your application endpoints.

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

  3. Open the Applications page and confirm your application appears in the list.

  4. Click your application name, then go to the Traces page to view reported trace data.

If your application appears and traces are visible, the integration is working correctly.

Troubleshooting

No data appears in the console

Debug the io.jaegertracing.thrift.internal.senders.HttpSender.send(Process process, List<Span> spans) method and check the return value.

SymptomCauseSolution
HTTP 403 responseInvalid endpointCopy the correct endpoint from the console. Make sure you selected the right region and client type (Jaeger).
Connection timeoutEndpoint does not match your network environmentUse a VPC endpoint if your application runs on Alibaba Cloud. Use a public endpoint if your application runs outside Alibaba Cloud.
No spans generatedSampler is misconfiguredSet the sampler type to const with param 1 to sample all traces during debugging.
Application does not appear on the Applications pageTracer not registered or endpoint unreachableVerify that GlobalTracer.register() is called and the endpoint URL is reachable from your application host.

Enable debug logging

To see whether spans are generated and sent, enable Jaeger client debug logging by adding the following JVM argument:

-Dorg.slf4j.simpleLogger.log.io.jaegertracing=debug

Check the application logs for span submission results. If spans appear in logs but not in the console, the endpoint URL or network configuration is likely incorrect.