1. 前言
我曾经写过一篇关于OpenTelemetry的文章,介绍如何使用基于eBPF的绝对无侵入方式来监控各种语言的应用。这种方式仍然是OpenTelemetry非侵入式监控GoLang应用的主要方式之一,但还有一种不修改应用代码来监控GoLang应用的方法,也比较成熟并被广泛使用,这里一并介绍一下。
2. 使用基于eBPF的绝对无侵入方式(OBI)
这是对我原来的文章《OpenTelemetry OBI - 非侵入式监控各种语言应用的神器的简单回顾,详细信息请参照原文。
首先要下载OBI工具,到 OBI 的发行网页(Releases · open-telemetry/opentelemetry-ebpf-instrumentation · GitHub),根据您的平台选择最新的发行版来下载。比如对于最常见的平台(amd64) 和当前最新的版本好v0.10.0, 下载:obi-v0.10.0-linux-amd64.tar.gz。
配饰OBI的方式非常多。可以采用环境变量,也可以用配置文件。对于这个简单的测试,我使用了以下的配置文件:obi.yaml
XML
discovery:
instrument:
- open_ports: 8080,9090,28080
log_level: DEBUG
ebpf:
context_propagation: all
otel_traces_export:
endpoint: http://localhost:4318
otel_metrics_export:
endpoint: http://loalhost:4318
注意:
- 这个配置文件说明我要监控8080、9090和28080三个端口的应用。
- 通过OTLP协议发送信息到OpenTelemetry Collector或者OpenTelemetry后端,这个例子里是http://localhost:4318。
以下是运行OBI的命令(在应用所在的Linux主机上运行,注意应用的端口必须在 obi.yaml 设置的范围之内):
bash
sudo ./obi --config=./obi.yaml
至于配置OBI的详细说明,请参照官方文档:Configure OBI | OpenTelemetry
为了让OpenTelemetry很好的区分不同的应用,请在启动应用之前,设置OTEL_SERVICE_NAME环境变量。例如:
export OTEL_SERVICE_NAME=my-godemo
./app
这样,如果访问您的程序,在OpenTelemetry Collector或者OpenTelemetry后端,就可以发现大量的metrics和traces。
3. 使用编译时无侵入插桩(Compile-Time Instrumentation)
3.1 概述
这种方式也不需要修改应用代码,只是需要稍微调整一下编译的命令。
没有额外配置的情况下,编译时无侵入插桩 otelc 会自动扫描并识别项目中引入的以下依赖,并自动为你应用内置的 Hook 规则:
- HTTP 框架
net/http(标准库)、github.com/gin-gonic/gin
自动拦截 HTTP Request/Response,自动从 Header 提取/注入 TraceContext
- RPC 框架
自动拦截 gRPC Client & Server 调用并续接 Trace
- 数据库/SQL
database/sql(标准库)、go.mongodb.org/mongo-driver
自动拦截 SQL 查询,记录 SQL 语句与耗时
- 缓存/MQ
自动记录 Redis 命令、Kafka 消息发布/消费
- 日志与指标
log/slog(标准库)、github.com/sirupsen/logrus、Go runtime
自动将当前的 Trace ID / Span ID 注入日志,自动收集 Go 运行时指标
3.2 下载 otelc 工具
到"Releases · open-telemetry/opentelemetry-go-compile-instrumentation · GitHub"选择和您的平台匹配的otelc的最高版本下载即可。对于我使用的Linux平台,大致的命令如下:
wget https://github.com/open-telemetry/opentelemetry-go-compile-instrumentation/releases/download/v1.0.1/otelc-linux-amd64
mv otelc-linux-amd64 otelc
chmod +x otelc
如果为了方便调用,可以把 otelc 放到 /usr/bin 下。
3.3 使用 otelc 编译GoLang代码
如果您原来的编译命令是:
go build -o httpsvr
那就改成:
otelc go build -o httpsvr
自动插桩在编译时完成!
3.4 运行被编译时插桩的程序
如果您原来只是简单地执行:
./httpsvr
现在还需要指定您的应用的OpenTelemetry服务名(这里假设是my-service),还有如何发送数据到OpenTelemetry Collector或者OpenTelemetry后端(这里假设是http://localhost:4318)。那么需要的命令是:
export OTEL_SERVICE_NAME=my-service
export OTEL_TRACES_EXPORTER=otlp
export OTEL_METRICS_EXPORTER=otlp
export OTEL_LOGS_EXPORTER=otlp
export OTEL_EXPORTER_OTLP_ENDPOINT="http://localhost:4318"
export OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
./httpsvr
好了,这时候如果访问您的程序,您就可以在OpenTelemetry Collector或者OpenTelemetry后端看到大量metrics和traces了。
3.5 编译时插装还可以使用配置文件进行增强
通过使用编译时插装的配置文件,可以给指定的任意函数加trace。但是目前没有官方提供的通用包,不但要有配置, 还需要自己编写一些代码。 虽然加trace不难, 但是拼接trace和span有难度。我这里就先不写了,详情请参考:Go compile-time instrumentation | OpenTelemetry。
4. 比较"编译时无侵入插桩 (otelc)"和"基于 eBPF 的无侵入插桩 (OBI)"
- "编译时无侵入插桩 (otelc)"的强项
- Go 框架的理解
- 自定义函数插桩(目前还没有通用的代码)
- "基于 eBPF 的无侵入插桩 (OBI)"的强项
- 真正零侵入,简单易行
- 跨语言
- 操作系统底层网络连接的感知能力
您可以配合两种插桩方式,为了避免一个调用多个trace,可以禁止一部分"编译时无侵入插桩 (otelc)",在启动引用前可以增加如下的环境变量:
export OTEL_GO_DISABLED_INSTRUMENTATIONS=nethttp,grpc
5. 总结
本文介绍了两种非侵入式监控GoLang应用的方法:基于eBPF的绝对无侵入方式(OBI)和编译时无侵入插桩(otelc)。OBI通过下载工具并配置监控端口,无需修改代码即可收集应用指标和追踪数据。编译时插桩则需在构建阶段使用otelc工具,自动为常见框架添加监控功能,运行时通过环境变量配置数据导出。两种方式各有优势:OBI简单跨语言,otelc对Go框架支持更深入且支持自定义函数插桩。文章详细说明了两种方法的配置步骤,并建议可根据需求配合使用,同时提供了相关官方文档链接供进一步参考。