news 2026/4/18 2:22:28

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/4/13 19:37:03

高频开关下续流二极管损耗计算与优化示例

高频开关下续流二极管的损耗真相&#xff1a;从计算到优化的实战指南你有没有遇到过这样的情况&#xff1f;一个设计看似完美的Buck电源&#xff0c;在300kHz以上频率运行时&#xff0c;效率却始终卡在87%上不去。测温发现&#xff0c;那个不起眼的“小二极管”居然烫得不敢用手…

作者头像 李华
网站建设 2026/4/16 4:06:17

基于Dify的RAG系统构建全流程:连接GPU算力释放大模型潜力

基于Dify的RAG系统构建全流程&#xff1a;连接GPU算力释放大模型潜力 在企业智能化转型加速的今天&#xff0c;越来越多组织希望将大语言模型&#xff08;LLM&#xff09;落地到实际业务场景中——从智能客服到内部知识问答&#xff0c;从自动报告生成到合同辅助审查。但现实却…

作者头像 李华
网站建设 2026/4/16 10:51:48

SpringBoot倒下后,java的“35岁危机”提前来了!!!

马上就要2026年了&#xff0c;想跟大家说点儿心里话。当下java行业正经历“结构性洗牌”&#xff1a;3年岗位缩减40%&#xff0c;AI替代30%基础编码&#xff0c;1:120的竞争比让求职难上加难&#xff0c;未来3年更有40万开发者面临淘汰。最近筛简历&#xff0c;清一色的Spring …

作者头像 李华
网站建设 2026/4/9 21:16:22

【计算机毕设】基于Python的热门游戏推荐系统的设计与实现

&#x1f49f;博主&#xff1a;程序员小俊&#xff1a;CSDN作者、博客专家、全栈领域优质创作者 &#x1f49f;专注于计算机毕业设计&#xff0c;大数据、深度学习、Java、小程序、python、安卓等技术领域 &#x1f4f2;文章末尾获取源码数据库 &#x1f308;还有大家在毕设选题…

作者头像 李华
网站建设 2026/4/10 23:12:15

ModbusRTU硬件层解析:RS-485电路设计深度剖析

ModbusRTU硬件层解析&#xff1a;RS-485电路设计深度剖析在工业自动化现场&#xff0c;你是否遇到过这样的场景&#xff1f;一台PLC通过ModbusRTU轮询多个从站&#xff0c;突然某个传感器通信中断&#xff1b;环境稍一嘈杂&#xff0c;CRC校验就频繁出错&#xff1b;设备重启后…

作者头像 李华
网站建设 2026/4/6 9:27:35

Dify平台如何实现多渠道消息推送?

Dify平台如何实现多渠道消息推送&#xff1f; 在企业智能化转型加速的今天&#xff0c;用户不再满足于单一入口的AI交互。客服咨询后能否自动收到短信确认&#xff1f;工单处理进展是否能实时推送到钉钉群&#xff1f;这些看似简单的通知需求&#xff0c;背后却涉及复杂的系统集…

作者头像 李华