ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

为 highlight.io 编写新语言 SDK:基于 OpenTelemetry 的信号上报架构与实现指南

为 highlight.io 编写新语言 SDK:基于 OpenTelemetry 的信号上报架构与实现指南 可观测性后端【免费下载链接】highlighthighlight.io: The open source, full-stack monitoring platform. Error monitoring, session replay, logging, distributed tracing, and more.项目地址https://gitcode.com/gh_mirrors/hi/highlight点击查看免费下载highlight.io 的所有后端语言 SDKGo、Python、Node.js、Java 等都构建在 OpenTelemetry 为主线结合sdk/highlight-go与sdk/highlight-py的真实源码完整梳理一个 SDK 应当实例化的 OTel 构造、Highlight 专属属性的语义约定以及错误、日志、指标三种记录方式的落地实现。读完本文你将能看懂现有 SDK 的实现原理并据此为新语言编写一个符合 highlight.io 上报规范的全新 SDK。1. SDK 与 Collector一条基于 OTLP 的数据链路在动手写 SDK 之前先理解数据从应用进程到 highlight.io 后端仓库的完整路径SDK 在应用进程内创建 OpenTelemetry Provider 与 Exporter应用产生的 Span、LogRecord、Metric 被批量处理器BatchProcessor缓存Exporter 通过 OTLP HTTPS 将数据推送到 Collector默认端点https://otel.highlight.io:4318trace 走/v1/traces、log 走/v1/logs、metric 走/v1/metricsCollector 转发给 public graph仓库中对应 backend/public-graph/graph/schema.resolvers.go完成 SDK 数据的摄取入库。关于采集端架构的整体视图SDK、Collector、public graph 之间的数据流参见 architecture.md 中的架构图。这个默认端点在源码中有明确定义在 sdk/highlight-go/otel.go 中OTLPDefaultEndpoint https://otel.highlight.io:4318。同时SDK 通过SetOTLPEndpoint见 sdk/highlight-go/highlight.go支持覆盖端点因此自托管部署 highlight.io 时可以让 SDK 指向你自己的 Collector 地址。2. 每个 SDK 必须实例化的核心 OTel 构造为了让 trace 与 log 两种信号能够稳定地批量上报SDK 初始化时至少需要实例化下面两组构造源码层面即Provider Processor Exporter三件套Trace 链路TracerProvider—— 设置全局 OTel SDK 的 trace 配置资源、采样、批处理BatchSpanProcessor—— 将 Span 缓存成批按批次导出OTLPSpanExporter—— 通过 OTLP HTTPS 将 trace 导出到 Collector 的/v1/traces。Log 链路LoggerProvider—— 设置全局 OTel SDK 的 log 配置BatchLogRecordProcessor—— 将 LogRecord 缓存成批导出OTLPLogExporter—— 通过 OTLP HTTPS 将日志导出到 Collector 的/v1/logs。在 Go SDK 中这三个 Provider 分别由CreateTracerProvider、CreateLoggerProvider、CreateMeterProvider构建见 sdk/highlight-go/otel.go并由StartOTLP()统一装配、通过otel.SetTracerProvider/otel.SetLoggerProvider注册为全局sdk/highlight-go/otel.go。其中 tracer 链路的批处理参数值得注意WithBatchTimeout(time.Second)—— 每 1 秒尝试导出一批WithExportTimeout(30 * time.Second)—— 单次导出最长 30 秒WithMaxExportBatchSize(1024 * 1024)与WithMaxQueueSize(1024 * 1024)—— 批量与队列容量上限。此外 trace 链路还挂载了一个自定义highlightSamplersdk/highlight-go/otel.go支持按 SpanKind 配置采样比例WithSamplingRate/WithSamplingRateMap默认 100% 采样。Python SDK 的对应实现见 sdk/highlight-py/highlight_io/sdk.py同样使用TracerProvider BatchSpanProcessor OTLPSpanExporter、LoggerProvider BatchLogRecordProcessor OTLPLogExporter并设置了schedule_delay_millis50005 秒批量延迟、max_export_batch_size128 * 1024、max_queue_size1024 * 1024且三个 Exporter 都开启了 Gzip 压缩Compression.Gzip。3. 配置 OpenTelemetry 属性Highlight 如何识别你的数据Highlight 遵循 OpenTelemetry 的语义约定semantic conventions来解析通用元数据如service.name、code.function等但有几个 key 是 Highlight 单独识别、用来做数据归属与关联的。3.1 设置 Highlight Project ID关键步骤要让 OTel 数据落入你指定的 Highlight 项目必须随数据携带项目标识官方提供了两种等价方式x-highlight-project—— HTTP 请求头适用于在 Exporter 上配置highlight.project_id—— 属性Attributekey适用于 Resource 属性或单个 Span / Log / Metric 记录上的属性。选择哪种取决于语言实现某些 OTel 实现更方便在 Exporter 的headers中携带 project ID另一些则更适合作为 Resource 属性统一附加到所有信号上。3.2 示例Node.js 原生 OpenTelemetry 配置以下是官方文档给出的完整 Node.js 配置示例同时演示了 trace 与事件型 log/metric 的上报方式import { NodeSDK } from opentelemetry/sdk-node import { OTLPTraceExporter } from opentelemetry/exporter-trace-otlp-http; import { Resource } from opentelemetry/resources import type { Attributes } from opentelemetry/api const attributes: Attributes { // Provide the highlight project ID as a resource attribute or via the exporter headers // highlight.project_id: YOUR_PROJECT_ID, service.name: my-service } const sdk new NodeSDK({ resource: new Resource(attributes), traceExporter: new OTLPTraceExporter({ // NB: this is the url for trace exports. if you are using a language which supports // the opentelemetry logs format, use https://otel.highlight.io:4318/v1/logs url: https://otel.highlight.io:4318/v1/traces, // In some OpenTelemetry implementations, its easier to provide // the project ID as a header rather than a resource attribute. headers: { x-highlight-project: YOUR_PROJECT_ID } }) }); const tracer trace.getTracer(my-tracer); sdk.start(); const log (level: string, message: string) { const span tracer.startSpan(main) span.setAttributes({ [highlight.session_id]: abc123, [highlight.trace_id]: def456, customer: vadim, customer_id: 1234 }) span.addEvent(log, { [log.severity]: level, [log.message]: message }, new Date()) span.addEvent(metric, { [metric.name]: my-web-vital, [metric.value]: 12.34 }, new Date()) span.end() }; log(info, hello, world!)从代码中可以提炼出几条重要的约定trace 端点与 log 端点分开https://otel.highlight.io:4318/v1/traces与https://otel.highlight.io:4318/v1/logs项目归属可通过headers: { x-highlight-project: ... }或 Resource 属性highlight.project_id二选一除 Highlight 保留属性外你完全可以附加自定义业务属性示例中的customer、customer_id它们会随数据一并入库用于后续的过滤与查询。关于更多 OTel 原生接入的细节可继续阅读官方文档 4_tracing.md。4. 记录错误异常即 Trace EventHighlight 通过 OTLP 上报的数据本质是 Trace属性遵循语义约定。创建 Trace 时SDK 会额外设置三个 Span 属性来携带 Highlight 上下文highlight.project_id—— 提供给 SDK 的 Highlight 项目 IDhighlight.session_id—— 来自网络请求X-Highlight-Request请求头中的 Session IDhighlight.trace_id—— 来自网络请求X-Highlight-Request请求头中的 Request ID。4.1 将异常上报为 OTel Trace按照异常语义约定异常在 OpenTelemetry 中表示为 Trace Event。多数 OTel SDK 提供了span.record_exception(exc)方法自动按约定填充异常类型、消息与堆栈等属性。Python 的典型用法是把上报逻辑封装进一个 contextmanager为当前调用创建 trace# create a trace for the current invocation with self.tracer.start_as_current_span(my-span-name) as span: span.set_attributes({highlight.project_id: _project_id}) span.set_attributes({highlight.session_id: session_id}) span.set_attributes({highlight.trace_id: request_id}) try: # contextmanager yields execution to the code using the contextmanager yield except Exception as e: # if an exception is raised, record it on the current span span.record_exception(e) raise这正对应 Python SDK 中H.tracecontextmanager 与H.record_exception的实现见 sdk/highlight-py/highlight_io/sdk.py 与 sdk/highlight-py/highlight_io/sdk.py。Go SDK 的底层实现更能体现对异常语义约定的深入处理RecordError/RecordSpanErrorsdk/highlight-go/otel.go会先尝试把错误断言为ErrorWithStack接口即携带errors.StackTrace的错误。若错误自带真实堆栈则直接以exception事件写入exception.type、exception.message、exception.stacktrace三个语义属性否则回退到span.RecordError(err, trace.WithStackTrace(true))并顺带处理*url.Error类型的网络错误额外记录Op与URL属性。5. 记录日志原生 Logs 端点与 Trace Event 回退5.1 两种上报路径的选择如果目标语言的 OTel SDK 支持实验性的日志摄取端点/v1/logs优先使用原生 LogRecord 上报如果不支持则采用回退方案——把日志作为 Trace 的 Event 上报。回退方案的约定如下事件名Event nameloglog.severity事件属性日志严重级别字符串log.message事件属性日志消息正文。5.2 通过 LogRecord 关联 Highlight 上下文当使用原生日志数据模型时通过 LogRecord 的属性Attributes关联 Highlight 上下文约定与 Trace 一致highlight.project_id—— 提供给 SDK 的 Highlight 项目 IDhighlight.session_id—— 来自X-Highlight-Request请求头的 Session IDhighlight.trace_id—— 来自X-Highlight-Request请求头的 Request ID。5.3 Go 示例logrus Hook 上报日志以下官方示例展示了 Go 中如何拦截日志框架logrus调用并把日志转换为 Span Eventpackage main import github.com/highlight/highlight/sdk/highlight-go func RecordLog(log string) { span, _ : highlight.StartTrace(context.TODO(), highlight-go/logrus) defer highlight.EndTrace(span) attrs : []attribute.KeyValue{ LogSeverityKey.String(ERROR), LogMessageKey.String(entry.Message), } span.AddEvent(highlight.LogEvent, trace.WithAttributes(attrs...)) }其中的常量在源码中有准确定义LogEvent log、LogSeverityAttribute log.severity、LogMessageAttribute log.message见 sdk/highlight-go/otel.go并保留了level、severity、message等历史 key 的兼容映射。5.4 源码级实现logrus Hook 的完整行为Go SDK 对 logrus 的完整集成位于 sdk/highlight-go/log/logrus.go。Hook.Fire的行为可以拆解为用日志时间作为 Span 开始时间开启名为highlight.go.log的 client 类型 Span将级别字符串大写warning归一为warn写入log.severity消息写入log.message若entry.Caller存在则附加code.function、code.filepath、code.lineno语义属性entry.Data中的字段会逐个转为attribute.String附加到事件当日志级别达到errorStatusLevel默认logrus.ErrorLevel时将 Span 状态置为Error。WithLevels选项可自定义 Hook 触发的日志级别默认覆盖PanicLevel到WarnLevel。6. 语言差异显式 Hook 注入 vs 自动拦截官方文档特别强调了一个关键差异SDK 暴露的公共 API 因语言而异。例如Go提供 logger hook API由应用显式配置如把上面的Hook注册到 logrusPythonSDK 自动把钩子注入 Python 内置的logging包应用无需任何额外配置。Python 侧的自动拦截在 sdk/highlight-py/highlight_io/sdk.py 中实现通过LoggingInstrumentor对logging进行埋点并把log_hook作为回调同时用setLogRecordFactory替换日志记录工厂确保每条日志都处于活跃 Span 的上下文之中。log_hook构造LogRecord时填充了丰富的语义属性attributes span.attributes.copy() attributes[code.function] record.funcName attributes[code.namespace] record.module attributes[code.filepath] record.pathname attributes[code.lineno] record.lineno r LogRecord( timestampint(record.created * 1000.0 * 1000.0 * 1000.0), trace_idctx.trace_id, span_idctx.span_id, trace_flagsctx.trace_flags, severity_textrecord.levelname, severity_numberstd_to_otel(record.levelno), bodyrecord.getMessage(), resourcespan.resource, attributesattributes, )这段代码位于 sdk/highlight-py/highlight_io/sdk.py其中几个细节值得新 SDK 作者注意timestamp由 Pythonrecord.created秒换算为纳秒*1000.0 * 1000.0 * 1000.0severity_text取日志级别名severity_number用std_to_otel把 Python 级别号映射为 OTel 标准数值同时附加code.function/code.namespace/code.filepath/code.lineno来还原日志的产生位置如果日志携带异常信息record.exc_info则转调record_exception走异常事件路径。7. 会话与请求上下文的来源X-Highlight-Request请求头highlight.session_id与highlight.trace_id的取值来自前端在请求上携带的X-Highlight-Request请求头。Go SDK 在 sdk/highlight-go/highlight.go 的InterceptRequestWithContext中实现了解析逻辑先从请求头中提取X-Highlight-Request按/分割出sessionSecureID与requestID存入 context随后StartTraceWithTracersdk/highlight-go/otel.go在创建 Span 时把这两个值写入highlight.session_id/highlight.trace_id属性并把requestID解析为 TraceID支持 hex 与 base64 两种编码见getTraceIDsdk/highlight-go/otel.go使后端 trace 与前端会话、请求在可视化上自然关联。Python 侧的等价逻辑是通过HighlightSpanProcessor.on_start在 Span 启动时从 baggage 读取 header 值并设置三个 Highlight 属性sdk/highlight-py/highlight_io/sdk.py并用 LRU 缓存 trace_id 到(session_id, request_id)的映射供日志路径查询使用。8. 指标记录第三种信号虽然官方文档在 adding-an-sdk.md 中重点讲解 trace 与 log但 Node.js 示例里的metric事件metric.name、metric.value属性与仓库源码都表明指标同样是 SDK 的一等公民。在 Go SDK 中MeterProvider由CreateMeterProvider构建sdk/highlight-go/otel.go每 5 秒周期导出对外暴露RecordMetricGauge、RecordHistogram、RecordCount三个 APIsdk/highlight-go/otel.go同样会把会话与请求 ID 作为属性注入。Python SDK 则提供record_metric、record_count、record_incr、record_histogram、record_up_down_counter等方法sdk/highlight-py/highlight_io/sdk.py。因此新语言 SDK 在条件允许时也应当覆盖/v1/metrics端点。9. 编写新 SDK 的检查清单与深入阅读综合官方文档与仓库源码一个符合 highlight.io 规范的 SDK 至少应做到使用 OpenTelemetry SDK实例化 TracerProvider / LoggerProvider及 MeterProvider并通过 BatchProcessor OTLP Exporter 上报到https://otel.highlight.io:4318的/v1/traces、/v1/logs可选/v1/metrics通过x-highlight-project请求头或highlight.project_id属性提供项目 ID三种信号都必须携带解析X-Highlight-Request请求头并注入highlight.session_id/highlight.trace_id异常按 exception 语义约定作为 Trace Event 上报日志优先走原生 LogRecord否则以log事件 log.severity/log.message属性回退为语言生态提供 hookGo 的 logrus hook或自动拦截Python 的logging自动注入等集成方式。可继续深入的仓库资料官方 SDK 接入文档adding-an-sdk.md、architecture.md、4_tracing.mdGo SDK 核心实现sdk/highlight-go/otel.go、sdk/highlight-go/highlight.go、sdk/highlight-go/log/logrus.goPython SDK 核心实现sdk/highlight-py/highlight_io/sdk.py更多语言 SDK 示例位于 sdk 目录highlight-node、highlight-java、highlight-rust 等可作为新语言实现的参考模板。赞分享可观测性后端【免费下载链接】highlighthighlight.io: The open source, full-stack monitoring platform. Error monitoring, session replay, logging, distributed tracing, and more.项目地址https://gitcode.com/gh_mirrors/hi/highlight点击查看免费下载相关推荐PuerTs 语言插件P-API编写指南基于 pesapi 接口为 Unity 实现新脚本语言后端PuerTs 语言插件P API编写指南基于 pesapi 接口为 Unity 实现新脚本语言后端 本文为 PuerTsPuerTs for Unity游戏开发跨平台highlight.io 手动上报错误完全指南H.consumeError 与各语言 SDK 的捕获边界之外highlight.io 手动上报错误完全指南H.consumeError 与各语言 SDK 的捕获边界之外 本指南系统讲解 highlight.io 全栈可可观测性后端Highlight.io 基于 ClickHouse 构建 OpenTelemetry 指标Metrics摄取与可视化管道Highlight.io 基于 ClickHouse 构建 OpenTelemetry 指标Metrics摄取与可视化管道 OpenTelemetryOT可观测性后端创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表