logback-自定义Pattern模板

背景

有的时候需要自定义日志字段,即在日志字段里加自定义字段变量。

本质

自定义日志模板,本质是自定义字段变量。

实现步骤

1.自定义字段
2.实现自定义字段处理类

自定义字段

配置文件

<!-- 统一日志格式输出用|分隔方便 elk日志工具收集处理 ,默认日志格式是 时间|级别|日志戳|代码路径|扩展json(收集图表数据,无则域留空)|脱敏后日志内容 -->
 <property name="logback.pattern"
  value="%date{yyyy-MM-dd HH:mm:ss.SSS}|%-5level|%logPreFix|%class.%method:%line|%extjson|%sensitiveMsg%n" />
    

logPreFix是自定义字段。

实现自定义字段处理类

步骤
1.配置自定义字段处理类
2.实现自定义字段处理类


自定义字段之后,还需要指定自定义字段的自定义处理类。

配置文件

<appender name="INFO_FILE"
  class="kalvan.log.logback.appender.ExtRollingFileAppender">
  <file>${logback.logpath}/info.log</file>
  <!-- see https://logback.qos.ch/manual/filters.html -->
  <filter class="ch.qos.logback.classic.filter.LevelFilter">
   <level>INFO</level>
   <onMatch>ACCEPT</onMatch>
   <onMismatch>DENY</onMismatch>
  </filter>
  <!-- see https://logback.qos.ch/manual/appenders.html#SizeAndTimeBasedFNATP -->
  <rollingPolicy
   class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
   <fileNamePattern>${logback.logpath}/info.%d{yyyyMMdd}.%i.log
   </fileNamePattern>
   <maxFileSize>${logback.maxFileSize}</maxFileSize>
  </rollingPolicy>
  <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
   <!-- see https://logback.qos.ch/manual/layouts.html -->
   <layout class="kalvan.log.logback.layout.ExtLayout"> //自定义字段的处理类
    <pattern>${logback.pattern}</pattern> //自定义字段
   </layout>
  </encoder>
 </appender>

实现类

其实这里只是映射字段和字段处理类,字段处理类还需要单独自定义。

public class ExtLayout extends PatternLayout {
 static {
  // 记录线程号
  defaultConverterMap.put("threadid", ThreadIdConverter.class.getName());
  // 处理消息内容屏蔽敏感信息
  defaultConverterMap.put("sensitiveMsg",
    SensitiveMessageConverter.class.getName());
  // 统一日志前缀
  defaultConverterMap
    .put("logPreFix", LogPreFixConverter.class.getName()); //自定义字段
  // json扩展数据收集用于图表展示
  defaultConverterMap.put("extjson", ExtJsonConverter.class.getName());
 }

}

字段处理类

这里的实现比较复杂一点,基于线程本地变量实现全链路跟踪。

public class LogPreFixConverter extends ClassicConverter {
 private static final ThreadLocal<String> logPreFixThreadLocal = new ThreadLocal<String>();
    
@Override
 public String convert(ILoggingEvent event) { //这个方法的作用,就是映射字段变量和字段变量的值
  try {
   return getCurrentThreadLogPreFix(event.getFormattedMessage());
  } catch (Throwable t) {
   // TODO 处理异常,这时不应该再打印日志避免死循环
   System.err.println("LogPreFixConverter处理异常" + t.getMessage());
  }
  return "errorLogPreFix";
 }

总结

1.每个自定义字段,都需要单独的自定义字段处理类,也就是说,一个自定义字段类只能处理一个自定义字段,如果有多个自定义字段,就要实现多个自定义字段处理类分别处理不同的自定义字段。

2.公司封装了自己的日志jar,专门用于同一处理自定义字段。

参考

https://my.oschina.net/u/2277...

阅读 376

推荐阅读