Java自动日志监控框架auto-log详解
1. 需求概述
日常开发中,不管是单体还是分布式微服务,服务监控是必不可少的环节,没有监控的应用是很可怕的,你不知道应用服务处于什么状态,有什么风险,什么时候会宕掉。服务监控除了一些大型的监控工具,比如ELK,Zabbx,Prometheus,Arthas等工具外,本文要讲的是轻量级的日志监控工具,轻量到可以不引入Spring,就是一个简单的请求前后出入参以及异常的打印,以及自定义一些过滤器拦截器,traceID等功能,而不必每个服务的每个方法都手动处理。
实现本身也很简单,只需要通过切面+注解实现,github上发现auto-log无论是从架构设计,到实现,规范,注释,包括使用方式都值得推荐,感谢大佬,这里只做引荐,简单梳理使用验证。
2. auto-log简介
2.1 auto-log定义
auto-log 是一款为 java 设计的自动日志监控框架。
2.2 auto-log目的
经常会写一些工具,有时候手动加一些日志很麻烦,引入 spring 又过于大材小用。
所以希望从从简到繁实现一个工具,便于平时使用。
2.3 auto-log特性
- 基于注解+字节码,配置灵活
- 自动适配常见的日志框架
- 支持编程式的调用
- 支持注解式,完美整合 spring
- 支持整合 spring-boot
- 支持慢日志阈值指定,耗时,入参,出参,异常信息等常见属性指定
- 支持 traceId 特性
- 支持类级别定义注解
- 支持自定义拦截器和过滤器
2.4 注解说明
@AutoLog
核心注解 @AutoLog 的属性说明如下:
@TraceId
@TraceId 放在需要设置 traceId 的方法上,比如 Controller 层,mq 的消费者,rpc 请求的接受者等。
属性 | 类型 | 默认值 | 说明 |
---|---|---|---|
id | Class | 默认为 uuid | traceId 的实现策略 |
putIfAbsent | boolean | false | 是否在当前线程没有值的时候才设置值 |
enable | boolean | true | 是否启用 |
interceptor | Class[] | 默认实现 | 拦截器实现,支持指定多个和自定义 |
2.5 自定义拦截器
内置拦截器
AutoLogInterceptor 默认实现。
自定义拦截器
1.直接继承自 AbstractAutoLogInterceptor 类,并且实现对应的方法即可。
2.使用的时候指定自定义拦截器。
@AutoLog(interceptor = MyAutoLogInterceptor.class)
2.6 自定义过滤器
内置过滤器
WebParamFilter 主要用于过滤 HttpRequest HttpServlet 等无法直接 JSON 序列化的对象。
自定义过滤器
1.直接继承 AbstractParamFilter 类实现对应的方法即可。
2.使用的时候指定自定义过滤器。
@AutoLog(paramFilter = MyParamFilter.class)
2.7 注意事项
1.auto-log默认是开启的@EnableAutoLog,无需再次开启,多次开启也不影响使用。
2.集成springboot只需要引入stater即可,无需任何配置。
2.8 开源地址
Github: https://github.com/houbb/auto-log
Gitee: https://gitee.com/houbinbin/auto-log
3.实现验证
3.1 引入依赖
<!--autolog-->
<dependency>
<groupId>com.github.houbb</groupId>
<artifactId>auto-log-springboot-starter</artifactId>
<version>0.0.15</version>
</dependency>
只需要引入 jar 即可,其他的什么都不用配置。
使用方式和 spring 一致。
3.2 代码实现
LogController
package com.zrj.autolog.controller;
import com.github.houbb.auto.log.annotation.AutoLog;
import com.github.houbb.auto.log.annotation.TraceId;
import com.zrj.autolog.entity.Log;
import com.zrj.autolog.entity.Response;
import com.zrj.autolog.filter.MyLogParamFilter;
import com.zrj.autolog.interceptor.MyLogInterceptor;
import com.zrj.autolog.service.LogService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
/**
* 用户控制类
*
* @author zrj
* @since 2021-06-21 16:44:24
*/
@Slf4j
@RestController
@RequestMapping("/log")
@Api(tags = "日志管理", description = "日志管理")
public class LogController {
@Resource
private LogService logService;
/**
* 测试接口
* 自定义过滤器,拦截器
*/
@TraceId
@GetMapping("/test")
@ApiOperation(value = "测试接口")
@AutoLog(description = "测试接口", costTime = true, interceptor = MyLogInterceptor.class, paramFilter = MyLogParamFilter.class)
public Response<String> test() {
return Response.success("日志管理测试成功", null);
}
/**
* 自动日志管理
*/
@TraceId
@AutoLog(description = "自动日志管理", costTime = true)
@PostMapping("/autolog")
@ApiOperation(value = "自动日志管理测试")
public Response<Log> autolog(@RequestBody Log log) {
Log build = logService.getLog();
if (build != null) {
return Response.success("查询成功", build);
}
return Response.fail("查询失败");
}
}
MyLogParamFilter
package com.zrj.autolog.filter;
import com.github.houbb.auto.log.core.support.filter.param.AbstractParamFilter;
/**
* 自定义入参过滤器(paramFilter)
*
* @author zrj
* @since 2021/11/10
**/
public class MyLogParamFilter extends AbstractParamFilter {
/**
* 执行参数过滤
*
* @param params 入参
* @return 结果
* @since 0.0.12
*/
@Override
protected Object[] doFilter(Object[] params) {
Object[] newParams = new Object[1];
newParams[0] = "自定义过滤器设置我我想要的值";
return newParams;
}
}
MyLogInterceptor
package com.zrj.autolog.interceptor;
import com.github.houbb.auto.log.annotation.AutoLog;
import com.github.houbb.auto.log.api.IAutoLogInterceptorContext;
import com.github.houbb.auto.log.core.support.interceptor.autolog.AbstractAutoLogInterceptor;
import lombok.extern.slf4j.Slf4j;
import java.util.Arrays;
/**
* 自定义日志拦截器(interceptor)
*
* @author zrj
* @since 2021/11/10
**/
@Slf4j
public class MyLogInterceptor extends AbstractAutoLogInterceptor {
/**
* 方法执行以前
* @param autoLog 注解
* @param context 上下文
* @since 0.0.10
*/
@Override
protected void doBefore(AutoLog autoLog, IAutoLogInterceptorContext context) {
log.info("我的自定义入参:" + Arrays.toString(context.filterParams()));
}
/**
* 方法执行以后
* @param autoLog 注解
* @param result 方法执行结果
* @param context 上下文
* @since 0.0.10
*/
@Override
protected void doAfter(AutoLog autoLog, Object result, IAutoLogInterceptorContext context) {
log.info("我的自定义出参:" + result);
}
/**
* 异常处理
* @param autoLog 注解
* @param exception 异常信息
* @param context 上下文
* @since 0.0.10
*/
@Override
protected void doException(AutoLog autoLog, Exception exception, IAutoLogInterceptorContext context) {
log.info("我的自定义异常:");
exception.printStackTrace();
}
}
3.3 处理结果
MyLogInterceptor : 我的自定义入参:[自定义过滤器设置我我想要的值]
MyLogInterceptor : 我的自定义出参:Response(message=日志管理测试成功, data=null, code=200)
AutoLogInterceptor : [f4794449d6454e13807fdd5a5fffc2dd] <自动日志管理>入参: [{
"des":"日志描述","level":"日志级别","name":"日志名称","id":"日志ID"}].
e.impl.LogServiceImpl : 这里保存日志信息
AutoLogInterceptor : [f4794449d6454e13807fdd5a5fffc2dd] <自动日志管理>出参:{
"code":"200","data":{
"des":"测试啦","id":"20211109001","level":"info","name":"自动日志"},"message":"查询成功"}.
AutoLogInterceptor : [f4794449d6454e13807fdd5a5fffc2dd] <自动日志管理>耗时:70ms.