四夜莺n9e(Flashcat)监控:mtail监控日志

一. mtail与categraf中的mtail

谷歌开源的从日志提取metric的工具 项目地址:github.com/google/mtai... mtail服务下载解压:

categraf中的mtail:github.com/flashcatclo...

  • categraf 将mtail作为一个插件集成了进来,并且兼容 mtail 的语法,简化了部署。一般都是一个 mtail 进程处理一类日志,但是对于很高配的物理机,上面会部署很多不同的服务,每个服务进程都对应一个 mtail,此时机器上会出现特别多的 mtail 进程,较难维护。

  • 把 mtail 集成到 categraf 之后,复用 categraf 的多实例插件机制,可以做到一台机器上只有一个 categraf 进程即可读取解析多个服务的日志

  • 功能: 提取日志内容,转换为监控metrics

  • 输入: 日志

  • 输出: metrics 按照mtail语法输出, 仅支持counter、gauge、histogram

  • 处理: 本质是golang的正则提取+表达式计算

二. mtail安装

shell 复制代码
# 去gitlab上下载
$ wget https://github.com/google/mtail/releases/download/v3.0.0-rc51/mtail_3.0.0-rc51_Linux_x86_64.tar.gz
$ tar xf mtail_3.0.0-rc51_Linux_x86_64.tar.gz
$ cp mtail /usr/local/bin
 
# 查看mtail版本
$ mtail --version

 
# mtail后台启动
$ nohup mtail -port 3903 -logtostderr -progs test.mtail -logs test.log &
 
# 默认端口是3903
$ nohup ./mtail -progs test.mtail -logs test.log &
 
# 查看是否启动成功
$ ps -ef | grep mtail
 
# 查看mtail的帮助文档
$ mtail -h

默认会起3903端口

三. mtail参数

nohup ./mtail -progs test.mtail -logs test.log & -progs 定义mtail日志规则的格式,-logs 定义我们要读取的日志文件的路径 .mtail的规则格式参考:github.com/google/mtai... -one_shot 就是直接以json格式打印输出出来,可以用作测试(就不会有3903端口)

-one_shot 也可以指定prometheus格式

bash 复制代码
mkdir mtail   # 创建一个专门的mtail测试案列文件夹
 #创建日志文件件并且在里面各自生产日志文件
mkdir target1  && cd target1 && touch a.log
mkdir target2  && cd target2 && touch b.log

#创建两个mtail规则脚本文件。必须以.mtail后缀的文件
mkdir progs1 && cd progs1 && touch progs_a.mtail 
mkdir progs2 && cd progs2 && touch progs_b.mtail

 
#配置progs规则脚本文件,progs_a.mtail收集a.logs中error字段的日志,progs_b.mtail我们用来收集b.logs中FATAL字段的日志
 
vim progs-a.mtail
gauge err_cnt 
/ERROR.*/ {
      err_cnt++
}
 
 
vim progs-b.mtail
gauge keyword_cnt 
/FATAL.*/ {
      keyword_cnt++
}
 
##这个规则的用法是使用GO的正则表达式进行配置说明,比如第一行gauge err_cnt是声明我们这个mtail规则名称是什么
##然后第二行/ERROR.*/ 的意思就是读取日志文件中包含ERROR字段的所有
##第三行就是如果读## 取到日志文件中出现EEROR字段,就自动增加检测到的ERROR报错信息
 
#需要分开启动两个mtail进程才能把两个监控区分开 
nohup ./mtail -progs ./progs1/progs_a.mtail  -logs ./target1/a.log &
nohup ./mtail -progs ./progs2/progs_b.mtail  -logs ./target2/b.log &

#可以echo对应的字段到相应的日志文件来伪造日志,访问对应ip的3903端口可以搜索到相应的指标

mtail参数详解

csharp 复制代码
$ mtail -h
mtail version 3.0.0-rc51 git revision 6fdbf8ec96a63c674c53148eeb9ec96043a2ec9c go version go1.19.4 go arch amd64 go os linux

Usage:
 -address string # 绑定HTTP监听器的主机或者IP地址
 -alsologtostderr # 记录标准错误和文件
 -block_profile_rate int # 报告goroutine阻塞事件之前的阻塞时间的纳秒数。0表示关闭。
 -collectd_prefix string # 发送给collectd的指标前缀
 -collectd_socketpath string # collectd socket路径,用于向其写入metrics
 -compile_only # 仅禅师编译mtail脚本程序,不执行
 -disable_fsnotify # 是否禁用文件动态发现机制。为true时,不会监听动态加载发现的新文件,只会监听程序启动时的文件。
 -dump_ast # 解析后dump程序的AST(默认到/tmp/mtail.INFO)
 -dump_ast_types # 在类型检查之后dump带有类型注释的程序的AST(默认到/tmp/mtail.INFO)
 -dump_bytecode # dump程序字节码
 -emit_metric_timestamp # 发出metric的记录时间戳。如果禁用(默认设置),则不会向收集器发送显式时间戳。
 -emit_prog_label # 在导出的变量里面展示prog对应的标签。默认为true
 -expired_metrics_gc_interval duration # metric的垃圾收集器运行间隔(默认为1h0m0s)
 -graphite_host_port string # graphite carbon服务器地址,格式Host:port。用于向graphite carbon服务器写入metrics
 -graphite_prefix string # 发送给graphite指标的metrics前缀
 -http_debugging_endpoint # 是否开启调式接口(/debug/*),默认开启
 -http_info_endpoint # 是否开始info接口(/progz,/varz),默认开启
 -ignore_filename_regex_pattern string # 需要忽略的日志文件名字,支持正则表达式。使用场景:当-logs参数指定的为一个目录时,可以使用ignore_filename_regex_pattern 参数来忽略一部分文件
 -jaeger_endpoint string # 如果设为true,可以将跟踪导出到Jaeger跟踪收集器。使用--jaeger_endpoint标志指定Jaeger端点URL
 -log_backtrace_at value # 当日志记录命中设置的行N时,发出堆栈跟踪
 -log_dir string # mtail程序的日志文件的目录,与logtostderr作用类似,如果同时配置了logtostderr参数,则log_dir参数无效
 -logs value # 监控的日志文件列表,可以使用,分隔多个文件,也可以多次使用-logs参数,也可以指定一个文件目录,支持通配符*,指定文件目录时需要对目录使用单引号。
 -logtostderr # 直接输出标准错误信息,编译问题也直接输出
 -max_recursion_depth int # 以解析的标记来衡量mtail语句的最大长度。过长的mtail表达式可能会导致编译和运行时的性能问题。(默认为100)
 -max_regexp_length int # 一个mtail regexp表达式的最大长度。过长的模式可能会导致编译和运行时的性能问题。(默认为1024)
 -metric_push_interval duration # metric推送时间间隔,单位:秒,默认60秒
 -metric_push_interval_seconds int # 弃用,用--metric_push_interval代替
 -metric_push_write_deadline duration # 在出现错误退出之前等待推送成功的时间。(默认10s)
 -mtailDebug int # 设置解析器debug级别
 -mutex_profile_fraction int # 报告的互斥争夺事件的比例。 0将关闭
 -one_shot # 此参数将编译并运行mtail程序,然后从指定的文件开头开始读取日志(从头开始读取日志,不是实时tail),然后将收集的所有metrics打印到日志中。此参数用于验证mtail程序是否有预期输出,不用于生产环境。
 -one_shot_format string # 与-one_shot一起使用的格式。这只是一个调试标志,不适合生产使用。支持的格式: json, prometheus. (默认为 "json")
 -override_timezone string # 设置时区,如果使用此参数,将在时间戳转换中使用指定的时区来替代UTC
 -poll_interval duration # 设置轮询所有日志文件以获取数据的间隔;必须为正,如果为零将禁用轮询。使用轮询模式,将仅轮询在mtail启动时找到的文件
 -poll_log_interval duration # 设置找到所有匹配的日志文件进行轮询的时间间隔;必须是正数,或者是0来禁用轮询。 在轮询模式下,只有在mtail启动时发现的文件会被轮询。(默认250ms)
 -port string # 监听的http端口,默认3903
 -progs string # mtail脚本程序所在路径
 -stale_log_gc_interval duration # stale的垃圾收集器运行间隔(默认为1h0m0s)
 -statsd_hostport string # statsd地址,格式Host:port。用于向statsd写入metrics
 -statsd_prefix string # 发送给statsd指标的metrics前缀
 -stderrthreshold value # 严重性级别达到阈值以上的日志信息除了写入日志文件以外,还要输出到stderr。各严重性级别对应的数值:INFO---0,WARNING---1,ERROR---2,FATAL---3,默认值为2.
 -syslog_use_current_year # 如果时间戳没有年份,则用当前年替代。(默认为true)
 -trace_sample_period int # 用于设置跟踪的采样频率和发送到收集器的频率。将其设置为100,则100条收集一条追踪。
 -unix_socket string # socket监控地址
 -v value # v日志的日志级别,该设置可能被 vmodule标志给覆盖.默认为0.
 -version # 打印mtail版本
 -vm_logs_runtime_errors # 启用运行时错误的记录到标准日志。 如果设置为false,则只将错误打印到HTTP控制台。(默认为true)
 -vmodule value # 按文件或模块来设置日志级别,如:-vmodule=mapreduce=2,file=1,gfs*=3

四. categraf中的mtail插件使用

categraf中的mtail以及语法:github.com/flashcatclo...

下载categraf,并配置mtail模块 (categraf安装可以见上一篇博客:三夜莺n9e(Flashcat)监控采集器categraf

lua 复制代码
##一般每个instance需要指定不同的progs参数(不同的progs文件或者目录),否则指标会相互干扰。 注意: 如果不同instance使用相同progs, 可以通过给每个instance增加labels做区分,


vim /categraf/conf/input.mtail/mtail.toml
 
[[instances]]
# .mtail的规则配置文件的路径
progs = "/opt/mtail/progs1/progs_a.mtail" 
## 指定mtail要读取的日志
logs = ["/opt/mtail/target1/a.log"]      
# override_timezone = "Asia/Shanghai"  # 时区
# emit_metric_timestamp = "true" #string type  # 时间戳的配置 ,默认是开启的
#标签,如果不同instance使用相同progs, 可以通过给每个instance增加labels做区分,
labels = { log="a.log" }

 
[[instances]]
progs = "/opt/mtail/progs2/progs_b.mtail" 
logs = ["/opt/mtail/target2/b.log"]       
# override_timezone = "Asia/Shanghai"
# emit_metric_timestamp = "true" # string type
labels = { log="b.log" }

重启categraf服务,使得配置生效 

开始测试

css 复制代码
#执行测试命令,会开始回显提示,已经开始监听TAILING相应的日志文件
/opt/categraf/categraf --inputs --test mtail

#模拟日志输出,可以在categraf 上看到回显
echo "2023 ERROR XXXXAAA" > a.log
echo "FATAL" > a.log
#输入FATAL也并未影响a.log中对ERROR的统计

echo "FATAL" > b.log

五. categraf中的mtail语法

1. 处理流程(不停的tail日志的line,用正则去匹配,匹配到了,do something)
rust 复制代码
for line in lines:
  for regex in regexes:
    if match:
      do something
2. 语法
python 复制代码
exported variable 

#pattern 定义匹配什么,action定义去做什么
pattern { 
  action statements
} 

#支持定义函数
def decorator { 
  pattern and action statements
}
3. 定义指标名称

前面也提过,指标仅支持 counter gauge histogram 三种类型。 Counter(计数器):用于记录单调递增的值,例如请求数、错误数等。 Gauge(仪表):用于记录可增可减的值,例如 CPU 使用率、内存使用量等。 Histogram(直方图):用于记录数据的分布情况,例如请求延迟、响应大小等。

lua 复制代码
#计数
counter lines
/INFO.*/ {
    lines++
}

注意,定义的名称只支持 C类型的命名方式(字母/数字/下划线),如果想使用"-" 要使用"as"导出别名。例如,

counter lines_total as "line-count" 这样获取到的就是line-count这个指标名称了

4. 匹配与计算(pattern/action)
sql 复制代码
PATTERN {
ACTION
}

例子

bash 复制代码
/foo/ {
  ACTION1
}

variable > 0 {
  ACTION2
}

/foo/ && variable > 0 {
  ACTION3
}

支持RE2正则匹配(go用的正则)

javascript 复制代码
const PREFIX /^\w+\W+\d+ /

PREFIX {
  ACTION1
}

PREFIX + /foo/ {
  ACTION2
}

这样,ACTION1 是匹配以小写字符+大写字符+数字+空格的行,ACTION2 是匹配小写字符+大写字符+数字+空格+foo开头的行。

关系运算符

scss 复制代码
< 小于 <= 小于等于
> 大于 >= 大于等于
== 相等 != 不等
=~ 匹配(模糊) !~ 不匹配(模糊)
|| 逻辑或 && 逻辑与 ! 逻辑非

数学运算符

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

支持else与otherwise

bash 复制代码
/foo/ {
ACTION1
} else {
ACTION2
}

支持嵌套

bash 复制代码
#匹配foo执行action1.匹配foo2执行actipn2。其他执行action3
/foo/ {
  /foo1/ {
     ACTION1
  }
  /foo2/ {
     ACTION2
  }
  otherwise {
     ACTION3
  }
}

支持命名与非命名提取

scss 复制代码
#operation就是变量名
/(?P<operation>\S+) (\S+) \[\S+\] (\S+) \(\S*\) \S+ (?P<bytes>\d+)/ {
  bytes_total[$operation][$3] += $bytes
}

增加常量label

bash 复制代码
# test.mtail
# 定义常量label env
hidden text env
# 给label 赋值 这样定义是global范围;
# 局部添加,则在对应的condition中添加
#getfilename()是内置的一个用法,结果可以增加logfile="xxx"的一个lable
env="production"
counter line_total by logfile,env
/^(?P<date>\w+\s+\d+\s+\d+:\d+:\d+)/ {
    line_total[getfilename()][env]++
}

获取到的metrics中会添加上env=production的label 如下:

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

如果要给metrics增加变量label,必须要使用命名提取。例如

ini 复制代码
# 日志内容
192.168.0.1 GET /foo
192.168.0.2 GET /bar
192.168.0.1 POST /bar



# 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]++
}



# 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

命名提取的变量可以在条件中使用

ruby 复制代码
/(?P<x>\d+)/ && $x > 1 {
nonzero_positives++
}
5. 时间处理

不显示处理,则默认使用系统时间

默认emit_metric_timestamp="false" (注意是字符串)

ini 复制代码
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

参数 emit_metric_timestamp="true" (注意是字符串)

ini 复制代码
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

使用日志的时间

bash 复制代码
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



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, 这个时候日志提取的时间会当做东八区时间 转换为timestamp, 然后再从timestamp转换为各时区时间时 就没有问题了,如图。

如果不带 override_timezone=Asia/Shanghai, 则默认将Aug 22 15:34:32 当做UTC时间,转换为timestamp。 这样再转换为本地时间时,会多了8个小时, 如图。

其他日志处理方案

本文介绍的日志处理方案相对简单,就像一把瑞士军刀,小巧锋利,如果你已经把日志都收集到 ElasticSearch 中了,可以对 ElasticSearch 中的日志做告警。

相关推荐
柏油7 小时前
MySQL InnoDB 行锁
数据库·后端·mysql
咖啡调调。7 小时前
使用Django框架表单
后端·python·django
白泽talk7 小时前
2个小时1w字| React & Golang 全栈微服务实战
前端·后端·微服务
摆烂工程师7 小时前
全网最详细的5分钟快速申请一个国际 “edu教育邮箱” 的保姆级教程!
前端·后端·程序员
一只叫煤球的猫8 小时前
你真的会用 return 吗?—— 11个值得借鉴的 return 写法
java·后端·代码规范
Asthenia04128 小时前
HTTP调用超时与重试问题分析
后端
颇有几分姿色8 小时前
Spring Boot 读取配置文件的几种方式
java·spring boot·后端
AntBlack8 小时前
别说了别说了 ,Trae 已经在不停优化迭代了
前端·人工智能·后端
@淡 定8 小时前
Spring Boot 的配置加载顺序
java·spring boot·后端