Trazas y otra telemetría con OpenTelemetry
Esta página explica cómo implementar logging, tracing y métricas usando OpenTelemetry.
Habilitar OpenTelemetry
Habilitar OpenTelemetry para una aplicación consiste en los siguientes pasos:
-
Añadir las dependencias de Lightbend Telemetry ("Cinnamon"):
<dependency> <groupId>com.lightbend.cinnamon</groupId> <artifactId>cinnamon-opentracing-zipkin</artifactId> </dependency> <dependency> <groupId>com.lightbend.cinnamon</groupId> <artifactId>cinnamon-opentracing_${scala.version}</artifactId> </dependency> <dependency> <groupId>com.lightbend.cinnamon</groupId> <artifactId>cinnamon-agent</artifactId> </dependency>A partir de IPF 2024.2.0, se requiere una solución temporal para evitar conflictos entre versiones de librerías. Por favor añade lo siguiente al bloque
<dependencyManagement>de tupom.xmlraíz para usar OTel y OpenTracing juntos:<dependency> <groupId>io.opentracing</groupId> <artifactId>opentracing-util</artifactId> <version>0.33.0</version> </dependency> <dependency> <groupId>io.zipkin.reporter2</groupId> <artifactId>zipkin-sender-urlconnection</artifactId> <version>2.16.3</version> </dependency> <dependency> <groupId>io.zipkin.reporter2</groupId> <artifactId>zipkin-reporter</artifactId> <version>2.16.3</version> </dependency> <dependency> <groupId>io.zipkin.zipkin2</groupId> <artifactId>zipkin</artifactId> <version>2.23.2</version> </dependency> -
Habilitar el Java Agent de Lightbend Telemetry, p. ej. en la sección
CMDde la imagen Docker:exec java -javaagent:/${project.artifactId}/lib/com.lightbend.cinnamon-cinnamon-agent-${cinnamon.version}.jarNOTA: Esto ya se hace como parte del Icon Project Archetype, por lo que normalmente este paso no es necesario
-
Habilitar los exportadores relevantes de métricas o eventos según la documentación de Lightbend Telemetry para métricas, eventos, logs.
-
Para habilitar tracing, asegúrate de que el OpenTelemetry Collector está configurado para recibir spans formateados como OpenTracing, y sigue las instrucciones en Zipkin reporter.
Si todo funcionó correctamente, deberías ver algunas trazas en tu herramienta preferida (por ejemplo Jaeger, Zipkin, Grafana Tempo):

Propagación de contexto
También es posible configurar IPF para simplemente propagar los encabezados relevantes sin crear información de tracing adicional. Por defecto, Lightbend Telemetry soporta reenviar los siguientes tipos de contexto:
| Tipo | Documentación para habilitar |
|---|---|
W3C Trace Context (por defecto para OpenTelemetry) |
|
B3 (por Zipkin) |
|
AWS X-Ray |
Limitaciones
El tracing y la telemetría en general suelen ser de "código cero": simplemente habilitando el agente de Cinnamon se habilita la introspección a nivel de código para añadir los detalles de tracing relevantes.
Sin embargo, Lightbend Telemetry actualmente solo soporta Kafka y HTTP. Si, en cualquier frontera, los mensajes van por JMS (o cualquier otro protocolo que no sea Kafka o HTTP), el contexto de traza se perderá y se requerirá intervención para conectar las trazas.
Para conectar las trazas, sigue las instrucciones en Inject and Extract para extraer el SpanContext al enviar e inyectarlo al recibir mensajes. Un ejemplo usando un CorrelationService personalizado podría ser:
import com.iconsolutions.ipf.core.shared.correlation.CorrelationService;
import lombok.AllArgsConstructor;
@AllArgsConstructor
public class OpenTracingAwareCorrelationService implements CorrelationService {
private final CorrelationService delegate;
@Override
public CompletionStage<Correlation> save(Correlation correlation) {
var map = new HashMap<String, String>();
GlobalTracer.get().inject(ActiveSpan.getContext(), Format.Builtin.TEXT_MAP, new TextMapAdapter(map));
correlation.getSupportingContext().mergedWith(SupportingContext.of(map));
return delegate.save(correlation);
}
@Override
public CompletionStage<Optional<Correlation>> findByCorrelationId(CorrelationId correlationId) {
return delegate.findByCorrelationId(correlationId)
.thenApply(maybeCorrelation -> {
maybeCorrelation.ifPresent(it -> GlobalTracer.get().extract(Format.Builtin.TEXT_MAP, new TextMapAdapter(it.getSupportingContext().getMetaData().getValues())));
return maybeCorrelation;
});
}
}
Esta implementación de CorrelationService guardará el Span activo de OpenTracing en el almacén de correlaciones cuando sea posible y lo extraerá cuando sea posible.
Ten en cuenta que esto requerirá introducir una dependencia en OpenTracing, que es una librería deprecada a favor de OpenTelemetry. Esta página se actualizará cuando Lightbend Telemetry se actualice para soportar tracing nativo de OpenTelemetry.
Soporte de Lightbend Telemetry ("Cinnamon") para tracing
Lightbend Telemetry ("Cinnamon") actualmente no soporta el estándar OpenTelemetry para trazas y solo implementa la API legada OpenTracing. Sin embargo, el collector de OpenTelemetry y AWS X-Ray soportan el formato legado Zipkin de OpenTracing. Por tanto, no deberías necesitar hacer nada más para que las trazas funcionen en OpenTelemetry.
No debería ser necesaria configuración adicional aparte de añadir las librerías en el paso 1, pero haz clic aquí para ver qué configuración se puede ajustar en la librería.
Combinando OpenTelemetry y OpenTracing
Puede que tengas el requisito de propagar el contexto de traza entre OpenTelemetry y OpenTracing. Por ejemplo, si aplica la siguiente combinación:
-
Estás usando el OpenTelemetry Java Agent
-
Estás iniciando un flujo desde un
@RestController,@KafkaListener,@JmsListenerde Spring, o similar -
Estás recibiendo un contexto de traza en forma de cabeceras desde un sistema o broker ascendente
Por defecto, la traza se romperá entre el lado de Spring y el lado de IPF, porque Lightbend Telemetry (y por extensión Akka e IPF) usa la API de OpenTracing, y no será consciente del contexto de traza de OTel que fue poblado por Spring. El contexto necesita propagarse manualmente de OTel a OpenTracing; sigue estos pasos para configurar tu aplicación y conectar el contexto de traza entre OTel y OpenTracing:
-
Añade primero el agente de Lightbend Telemetry y en segundo lugar el agente de OTel:
-javaagent:/path/to/cinnamon-agent-2.20.1.jar -javaagent:/path/to/opentelemetry-javaagent.jar -
Deshabilita la instrumentación de OTel para Akka y Akka HTTP con propiedades del sistema (o variables de entorno, o entradas de archivo de configuración):
otel.instrumentation.akka-http.enabled=false otel.instrumentation.akka.enabled=false -
Asegúrate de que los valores de
otel.service.nameycinnamon.applicationsean los mismos, para que las trazas parezcan provenir de la misma aplicación IPF (a menos que quieras que sean diferentes)Valores por defecto:
-
cinnamon.application: nombre cualificado del punto donde se inició la JVM en minúsculas, p. ej.com.mycorp.application -
otel.service.name:unknown_service:java
-
-
Al pasar del consumidor de mensajes de Spring o del controlador REST, inyecta el contexto de OTel en un mapa y extráelo en OpenTracing:
@PostMapping(value = "/submit") public CompletionStage<ResponseEntity<Void>> helloMapping(@RequestHeader Map<String, String> headers, @RequestBody String number) { //crear un mapa vacío para transportar el contexto var otelContext = new HashMap<String, String>(); //poner el contexto de OTel en el mapa GlobalOpenTelemetry.get().getPropagators().getTextMapPropagator().inject(Context.current(), otelContext, (carrier, key, value) -> carrier.put(key, value)); //poner el contenido del mapa en un OpenTracing SpanContext var openTracingContext = GlobalTracer.get().extract(Format.Builtin.TEXT_MAP, new TextMapAdapter(otelContext)); //establecer el nuevo OpenTracing SpanContext como el actual GlobalExtendedTracer.get().local().activateContext(openTracingContext); //llamar a IPF return MyDomain.initiation().handle(new InitiateMyFlowInput.Builder().build()) .thenCompose(__ -> ResponseEntity.accepted().build); }