接入ARMS应用监控以后,ARMS探针对常见的Java框架进行了自动埋点,因此不需要修改任何代码,就可以实现调用链信息的采集。如果您需要在调用链信息中,体现业务方法的执行情况,可以引入OpenTelemetry Java SDK,在业务代码中增加自定义埋点。
ARMS探针支持的组件和框架,请参见ARMS应用监控支持的Java组件和框架。
前提条件
引入依赖
请先参考如下Maven代码引入OpenTelemetry Java SDK。更多信息,请参见OpenTelemetry官方文档。
<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>
ARMS对OpenTelemetry埋点的兼容
名词介绍
此处只介绍一些常用的名词,其他名称解释,请参见OpenTelemetry Specification。
Span:一次请求的一个具体操作,比如远程调用入口或者内部方法调用。
SpanContext:一次请求追踪的上下文,包含traceId、spanId等信息。
Attribute:Span的附加属性字段,用于记录关键信息。
Baggae:在整条链路上透传的一些Key、Value信息。
使用OpenTelemetry Java SDK
通过OpenTelemetry的SDK主要可以实现以下操作:
埋点生成Span。
为Span增加Attributes。
在链路上下文透传Baggage。
获取当前Trace上下文并打印traceId、spanId等。
此处通过一段示例代码演示如何使用OpenTelemetry SDK完成上述操作。
以下代码片段需要注意,最终获取OpenTelemetry实例需要通过调用GlobalOpenTelemetry.get()方法获取,不能直接使用上一步通过OpenTelemetry SDK手动构建的Opentelemetry实例。否则会导致在4.x版本探针中无法看到通过SDK埋点生成的Span数据。
@RestController
@RequestMapping("/ot")
public class OpenTelemetryController {
private Tracer tracer;
private ScheduledExecutorService ses = Executors.newSingleThreadScheduledExecutor();
@PostConstruct
public void init() {
OpenTelemetrySdk.builder()
.setPropagators(ContextPropagators.create(W3CTraceContextPropagator.getInstance()))
.buildAndRegisterGlobal();
tracer = GlobalOpenTelemetry.get().getTracer("manual-sdk", "1.0.0");
ses.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
Span span = tracer.spanBuilder("schedule")
.setAttribute("schedule.time", System.currentTimeMillis())
.startSpan();
try (Scope scope = span.makeCurrent()) {
System.out.println("scheduled!");
Thread.sleep(500L);
span.setAttribute("schedule.success", true);
System.out.println(Span.current().getSpanContext().getTraceId()); // 获取 TraceId
} catch (Throwable t) {
span.setStatus(StatusCode.ERROR, t.getMessage());
} finally {
span.end();
}
}
}, 10, 30, TimeUnit.SECONDS);
}
@ResponseBody
@RequestMapping("/parent")
public String parent() {
Span span = tracer.spanBuilder("parent").setSpanKind(SpanKind.SERVER).startSpan();
try (Scope scope = span.makeCurrent()) {
// 使用Baggage透传业务自定义标签
Baggage baggage = Baggage.current().toBuilder()
.put("user.id", "1")
.put("user.name", "name")
.build();
try (Scope baggageScope = baggage.storeInContext(Context.current()).makeCurrent()) {
child();
}
span.setAttribute("http.method", "GET");
span.setAttribute("http.uri", "/parent");
} finally {
span.end();
}
return "parent";
}
private void child() {
Span span = tracer.spanBuilder("child").startSpan();
try (Scope scope = span.makeCurrent()) {
System.out.println("current traceId = " + Span.current().getSpanContext().getTraceId());
System.out.println("userId in baggage = " + Baggage.current().getEntryValue("user.id"));
Thread.sleep(1000);
} catch (Throwable e) {
span.setStatus(StatusCode.ERROR, e.getMessage());
} finally {
span.end();
}
}
}
示例代码说明:
在
OpenTelemetryController
的init
方法中启动了一个定时调度任务,并在调度任务开始时创建一个Span,在调度任务结束时关闭该Span。在
OpenTelemetryController
的parent
方法中调用了Opentelemetry SDK的多个方法。每次被调用时创建一个名为
parent
的Span,并在方法结束时关闭该Span。调用Baggage SDK,新加了名为
user.id
和user.name
的两对Baggage,这两个Baggage后续会传递到下游应用。为步骤2.1创建的Span新增了两个Attribute。
在
OpenTelemetryController
的child
方法中会执行以下操作。
不同探针差异点对比
对于上述代码中的不同操作,ARMS 3.x及以下版本探针和ARMS 4.x探针的支持情况有所区别,详情可见下方表格。
步骤 | 4.x及以上版本探针 | 3.x及以下版本探针 |
1 | 支持,会生成一个新的Span。 | 支持,会生成一个新的Span。 |
2.1 | 支持 | 支持 |
2.2 | 支持 | 不支持 |
2.3 | 支持 | 支持 |
3.1 | 支持 | 支持,该Span会作为步骤2.1创建出来的Span的方法栈存在。 |
3.2 | 支持,和ARMS中traceId是一个。 | 不支持,打印出的traceId和ARMS探针中的traceId不同。 |
3.2 | 支持 | 支持 |
埋点效果展示
4.x及以上版本
步骤1埋点效果:
可以正常看到通过OpenTelemetry SDK生成的Span。
步骤2.x、3.x埋点效果:
通过OpenTelemetry SDK生成的Span(红框)和当前探针埋点Tomcat生成的Span(黄框)在一条链路上,且通过OpenTelemetry SDK生成的Span的相关Attribute也设置成功(蓝框)。
3.x及以上版本探针
步骤1埋点效果:
步骤2.x、3.x埋点效果:
通过OpenTelemetry SDK生成的Span(红框)和当前探针埋点Tomcat生成的Span(黄框)在一条链路上,其中名为
child
的Span会作为名为parent
的Span的方法栈存在,且通过OpenTelemetry SDK生成的Span的相关Attribute也设置成功(蓝框)。
相关文档
您可以在应用的业务日志中关联调用链的TraceId信息,从而在应用出现问题时,能够通过调用链的TraceId快速关联到业务日志,及时定位、分析解决问题。更多信息,请参见Java应用业务日志关联调用链TraceId。