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 到数据最终被导出到后端的数据流与类型校验过程。

Span 属性注入与数据流 应用代码 set_attribute(key, value) 类型校验器 类型/长度检查 Span 属性存储 键值对映射 Span 导出器 序列化与发送 可观测性后端 Jaeger / Zipkin / OTLP 丢弃 / 截断 类型不匹配 / 超长键值 数组超限

3.4 属性命名最佳实践

OpenTelemetry 语义约定(Semantic Conventions)推荐使用点号分隔的命名空间,避免使用大写字母或特殊字符。

  • 使用命名空间前缀: http.method、db.system、messaging.system
  • 避免保留字符: 键中不应包含 =、&、空格 等 URL 保留字符
  • 统一大小写: 全小写 + 下划线分隔,如 order_id 而非 orderId
  • 避免动态键名: 不要使用用户输入或运行时生成的字符串作为键名,防止基数爆炸
实践建议: 在微服务架构中,建议在服务启动时注册一个属性注入工具函数或装饰器,统一处理属性命名、类型转换与长度校验,避免在每个 Span 中重复编写校验逻辑。

3.5 常见错误与排查

错误场景 现象 解决方案
键名超过 256 字符 属性在导出时被截断或丢失 使用短键名,遵循语义约定
值类型不匹配 SDK 抛出类型错误或静默丢弃 使用 AttributeValue 联合类型进行显式转换
数组元素类型不一致 数组被整体丢弃 确保数组内所有元素类型相同
在 Span 结束后设置属性 属性不会被记录 确保在 span.end() 之前完成属性注入