☰
Highlight 原生 OpenTelemetry 集成实战:OTLP 端点、数据管线与 Collector 配置解析
2026/9/25 16:21:44 网站建设 项目流程
  • 可观测性
  • 后端

【免费下载链接】highlight

highlight.io: The open source, full-stack monitoring platform. Error monitoring, session replay, logging, distributed tracing, and more.

项目地址:https://gitcode.com/gh_mirrors/hi/highlight
点击查看免费下载

为应用埋点做性能追踪本身就是一项繁琐的工作,而多数可观测性方案还会带来供应商锁定:所有埋点数据的格式、去向都被单一厂商的私有 SDK 绑死。本文以 Highlight 官方博客《Day 1: OpenTelemetry on Highlight》为主线,讲解 OpenTelemetry(OTel)与 Highlight 的组合方案,并结合当前仓库源码,深入剖析 Highlight 后端是如何原生接收 OTLP 数据的——包括 OTLP 端点注册、字段提取与项目路由、Kafka + ClickHouse 的落库管线,以及可直接复用的 Collector 配置。

读完本文,你将掌握:如何把任意 OTel SDK/Collector 直接指向 Highlight 完成数据上报、Highlight 如何从 OTLP 数据中提取项目与会话上下文、以及一套支持多后端扇出的 Collector 生产配置。

为什么选择 OpenTelemetry:消除供应商锁定

博客开篇指出了一个普遍痛点:为代码埋点做追踪非常痛苦,而许多可观测性方案会造成供应商锁定——你投入的所有追踪工作量,最终只能发往某一种你并不控制的服务器。

Highlight 给出的统一解法是:让 OpenTelemetry 负责"数据采集与协议",让 Highlight 负责"存储与可视化"。

  • OpenTelemetry 提供全面的 tracing、logging、metrics 与错误监控能力,且数据目的地与埋点代码解耦。它同时是"有主张又灵活"的:借助 OTel Collector 的 processors 和 exporters,你可以把同一条数据流分发到 ClickHouse、Prometheus 或其他开源数据库;
  • Highlight 则显著降低"存下这些数据并可视化"的工程开销:只需把你的 OpenTelemetry Collector 指向 Highlight(Cloud 或 Self-Hosted),其余工作都由 Highlight 完成。从源码结构看,Highlight 后端使用 Kafka 做异步缓冲、ClickHouse 做最终存储,并配套完整的搜索与查看界面;
  • 一个关键的产品能力:Highlight 会把服务端细粒度的 traces 与 logs归属到前端会话(session)上,从而让你能回看"哪些用户操作触发了哪些后端代码"。

官方入门文档位于 Native OpenTelemetry Overview,其中错误监控、日志、追踪、浏览器数据的分主题指南同在该目录下(错误监控、日志、追踪、浏览器、指标)。

四个核心收益(博客原文要点)

博客列出的集成收益可以归纳为四点,逐条展开:

  1. 厂商无关的埋点(Vendor Agnostic Instrumentation):使用 OpenTelemetry 的埋点不关心数据最终发往哪里。这种自由度让你免于供应商锁定,保持可观测性策略的灵活性——今天发往 Highlight,明天多一路扇出到自建后端,埋点代码零改动。
  2. 广泛的库与语言支持:OTel 规范的开源属性意味着它覆盖大量语言与库,兼容性与通用性极强。仓库中sdk/目录下的各语言 SDK(Go、Node、Python、Ruby、Java、Rust、.NET 等)底层均基于 OTel 构建。
  3. 自动埋点(Auto-Instrumentation):OpenTelemetry 维护着一个包含数百个兼容库、插件与集成的大型生态注册表;如果你在用的某个库"已经有 OTel 插件,甚至库本身已内置 OTel 埋点",那么接入成本几乎为零。
  4. 用 Highlight 简化数据管理:集成后无需再关心追踪数据的存储与查看细节,可以把精力集中在"理解并优化应用性能"本身。

源码剖析:Highlight 后端的原生 OTLP 端点

博客说"只需把 Collector 指向 Highlight",那么 Highlight 后端到底暴露了什么?答案在 backend/otel/otel.go 中的Listen方法——它注册了一组标准 OTLP 路径:

// backend/otel/otel.go (Listen) func (o *Handler) Listen(r *chi.Mux) { r.Route("/otel/v1", func(r chi.Router) { r.Use(highlightChi.UseMiddleware(trace.WithSpanKind(trace.SpanKindConsumer))) r.HandleFunc("/traces", o.HandleTrace) r.HandleFunc("/logs", o.HandleLog) r.HandleFunc("/metrics", o.HandleMetric) }) }

即后端提供三个 OTLP 接收端点:

端点处理器解析格式对应信号
POST /otel/v1/tracesHandleTraceptraceotlp.ExportRequest(protobuf)Traces
POST /otel/v1/logsHandleLogplogotlp.ExportRequest(protobuf)Logs
POST /otel/v1/metricsHandleMetricpmetricotlp.ExportRequest(protobuf)Metrics

该 Handler 在 backend/main.go 中被构造并挂载(otelHandler := otel.New(publicResolver);otelHandler.Listen(r)),因此任何支持 OTLP 的 SDK 或 Collector 都可直接发送数据,无需 Highlight 私有 SDK。

一个请求的生命周期:以 HandleTrace 为例

HandleTrace(backend/otel/otel.go#L127)的处理流程展示了"Kafka 高效摄入"这一博客承诺的落地方式:

  1. 读取并解压请求体:highlightHttp.GetBody读取请求体;
  2. 解析 protobuf:req.UnmarshalProto(output)失败即返回 400;
  3. 逐 Resource → Scope → Span 遍历,对每个 span 调用extractFields提取字段(见下节)。这里有两个值得注意的细节:
    • 以fs开头的 span(IgnoredSpanNamePrefixes)只作为 trace 摄入,不再生成 log/error/metric,避免文件系统操作噪音;
    • span 事件(Span Events)会被识别为三类特殊事件:exception(错误)、log(日志)、metric(数值指标),分别路由到错误、日志、指标管线;
  4. 按类别提交到 Kafka:
    • 指标 →MetricSumQueue(kafkaqueue.OTeLMetricSumRow等);
    • 错误 →AsyncProducerQueue,消息类型PushBackendPayload,按 session 作为 Kafka key(无 session 的错误会随机分配 key),保证同一会话的错误有序;
    • span →TracesQueue,以 traceID 作为消息 key;
    • 日志 →BatchedQueue(PushLogsFlattened);
  5. 任一步骤提交失败即返回503 Service Unavailable,让上游 Collector 依其重试策略重发。

每条数据在提交前还会经过IsTraceIngested/IsErrorIngested等过滤函数与配额检查(getQuotaExceededByProject通过 Redis 缓存每个项目的配额状态,超限项目的数据被直接丢弃),这是摄入管线上的重要自我保护机制。

字段提取:数据如何路由到正确的项目与会话

backend/otel/extract.go 中的extractFields是整个摄入层的核心:它把resource、span、span event、scope、log record、metric各层属性合并(mergeMaps,后者优先),再按优先级解析出路由字段。合并顺序为:

originalAttrs := mergeMaps( resourceAttributes, spanAttributes, spanEventAttributes, scopeAttributes, logAttributes, metricMetadata, metricAttributes, )

Highlight 特有的路由属性包括:

  • highlight.project_id— 决定数据写入哪个项目;同时也支持通过请求头X-Highlight-Project(highlight.ProjectIDHeader)覆盖;
  • highlight.session_id— 会话 ID,用于把后端数据归属到前端会话;
  • highlight.trace_id— 请求 ID,充当后端请求的追踪标识;
  • highlight.source(frontend/backend)、highlight.type(http.request/highlight.internal)、highlight.key等可选上下文字段。

这些属性正是博客所强调的"把细粒度服务端数据归属到前端会话"的实现基础。按照 Native OpenTelemetry 概览文档 的说明,SDK 会在 span 上额外设置highlight.project_id、highlight.session_id、highlight.trace_id三个 SpanAttribute(session/request ID 来自网络请求的X-Highlight-Request头,格式为sessionId/requestId),并按 OTel 语义约定上报 Trace 与 Log。

extractFields同时处理了大量真实世界的边缘情况,均有对应单元测试(backend/otel/extract_test.go、backend/otel/otel_test.go)佐证:

  • 项目 ID 的多来源解析:属性highlight.project_id、请求头、syslog 消息前缀(如119 <40>1 ... heroku ...形式的 heroku drain)、fluent tag 中的highlight.project_id=xxx、Heroku drain token 反查项目映射(matchHerokuDrain,结果缓存在 Redis);
  • syslog / systemd 日志解析:extractSyslog与extractSystemd分别处理 RFC 5424 syslog 与 systemd journal 结构化日志;
  • 语义约定字段提取:exception.type/exception.message/exception.stacktrace、service.name/service.version、deployment.environment、log.severity/log.message、metric.name/metric.value等;
  • 错误生成:getBackendError(backend/otel/otel.go#L66)在 span 的exception事件上构造BackendErrorObjectInput,堆栈会经过stacktraces.FormatStructureStackTrace(..., stacktraces.FromOTeL())格式化。

此外,从源码结构看还有一个安全细节:生产环境下,来自"外部 Hobby 实例路由到云项目 1"的数据会被标记为 external 并丢弃其中的 exception(ExternalHighlightData/fields.external),防止跨实例数据污染。

仓库中的 Collector 参考配置

仓库内有两份可直接参考的 OpenTelemetry Collector 配置,分别对应生产部署与本地开发:

生产配置:deploy/otel-collector.yaml

关键要点:

receivers: otlp: protocols: grpc: endpoint: '0.0.0.0:4317' max_recv_msg_size_mib: 1000 http: endpoint: '0.0.0.0:4318' cors: allowed_headers: - 'X-Highlight-Request' # 放行 Highlight 上下文头 # ... # 另含 syslog(RFC 5424, UDP 6513 / TCP 6514)、fluentforward、tcplog、 # awsfirehose(cwmetrics / cwlogs / otlp_v1)等日志类接收器 processors: memory_limiter: limit_mib: 14336 spike_limit_mib: 1024 batch: metadata_keys: [x-highlight-project] # 按项目批量 send_batch_size: 1000 send_batch_max_size: 10000 attributes: actions: - key: highlight.project_id from_context: metadata.x-highlight-project action: insert # 把 header 写入属性 service: pipelines: traces: { receivers: [otlp], processors: [memory_limiter, batch, attributes], exporters: [otlphttp] } metrics: { receivers: [otlp, awsfirehose/cwmetrics, awsfirehose/otlp_v1], ... } logs: { receivers: [otlp, fluentforward, tcplog, syslog, awsfirehose/cwlogs], ... }

值得关注的工程细节:

  • batch处理器以x-highlight-project元数据作为 metadata_keys:保证同一项目的数据被聚在同一批中,配合后端"session 作为 Kafka key"的排序策略,端到端保持会话内有序;
  • attributes处理器把 header 中的项目 ID 注入为highlight.project_id属性,使纯 header 路由的数据也能被extractFields识别;
  • otlphttpexporter使用 snappy 压缩、100 消费者、1 万条发送队列,并开启指数退避重试(initial_interval: 1s→max_interval: 30s,最长 300s)——这与后端返回 503 的"让上游重试"设计正好衔接。

本地/自托管配置:docker/collector.yml

自托管版在同样的接收器基础上追加了otlp/https(8318 端口,挂载 TLS 证书)接收器,exporter 指向宿主机后端https://host.docker.internal:8082/otel(snappy 压缩 + 重试),并附带debugexporter 便于本地调试。配合 docker/compose.yml 与 docker/run.sh 即可在本地拉起"Collector + 后端 + ClickHouse + Kafka"的完整链路——这正是博客中"指向 Highlight(Cloud 或 Self-Hosted)"里 Self-Hosted 一侧的实操形态。

多后端扇出:埋点一次,分发多处

博客强调 OTel 方案"在数据存储上既有主张又保持灵活"。当需要同时向多个可观测后端发数据时,官方概览文档给出了标准的 Collector 扇出配置:

receivers: otlp: # 接收你的应用 SDK protocols: grpc: endpoint: '0.0.0.0:4317' http: endpoint: '0.0.0.0:4318' processors: batch: exporters: otlphttp/highlight: endpoint: 'https://otel.highlight.io' compression: gzip otlphttp/example: endpoint: 'https://example.com/otel' service: pipelines: traces: receivers: [otlp] processors: [batch] exporters: [otlphttp/highlight, otlphttp/example] metrics: receivers: [otlp] processors: [batch] exporters: [otlphttp/highlight, otlphttp/example] logs: receivers: [otlp] processors: [batch] exporters: [otlphttp/highlight, otlphttp/example]

将应用 SDK 指向 Collector、由 Collector 扇出到 Highlight 与其他后端,是"埋点与目的地解耦"这一收益最直接的体现。若你的语言 SDK 尚不支持原生日志上报,该文档还建议以 span event 形式上报(事件名log,携带log.severity与log.message属性),后端HandleTrace中的highlight.LogEvent分支正是这一路径的消费端。

小结

  • Highlight 的后端原生实现了 OTLP(protobuf)接收端点/otel/v1/{traces,logs,metrics}(backend/otel/otel.go),任意 OTel SDK 或 Collector 可直接对接,无供应商私有协议;
  • extractFields(backend/otel/extract.go)负责从多层属性与请求头中提取highlight.project_id、highlight.session_id、highlight.trace_id等路由字段,把后端数据归属到正确的项目与前端会话,并兼容 syslog、systemd、heroku drain、fluent tag 等边缘来源;
  • 数据管线为"OTLP 解析 → 过滤与配额检查 → 按类别进入 Kafka 队列 → ClickHouse 落库",失败时以 503 触发 Collector 重试;
  • 仓库提供了生产(deploy/otel-collector.yaml)与本地自托管(docker/collector.yml)两套 Collector 配置,以及按项目分批、header 注入属性、指数退避重试等可直接借鉴的工程细节;
  • 通过 Collector 的 fan-out 能力,同一份 OTel 埋点可同时服务多个可观测后端,这是 OpenTelemetry 与 Highlight 组合方案对抗供应商锁定的核心机制。
  • 可观测性
  • 后端

【免费下载链接】highlight

highlight.io: The open source, full-stack monitoring platform. Error monitoring, session replay, logging, distributed tracing, and more.

项目地址:https://gitcode.com/gh_mirrors/hi/highlight
点击查看免费下载
上一篇:8大网盘直链解析:一键拿到真实下载地址
下一篇:Windows 离线实时语音字幕:三步装好 TMSpeech,会议纪要自动生成

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询