作者:来自 Elastic Vihas Makwana

在 OpenTelemetry Collector 中从 YAML、CSV 或 DNS 查找任意值,或者通过 Elastic 构建并提交到 Collector Contrib 的 processor 接入你自己的数据源。
丰富化是那些听起来很简单的任务之一,直到你尝试在遥测管道中实现它。你在日志记录中有一个 user.id,并且想要获取 user.name。你有一个 client.ip,并且想要获取其背后的主机名。直到现在,OpenTelemetry Collector 还没有一种通用方式来执行这种类型的查找。
目前最接近的选择是在 transform processor 中手动编写映射:
bash
`
1. # otel.yml
2. processors:
3. transform:
4. log_statements:
5. - context: log
6. statements:
7. - set(attributes["user.name"], "Alice") where attributes["user.id"] == "user001"
8. - set(attributes["user.name"], "Bob") where attributes["user.id"] == "user002"
9. - set(attributes["user.name"], "Carol") where attributes["user.id"] == "user003"
10. # ...and one more line for every user
`AI写代码
这对于少量条目有效,但无法扩展到超过 10 到 20 个条目的情况。每一个新的映射都意味着增加另一条语句,查找数据和你的管道配置位于同一个文件中,并且无法指向已经存在的参考数据。它证明了这种需求是真实存在的,但它只能覆盖最简单、最小规模的场景。
如果你运行 Collector,并且一直在使用 transform processor、sidecar 脚本或下游 ingest pipeline 只是为了添加参考数据,那么这个组件就是为你准备的。

为什么 OpenTelemetry Collector 需要 lookup processor
Collector 已经能够很好地处理几种丰富化模式。transform processor 会根据记录中已有的数据重新组织和派生数据。k8sattributes 和 resourcedetection processors 会附加系统和环境元数据,例如 Kubernetes pod 详细信息或云主机信息。
但它无法根据你已经拥有的键来查找相关数据。尤其是以下三种模式没有对应的解决方案:
- 从 JSON、YAML 或 CSV 中的静态参考数据进行基于文件的查找
- 从外部服务进行基于 HTTP 和 API 的丰富化
- DNS 查找,例如将 IP 解析为主机名
这些是在其他数据采集器和转换工具中的日常任务。将内部服务 ID 映射到易读名称,根据客户 ID 附加业务元数据,或者解析 IP,都属于这一类任务。如果没有原生组件,团队只能构建脆弱的变通方案,或者将工作推送到下游,而在那里更难复用。
这个差距正是新的 lookup processor 所解决的问题。Elastic 的 Data Processing 团队提出了它,社区接受了它,并且它是在 Grafana 的合作下构建完成的,感谢 Sam DeHaan(GH: dehaansa)。lookup processor 从你的遥测数据中获取一个值,使用 OTTL 构建查找键,查询 YAML 文件或 DNS 等数据源,并将结果作为新的属性写回。
OpenTelemetry lookup processor 的设计方式
该设计源于社区对更丰富丰富化能力的反复需求。促成它的一些示例包括:
- 根据 YAML 或 CSV 定义通过键匹配丰富属性(#40526)
- 使用来自清单数据源的资源元数据丰富遥测数据(#40936)
- 通用资源检测器(#29627)
- Alert Manager receiver 和 exporter(#18526)
- gRPC processor / connector(#20888)
与其为每个请求构建一个一次性组件,目标是创建一个足够灵活的单一 processor 来覆盖这些场景。以下四个理念塑造了它:
- 支持每个 processor 进行多次查找,因此一个实例可以在单次处理中丰富多个属性。
- 支持缓存,因此 DNS 等外部数据源不会针对同一个键被反复查询。
- 使用 OTTL 进行键提取,因此你可以获得完整的表达式语言,用于从记录中提取查找键,包括转换器。
- 支持可扩展的数据源,因此你不会受限于内置的数据源集合。你可以为自己的数据注册自定义数据源。

可扩展的数据源对于该 processor 的长期价值最为重要。数据源是一个小型、定义清晰的接口,因此该 processor 是一个丰富化基础,而不是一个固定的功能列表。YAML 和 CSV 目前覆盖静态参考数据,DNS 覆盖动态解析,而相同的接口为 HTTP API、键值存储或任何特定于你环境的数据源留下了扩展空间。
Lookup processor 如何使用 OTTL 评估键
无论你配置哪种数据源,该 processor 都会针对每条记录执行相同的三个步骤。

首先,它会评估一个 OTTL 表达式,以从记录中生成一个查找键。其次,它会将该键传递给配置的数据源,并获取返回值。第三,它会将该值写入你指定的属性中,写入记录本身或其父资源中。当某个键没有匹配项时,该 processor 会写入一个可配置的默认值,以确保下游查询保持可预测。
接下来的两个部分将介绍当前可用的两个数据源。
在 OpenTelemetry Collector 中使用 YAML 进行基于文件的查找
最常见的场景是静态参考数据。你将一个映射文件保存在 Collector 旁边,并根据它丰富记录。这里,processor 会读取一个 YAML 文件,并根据 user.id 为每条日志添加 user.name。
markdown
`
1. # otel.yml
2. processors:
3. lookup:
4. source:
5. type: yaml
6. path: /etc/otel/mappings.yaml
7. lookups:
8. - key: log.attributes["user.id"]
9. attributes:
10. - destination: user.name
11. default: "Unknown User"
`AI写代码
映射文件是一组简单的键值对:
bash
`
1. # /etc/otel/mappings.yaml
2. user001: "Alice"
3. user002: "Bob"
`AI写代码
key 字段是一个 OTTL 值表达式,因此 log.attributes"user.id" 会从日志记录中读取 user.id 属性。destination 是查找到的值写入的位置,而 default 是当键在文件中不存在时写入的内容。
给定以下传入的日志记录:
css
`
1. {
2. "body": "User logged in",
3. "attributes": {
4. "user.id": "user001",
5. "http.method": "POST"
6. }
7. }
`AI写代码
该 processor 查找 user001,找到 Alice,并生成:
css
`
1. {
2. "body": "User logged in",
3. "attributes": {
4. "user.id": "user001",
5. "user.name": "Alice",
6. "http.method": "POST"
7. }
8. }
`AI写代码
原始属性保持不变,丰富化后的值会添加在它们旁边。对于将参考数据保存在电子表格或导出文件中而不是 YAML 中的团队,CSV 数据源的工作方式相同。
在 OpenTelemetry Collector 中进行 DNS 查找丰富化
静态文件是一回事,但有些丰富化需要实时变化的数据。将 IP 地址解析为主机名是典型示例,也是该 processor 支持的第一个动态数据源。你不需要使用文件,而是将它指向一个 DNS 服务器。
markdown
`
1. # otel.yml
2. processors:
3. lookup:
4. source:
5. type: dns
6. lookups:
7. - key: log.attributes["client.ip"]
8. attributes:
9. - destination: client.hostname
10. default: "Not found"
`AI写代码
配置的结构与 YAML 示例完全相同。只有数据源发生了变化。该 processor 从记录中提取 client.ip,向 DNS 解析器请求反向解析,并将主机名写回。
给定以下传入记录:
css
`
1. {
2. "body": "User logged in",
3. "attributes": {
4. "client.ip": "8.8.8.8",
5. "http.method": "POST"
6. }
7. }
`AI写代码
DNS 数据源解析 8.8.8.8,并生成:
css
`
1. {
2. "body": "User logged in",
3. "attributes": {
4. "client.ip": "8.8.8.8",
5. "client.hostname": "dns.google",
6. "http.method": "POST"
7. }
8. }
`AI写代码
因为 DNS 查询会访问外部系统,所以缓存的作用就体现出来了。该 processor 会将结果保存在内存缓存中,因此共享相同 IP 的一系列记录不会变成一系列相同的 DNS 查询。这样可以降低延迟,并避免对解析器造成过大压力。
编写自定义 lookup source
内置数据源覆盖了常见场景,但真正的设计目标是可扩展性。数据源是一个小型契约:你实现一个查找函数,该函数接收字符串键并返回一个值。processor 负责 OTTL 键评估、缓存、默认值以及属性写入,因此自定义数据源只需要回答"这个键对应什么值?"这个问题。
这意味着,如果你已经运行一个内部元数据 API、Redis 缓存或自定义数据库,你可以将其接入为一个数据源,并复用 processor 提供的其他所有功能。基于 HTTP 的数据源和键值存储都是自然匹配的选择,它们也正位于路线图中,因为该接口使它们很容易添加。
Elastic 如何计划使用这个 lookup processor
Elastic 基于 OpenTelemetry Collector Contrib 构建其 Collector 发行版。计划包含 lookup processor,使团队今天通过脆弱变通方案完成的丰富化工作可以在管道内部运行,而不是在下游执行。
有两种模式尤为突出。第一种是参考数据丰富化:将内部服务 ID 转换为易读名称,或者根据 ID 附加团队或客户等元数据,使遥测数据到达时已经带有用于搜索和关联的标签。第二种是 DNS 解析:在数据落地之前将 client.ip 转换为主机名,这对于网络和安全遥测非常重要,因为你通常需要名称而不是原始地址。
在 Collector 中执行这些操作,可以让参考数据更接近遥测处理的位置,并避免在单独的 ingest 步骤中重复实现逻辑。随着数据源接口扩展以支持 HTTP API 和键值存储,同一个 processor 可以支持更丰富的丰富化,而无需改变管道配置方式。
Lookup processor 路线图以及如何贡献
Lookup processor 的主要实现已经合并到 OpenTelemetry Collector Contrib 上游。核心 processor 和 YAML 数据源首先完成合并,随后 DNS 数据源作为第一个动态查找功能加入。
未来还有大量工作需要完成,欢迎贡献:
- 用于从外部 API 进行丰富化的 HTTP lookup source。
- 更多 DNS 能力,包括 A 和 AAAA 查询,以及支持多个 DNS 服务器。
- 组件遥测,以便你可以观察缓存命中率和未命中率、查找延迟以及错误率。
- 随着真实使用场景增加而进行的性能优化。
如果你想尝试它,可以将 processor 添加到包含 Contrib 的 Collector 构建中,将 YAML 数据源指向一个映射文件,并丰富一条真实记录。然后在 OpenTelemetry Collector Contrib 仓库中提交 issue 或 pull request。该组件由社区共同维护,获得的数据源和反馈越多,它就会变得越有用。
想进一步了解,可以阅读 lookup processor README 和丰富化跟踪 issue。要了解更多 Elastic 如何基于 OpenTelemetry 构建功能,请浏览 Elastic Observability Labs 中的 OpenTelemetry 文章。
原文:OpenTelemetry lookup processor: File and DNS enrichment --- Elastic Observability Labs