使用 OpenTelemetry Collector 接收任何自定义指标
博客文章在发布后不会更新。这篇文章已经发布一年多了,其内容可能已过时,部分链接可能无效。在依赖任何信息之前,请务必核实。
虽然 OpenTelemetry (OTel) 可以帮助您解决故障排除和处理“未知的未知数”,但它对于管理路由任务(例如监控系统指标,如磁盘使用情况、服务器可用性或 SSL 证书过期日期)也至关重要。这可以通过利用 OpenTelemetry Collector 可用的 90 多个接收器中的任何一个来实现,例如 Host Metrics Receiver 或 HTTP Check Receiver。
但是,如果现有接收器无法满足您的特定需求怎么办?假设您有一系列 shell 脚本可以提供自定义指标,并且您想将这些指标导出到 OpenTelemetry Collector。您可以编写自己的接收器,但这需要精通 Go。
在踏上这条道路之前,请仔细检查可用的接收器:其中一些接收器能够以不同的格式(如 Carbon、StatsD、InfluxDB、Prometheus,甚至 SNMP)吸收指标,并将它们集成到 OpenTelemetry 生态系统中。通过对 shell 脚本进行少量修改,您就可以使用其中一个接收器来实现您的目标。例如,Carbon Receiver 凭借其简单的 纯文本协议,非常适合与 shell 脚本一起使用。它的协议非常简单
纯文本协议是 Carbon 支持的最简单的协议。发送的数据必须采用以下格式:
<metric path> <metric value> <metric timestamp>。
示例脚本:检查证书过期情况
考虑以下 shell 脚本,该脚本接受主机名作为参数,并使用 openssl s_client 来检索证书并计算证书过期前的剩余时间
#!/bin/bash
HOST=${1}
PORT=${2:-443}
now=$(date +%s)
notAfterString=$(echo q | openssl s_client -servername "${HOST}" "${HOST}:${PORT}" 2>/dev/null | openssl x509 -noout -enddate | awk -F"=" '{ print $2; }')
if [[ "$(uname)" == "Darwin" ]] ; then
notAfter=$(date -j -f "%b %d %H:%M:%S %Y %Z" "${notAfterString}" +%s)
else
notAfter=$(date -d "${notAfterString}" +%s)
fi
secondsLeft=$(($notAfter-$now))
echo ${secondsLeft}
您可以按如下方式测试此脚本
$ ./ssl_check.sh opentelemetry.io
4357523
使用 Carbon 的纯文本协议
要使此脚本使用 Carbon 的纯文本协议,您需要修改脚本的最后几行,以 Carbon 格式输出指标
#!/bin/bash
HOST=${1}
PORT=${2:-443}
now=$(date +%s)
str=$(echo q | openssl s_client -servername "${HOST}" "${HOST}:${PORT}" 2>/dev/null | openssl x509 -noout -enddate | awk -F"=" '{ print $2; }')
if [[ "$(uname)" == "Darwin" ]] ; then
notAfter=$(date -j -f "%b %d %H:%M:%S %Y %Z" "${notAfterString}" +%s)
else
notAfter=$(date -d "${notAfterString}" +%s)
fi
secondsLeft=$(($notAfter-$now))
metricPath="tls.server.not_after.time_left;unit=s"
echo "${metricPath} ${secondsLeft} ${now}"
通过这样做,脚本将输出 <metric path> 为 tls.server.not_after.time_left;unit=s,<metric value> 为 ${secondsLeft},<metric timestamp> 为 ${now}。
这就是我们将指标发送到启用了 Carbon Receiver 的 OpenTelemetry Collector 所需的所有操作。
使用 OTel Collector 接收任何指标
要进行测试,请使用以下配置启动 OpenTelemetry Collector:
receivers:
carbon:
endpoint: localhost:8080
transport: tcp
parser:
type: plaintext
config:
exporters:
debug:
verbosity: detailed
service:
pipelines:
metrics:
receivers: [carbon]
exporters: [debug]
例如,如果您已将此文件保存为 collector-config.yml,请执行以下命令
$ ./otelcol --config collector-config.yml
2023-11-24T12:52:51.340+0100 info service@v0.89.0/telemetry.go:85 Setting up own telemetry...
2023-11-24T12:52:51.341+0100 info service@v0.89.0/telemetry.go:202 Serving Prometheus metrics {"address": ":8888", "level": "Basic"}
2023-11-24T12:52:51.341+0100 info exporter@v0.89.0/exporter.go:275 Development component. May change in the future. {"kind": "exporter", "data_type": "metrics", "name": "debug"}
2023-11-24T12:52:51.341+0100 info service@v0.89.0/service.go:143 Starting otelcol-any-metric... {"Version": "1.0.0", "NumCPU": 10}
2023-11-24T12:52:51.341+0100 info extensions/extensions.go:34 Starting extensions...
2023-11-24T12:52:51.342+0100 info service@v0.89.0/service.go:169 Everything is ready. Begin running and processing data.
对于测试,您可以使用 OpenTelemetry Collector Contrib 发行版,其中包含所有可用的接收器。但是,在生产环境中,您可以使用 OpenTelemetry Collector Builder(ocb)构建自己的 Collector。这是一个建议的配置
dist:
name: otelcol-any-metric
description: Custom OpenTelemetry Collector for receiving any kind of metric
output_path: ./
exporters:
- gomod: go.opentelemetry.io/collector/exporter/debugexporter v0.89.0
- gomod: go.opentelemetry.io/collector/exporter/otlpexporter v0.89.0
- gomod: go.opentelemetry.io/collector/exporter/otlphttpexporter v0.89.0
processors:
- gomod:
github.com/open-telemetry/opentelemetry-collector-contrib/processor/transformprocessor
v0.89.0
receivers:
- gomod: go.opentelemetry.io/collector/receiver/otlpreceiver v0.89.0
- gomod:
github.com/open-telemetry/opentelemetry-collector-contrib/receiver/carbonreceiver
v0.89.0
在 OpenTelemetry Collector 运行后,打开第二个 shell 并将您的指标传输到其中
./ssl_check.sh opentelemetry.io | nc 127.0.0.1 8080
Debug Exporter 将在控制台上为您显示指标
2023-11-24T12:54:51.369+0100 info ResourceMetrics #0
Resource SchemaURL:
ScopeMetrics #0
ScopeMetrics SchemaURL:
InstrumentationScope
Metric #0
Descriptor:
-> Name: tls.server.not_after.time_left
-> Description:
-> Unit:
-> DataType: Gauge
NumberDataPoints #0
Data point attributes:
-> unit: Str(s)
StartTimestamp: 1970-01-01 00:00:00 +0000 UTC
Timestamp: 2023-11-24 11:54:51 +0000 UTC
Value: 4356471
{"kind": "exporter", "data_type": "metrics", "name": "debug"}
就是这样!您可以对任何其他报告自定义指标的 shell 脚本使用相同的技术。
使用 Transform Processor 进行精细调整
Carbon Receiver 使用 ; 作为分隔符来分割 <metric path>,以提取指标名称(第一个元素)和数据点属性(所有其他元素)。在我们的示例中,这意味着指标名称将是 tls.server.not_after.time_left,并且将具有数据点属性 unit: Str(s)。
虽然这种方法很简单,但它不允许您设置任何其他详细信息,例如资源、指标描述或特别地,指标单位。
但是,Transform Processor 可以帮助您。通过将 OpenTelemetry Transformation Language (OTTL) 语句集成到您的 collector-config.yml 中,您可以将数据点属性 unit 转换为指标的单位
receivers:
carbon:
endpoint: localhost:8080
transport: tcp
parser:
type: plaintext
config:
exporters:
debug:
verbosity: detailed
processors:
transform:
metric_statements:
- context: datapoint
statements:
- set(metric.unit, attributes["unit"])
- delete_key(attributes, "unit")
service:
pipelines:
metrics:
receivers: [carbon]
processors: [transform]
exporters: [debug]
再次运行 ssl_check.sh
./ssl_check.sh opentelemetry.io | nc 127.0.0.1 8080
现在,Debug Exporter 还将把单位包含到指标描述符中
2023-11-24T12:54:51.369+0100 info ResourceMetrics #0
Resource SchemaURL:
ScopeMetrics #0
ScopeMetrics SchemaURL:
InstrumentationScope
Metric #0
Descriptor:
-> Name: tls.server.not_after.time_left
-> Description:
-> Unit: s
-> DataType: Gauge
NumberDataPoints #0
Data point attributes:
-> unit: Str(s)
StartTimestamp: 1970-01-01 00:00:00 +0000 UTC
Timestamp: 2023-11-24 11:54:51 +0000 UTC
Value: 4356471
{"kind": "exporter", "data_type": "metrics", "name": "debug"}
如果您希望将指标与您使用 OpenTelemetry 进行检测的服务关联起来,您可以首先将 service.name 和 service.namespace 添加到您的 shell 脚本中作为数据点属性
metricName="tls.server.not_after.time_left;unit=s;service.name=otel-webserver;service.namespace=opentelemetry.io"
echo "${metricName} ${secondsLeft} ${now}"
接下来,添加另一个 OTTL 语句,从这些数据点属性创建资源
processors:
transform:
metric_statements:
- context: datapoint
statements:
- set(metric.unit, attributes["unit"])
- set(resource.attributes["service.name"], attributes["service.name"])
- set(resource.attributes["service.namespace"],
attributes["service.namespace"])
- delete_key(attributes, "unit")
- delete_key(attributes, "service.name")
- delete_key(attributes, "service.namespace")
再次运行 ssl_check.sh
./ssl_check.sh opentelemetry.io | nc 127.0.0.1 8080
现在,Debug Exporter 还将包含具有 service.name 和 service.namespace 属性的资源
2023-11-24T14:49:03.806+0100 info ResourceMetrics #0
Resource SchemaURL:
Resource attributes:
-> service.name: Str(otel-webserver)
-> service.namespace: Str(opentelemetry.io)
ScopeMetrics #0
ScopeMetrics SchemaURL:
InstrumentationScope
Metric #0
Descriptor:
-> Name: tls.server.not_after.time_left
-> Description:
-> Unit: s
-> DataType: Gauge
NumberDataPoints #0
StartTimestamp: 1970-01-01 00:00:00 +0000 UTC
Timestamp: 2023-11-24 13:49:03 +0000 UTC
Value: 4349619
{"kind": "exporter", "data_type": "metrics", "name": "debug"}
Transform Processor 和 OTTL 提供了广泛的功能。从中了解更多
- OTTL README.md
- OTTL Me Why Transforming Telemetry in the OpenTelemetry Collector Just Got Better,由 Tyler Helmuth 和 Evan Bradley 发表演讲
这样,您就可以使用 OpenTelemetry Collector 接收任何自定义指标了!
奖励:使用 OTLP!
虽然使用 Carbon Receiver 和 Transform Processor 是一种可靠的收集自定义指标的方法,但使用外部格式将指标导入 OpenTelemetry 可能显得有些不寻常,尤其是当 OpenTelemetry Protocol (OTLP) 提供了您所需的一切时。
作为 Carbon Receiver 的替代方案,您还可以使用 OTLP JSON 发送自定义指标
#!/bin/bash
URL=${1}
PORT=${2:-443}
now=$(date +%s)
notAfterString=$(echo q | openssl s_client -servername "${URL}" "${URL}:${PORT}" 2>/dev/null | openssl x509 -noout -enddate | awk -F"=" '{ print $2; }')
if [[ "$(uname)" == "Darwin" ]] ; then
notAfter=$(date -j -f "%b %d %H:%M:%S %Y %Z" "${notAfterString}" +%s)
else
notAfter=$(date -d "${notAfterString}" +%s)
fi
secondsLeft=$(($notAfter-$now))
data="
{
\"resourceMetrics\": [
{
\"resource\": {
\"attributes\": [
{
\"key\": \"service.name\",
\"value\": {
\"stringValue\": \"${URL}\"
}
}
]
},
\"scopeMetrics\": [
{
\"metrics\": [
{
\"name\": \"tls.server.not_after.time_left\",
\"unit\": \"s\",
\"description\": \"\",
\"gauge\": {
\"dataPoints\": [
{
\"asInt\": ${secondsLeft},
\"timeUnixNano\": ${now}000000000
}
]
}
}
]
}
]
}
]
}
"
curl -X POST -H "Content-Type: application/json" -d "${data}" -i localhost:4318/v1/metrics
在您的 collectors-config 中启用 OTLP Receiver
receivers:
otlp:
protocols:
http:
grpc:
exporters:
debug:
verbosity: detailed
service:
pipelines:
metrics:
receivers: [otlp]
exporters: [debug]
执行您的更新后的 ssl_check.sh
./ssl_check.sh opentelemetry.io
这次,您的指标将显示正确的单位设置,并且资源将按 JSON 中的定义进行报告
2023-11-24T15:28:51.212+0100 info ResourceMetrics #0
Resource SchemaURL:
Resource attributes:
-> service.name: Str(opentelemetry.io)
ScopeMetrics #0
ScopeMetrics SchemaURL:
InstrumentationScope
Metric #0
Descriptor:
-> Name: tls.server.not_after.time_left
-> Description:
-> Unit: s
-> DataType: Gauge
NumberDataPoints #0
StartTimestamp: 1970-01-01 00:00:00 +0000 UTC
Timestamp: 2023-11-24 14:28:51 +0000 UTC
Value: 4347231
{"kind": "exporter", "data_type": "metrics", "name": "debug"}
在 shell 脚本中处理 JSON 并不理想,正如本示例清楚表明的那样!虽然有改进的方法,但最终您可能会发现使用 Python 或 Node.js 等语言,或将指标(支持 gauge)集成到您喜欢的 OTel CLI 工具中效率更高!
摘要
在本篇文章中,您学习了如何使用像 Carbon Receiver 这样的“通用”接收器将任何指标馈送到 OpenTelemetry Collector。当现有接收器不满足您的需求并且您不想用 Go 编写自己的接收器时,请使用此方法。
您学会了如何直接使用 OTLP 和 curl 将指标发送到 OpenTelemetry Collector。当您无法修改 OpenTelemetry Collector 的管道时,请使用此方法。随着通过 OTLP 导出指标的命令行工具的可用,它也将成为“通用”接收器的有效替代方案。