使用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 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 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 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 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.*/
packagech.qos.logback.classic.pattern;importch.qos.logback.classic.spi.CallerData;importch.qos.logback.classic.spi.ILoggingEvent;public class LineOfCallerConverter extendsClassicConverter {publicString convert(ILoggingEvent le) {
StackTraceElement[] cda=le.getCallerData();if (cda != null && cda.length > 0) {return Integer.toString(cda[0].getLineNumber());
}else{returnCallerData.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里的控制台不生效。
好,完毕!