logback.xml日志输出原理分析

childrenList

0 = {Logger@13299} “Logger[SYSLOGGER]”
1 = {Logger@6444}Logger[BASELOGGER]"
2 = {Logger@13300} “Logger[BUSILOGGER]”
3 = {Logger@13301} “Logger[MONLOGGER]”
4 = {Logger@13302} “Logger[org]”
5 = {Logger@13303} “Logger[com]”
6 = {Logger@13304} “Logger[cn]”

appenderList

2 = {Logger@13300} “Logger[BUSILOGGER]” 下面有个appenderList,appenderList下面有2个输出目的地。

0 = {AsyncAppender@13142} ch.qos.logback.classic.AsyncAppender[ASYNC_SYSFILE]"
1 = {ConsoleAppender@10175} “ch.qos.logback.core.ConsoleAppender[STDOUT]”

这2个目的地就是对应我们的Logback配置文件。一个是控制台,一个是日志文件。

public int appendLoopOnAppenders(E e) {
    int size = 0;
    final Appender<E>[] appenderArray = appenderList.asTypedArray();
    final int len = appenderArray.length;
    for (int i = 0; i < len; i++) {
        appenderArray[i].doAppend(e);  通过doAppend方法对2个目的地追加要打印的日志。
        size++;
    }
    return size;
}

在执行subAppend方法的时候,会对日志按照指定的输出logback.xml配置的格式转换成byte

protected void subAppend(E event) {
    byte[] byteArray = this.encoder.encode(event);
    writeBytes(byteArray);   //滚动写入到对应的目的地。
}

public byte[] encode(E event) {
    String txt = layout.doLayout(event);
    return convertToBytes(txt);
}

layout就是日志格式对象,该对象包含很多属性,日志格式属性对象比如下面这种

[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%cn] [%X{tid}] [%ip] [%ALogger] [%-5level] [%thread] [%AClass{36}:%ALine] [%X{pid}] [%X{sid}] #%msg#%n

最终会调用下面方法,来遍历虽有的处理类,将日志格式中的变量替换,这里就要重点介绍处理类了。

protected String writeLoopOnConverters(E event) {
    StringBuilder strBuilder = new StringBuilder(INTIAL_STRING_BUILDER_SIZE); 定义字符串,通过append的方式追加到尾部。
    Converter<E> c = head;   //head表示第一个处理类,head有个方法getNext(),就是拿到第二个处理类,每个处理类都有next,直到最后一个next为null
    while (c != null) {
        c.write(strBuilder, event);  //调用【处理类】的write方法,把要替换的日志写到strBuilder里面去。
        c = c.getNext();
    }
    return strBuilder.toString();
}

日志格式里面有很多变量,都需要不同的【处理类】来替换,那么每个变量都有对应的处理类,比如上面我们定义了变量tid、ip、ALine、pid这是我们自己定义的变量,那么我们就要往里面添加对应的处理类,比如处理Ip的处理类IpConverter.class,处理ALine变量的类ALineOfCallerConverter.class,这都是处理类,都是自己定义的。下面会介绍如何定义这些处理类。

定义日志输出格式:

方式一:

<encoder> 
	<pattern>%-4relative [%thread] %-5level %logger{35} - %msg %n</pattern> 
</encoder> 

方式二:

<encoder class="cn.com.xxx.component.logback.encoder.PatternLayoutEncoder"></encoder>

PatternLayoutEncoder是我们自己定义的类,继承了PatternLayoutEncoderBase接口

public class PatternLayoutEncoder extends PatternLayoutEncoderBase<ILoggingEvent> {
	//定义输出格式
    private static String PATTERN_SUFFIX = "[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%cn] [%X{tid}] [%ip] [%ALogger] [%-5level] [%thread] [%AClass{36}:%Line] [%X{pid}] [%X{sid}] #%msg#%n";

    public PatternLayoutEncoder() {
    }

    //重写了父类start方法
    public void start() {
        APatternLayout patternLayout = new APatternLayout();
        patternLayout.setContext(this.context);
        patternLayout.setPattern(PATTERN_SUFFIX);
        patternLayout.setOutputPatternAsHeader(this.outputPatternAsHeader);
        patternLayout.start();
        this.layout = patternLayout;
        super.start();
    }
}

上面有个APatternLayout,主要是完成往【处理类Map】里面添加我们自定义的【处理类】

public class APatternLayout extends PatternLayout {
    public APatternLayout() {
    }

    static {
    	//defaultConverterMap处理类的Map

        defaultConverterMap.put("ip", IpConverter.class.getName());
        defaultConverterMap.put("AClass", AClassConverter.class.getName());
        defaultConverterMap.put("ALine", ALineOfCallerConverter.class.getName());
        defaultConverterMap.put("ALogger", ALoggerPatternConverter.class.getName());
        defaultConverterMap.put("X", LogbackMDCPatternConverter.class.getName());
    }
}

比如IpConverter.class处理类,需要继承ClassicConverter类,然后重写对应的convert方法。

public class IpConverter extends ClassicConverter {
    public IpConverter() {
    }

    public String convert(ILoggingEvent event) {
        return getLocalHostIP();
    }

    private static String getLocalHostIP() {
        try {
            InetAddress addr = InetAddress.getLocalHost();
            return addr.getHostAddress();
        } catch (UnknownHostException var1) {
            return "127.0.0.1";
        }
    }
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

信仰_273993243

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值