log4j 显示代码行数_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 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里的控制台不生效。

好,完毕!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值