本文基于 Opentelemetry JS 语言的实现,梳理了其对 OTEL 的具体实现,方便深入理解 OTEL 的工作原理,便于日常项目中的可观测性数据上报和自定义的三方 instrumentation 组件开发。

1. API

1.1 API 结构梳理

API 模块提供了 context、metrics、trace、propagation 等核心功能的 API 定义,以及它们的默认实现。

image.png

1.2 API 具体实现

1
├── api
│   ├── context.ts # 维护一个 ContextAPI 单例对象 context,提供全局 context 的设置、访问等方法
│   ├── diag.ts    # 维护一个 DiagAPI 单例对象 diag,提供全局诊断日志的管理
│   ├── metrics.ts # 维护一个 MetricsAPI 单例对象 metrics,提供全局 MeterProvider 管理、Meter 创建功能
│   ├── propagation.ts # 维护一个 PropagationAPI 单例对象 propagation
		       # 提供全局 propagator 的设置、inject、extract 方法、Baggage 相关方法
│   └── trace.ts   # 维护一个 TraceAPI 单例对象 trace,提供全局 TracerProvider 的管理、Tracer创建功能
├── baggage        #【具体实现】baggage,由 propagation.ts 调用
│   ├── context-helpers.ts # 操作 baggage 在 context 中读写的工具函数
│   ├── internal
│   │   ├── baggage-impl.ts # baggage 具体实现
│   │   └── symbol.ts # 数据类型 symbol 标记
│   ├── types.ts      # Baggage 相关接口定义,baggage-impl.ts 实现了 Baggage 接口
│   └── utils.ts      # 提供出口方法 createBaggage、baggageEntryMetadataFromString
├── common            # 一些基础类型定义
│   ├── Attributes.ts # 属性类型
│   ├── Exception.ts  # 异常类型
│   └── Time.ts       # 时间类型
├── context           # context 相关实现
│   ├── NoopContextManager.ts # 默认的 NoopContextManager implements types.ContextManager
			      # 第一次 active 时返回 ROOT_CONTEXT
│   ├── context.ts            # 默认的 BaseContext implements Context,提供一个实例作为 ROOT_CONTEXT
│   └── types.ts              # Context、ContextManager 接口定义
├── diag                      # 诊断日志相关实现
│   ├── ComponentLogger.ts    # 日志组件 logger
│   ├── consoleLogger.ts      # 控制台 logger
│   ├── internal
│   │   ├── logLevelLogger.ts # 根据现有 logger 创建限制输出级别的 logger
│   │   └── noopLogger.ts     # 未设置任何 logger 时的 no operation logger,啥也不干
│   └── types.ts              # DiagLogger、DiagLoggerApi 接口定义
├── internal # 内部公共能力模块
│   ├── global-utils.ts # 根据 platform 获取并维护一个全局对象
			# 含 DiagLogger、TracerProvider、ContextManager、
		        # MeterProvider、TextMapPropagator
			# 并提供 get、register、unregister 等函数
│   └── semver.ts # 提供一个semver版本兼容性判断函数,输入版本号,输出当前api是否支持此版本号
├── metrics                   # metrics 相关接口定义和默认实现
│   ├── Meter.ts              # Meter 接口定义,含各类指标的创建等方法定义
│   ├── MeterProvider.ts      # MeterProvider 接口定义,里边就一个 getMeter 方法
│   ├── Metric.ts             # 各类指标和指标选项定义,如 Histogram、Counter 等
│   ├── NoopMeter.ts          # 默认的 Meter 实现,各类方法都返回一个啥也不干的指标对象
│   ├── NoopMeterProvider.ts  # 默认的 MeterProvider 实现,getMeter 返回 NoopMeter 对象
│   └── ObservableResult.ts   # ObservableResult、BatchObservableResult 接口定义
├── platform # 根据不同平台获取 global 对象
│   ├── browser # 浏览器环境获取 global
│   │   ├── globalThis.ts
│   │   └── index.ts
│   ├── index.ts # 默认返回 node 环境 global
│   └── node # node 环境获取 global
│       ├── globalThis.ts
│       └── index.ts
├── propagation                    # propagation 相关接口定义和默认实现
│   ├── NoopTextMapPropagator.ts   # 默认的 TextMapPropagator 实现,啥也不干
│   └── TextMapPropagator.ts       # TextMapPropagator 接口定义,提供 inject /extract 方法
├── trace                            # trace 相关接口和默认实现
│   ├── internal
│   │   ├── tracestate-impl.ts       # 一个实现 TraceState 接口的 TraceStateImpl,提供设置/读取
				     # 序列化、反序列化等方法 
│   │   ├── tracestate-validators.ts # 提供 TraceState 的key/value合法性校验方法(正则)
│   │   └── utils.ts                 # 基于 TraceStateImp 包装 createTraceState 函数并导出
│   ├── NonRecordingSpan.ts          # 默认的 Span 实现,一个啥也不干的 Span 类实现
│   ├── NoopTracer.ts                # 默认的 Tracer 实现,返回 NonRecordingSpan
│   ├── NoopTracerProvider.ts        # 默认的 TracerProvider 实现,返回 NoopTracer
│   ├── ProxyTracer.ts               # 代理 Tracer,可以传入 TracerDelegator 对象代理其他 Tracer
│   ├── ProxyTracerProvider.ts       # 代理 TracerProvider,可以代理另一个 TracerProvider
│   ├── Sampler.ts                   # Sampler 采样器接口定义,提供 shouldSample 方法
│   ├── SamplingResult.ts            # SamplingResult 采样结果接口定义,含是否记录结果
│   ├── SpanOptions.ts               # startSpan 传入的选项
│   ├── attributes.ts              # 对 ../common/Attributes 中的属性导出
│   ├── context-utils.ts           # 封装从 content 中增删改查 span 的方法
│   ├── invalid-span-constants.ts  # 实现默认的非法 SpanContext
│   ├── link.ts                    # Link 接口定义
│   ├── span.ts                    # Span 接口定义
│   ├── span_context.ts            # SpanContext 接口定义,是 Span 的一个属性,含 spanid、traceid等
│   ├── span_kind.ts               # SpanKind 枚举 
│   ├── spancontext-utils.ts       # 提供 SpanContext 合法性判断相关方法
                                   # 提供 wrapSpanContext 基于 SpanContext 创建一个 Span 对象
│   ├── status.ts                  # SpanStatus 接口,含 code、message 属性
│   ├── trace_flags.ts             # TraceFlags 枚举
│   ├── trace_state.ts             # TraceState 接口定义,含设置、获取、序列化等方法
│   ├── tracer.ts                  # Tracer 接口定义,含 startSpan、startActiveSpan 方法
│   ├── tracer_options.ts          # TracerOptions 接口定义
│   └── tracer_provider.ts         # TracerProvider 接口定义,含 getTracer 方法
├── context-api.ts            # 导出 ContextAPI 实例(/api/context.ts)
├── diag-api.ts               # 导出 DiagAPI 实例(/api/diag.ts)
├── index.ts                  # 全局出口
├── metrics-api.ts            # 导出 MetricsAPI 实例(/api/metrics)
├── propagation-api.ts        # 导出 PropagationAPI 实例(/api/propagation)
└── trace-api.ts              # 导出 TraceAPI 实例(/api/trace)

其中内容比较多的 trace 模块结构:

trace uml

2. 稳定阶段模块

2.1 稳定阶段模块结构梳理

image.png

模块列表:

1
packages
├── opentelemetry-context-async-hooks      # 基于 async_hooks 实现异步上下文库
                                           # 并实现 ContextManager API接口
├── opentelemetry-context-zone             # 基于 zone.js 实现的 web 环境异步上下文库
                                           # 实际上只是导出 @opentelemetry/context-zone-peer-dep
├── opentelemetry-context-zone-peer-dep    # 基于 zone.js 实现 ContextManager API接口
├── opentelemetry-core                     # API 中 trace 的相关实现,后面细说
├── opentelemetry-exporter-jaeger          # jaeger 的 SpanExporter 实现
├── opentelemetry-exporter-zipkin          # zipkin 的 SpanExporter 实现
├── opentelemetry-propagator-b3            # B3 格式的 TextMapPropagator 实现
├── opentelemetry-propagator-jaeger        # jaeger 的 TextMapPropagator 实现
├── opentelemetry-resources                # Resource 的接口定义、具体实现
                                           # 默认的浏览器、环境变量 detector 实现
├── opentelemetry-sdk-trace-base           # trace 的基础实现,提供手动 instrumentation 方法
                                           # 实现了 API 中的 TracerProvider 和 Sampler
├── opentelemetry-sdk-trace-node           # 实现了 node 环境的 auto instrumentation
                                           # 配合 opentelemetry-instrumentation 实现
├── opentelemetry-sdk-trace-web            # 实现了 web 环境的 auto instrumentation
├── opentelemetry-semantic-conventions     # Trace 和 Resource 的术语表
├── opentelemetry-shim-opentracing         # 从 opentracing 升级到 otel 组件
├── sdk-metrics                            # metrics 的相关实现,提供手动 instrumentation 方法
└── template

2.2 @opentelemetry/core 模块具体实现

1
packages/opentelemetry-core/src
├── baggage
│   ├── propagation
│   │   └── W3CBaggagePropagator.ts  # 按 W3C trace 规范实现的 Baggage TextMapPropagator
│   ├── constants.ts                 # Baggage 相关约束常量
│   └── utils.ts                     # Baggage 相关实现
├── common                           # API 中工具函数的实现
│   ├── ......
├── internal                         
│   ├── exporter.ts                  # Exporter 接口定义
│   └── validators.ts                # 命名校验工具函数
├── platform                         # 平台相关工具函数
│   ├── browser                      # 浏览器运行环境相关工具函数
│   │   ├── ......
│   ├── node                         # node 运行环境相关工具函数
│   │   ├── ......
│   └── index.ts
├── propagation
│   └── composite.ts                    # 多传播渠道 TextMapPropagator 实现
├── trace                               # trace相关实现
│   ├── sampler                         # 各类采样器实现
│   │   ├── AlwaysOffSampler.ts         # 不上报的采样器
│   │   ├── AlwaysOnSampler.ts          # 总是上报的采样器
│   │   ├── ParentBasedSampler.ts       # 基于父采样结果的采样器
│   │   └── TraceIdRatioBasedSampler.ts # 基于 trace_id 的比例采样器
│   ├── IdGenerator.ts                  # IdGenerator 接口定义
│   ├── TraceState.ts                   # TraceState API 接口的具体实现
│   ├── W3CTraceContextPropagator.ts    # 按 W3C trace 规范实现的 TraceContext TextMapPropagator
│   ├── rpc-metadata.ts                 # rpc context 元数据设置函数
│   └── suppress-tracing.ts             # 设置/获取 取消 trace 标记的函数
├── utils                               # 工具函数
│   ├── ......
├── ExportResult.ts                     # export 结果接口定义
└── index.ts

2.3 @opentelemetry/sdk-metrics 具体实现

1
├── aggregator                         # 数据聚合相关实现 DROP/SUM/LAST_VALUE/HISTOGRAM/...
│   ├── ......
├── exemplar                           # 指标数据采集相关实现(measurement)                                         
│   ├── ......
├── export                                  # exporter 相关实现
│   ├── AggregationSelector.ts              # 时序聚合方案选择函数
│   ├── AggregationTemporality.ts           # 时序聚合方案枚举,增量/总量
│   ├── ConsoleMetricExporter.ts            # PushMetricExporter 基于控制台的实现类
│   ├── InMemoryMetricExporter.ts           # PushMetricExporter 保存到内存的实现
│   ├── MetricData.ts                       # 定义指标数据类型接口,包装 aggregator/types 的类型
│   ├── MetricExporter.ts                   # 指标数据导出接口 PushMetricExporter
│   ├── MetricProducer.ts                   # 指标数据生产器接口,提供 collect 方法
│   ├── MetricReader.ts                     # 指标读取器抽象类,维护 MetricProducer
│   └── PeriodicExportingMetricReader.ts    # 定时导出的 MetricReader 派生类
├── state                              # 指标数据存储相关实现
│   ├── ......
├── view                               # 数据视图相关实现
│   ├── ......
├── InstrumentDescriptor.ts    # 指标描述信息接口定义
├── Instruments.ts             # 对 API 中 Metrics 中各类指标类型接口的具体实现,如 Histogram 等
├── Meter.ts                   # 对 API 中 Meter 接口的具体实现
├── MeterProvider.ts           # 对 API 中 MeterProvider 接口的具体实现
├── ObservableResult.ts        # 对 API 中 ObservableResult 接口的具体实现
├── index.ts                   # 模块出口

sdk-mertics 模块UML:

trace uml

指标采集内部组件之间的关系:

image.png

一个指标 创建 → 收集指标值 → 数据聚合视图 → 指标读取 → 指标上报 的流程:

image.png

3. 实验阶段模块

实验阶段的模块 api 处于不稳定阶段,目前 logs 的 api 在不稳定阶段。还有一些官方的 exporter、instrumentation 模块也处于不稳定阶段。

3.1 实验阶段模块结构梳理

实验阶段模块代码结构:

image.png

实验阶段模块具体的列表和作用如下:

1
./experimental/packages
├── api-events  # EventsAPI,含全局 EventEmitterProvider 注册、事件库&事件接口定义等
├── api-logs    # LogsAPI,含全局 LoggerProvider 注册、日志库&日志接口定义等
├── exporter-logs-otlp-grpc  # 实现 otlp pb 数据编码协议 & grpc 传输协议的 logs 导出模块
├── exporter-logs-otlp-http  # 实现 otlp json 数据编码协议 & http 传输协议的 logs 导出模块
├── exporter-logs-otlp-proto # 实现 otlp pb 数据编码协议 & http 传输协议的 logs 导出模块
├── exporter-trace-otlp-grpc # 实现 otlp pb 数据编码协议 & grpc 传输协议的 trace 导出模块
├── exporter-trace-otlp-http # 实现 otlp json 数据编码协议 & http 传输协议的 trace 导出模块
├── exporter-trace-otlp-proto # 实现 otlp pb 数据编码协议 & http 传输协议的 trace 导出模块
├── opentelemetry-browser-detector # 浏览器环境的 Resource detector 
├── opentelemetry-exporter-metrics-otlp-grpc # otlp pb 编码 & grpc 传输协议的 metrics 导出
├── opentelemetry-exporter-metrics-otlp-http # otlp json 编码 & http 传输协议的 metrics 导出
├── opentelemetry-exporter-metrics-otlp-proto # otlp pb 编码 & http 传输协议的 metrics 导出
├── opentelemetry-exporter-prometheus    # 实现 prometheus 协议的 metrics 导出(pull模式)
├── opentelemetry-instrumentation        # 提供 instrumentation 接口定义、基础类实现
                                         # 以及实现自动检测相关的方法
├── opentelemetry-instrumentation-fetch  # 基于 instrumentation 实现的 fetch trace监控模块
├── opentelemetry-instrumentation-grpc   # 基于 instrumentation 实现的 grpc trace、metrics 监控模块
├── opentelemetry-instrumentation-http   # 基于 instrumentation 实现的 http trace、metrics 监控模块
├── opentelemetry-instrumentation-xml-http-request # 基于 instrumentation 实现的 xhr trace监控模块
├── opentelemetry-sdk-node    # 提供实现了全部 Trace 和 Metrics API 的 SDK (此模块只是导出包装)
├── otlp-exporter-base        # 提供一个 otlp 导出的基类,供上报到 collector 使用
├── otlp-grpc-exporter-base   # 基于 otlp-exporter-base 实现的 grpc 版,只支持 node 
├── otlp-proto-exporter-base  # 基于 otlp-exporter-base 实现的 http + pb 版
├── otlp-transformer          # otlp 序列化方法
├── sdk-logs                  # logs 的相关实现
└── shim-opencensus           # opencensus 升级到 opentelemetry 工具包

3.2 实现自定义的 instrumentation 模块

参考文档:

☞ 参与评论