Cette page guide une première intégration : déclarer les artefacts, configurer l’exporter OTLP, démarrer le runtime auto-configuré, et observer un span dans le Collector. La cible est un projet Java 25 + Maven 4 qui consomme déjà Cassini (JAX-RS) et Vauban (CDI) — l’intégration HTTP et CDI est alors automatique.
Prérequis
-
Java 25 (Temurin) —
sdk envdepuis le repo (.sdkmanrcfourni). -
Maven 3.9.16 — si
mvnéchoue avec « modelVersion 4.1.0 not supported »,sdk use maven 3.9.16. -
Un OpenTelemetry Collector accessible en HTTP (ou un récepteur compatible OTLP/HTTP-JSON). Pour les essais :
docker run --rm -p 4318:4318 otel/opentelemetry-collector:latest.
Déclarer les artefacts
Ajouter au pom.xml consommateur :
<dependency>
<groupId>io.vidocq.humboldt</groupId>
<artifactId>humboldt-runtime</artifactId>
<version>${humboldt.version}</version>
</dependency>
<!-- Optionnel — instrumentation automatique JAX-RS via Cassini -->
<dependency>
<groupId>io.vidocq.humboldt</groupId>
<artifactId>humboldt-rest</artifactId>
<version>${humboldt.version}</version>
</dependency>
<!-- Optionnel — interceptor @WithSpan via CDI Vauban -->
<dependency>
<groupId>io.vidocq.humboldt</groupId>
<artifactId>humboldt-cdi</artifactId>
<version>${humboldt.version}</version>
</dependency>
Le module humboldt-runtime agrège transitivement le SDK trace, metric, log, l’exporter OTLP HTTP, le propagator W3C et l’auto-config par variables d’environnement.
Déclarer le module dans module-info.java
module mon.application {
requires io.vidocq.humboldt.api;
requires io.vidocq.humboldt.runtime;
// Optionnel selon l'intégration choisie
requires io.vidocq.humboldt.cdi;
requires io.vidocq.humboldt.rest;
requires io.opentelemetry.api;
requires io.opentelemetry.context;
exports mon.application;
}
Configurer via variables d’environnement OTel
Humboldt lit les variables d’environnement standard OpenTelemetry (OTEL_*), avec repli sur les system properties équivalentes (otel.*). Voir Référence pour la table exhaustive.
export OTEL_SERVICE_NAME=mon-service
export OTEL_RESOURCE_ATTRIBUTES=service.namespace=billing,deployment.environment=prod
export OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318
export OTEL_TRACES_EXPORTER=otlp
export OTEL_METRICS_EXPORTER=otlp
export OTEL_LOGS_EXPORTER=otlp
export OTEL_TRACES_SAMPLER=parentbased_traceidratio
export OTEL_TRACES_SAMPLER_ARG=1.0
Auto-configurer le runtime
Au démarrage de l’application :
import io.opentelemetry.api.GlobalOpenTelemetry;
import io.vidocq.humboldt.runtime.AutoConfiguredHumboldt;
import io.vidocq.humboldt.runtime.HumboldtAutoConfigure;
public final class Main {
public static void main(String[] args) throws Exception {
try (AutoConfiguredHumboldt sdk = HumboldtAutoConfigure.configure()) {
GlobalOpenTelemetry.set(sdk);
// Démarrer Chappe + Cassini + Vauban — l'instrumentation HTTP
// et l'interceptor @WithSpan utiliseront automatiquement ce SDK.
runApplication();
sdk.flush().join(10, java.util.concurrent.TimeUnit.SECONDS);
}
}
}
AutoConfiguredHumboldt implémente io.opentelemetry.api.OpenTelemetry (interface standard OTel) et AutoCloseable : il expose getTracerProvider(), getMeterProvider(), getLogsBridge(), getPropagators() et coupe proprement les processors batch lors du close().
Émettre une première trace
import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.Tracer;
import io.opentelemetry.context.Scope;
public final class CheckoutService {
private static final Tracer TRACER =
GlobalOpenTelemetry.getTracer("mon.application", "1.0.0");
public Receipt checkout(Cart cart) {
Span span = TRACER.spanBuilder("checkout")
.setAttribute("cart.size", cart.size())
.startSpan();
try (Scope ignored = span.makeCurrent()) {
return doCheckout(cart);
} catch (RuntimeException ex) {
span.recordException(ex);
span.setStatus(io.opentelemetry.api.trace.StatusCode.ERROR);
throw ex;
} finally {
span.end();
}
}
}
Variante CDI (avec humboldt-cdi) :
import io.opentelemetry.instrumentation.annotations.WithSpan;
import jakarta.enterprise.context.ApplicationScoped;
@ApplicationScoped
public class CheckoutService {
@WithSpan("checkout")
public Receipt checkout(Cart cart) {
return doCheckout(cart);
}
}
Lancer un Collector local
docker run --rm \
-p 4318:4318 \
-v $(pwd)/otel-collector.yaml:/etc/otelcol/config.yaml \
otel/opentelemetry-collector:latest
Un fichier otel-collector.yaml minimal :
receivers:
otlp:
protocols:
http:
exporters:
logging:
loglevel: debug
service:
pipelines:
traces: { receivers: [otlp], exporters: [logging] }
metrics: { receivers: [otlp], exporters: [logging] }
logs: { receivers: [otlp], exporters: [logging] }
À l’exécution, les spans checkout apparaîtront dans la console du Collector avec le bon service.name et l’attribut cart.size.
Build et vérification
./mvnw -ntp install -DskipTests
./mvnw test
L’invariant à observer dans les logs : les threads exportateurs sont des virtual threads (HttpClient-virtual, humboldt-batch-worker). Aucune classe io.opentelemetry.sdk. ne doit apparaître dans le classpath applicatif — seul io.opentelemetry.api. est consommé.
Et après ?
-
Pour comprendre le vocabulaire OTel (Span, Resource, Scope, baggage), voir Concepts.
-
Pour les patterns d’instrumentation manuelle, métriques et logs : Cas d’usage.
-
Pour la table complète des clés
OTEL_*/MP_TELEMETRY_*: Référence.