Managed Service for OpenTelemetry collecte les données de trace des applications Java et fournit une topologie applicative, des traces, ainsi que des analyses des transactions anormales ou lentes et des requêtes SQL. Trois approches d'instrumentation sont disponibles, allant de la configuration sans code via un agent au contrôle complet par SDK.
| Approche | Effort | Cas d'usage |
|---|---|---|
| Agent Java OpenTelemetry (recommandé) | Minimal — attachez un JAR, aucune modification de code nécessaire | Convient à la plupart des applications. Commencez ici. |
| SDK OpenTelemetry pour Java | Modéré — rédaction de code d'instrumentation requise | Recommandé pour les spans personnalisés, les attributs spécifiques ou les frameworks non pris en charge |
| Combinaison Agent + SDK | Modéré — l'agent gère les bases, le SDK ajoute des spans personnalisés | Idéal pour allier couverture automatique et instrumentation ciblée |
Code d'exemple
Clonez ou parcourez le projet d'exemple pour obtenir une référence fonctionnelle :
git clone https://github.com/alibabacloud-observability/java-demo.git
cd java-demo/opentelemetry-demo
Méthode 1 : Instrumentation automatique avec l'agent Java OpenTelemetry
L'agent Java OpenTelemetry s'attache à votre JVM au démarrage et instrumente des centaines de bibliothèques et de frameworks sans nécessiter de modifications du code. Cette approche constitue le point de départ recommandé pour la majorité des applications.
Étape 1 : Télécharger l'agent
Téléchargez le JAR de l'agent le plus récent depuis GitHub Releases :
# wget
wget -O opentelemetry-javaagent.jar \
https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/latest/download/opentelemetry-javaagent.jar
# or curl
curl -Lo opentelemetry-javaagent.jar \
https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/latest/download/opentelemetry-javaagent.jar
Étape 2 : Configurer les paramètres JVM et démarrer l'application
Ajoutez l'indicateur -javaagent avant l'argument -jar. Choisissez le protocole HTTP ou gRPC selon vos besoins.
HTTP
java -javaagent:/path/to/opentelemetry-javaagent.jar \
-Dotel.resource.attributes=service.name=<your-service-name>,service.version=<your-version>,deployment.environment=<your-env> \
-Dotel.exporter.otlp.protocol=http/protobuf \
-Dotel.exporter.otlp.traces.endpoint=<traces-endpoint> \
-Dotel.exporter.otlp.metrics.endpoint=<metrics-endpoint> \
-Dotel.logs.exporter=none \
-jar /path/to/your/app.jar
Remplacez les espaces réservés par vos valeurs réelles :
| Espace réservé | Description | Exemple |
|---|---|---|
<your-service-name> |
Nom identifiant votre application | order-service |
<your-version> |
Version de l'application | 1.0.0 |
<your-env> |
Environnement de déploiement | production |
<traces-endpoint> |
Endpoint de trace indiqué dans la section Prérequis | http://tracing-analysis-dc-hz-internal.aliyuncs.com/adapt_ggxw4l****@7323a5caae3****_ggxw4l****@53df7ad2afe****/api/otlp/traces |
<metrics-endpoint> |
Endpoint de métriques indiqué dans la section Prérequis | http://tracing-analysis-dc-hz-internal.aliyuncs.com/adapt_ggxw4l****@7323a5caae3****_ggxw4l****@53df7ad2afe****/api/otlp/metrics |
Exemple :
java -javaagent:/path/to/opentelemetry-javaagent.jar \
-Dotel.resource.attributes=service.name=order-service,service.version=1.0.0,deployment.environment=production \
-Dotel.exporter.otlp.protocol=http/protobuf \
-Dotel.exporter.otlp.traces.endpoint=http://tracing-analysis-dc-hz-internal.aliyuncs.com/adapt_ggxw4l****@7323a5caae3****_ggxw4l****@53df7ad2afe****/api/otlp/traces \
-Dotel.exporter.otlp.metrics.endpoint=http://tracing-analysis-dc-hz-internal.aliyuncs.com/adapt_ggxw4l****@7323a5caae3****_ggxw4l****@53df7ad2afe****/api/otlp/metrics \
-Dotel.logs.exporter=none \
-jar /path/to/your/app.jar
gRPC
java -javaagent:/path/to/opentelemetry-javaagent.jar \
-Dotel.resource.attributes=service.name=<your-service-name>,service.version=<your-version>,deployment.environment=<your-env> \
-Dotel.exporter.otlp.protocol=grpc \
-Dotel.exporter.otlp.headers=Authentication=<token> \
-Dotel.exporter.otlp.endpoint=<endpoint> \
-Dotel.logs.exporter=none \
-jar /path/to/your/app.jar
Remplacez les espaces réservés par vos valeurs réelles :
| Espace réservé | Description | Exemple |
|---|---|---|
<token> |
Jeton d'authentification indiqué dans la section Prérequis | ggxw4l****@7323a5caae3****_ggxw4l****@53df7ad2afe**** |
<endpoint> |
Endpoint gRPC indiqué dans la section Prérequis | http://tracing-analysis-dc-hz-internal.aliyuncs.com:8090 |
Exemple :
java -javaagent:/path/to/opentelemetry-javaagent.jar \
-Dotel.resource.attributes=service.name=order-service,service.version=1.0.0,deployment.environment=production \
-Dotel.exporter.otlp.protocol=grpc \
-Dotel.exporter.otlp.headers=Authentication=ggxw4l****@7323a5caae3****_ggxw4l****@53df7ad2afe**** \
-Dotel.exporter.otlp.endpoint=http://tracing-analysis-dc-hz-internal.aliyuncs.com:8090 \
-Dotel.logs.exporter=none \
-jar /path/to/your/app.jar
Pour transférer les données de trace via un OpenTelemetry Collector, supprimez-Dotel.exporter.otlp.headers=Authentication=<token>et définissez<endpoint>sur l'adresse du Collector située sur votre machine locale.
Étape 3 : Vérifier les données de trace
Ouvrez la console Managed Service for OpenTelemetry.
Dans la page Applications, cliquez sur le nom de votre application.
Vérifiez que les traces apparaissent bien sur la page de détails de l'application.
Résolution des problèmes :
Si aucune donnée ne s'affiche, vérifiez que l'endpoint et le jeton sont corrects.
-
Activez la journalisation de débogage pour inspecter le comportement de l'agent :
-Dotel.javaagent.debug=true -
Désactivez temporairement l'agent sans le retirer de la commande de démarrage :
-Dotel.javaagent.enabled=false
Méthode 2 : Instrumentation manuelle avec le SDK OpenTelemetry pour Java
Utilisez le SDK OpenTelemetry pour Java lorsque vous avez besoin d'un contrôle total sur les opérations générant des spans, sur leurs attributs, ou lorsque l'agent automatique ne prend pas en charge votre framework.
Étape 1 : Ajouter les dépendances Maven
Ajoutez les éléments suivants à votre fichier pom.xml :
<dependencies>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-api</artifactId>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-sdk-trace</artifactId>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-exporter-otlp</artifactId>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-sdk</artifactId>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-semconv</artifactId>
<version>1.30.0-alpha</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-bom</artifactId>
<version>1.30.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
Étape 2 : Initialiser le tracer
Créez une classe utilitaire configurant l'exportateur, les attributs de ressource et le tracer. Sélectionnez le protocole correspondant à votre environnement.
HTTP
import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.trace.Tracer;
import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator;
import io.opentelemetry.context.propagation.ContextPropagators;
import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter;
import io.opentelemetry.sdk.OpenTelemetrySdk;
import io.opentelemetry.sdk.resources.Resource;
import io.opentelemetry.sdk.trace.SdkTracerProvider;
import io.opentelemetry.sdk.trace.export.BatchSpanProcessor;
import io.opentelemetry.semconv.resource.attributes.ResourceAttributes;
public class OpenTelemetrySupport {
static {
// Define the resource that describes this service
Resource resource = Resource.getDefault()
.merge(Resource.create(Attributes.of(
ResourceAttributes.SERVICE_NAME, "<your-service-name>",
ResourceAttributes.SERVICE_VERSION, "<your-version>",
ResourceAttributes.DEPLOYMENT_ENVIRONMENT, "<your-env>",
ResourceAttributes.HOST_NAME, "<your-host-name>"
)));
// Build a tracer provider with the OTLP HTTP exporter
SdkTracerProvider sdkTracerProvider = SdkTracerProvider.builder()
.addSpanProcessor(BatchSpanProcessor.builder(OtlpHttpSpanExporter.builder()
.setEndpoint("<endpoint>") // Trace endpoint from the Prerequisites section
.build()).build())
.setResource(resource)
.build();
// Register the SDK globally
OpenTelemetry openTelemetry = OpenTelemetrySdk.builder()
.setTracerProvider(sdkTracerProvider)
.setPropagators(ContextPropagators.create(W3CTraceContextPropagator.getInstance()))
.buildAndRegisterGlobal();
tracer = openTelemetry.getTracer("OpenTelemetry Tracer", "1.0.0");
}
private static Tracer tracer;
public static Tracer getTracer() {
return tracer;
}
}
gRPC
import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.trace.Tracer;
import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator;
import io.opentelemetry.context.propagation.ContextPropagators;
import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter;
import io.opentelemetry.sdk.OpenTelemetrySdk;
import io.opentelemetry.sdk.resources.Resource;
import io.opentelemetry.sdk.trace.SdkTracerProvider;
import io.opentelemetry.sdk.trace.export.BatchSpanProcessor;
import io.opentelemetry.semconv.resource.attributes.ResourceAttributes;
public class OpenTelemetrySupport {
static {
// Define the resource that describes this service
Resource resource = Resource.getDefault()
.merge(Resource.create(Attributes.of(
ResourceAttributes.SERVICE_NAME, "<your-service-name>",
ResourceAttributes.SERVICE_VERSION, "<your-version>",
ResourceAttributes.DEPLOYMENT_ENVIRONMENT, "<your-env>",
ResourceAttributes.HOST_NAME, "<your-host-name>"
)));
// Build a tracer provider with the OTLP gRPC exporter
SdkTracerProvider sdkTracerProvider = SdkTracerProvider.builder()
.addSpanProcessor(BatchSpanProcessor.builder(OtlpGrpcSpanExporter.builder()
.setEndpoint("<endpoint>") // gRPC endpoint from the Prerequisites section
.addHeader("Authentication", "<token>") // Authentication token from the Prerequisites section
.build()).build())
.setResource(resource)
.build();
// Register the SDK globally
OpenTelemetry openTelemetry = OpenTelemetrySdk.builder()
.setTracerProvider(sdkTracerProvider)
.setPropagators(ContextPropagators.create(W3CTraceContextPropagator.getInstance()))
.buildAndRegisterGlobal();
tracer = openTelemetry.getTracer("OpenTelemetry Tracer", "1.0.0");
}
private static Tracer tracer;
public static Tracer getTracer() {
return tracer;
}
}
Étape 3 : Créer des spans
Utilisez le tracer pour créer des spans parents et enfants. Chaque span capture une unité de travail, accompagnée de ses attributs et de son statut d'erreur éventuel.
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.StatusCode;
import io.opentelemetry.context.Scope;
public class Main {
public static void parentMethod() {
// Start a parent span
Span span = OpenTelemetrySupport.getTracer().spanBuilder("parent span").startSpan();
try (Scope scope = span.makeCurrent()) {
span.setAttribute("good", "job");
childMethod();
} catch (Throwable t) {
span.setStatus(StatusCode.ERROR, "handle parent span error");
} finally {
span.end();
}
}
public static void childMethod() {
// Start a child span -- automatically linked to the parent through Context
Span span = OpenTelemetrySupport.getTracer().spanBuilder("child span").startSpan();
try (Scope scope = span.makeCurrent()) {
span.setAttribute("hello", "world");
} catch (Throwable t) {
span.setStatus(StatusCode.ERROR, "handle child span error");
} finally {
span.end();
}
}
public static void main(String[] args) {
parentMethod();
}
}
Étape 4 : Démarrer l'application et vérifier
Démarrez l'application, puis ouvrez la console Managed Service for OpenTelemetry. Dans la page Applications, cliquez sur le nom de votre application et confirmez l'apparition des traces.
Méthode 3 : Combiner l'agent Java avec le SDK
Utilisez l'agent pour une couverture automatique étendue et le SDK pour des spans personnalisés ciblés. L'agent configure automatiquement le SDK au démarrage grâce à la dépendance opentelemetry-sdk-extension-autoconfigure. La classe utilitaire OpenTelemetrySupport de la Méthode 2 n'est donc pas nécessaire.
Étape 1 : Télécharger l'agent
Téléchargez l'agent Java OpenTelemetry comme décrit dans l'Étape 1 de la Méthode 1.
Étape 2 : Ajouter les dépendances Maven
En complément des dépendances listées dans l'Étape 1 de la Méthode 2, ajoutez les éléments suivants :
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-extension-annotations</artifactId>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-sdk-extension-autoconfigure</artifactId>
<version>1.23.0-alpha</version>
</dependency>
La dépendance opentelemetry-sdk-extension-autoconfigure transfère automatiquement les paramètres de l'agent vers le SDK. Vous n'avez donc pas besoin de configurer l'exportateur ou les attributs de ressource dans le code.
Étape 3 : Obtenir un tracer
Puisque l'agent gère l'initialisation du SDK, récupérez directement le tracer global :
OpenTelemetry openTelemetry = GlobalOpenTelemetry.get();
Tracer tracer = openTelemetry.getTracer("instrumentation-library-name", "1.0.0");
Étape 4 : Ajouter une instrumentation personnalisée
Trois techniques permettent d'ajouter une instrumentation par-dessus l'agent :
Technique 1 : Ajouter des attributs à un span créé automatiquement
Appelez Span.current() à l'intérieur d'une méthode déjà instrumentée pour y attacher des attributs métier :
@RequestMapping("/async")
public String async() {
Span span = Span.current();
span.setAttribute("user.id", "123456");
userService.async();
child("vip");
return "async";
}
Technique 2 : Utiliser @WithSpan pour une instrumentation basée sur les annotations
Annotez une méthode avec @WithSpan pour créer automatiquement un span. Utilisez @SpanAttribute pour enregistrer les paramètres :
@WithSpan
private void child(@SpanAttribute("user.type") String userType) {
System.out.println(userType);
biz();
}
Technique 3 : Créer manuellement des spans avec un tracer
Pour un contrôle total, construisez des spans via l'API du tracer. Cet exemple montre également comment propager le contexte dans un thread asynchrone :
private void biz() {
Tracer tracer = GlobalOpenTelemetry.get().getTracer("tracer");
Span span = tracer.spanBuilder("biz (manual)")
.setParent(Context.current().with(Span.current())) // optional -- set automatically
.startSpan();
try (Scope scope = span.makeCurrent()) {
span.setAttribute("biz-id", "111");
// Propagate context into an async task
es.submit(() -> {
Span asyncSpan = tracer.spanBuilder("async")
.setParent(Context.current().with(span))
.startSpan();
try {
Thread.sleep(1000L); // simulate async work
} catch (Throwable e) {
// handle error
}
asyncSpan.end();
});
Thread.sleep(1000); // simulate business logic
} catch (Throwable t) {
span.setStatus(StatusCode.ERROR, "handle biz error");
} finally {
span.end();
}
}
Code complet du contrôleur et du service
Contrôleur (com.alibaba.arms.brightroar.console.controller) :
package com.alibaba.arms.brightroar.console.controller;
import com.alibaba.arms.brightroar.console.service.UserService;
import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.StatusCode;
import io.opentelemetry.api.trace.Tracer;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.Scope;
import io.opentelemetry.extension.annotations.SpanAttribute;
import io.opentelemetry.extension.annotations.WithSpan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
private ExecutorService es = Executors.newFixedThreadPool(5);
// Technique 1: Add attributes to an auto-created span
@RequestMapping("/async")
public String async() {
System.out.println("UserController.async -- " + Thread.currentThread().getId());
Span span = Span.current();
span.setAttribute("user.id", "123456");
userService.async();
child("vip");
return "async";
}
// Technique 2: Annotation-based instrumentation
@WithSpan
private void child(@SpanAttribute("user.type") String userType) {
System.out.println(userType);
biz();
}
// Technique 3: Manual span creation
private void biz() {
Tracer tracer = GlobalOpenTelemetry.get().getTracer("tracer");
Span span = tracer.spanBuilder("biz (manual)")
.setParent(Context.current().with(Span.current()))
.startSpan();
try (Scope scope = span.makeCurrent()) {
span.setAttribute("biz-id", "111");
es.submit(new Runnable() {
@Override
public void run() {
Span asyncSpan = tracer.spanBuilder("async")
.setParent(Context.current().with(span))
.startSpan();
try {
Thread.sleep(1000L); // simulate async work
} catch (Throwable e) {
}
asyncSpan.end();
}
});
Thread.sleep(1000); // simulate business logic
System.out.println("biz done");
OpenTelemetry openTelemetry = GlobalOpenTelemetry.get();
openTelemetry.getPropagators();
} catch (Throwable t) {
span.setStatus(StatusCode.ERROR, "handle biz error");
} finally {
span.end();
}
}
}
Service (com.alibaba.arms.brightroar.console.service) :
package com.alibaba.arms.brightroar.console.service;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
@Service
public class UserService {
@Async
public void async() {
System.out.println("UserService.async -- " + Thread.currentThread().getId());
System.out.println("my name is async");
System.out.println("UserService.async -- ");
}
}
Étape 5 : Configurer les paramètres JVM et démarrer l'application
java -javaagent:/path/to/opentelemetry-javaagent.jar \
-Dotel.resource.attributes=service.name=<your-service-name> \
-Dotel.exporter.otlp.headers=Authentication=<token> \
-Dotel.exporter.otlp.endpoint=<endpoint> \
-jar /path/to/your/app.jar
Exemple :
java -javaagent:/path/to/opentelemetry-javaagent.jar \
-Dotel.resource.attributes=service.name=ot-java-agent-sample \
-Dotel.exporter.otlp.headers=Authentication=b590xxxxuqs@3a75d95xxxxx9b_b59xxxxguqs@53dxxxx2afe8301 \
-Dotel.exporter.otlp.endpoint=http://tracing-analysis-dc-bj:8090 \
-jar /path/to/your/app.jar
Pour transférer les données de trace via un OpenTelemetry Collector, supprimez-Dotel.exporter.otlp.headers=Authentication=<token>et définissez<endpoint>sur l'adresse du Collector située sur votre machine locale.
Ouvrez la console Managed Service for OpenTelemetry. Dans la page Applications, cliquez sur le nom de votre application et confirmez l'apparition des traces.
Frameworks Java pris en charge
L'agent Java OpenTelemetry instrumente automatiquement les frameworks suivants. Pour consulter la liste complète et actualisée, reportez-vous à la documentation Bibliothèques, frameworks, serveurs d'applications et JVM pris en charge.