概述
思考如下几个问题:
微服务组件几十个,怎么去看某个请求的日志?难道要登录一台一台机器去手工tail?
甚至都不知道该请求经过了哪几个服务?
该请求经过的每个微服务的耗时多少?瓶颈在哪个服务?
elk是有了,但还是不能愉快的查看某个请求链路的所有日志?怎么定义某个请求?
elk展示的时间不对,并不是实际日志的时间?
elk中java异常栈显示异常,怎么是一行一行的?
本篇文章就是解决上述所有问题
一些约定
使用elk技术栈来收集和展示日志
这里定义了一些规范:
标签
在filebeat端,设置tag,示例如下:
tags: ["crm", "member"]
增加了2个tag
第一个是子部门的名称,CRM子部门为:crm,IOT子部门为:iot
第二个是应用的名称,比如member是会员服务,shop为商城名称,一般和git中该项目的名称一样即可
tags会在查询日志时用到,后续会说明
这个操作不需要开发人员自己操作
field
日志收集时统一加上ip地址,可以方便定位到某台具体的机器
这个操作不需要开发人员自己操作
其他
线上严禁乱打日志,所有日志需调整为warn或者warn级别以上
确有线上排查问题需求,去对应的springboot admin中临时调整日志级别即可,排查完后记得调整回来
改造
官方的log4j2和logback插件,打印的traceId竟然格式不一致,一个有空格一个没有空格
导致在elk收集时,由于分词的原因,对logback的日志不能很好的进行搜索
log4j2
logback
其实对于没有空格的,仍然可以用通配符*的方式进行搜索,只是略为麻烦一点
故进行改造,使得logback的日志也有空格
filter
上述只是在日志中打印了traceId,我怎么知道线上的某个请求的traceId是多少呢
使用拦截器即可,代码示例如下:
public class TraceFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) servletRequest;
HttpServletResponse resp = (HttpServletResponse) servletResponse;
MDC.put("uri", req.getRequestURI());
resp.addHeader("traceId", TraceContext.traceId());
try {
filterChain.doFilter(req, servletResponse);
} finally {
MDC.remove("uri");
}
}
}
这样就可以在响应头中愉快的找到traceId了
查询链路和日志最佳实践
skywalking
最经典的操作即是根据上述获取traceId,然后根据traceId来查询链路
kibana
根据traceId来搜索全链路日志
如果所有子部门都接入了skywaking和elk,那么跨子部门调用的日志也全部都会有
搜索某个子部门日志
可以根据上述配置的tag来搜索日志,比如只想搜索某个部门的日志,比如crm,那么tags设置为crm即可
也可以直接在左侧过滤字段
效果如下:
搜索某个应用日志
操作类似上面
时间筛选
机器筛选
图表
在图表中可以清晰的看到某个时间点的日志量
不喜欢图表可以关掉
查询说明和优化
目前,所有部门的所有组件都使用一个索引,只是按天来滚动,然后我们建立了一个log*的索引模式,这样搜索时默认使用这一个
这样所有组件都是通的,根据一个traceid,即可跨所有组件来搜索相关的日志
如果要根据部门,或者组件来搜索,上面其他章节也进行说明了
但是,如果不知道的话,会发现每次进来都要重新输入搜索条件,较为繁琐
其实,搜索条件是可以保存的
这样可以快速复用已保存的搜索条件,而不用每次都输入
索引模式优化
除了上述可以保存搜索条件,我们对索引模式也进行了优化
每个服务的名称以 部门-组件-日期 分别建立索引
然后建立索引模式:部门*,部门-组件*,和*
这样可以按照,部门,组件,或者全部的维度来搜索
以测试环境的dfs组件为例:
生成的索引名称为:crm-dfs-2023.07.07
然后分别建立索引模式:crm*,crm-dfs和,如下图
这样,如果只想搜索dfs该组件的日志,选择crm-dfs即可,如果想搜索crm部门的日志,选择crm即可,想搜索全部部门的人日志选择