java输出7行号_Log4j是如何打印出行号的(有源码分析)

Log4J是如何打印出行号的呢,之前一直以为是通过JAVA的反射.今天特意去查了一下,JAVA的方式好像没有提供这样的接口.于是研究了一下Log4J的代码,现在分享出来.

开门见山:

直接开门见山的讲重点, 其实要获得JAVA的行号,Log4j就是先抛出异常,然后在异常堆栈中找到调用函数所在位置. 下面根据下面的一个异常堆栈,来分析如何通过2歩找到找位置的办法.

1)mons.logging.impl.Log4JLogger所在行

2)接下来,去掉下一行的1个空格,一个"at",就可以得到 "log.Main.main(Main.java:22)"

java.lang.Throwable

at org.apache.log4j.spi.LoggingEvent.getLocationInformation(LoggingEvent.java:191)

at org.apache.log4j.helpers.PatternParser$LocationPatternConverter.convert(PatternParser.java:483)

at org.apache.log4j.helpers.PatternConverter.format(PatternConverter.java:64)

at org.apache.log4j.PatternLayout.format(PatternLayout.java:503)

at org.apache.log4j.WriterAppender.subAppend(WriterAppender.java:301)

at org.apache.log4j.WriterAppender.append(WriterAppender.java:159)

at org.apache.log4j.AppenderSkeleton.doAppend(AppenderSkeleton.java:230)

at org.apache.log4j.helpers.AppenderAttachableImpl.appendLoopOnAppenders(AppenderAttachableImpl.java:65)

at org.apache.log4j.Category.callAppenders(Category.java:203)

at org.apache.log4j.Category.forcedLog(Category.java:388)

at org.apache.log4j.Category.log(Category.java:853)

at mons.logging.impl.Log4JLogger.debug(Log4JLogger.java:171)

at log.Main.main(Main.java:22)

关键代码分析:

Log4j打印出行号,关键就在LocationInfo. 这个Class就是通过对异常堆栈和mons.logging.Log的实例(比如:mons.logging.impl.Log4JLogger)的处理,来得到fullInfo(比如:log.Main.main(Main.java:22)). 接下来基于fullInfo再得到行号,类名,包名就手到擒来了.

下面是LocationInfo的构造函数的分析:

public LocationInfo(Throwable t, String fqnOfCallingClass) {

if(t == null)

return;

String s;

// Protect against multiple access to sw.

synchronized(sw) {

t.printStackTrace(pw);

s = sw.toString();

sw.getBuffer().setLength(0);

}

//System.out.println("s is ["+s+"].");

int ibegin, iend;

// Given the current structure of the package, the line

// containing "org.apache.log4j.Category." should be printed just

// before the caller.

// This method of searching may not be fastest but it's safer

// than counting the stack depth which is not guaranteed to be

// constant across JVM implementations.

//找到Log4JLogger对应的行的行头

ibegin = s.lastIndexOf(fqnOfCallingClass);

if(ibegin == -1)

return;

//找到Log4JLogger对应的行的行尾

ibegin = s.indexOf(Layout.LINE_SEP, ibegin);

if(ibegin == -1)

return;

//后移到下一行的行头,也就是真正需要信息所在行

ibegin+= Layout.LINE_SEP_LEN;

// determine end of line

//找到真正需要信息所在行的行尾

iend = s.indexOf(Layout.LINE_SEP, ibegin);

if(iend == -1)

return;

// VA has a different stack trace format which doesn't

// need to skip the inital 'at'

if(!inVisualAge) {

// back up to first blank character

//判断,真正信息说在行是否有"at "这个关键字

ibegin = s.lastIndexOf("at ", iend);

if(ibegin == -1)

return;

// Add 3 to skip "at ";

//如果有"at "这样的关键字,就过滤掉.

ibegin += 3;

}

// everything between is the requested stack item

this.fullInfo = s.substring(ibegin, iend);

}

来龙去脉:

为了分析Log4j行号的来龙去脉,我写了下面的测试类,

package log;

import mons.logging.Log;

import mons.logging.LogFactory;

public class Main {

/**

* Logger for this class

*/

private static final Log logger = LogFactory.getLog(Main.class);

/**

* @param args

*/

public static void main(String[] args) {

if (logger.isDebugEnabled()) {

logger.debug("main(String[]) - start"); //$NON-NLS-1$

}

if (logger.isDebugEnabled()) {

logger.debug("main(String[]) - end"); //$NON-NLS-1$

}

}

}

然后基于上面的代码,跟踪到了如下的调用栈,getLocationInformation就是上面分析得到行号的关键地方.

Thread [main] (Suspended)

owns: ConsoleAppender (id=53)

owns: RootLogger (id=49)

LocationInfo.(Throwable, String) line: 146

LoggingEvent.getLocationInformation() line: 191

PatternParser$LocationPatternConverter.convert(LoggingEvent) line: 483

PatternParser$LocationPatternConverter(PatternConverter).format(StringBuffer, LoggingEvent) line: 64

PatternLayout.format(LoggingEvent) line: 503

ConsoleAppender(WriterAppender).subAppend(LoggingEvent) line: 301

ConsoleAppender(WriterAppender).append(LoggingEvent) line: 159

ConsoleAppender(AppenderSkeleton).doAppend(LoggingEvent) line: 230

AppenderAttachableImpl.appendLoopOnAppenders(LoggingEvent) line: 65

Logger(Category).callAppenders(LoggingEvent) line: 203

Logger(Category).forcedLog(String, Priority, Object, Throwable) line: 388

Logger(Category).log(String, Priority, Object, Throwable) line: 853

Log4JLogger.debug(Object) line: 171

Main.main(String[]) line: 22

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值