Nightingale 内置集成 mtail 插件:用正则表达式把日志转换为监控指标实战指南
2026/9/15 20:06:54 网站建设 项目流程

Nightingale 内置集成 mtail 插件:用正则表达式把日志转换为监控指标实战指南

【免费下载链接】nightingaleNightingale is to monitoring and alerting what Grafana is to visualization.项目地址: https://gitcode.com/GitHub_Trending/ni/nightingale

日志是系统运行状态的第一手证据,但监控系统只认识时序指标。mtail 插件的价值在于:它把「读取日志文件 → 正则提取字段 → 表达式计算 → 输出指标」这条链路收敛成一个声明式规则文件,让运维可以直接用接近 Golang 的语法把任意文本日志变成 counter、gauge、histogram 指标,再交由 Nightingale 采集、存储与告警。本文以 integrations/Mtail/markdown/README.md 为骨架,结合仓库内的 mtail.toml 配置模板与集成中心的装载逻辑,完整讲解插件的配置、规则语法、标签维度与时间处理,读完即可独立编写并调试自己的 mtail 规则。

插件定位:日志进,指标出

mtail 插件的工作方式可以用三句话概括:

  • 输入:日志(文件或目录,支持模糊匹配、多文件);
  • 输出:指标,仅支持counter(计数器)、gauge(瞬时值)、histogram(直方图)三种类型;
  • 处理:本质是 Golang 正则提取 + 表达式计算,即对每一行日志依次尝试规则文件中的正则,命中后执行对应的动作语句。

值得注意的是,这个插件属于 categraf 生态(categraf 是 Nightingale 默认配套的采集器),而 Nightingale 仓库本身把integrations/目录视为「categraf 配置语法与指标命名的权威事实来源」。例如 center/integration/init.go 在启动时会扫描integrations/下每个组件目录,把markdown/README.md的内容注册为内置组件说明(对应 init.go 的读取逻辑);aiagent/tools/integrations_loader.go 则把每个组件的markdown/README.mdcollect/*/*.toml一并编入文档索引(见 scanIntegrationComponent),供 AI 检索真实的[[instances]]写法。因此本文介绍的配置与规则,就是仓库内被当作 ground truth 的那一份。

快速启动:编辑 mtail.toml 并验证

1. 在 mtail.toml 中声明 instance

在 categraf 的conf/inputs.mtail/mtail.toml中指定采集实例。仓库自带的模板位于 integrations/Mtail/collect/mtail/mtail.toml,核心参数如下:

[[instances]] # progs = "/path/to/prog1" # mtail 规则文件目录(或单个文件) # logs = ["/path/to/a.log", "path/to/b.log"] # 要读取的日志,支持多个 # override_timezone = "Asia/Shanghai" # 日志时间时区 # emit_metric_timestamp = "true" # 字符串类型,注意是 "true" 而不是 true # [[instances]] # 需要第二个实例时再开一组 # progs = "/path/to/prog2" # logs = ["/path/to/logdir/"] # 也支持目录 # override_timezone = "Asia/Shanghai" # emit_metric_timestamp = "true"

原文档中的完整配置示例:

[[instances]] ## 指定 mtail prog 的目录 progs = "/path/to/prog1" ## 指定 mtail 要读取的日志 logs = ["/path/to/a.log", "path/to/b.log"] ## 指定时区 # override_timezone = "Asia/Shanghai" ## metrics 是否带时间戳,注意,这里是 "true" # emit_metric_timestamp = "true"

要点说明:

  • progs指向规则文件或规则目录;一般每个 instance 需要指定不同的 progs(不同的文件或目录),否则指标会相互干扰
  • 如果多个 instance 被迫共用同一份 progs,可以通过给每个 instance 增加 labels 做区分,两种写法等价:
labels = { k1=v1 }

或:

[instances.labels] k1=v1
  • logs支持模糊匹配(glob),也支持多个日志文件。
  • emit_metric_timestamp的取值是字符串"true"/"false",不要写成布尔值。

2. 编写规则文件

/path/to/prog1目录下创建规则文件,例如:

gauge xxx_errors /ERROR.*/ { xxx_errros++ }

3. 联调验证五步法

文档给出的标准调试流程非常实用:

  1. 一个终端中执行categraf --test --inputs mtail,用于测试;
  2. 另一个终端中,向/path/to/a.log/path/to/b.log追加一行包含ERROR的日志;
  3. 观察 categraf 的输出,确认指标被正确计数;
  4. 测试通过后,正常启动 categraf 即可。

--test模式是 categraf 内置的采集器调试开关,能直接看到 mtail 插件针对实时写入日志的输出,建议任何规则改动都先走这一步再上线。

处理规则与语法详解

处理流程

插件对每行日志的执行逻辑可以抽象为如下伪代码:

for line in lines: for regex in regexes: if match: do something

即逐行扫描、逐正则尝试匹配,命中则执行动作语句。这意味着规则的顺序会影响执行结果,多条规则可能同时命中同一行。

语法骨架

规则文件的顶层结构如下(类 Golang 风格):

exported variable # 声明指标/变量 pattern { # 匹配模式 + 动作 action statements } def decorator { # 装饰器:复用一段 pattern 与 action pattern and action statements }

定义指标名称

指标仅支持countergaugehistogram三种类型。一个最简单的例子:

counter lines /INFO.*/ { lines++ }

每命中一行包含INFO的日志,lines计数器自增。

命名约束:指标名称只支持 C 风格命名(字母/数字/下划线),如果想在指标名中使用-,必须用as导出别名:

counter lines_total as "line-count"

这样对外暴露的指标名就是line-count,而规则内部仍用lines_total引用。

匹配与计算(pattern/action)

PATTERN { ACTION }是核心结构,PATTERN 可以是正则、条件表达式,或两者的组合:

/foo/ { ACTION1 } variable > 0 { ACTION2 } /foo/ && variable > 0 { ACTION3 }

正则部分使用RE2 语法(Go 标准库的正则引擎),并且支持把正则定义为常量后再拼接:

const PREFIX /^\w+\W+\d+ / PREFIX { ACTION1 } PREFIX + /foo/ { ACTION2 }

上例中,ACTION1 匹配「以小写字符 + 大写字符(应为词字符)+ 数字 + 空格开头」的行(原文档注释:^\w+\W+\d+,即词字符序列 + 非词字符序列 + 数字 + 空格),ACTION2 在此基础上再要求后面以foo开头。正则常量拼接让复杂规则可读性大幅提升。

关系运算符

规则条件中可使用完整的关系运算:

  • <小于、<=小于等于
  • >大于、>=大于等于
  • ==相等、!=不等
  • =~匹配(模糊)、!~不匹配(模糊)
  • ||逻辑或、&&逻辑与、!逻辑非

数学运算符

动作语句中支持丰富的数学与位运算:

  • |按位或、&按位与、^按位异或
  • + - * /四则运算
  • <<按位左移、>>按位右移
  • **指数运算
  • =赋值、++自增、--自减、+=加且赋值

分支:else 与 otherwise

规则支持else分支:

/foo/ { ACTION1 } else { ACTION2 }

也支持条件嵌套,otherwise相当于「以上都不满足时兜底」:

/foo/ { /foo1/ { ACTION1 } /foo2/ { ACTION2 } otherwise { ACTION3 } }

命名与非命名提取

正则捕获组既可以用下标($1$3)引用,也可以用命名组((?P<name>...))引用:

/(?P<operation>\S+) (\S+) \[\S+\] (\S+) \(\S*\) \S+ (?P<bytes>\d+)/ { bytes_total[$operation][$3] += $bytes }

命名捕获的变量同样可以在条件中使用:

/(?P<x>\d+)/ && $x > 1 { nonzero_positives++ }

为指标增加标签

mtail 规则的标签能力分为两类,实战中要区分清楚。

常量标签(global 范围):用hidden text声明一个隐藏文本变量并赋值,再通过by声明到指标上:

# test.mtail # 定义常量 label env hidden text env # 给 label 赋值,这样定义是 global 范围; # 局部添加,则在对应的 condition 中添加 env="production" counter line_total by logfile,env /^(?P<date>\w+\s+\d+\s+\d+:\d+:\d+)/ { line_total[getfilename()][env]++ }

输出指标会自动带上env=production标签:

# metrics line_total{env="production",logfile="/path/to/xxxx.log",prog="test.mtail"} 4 1661165941788

注意输出中还有两个自动附加的标签:logfile(日志来源文件,由getfilename()函数写入)与prog(规则文件名),它们能帮助你在多文件、多规则场景下定位指标来源。

变量标签(必须命名提取):如果标签的值来自日志内容本身,则必须使用命名捕获组。例如有以下日志:

# 日志内容 192.168.0.1 GET /foo 192.168.0.2 GET /bar 192.168.0.1 POST /bar

规则可以按 host 与 verb 维度拆分指标:

# test.mtail counter my_http_requests_total by log_file, verb /^/ + /(?P<host>[0-9A-Za-z\.:-]+) / + /(?P<verb>[A-Z]+) / + /(?P<URI>\S+).*/ + /$/ { my_http_requests_total[getfilename()][$verb]++ }

输出结果按 verb 拆分:

# metrics my_http_requests_total{logfile="xxx.log",verb="GET",prog="test.mtail"} 4242 my_http_requests_total{logfile="xxx.log",verb="POST",prog="test.mtail"} 42

时间处理:系统时间、日志时间与时区陷阱

时间戳是监控指标正确性的关键,mtail 提供三档时间策略。

1. 默认:使用系统时间

不显式处理时,指标默认使用采集时刻的系统时间,且不携带时间戳字段。默认emit_metric_timestamp="false"(字符串),此时直方图输出形如:

http_latency_bucket{prog="histo.mtail",le="1"} 0 http_latency_bucket{prog="histo.mtail",le="2"} 0 http_latency_bucket{prog="histo.mtail",le="4"} 0 http_latency_bucket{prog="histo.mtail",le="8"} 0 http_latency_bucket{prog="histo.mtail",le="+Inf"} 0 http_latency_sum{prog="histo.mtail"} 0 http_latency_count{prog="histo.mtail"} 0

2. 携带时间戳:emit_metric_timestamp="true"

设置emit_metric_timestamp = "true"(注意是字符串)后,每条指标尾部会追加毫秒时间戳:

http_latency_bucket{prog="histo.mtail",le="1"} 1 1661152917471 http_latency_bucket{prog="histo.mtail",le="2"} 2 1661152917471 http_latency_bucket{prog="histo.mtail",le="4"} 2 1661152917471 http_latency_bucket{prog="histo.mtail",le="8"} 2 1661152917471 http_latency_bucket{prog="histo.mtail",le="+Inf"} 2 1661152917471 http_latency_sum{prog="histo.mtail"} 3 1661152917471 http_latency_count{prog="histo.mtail"} 4 1661152917471

可以看到 bucket 的le分桶与 sum/count 语义完全对齐 Prometheus 直方图规范:按1,2,4,8,+Inf累积分桶,count为总样本数,sum为延迟之和。

3. 使用日志时间:strptime + override_timezone

如果日志自带时间,可以解析日志时间作为指标时间戳。假设日志形如:

Aug 22 15:28:32 GET /api/v1/pods latency=2s code=200 Aug 22 15:28:32 GET /api/v1/pods latency=1s code=200 Aug 22 15:28:32 GET /api/v1/pods latency=0s code=200

规则用strptime解析日期字段,并计算延迟直方图:

histogram http_latency buckets 1, 2, 4, 8 /^(?P<date>\w+\s+\d+\s+\d+:\d+:\d+)/ { strptime($date, "Jan 02 15:04:05") /latency=(?P<latency>\d+)/ { http_latency=$latency } }

时区陷阱(重点):日志提取的时间,一定要注意时区问题。override_timezone参数控制日志时间解析使用的时区,否则默认按 UTC 转换

  • 启动时指定override_timezone=Asia/Shanghai,则Aug 22 15:34:32会被当作东八区时间转换为 timestamp,之后再从 timestamp 转换到各时区展示时就不会偏差,效果见 timestamp.png;
  • 如果不带override_timezone=Asia/ShanghaiAug 22 15:34:32默认被当作 UTC 时间转换为 timestamp,再转换为本地时间时会多出 8 个小时,效果见 timezone.png。

这正是文档反复强调「时区问题」的原因:strptime 只负责格式解析,时区归属由override_timezone决定。生产环境务必在 instance 配置中显式声明日志所在时区,避免时间戳偏移导致告警判定错误。

多实例、多规则文件的最佳实践

结合 mtail.toml 模板可以总结出几条实战建议:

  1. progs 隔离优先:每个 instance 使用独立的规则目录,避免指标互相干扰;确实要复用规则时,用labels = { k1=v1 }[instances.labels]区分。
  2. 目录也是合法日志源logs既可以是具体文件列表,也可以是日志目录(logs = ["/path/to/logdir/"]),配合模糊匹配适合日志轮转场景。
  3. 指标归属可追踪:输出指标自动带prog(规则文件名)与logfile(日志来源)标签,多规则、多文件时务必善用getfilename()by维度。
  4. 命名规范化:指标名遵循 C 风格命名,需要连字符时用as导出别名,避免 Prometheus 生态下游解析出问题。
  5. 时间策略统一:要么统一用系统时间,要么显式配置override_timezone并配合emit_metric_timestamp,混用不同时间来源会造成时序错乱。

在 Nightingale 中的集成视角

除了作为 categraf 采集插件,mtail 组件在 Nightingale 仓库中还承担了「内置集成」的角色:integrations/Mtail/目录下的markdown/README.mdmarkdown/README.en_US.mdcollect/mtail/mtail.toml会被 center/integration/init.go 在服务启动时扫描装载——README 成为组件说明,collect下的 toml 则作为采集配置模板对外提供(见 init.go 的目录扫描逻辑)。同时,cmd/integrations-i18n/main.go 中的 i18n 门禁要求中文 README 必须配套README.en_US.md英文副本,保证内置组件说明的国际化完整。这意味着你在本文学到的 mtail 配置语法,也正是 Nightingale 集成中心向用户展示、并由 AI 助手检索引用的权威写法。

小结

mtail 插件用一套简洁的「正则匹配 + 表达式计算」模型,把日志到指标的转换成本降到最低。核心要点可归纳为:

  • 三种指标类型:counter/gauge/histogram,声明即用;
  • 规则结构:pattern { action },支持 RE2 正则、常量拼接、else/otherwise分支与嵌套;
  • 维度扩展:常量标签用hidden text+ 全局赋值,变量标签必须走命名捕获组;
  • 时间策略:默认系统时间,emit_metric_timestamp控制是否带毫秒时间戳,strptime+override_timezone解析日志时间并规避时区偏移;
  • 调试路径:categraf --test --inputs mtail实时验证,通过后再正式启动。

掌握这些能力后,无论是解析 Nginx 访问日志统计接口 QPS、从应用日志提取延迟直方图,还是把业务埋点文本转成可告警的 counter 指标,都可以用几行 mtail 规则快速落地。

【免费下载链接】nightingaleNightingale is to monitoring and alerting what Grafana is to visualization.项目地址: https://gitcode.com/GitHub_Trending/ni/nightingale

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询