作者:来自 Elastic dmathieu

大多数人把 OpenTelemetry Collector 当作一个高级的 telemetry 路由器使用。但因为有时需要超越内置组件,在这个表面之下,它实际上是一个可插拔、可扩展的框架,旨在进行深度定制。
让我们看看如何将 Collector 用作一个框架。
为什么我要构建自定义 Collector?
没有两个 observability 堆栈是完全相同的。
你可能需要:
- 一个自制的 auth 层来处理传入的 telemetry
- 一个遵从性要求的数据清洗器
- 一个导出器,用于公司外没人听说过的系统
- 一个接收器,用于只存在于你工程传说中的协议
当内置组件无法满足需求时,Collector 提供了 API,让你可以干净、官方地编写缺失的部分。
🧩 Collector 里有什么?
使用 Collector 时,你将与以下一种(或多种)组件类型交互:
Receivers
它们接收数据并将其转换为内部数据类型,以供其他组件使用。
Processors
它们在传输中修改 telemetry,例如敏感数据脱敏、数据增强、采样等。
Exporters
它们获取处理后的数据,可能进行转换后发送到其他地方(另一个 Collector 或你的 observability 提供商)。
Extensions
它们处理所有非 telemetry 的功能:认证、健康检查等。
每种组件类型遵循相同模式:
- 一个 config struct(你的 YAML 设置)
- 一个 factory(Collector 如何创建你的组件)
- 一个组件实现(启动、关闭及处理逻辑)
让我们构建一个组件。
🔧 你的第一个 processor
让我们构建一个最小但可用的自定义 processor,为每个 span 添加一个属性。
这里是一个最小但可用的自定义 processor,为每个 span 添加一个属性。
已经有一个内置组件 attributesprocessor,可以为 span 添加属性。
模块设置
OpenTelemetry Collector 使用 Go 编写,每个组件都将插入其中。
因此每个组件都必须是一个 Go 模块。
本文假设你具备 Go 编程语言基础知识以及模块的使用方法。
你将需要一个 Go 模块:
markdown
`
1. mkdir otel-processor-example
2. cd otel-processor-example
3. go mod init
`AI写代码
配置 struct
每个 Collector 组件都从一个 config.go 文件开始:
go
``
1. type Config struct {
2. AttributeKey string `mapstructure:"key"`
3. AttributeValue string `mapstructure:"value"`
4. }
``AI写代码
这将允许你像这样配置组件:
markdown
`
1. processors:
2. addattribute:
3. key: environment
4. value: production
`AI写代码
处理逻辑
这是组件内部实际执行的逻辑。
它可以启动一个 HTTP 服务器以接收请求(如果它是一个 receiver),发送外部 HTTP 请求(如果它是一个 exporter),或者更简单地,接收数据、进行转换并将其传递到下一个处理层。
css
`
1. func createTracesProcessor(
2. ctx context.Context,
3. set processor.CreateSettings,
4. cfg component.Config,
5. ) (processor.Traces, error) {
6. conf := cfg.(*Config)
8. return processorhelper.NewTracesProcessor(
9. ctx,
10. set,
11. conf,
12. func(ctx context.Context, td ptrace.Traces) (ptrace.Traces, error) {
13. rs := td.ResourceSpans()
15. for i := 0; i < rs.Len(); i++ {
16. ils := rs.At(i).ScopeSpans()
17. for j := 0; j < ils.Len(); j++ {
18. spans := ils.At(j).Spans()
19. for k := 0; k < spans.Len(); k++ {
20. span := spans.At(k)
21. span.Attributes().PutStr(conf.Key, conf.Value)
22. }
23. }
24. }
26. return td, nil
27. },
28. )
29. }
`AI写代码
在这种情况下,processor 会遍历 trace 数据,并为每个 span 添加一个属性。
Factory
Factory 将所有部分连接在一起:
csharp
`
1. func NewFactory() component.ProcessorFactory {
2. return processor.NewFactory("addattribute", createDefaultConfig, processor.WithTraces(createTracesProcessor))
3. }
5. func createDefaultConfig() component.Config {
6. return &Config{
7. Key: "env",
8. Value: "default",
9. }
10. }
`AI写代码
这告诉 Collector,该组件名为 addattribute(因此你可以在配置中使用该名称),并且它可以处理 traces。
🏗️ 打包自定义 collector
现在你有了自定义组件,你会想使用它。
为此,你需要构建一个自定义 collector,并告诉它提供这个组件。
在一个新文件夹中(你的自定义 collector 与组件不同),创建一个 builder-config.yaml 文件:
yaml
`
1. dist:
2. name: custom-collector
3. description: "Collector with custom processor"
4. output_path: ./dist
6. processors:
7. addattribute:
8. path: /path/to/your/component
`AI写代码
然后,构建你自己的 Collector:
arduino
`
1. go install go.opentelemetry.io/collector/cmd/builder@latest
2. builder --config builder-config.yaml
`AI写代码
你将在 dist 文件夹中得到一个自定义 Collector 二进制文件。
🚀 运行 collector
你可以像配置内置 processor 一样配置你的新 processor,通过配置 config.yaml:
markdown
`
1. receivers:
2. otlp:
4. processors:
5. addattribute:
6. key: "environment"
7. value: "staging"
9. exporters:
10. logging:
12. service:
13. pipelines:
14. traces:
15. receivers: [otlp]
16. processors: [addattribute]
17. exporters: [logging]
`AI写代码
启动 collector,发送一些 telemetry,你会看到你的自定义属性被添加到每个地方。
🎁 总结
OpenTelemetry Collector 不只是一个路由器。它是一个可扩展引擎,你可以:
- 添加新协议
- 执行自定义安全策略
- 按需转换数据
- 为任何后端构建 exporter
- 与社区共享你的组件
实际上,Elastic 的 OpenTelemetry 分发版是一个自定义 collector,其中包含内置组件以及为正确处理数据并发送到 Elasticsearch 所需的自定义组件。
你可以在 opentelemetry-collector-components 存储库中查看这些自定义组件。
无论你是想解决自己堆栈中的问题,还是贡献未来广泛使用的组件,构建一个自定义组件其实非常可行。