首页 > 学院 > 开发设计 > 正文

关于log4j

2019-11-11 02:50:12
字体:
来源:转载
供稿:网友

Log4j 是如何获取 类名、函数名、行数的

见 org.apache.log4j.spi.LocationInfo.LocationInfo(Throwable t, String fqnOfCallingClass)

源码分析

Object[] noArgs = null; // 获取函数调用栈 Object[] elements = (Object[]) getStackTraceMethod.invoke(t, noArgs); String PRevClass = NA; for(int i = elements.length - 1; i >= 0; i--) { String thisClass = (String) getClassNameMethod.invoke(elements[i], noArgs); // 判断当前调用的类是否为 Category if(fqnOfCallingClass.equals(thisClass)) { int caller = i + 1; if (caller < elements.length) { className = prevClass; methodName = (String) getMethodNameMethod.invoke(elements[caller], noArgs); fileName = (String) getFileNameMethod.invoke(elements[caller], noArgs); if (fileName == null) { fileName = NA; } int line = ((Integer) getLineNumberMethod.invoke(elements[caller], noArgs)).intValue(); if (line < 0) { lineNumber = NA; } else { lineNumber = String.valueOf(line); } StringBuffer buf = new StringBuffer(); buf.append(className); buf.append("."); buf.append(methodName); buf.append("("); buf.append(fileName); buf.append(":"); buf.append(lineNumber); buf.append(")"); this.fullInfo = buf.toString(); } return; } prevClass = thisClass; }

函数调用栈

org.apache.log4j.spi.LoggingEvent.getLocationInformation(LoggingEvent.java:253)↓org.apache.log4j.helpers.PatternParser$LocationPatternConverter.convert(PatternParser.java:500)↓org.apache.log4j.helpers.PatternConverter.format(PatternConverter.java:65)↓org.apache.log4j.PatternLayout.format(PatternLayout.java:506)↓org.apache.log4j.WriterAppender.subAppend(WriterAppender.java:310)↓org.apache.log4j.WriterAppender.append(WriterAppender.java:162)↓org.apache.log4j.AppenderSkeleton.doAppend(AppenderSkeleton.java:251)↓org.apache.log4j.helpers.AppenderAttachableImpl.appendLoopOnAppenders(AppenderAttachableImpl.java:66)↓org.apache.log4j.Category.callAppenders(Category.java:206)↓xxx.xxx.Main(args:line)

从函数调用栈从下往上开始查找 Category ,若当前调用类为 Category, 则上层就是 Main 方法的调用信息。

如何手动获取 函数调用信息(类名、函数名、行号)

// 指定 fqnOfCategoryClass 为 LoggingEvent.class.getName()LoggingEvent event = new LoggingEvent(LoggingEvent.class.getName(), logger, Level.DEBUG, "i am message", null);// 然后手动获取 LocationInfo,这时函数调用栈的倒数第二层就是// org.apache.log4j.spi.LoggingEvent.getLocationInformation(:line)// 此时的 line 就是下面这行代码的 行号LocationInfo info = event.getLocationInformation();

上面获取的行号只是 event.getLocationInformation() 的行数,所以要想获得自己想要的行号,必须对以上操作进行包装。

献上一个包装的 Logger

maven

<dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version></dependency>

wrapper Logger

注意观察 FQCN 的使用

import org.apache.log4j.Level;import org.apache.log4j.spi.LoggingEvent;/** * wrapper org.apache.log4j.Logger * * @author Jinpeng Cui * */public class Logger { public static final boolean enable = true; private static final String FQCN = Logger.class.getName(); private static org.apache.log4j.Logger proxy; public Logger(final String clazzName) { proxy = org.apache.log4j.Logger.getLogger(clazzName); } public static Logger getLogger(final Class<?> clazz) { return new Logger(clazz.getName()); } public void error(String message) { if (isErrorEnable()) { forceLog(Level.ERROR, message); } } public void info(String message) { if (isInfoEnabled()) { forceLog(Level.INFO, message); } } public void debug(String message) { if (isDebugEnabled()) { forceLog(Level.DEBUG, message); } } private void forceLog(Level level, String message) { proxy.callAppenders(new LoggingEvent(FQCN, proxy, level, message, null)); } public boolean isErrorEnable() { return enable && proxy.isEnabledFor(Level.ERROR); } public boolean isInfoEnabled() { return enable && proxy.isEnabledFor(Level.INFO); } public boolean isDebugEnabled() { return enable && proxy.isEnabledFor(Level.DEBUG); }}
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表