news 2026/6/5 19:57:23

OTLP Trace数据结构

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
OTLP Trace数据结构

根据你的问题,OTLP(OpenTelemetry Protocol)是OpenTelemetry项目原生的数据传输协议,其数据模型基于ProtoBuf(Protocol Buffers)定义。你可以直接使用OpenTelemetry官方提供的Java类库来处理其Trace数据,无需从零开始手动定义。

📦 核心数据结构与Java类

OTLP的Trace数据是一个层次化的结构,其核心的Java类定义在 opentelemetry-proto 依赖中。主要类的层次关系如下:

· ExportTraceServiceRequest
· 描述:最顶层的请求容器,代表一次上报的所有数据。
· 核心字段:repeated ResourceSpans resource_spans
· ResourceSpans
· 描述:代表来自同一“资源”(如一个微服务实例)的所有Trace数据。
· 核心字段:
· Resource resource:描述数据源的属性(如服务名、主机名、K8s Pod信息)。
· repeated ScopeSpans scope_spans
· ScopeSpans (旧称 InstrumentationLibrarySpans)
· 描述:代表同一“检测库”(如某个特定版本的SDK或框架)产生的Span集合。
· 核心字段:
· InstrumentationScope scope:描述检测库的信息(名称、版本)。
· repeated Span spans
· Span
· 描述:单个跨度(Span),是Trace数据的最小单元,代表一个具体的工作单元(如一次函数调用、一次HTTP请求)。
· 核心字段:
· bytes trace_id:Trace的唯一标识,16字节。
· bytes span_id:Span的唯一标识,8字节。
· bytes parent_span_id:父Span的ID,用于构建调用链。
· string name:Span的名称(如接口路径、方法名)。
· SpanKind kind:Span类型(如 SERVER、CLIENT)。
· fixed64 start_time_unix_nano:开始时间戳(纳秒)。
· fixed64 end_time_unix_nano:结束时间戳(纳秒)。
· repeated KeyValue attributes:键值对属性(如 http.status_code=200)。
· Status status:状态(OK, ERROR)。
· repeated Span.Link links:指向其他相关Span的链接。
· repeated Event events:Span期间发生的事件(日志)。

🔧 如何使用这些类

1. 添加Maven依赖
要在项目中使用这些预生成的类,你需要在pom.xml 中添加以下依赖:

```xml
<dependency>
<groupId>io.opentelemetry.proto</groupId>
<artifactId>opentelemetry-proto</artifactId>
<version>1.1.0</version> <!-- 请检查并使用最新版本 -->
</dependency>
```

2. 构建和序列化数据示例
以下代码展示了如何使用这些类构建一个简单的Span,并将其序列化为Protobuf格式的字节数组,以便通过OTLP协议(如HTTP)发送:

```java
import com.google.protobuf.ByteString;
import io.opentelemetry.proto.collector.trace.v1.ExportTraceServiceRequest;
import io.opentelemetry.proto.common.v1.AnyValue;
import io.opentelemetry.proto.common.v1.KeyValue;
import io.opentelemetry.proto.resource.v1.Resource;
import io.opentelemetry.proto.trace.v1.ScopeSpans;
import io.opentelemetry.proto.trace.v1.Span;
import io.opentelemetry.proto.trace.v1.Status;

public class OtlpTraceBuilder {

public static byte[] buildTraceRequest() {
// 1. 创建一个 Span
Span span = Span.newBuilder()
.setTraceId(ByteString.copyFromUtf8("1234567890abcdef1234567890abcdef")) // 16字节的十六进制字符串
.setSpanId(ByteString.copyFromUtf8("1234567890abcdef")) // 8字节的十六进制字符串
.setName("/api/user/login")
.setKind(Span.SpanKind.SPAN_KIND_SERVER)
.setStartTimeUnixNano(System.nanoTime())
.setEndTimeUnixNano(System.nanoTime() + 1_000_000L) // 假设持续1毫秒
.addAttributes(KeyValue.newBuilder()
.setKey("http.method")
.setValue(AnyValue.newBuilder().setStringValue("GET").build())
.build())
.addAttributes(KeyValue.newBuilder()
.setKey("http.status_code")
.setValue(AnyValue.newBuilder().setIntValue(200).build())
.build())
.setStatus(Status.newBuilder().setCode(Status.StatusCode.STATUS_CODE_OK).build())
.build();

// 2. 将 Span 放入 ScopeSpans 和 ResourceSpans
ScopeSpans scopeSpans = ScopeSpans.newBuilder().addSpans(span).build();
io.opentelemetry.proto.trace.v1.ResourceSpans resourceSpans =
io.opentelemetry.proto.trace.v1.ResourceSpans.newBuilder()
.setResource(Resource.newBuilder()
.addAttributes(KeyValue.newBuilder()
.setKey("service.name")
.setValue(AnyValue.newBuilder().setStringValue("user-service").build())
.build())
.build())
.addScopeSpans(scopeSpans)
.build();

// 3. 构建最终的导出请求
ExportTraceServiceRequest request = ExportTraceServiceRequest.newBuilder()
.addResourceSpans(resourceSpans)
.build();

// 4. 序列化为字节数组 (可通过HTTP/gRPC发送)
return request.toByteArray();
}
}
```

💡 关键细节与注意事项

· ID格式:trace_id 和 span_id 在协议层是字节数组(ByteString),但通常用十六进制字符串表示和传递。示例中为了直观使用了字符串,实际生产环境需确保正确的字节转换。
· 时间单位:所有时间戳(start_time_unix_nano)的单位是纳秒。
· 状态码:Span的状态码 (status.code) 是 STATUS_CODE_UNSET、STATUS_CODE_OK 或 STATUS_CODE_ERROR。
· 传输方式:序列化后的Protobuf数据可以通过OTLP协议发送,常见端口是gRPC的 4317 或HTTP的 4318(端点通常为 /v1/traces)。

📚 扩展学习

如果你需要实现一个接收端(Collector)来解析OTLP数据,可以参考以下基于Spring Boot的控制器代码片段:

```java
import io.opentelemetry.proto.collector.trace.v1.ExportTraceServiceRequest;
import com.google.protobuf.InvalidProtocolBufferException;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/v1/traces")
public class OtlpTraceController {
@PostMapping(consumes = "application/x-protobuf")
public String receiveTrace(@RequestBody byte[] body) {
try {
ExportTraceServiceRequest request = ExportTraceServiceRequest.parseFrom(body);
// 处理 request 中的 trace 数据
System.out.println("Received trace data.");
return "OK";
} catch (InvalidProtocolBufferException e) {
return "Invalid Protobuf data";
}
}
}
```

要运行此控制器,你需要在Spring配置中添加对Protobuf消息转换器的支持。

如果你想进一步了解某个特定类(如 Span 或 Resource)的完整字段定义,或者需要查看更复杂的示例(例如包含 links 或 events 的Span),我可以为你提供更详细的说明。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/28 20:45:21

Dify平台如何实现跨语言的翻译辅助?

Dify平台如何实现跨语言的翻译辅助&#xff1f; 在全球化浪潮席卷各行各业的今天&#xff0c;企业面对的不再只是本地市场&#xff0c;而是遍布全球的用户群体。随之而来的挑战是&#xff1a;如何高效、准确地处理多语言内容&#xff1f;传统机器翻译系统虽然能完成基础转换&am…

作者头像 李华
网站建设 2026/6/1 0:48:22

Dify开源项目Roadmap路线图公开披露

Dify开源项目Roadmap路线图深度解读 在大模型技术席卷全球的今天&#xff0c;我们正站在一个关键的转折点上&#xff1a;AI不再只是实验室里的前沿探索&#xff0c;而是逐步渗透进企业真实业务场景中的生产力工具。然而&#xff0c;从“能用”到“好用”&#xff0c;中间隔着一…

作者头像 李华
网站建设 2026/6/5 16:37:54

一文说清QTimer单次与周期定时的区别与选择

QTimer单次与周期定时&#xff1a;深入理解机制差异与工程选型 在开发一个复杂的Qt应用时&#xff0c;你是否曾遇到过这样的问题&#xff1a; - 界面卡顿&#xff0c;明明只设置了一个“每秒刷新”的定时器&#xff0c;CPU占用却居高不下&#xff1f; - 登录失败后禁用按钮30…

作者头像 李华
网站建设 2026/5/30 19:30:38

Dify可视化编排实战:零基础构建AI智能体与文本生成应用

Dify可视化编排实战&#xff1a;零基础构建AI智能体与文本生成应用 在大模型技术席卷各行各业的今天&#xff0c;越来越多企业希望将LLM&#xff08;大语言模型&#xff09;融入自身业务——无论是客服问答、内容创作&#xff0c;还是知识管理。但现实往往令人望而却步&#xf…

作者头像 李华
网站建设 2026/5/30 6:57:49

串口DMA在工业网关中的角色与配置:一文说清

串口DMA在工业网关中的角色与配置&#xff1a;一文说清工业通信的“隐形引擎”——从一个丢包问题说起某天&#xff0c;一位工程师向我吐槽&#xff1a;他的工业网关在现场运行时频繁出现Modbus数据丢失&#xff0c;设备状态更新延迟严重。他反复检查了线路、波特率和协议实现&…

作者头像 李华
网站建设 2026/5/28 14:33:40

Windows 11下WinDbg Preview下载安装一文说清

Windows 11下WinDbg Preview安装与配置实战指南&#xff1a;从下载到蓝屏分析一气呵成 你是不是也曾在系统崩溃后面对一个 .dmp 文件束手无策&#xff1f;或者想调试驱动却卡在工具安装这一步&#xff1f;别急&#xff0c;今天我们就来把 WinDbg Preview 这件事彻底讲明白…

作者头像 李华