Java日志框架
2017-12-20 17:11
309 查看
Java日志框架的行号是怎么获取到的?
用过很多框架,如log4j,logback等。每种框架都支持在日志中输出行号,那框架是如何得到行号的呢?
以logback来说。
在发起logger.info("xxx");调用时,会build一个LoggingEvent对象。在此对象中有获取当前当前调用栈的方法:
在这里,通过new Threwable(),然后遍历StackTraceElement来获取当前调用有效栈。因为堆栈是从当前点往外逐层叠加的,那遍历栈时判断栈归属类是否为ch.qos.logback.classic.Logger.class.getName() || org.apache.log4j.Category || org.slf4j.Logger || 是否在框架自身的package内。当跳出此循环后,即定位到日志输出行。在StackTraceElement中有lineNumber记录,直接读取即可得到此行号。此过程如下:
在扩展日志框架,在内容中插入自定义的内容时,需要注意框架包声明。
因为是在扩展中调用具体日志框架实例,那日志输出的行号会定位到你的扩展实现中,此时丢失业务日志输出行号。从上述逻辑可以看出,在定位有效堆栈的时候,框架package是一个过滤条件,那将扩展所在的package加入框架package中即可解决此问题。
这样看来,日志要获取输出点行号是比较复杂的一个过程,日志输出如果过多,节点资源损耗预计比较可观。
用过很多框架,如log4j,logback等。每种框架都支持在日志中输出行号,那框架是如何得到行号的呢?
以logback来说。
在发起logger.info("xxx");调用时,会build一个LoggingEvent对象。在此对象中有获取当前当前调用栈的方法:
1 public StackTraceElement[] getCallerData() { 2 if (callerDataArray == null) { 3 callerDataArray = CallerData 4 .extract(new Throwable(), fqnOfLoggerClass, loggerContext.getMaxCallerDataDepth(), loggerContext.getFrameworkPackages()); 5 } 6 return callerDataArray; 7 }
在这里,通过new Threwable(),然后遍历StackTraceElement来获取当前调用有效栈。因为堆栈是从当前点往外逐层叠加的,那遍历栈时判断栈归属类是否为ch.qos.logback.classic.Logger.class.getName() || org.apache.log4j.Category || org.slf4j.Logger || 是否在框架自身的package内。当跳出此循环后,即定位到日志输出行。在StackTraceElement中有lineNumber记录,直接读取即可得到此行号。此过程如下:
1 /** 2 * Extract caller data information as an array based on a Throwable passed as 3 * parameter 4 */ 5 public static StackTraceElement[] extract(Throwable t, String fqnOfInvokingClass, final int maxDepth, List<String> frameworkPackageList) { 6 if (t == null) { 7 return null; 8 } 9 10 StackTraceElement[] steArray = t.getStackTrace(); 11 StackTraceElement[] callerDataArray; 12 13 int found = LINE_NA; 14 for (int i = 0; i < steArray.length; i++) { 15 if (isInFrameworkSpace(steArray[i].getClassName(), fqnOfInvokingClass, frameworkPackageList)) { 16 // the caller is assumed to be the next stack frame, hence the +1. 17 found = i + 1; 18 } else { 19 if (found != LINE_NA) { 20 break; 21 } 22 } 23 } 24 25 // we failed to extract caller data 26 if (found == LINE_NA) { 27 return EMPTY_CALLER_DATA_ARRAY; 28 } 29 30 int availableDepth = steArray.length - found; 31 int desiredDepth = maxDepth < (availableDepth) ? maxDepth : availableDepth; 32 33 callerDataArray = new StackTraceElement[desiredDepth]; 34 for (int i = 0; i < desiredDepth; i++) { 35 callerDataArray[i] = steArray[found + i]; 36 } 37 return callerDataArray; 38 }
在扩展日志框架,在内容中插入自定义的内容时,需要注意框架包声明。
因为是在扩展中调用具体日志框架实例,那日志输出的行号会定位到你的扩展实现中,此时丢失业务日志输出行号。从上述逻辑可以看出,在定位有效堆栈的时候,框架package是一个过滤条件,那将扩展所在的package加入框架package中即可解决此问题。
这样看来,日志要获取输出点行号是比较复杂的一个过程,日志输出如果过多,节点资源损耗预计比较可观。
相关文章推荐
- Java日志框架梳理-Java日志框架总览
- 告别System.out.print()—J2SDK1.4新增Java日志框架 (一)
- java日志框架log4j详细配置及与slf4j联合使用教程
- 【日志】Java日志工具(common-logging/log4j/slf4j)在常用框架(Struts2/Spring/Hibernate/Mybatis)中的灵活运用
- 2017年Java日志框架及工具综述
- JAVA日志框架分类简介
- 番外 03:Java日志框架引入 log4j2(Log For Java version2.x)
- JAVA 开发平台的技术和框架(五)日志管理 :common-logging slf4j log4j logBack
- Java日志框架——查看“完整的执行的SQL语句”
- 能够使开发和调试更为方便的java日志框架
- Java日志框架:SLF4J, Apache Common-Logging, Log4J和Logback
- Java日志框架——Logback的Filter
- Java日志相关的框架的简单的介绍
- Java程序员最常用的8个Java日志框架
- 【Java】Java日志框架Logback的简单例子
- java web 项目配置日志框架log4j
- 轻量级java调用流程追踪日志框架-trace4j
- 第一章Java常用日志框架介绍
- Java--日志框架2
- Java日志框架——日志框架配置文件的查找