OpenTelemetry【一、对接 skywalking OAP】

OpenTelemetry + SpringBoot 接入 SkyWalking 完整教程

整体架构说明

SkyWalking OAP 原生支持 OpenTelemetry OTLP 协议(HTTP/gRPC)
流程:
SpringBoot(OpenTelemetry SDK) → OTLP协议 → SkyWalking OAP Server → SkyWalking UI展示链路

两种方案区分:

  1. OpenTelemetry Java Agent(无代码侵入,推荐)
  2. OpenTelemetry SDK 编码集成(代码侵入,灵活定制)

SkyWalking OAP 默认开启 OTLP 接收端口:

  • OTLP gRPC:11800(默认兼容,和SkyWalking Java Agent共用端口)
  • OTLP HTTP:12800

方案一:OpenTelemetry Java Agent(零代码侵入|首选)

不需要修改一行业务代码,启动挂载agent即可采集链路,上报SkyWalking。

1. 准备文件

下载 OpenTelemetry Java Agent
地址:https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases
文件名:opentelemetry-javaagent.jar

2. SpringBoot 启动参数

java \
-javaagent:./opentelemetry-javaagent.jar \
# OTLP 上报地址,指向 SkyWalking OAP
-Dotel.exporter.otlp.endpoint=http://127.0.0.1:11800 \
-Dotel.exporter.otlp.protocol=grpc \
# 服务名称(SkyWalking UI展示的服务名)
-Dotel.service.name=otel-demo-service \
# 采样率:1.0=全量采集,生产可调整0.1
-Dotel.traces.sampler=parentbased_always_on \
# 开启MDC自动注入traceId(关键!日志打印traceId)
-Dotel.javaagent.logging.application-logging.mdc.enabled=true \
-jar demo.jar

⚠️ 重要:SkyWalking OAP 无需额外修改配置,默认接收 OTLP gRPC 数据。

3. 日志打印 TraceId(MDC方式)

OpenTelemetry Agent自动将 traceId、spanId、trace_flags 注入SLF4J MDC
MDC Key:

  • traceId
  • spanId
  • trace_flags

logback.xml 日志模板

<encoder>
    <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} traceId=%X{traceId} spanId=%X{spanId} - %msg%n</pattern>
</encoder>

启动应用调用接口,日志自动输出traceId。

4. 在代码中获取 TraceId(无需引入依赖)

import org.slf4j.MDC;

String traceId = MDC.get("traceId");

如果想要API方式获取(方案二SDK模式使用)


方案二:OpenTelemetry SDK 代码集成(有侵入,适合自定义埋点)

Step1 Maven依赖

<!-- OpenTelemetry BOM统一版本管理 -->
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>io.opentelemetry</groupId>
            <artifactId>opentelemetry-bom</artifactId>
            <version>1.40.0</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<dependencies>
    <!-- OpenTelemetry Core -->
    <dependency>
        <groupId>io.opentelemetry</groupId>
        <artifactId>opentelemetry-api</artifactId>
    </dependency>
    <dependency>
        <groupId>io.opentelemetry</groupId>
        <artifactId>opentelemetry-sdk</artifactId>
    </dependency>
    <!-- OTLP gRPC Exporter 上报SkyWalking -->
    <dependency>
        <groupId>io.opentelemetry</groupId>
        <artifactId>opentelemetry-exporter-otlp</artifactId>
    </dependency>
    <!-- SpringBoot Web自动埋点工具 -->
    <dependency>
        <groupId>io.opentelemetry.instrumentation</groupId>
        <artifactId>opentelemetry-spring-boot-starter</artifactId>
        <version>2.11.0-alpha</version>
    </dependency>
</dependencies>

Step2 application.yml 配置(OTLP上报SkyWalking)

otel:
  service:
    name: otel-spring-demo
  traces:
    exporter: otlp
  exporter:
    otlp:
      endpoint: http://127.0.0.1:11800
      protocol: grpc
  instrumentation:
    logging:
      mdc-enabled: true # 自动MDC注入traceId

Step3 API获取TraceId & 手动创建Span

import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.Tracer;
import io.opentelemetry.api.trace.TracerProvider;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.Scope;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@RestController
public class OtelTraceController {
    private static final Logger log = LoggerFactory.getLogger(OtelTraceController.class);

    @Autowired
    private OpenTelemetry openTelemetry;

    // 获取Tracer
    private Tracer getTracer() {
        return openTelemetry.getTracer("otel-demo-tracer");
    }

    @GetMapping("/otel/test")
    public String testTrace() {
        // ============ 方式1:从当前上下文获取TraceId ============
        Span currentSpan = Span.current();
        String traceId = currentSpan.getSpanContext().getTraceId();
        String spanId = currentSpan.getSpanContext().getSpanId();
        log.info("接口调用 traceId={}, spanId={}", traceId, spanId);

        // ============ 方式2:MDC获取(和日志保持一致) ============
        // MDC.get("traceId");

        // ============ 手动新建自定义Span(模拟业务埋点) ============
        Tracer tracer = getTracer();
        Span childSpan = tracer.spanBuilder("自定义业务-span-订单处理")
                .setAttribute("orderId", "10086")
                .startSpan();

        try (Scope scope = childSpan.makeCurrent()) {
            // span作用域内代码
            doBusiness();
        } catch (Exception e) {
            // 上报异常到链路
            childSpan.recordException(e);
            throw e;
        } finally {
            childSpan.end(); // 必须关闭span
        }

        return "success, traceId:" + traceId;
    }

    private void doBusiness() {
    }
}

Step4 关键说明:Span生命周期

Span span = tracer.spanBuilder("span名称").startSpan();
try(Scope scope = span.makeCurrent()){
    // 业务代码,当前上下文切换到新span
}finally{
    span.end(); // 结束span,数据发送到exporter
}

Step5 异步场景传递上下文

OpenTelemetry 使用 Context.wrap() 包装线程任务传递链路上下文

Runnable task = Context.current().wrap(() -> {
    Span span = Span.current();
    log.info("异步线程traceId:{}", span.getSpanContext().getTraceId());
});
new Thread(task).start();

三、SkyWalking OAP 关键配置校验(非常重要)

SkyWalking 默认开启OTLP接收,无需额外修改。
文件:application.yml(oap配置)

receiver-otlp:
  selector: ${SW_RECEIVER_OTLP:default}
  default:
    # gRPC端口默认11800
    grpc:
      host: 0.0.0.0
      port: 11800

✅ OpenTelemetry OTLP gRPC 和 SkyWalking Java Agent 使用同一个11800端口,可以混合接入
即:一部分服务使用skywalking-agent,一部分使用opentelemetry,链路互通,UI统一查看。

协议选择建议

  1. grpc 性能更好,推荐 otel.exporter.otlp.protocol=grpc
  2. 如果网络限制只能http:protocol=http/protobuf,端口改为12800

四、常见问题汇总

1. SkyWalking UI看不到OpenTelemetry上报的数据

  1. 确认endpoint地址是 OAP地址:11800,不要填UI的8081
  2. 检查OAP启动日志:receiver-otlp gRPC server start
  3. 应用启动日志看OTLP exporter有没有报错连接失败
  4. 必须发起接口请求产生链路,无调用无数据

2. MDC拿不到traceId

  • Agent模式:添加启动参数 -Dotel.javaagent.logging.application-logging.mdc.enabled=true
  • SDK starter模式:otel.instrumentation.logging.mdc-enabled=true

3. TraceId为空/无效

Span.current().getSpanContext().isValid() 先判断有效性;
只有在产生链路的请求线程内才能获取有效traceId;单元测试、定时任务若无埋点则为空。

4. OpenTelemetry 和 SkyWalking Agent能不能混用?

可以!同一个OAP同时接收两种协议

  • SkyWalking Agent:SkyWalking原生协议
  • OpenTelemetry SDK/Agent:OTLP协议
    最终全部在SkyWalking UI统一展示拓扑、链路。

⚠️ 禁止同一个进程同时挂载 skywalking-agent + opentelemetry-agent,两者会冲突字节码增强!


五、OpenTelemetry vs SkyWalking Agent 选型对比

方案 侵入性 协议 适用场景
SkyWalking Java Agent 零代码 SkyWalking自定义协议 纯Java栈,不想迁移标准OTel
OpenTelemetry Java Agent 零代码 OTLP 多语言技术栈、未来兼容多种可观测平台
OpenTelemetry SDK编码 代码侵入 OTLP 需要高度自定义埋点、特殊链路处理
posted @ 2026-08-03 13:58  蓝迷梦  阅读(2)  评论(0)    收藏  举报