3. 属性注入基础:在 Span 上设置属性的 API
属性(Attributes)是 OpenTelemetry 中附加在 Span 上的键值对元数据,用于描述操作的上下文信息,如 HTTP 方法、数据库语句、用户 ID 等。本章聚焦于在 Span 上注入属性的核心 API、数据类型与系统限制。
3.1 核心 API:SetAttribute 与 SetAttributes
OpenTelemetry SDK 为 Span 对象提供了两种属性设置方法,分别适用于单属性注入与批量注入场景。
| 方法 | 签名 | 适用场景 |
|---|---|---|
set_attribute(key, value) |
set_attribute(key: str, value: AttributeValue) |
注入单个属性,如请求 ID、状态码 |
set_attributes(attributes) |
set_attributes(attributes: Mapping[str, AttributeValue]) |
批量注入多个属性,如从字典或请求头中提取的元数据 |
关键行为: 两次调用
set_attribute 使用相同 key 时,后一次的值会覆盖前一次。批量 set_attributes 中若存在重复 key,最终值取决于 SDK 实现(通常为最后一个值)。
Python 示例
from opentelemetry import trace
tracer = trace.get_tracer(__name__)
with tracer.start_as_current_span("process_order") as span:
# 单属性注入
span.set_attribute("order.id", "ORD-12345")
span.set_attribute("order.amount", 299.99)
# 批量注入
attributes = {
"payment.method": "credit_card",
"payment.currency": "USD",
"payment.status": "completed",
}
span.set_attributes(attributes)
Go 示例
import "go.opentelemetry.io/otel/attribute"
ctx, span := tracer.Start(ctx, "process_order")
defer span.End()
// 单属性注入
span.SetAttributes(attribute.String("order.id", "ORD-12345"))
span.SetAttributes(attribute.Float64("order.amount", 299.99))
// 批量注入
span.SetAttributes(
attribute.String("payment.method", "credit_card"),
attribute.String("payment.currency", "USD"),
attribute.String("payment.status", "completed"),
)
Java 示例
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.common.Attributes;
Span span = tracer.spanBuilder("process_order").startSpan();
// 单属性注入
span.setAttribute("order.id", "ORD-12345");
span.setAttribute("order.amount", 299.99);
// 批量注入
Attributes attributes = Attributes.builder()
.put("payment.method", "credit_card")
.put("payment.currency", "USD")
.put("payment.status", "completed")
.build();
span.setAllAttributes(attributes);
span.end();
3.2 属性类型与值限制
OpenTelemetry 规范定义了属性值的合法类型,以及键与值的长度限制。违反限制可能导致数据被静默丢弃或截断。
| 类型 | 示例值 | 说明 |
|---|---|---|
string |
"GET" |
UTF-8 编码字符串 |
boolean |
true |
布尔值 |
int64 |
200 |
64 位有符号整数 |
float64 |
3.14 |
64 位浮点数 |
array |
["a","b","c"] |
同类型元素的数组,元素类型必须一致 |
限制规则:
- 属性键(key)最大长度 256 个字符,超出部分会被截断。
- 属性值(value)最大长度 4096 个字符,超出部分会被截断。
- 数组类型最多包含 2048 个元素,超出部分会被丢弃。
- 不支持嵌套对象、二进制数据或自定义类型。
3.3 属性注入流程与数据流
下图展示了从应用代码调用 set_attribute 到数据最终被导出到后端的数据流与类型校验过程。
3.4 属性命名最佳实践
OpenTelemetry 语义约定(Semantic Conventions)推荐使用点号分隔的命名空间,避免使用大写字母或特殊字符。
- 使用命名空间前缀:
http.method、db.system、messaging.system - 避免保留字符: 键中不应包含
=、&、空格等 URL 保留字符 - 统一大小写: 全小写 + 下划线分隔,如
order_id而非orderId - 避免动态键名: 不要使用用户输入或运行时生成的字符串作为键名,防止基数爆炸
实践建议: 在微服务架构中,建议在服务启动时注册一个属性注入工具函数或装饰器,统一处理属性命名、类型转换与长度校验,避免在每个 Span 中重复编写校验逻辑。
3.5 常见错误与排查
| 错误场景 | 现象 | 解决方案 |
|---|---|---|
| 键名超过 256 字符 | 属性在导出时被截断或丢失 | 使用短键名,遵循语义约定 |
| 值类型不匹配 | SDK 抛出类型错误或静默丢弃 | 使用 AttributeValue 联合类型进行显式转换 |
| 数组元素类型不一致 | 数组被整体丢弃 | 确保数组内所有元素类型相同 |
| 在 Span 结束后设置属性 | 属性不会被记录 | 确保在 span.end() 之前完成属性注入 |