关于log4j

来源:互联网 发布:apache ant 1.9.6 编辑:程序博客网 时间:2024/04/29 18:00

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);    }}
0 0
原创粉丝点击