追踪 API
Status: Stable, 除非另有说明
Tracing API 主要由以下组件构成
TracerProvider是 API 的入口点。它提供对Tracer的访问。Tracer负责创建Span。Span是用于跟踪操作的 API。
数据类型
尽管不同语言和平台有不同的数据表示方式,本节定义了此 API 的一些通用要求。
时间
OpenTelemetry 可以处理高达纳秒 (ns) 精度的数值。这些数值的表示方式因语言而异。
时间戳
时间戳是自 Unix 纪元以来的经过时间。
- 最小精度是毫秒。
- 最大精度是纳秒。
持续时间
持续时间是两个事件之间经过的时间。
- 最小精度是毫秒。
- 最大精度是纳秒。
TracerProvider
可以使用 TracerProvider 访问 Tracer。
在 API 的实现中,TracerProvider 应是持有任何配置的状态对象。
通常,TracerProvider 应从中央位置访问。因此,API 应提供一种方法来设置/注册和访问全局默认 TracerProvider。
尽管存在全局 TracerProvider,但某些应用程序可能希望或必须使用多个 TracerProvider 实例,例如为每个实例(从而为其获取的 Tracer)具有不同的配置(如 SpanProcessor),或者因为它们与依赖注入框架更容易集成。因此,TracerProvider 的实现应允许创建任意数量的 TracerProvider 实例。
TracerProvider 操作
TracerProvider 必须提供以下功能
- 获取
Tracer
获取 Tracer
此 API 必须接受以下参数
name(必需): 此名称应唯一标识 instrumentation scope,例如 instrumentation library(例如io.opentelemetry.contrib.mongodb)、包、模块或类名。如果应用程序或库具有内置的 OpenTelemetry instrumentation,则 Instrumented library 和 Instrumentation library 可能指向同一个库。在这种情况下,name表示该库或应用程序中的模块名称或组件名称。如果指定了无效名称(null 或空字符串),则必须返回一个工作的 Tracer 实现作为回退,而不是返回 null 或抛出异常,其name属性应设置为 **空** 字符串,并应记录一条报告指定值无效的消息。如果某个库实现了 OpenTelemetry API 并且不支持“命名”功能(例如,一个甚至不相关的可观察性实现),它也可以忽略此名称并为所有调用返回一个默认实例。如果应用程序所有者配置 SDK 来抑制此库产生的遥测数据,TracerProvider 也可以在此处返回一个 no-op Tracer。version(可选): 指定 instrumentation scope 的版本(如果 scope 有版本)(例如,库版本)。示例值:1.0.0。- [since 1.4.0]
schema_url(可选): 指定在发出的遥测数据中应记录的 Schema URL。 - [since 1.13.0]
attributes(可选): 指定要与发出的遥测数据关联的 instrumentation scope 属性。
术语“相同”用于描述所有参数都相等的 Tracer 实例。术语“不同”用于描述至少有一个参数值不同的 Tracer 实例。
实现不得要求用户重复获取具有相同标识的 Tracer 以便应用配置更改。这可以通过允许使用过时的配置来完成,或者确保新的配置也适用于先前返回的 Tracer。
注意:这可以例如通过将任何可变配置存储在 TracerProvider 中,并让 Tracer 实现对象引用它们从中获取的 TracerProvider 来实现。如果必须为每个 tracer 存储配置(例如,禁用某个 tracer),tracer 可以例如在 TracerProvider 的映射中查找其标识,或者 TracerProvider 可以维护所有返回的 Tracer 的注册表并主动更新其配置(如果发生更改)。
上下文交互
本节定义了 Tracing API 中所有与 Context 交互的操作。
API 必须提供以下功能与 Context 实例进行交互
- 从
Context实例中提取Span - 将
Span与Context实例组合,创建一个新的Context实例
上述功能是必需的,因为 API 用户不应访问 Tracing API 实现使用的 Context Key。
如果语言支持隐式传播 Context(参见 此处),API 还应提供以下功能
- 从隐式上下文中获取当前活动的 span。这等同于获取隐式上下文,然后从上下文中提取
Span。 - 将当前活动的 span 设置到新的上下文中,并使其成为隐式上下文。这等同于将当前隐式上下文的值与
Span组合以创建新的上下文,然后使其成为当前隐式上下文。
以上所有功能仅对上下文 API 进行操作,它们可以作为 trace 模块的静态方法,或作为 trace 模块内某个类的静态方法公开。此功能应在可能的情况下完全在 API 中实现。
Tracer
tracer 负责创建 Span。
请注意,Tracer 通常不应负责配置。这应由 TracerProvider 负责。
Tracer 操作
Tracer 必须提供以下功能
- 创建新的
Span(参见Span部分)
Tracer 应提供以下功能
Enabled
状态: 开发中
为了帮助用户避免在创建 Span 时执行计算成本高昂的操作,Tracer 应提供此 Enabled API。
目前此 API 没有必需参数。未来可以添加参数,因此 API 必须以一种可以添加参数的方式进行构建。
此 API 必须返回一种惯用的语言布尔类型。返回 true 表示 Tracer 对提供的参数已启用,返回 false 表示 Tracer 对提供的参数已禁用。
返回值并非总是静态的,它可能随时间变化。API 应记录,以确保获得最新响应,仪表化作者每次 创建新 Span 时都需要调用此 API。
SpanContext
SpanContext 代表 Span 的一部分,该部分必须被序列化并与分布式上下文一起传播。SpanContext 是不可变的。
OpenTelemetry SpanContext 表示符合 W3C TraceContext 规范。它包含两个标识符 - TraceId 和 SpanId - 以及一组通用的 TraceFlags 和系统特定的 TraceState 值。
TraceId 有效的跟踪标识符是至少有一个非零字节的 16 字节数组。
SpanId 有效的 span 标识符是至少有一个非零字节的 8 字节数组。
TraceFlags 包含有关跟踪的详细信息。与 TraceState 值不同,TraceFlags 在所有跟踪中都存在。当前版本的规范支持两个标志
TraceState 包含特定于跟踪系统的跟踪标识数据,表示为键值对列表。TraceState 允许多个跟踪系统参与同一跟踪。它在 W3C Trace Context 规范 中有完整描述。有关 TraceState 中特定的 OpenTelemetry 值,请参阅 TraceState Handling 文档。
IsRemote,一个布尔值,指示 SpanContext 是从外部接收的还是本地生成的,请参阅 IsRemote。
API 必须实现创建 SpanContext 的方法。这些方法应该是创建 SpanContext 的唯一方式。此功能必须在 API 中完全实现,并且不应被覆盖。
检索 TraceId 和 SpanId
API 必须允许以以下形式检索 TraceId 和 SpanId
- Hex - 返回小写 hex 编码 的
TraceId(结果必须是 32 个十六进制字符的小写字符串)或SpanId(结果必须是 16 个十六进制字符的小写字符串)。 - Binary - 返回
TraceId的二进制表示(结果必须是 16 字节数组)或SpanId(结果必须是 8 字节数组)。
API 不应暴露其内部存储方式的细节。
IsValid
必须提供一个名为 IsValid 的 API,它返回一个布尔值,如果 SpanContext 具有非零 TraceID 和非零 SpanID,则返回 true。
IsRemote
必须提供一个名为 IsRemote 的 API,它返回一个布尔值,如果 SpanContext 是从远程父级传播过来的,则返回 true。通过 Propagators API 提取 SpanContext 时,IsRemote 必须返回 true,而对于任何子 span 的 SpanContext,它必须返回 false。
TraceState
TraceState 是 SpanContext 的一部分,由不可变的字符串键值对列表表示,并由 W3C Trace Context 规范 正式定义。Tracing API 必须在 TraceState 上提供至少以下操作
- 获取给定键的值
- 添加新的键/值对
- 更新给定键的现有值
- 删除键/值对
这些操作必须遵循 W3C Trace Context 规范 中描述的规则。所有更改操作都必须返回一个应用了修改的新 TraceState。TraceState 必须始终根据 W3C Trace Context 规范 中指定的规则进行验证。每个更改操作都必须验证输入参数。如果传入无效值,操作不得返回包含无效数据的 TraceState,并且必须遵循 通用错误处理指南。
请注意,由于 SpanContext 是不可变的,因此无法用新的 TraceState 更新 SpanContext。这些更改仅在 SpanContext propagation 或 遥测数据导出 之前才有意义。在这两种情况下,Propagator 和 SpanExporter 都可以在序列化到线路上之前创建修改后的 TraceState 副本。
Span
Span 代表跟踪中的单个操作。Span 可以嵌套形成一个跟踪树。每个跟踪包含一个根 span,它通常描述整个操作,以及可选的一个或多个子 span 表示其子操作。
Span 封装
- span 名称
- 一个不可变的
SpanContext,唯一标识Span - 一个父 span,形式为
Span、SpanContext或 null - 一个
SpanKind - 开始时间戳
- 结束时间戳
Attributes- 指向其他
Span的Link列表 - 一系列带时间戳的
Event - 一个
Status。
span 名称 简洁地标识 Span 所代表的工作,例如,RPC 方法名、函数名,或较大计算中子任务或阶段的名称。span 名称应是有意义的(在统计上)“Span 类”的通用字符串,而不是单个 Span 实例,同时仍然易于人类阅读。也就是说,“get_user”是一个合理的名称,而“get_user/314159”(其中“314159”是用户 ID)则不是一个好的名称,因为它具有很高的基数。通用性应优先于人类可读性。
例如,以下是一个用于获取假设账户信息的端点的潜在 span 名称
| Span 名称 | 指南 |
|---|---|
get | 太笼统 |
get_account/42 | 太具体 |
get_account | 好,并且 account_id=42 会是一个不错的 Span 属性 |
get_account/{accountId} | 也很好(使用“HTTP 路由”) |
Span 的开始和结束时间戳反映了操作经过的实际时间。
例如,如果一个 span 代表一个请求-响应周期(例如 HTTP 或 RPC),则 span 应具有一个对应于第一个子操作开始时间的开始时间,以及一个对应于最后一个子操作完成时间的结束时间。这包括
- 接收请求数据
- 解析数据(例如,从二进制或 json 格式)
- 任何中间件或额外的处理逻辑
- 业务逻辑
- 构造响应
- 发送响应
子 span(或在某些情况下是事件)可以被创建来表示需要更详细可观察性的子操作。子 span 应衡量各自子操作的时间,并可能添加额外的属性。
Span 的开始时间应在 span 创建时设置为当前时间。创建 Span 后,应可以更改其名称、设置其 Attribute、添加 Event 并设置 Status。这些在 Span 的结束时间设置后不得更改。
Span 不应被用于在进程内传播信息。为了防止滥用,实现不应提供对 Span 属性的访问,除了其 SpanContext。
供应商可以实现 Span 接口以实现供应商特定的逻辑。但是,替代实现不得允许调用者直接创建 Span。所有 Span 都必须通过 Tracer 创建。
Span 创建
除了使用 Tracer 创建 Span 之外,不得提供任何其他 API。
在支持隐式 Context 传播的语言中,Span 创建默认情况下不得将新创建的 Span 设置为 当前 Context 中的活动 Span,但此功能可以作为单独的操作另外提供。
API 必须接受以下参数
Span 名称。这是一个必需参数。
父
Context或表示新Span应该是根Span的指示。API 也可以有一个选项,作为默认行为,使用当前 Context 作为父级。此 API 不得接受Span或SpanContext作为父级,只能接受完整的Context。Span 的语义父级必须根据 从 Context 确定父 Span 中描述的规则来确定。
SpanKind,如果未指定,默认为SpanKind.Internal。Attributes。此外,这些属性可用于做出采样决策,如 采样描述中所述。如果未指定,则假定为空集合。API 文档必须说明,在 span 创建时添加属性比稍后调用
SetAttribute更可取,因为采样器只能考虑在 span 创建时已存在的信息。Links - 链接的有序序列,参见 API 定义。开始时间戳,默认为当前时间。仅当 span 创建时间已过时才应设置此参数。如果 API 在 Span 逻辑开始时被调用,API 用户不得显式设置此参数。
每个 span 有零个或一个父 span,以及零个或多个子 span,它们代表因果相关的操作。一组相关的 span 构成一个跟踪。如果 span 没有父级,则称其为根 span。每个跟踪包含一个根 span,它是跟踪中所有其他 span 的共享祖先。实现必须提供将 Span 创建为根 span 的选项,并且必须为每个创建的根 span 生成新的 TraceId。对于带有父级的 Span,TraceId 必须与父级相同。此外,子 span 默认必须继承其父级的全部 TraceState 值。
如果 span 是在另一个进程中创建的 Span 的子级,则该 span 被称为具有远程父级。每个 propagators 的反序列化必须在父 SpanContext 上将 IsRemote 设置为 true,以便 Span 创建知道父级是否是远程的。
创建的任何 span 都必须被结束。这是用户的责任。如果用户忘记结束 span,API 实现可能会泄漏内存或其他资源(包括,例如,用于迭代所有 span 的定期工作的 CPU 时间)。
从 Context 确定父 Span
当从 Context 创建新 Span 时,Context 可能包含一个代表当前活动实例的 Span,并将被用作父级。如果 Context 中没有 Span,则新创建的 Span 将是一个根 span。
SpanContext 不能直接设置为 Context 中的活动项,而是通过 将其包装到 Span 中。例如,执行上下文提取的 Propagator 可能需要此功能。
指定 links
在 Span 创建期间,用户必须能够记录到其他 Span 的链接。链接的 Span 可以来自同一跟踪或不同跟踪 - 请参阅 links。在 Span 创建时添加的 Links 可能会被 Samplers 考虑以做出采样决策。
Span 操作
除了检索 Span 的 SpanContext 和 IsRecording 的函数外,以下任何函数在 Span 完成后都不得调用。
Get Context
Span 接口必须提供
- 一个返回给定
Span的SpanContext的 API。即使Span完成后,返回的值也可以被使用。返回的值在整个 Span 的生命周期内必须相同。这可以称为GetContext。
IsRecording
当通过 SetAttributes、AddEvent、SetStatus 等函数提供数据时,Span 会进行记录(IsRecording 返回 true),这些数据会以某种形式(例如,内存中)被捕获。当 Span 不记录时(IsRecording 返回 false),所有这些数据都会立即被丢弃。后续的设置或添加数据的尝试将不会被记录,从而使 span 实际上成为一个 no-op。
即使整个跟踪未被采样,此标志也可能为 true。这允许记录和处理单个 Span 的信息,而无需将其发送到后端。这种情况的一个例子可能是记录和处理所有传入请求,用于处理和构建 SLA/SLO 延迟图,同时只将一部分 - 采样的 span - 发送到后端。另请参阅 SDK 设计的 采样部分。
Span 结束后,它应变为非记录状态,并且 IsRecording 应始终返回 false。唯一已知的例外是 API 的流式实现,它们不保留本地状态,并且在结束 span 后无法更改 IsRecording 的值。
IsRecording 不应接受任何参数。
此标志应用于避免在 Span 肯定不会被记录时进行昂贵的 Span 属性或事件计算。请注意,任何子 span 的记录都独立于此标志的值来确定(通常基于 TraceFlags 在 SpanContext 上的 sampled 标志)。
API 用户在仪表化代码时应只访问 IsRecording 属性,并且除非在上下文传播器中使用,否则永远不要访问 SampledFlag。
Set Attributes
Span 必须能够设置与之关联的 Attributes。
Span 接口必须提供
- 一种设置单个
Attribute的 API,其中属性属性作为参数传递。这可以称为SetAttribute。为了避免额外的内存分配,某些实现可以为每种可能的值类型提供单独的 API。
Span 接口可以提供
- 一种一次设置多个
Attributes的 API,其中Attributes在一次方法调用中传递。
设置具有与现有属性相同键的属性应覆盖现有属性的值。
请注意,OpenTelemetry 项目记录了某些 “标准属性”,这些属性具有指定的语义含义。
请注意,Samplers 只能考虑在 span 创建时已存在的信息。此后所做的任何更改,包括新的或更改的属性,都无法改变其决策。
Add Events
Span 必须能够添加事件。事件具有与其添加到 Span 的时间相关的时间戳。
Event 的结构由以下属性定义
- 事件名称。
- 事件的时间戳。可以是事件添加时的时间,也可以是用户提供的自定义时间戳。
- 零个或多个
Attributes,进一步描述事件。
Span 接口必须提供
- 一种记录单个
Event的 API,其中Event属性作为参数传递。这可以称为AddEvent。此 API 接受事件的名称、可选的Attributes和可选的Timestamp,可用于指定事件发生的时间,可以作为单独的参数或作为封装它们的不可变对象,无论哪种最适合语言。如果用户未提供自定义时间戳,则实现会自动在事件上设置调用此 API 的时间。
事件应保留其记录的顺序。这通常会匹配事件时间戳的顺序,但事件可能使用自定义时间戳乱序记录。
消费者应注意,事件的时间戳可能早于 span 的开始时间或晚于 span 的结束时间,如果用户为事件或在开始或结束 span 时提供了自定义时间戳。规范不要求对超出范围的提供的时间戳进行任何规范化。
请注意,OpenTelemetry 项目记录了某些 “标准事件名称和键”,这些名称和键具有指定的语义含义。
请注意,RecordException 是 AddEvent 的一种特殊变体,用于记录异常事件。
Add Link
Span 必须能够在创建后向其添加 Links(参见 Links)。创建 Span 后添加的 Links 可能不会被 Samplers 考虑。
Set Status
设置 Span 的 Status。如果使用,这将覆盖默认的 Span 状态,即 Unset。
Status 的结构由以下属性定义
StatusCode,下面列出的值之一。- 可选的
Description,提供Status的描述性消息。Description仅与ErrorStatusCode值一起使用。空Description等同于不存在的描述。
注意:OTLP 协议定义将 Description 属性称为 message。
StatusCode 是以下值之一
Unset- 默认状态。
Ok- 应用程序开发人员或操作员已验证操作成功完成。
Error- 操作包含错误。
这些值形成一个全序:Ok > Error > Unset。这意味着,使用 StatusCode=Ok 设置 Status 将覆盖任何先前或将来的尝试使用 StatusCode=Error 或 StatusCode=Unset 来设置 span Status 的行为。有关更具体的规则,请参见下文。
Span 接口必须提供
- 一种设置
Status的 API。这应称为SetStatus。此 API 接受StatusCode和可选的Description,作为单独的参数或作为封装它们的不可变对象,无论哪种最适合语言。对于StatusCodeOk&Unset值,Description必须被忽略。
状态码应保持未设置,除非在以下情况下
尝试设置值 Unset 应被忽略。
当状态被 Instrumentation Libraries 设置为 Error 时,Description 应被记录并可预测。状态码仅应根据语义约定中定义的规则设置为 Error。对于语义约定未涵盖的操作,Instrumentation Libraries 应发布自己的约定,包括 Description 的可能值及其含义。
通常,Instrumentation Libraries 不应将状态码设置为 Ok,除非明确配置。Instrumentation Libraries 应将状态码保留为 Unset,除非发生错误,如上所述。
应用程序开发者和操作员可以设置状态码为 Ok。
当 span 状态设置为 Ok 时,它应被视为最终状态,任何进一步更改它的尝试都应被忽略。
分析工具在响应 Ok 状态时应抑制它们否则会生成的任何错误。例如,以抑制 404 等嘈杂的错误。
仅最后一次调用的值将被记录,实现可以忽略之前的调用。
UpdateName
更新 Span 的名称。更新后,任何基于 Span 名称的采样行为将取决于实现。
请注意,采样器只能考虑在 span 创建时已存在的信息。之后进行的任何更改,包括更新的 span 名称,都无法改变其决定。
名称更新的替代方案可能是在 span 创建后期,当 Span 以过去的显式时间戳开始,并且最终的 Span 名称已知时;或者将具有所需名称的 Span 报告为子 Span。
必需参数
- 新的span 名称,它将取代
Span启动时传递的任何名称
End
指示此 span 描述的操作已结束(或在可选指定的过去时间结束)。
实现应忽略后续所有对 End 和其他 Span 方法的调用,即 Span 在结束时变为不可记录(当 Tracer 流式传输事件且 Span 没有关联的可变状态时可能存在例外)。
语言 SIGs 可能会在 API 中提供除 End 之外的其他方法来结束 span,以支持 Python 中的 with 语句等特定于语言的功能。但是,此类方法的所有 API 实现都必须在内部调用 End 方法,并应有文档记录。
End 对子 spans 没有任何影响。它们可能仍在运行,并且可以稍后结束。
End 不得激活 Span 在其活动的任何 Context 中。通过 Context 仍然可以使用已结束的 span 作为父 span。此外,将 Span 放入 Context 的任何机制在 Span 结束后仍然有效。
参数
- (可选) 用于显式设置结束时间戳的时间戳。如果省略,则必须将其视为当前时间。
期望此操作在生产应用程序的“热路径”中被调用。它需要被设计成快速完成,如果不是立即完成的话。此操作本身不得在调用线程上执行阻塞 I/O。使用的任何锁定都需要最小化,并应尽可能完全删除。从此操作调用的某些下游 SpanProcessors 和后续 SpanExporters 可能用于测试、概念验证或调试,它们本身可能并非为生产使用而设计。它们不属于此要求和建议的范围。
Record Exception
为了方便记录异常,如果语言使用异常,则应提供 RecordException 方法。这是 AddEvent 的一个专门变体,因此对于此处未指定的任何内容,都适用与 AddEvent 相同的要求。
该方法的签名由每种语言确定,并可根据需要进行重载。该方法必须将异常记录为 Event,并遵循 exceptions 文档中概述的约定。所需的最少参数不应超过异常对象。
如果提供了 RecordException,该方法必须接受一个可选参数以提供任何附加的事件属性(这应该以与 AddEvent 方法相同的方式完成)。如果同名的属性已由该方法生成,则附加属性具有优先权。
注意:RecordException 可被视为 AddEvent 的变体,带有额外的异常特定参数,而所有其他参数都是可选的(因为它们具有异常语义约定中的默认值)。
Span lifetime
Span lifetime 代表将开始和结束时间戳记录到 Span 对象的过程。
- 开始时间在 Span 创建时记录。
- 结束时间需要在操作结束时记录。
开始和结束时间以及 Event 的时间戳必须在调用相应 API 时记录。
Wrapping a SpanContext in a Span
API 必须提供一个将 SpanContext 包装到实现 Span 接口的对象中的操作。这是为了在进程内 Span 传播等操作中公开 SpanContext 作为 Span。
如果为了支持此操作需要一种新类型,则应尽可能不公开它(例如,只公开一个返回具有 Span 接口类型的对象的函数)。如果需要公开新类型,则应将其命名为 NonRecordingSpan。
行为定义如下:
GetContext必须返回包装的SpanContext。IsRecording必须返回false,以表明事件、属性和其他元素未被记录,即它们被丢弃。
Span 的其余功能必须定义为 no-op 操作。注意:这包括 End,因此作为一般规则的例外,不需要(甚至没有帮助)结束这样的 Span。
此功能必须在 API 中完全实现,并且不应被覆盖。
SpanKind
SpanKind 阐明了通过父/子关系或 span 链接而关联的 Spans 之间的关系。SpanKind 描述了两个独立的属性,这些属性在分析过程中对跟踪系统有益。
- Span 是表示对远程服务的出站调用(
CLIENT和PRODUCERspans)还是表示对外部发起的传入请求的处理(SERVER和CONSUMERspans)。 - Span 是否表示请求/响应操作(
CLIENT和SERVERspans)还是延迟执行(PRODUCER和CONSUMERspans)。
为了使 SpanKind 有意义,调用者应确保单个 Span 不服务于多个目的。例如,服务器端 span 不应用于描述出站远程过程调用。作为简单的指导,instrumentation 应在注入远程出站调用的 SpanContext 之前创建新的 Span。
注意:CLIENT span 可能有一个子 span,该子 span 也是 CLIENT span;或者 PRODUCER span 可能有一个本地子 span,该子 span 是 CLIENT span,具体取决于提供功能的各种组件的构建和 instrumention 方式。
语义约定为特定技术应记录它们定义的每个 span 的 kind。
例如,Database Client Semantic Conventions 建议使用 CLIENT span kind 来描述数据库调用。如果数据库客户端通过 HTTP 与服务器通信,则 HTTP instrumentation(启用时)会创建嵌套的 CLIENT spans 来跟踪逻辑数据库 CLIENT 操作范围内的单个 HTTP 调用。
以下是可能的 SpanKind:
SERVER表示 span 覆盖了远程请求的服务器端处理,而客户端等待响应。CLIENT表示 span 描述了对远程服务的请求,客户端等待响应。当CLIENTspan 的上下文被传播时,CLIENTspan 通常成为远程SERVERspan 的父 span。PRODUCER表示 span 描述了本地或远程操作的启动或调度。此启动 span 通常在相关的CONSUMERspan 之前结束,甚至可能在CONSUMERspan 开始之前结束。在具有批处理的消息传递场景中,跟踪单个消息需要为每个消息创建新的
PRODUCERspan。CONSUMER表示 span 代表由生产者发起的(一个)操作的处理,生产者不等待结果。INTERNAL默认值。表示 span 代表应用程序内部的操作,而不是具有远程父项或子项的操作。
总结这些 kind 的解释:
SpanKind | 调用方向 | 通信风格 |
|---|---|---|
CLIENT | outgoing | request/response |
SERVER | incoming | request/response |
PRODUCER | outgoing | deferred execution |
CONSUMER | incoming | deferred execution |
INTERNAL |
Link
用户必须能够记录指向其他 SpanContext 的链接。链接的 SpanContext 可以来自同一个跟踪或不同的跟踪 - 请参阅 Links between spans。
Link 在结构上由以下属性定义:
- 要链接到的
Span的SpanContext。 - 零个或多个
Attributes,用于进一步描述链接。
API 必须提供:
- 一个记录单个
Link的 API,其中Link属性作为参数传递。这可以称为AddLink。此 API 接受要链接到的Span的SpanContext和可选的Attributes,可以作为单独的参数或作为封装它们的不可变对象传递,具体取决于最适合语言的方式。实现应记录包含SpanContext的链接,其中TraceId或SpanId为空(全零),只要属性集或TraceState非空。
Span 接口可以提供
- 一个一次性添加多个
Link的 API,其中Link在一次方法调用中传递。
Span 应保持 Link 设置的顺序。
API 文档必须说明,对于在 span 创建期间可用的上下文,在 span 创建时添加链接优于稍后调用 AddLink,因为头部采样决策只能考虑在 span 创建期间存在的信息。
Concurrency
对于支持并发执行的语言,Tracing API 提供了特定的保证和安全性。并非所有 API 函数都可以安全地并发调用。
TracerProvider - 所有方法都可以安全地并发调用。
Tracer - 所有方法都可以安全地并发调用。
Span - Span 的所有方法都可以安全地并发调用。
Event - Events 是不可变的,可以安全地并发使用。
Link - Links 是不可变的,可以安全地并发使用。
Included Propagators
有关 propagators 如何分发,请参阅 Propagators Distribution。
Behavior of the API in the absence of an installed SDK
通常,在没有安装 SDK 的情况下,Trace API 是一个“no-op”API。这意味着 Tracer 或 Spans 上的操作应无副作用且不做任何事情。然而,这个通用规则有一个重要的例外,它与 SpanContext 的传播有关:API 必须返回一个非记录的 Span,其中 SpanContext 位于父 Context 中(无论是显式给出还是隐式当前)。如果父 Context 中的 Span 已经是不可记录的,则应直接返回它,而不实例化新的 Span。如果父 Context 中没有 Span,则必须返回一个空的非记录 Span(即,具有所有零 Span 和 Trace ID 的 SpanContext,空的 Tracestate,以及未采样的 TraceFlags)。这意味着由已配置的 Propagator 提供的 SpanContext 将会传播到任何子 span,并最终也传播到 Inject,但不会创建新的 SpanContext。