如何编写语义约定

状态: 开发中

本文档描述了有关如何为新领域定义约定或对现有约定进行重大更改的要求、建议和最佳实践。

定义新约定

  • 新约定**必须**有一组代码所有者。有关更多详细信息,请参阅项目管理
  • 新约定**应**在 YAML 文件中定义。有关详细信息,请参阅语义约定 YAML 模型
  • 新约定**应**以 development 稳定性级别定义。
  • 新约定**应**包含遥测信号定义(Span、Metric、Event、Resource、Profile),并且**可**包含新的属性定义。

最佳实践

注意

本节包含非规范性指南。

请阅读T 型信号,了解如何通过定义约定的关键用例来创建语义约定。

原型设计

强烈建议在一项或多项仪表化中对拟议约定进行原型设计,并

  • 验证收集拟议遥测和属性的可行性,确保信息可用且可以合理地收集,

  • 确认拟议术语适用于约定所涵盖的各种库和技术,

  • 为仪表化作者提供有关何时以及如何收集属性和记录遥测的实际指导,

  • 评估新或更新的遥测如何与其他仪表化层集成,识别差距、重复或改进最终用户体验的机会。

定义属性

尽可能重用现有属性。查阅现有约定以查找类似领域,或查看通用属性。鼓励语义约定作者使用不同命名空间中的属性。

如果满足以下所有条件,请考虑添加新属性:

  • 通过增强遥测,为最终用户带来明确的益处。
  • 在语义约定的 Span、Metric、Event、Resource 或其他遥测信号的定义中有明确的使用计划。
  • 有明确计划说明这些属性将如何被仪表化使用。

如果属性的益处和用例尚不明确,语义约定维护者可能会拒绝添加新属性。

定义新属性时:

  • 遵循命名指南

  • 提供描述性的 briefnote 部分,以清楚地解释属性的含义。

    • 如果属性代表外部文档化的常见概念,请包含相关链接。例如,始终链接到 RFC 或其他标准中定义的概念。

    • 如果属性的值可能包含 PII 或其他敏感信息,请在 note 中明确指出。

      包含类似以下的警告:

        - id: user.full_name
          ...
          note: |
            ...
      
            > [!WARNING]
            >
            > This attribute contains sensitive (PII) information.
      
  • 使用适当的属性类型

    • 如果值有一组合理简短(开放或封闭)的可能值,请将其定义为枚举。
    • 如果值为时间戳,请以 ISO 8601 格式的字符串形式记录。
    • 对于原始值数组,请使用数组类型。避免将数组记录为单个字符串。
    • 数组应是同质的,意味着所有元素共享相同的类型并代表相同的概念。例如:
      • 纬度和经度应定义为单独的属性(geo.latgeo.lon),而不是合并到单个数组中,因为它们代表不同的概念。
    • 使用模板类型来定义具有动态名称的属性(只有名称的最后一个段应该是动态的)。这对于捕获用户定义的键值对(如 HTTP 标头)非常有用。
    • 尽可能将复杂值表示为一组扁平属性。
      • 复杂或结构化属性(未在标准属性集中列出)**只能**在 Event 和 Span 上引用(Development)。

        语义约定作者应假定后端不会为复杂属性的单个属性编制索引,查询或聚合此类属性效率低下且复杂,并且报告复杂属性会带来更高的性能开销。

  • 使用 development 稳定性定义新属性。

  • 提供真实的示例。

  • 避免定义具有潜在无界值(如长度超过 1 KB 的字符串或超过 1,000 个元素的数组)的属性。此类值应记录在日志或事件正文中。

考虑属性的范围以及其未来可能如何演变。

  • 为狭窄用例定义属性时,考虑潜在的更广泛用例。例如,如果创建一个特定于系统的属性,请评估同一领域中的其他系统将来是否需要类似的属性。

    类似地,与其定义一个简单的布尔标志来指示成功或失败,不如考虑一种更具可扩展性的方法,例如使用 foo.status_code 属性来包含其他详细信息。

  • 定义适用于多个域或系统的广泛属性时,请检查行业中是否存在现有标准或被广泛接受的最佳实践。避免创建不基于既定标准的一般性属性。

注意

在为具有多个实现或系统的领域(如数据库或云提供商)定义约定,可能需要时间来在过于通用和不够通用之间取得适当的平衡。

从实验性约定开始,记录它们如何应用于各种提供商、系统或库,并进行仪表化原型设计。

最终用户体验应作为主要指导原则。

  • 如果该属性预计将在该领域的通用指标中使用,请考虑引入一个通用属性。

    例如,大多数消息系统都有类似队列或主题的概念。队列或主题名称对于延迟和吞吐量指标至关重要,对于 Span 调试和可视化消息流同样重要。这表明需要一个通用属性来表示任何类型的消息传递目标。

  • 如果属性在狭窄场景下有用,或者特定于某些系统指标、Span 或事件,则它可能不需要通用。

定义枚举属性成员

枚举属性通常分为三类:

完整枚举记录所有可能的值。例如,cpu.mode 涵盖了所有已知的 CPU 模式。system.cpu.time 等指标的定义依赖于所有模式。作者应预先记录所有已知值,尽管以后可能会添加新值以支持新的操作系统或 CPU 架构。

开放枚举(如 error.type)允许约定和仪表化定义自己的适用值。

系统标识符枚举指定系统、项目、提供商、产品或协议。例如,db.system.name 包含数据库名称,如 mongodbmysql

系统标识符枚举有助于区分遥测信号。MongoDB 和 MySQL 都遵循通用的数据库约定,但填充 db.collection.name 等属性的方式不同,并具有系统特定属性。每个系统都有自己的 Span 定义和文档。请参阅MongoDBMySQL作为示例,并查看特定于系统的命名以获取命名指南。

重要提示

系统标识符枚举不需要列出所有可能的系统、组件或技术。

使用枚举属性的 OpenTelemetry 仪表化**应**在发布**稳定**的工件之前记录其值,并且**可**在不稳定的工件中或通过功能标志支持未记录的值。

只有当你也记录了约定如何应用于该系统时,才定义新的系统标识符。例如,在添加新的 db.system.name 值时,请创建文档和 Span 定义,以显示通用属性如何适用于该数据库。

定义 Span

待定

定义 Metric

待定

定义实体

遵循实体建模指南

定义 Event

待定

稳定现有约定

  • 所有约定**必须**在 YAML 中定义后才能声明为稳定。
  • 未被仪表化使用的约定**不得**声明为稳定。

待办

  • 迁移计划

迁移计划

待办