O agente do ARMS instrumenta automaticamente frameworks Java comuns para coletar traces sem alterações no código. No entanto, se sua aplicação utilizar um protocolo proprietário para comunicação entre processos, o cliente e o servidor podem aparecer como spans desconectados no trace.
Para vinculá-los, utilize o OpenTelemetry SDK for Java a fim de propagar manualmente o contexto do trace — incluindo o ID do trace, o ID do span, a flag de amostragem e o baggage — do cliente para o servidor.
Como funciona
A propagação de contexto segue um padrão de injeção e extração:
Lado do cliente (injeção): Antes de enviar uma solicitação, o cliente serializa o contexto atual do trace e o grava nos cabeçalhos da mensagem de saída.
Lado do servidor (extração): Ao receber a solicitação, o servidor lê o contexto do trace nos cabeçalhos da mensagem e o define como o contexto atual. Quaisquer spans criados posteriormente tornam-se filhos do trace original.
Este documento utiliza os formatos de propagação W3C Trace Context e W3C Baggage por meio de W3CTraceContextPropagator e W3CBaggagePropagator.
Pré-requisitos
Antes de começar, certifique-se de ter:
Integrado o Application Monitoring do ARMS
O agente do ARMS V4.x ou superior. Para instruções de atualização, consulte Atualize o agente do ARMS
Adicionar dependências do Maven
Adicione as seguintes dependências ao seu arquivo pom.xml. Para mais detalhes, consulte OpenTelemetry Java Instrumentation.
<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-sdk</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-bom</artifactId>
<version>1.23.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
Defina o transportador de mensagens
A classe CustomRpcCallMessage representa uma entidade de mensagem em um protocolo proprietário. Ela usa um headerMap para transportar o contexto do trace entre processos. Caso a classe de mensagem do seu protocolo não possua um mapa de cabeçalhos, adicione um.
class CustomRpcCallMessage {
private Map<String, String> headerMap;
// Other fields omitted.
public String getHeader(String key) {
return headerMap.get(key);
}
public void setHeader(String key, String value) {
this.headerMap.put(key, value);
}
public Map<String, String> getHeaderMap() {
return headerMap;
}
}
Injetar contexto no lado do cliente
Antes de enviar uma solicitação, injete o contexto atual do trace e o baggage na mensagem de saída. Defina um TextMapSetter que escreva pares chave-valor nos cabeçalhos da mensagem e, em seguida, chame inject() tanto para os propagadores de contexto do trace quanto para os de baggage.
import io.opentelemetry.api.baggage.propagation.W3CBaggagePropagator;
import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.propagation.TextMapSetter;
public static void clientSide(String[] args) {
CustomRpcCallMessage rpcCall = new CustomRpcCallMessage();
// Define how to write context entries into the carrier
TextMapSetter<CustomRpcCallMessage> setter =
(carrier, key, value) -> carrier.setHeader(key, value);
// Inject W3C Trace Context and Baggage into the outgoing message
W3CTraceContextPropagator.getInstance().inject(Context.current(), rpcCall, setter);
W3CBaggagePropagator.getInstance().inject(Context.current(), rpcCall, setter);
// Send rpcCall to the server through your proprietary protocol
}
Extrair contexto no lado do servidor
Quando o servidor receber uma solicitação, extraia o contexto do trace e o baggage da mensagem recebida. Defina um TextMapGetter que leia pares chave-valor dos cabeçalhos da mensagem e chame extract() para reconstruir o contexto. Utilize context.makeCurrent() para ativar o contexto extraído, permitindo que os spans subsequentes se unam ao trace original.
import io.opentelemetry.api.baggage.propagation.W3CBaggagePropagator;
import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.Scope;
import io.opentelemetry.context.propagation.TextMapGetter;
private static void serverSide() {
// Receive the incoming request
CustomRpcCallMessage rpcCall = /* received message */;
// Define how to read context entries from the carrier
TextMapGetter<CustomRpcCallMessage> getter = new TextMapGetter<>() {
@Override
public Iterable<String> keys(CustomRpcCallMessage carrier) {
return carrier.getHeaderMap().keySet();
}
@Override
public String get(CustomRpcCallMessage carrier, String key) {
return carrier.getHeader(key);
}
};
// Extract W3C Trace Context and Baggage from the incoming message
Context context = W3CTraceContextPropagator.getInstance().extract(Context.current(), rpcCall, getter);
context = W3CBaggagePropagator.getInstance().extract(context, rpcCall, getter);
// Activate the extracted context for this scope
try (Scope scope = context.makeCurrent()) {
// Process the request. Spans created here join the caller's trace.
}
}
Adaptar o código ao seu protocolo
Na maioria dos casos, apenas as implementações de TextMapSetter e TextMapGetter precisam ser alteradas. Mapeie os métodos set e get para corresponder à forma como a classe de mensagem do seu protocolo armazena e recupera valores de cabeçalho. As chamadas de injeção e extração permanecem as mesmas, independentemente do tipo de transportador.
Próximos passos
Associe IDs de trace aos logs da aplicação para localizar e resolver erros com maior rapidez. Consulte Associar IDs de trace a logs para uma aplicação Java.