使用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ülcü */ 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
