Skip to content

Prometheus 监控实战系列 09:日志监控实战:基于 mtail 实现日志数据到指标的转化与应用

约 1824 字大约 6 分钟

Prometheus 监控实战系列Prometheus

2026-03-29

在主机、容器、应用监控之外,日志是另一类承载系统状态的核心数据——尤其对于无法直接暴露监控指标的遗留应用,调整日志输出并提取指标,是低成本实现可观测性的关键手段。本文将聚焦 mtail 工具,详解如何将日志数据转化为 Prometheus 可抓取的时序指标,完成日志监控的落地实践。

一、为什么选择 mtail 做日志指标提取?

日志中包含请求耗时、错误码、响应字节数等关键信息,但原生日志无法被 Prometheus 直接采集。常见的日志处理工具中:

  • GrokExporter 功能强大但相对厚重;
  • ELK/Logstash 无法直接输出 Prometheus 指标(需借助插件间接对接);
  • mtail(Google SRE 开发,Go 语言实现,Apache2.0 协议):轻量、易用,专为“从日志提取时序指标”设计,原生支持 Prometheus 输出,是日志转指标的最优选择之一。

mtail 的核心逻辑:通过自定义“mtail 程序”定义日志匹配规则,将匹配到的日志内容转化为 Counter/Gauge 等指标,暴露 HTTP 端点供 Prometheus 抓取。

二、mtail 环境搭建

2.1 下载与安装

mtail 提供多平台二进制包,以 Linux x86_64 为例:

# 下载二进制包(修正原文-0参数错误,应为-O)
wget https://github.com/google/mtail/releases/download/v3.0.0-rc16/mtail_v3.0.0-rc16/linux_amd64 -O mtail
# 添加执行权限
chmod 0755 mtail
# 移动到系统可执行目录
sudo cp mtail /usr/local/bin

验证安装是否成功:

mtail --version
# 预期输出:mtail version v3.0.0-rc16-xxx go version go1.8.3

2.2 mtail 核心概念

  • mtail 程序:后缀为 .mtail 的脚本文件,定义“日志匹配规则 + 指标操作逻辑”;
  • 指标类型:支持 Counter(计数器)、Gauge(测量值),需先定义再使用;
  • 匹配规则:基于 RE2 正则表达式,支持条件逻辑(else 子句)、关系表达式;
  • 暴露端点:默认在 3903 端口启动 HTTP 服务,/metrics 路径输出 Prometheus 格式指标。

三、基础实战:日志行计数(快速上手)

通过最简单的“统计日志总行数”示例,理解 mtail 核心用法。

3.1 创建 mtail 程序目录

sudo mkdir /etc/mtail

3.2 编写基础 mtail 程序

创建 line_count.mtail 文件,实现“每解析一行日志,计数器 +1”:

# 定义计数器指标
counter line_count

# 匹配所有日志行(/$/ 匹配行尾),匹配后递增计数器
/$/ {
    line_count++
}

将文件放入程序目录:

sudo cp line_count.mtail /etc/mtail/

3.3 启动 mtail 并验证

启动 mtail,指定程序目录和待解析的日志文件:

sudo mtail --progs /etc/mtail --logs '/var/log/*.log'
  • --progs:指定 mtail 程序目录;
  • --logs:指定待解析的日志文件(支持 glob 通配符、逗号分隔列表、多次指定);
  • mtail 自动处理日志截断、轮换,无需额外配置。

验证指标输出

访问 mtail 诊断页面:http://<主机IP>:3903,可查看 mtail 运行状态、已加载程序等信息。

访问 http://<主机IP>:3903/metrics,可看到 Prometheus 格式的指标:

TYPE line_count counter
# line_count defined at line_count.mtail:1:9-18
line_count{prog="line_count.mtail"} 1561
  • prog 标签默认携带生成指标的程序名,可通过 --emit_prog_label=false 关闭。

四、进阶实战1:解析 Apache 访问日志

以 Apache combined 日志格式为例,提取“请求数、响应字节数”指标,并按「请求方法、HTTP 版本、响应状态码」维度拆分。

4.1 编写 Apache 日志解析程序

创建 /etc/mtail/apache_combined.mtail,内容如下:

# 定义计数器:按请求方法/HTTP版本/响应状态码维度统计请求数
counter apache_http_requests_total by request_method, http_version, request_status
# 定义计数器:按相同维度统计响应字节数
counter apache_http_bytes_total by request_method, http_version, request_status

# 匹配 Apache combined 日志格式(RE2 正则)
/^(?P<hostname>\S+) \S+ \S+ \[(?P<timestamp>[^\]]+)\] "(?P<request_method>[A-Z]+) (?P<path>\S+) (?P<http_version>HTTP/\d\.\d)" (?P<request_status>\d{3}) (?P<response_size>\d+) "(?P<referer>[^"]*)" "(?P<user_agent>[^"]*)"$/ {
    # 递增请求数计数器
    apache_http_requests_total[$request_method][$http_version][$request_status]++
    # 累加响应字节数(转为数值类型)
    apache_http_bytes_total[$request_method][$http_version][$request_status] += strptoul($response_size, 10)
}

4.2 启动 mtail 并验证

sudo mtail --progs /etc/mtail --logs '/var/log/apache/*.access.log'

访问 /metrics 可看到维度化的指标:

# TYPE apache_http_requests_total counter
apache_http_requests_total{http_version="HTTP/1.1",request_method="GET",request_status="200",prog="apache_combined.mtail"} 73
apache_http_requests_total{http_version="HTTP/1.1",request_method="GET",request_status="304",prog="apache_combined.mtail"} 3

# TYPE apache_http_bytes_total counter
apache_http_bytes_total{http_version="HTTP/1.1",request_method="GET",request_status="200",prog="apache_combined.mtail"} 2814654
apache_http_bytes_total{http_version="HTTP/1.1",request_method="GET",request_status="304",prog="apache_combined.mtail"} 0

五、进阶实战2:解析 Rails 日志构建性能直方图

Rails 日志包含请求耗时信息,通过 mtail 提取耗时并构建直方图,分析请求性能分布。

5.1 编写 Rails 日志解析程序

创建 /etc/mtail/rails.mtail,内容如下:

# 基础计数器:启动/完成的请求数
counter rails_requests_started_total
counter rails_requests_started by verb
counter rails_requests_completed_total
counter rails_requests_completed by status

# 耗时统计:总和、计数、直方图桶(按耗时区间拆分)
counter rails_requests_completed_milliseconds_sum by status
counter rails_requests_completed_milliseconds_count by status
counter rails_requests_completed_milliseconds_bucket by le, status

# 匹配请求启动日志
/^Started (?P<verb>[A-Z]+) .*/ {
    rails_requests_started_total++
    rails_requests_started[$verb]++
}

# 匹配请求完成日志,提取状态码和耗时
/^Completed (?P<status>\d{3}) .+ in (?P<request_milliseconds>\d+)ms .*$/ {
    rails_requests_completed_total++
    rails_requests_completed[$status]++
    
    # 累加耗时总和与计数
    rails_requests_completed_milliseconds_sum[$status] += strptoul($request_milliseconds, 10)
    rails_requests_completed_milliseconds_count[$status]++
    
    # 构建直方图桶(le = less than or equal)
    $request_milliseconds <= 10 {
        rails_requests_completed_milliseconds_bucket["10"][$status]++
    }
    $request_milliseconds <= 50 {
        rails_requests_completed_milliseconds_bucket["50"][$status]++
    }
}

5.2 验证指标输出

启动 mtail 解析 Rails 日志后,/metrics 会输出如下指标:

rails_requests_started_total{prog="rails.mtail"} 44
rails_requests_started{verb="POST",prog="rails.mtail"} 19
rails_requests_completed_milliseconds_bucket{le="10",status="200",prog="rails.mtail"} 93
rails_requests_completed_milliseconds_bucket{le="50",status="200",prog="rails.mtail"} 217

通过直方图桶可清晰看到:200 状态的请求中,93 个耗时 ≤10ms,所有 217 个请求耗时 ≤50ms。

六、mtail 部署最佳实践

  1. 边车(Sidecar)模式:推荐为每个应用部署一个 mtail 实例(容器化场景更友好),避免单实例处理多应用日志导致的性能问题;
  2. 单实例多程序:若需单实例运行多个 mtail 程序,需注意 mtail 会对所有日志文件执行所有程序,可能增加主机负载;
  3. 权限配置:mtail 运行用户需具备日志文件的读取权限,否则会在 --logtostderr 输出中看到读取错误;
  4. 端口自定义:通过 --address <IP>--port <端口> 调整 mtail 暴露的 HTTP 端点(默认 3903)。

七、Prometheus 抓取 mtail 指标

7.1 配置 Prometheus 抓取任务

修改 Prometheus 配置文件 prometheus.yml,添加基于文件发现的抓取任务:

scrape_configs:
  - job_name: 'mtail'
    file_sd_configs:
      - files:
          - 'targets/mtail/*.json'
        refresh_interval: 5m  # 5分钟刷新一次目标列表
    scrape_interval: 15s  # 抓取间隔

7.2 定义抓取目标

创建 targets/mtail/mtail_targets.json,指定 mtail 实例地址:

[
  {
    "targets": ["web:3903", "rails:3903"],
    "labels": {
      "env": "production"
    }
  }
]

重启 Prometheus 后,即可在 Prometheus UI 中看到 mtail 生成的所有指标,用于告警、可视化等场景。

八、总结与拓展

mtail 是日志转 Prometheus 指标的轻量利器,通过自定义正则匹配和指标逻辑,可快速挖掘日志中的可观测性价值,尤其适合遗留系统的监控补全。

拓展学习资源