本文基于 Opentelemetry JS 语言的实现,梳理了其对 OTEL 的具体实现,方便深入理解 OTEL 的工作原理,便于日常项目中的可观测性数据上报和自定义的三方 instrumentation 组件开发。
1. API
1.1 API 结构梳理
API 模块提供了 context、metrics、trace、propagation 等核心功能的 API 定义,以及它们的默认实现。
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 模块结构:
2. 稳定阶段模块
2.1 稳定阶段模块结构梳理
模块列表:
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:
指标采集内部组件之间的关系:
一个指标 创建 → 收集指标值 → 数据聚合视图 → 指标读取 → 指标上报 的流程:
3. 实验阶段模块
实验阶段的模块 api 处于不稳定阶段,目前 logs 的 api 在不稳定阶段。还有一些官方的 exporter、instrumentation 模块也处于不稳定阶段。
3.1 实验阶段模块结构梳理
实验阶段模块代码结构:
实验阶段模块具体的列表和作用如下:
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 模块
参考文档:
- https://github.com/open-telemetry/opentelemetry-js
- https://www.timescale.com/blog/a-deep-dive-into-open-telemetry-metrics/
本文链接:https://www.zoucz.com/blog/2023/12/17/a833c170-9c8d-11ee-9fa0-5dbc93f9d3ee/