【云原生•监控】mtail轻量日志监控体系

前言

「笔者已经在公有云上搭建了一套暂时环境,能够先登录体会下:」

http://124.222.45.207:17000/login
账号:root/root.2020

简介

「可观测性渠道三大支柱:日志监控、调用链监控和衡量目标监控,其间最为咱们熟知的是日志监控,因为咱们开发体系基本都离不开日志,也是处理问题最为常见的一种方法。日志的特色便是它是一个个离散的事情,因为一个事情的发生所以导致了一条日志的发生,用于问题剖析判断时供给更为翔实的头绪。」

举个比如:如程序忽然无法衔接MySQL数据库,经过反常日志(如下)很简略发现是因为Too many connections导致数据库衔接失败:

[ERROR][2023-05-2021:14:43]com.alibaba.druid.pool.DruidDataSource.init(629)|initdatasourceerror
com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException:Toomanyconnections
atsun.reflect.NativeConstructorAccessorImpl.newInstance0(NativeMethod)
atsun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
atsun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
atjava.lang.reflect.Constructor.newInstance(Constructor.java:423)
atcom.mysql.jdbc.Util.handleNewInstance(Util.java:408)
atcom.mysql.jdbc.Util.getInstance(Util.java:383)

Too many connections这种反常通常是因为超越MySQL服务器允许的最大衔接数而引起的,能够经过增加数据库衔接数或封闭未运用的衔接来处理该问题。从这个示例能够看出:「日志监控对反常状况下问题剖析更加直接,比如恳求参数、反常事情等,为问题剖析判断供给更为翔实的头绪;调用链监控偏向恳求调用的链路剖析,往往用于发现链路间功能问题;而衡量目标监控特色是数值类型,往往用于核算聚合或供给功能目标的运转趋势状况,需求丰厚经验才能发现潜在问题,一般为问题剖析定位过程中可能的猜想供给有效的数据支撑依据,如上述Too many connections导致数据库衔接反常,就能够经过衡量目标查看MySQL的衔接数进行佐证,并经过衔接数趋势线查看什么时间点开端呈现衔接数反常上升进行进一步的剖析排查。」

「说到日志监控,咱们榜首反响的可能是ELK的计划,或许Loki的计划,这两个计划都是把日志采集了发到中心,在中心存储、查看、剖析。这种日志计划问题是运用elasticsearch,存储量十分大,巨大的全文索引开支,如一套ELK监控体系一天新增的日志存储量可能会上TB;另一个问题便是这些日志是离散的,而且是海量的,不太方便进行聚合核算。」

然后,在实际出产中往往还有如下需求:

  • 如依据日志核算某个事务接口一天的调用量,然后获取事务订单量、付出金额等;

  • 日志中触发Error的次数,以及想知道每天都触发了哪些Error,每种Error触发次数核算等;

  • 依据日志关键字告警:

    • 如上述MySQL衔接反常: Too many connections
    • jvm内存溢出:java.lang.OutOfMemoryError: Java heap space
    • 如衔接拒绝:java.net.ConnectException: Connection refused

如上述需求并不需求全量的日志,所以,能够经过日志转衡量目标处理:「将日志流消息转换核算后生成衡量目标,然后监控体系抓取运用PromQL语法进行聚合核算剖析」

这儿给咱们介绍一个Google出品的东西mtailmtail便是流式读取日志,经过正则表达式匹配的方法从日志中提取metrics目标,这种方法能够利用目标机器的算力,别的一个好处是无侵入性,不需求事务埋点,如果事务程序是第三方供货商供给的,咱们改不了其代码,mtail此时就十分合适了。

mtail装置运用

1、mtail装置:

[root@VM-4-14-centostools]#mkdir/disk/tools/mtail
[root@VM-4-14-centostools]#cd/disk/tools/mtail
[root@VM-4-14-centosmtail]#tar-zxvfmtail_3.0.0-rc51_Linux_x86_64.tar.gz

2、mtail发动:

[root@VM-4-14-centosmtail]#./mtail--progs/disk/tools/mtail/conf--logs'/disk/tools/mtail/logs/*.log'--logs/var/log/messages--log_dir/disk/tools/mtail/logdir--poll_interval250ms

「中心参数如下:」

1、--progs:指定一个目录,这个目录里放置一堆的*.mtail文件,每个mtail文件便是描绘的正则提取规矩

2、--logs: 监控的日志文件列表,能够运用,分隔多个文件,也能够多次运用--logs参数,也能够指定一个文件目录,支撑通配符,指定文件目录时需求对目录运用单引号。如:--logs a.log,b.log,c.log --logs a.log --logs b.log --logs c.log --logs '/export/logs/*.log'

3、--log_dirmtail组件本身日志寄存目录

4、--portmtail组件http监听端口,默许3903

mtail发动之后会主动监听一个端口3903,在3903的/metrics接口露出契合Prometheus协议的监控数据,Prometheus 或许 Categraf 或许 Telegraf 等就能够从 /metrics 接口提取监控数据。

这样看起来,原理就很明晰了,mtail 发动之后,依据 --logs 找到相关日志文件,seek 到文件结尾,开端流式读取,每读到一行,就依据 --progs 指定的那些规矩文件做匹配,看是否契合某些正则,从中提取时序数据,然后经过3903的/metrics露出采集到的监控目标。

规矩语法

mtail的目的是从日志中提取信息并将其传递到监控体系。因此,有必要导出目标变量并命名,目标支撑countergaugehistogram三种类型,而且命名的变量有必要在COND脚本之前。

标准格式为:

COND{
ACTION
}

其间COND是一个条件表达式。它能够是正则表达式,也能够boolean类型的条件句子。如下:

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

COND表达式可用的运算符如下:

  • 联系运算符:

< , <= , > , >= , == , != , =~ , !~ , || , && , !

  • 算术运算符:

| , & , ^ , + , – , * , /, << , >> , **

**「导出的目标变量」**可用的运算符如下:

= , += , ++ , –

规矩示例

「1、导出一个counter类型的目标lines_total:核算日志行数」

#simplelinecounter
counterlines_total
/$/{
lines_total++
}

「2、导出一个counter类型的目标error_count:核算呈现ERROR、error、Failed、faild这四个关键字的日志行数」

countererror_count

/ERROR|error|Failed|faild/{
error_count++
}

「3、导出一个counter类型的目标out_of_memory_count:核算内存溢出呈现次数」

counterout_of_memory_count

/java.lang.OutOfMemoryError/{
out_of_memory_count++
}

转成衡量目标后,结合PromQL语法很简略进行预警规矩配置:

groups:
-name:memory.rules
rules:
-alert:OutOfMemoryError
expr:increase(out_of_memory_count[1m])>0
labels:
severity:series
annotations:
summary:"java.lang.OutOfMemoryError"
description:"{{$labels.instance}}呈现JVM内存溢出过错"

「4、这儿我用mtail监控一下n9e-server的日志,从中提取一下各个告警规矩触发的 notify 的数量,这个日志举例:」

2021-12-2710:00:30.537582INFOengine/logger.go:19event(cbb8d4be5efd07983c296aaa4dec5737triggered)notify:rule_id=9[__name__=net_response_result_codeauthor=qinident=10-255-0-34port=4567protocol=tcpserver=localhost]2@1640570430

很明显,日志中有这么个关键字:notify: rule_id=9,能够用正则来匹配,核算呈现的行数,ruleid 也能够从中提取到,这样,咱们能够把 ruleid 作为标签上报,于是乎,咱们就能够写出这样的 mtail 规矩了:

countermtail_alert_rule_notify_totalbyruleid
/notify:rule_id=(?P<ruleid>\d+)/{
mtail_alert_rule_notify_total[$ruleid]++
}

「5、java反常类型核算」

counterexception_countbyexception,log
/(?P<exception>[A-Z]*(.[A-Za-z]*)*(Exception|Error)):(?P<log>.*)/{
exception_count[$exception][$log]++
}

然后向日志文件中输入空指针反常和jvm内存溢出反常:

java.lang.NullPointerException:Someerrormessagehere.
atcom.example.myapp.MyClass.someMethod(MyClass.java:123)
atcom.example.myapp.OtherClass.doSomething(OtherClass.java:45)
java.lang.OutOfMemoryError:Javaheapspace
Dumpingheaptod://\java_pid10000.hprof...
Exceptioninthread"main"java.lang.OutOfMemoryError:Javaheapspace
atcn.intsmaze.dump.OOMDump$OOMIntsmaze.<init>(OOMDump.java:27)
atcn.intsmaze.dump.OOMDump.fillHeap(OOMDump.java:34)
atcn.intsmaze.dump.OOMDump.main(OOMDump.java:47)
atsun.reflect.NativeMethodAccessorImpl.invoke0(NativeMethod)
atsun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
atsun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
atjava.lang.reflect.Method.invoke(Method.java:498)
Heapdumpfilecreated[10195071bytesin0.017secs]
atcom.intellij.rt.execution.application.AppMain.main(AppMain.java:147)

访问/metrics端点就能够看到目标数据:

#HELPexception_countdefinedatgj.mtail:7:9-23
#TYPEexception_countcounter
exception_count{exception="java.lang.NullPointerException",log="Someerrormessagehere.",prog="gj.mtail"}3
exception_count{exception="java.lang.OutOfMemoryError",log="Javaheapspace",prog="gj.mtail"}2

exception标签标识java反常类型,log标签标识简略反常描绘。

注意:实际出产log标签是不太合适的,因为log标签基数太多会导致目标膨胀。

将反常目标转成衡量目标,运用PromQL语法就很简略核算出每种反常类型每天触发的次数,或许结合Grafana实时展示核算数据、趋势线等。