## OpenTelemetry 

- OpenTelemetry是 CNCF 的一个可观测性项目，旨在提供可观测性领域的标准化方案，解决观测数据的数据模型、采集、处理、导出等的标准化问题，提供与三方 vendor 无关的服务。
- OpenTelemetry 是什么？
    - OpenTelemetry 是一组标准和工具的集合，旨在管理观测类数据，如 trace、metrics、logs 等 (未来可能有新的观测类数据类型出现)。
    - OpenTelemetry 提供与 vendor 无关的实现，根据用户的需要将观测类数据导出到不同的后端，如开源的 Prometheus、Jaeger 或云厂商的服务中。
- OpenTelemetry 不是什么
    - 即 OpenTelemetry 不提供与可观测性相关的后端服务，这类后端服务通常提供的是存储、查询、可视化等服务。
    - 通过下述抽象图可以简单理解 OpenTelemetry 的工作范围：
    - ![png](https://ucc.alicdn.com/pic/developer-ecology/2541b8c5a42e4bffb2fea28926f70715.png)


### 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

––|–––––––|–––––––|–––––––|–––––––|–––––––|–––––––|–––––––|–> time

 [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;
}
    
```
![](http://ser.yinengyun.com:10082/tech/img/uploads/b7890ae31d173aace3a870ea11dd9cad/20221107175920.png)
- [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演示