背景
监控异常日志是一个很重要的事情,如何快速简单的通过一个脚本实现呢?今天我们来一起探索一下吧!我这里部署了一个springboot3+jdk17的web服务,日志格式如下所示:
2024-03-19 11:14:02.628 [http-nio-8080-exec-10] ERROR c.u.f.exception.GlobalExceptionHandler -
org.springframework.web.servlet.resource.NoResourceFoundException: No static resource .
at org.springframework.web.servlet.resource.ResourceHttpRequestHandler.handleRequest(ResourceHttpRequestHandler.java:585)
at org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter.handle(HttpRequestHandlerAdapter.java:52)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1089)
我的目的是把这完整的错误日志通过飞书的webhook 进行发送。
实现过程
通过tail -f 监听异常日志的,这里假定日志文件:logs/error.log,这个文件里面的日志都是异常日志,当然你也可以加各种过滤条件, 通过和ai助手交流,写出的第一个脚本如下:
tail -n 0 -f "logs/error.log" | awk '
BEGIN {
RS="[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}.[0-9]+ \\[.*\\] " # 设置记录分隔符为时间戳开头的模式
}
{
print "Record Separator:", RT
print "Record:", RT $0 # 打印记录时包含记录分隔符
}'
简单解释下:就是通过 tail -n 0 -f 实时显示新增的内容,然后通过管道 | 使用awk 的 BEGIN 设置分隔符,这样就可以打印出完整的异常日志,但是测试中发现,只能打印上一条日志,最新的由于没有新的分隔符出现,导致无法打印出来,于是开始研究awk有没有后超时机制,长时间无法等到分隔符的时候,打印最后的日志行,遗憾的是我并没有知道合适的超时机制。
思来想去,找到的解决方案就是起一个子线程去监听最后一次收到消息的时间,如果大于规定的时间(比如10s),则打印这些日志,打印后清空缓存的日志,线程之间传递数据,我这边选择使用管道,接着就是调试代码了。
完成日志监控
开始写代码之前,我发现了read可以加超时时间,于是有了下面的脚本代码。
#!/bin/bash
monitor_logs() {
# 监控日志输入,并处理日志输入
tail -n 0 -f "logs/error.log" | (
while true; do
# 初始化 pre_log
prev_log=""
while IFS= read -r -t 10 line; do
if [[ $line =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}\ [0-9]{2}:[0-9]{2}:[0-9]{2}\.[0-9]+ ]]; then
if [[ -n $prev_log ]]; then
echo "Record: $prev_log" # 输出一条日志记录
prev_log=""
fi
fi
prev_log="$prev_log$line"
done
echo "timeout Record: $prev_log" # 输出一条日志记录
done
)
}
monitor_logs
这里发现没有没有换行符,需要再在合并日志行的时候加上$'\n' 就可以了,超时的时候还需要加下判断是否有prev_log,同时需要注意,--follow=name,如果直接使用-f 是以描述符监听文件,因为我们的日志会滚动,索引应该使用 --follow=name 最终代码如下
#!/bin/bash
monitor_logs() {
# 监控日志输入,并处理日志输入
tail -n 0 --follow=name "logs/error.log" | (
while true; do
# 初始化 pre_log
prev_log=""
while IFS= read -r -t 10 line; do
if [[ $line =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}\ [0-9]{2}:[0-9]{2}:[0-9]{2}\.[0-9]+ ]]; then
if [[ -n $prev_log ]]; then
# 这里可以进行通过飞书webhook进行通知
echo "Record: $prev_log" # 输出一条日志记录
prev_log=""
fi
fi
prev_log="$prev_log$line"$'\n'
done
if [[ -n $prev_log ]]; then
# 这里可以进行通过飞书webhook进行通知
echo "timeout Record: $prev_log"
fi
done
)
}
monitor_logs
换行符正常输出
至此,已经完成了脚本,代码比较简单,希望可以给大家提供一个思路,监控任重道远,AI让我们获取知识的途径又多了一种。
飞书机器人
写这部分主要是因为一点,发文本消息的时候换行符、制表符等会造成发送失败,下面是一个可用的消息发送,主要逻辑是过滤掉 \t ,并替换\n 让消息可读行更好,希望对大家有帮助。
# 发送飞书通知
send_feishu_notification() {
local message="$1"
message=$(echo "$message" | tr -d '\t')
message="${message//$'\n'/\\\n}"
# 发送通知到飞书 webhook
curl -X POST -H "Content-Type: application/json" -d "{\"msg_type\":\"text\",\"content\":{\"text\":\"$message\"}}" "$FEISHU_WEBHOOK_URL"
}
结束!