zoukankan      html  css  js  c++  java
  • logback是怎么知道java代码的行数的?

    使用logback,忽然想到这个问题,然后问了几个同事都没研究过,我来看看logback是如何知道的

    打断点如下:

    stop in com.sql.mysql.sharding.plugin.ExecutorInterceptor.intercept
    
    stop in ch.qos.logback.classic.Logger.callAppenders
    
    stop in ch.qos.logback.core.encoder.LayoutWrappingEncoder.encode

    encode的java函数如下:

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

    那么layout的值是啥呢?

    main[1] print layout
     layout = "ch.qos.logback.classic.PatternLayout("%level %date , %logger{36} [%file:%line] , Thread-[%thread] - %msg%n")"

    就是我们自己定义的格式,好,继续往下走。

    碰到了这个函数

    protected String writeLoopOnConverters(E event) {
            StringBuilder strBuilder = new StringBuilder(INTIAL_STRING_BUILDER_SIZE);
            Converter<E> c = head;
            while (c != null) {
                c.write(strBuilder, event);
                c = c.getNext();
            }
            return strBuilder.toString();
        }
    ​

    这里看来是做了一个字符串拼接的功能!,继续

    ========================================================

    Step completed: "thread=main", ch.qos.logback.core.pattern.PatternLayoutBase.writeLoopOnConverters(), line=113 bci=11
    113            Converter<E> c = head;
    
    main[1] print head
     head = "ch.qos.logback.classic.pattern.LevelConverter@cf3a8fb"

    其实也就可以猜到,这里是要一个链表的converter,每个converter构造自己的内容

    我们来看看logback提供了哪些converter

    ---

    未完待续,好,继续

    1)ch.qos.logback.classic.pattern.LevelConverter

    @Override
        final public void write(StringBuilder buf, E event) {
            String s = convert(event);
    
            if (formattingInfo == null) {
                buf.append(s);
                return;
            }
    
            int min = formattingInfo.getMin();
            int max = formattingInfo.getMax();
    
            if (s == null) {
                if (0 < min)
                    SpacePadder.spacePad(buf, min);
                return;
            }
    
            int len = s.length();
    
            if (len > max) {
                if (formattingInfo.isLeftTruncate()) {
                    buf.append(s.substring(len - max));
                } else {
                    buf.append(s.substring(0, max));
                }
            } else if (len < min) {
                if (formattingInfo.isLeftPad()) {
                    SpacePadder.leftPad(buf, s, min);
                } else {
                    SpacePadder.rightPad(buf, s, min);
                }
            } else {
                buf.append(s);
            }
        }

    2)ch.qos.logback.classic.pattern.DateConverter

     3)ch.qos.logback.classic.pattern.LoggerConverter

    public class LoggerConverter extends NamedConverter {
    
        protected String getFullyQualifiedName(ILoggingEvent event) {
            return event.getLoggerName();
        }
    }

    这个在event创建时就赋值了,这样就知道是哪个类里面的log打的消息了

    4)ch.qos.logback.classic.pattern.FileOfCallerConverter

    获取Java文件

        public StackTraceElement[] getCallerData() {
            if (callerDataArray == null) {
                callerDataArray = CallerData
                                .extract(new Throwable(), fqnOfLoggerClass, loggerContext.getMaxCallerDataDepth(), loggerContext.getFrameworkPackages());
            }
            return callerDataArray;
        }

    看起来是获得了一个栈,具体是什么呢,进去看

    public static StackTraceElement[] extract(Throwable t, String fqnOfInvokingClass, final int maxDepth, List<String> frameworkPackageList) {
            if (t == null) {
                return null;
            }
    
            StackTraceElement[] steArray = t.getStackTrace();
            StackTraceElement[] callerDataArray;
    
            int found = LINE_NA;
            for (int i = 0; i < steArray.length; i++) {
                if (isInFrameworkSpace(steArray[i].getClassName(), fqnOfInvokingClass, frameworkPackageList)) {
                    // the caller is assumed to be the next stack frame, hence the +1.
                    found = i + 1;
                } else {
                    if (found != LINE_NA) {
                        break;
                    }
                }
            }
    
            // we failed to extract caller data
            if (found == LINE_NA) {
                return EMPTY_CALLER_DATA_ARRAY;
            }
    
            int availableDepth = steArray.length - found;
            int desiredDepth = maxDepth < (availableDepth) ? maxDepth : availableDepth;
    
            callerDataArray = new StackTraceElement[desiredDepth];
            for (int i = 0; i < desiredDepth; i++) {
                callerDataArray[i] = steArray[found + i];
            }
            return callerDataArray;
        }

    其实就是利用了一个new Throwable()的t.getStackTrace(); 来获取一个栈,

    但是其实有很多个,那么这么识别出来我要到哪一层呢?

    [1] ch.qos.logback.classic.spi.CallerData.extract (CallerData.java:63)
      [2] ch.qos.logback.classic.spi.LoggingEvent.getCallerData (LoggingEvent.java:258)
      [3] ch.qos.logback.classic.pattern.FileOfCallerConverter.convert (FileOfCallerConverter.java:22)
      [4] ch.qos.logback.classic.pattern.FileOfCallerConverter.convert (FileOfCallerConverter.java:19)
      [5] ch.qos.logback.core.pattern.FormattingConverter.write (FormattingConverter.java:36)
      [6] ch.qos.logback.core.pattern.PatternLayoutBase.writeLoopOnConverters (PatternLayoutBase.java:115)
      [7] ch.qos.logback.classic.PatternLayout.doLayout (PatternLayout.java:141)
      [8] ch.qos.logback.classic.PatternLayout.doLayout (PatternLayout.java:39)
      [9] ch.qos.logback.core.encoder.LayoutWrappingEncoder.encode (LayoutWrappingEncoder.java:115)
      [10] ch.qos.logback.core.OutputStreamAppender.subAppend (OutputStreamAppender.java:230)
      [11] ch.qos.logback.core.OutputStreamAppender.append (OutputStreamAppender.java:102)
      [12] ch.qos.logback.core.UnsynchronizedAppenderBase.doAppend (UnsynchronizedAppenderBase.java:84)
      [13] ch.qos.logback.core.spi.AppenderAttachableImpl.appendLoopOnAppenders (AppenderAttachableImpl.java:51)
      [14] ch.qos.logback.classic.Logger.appendLoopOnAppenders (Logger.java:270)
      [15] ch.qos.logback.classic.Logger.callAppenders (Logger.java:257)
      [16] ch.qos.logback.classic.Logger.buildLoggingEventAndAppend (Logger.java:421)
      [17] ch.qos.logback.classic.Logger.filterAndLog_0_Or3Plus (Logger.java:383)
      [18] ch.qos.logback.classic.Logger.info (Logger.java:579)
      [19] com.sql.mysql.sharding.plugin.ExecutorInterceptor.intercept (ExecutorInterceptor.java:53)
      [20] org.apache.ibatis.plugin.Plugin.invoke (Plugin.java:61)
      [21] com.sun.proxy.$Proxy3.update (null)
      [22] org.apache.ibatis.session.defaults.DefaultSqlSession.update (DefaultSqlSession.java:198)
      [23] org.apache.ibatis.session.defaults.DefaultSqlSession.delete (DefaultSqlSession.java:213)
      [24] org.apache.ibatis.binding.MapperMethod.execute (MapperMethod.java:67)
      [25] org.apache.ibatis.binding.MapperProxy.invoke (MapperProxy.java:59)
      [26] com.sun.proxy.$Proxy4.deleteRole (null)
      [27] notransaction.ShardingNoTransaction.main (ShardingNoTransaction.java:24)

    其实有一行代码

    for (int i = 0; i < steArray.length; i++) {
                if (isInFrameworkSpace(steArray[i].getClassName(), fqnOfInvokingClass, frameworkPackageList)) {
                    // the caller is assumed to be the next stack frame, hence the +1.
                    found = i + 1;
                } else {
                    if (found != LINE_NA) {
                        break;
                    }
                }
            }

    关键就是这行代码isInFrameworkSpace

    static boolean isInFrameworkSpace(String currentClass, String fqnOfInvokingClass, List<String> frameworkPackageList) {
            // the check for org.apache.log4j.Category class is intended to support
            // log4j-over-slf4j. it solves http://bugzilla.slf4j.org/show_bug.cgi?id=66
            if (currentClass.equals(fqnOfInvokingClass) || currentClass.equals(LOG4J_CATEGORY) || currentClass.startsWith(SLF4J_BOUNDARY)
                            || isInFrameworkSpaceList(currentClass, frameworkPackageList)) {
                return true;
            } else {
                return false;
            }
        }

    如果是

    1)"ch.qos.logback.classic.Logger"

    2)"org.apache.log4j.Category"

    3)以"org.slf4j.Logger";开头

    4)或者以frameworkPackageList里面的值开头的都是日志框架的

    直到找到第一个我们业务自己的为止!

    然后把调用栈拷贝出来,再执行下面的函数

        public String convert(ILoggingEvent le) {
            StackTraceElement[] cda = le.getCallerData();
            if (cda != null && cda.length > 0) {
                return cda[0].getFileName();
            } else {
                return CallerData.NA;
            }
        }
    Step completed: "thread=main", ch.qos.logback.core.pattern.FormattingConverter.write(), line=36 bci=5
    36            String s = convert(event);
    
    main[1] step
    > 
    Step completed: "thread=main", ch.qos.logback.core.pattern.FormattingConverter.write(), line=38 bci=6
    38            if (formattingInfo == null) {
    
    main[1] print s
     s = "ExecutorInterceptor.java"

    这样就获得了文件名

    5)ch.qos.logback.classic.pattern.LineOfCallerConverter

    这里会复用上一个步骤的结果

    Step completed: "thread=main", ch.qos.logback.classic.spi.LoggingEvent.getCallerData(), line=257 bci=0
    257            if (callerDataArray == null) {
    
    main[1] print callerDataArray
     callerDataArray = instance of java.lang.StackTraceElement[8] (id=2233)
    /**
     * Logback: the reliable, generic, fast and flexible logging framework.
     * Copyright (C) 1999-2015, QOS.ch. All rights reserved.
     *
     * This program and the accompanying materials are dual-licensed under
     * either the terms of the Eclipse Public License v1.0 as published by
     * the Eclipse Foundation
     *
     *   or (per the licensee's choosing)
     *
     * under the terms of the GNU Lesser General Public License version 2.1
     * as published by the Free Software Foundation.
     */
    package ch.qos.logback.classic.pattern;
    
    import ch.qos.logback.classic.spi.CallerData;
    import ch.qos.logback.classic.spi.ILoggingEvent;
    
    public class LineOfCallerConverter extends ClassicConverter {
    
        public String convert(ILoggingEvent le) {
            StackTraceElement[] cda = le.getCallerData();
            if (cda != null && cda.length > 0) {
                return Integer.toString(cda[0].getLineNumber());
            } else {
                return CallerData.NA;
            }
        }
    
    }

    这样就获得了行号!!!

    6) ch.qos.logback.classic.pattern.ThreadConverter

    /**
     * Logback: the reliable, generic, fast and flexible logging framework.
     * Copyright (C) 1999-2015, QOS.ch. All rights reserved.
     *
     * This program and the accompanying materials are dual-licensed under
     * either the terms of the Eclipse Public License v1.0 as published by
     * the Eclipse Foundation
     *
     *   or (per the licensee's choosing)
     *
     * under the terms of the GNU Lesser General Public License version 2.1
     * as published by the Free Software Foundation.
     */
    package ch.qos.logback.classic.pattern;
    
    import ch.qos.logback.classic.spi.ILoggingEvent;
    
    /**
     * Return the events thread (usually the current thread).
     * 
     * @author Ceki G&uuml;lc&uuml;
     */
    public class ThreadConverter extends ClassicConverter {
    
        public String convert(ILoggingEvent event) {
            return event.getThreadName();
        }
    
    }
    

    线程名

        public String getThreadName() {
            if (threadName == null) {
                threadName = (Thread.currentThread()).getName();
            }
            return threadName;
        }

    然后还有其它的一些颜色配置,这个看

    http://blog.csdn.net/java_zone/article/details/54341029

    就好了,需要在真实的shell上才生效,eclipse里的控制台不生效。

    好,完毕!

    https://my.oschina.net/qiangzigege/blog/1586544

  • 相关阅读:
    asyncio异步IO--协程(Coroutine)与任务(Task)详解
    python爬虫实战:利用scrapy,短短50行代码下载整站短视频
    深入理解Git的实现原理
    Upsource 代码审查工具安装及使用
    MAC MAMP集成环境安装 PHP 扩展
    千万数据量数据表分表实践
    设计模式:序言
    设计模式 行为型
    PHP5底层原理之变量
    PHP5底层原理之垃圾回收机制
  • 原文地址:https://www.cnblogs.com/softidea/p/13491979.html
Copyright © 2011-2022 走看看