## OpenTelemetry
- OpenTelemetry是 CNCF 的一个可观测性项目,旨在提供可观测性领域的标准化方案,解决观测数据的数据模型、采集、处理、导出等的标准化问题,提供与三方 vendor 无关的服务。
- OpenTelemetry 是什么?
- OpenTelemetry 是一组标准和工具的集合,旨在管理观测类数据,如 trace、metrics、logs 等 (未来可能有新的观测类数据类型出现)。
- OpenTelemetry 提供与 vendor 无关的实现,根据用户的需要将观测类数据导出到不同的后端,如开源的 Prometheus、Jaeger 或云厂商的服务中。
- OpenTelemetry 不是什么
- 即 OpenTelemetry 不提供与可观测性相关的后端服务,这类后端服务通常提供的是存储、查询、可视化等服务。
- 通过下述抽象图可以简单理解 OpenTelemetry 的工作范围:
- 
### trace
- opentelemetry中的trace由多个span定义,可以将trace视为span的有向无环图, 其中span间的边定义为父/子关系。
```
Causal relationships between Spans in a single Trace
[Span A] ←←←(the root span)
|
+------+------+
| |
[Span B] [Span C] ←←←(Span C is a `child` of Span A)
| |
[Span D] +---+-------+
| |
[Span E] [Span F]
```
- 更直观的查看方式,通过时间轴查看trace
```
Temporal relationships between Spans in a single Trace
[Span A···················································]
[Span B··········································]
[Span D······································]
[Span C····················································]
[Span E·······] [Span F··]
```
- 一个Span代表一个工作或操作单元包含如下字段
- Name
- Parent span ID (empty for root spans)
- Start and End Timestamps
- Span Context
- Attributes
- Span Events
- Span Links
- Span Status
- SpanContext 表示标识跟踪中的 Span 的所有信息
- TraceId 跟踪ID,表示一个跟踪链,需要全局唯一
- SpanId 跨度标识,需要在跟踪链中唯一
- TraceFlags 跟踪标志,用于外部觉得是否需要应用跟踪
- [Tracestate](https://w3c.github.io/trace-context/#tracestate-field) 跟踪状态,分布式跟踪是一组事件,跨应用程序的各个组件进行合并
- Span Links
- span可以链接到零个或多个其他因果相关的span
### Baggage 跨多端采集
- 实现标准 [w3c trace-context](https://www.w3.org/TR/trace-context/)
+ traceparent: 00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01
- version: 2hex 版本
- trace-id: 32hex 应该跟踪ID,全局唯一
- parent-id: 16hex 父spanid
- trace-flags: 2hex 抽样标志 00表示需要记录,01表示采样
+ tracestate(可选)
- 跨不同的分布式跟踪系统提供额外的供应商特定的跟踪标识信息,它还传达有关请求在多个分布式跟踪图中的位置的信息
- 格式:标头名称保持小写。标头名称是一个没有任何分隔符的单词,例如 vendorname1=opaqueValue1,vendorname2=opaqueValue2
### rust 采集演示
``` RUST
fn work() {
let root = tracing::info_span!("child work");
let _enter = root.enter();
}
async fn work_async() {
let root = tracing::info_span!("child work async");
let _enter = root.enter();
}
// 自动创建span方法
#[instrument]
#[inline]
async fn expensive_work() {
tracing::span!(tracing::Level::INFO, "expensive_step_1")
.in_scope(|| thread::sleep(Duration::from_millis(25)));
tracing::span!(tracing::Level::INFO, "expensive_step_2")
.in_scope(|| thread::sleep(Duration::from_millis(25)));
}
#[tokio::test(flavor = "multi_thread")]
async fn test() -> Result<(), Box<dyn Error + Send + Sync + 'static>> {
let root = tracing::info_span!("app_start");
let _enter = root.enter();
// 同步调用
work();
// 异步调用
work_async()
.instrument(tracing::info_span!("child work async root"))
.await;
// 自动创建span方法
expensive_work().await;
}
```

- [instrument官方说明文档](https://tracing-rs.netlify.app/tracing/attr.instrument.html)
### ts 采集演示
```
import { getTrace } from "pi_common/opentelemetry/trace_lib";
let tracer = getTrace();
// Baggage导出
// {"traceparent": "00-277656cdf4562c5892da9925ce98c697-0fa197db81558780-01", "tracestate": ""}
// 还原父span
const parentSpan = tracer.extract(
"http_headers", {
traceparent
});
const span = tracer.startSpan('listener_pid', {
childOf: parentSpan,
});
// 添加属性
span.setTag('alpha', '200');
span.setTag('beta', '50');
// 添加事件
span.log({
state: 'waiting'
});
span.finish();
```
#### 阿里云demo演示