四夜莺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 中的日志做告警。

相关推荐
大梦百万秋9 分钟前
Spring Boot实战:构建一个简单的RESTful API
spring boot·后端·restful
斌斌_____37 分钟前
Spring Boot 配置文件的加载顺序
java·spring boot·后端
路在脚下@1 小时前
Spring如何处理循环依赖
java·后端·spring
海绵波波1072 小时前
flask后端开发(1):第一个Flask项目
后端·python·flask
小奏技术2 小时前
RocketMQ结合源码告诉你消息量大为啥不需要手动压缩消息
后端·消息队列
AI人H哥会Java4 小时前
【Spring】控制反转(IoC)与依赖注入(DI)—IoC容器在系统中的位置
java·开发语言·spring boot·后端·spring
凡人的AI工具箱4 小时前
每天40分玩转Django:Django表单集
开发语言·数据库·后端·python·缓存·django
奔跑草-4 小时前
【数据库】SQL应该如何针对数据倾斜问题进行优化
数据库·后端·sql·ubuntu
中國移动丶移不动5 小时前
Java 并发编程:原子类(Atomic Classes)核心技术的深度解析
java·后端
Q_19284999066 小时前
基于Spring Boot的旅游推荐系统
spring boot·后端·旅游