宣布支持 OTel 中的复杂属性类型

在遥测数据中,使用简单的键值对作为属性是很常见的。大多数遥测后端都针对这种模式进行了优化,使其能够高效地存储、索引和查询数据。

OpenTelemetry 在设计时就考虑到了这一点。语义约定和仪器化旨在提供有用的属性,这些属性可以轻松地进行过滤和聚合。

但是,当数据本身很复杂时会发生什么?OpenTelemetry 还致力于捕捉真实世界系统、库和应用程序的可观测性,这些系统的可观测属性有时会很复杂。

最近,OpenTelemetry 宣布将在所有 OTel 信号中支持捕获复杂数据,首先是 OTLP 1.9.0,未来还将在整个生态系统的 OpenTelemetry API 和 SDK 版本中支持。

在本文中,我们将介绍何时以及如何使用复杂数据,何时避免使用,以及后端如何开始支持它们。

即将支持 OpenTelemetry 中的复杂属性类型

OpenTelemetry API 和 SDK 将在所有信号上添加对以下属性类型的支持

  • Map(键为字符串,值为任何支持的类型)
  • 异构数组(包含任何支持类型的元素)
  • 字节数组
  • 空值

直到最近,这些类型仅在日志中受支持——其他信号上的属性仅限于原始类型和原始类型数组。

遵循 OTEP 4485:扩展属性以支持复杂值 及其在 OTLP 和规范中的实现,这种支持将被扩展到所有 OTel 信号。

新的属性类型,尤其是 Map 和异构数组,应谨慎使用。许多可观测性后端并未针对查询、索引或聚合复杂属性进行优化。语义约定将假定复杂属性未被索引,并将避免在指标或其他需要高效查询的场景中使用它们。

尽可能坚持使用原始值。

我们为什么要这样做?

在我们进行语义约定和仪器化工作时,我们越来越多地遇到扁平属性无法合理地捕获真实世界场景复杂性的情况。

例如

在将复杂属性的支持扩展到所有信号之前,我们探索了几种替代方案

将支持限制在日志(和 Span)

为不同信号设置不同的属性收集类型会影响 API 的易用性,使处理属性变得不那么方便和高效。

扁平化

扁平化对于原始类型的 Map 效果很好,但对于数组则会失效。例如,结构化数据如

{
  "data": [
    {
      "foo": "bar",
      "baz": 42
    }
  ]
}

被报告为

data.0.foo = "bar"
data.0.baz = 42

data.foo = ["bar"]
data.baz = [ 42 ]

这两种方法都有限制,并且会导致糟糕的用户体验。

字符串序列化

另一个选项是要求用户或仪器化将复杂数据序列化为字符串。虽然可行,但这会带来不一致和错误的风险。它还会限制后续处理并导致糟糕的截断策略。最终,是否保留结构或序列化数据应由后端决定。在后端处理序列化可以为最终用户提供更大的一致性和便利性。

后端应如何支持复杂属性?

我们鼓励后端构建利用结构化属性值的用户体验,允许用户基于嵌套属性查询数据。

同时,我们建议后端在摄取时将复杂属性序列化为 JSON(或其他合适的格式)。

OTel 规范、语义约定和 API 文档将清楚地向仪器化作者传达,复杂属性支持可能有限,并将继续建议尽可能使用扁平属性。

何时应使用复杂属性?

当您可以使用扁平属性合理地表达数据时,请使用扁平属性。

仅当数据过于复杂而无法用扁平属性表达时,才使用复杂属性——例如,在记录复杂对象列表时。

对于语义约定和仪器化库,我们不建议针对此公告更改现有内容。这仅应影响需要使用复杂属性的新功能。

评论?

我们已在 GitHub issue 中讨论此博文,我们非常欢迎您的反馈。