Log4J是如何打印出行号的呢,之前一直以为是通过JAVA的反射.今天特意去查了一下,JAVA的方式好像没有提供这样的接口.于是研究了一下Log4J的代码,现在分享出来.
- 开门见山:
直接开门见山的讲重点, 其实要获得JAVA的行号,Log4j就是先抛出异常,然后在异常堆栈中找到调用函数所在位置. 下面根据下面的一个异常堆栈,来分析如何通过2歩找到找位置的办法.
1)找到org.apache.commons.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 org.apache.commons.logging.impl.Log4JLogger.debug(Log4JLogger.java:171) at log.Main.main(Main.java:22)
- 关键代码分析:
Log4j打印出行号,关键就在LocationInfo. 这个Class就是通过对异常堆栈和org.apache.commons.logging.Log的实例(比如:org.apache.commons.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 org.apache.commons.logging.Log; import org.apache.commons.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.<init>(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
相关推荐
在Spring项目中配置log4j是一项基础且重要的工作,它能帮助我们记录应用程序的运行日志,便于调试、排查问题和性能分析。Log4j是一个广泛使用的Java日志框架,提供灵活的日志记录功能。接下来,我们将详细讲解如何在...
**标题:“log4j 实例”** 在Java开发中,日志记录是不可或缺的一部分,而Log4j作为一款广泛使用的开源日志框架,为开发者提供了强大的日志处理能力。本实例将深入探讨如何在实际项目中应用Log4j,帮助你理解和掌握...
《深入理解Log4j:基于1.2.14版本的分析》 在Java开发领域,日志管理是一项至关重要的任务,它可以帮助开发者追踪程序运行状态,定位问题,以及进行性能监控。Log4j作为Apache组织开发的一个开源日志框架,因其强大...
工具方面,Log4j提供了强大的日志管理和分析能力,可以帮助开发者定位问题、监控系统状态,同时,通过不同的Appender和布局,可以灵活地定制日志输出的格式和存储方式。 **压缩包子文件的文件名称列表:Log4jDemo**...
《log4j.properties的简单运用》 在Java开发中,日志记录是一项至关重要的任务,它可以帮助开发者追踪程序运行过程中的错误、调试信息以及其他关键事件。Log4j是一款广泛使用的日志框架,它允许我们自定义日志级别...
Log4j的配置文件通常是`log4j.properties`或`log4j.xml`,在这里你可以设置不同级别的日志输出,例如DEBUG、INFO、WARN、ERROR等。 对于Ibatis,这是一个轻量级的持久层框架,它将SQL语句与Java代码分离,提供了...
源码分析可以帮助我们深入理解其工作原理,从而更好地利用它或进行定制化开发。 首先,我们来看看`logging-log4j-1.2.14`这个版本。这是Log4j的一个较旧但广泛使用的版本。尽管现在已经有更新的Log4j 2.x系列,但...
1. **配置文件**:Log4j的配置通常在`log4j.properties`或`log4j.xml`文件中完成。在这个文件中,你可以定义日志的级别(如DEBUG、INFO、WARN、ERROR、FATAL),设置日志输出目的地(控制台、文件、数据库等),以及...
《log4j.properties全应用详解》 在Java开发中,日志记录是不可或缺的一部分,它帮助开发者追踪程序运行状态,定位错误,优化性能。本文将深入探讨log4j.properties配置文件的使用,以及如何在实际项目中充分利用其...
如`log4j.appender.FILE.layout=org.apache.log4j.PatternLayout`并指定模式`log4j.appender.FILE.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n`,定义了日期、优先级、类名、行号和消息等信息。...
**标题与描述解析** 标题"Log4jDemo包"指的是一个使用...同时,结合`src`目录下的Java源码,我们可以深入理解Log4j的使用和配置。这个项目对于初学者来说,是一个很好的起点,帮助他们掌握Java日志处理的关键概念。
此外,Log4j与其他开源工具,如IDE插件、构建工具(Maven、Gradle)等有很好的集成,方便在项目中快速配置和使用。 总结,`log4j.properties`是Log4j的核心配置文件,通过它可以精细化控制日志的输出。熟练掌握这个...
**标题:“log4j配置详解”** 在Java开发中,日志记录是不可或缺的一部分,它可以帮助开发者追踪程序运行状态,定位错误,以及进行性能分析。Log4j是一款广泛使用的日志框架,提供了灵活且高效的日志记录功能。这篇...
此外,Log4j2提供了更丰富的功能,如异步日志记录,性能上有显著提升;支持JSON、XML等结构化日志格式,便于后期数据处理;并且有更强大的配置方式,比如通过Java API动态调整日志配置。 总的来说,Log4j作为一个...
通过熟练掌握`log4j.properties`配置,开发者可以构建出符合项目需求的日志管理系统,实现日志的高效记录、查询和分析。了解并充分利用这些特性,将有助于提升软件的可维护性和稳定性,同时降低故障排查的成本。 在...
《全面解析Log4j.xml配置文件》 在Java开发中,日志管理是不可或缺的一部分,它可以帮助我们跟踪程序运行状态,排查错误,优化性能。Log4j作为一款广泛应用的日志框架,其强大的功能和灵活的配置深受开发者喜爱。...
log4c 是一个基于 C 语言的日志记录框架,它借鉴了 Java 中的 log4j 设计理念,旨在为 C 语言开发者提供一个功能强大、灵活且易于使用的日志系统。这个压缩包包含了 log4c 的一个完整实例,适合初学者学习和参考。 ...
通过对log4cxx源码的分析,我们可以看到其设计的精巧之处,以及如何通过配置实现高效、灵活的日志管理。掌握log4cxx的使用和原理,对于提升C++项目的可维护性和稳定性具有重要意义。在实际开发中,理解并利用这些...
在实际应用中,我们可以通过日志框架(如Log4j、SLF4J)记录这些异常信息,以便于后期分析。同时,为了不影响正常的`Assert`功能,我们可以在特定的测试环境中使用这个自定义版本,而在生产环境中保持原版`Assert`。...
`portal-log4j-ext.xml`是Liferay日志配置的核心文件,用于定制日志行为。这篇文章将深入探讨Liferay的日志管理系统及其与`log4j`框架的集成。 Liferay日志系统基于Apache Log4j,一个广泛使用的开源日志记录库。...