如何优雅的在log日志中打印操作人
本文中的log日志基于slf4j,使用的注解为lombok.extern.slf4j
本文的日志打印使用logback.xml配置
仅提供了如何打印日志,不包含如何优雅的写日志
更新:今日发现一个如何优雅的写日志的文章,在这里引用一下以做记录打印优质日志的 10 条军规
一、将操作人添加到日志中
这里利用到slf4j的MDC,调用put(key,val)会将值塞入mdcAdapter(LogbackMDCAdapter)中
在logback.xml中可以使用%X{key}获取val
例如key为user,值为张三
MDC.put("user","张三");
在logback.xml中即可用%X{user}获取到张三
<!-- 这是一个完整的日志pattern,你可以将%X{user}放到任何一个位置 -->
<property name="PATTERN"
value="%date{yyyy-MM-dd HH:mm:ss.SSS} ${profile} [%level] --- [%thread] [${application}] %logger{26} - %X{user} - %msg%n"/>
添加认证拦截器,在用户携带登录信息访问时,使用MDC将需要写入日志的操作人放入自定义的key中,然后在logback.xml的pattern中添加%X{key},即可在打印日志时打印出操作人的信息。
java案例代码如下
@Slf4j
@Component
public class AuthInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
if (handler instanceof HandlerMethod) {
// 获取当前登录的用户
UserInfoDTO user = getUserInfo();
if (Objects.isNull(user)) {
/**
* 无需登录用户即可访问的,则不在MDC中存值
* 如果有某些业务需要记录访问人,可以在业务逻辑执行前,将参数中标记用户的参数放入user中,
* 如MDC.put("user", param.getCellphone());
*/
return true;
}
MDC.put("user", user.getUsername() + ":" +user.getRealName());
}
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
MDC.clear();
}
}
xml案例代码如下
<property name="LOG_FILE" value="xxx"/>
<property name="PATTERN"
value="%date{yyyy-MM-dd HH:mm:ss.SSS} ${profile} [%level] --- [%thread] [${application}] %logger{26} - %X{user} - %msg%n"/>
<!-- 中间略过啦 -->
<root level="INFO">
<!-- 控制台输出,具体不作展示 -->
<appender-ref ref="STDOUT"/>
<!-- 输出到文件,具体不作展示 -->
<appender-ref ref="LOG_OUT"/>
</root>
xml案例代码如下
访问接口,从接口中打印的log日志就可以看到 admin:张三 这个操作人信息
二、自定义日志打印操作人
虽然日志成功打印了,但是一些查询语句之类的也加上了操作人,有些小伙伴只想在自定义日志上加操作人,就需要进一步的进行改造啦。
Slf4j注解中有个topic值,用来指定采用的logger。如果不传参,或者参数与logback中的logger不对应,就会默认走name为root的logger。
@Retention(RetentionPolicy.SOURCE)
@Target({ElementType.TYPE})
public @interface Slf4j {
String topic() default "";
}
先在logback中注册一个logger,name自定义
<!-- name如果设置包名,则指定包下的所有日志都走这个配置;如果设置自定义名称,则topic一致的走这个配置 -->
<!-- additivity为false,则只走自定义的appender-ref,为true,则日志还会走root的appender-ref -->
<logger name="CUSTOM_LOGGER" level="INFO" additivity="false">
<!-- 这里STDOUT_USER与上边的STDOUT,上边的STDOUT的pattern改为无%X{user}的 -->
<appender-ref ref="STDOUT_USER"/>
</logger>
将@Slf4j注解改为@Slf4j(topic = “CUSTOM_LOGGER”)
这样就可以将自定义日志和系统日志分开,输入日志如下:
细心的小伙伴会发现,这里的logger中,只使用了控制台输出,而没有采用log文件输出。原因是如果多个采用的logger,文件输出指向同一个文件,则启动项目时会报错,因此我们还需要继续改造。
三、自定义日志存到其他文件
logback.xml新做一个appender-ref,指向另一个log文件配置LOG_FILE_USER,文件输出为yyy,将自定义日志的文件与系统日志的区分开。
<property name="LOG_FILE" value="xxx"/>
<property name="LOG_FILE_USER" value="yyy"/>
<property name="PATTERN"
value="%date{yyyy-MM-dd HH:mm:ss.SSS} ${profile} [%level] --- [%thread] [${application}] %logger{26} - %X{user} - %msg%n"/>
<!-- 中间略过啦 -->
<!-- 这里的additivity为什么改为true,下边会做讲解 -->
<logger name="CUSTOM_LOGGER" level="INFO" additivity="true">
<appender-ref ref="STDOUT_USER"/>
<appender-ref ref="LOG_OUT_USER"/>
</logger>
<root level="INFO">
<!-- 控制台输出,具体不作展示 -->
<appender-ref ref="STDOUT"/>
<!-- 输出到文件,具体不作展示 -->
<appender-ref ref="LOG_OUT"/>
</root>
如果additivity为false,操作日志在yyy文件中,而系统日志在xxx文件,有些业务需要通过操作日志+sql来排查问题,就会变得非常麻烦。因此可以将additivity改为true,将操作日志在操作日志文件中打印一份,系统日志文件中打印一份。
控制台的日志输出如下:
至此,我们已将操作人优雅的打印到了log日志中~