跳到主要内容

在PubSub+ JCSMP API中分布式追踪的上下文传播

分布式追踪允许您的企业应用程序追踪消息从发布者发出,经过事件网格,最终到达接收应用程序的流动过程。有关详细概述,请参阅分布式追踪。有关版本要求的信息,请参阅分布式追踪版本兼容性。

有关如何为代码添加分布式追踪的工具,请参阅为 JCSMP 添加分布式追踪工具。

  • PubSub+ OpenTelemetry API 库仅支持 W3C 传播器。
  • 有关如何配置 OpenTelemetry SDK 环境变量的信息,请参阅 OpenTelemetry SDK 配置。
  • 默认情况下,追踪包括后端应用程序(如 Jaeger)可见的命令行参数。出于安全目的,重要的是禁用此功能,因为这些参数可能包含敏感信息,如您的用户名和密码。有关说明,请参阅 GitHub 上的 OpenTelemetry 文档中的禁用自动资源提供程序。

为JCSMP添加分布式追踪工具

有两种方法可以将分布式追踪集成到使用 PubSub+ JCSMP API 的应用程序中:

  • 自动工具化允许您的应用程序在不修改源代码的情况下注入和提取标准 OpenTelemetry 数据。

  • 手动工具化涉及对您的企业应用程序的源代码进行修改。这些代码修改允许您将额外的上下文(如行李和追踪状态)注入到消息中。

自动工具化

自动工具化不需要对应用程序代码进行任何更改即可发送遥测数据。您无需更改应用程序的启动参数或实现任何额外的库。

要使用自动工具化,您需要下载以下 .jar 文件并将它们放在您的项目中:

  • OpenTelemetry Java 工具化
  • PubSub+ OpenTelemetry 与 Solace JCSMP API 集成 有关 OpenTelemetry 版本兼容性,请参阅分布式追踪版本兼容性。

将上下文注入到传出消息中

在命令提示符下,输入以下命令以配置您的发布应用程序将 OpenTelemetry 数据注入到发布的消息中。

java -javaagent:<绝对路径到otel-jar>/opentelemetry-javaagent-all-<otel-java-version>.jar \
-Dotel.javaagent.extensions=<绝对路径到solace-jar>/solace-opentelemetry-jcsmp-integration-<solace-opentelemetry-version>.jar \
-Dotel.propagators="solace_jcsmp_tracecontext","solace_jcsmp_baggage" \
-Dotel.exporter.otlp.endpoint=<http://localhost:4317> \
-Dotel.exporter.otlp.protocol=grpc \
-Dotel.traces.exporter=otlp \
-Dotel.metrics.exporter=none \
-Dotel.resource.attributes="service.name=SolaceJCSMPPublisher" \
-jar <your-jcsmp-publisher-application>.jar

其中:

  • <绝对路径到otel-jar> 是包含您的 OpenTelemetry Java Agent JAR 文件的目录的绝对文件路径。
  • <绝对路径到solace-jar> 是包含您的 SolacePubSub+ OpenTelemetry JCSMP 集成 JAR 文件的目录的绝对文件路径。
  • solace_jcsmp_tracecontext 是 JCSMP 自定义追踪上下文传播器的名称。必须明确将其设置为 “solace_jcsmp_tracecontext”,以便 OTEL Java Agent 识别该传播器。
  • solace_jcsmp_baggage 是 JCSMP 自定义行李传播器的名称。必须明确将其设置为 “solace_jcsmp_baggage”,以便 OTEL Java Agent 识别该传播器。如果您不想传播行李,请省略此属性。
  • <http://localhost:4317> 是您使用的收集器的 URL。示例 localhost:4317 是本地运行的 OpenTelemetry 收集器的默认端口。要允许您的应用程序将追踪数据发送到 OTLP 端点,您需要将属性 otel.exporter.otlp.endpoint=http://localhost:4317 更新为指向您的收集器的 IP 地址。
  • <your-jcsmp-publisher-application> 是与您的 JCSMP 发布应用程序关联的 JAR 文件的名称。
  • <otel-java-version> 是与 PubSub+ OpenTelemetry 集成 for Solace JCSMP API 版本(<solace-opentelemetry-version>)兼容的 OpenTelementry Instrumentation Java Library 的版本。有关兼容性的信息,请参阅分布式追踪版本兼容性。
  • <solace-opentelemetry-version> 是与 OpenTelementry Instrumentation Library(<otel-java-version>)一起使用的 PubSub+ OpenTelemetry 集成 for Solace JCSMP 的版本。有关兼容性的信息,请参阅分布式追踪版本兼容性。

在命令提示符下,输入以下命令以配置您的队列接收器应用程序从接收到的消息中提取 OpenTelemetry 数据:

java -javaagent:<绝对路径到otel-jar>/opentelemetry-javaagent-all-<otel-java-version>.jar \
-Dotel.javaagent.extensions=<绝对路径到solace-jar>/solace-opentelemetry-jcsmp-integration-<solace-opentelemetry-version>.jar \
-Dotel.propagators="solace_jcsmp_tracecontext","solace_jcsmp_baggage" \
-Dotel.exporter.otlp.endpoint=<http://localhost:4317> \
-Dotel.exporter.otlp.protocol=grpc \
-Dotel.traces.exporter=otlp \
-Dotel.metrics.exporter=none \
-Dotel.resource.attributes="service.name=SolaceJCSMPConsumer" \
-jar <your-jcsmp-consumer-application>.jar

其中:

  • <绝对路径到otel-jar> 是包含您的 OpenTelemetry Java Agent JAR 文件的目录的绝对文件路径。
  • <绝对路径到solace-jar> 是包含您的 PubSub+ OpenTelemetry JCSMP 集成 JAR 文件的目录的绝对文件路径。
  • solace_jcsmp_tracecontext 是 JCSMP 自定义追踪上下文传播器的名称。必须明确将其设置为 “solace_jcsmp_tracecontext”,以便 OTEL Java Agent 识别该传播器。
  • solace_jcsmp_baggage 是 JCSMP 自定义行李传播器的名称。必须明确将其设置为 “solace_jcsmp_baggage”,以便 OTEL Java Agent 识别该传播器。如果您不想传播行李,请省略此属性。
  • <http://localhost:4317> 是您使用的收集器的 URL。示例 localhost:4317 是本地运行的 OpenTelemetry 收集器的默认端口。要允许您的应用程序将追踪数据发送到 OTLP 端点,您需要将属性 otel.exporter.otlp.endpoint=http://localhost:4317 更新为指向您的收集器的 IP 地址。
  • <your-jcsmp-consumer-application> 是与您的 JCSMP 消费应用程序关联的 JAR 文件的名称。
  • <otel-java-version> 是与 PubSub+ OpenTelemetry 集成 for Solace JCSMP API 版本(<solace-opentelemetry-version>)兼容的 OpenTelementry Instrumentation Java Library 的版本。有关兼容性的信息,请参阅分布式追踪版本兼容性。
  • <solace-opentelemetry-version> 是与 OpenTelementry Instrumentation Library(<otel-java-version>)一起使用的 PubSub+ OpenTelemetry 集成 for Solace JCSMP 的版本。有关兼容性的信息,请参阅分布式追踪版本兼容性。

当您使用自动工具化时,不应将最新版本的 opentelemetry-javaagent-all-<otel-java-version>.jarsolace-opentelemetry-jcsmp-integration-<solace-opentelemetry-version>.jar 添加为您的应用程序的 Maven 或 Gradle 依赖项。有关兼容性的信息,请参阅分布式追踪版本兼容性。

有关更多信息,请参阅:

  • Codelab:Solace 分布式追踪和上下文传播入门
  • PubSub+ 消息传递 API - 分布式追踪 OpenTelemetry 自动工具化跨度字段

手动工具化

手动工具化涉及对您的企业应用程序的源代码进行修改,并允许您将额外的上下文(如行李和追踪状态)注入到消息中。上下文传播使调试和优化您的应用程序变得简单。有关 Solace 事件消息中上下文传播的更多信息,请参阅分布式追踪上下文传播。以下示例展示了如何使用 OpenTelemetry API 创建跨度。

上下文传播如何在 JCSMP PubSub+ API 中启用分布式追踪

在您的客户端应用程序中,您可以使用 OpenTelemetry API 创建一个跨度,其中包含分布式系统中操作的元数据。此跨度与一个上下文相关联,该上下文包括一个唯一的 TraceID。接下来,当您使用 PubSub+ 消息生产者发布消息时,Solace OTel 集成包将上下文(包含 TraceID)注入到消息中。随着消息通过事件代理并被消费应用程序接收,每个步骤都会生成跨度,并且原始消息上下文中存在相同的 TraceID。当在发布或消费应用程序中关闭每个跨度时,Java OpenTelemetry API 将其发送到 OpenTelemetry 收集器,该收集器收集、处理并将跨度导出到使用其唯一 TraceID 相关跨度的后端应用程序。后端应用程序使用相关跨度创建一个 trace,这是一个端到端的快照,详细说明了消息如何通过分布式系统流动。如果您不使用上下文传播,那么后端应用程序将无法使用唯一的 TraceID 将跨度链接起来,这使得追踪消息通过分布式系统的流动变得困难。

依赖项

要启用分布式追踪的上下文传播,您必须首先将 Solace PubSub+ OpenTelemetry 集成 for Solace JCSMP API 库作为依赖项添加到您的应用程序中。此库会自动添加 OpenTelemetry API 和 SDK 库,这些库是上下文传播所必需的。有关 OpenTelemetry 版本兼容性,请参阅分布式追踪版本兼容性。添加库后,您可以访问以下两个接口:

  • SolaceJCSMPTextMapSetter — 此接口允许 TextMapPropagator 将上下文注入到消息中。

  • SolaceJCSMPTextMapGetter — 此接口允许 TextMapPropagator 从消息中提取上下文。

本指南假设您熟悉配置 OpenTelemetry 类的实例。有关配置 OpenTelemetry 对象的说明,请参阅 OpenTelemetry 文档中的 OpenTelemetry Java 手动工具化。

在消息发布时生成发送跨度

您的发布应用程序可以生成一个发送跨度并将其导出到 OpenTelemetry 收集器。以下步骤展示了如何将上下文注入到消息中并为发布的消息生成一个发送跨度:

  1. 使用 setAttribute() 方法为新跨度设置跨度属性。接下来,将当前上下文设置为该跨度的父级。使用 startSpan() 方法启动跨度:
final Span sendSpan = tracer
.spanBuilder("mySolacePublisherApp" + " " + MessagingOperationValues.PROCESS)
.setSpanKind(SpanKind.CLIENT)
// 发布到非临时主题端点
.setAttribute(SemanticAttributes.MESSAGING_DESTINATION_KIND, MessagingDestinationKindValues.TOPIC)
.setAttribute(SemanticAttributes.MESSAGING_TEMP_DESTINATION, false)
// 根据需要设置更多属性
//.setAttribute(...)
//.setAttribute(...)
.setParent(Context.current()) // 将当前上下文设置为父级跨度
.startSpan();
  1. 将步骤 1 中创建的跨度(在此示例中为 sendSpan)设置为新的当前上下文。接下来,将当前上下文注入到您的消息中,然后发布该消息。调用跨度的 end() 方法以导出跨度数据:
try (Scope scope = sendSpan.makeCurrent()) {
final SolaceJCSMPTextMapSetter setter = new SolaceJCSMPTextMapSetter();
final TextMapPropagator propagator = openTelemetry.getPropagators().getTextMapPropagator();
// 将带有发送跨度的当前上下文注入到消息中
propagator.inject(Context.current(), message, setter);
// 将消息发布到给定主题
messageProducer.send(message, messageDestination);
} catch (Exception e) {
sendSpan.recordException(e); // 跨度可以记录异常
sendSpan.setStatus(StatusCode.ERROR, e.getMessage()); // 将跨度状态设置为 ERROR/FAILED
} finally {
sendSpan.end(); // 调用 end() 后导出跨度数据
}

在消息接收时生成接收跨度

您的消费应用程序可以生成一个接收跨度,然后将其导出到 OpenTelemetry 收集器。以下步骤展示了如何从接收到的消息中提取追踪上下文并生成一个接收跨度:

  1. 使用 SolaceJCSMPTextMapGetter 从接收到的消息中提取任何现有上下文:
final SolaceJCSMPTextMapGetter getter = new SolaceJCSMPTextMapGetter();
final Context extractedContext = openTelemetry.getPropagators().getTextMapPropagator()
.extract(Context.current(), message, getter);
  1. 使用 makeCurrent() 方法将提取的上下文设置为当前上下文。接下来创建一个子跨度(在此示例中为 receiveSpan)并将提取的上下文设置为该子跨度的父级。使用 startSpan() 方法启动跨度:
try (Scope scope = extractedContext.makeCurrent()) {
// 创建一个子跨度并将提取的/当前上下文设置为该跨度的父级
final Span receiveSpan = tracer
.spanBuilder("mySolaceReceiverApp" + " " + MessagingOperationValues.RECEIVE)
.setSpanKind(SpanKind.CLIENT)
// 如果消息是在非临时队列端点上接收的情况
.setAttribute(SemanticAttributes.MESSAGING_DESTINATION_KIND,
MessagingDestinationKindValues.QUEUE)
.setAttribute(SemanticAttributes.MESSAGING_TEMP_DESTINATION, false)
// 根据需要设置更多属性
//.setAttribute(...)
//.setAttribute(...)
// 为消息发布者的应用程序跨度创建父子关系
.setParent(extractedContext)
// 启动跨度
.startSpan();

// 下一步继续 try-catch...
}
  1. 接收并处理消息,然后在接收跨度上调用 end() 方法以导出跨度数据:
try {
// 在回调函数中对消息进行操作
messageProcessor.accept(receivedMessage);
} catch (Exception e) {
receiveSpan.recordException(e); // 跨度可以记录异常
receiveSpan.setStatus(StatusCode.ERROR, e.getMessage()); // 将跨度状态设置为 ERROR
} finally {
receiveSpan.end(); // 调用 span.end() 时导出跨度数据
}