概述
OpenTelemetry(简称 otel) 是一个可观测框架和工具包, 旨在创建和管理遥测数据,如链路、指标和日志等。OpenTelemetry 不是像 Jaeger、Prometheus 或其他商业供应商那样的可观测性后端,它专注于遥测数据的生成、采集、管理和导出。
OpenTelemetry 架构图(引用自官方)
其中 otel collector 组件承担了遥测数据的采集,处理,导出的能力,是其中比较关键的组件。本篇文章就介绍下如何使用 otel collector 对日志数据进行采集,希望读者能了解到 otel collector 的用法。
Otel collector 架构介绍
Otel collector 可以对链路、指标和日志数据进行采集、处理和导出,从实现上分为核心层以及各种组件, 其中重要的组件层包括 Receiver、Processor 和 Exporter,如下图架构所示。
otel collector 的架构图(引用自官网)
Otel collector 核心代码仓库为 opentelemetry-collector,主要是 otel collector 官方核心层的实现,另外一个仓库 opentelemetry-collector-contrib 集合了很多第三方的插件, 这里组件功能比较丰富,一般我们会基于 opentelemetry-collector-contrib 安装部署。如果自定义 otel collector 的功能,比如只部署所需的组件,可以使用ocb进行自定义所需的 otel collector 进行部署。
为什么要用 otel collector 采集日志数据
单从日志的采集/处理服务来讲,比较常用的采集侧有 fluent, filebeat/logstash 等,尤其是因为 elk 成熟的日志服务解决方案,日志采集处理侧使用 filebeat/logstash 的特别多。但 elk 这套日志服务的解决方案存在了一些问题,logstash,elasticsearch 都是基于 java, 资源使用较多,随着需要采集的日志量越来越大,elasticsearch 的检索性能问题会越来越显著。新的大数据领域 OLAP 的解决方案,比如 clickhouse, starrocks 等软件服务的出现,日志服务使用 elasticsearch 不再是唯一选择,并且在体验要求高、资源限制高的场景下, 其他解决方案更具备性价比,最近几年经常有大厂互联网公司使用 clickhouse 或者 starrocks 取代 elasticsearch 建设日志服务,性能提升一个数量级的报道。
Otel collector 跟数据存储服务的生态耦合不大,它支持数据导出到各个主流存储服务,是可观测服务搭建的首选数据采集器。它不仅仅支持日志数据的采集,还支持链路、指标数据,方便可观测服务的技术栈统一。
性能上,基于基准性能测试结果,filebeat 在 3M/s 的数据采集中 CPU 单核使用 52%,内存使用 144M; otel collector CPU 单核使用 20%,内存使用 90M, 表现优异。
如何使用 otel collector 取代 filebeat/logstash 做日志数据采集
Otel collector 的配置分为 receiver、processor、exporter 等组件配置以及 service 做 pipline 的编排配置,而且 transform/grok processor 使用了和 logstash 同样的 grok 库,迁移的转换成本是比较低的。
比如 java 应用的日志采集之后需要经过正则表达式的解析转换为结构化的数据进行存储,在 logstash 的配置
filter {
if [log_tag] == "app-java" {
mutate {
rename => ["message","doc"]
}
grok {
patterns_dir => "/etc/logstash/patterns"
match => { "doc" => "%{JAVA_LOG}" }
remove_field => ["doc", "kubernetes"]
}
}
}
复制代码
其中对应正则表达式为
JAVA_LOG %{TIMESTAMP_ISO8601:time} %{DATA:level} %{WORD:line} --- \[%{DATA:thread}\] \[%{DATA:logger}\] \[%{DATA:class}\] : \[%{DATA:traceid}\] %{MESSAGE:message}
复制代码
如果使用 otel collector, 配置如下
processors:
transform/grok-app-java:
error_mode: ignore
log_statements:
- conditions:
- IsMap(attributes)
context: log
statements:
- 'merge_maps(attributes, ExtractGrokPatterns(attributes["body"], "%{TIMESTAMP_ISO8601:time}
%{DATA:level} %{NUMBER:line:int} --- \\[%{DATA:thread}\\] \\[%{DATA:logger}\\]
\\[%{DATA:class}\\] : \\[%{DATA:traceid}\\] %{MESSAGE:message}", true), "insert")'
- delete_key(attributes, "body")
复制代码
otel collector 采集容器日志的配置如下:
receivers:
filelog/log-java:
exclude:
- /var/log/pods/*/log-opentelemetry-agent/*.log
include:
- /var/log/pods/*/*/*.log*
include_file_name: false
include_file_path: true
operators:
- id: get-format
routes:
- expr: body matches "^\\{"
output: parser-docker
- expr: body matches "^[^ Z]+ "
output: parser-crio
- expr: body matches "^[^ Z]+Z"
output: parser-containerd
type: router
- id: parser-crio
output: extract_metadata_from_filepath
regex: ^(?P<time>[^ Z]+) (?P<stream>stdout|stderr) (?P<logtag>[^ ]*) ?(?P<log>.*)$
timestamp:
layout: 2006-01-02T15:04:05.999999999Z07:00
layout_type: gotime
parse_from: attributes.time
type: regex_parser
- id: parser-containerd
output: extract_metadata_from_filepath
regex: ^(?P<time>[^ ^Z]+Z) (?P<stream>stdout|stderr) (?P<logtag>[^ ]*) ?(?P<log>.*)$
timestamp:
layout: '%Y-%m-%dT%H:%M:%S.%LZ'
parse_from: attributes.time
type: regex_parser
- id: parser-docker
output: extract_metadata_from_filepath
timestamp:
layout: '%Y-%m-%dT%H:%M:%S.%LZ'
parse_from: attributes.time
type: json_parser
- cache:
size: 128
id: extract_metadata_from_filepath
parse_from: attributes["log.file.path"]
regex: ^.*\/(?P<namespace>[^_]+)_(?P<pod_name>[^_]+)_(?P<uid>[a-f0-9\-]{36})\/(?P<container_name>[^\._]+)\/(?P<restart_count>\d+)\.log$
type: regex_parser
- from: attributes.log
to: attributes.body
type: move
- from: attributes.container_name
to: attributes.app_name
type: move
- combine_field: attributes.body
combine_with: "\n"
source_identifier: attributes["log.file.path"]
is_first_entry: attributes.body matches "^\\d{4}-\\d{2}-\\d{2}"
type: recombine
start_at: end
storage: file_storage
复制代码
这只是它其中一部分功能,目前仓库里面已经集成了 receiver 组件接近 100 个,processor 组件 20+,exporter 组件 40+,涵盖几乎所有的数据采集,处理,导出的功能。美中不足的是,组件的介绍跟实践案例的资料比较少,建议在实际使用的时候看下源码了解下功能配置。
最后,附上日志服务架构图
日志服务架构图
如果使用 clickhouse 做日志数据存储的话,elasticsearch/kibana 的功能就可以直接使用 clickhouse 取代。
评论