maven 构建slf4j1.7.7之简单测试与源码解析
参考:slf4j官网 http://www.slf4j.org/manual.html
好像说一个东西 都有描述的 额
The Simple Logging Facade for Java (SLF4J) serves as a simple facade or abstraction for various logging frameworks, such as java.util.logging, logback and log4j. SLF4J allows the end-user to plug in the desired logging framework at deployment time. Note that SLF4J-enabling your library/application implies the addition of only a single mandatory dependency, namely slf4j-api-1.7.7.jar.
示意图
示意图就比较形象了
1、使用myeclipse 2013 构建maven工程,名为slf4j 此处有类似构建过程 http://blog.csdn.net/undergrowth/article/details/25241213
修改 添加slf4j-log4j12的依赖 pom.xml 如下
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.undergrowth</groupId> <artifactId>slf4j</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>slf4j</name> <url>http://maven.apache.org</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> <!-- 因为maven会处理slf4j-log4j12的传递依赖于slf4j-api --> <!-- <dependency> --> <!-- <groupId>org.slf4j</groupId> --> <!-- <artifactId>slf4j-api</artifactId> --> <!-- <version>1.7.7</version> --> <!-- </dependency> --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.7</version> </dependency> <!-- 如果配置多个日志框架 谁在前 用谁 --> <!-- <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-jdk14</artifactId> <version>1.7.7</version> </dependency> --> </dependencies> </project>
2、修改测试类 App.java
package com.undergrowth.slf4j; import java.util.Date; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Hello world! * */ public class App { final static Logger logger=LoggerFactory.getLogger(App.class); public static void main( String[] args ) { //不带占位符 logger.debug("hello world"); //带占位符 logger.debug("hello world {} ,{}", "under", new Date()); } }
修改测试类 AppTest.java
package com.undergrowth.slf4j; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * Unit test for simple App. */ public class AppTest extends TestCase { /** * Create the test case * * @param testName name of the test case */ public AppTest( String testName ) { super( testName ); } /** * @return the suite of tests being tested */ public static Test suite() { return new TestSuite( AppTest.class ); } /** * Rigourous Test :-) */ public void testApp() { String[] testArgs={}; App.main(testArgs); } }
测试testApp方法 运行结果
2014-九月-07 17:14:10 [main] DEBUG: com.undergrowth.slf4j.App - hello world 2014-九月-07 17:14:10 [main] DEBUG: com.undergrowth.slf4j.App - hello world under ,Sun Sep 07 17:14:10 CST 2014
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE log4j:configuration PUBLIC "-//APACHE//DTD LOG4J 1.2//EN" "log4j.dtd"> <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/"> <!-- Appenders --> <appender name="console" class="org.apache.log4j.ConsoleAppender"> <param name="Target" value="System.out" /> <layout class="org.apache.log4j.PatternLayout"> <param name="ConversionPattern" value="%d{yyyy-MMM-dd HH:mm:ss} [%t] %-5p: %c - %m%n" /> </layout> </appender> <!-- Root Logger --> <root> <priority value="debug" /> <appender-ref ref="console" /> </root> </log4j:configuration>
以上即是slf4j的的简单实例
3、查看slf4j的源码 简单解析其原理
a:去github上clone 一份slf4j的源码 如下
git clone https://github.com/qos-ch/slf4j.gitb:新建工程,导入myeclipse ,正常导入后 如下
可能问到的问题 参考
解决Maven报Plugin execution not covered by lifecycle configuration http://blog.csdn.net/xxd851116/article/details/25197373
c: 在上面的实例中 使用slf4j首先使用的是 org.slf4j.LoggerFactory.getLogger方法获取日志对象 查看getLogger()
/** * Return a logger named corresponding to the class passed as parameter, using * the statically bound {@link ILoggerFactory} instance. * * @param clazz the returned logger will be named after clazz * @return logger */ public static Logger getLogger(Class clazz) { return getLogger(clazz.getName()); }
/** * Return a logger named according to the name parameter using the statically * bound {@link ILoggerFactory} instance. * * @param name The name of the logger. * @return logger */ public static Logger getLogger(String name) { ILoggerFactory iLoggerFactory = getILoggerFactory(); return iLoggerFactory.getLogger(name); }
看到调用了 getILoggerFactory()方法 查看
/** * Return the {@link ILoggerFactory} instance in use. * <p/> * <p/> * ILoggerFactory instance is bound with this class at compile time. * * @return the ILoggerFactory instance in use */ public static ILoggerFactory getILoggerFactory() { if (INITIALIZATION_STATE == UNINITIALIZED) { INITIALIZATION_STATE = ONGOING_INITIALIZATION; performInitialization(); } switch (INITIALIZATION_STATE) { case SUCCESSFUL_INITIALIZATION: return StaticLoggerBinder.getSingleton().getLoggerFactory(); case NOP_FALLBACK_INITIALIZATION: return NOP_FALLBACK_FACTORY; case FAILED_INITIALIZATION: throw new IllegalStateException(UNSUCCESSFUL_INIT_MSG); case ONGOING_INITIALIZATION: // support re-entrant behavior. // See also http://bugzilla.slf4j.org/show_bug.cgi?id=106 return TEMP_FACTORY; } throw new IllegalStateException("Unreachable code"); }
在该方法的注释中 很明确的有一行 我英文也不是很好 猜测 大致意思就是ILoggerFactory的实例对象绑定是在编译的时候决定的 这么绕呢
ILoggerFactory instance is bound with this class at compile time.
那就是说在编译的时候 ILoggerFactory这个接口 就指向了实际上实现它的子类上
看看ILoggerFacroty吧
/** * Copyright (c) 2004-2011 QOS.ch * All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package org.slf4j; /** * <code>ILoggerFactory</code> instances manufacture {@link Logger} * instances by name. * * <p>Most users retrieve {@link Logger} instances through the static * {@link LoggerFactory#getLogger(String)} method. An instance of of this * interface is bound internally with {@link LoggerFactory} class at * compile time. * * @author Ceki Gülcü */ public interface ILoggerFactory { /** * Return an appropriate {@link Logger} instance as specified by the * <code>name</code> parameter. * * <p>If the name parameter is equal to {@link Logger#ROOT_LOGGER_NAME}, that is * the string value "ROOT" (case insensitive), then the root logger of the * underlying logging system is returned. * * <p>Null-valued name arguments are considered invalid. * * <p>Certain extremely simple logging systems, e.g. NOP, may always * return the same logger instance regardless of the requested name. * * @param name the name of the Logger to return * @return a Logger instance */ public Logger getLogger(String name); }
恩 也就只有一个 getLogger方法 好吧 还是接着看上面的getILoggerFactory方法吧
显示一个 if 判断
if (INITIALIZATION_STATE == UNINITIALIZED) { INITIALIZATION_STATE = ONGOING_INITIALIZATION; performInitialization(); }
很明显 第一次的话 肯定会执行 performInitialization(); 方法 查看
private final static void performInitialization() { bind(); if (INITIALIZATION_STATE == SUCCESSFUL_INITIALIZATION) { versionSanityCheck(); } }
恩 bind(); 接着看
private final static void bind() { try { Set<URL> staticLoggerBinderPathSet = findPossibleStaticLoggerBinderPathSet(); reportMultipleBindingAmbiguity(staticLoggerBinderPathSet); // the next line does the binding StaticLoggerBinder.getSingleton(); INITIALIZATION_STATE = SUCCESSFUL_INITIALIZATION; reportActualBinding(staticLoggerBinderPathSet); fixSubstitutedLoggers(); } catch (NoClassDefFoundError ncde) { String msg = ncde.getMessage(); if (messageContainsOrgSlf4jImplStaticLoggerBinder(msg)) { INITIALIZATION_STATE = NOP_FALLBACK_INITIALIZATION; Util.report("Failed to load class \"org.slf4j.impl.StaticLoggerBinder\"."); Util.report("Defaulting to no-operation (NOP) logger implementation"); Util.report("See " + NO_STATICLOGGERBINDER_URL + " for further details."); } else { failedBinding(ncde); throw ncde; } } catch (java.lang.NoSuchMethodError nsme) { String msg = nsme.getMessage(); if (msg != null && msg.indexOf("org.slf4j.impl.StaticLoggerBinder.getSingleton()") != -1) { INITIALIZATION_STATE = FAILED_INITIALIZATION; Util.report("slf4j-api 1.6.x (or later) is incompatible with this binding."); Util.report("Your binding is version 1.5.5 or earlier."); Util.report("Upgrade your binding to version 1.6.x."); } throw nsme; } catch (Exception e) { failedBinding(e); throw new IllegalStateException("Unexpected initialization failure", e); } }
看到这个方法这么多 就知道是重头戏了啊
先是 findPossibleStaticLoggerBinderPathSet() 方法
// We need to use the name of the StaticLoggerBinder class, but we can't reference // the class itself. private static String STATIC_LOGGER_BINDER_PATH = "org/slf4j/impl/StaticLoggerBinder.class"; private static Set<URL> findPossibleStaticLoggerBinderPathSet() { // use Set instead of list in order to deal with bug #138 // LinkedHashSet appropriate here because it preserves insertion order during iteration Set<URL> staticLoggerBinderPathSet = new LinkedHashSet<URL>(); try { ClassLoader loggerFactoryClassLoader = LoggerFactory.class .getClassLoader(); Enumeration<URL> paths; if (loggerFactoryClassLoader == null) { paths = ClassLoader.getSystemResources(STATIC_LOGGER_BINDER_PATH); } else { paths = loggerFactoryClassLoader .getResources(STATIC_LOGGER_BINDER_PATH); } while (paths.hasMoreElements()) { URL path = (URL) paths.nextElement(); staticLoggerBinderPathSet.add(path); } } catch (IOException ioe) { Util.report("Error getting resources from path", ioe); } return staticLoggerBinderPathSet; }
这里有一点 特别强调 也是我找了好久才找到的 你看
看到上面两张图 你会发现 slf4j-api里面 是有StaticLoggerBinder.java类的 log4j-12里面也是有 StaticLoggerBinder.java类的 那么按照道理来说 即使我在使用slf4j的时候不指定任何的实现日志框架
findPossibleStaticLoggerBinderPathSet() 这个方法 是不是至少都有一个结果?
答案是否 原因在这
看到了吧 原来slf4j-api在打包成jar的时候 删除了 org.slf4j.impl下面的所有java包 这也是下面代码成立的基础 这里不搞清楚 下面代码没法看啊
这里 我做过测试了 在上面的pom.xml 里面 我已经做了注释 有多个日志框架的时候 谁在前 用谁 (当然这里是 排除掉联合多个日志框架的情况)
这个 reportMultipleBindingAmbiguity方法呢 当你写了多个日志框架的时候 比如 你写了 log4j jcl 如上面的pom.xml中一样 人家就会友善的提醒你 你写了多个了
/** * Prints a warning message on the console if multiple bindings were found on the class path. * No reporting is done otherwise. * */ private static void reportMultipleBindingAmbiguity(Set<URL> staticLoggerBinderPathSet) { if (isAmbiguousStaticLoggerBinderPathSet(staticLoggerBinderPathSet)) { Util.report("Class path contains multiple SLF4J bindings."); Iterator<URL> iterator = staticLoggerBinderPathSet.iterator(); while (iterator.hasNext()) { URL path = (URL) iterator.next(); Util.report("Found binding in [" + path + "]"); } Util.report("See " + MULTIPLE_BINDINGS_URL + " for an explanation."); } }
最重要的来了
// the next line does the binding StaticLoggerBinder.getSingleton();
在上面已经说过了 因为slf4j-api中的StaticLoggerBinder已经被删除了 所以当你配置了日志实现框架的的时候 比如上面pom.xml 中的log4j12的时候 此时获取到的字节码 就是slf4j-log4j12中的StaticLoggerBinder的字节码 那么slf4j-log4j12里面的StaticLoggerBinder代码 如下‘
/** * Copyright (c) 2004-2011 QOS.ch * All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package org.slf4j.impl; import org.apache.log4j.Level; import org.slf4j.ILoggerFactory; import org.slf4j.LoggerFactory; import org.slf4j.helpers.Util; import org.slf4j.spi.LoggerFactoryBinder; /** * The binding of {@link LoggerFactory} class with an actual instance of * {@link ILoggerFactory} is performed using information returned by this class. * * @author Ceki Gülcü */ public class StaticLoggerBinder implements LoggerFactoryBinder { /** * The unique instance of this class. * */ private static final StaticLoggerBinder SINGLETON = new StaticLoggerBinder(); /** * Return the singleton of this class. * * @return the StaticLoggerBinder singleton */ public static final StaticLoggerBinder getSingleton() { return SINGLETON; } /** * Declare the version of the SLF4J API this implementation is compiled * against. The value of this field is usually modified with each release. */ // to avoid constant folding by the compiler, this field must *not* be final public static String REQUESTED_API_VERSION = "1.6.99"; // !final private static final String loggerFactoryClassStr = Log4jLoggerFactory.class .getName(); /** * The ILoggerFactory instance returned by the {@link #getLoggerFactory} * method should always be the same object */ private final ILoggerFactory loggerFactory; private StaticLoggerBinder() { loggerFactory = new Log4jLoggerFactory(); try { Level level = Level.TRACE; } catch (NoSuchFieldError nsfe) { Util .report("This version of SLF4J requires log4j version 1.2.12 or later. See also http://www.slf4j.org/codes.html#log4j_version"); } } public ILoggerFactory getLoggerFactory() { return loggerFactory; } public String getLoggerFactoryClassStr() { return loggerFactoryClassStr; } }
可以很清楚的看到 当使用 StaticLoggerBinder.getSingleton(); 的时候 使用的是单例模式 构建了一个StaticLoggerBinder对象 在它的构造函数里面构造了
Log4jLoggerFactory对象
源码
/** * Copyright (c) 2004-2011 QOS.ch * All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package org.slf4j.impl; import java.util.HashMap; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import org.apache.log4j.LogManager; import org.slf4j.ILoggerFactory; import org.slf4j.Logger; /** * Log4jLoggerFactory is an implementation of {@link ILoggerFactory} returning * the appropriate named {@link Log4jLoggerAdapter} instance. * * @author Ceki Gülcü */ public class Log4jLoggerFactory implements ILoggerFactory { // key: name (String), value: a Log4jLoggerAdapter; ConcurrentMap<String, Logger> loggerMap; public Log4jLoggerFactory() { loggerMap = new ConcurrentHashMap<String, Logger>(); } /* * (non-Javadoc) * * @see org.slf4j.ILoggerFactory#getLogger(java.lang.String) */ public Logger getLogger(String name) { Logger slf4jLogger = loggerMap.get(name); if (slf4jLogger != null) { return slf4jLogger; } else { org.apache.log4j.Logger log4jLogger; if(name.equalsIgnoreCase(Logger.ROOT_LOGGER_NAME)) log4jLogger = LogManager.getRootLogger(); else log4jLogger = LogManager.getLogger(name); Logger newInstance = new Log4jLoggerAdapter(log4jLogger); Logger oldInstance = loggerMap.putIfAbsent(name, newInstance); return oldInstance == null ? newInstance : oldInstance; } } }
会看到 Log4jLoggerFactory 的构造函数 是构建了一个 // key: name (String), value: a Log4jLoggerAdapter; 存放适配器的哈希map
好 现在看起来 发现 还是没有最终的串联起来 因为还有一步就成功了啊
看上面 bind()方法里面 当
StaticLoggerBinder.getSingleton(); INITIALIZATION_STATE = SUCCESSFUL_INITIALIZATION;
执行完后 初始化状态改为成功初始化 后面的就不说了 等此方法执行完后 回到 performInitialization() 再回到 getILoggerFactory() 看到有一个switch语句
switch (INITIALIZATION_STATE) { case SUCCESSFUL_INITIALIZATION: return StaticLoggerBinder.getSingleton().getLoggerFactory(); case NOP_FALLBACK_INITIALIZATION: return NOP_FALLBACK_FACTORY; case FAILED_INITIALIZATION: throw new IllegalStateException(UNSUCCESSFUL_INIT_MSG); case ONGOING_INITIALIZATION: // support re-entrant behavior. // See also http://bugzilla.slf4j.org/show_bug.cgi?id=106 return TEMP_FACTORY; }
因为在bind()中 初始化状态为成功初始化 那么此时 这里即 执行
return StaticLoggerBinder.getSingleton().getLoggerFactory();
上面说了
StaticLoggerBinder.getSingleton()
的字节码为 slf4j-log4j12里面的StaticLoggerBinder 那么 即会调用
public ILoggerFactory getLoggerFactory() { return loggerFactory; }
待getILoggerFactory() 执行完 返回到 getLogger(String name) 执行
return iLoggerFactory.getLogger(name);
哦 这里不就是执行 Log4jLoggerFactory对象 的getLogger方法么 是啊
/* * (non-Javadoc) * * @see org.slf4j.ILoggerFactory#getLogger(java.lang.String) */ public Logger getLogger(String name) { Logger slf4jLogger = loggerMap.get(name); if (slf4jLogger != null) { return slf4jLogger; } else { org.apache.log4j.Logger log4jLogger; if(name.equalsIgnoreCase(Logger.ROOT_LOGGER_NAME)) log4jLogger = LogManager.getRootLogger(); else log4jLogger = LogManager.getLogger(name); Logger newInstance = new Log4jLoggerAdapter(log4jLogger); Logger oldInstance = loggerMap.putIfAbsent(name, newInstance); return oldInstance == null ? newInstance : oldInstance; } }
这里就是从map中按照名字查找 是否有相应的日志适配器 有的话 返回 没有的话 添加到map中 并返回
接着 再返回到getLogger(Class clazz) 此时slf4j中才拿到了Logger对象 返回给
final static Logger logger=LoggerFactory.getLogger(App.class);上层
那么slf4j的日志是怎么输出来的呢 刚才只是slf4j拿到Logger 其实 实现就是在 上面的适配器中
Log4jLoggerAdapter
/** * Copyright (c) 2004-2011 QOS.ch * All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package org.slf4j.impl; import java.io.Serializable; import org.apache.log4j.Level; import org.slf4j.Logger; import org.slf4j.Marker; import org.slf4j.helpers.FormattingTuple; import org.slf4j.helpers.MarkerIgnoringBase; import org.slf4j.helpers.MessageFormatter; import org.slf4j.spi.LocationAwareLogger; /** * A wrapper over {@link org.apache.log4j.Logger org.apache.log4j.Logger} in * conforming to the {@link Logger} interface. * * <p> * Note that the logging levels mentioned in this class refer to those defined * in the <a * href="http://logging.apache.org/log4j/docs/api/org/apache/log4j/Level.html"> * <code>org.apache.log4j.Level</code></a> class. * * <p> * The TRACE level was introduced in log4j version 1.2.12. In order to avoid * crashing the host application, in the case the log4j version in use predates * 1.2.12, the TRACE level will be mapped as DEBUG. See also <a * href="http://bugzilla.slf4j.org/show_bug.cgi?id=68">bug 68</a>. * * @author Ceki Gülcü */ public final class Log4jLoggerAdapter extends MarkerIgnoringBase implements LocationAwareLogger, Serializable { private static final long serialVersionUID = 6182834493563598289L; final transient org.apache.log4j.Logger logger; /** * Following the pattern discussed in pages 162 through 168 of "The complete * log4j manual". */ final static String FQCN = Log4jLoggerAdapter.class.getName(); // Does the log4j version in use recognize the TRACE level? // The trace level was introduced in log4j 1.2.12. final boolean traceCapable; // WARN: Log4jLoggerAdapter constructor should have only package access so // that // only Log4jLoggerFactory be able to create one. Log4jLoggerAdapter(org.apache.log4j.Logger logger) { this.logger = logger; this.name = logger.getName(); traceCapable = isTraceCapable(); } private boolean isTraceCapable() { try { logger.isTraceEnabled(); return true; } catch (NoSuchMethodError e) { return false; } } /** * Is this logger instance enabled for the TRACE level? * * @return True if this Logger is enabled for level TRACE, false otherwise. */ public boolean isTraceEnabled() { if (traceCapable) { return logger.isTraceEnabled(); } else { return logger.isDebugEnabled(); } } /** * Log a message object at level TRACE. * * @param msg * - the message object to be logged */ public void trace(String msg) { logger.log(FQCN, traceCapable ? Level.TRACE : Level.DEBUG, msg, null); } /** * Log a message at level TRACE according to the specified format and * argument. * * <p> * This form avoids superfluous object creation when the logger is disabled * for level TRACE. * </p> * * @param format * the format string * @param arg * the argument */ public void trace(String format, Object arg) { if (isTraceEnabled()) { FormattingTuple ft = MessageFormatter.format(format, arg); logger.log(FQCN, traceCapable ? Level.TRACE : Level.DEBUG, ft .getMessage(), ft.getThrowable()); } } /** * Log a message at level TRACE according to the specified format and * arguments. * * <p> * This form avoids superfluous object creation when the logger is disabled * for the TRACE level. * </p> * * @param format * the format string * @param arg1 * the first argument * @param arg2 * the second argument */ public void trace(String format, Object arg1, Object arg2) { if (isTraceEnabled()) { FormattingTuple ft = MessageFormatter.format(format, arg1, arg2); logger.log(FQCN, traceCapable ? Level.TRACE : Level.DEBUG, ft .getMessage(), ft.getThrowable()); } } /** * Log a message at level TRACE according to the specified format and * arguments. * * <p> * This form avoids superfluous object creation when the logger is disabled * for the TRACE level. * </p> * * @param format * the format string * @param arguments * an array of arguments */ public void trace(String format, Object... arguments) { if (isTraceEnabled()) { FormattingTuple ft = MessageFormatter.arrayFormat(format, arguments); logger.log(FQCN, traceCapable ? Level.TRACE : Level.DEBUG, ft .getMessage(), ft.getThrowable()); } } /** * Log an exception (throwable) at level TRACE with an accompanying message. * * @param msg * the message accompanying the exception * @param t * the exception (throwable) to log */ public void trace(String msg, Throwable t) { logger.log(FQCN, traceCapable ? Level.TRACE : Level.DEBUG, msg, t); } /** * Is this logger instance enabled for the DEBUG level? * * @return True if this Logger is enabled for level DEBUG, false otherwise. */ public boolean isDebugEnabled() { return logger.isDebugEnabled(); } /** * Log a message object at level DEBUG. * * @param msg * - the message object to be logged */ public void debug(String msg) { logger.log(FQCN, Level.DEBUG, msg, null); } /** * Log a message at level DEBUG according to the specified format and * argument. * * <p> * This form avoids superfluous object creation when the logger is disabled * for level DEBUG. * </p> * * @param format * the format string * @param arg * the argument */ public void debug(String format, Object arg) { if (logger.isDebugEnabled()) { FormattingTuple ft = MessageFormatter.format(format, arg); logger.log(FQCN, Level.DEBUG, ft.getMessage(), ft.getThrowable()); } } /** * Log a message at level DEBUG according to the specified format and * arguments. * * <p> * This form avoids superfluous object creation when the logger is disabled * for the DEBUG level. * </p> * * @param format * the format string * @param arg1 * the first argument * @param arg2 * the second argument */ public void debug(String format, Object arg1, Object arg2) { if (logger.isDebugEnabled()) { FormattingTuple ft = MessageFormatter.format(format, arg1, arg2); logger.log(FQCN, Level.DEBUG, ft.getMessage(), ft.getThrowable()); } } /** * Log a message at level DEBUG according to the specified format and * arguments. * * <p> * This form avoids superfluous object creation when the logger is disabled * for the DEBUG level. * </p> * * @param format * the format string * @param arguments an array of arguments */ public void debug(String format, Object... arguments) { if (logger.isDebugEnabled()) { FormattingTuple ft = MessageFormatter.arrayFormat(format, arguments); logger.log(FQCN, Level.DEBUG, ft.getMessage(), ft.getThrowable()); } } /** * Log an exception (throwable) at level DEBUG with an accompanying message. * * @param msg * the message accompanying the exception * @param t * the exception (throwable) to log */ public void debug(String msg, Throwable t) { logger.log(FQCN, Level.DEBUG, msg, t); } /** * Is this logger instance enabled for the INFO level? * * @return True if this Logger is enabled for the INFO level, false otherwise. */ public boolean isInfoEnabled() { return logger.isInfoEnabled(); } /** * Log a message object at the INFO level. * * @param msg * - the message object to be logged */ public void info(String msg) { logger.log(FQCN, Level.INFO, msg, null); } /** * Log a message at level INFO according to the specified format and argument. * * <p> * This form avoids superfluous object creation when the logger is disabled * for the INFO level. * </p> * * @param format * the format string * @param arg * the argument */ public void info(String format, Object arg) { if (logger.isInfoEnabled()) { FormattingTuple ft = MessageFormatter.format(format, arg); logger.log(FQCN, Level.INFO, ft.getMessage(), ft.getThrowable()); } } /** * Log a message at the INFO level according to the specified format and * arguments. * * <p> * This form avoids superfluous object creation when the logger is disabled * for the INFO level. * </p> * * @param format * the format string * @param arg1 * the first argument * @param arg2 * the second argument */ public void info(String format, Object arg1, Object arg2) { if (logger.isInfoEnabled()) { FormattingTuple ft = MessageFormatter.format(format, arg1, arg2); logger.log(FQCN, Level.INFO, ft.getMessage(), ft.getThrowable()); } } /** * Log a message at level INFO according to the specified format and * arguments. * * <p> * This form avoids superfluous object creation when the logger is disabled * for the INFO level. * </p> * * @param format * the format string * @param argArray * an array of arguments */ public void info(String format, Object... argArray) { if (logger.isInfoEnabled()) { FormattingTuple ft = MessageFormatter.arrayFormat(format, argArray); logger.log(FQCN, Level.INFO, ft.getMessage(), ft.getThrowable()); } } /** * Log an exception (throwable) at the INFO level with an accompanying * message. * * @param msg * the message accompanying the exception * @param t * the exception (throwable) to log */ public void info(String msg, Throwable t) { logger.log(FQCN, Level.INFO, msg, t); } /** * Is this logger instance enabled for the WARN level? * * @return True if this Logger is enabled for the WARN level, false otherwise. */ public boolean isWarnEnabled() { return logger.isEnabledFor(Level.WARN); } /** * Log a message object at the WARN level. * * @param msg * - the message object to be logged */ public void warn(String msg) { logger.log(FQCN, Level.WARN, msg, null); } /** * Log a message at the WARN level according to the specified format and * argument. * * <p> * This form avoids superfluous object creation when the logger is disabled * for the WARN level. * </p> * * @param format * the format string * @param arg * the argument */ public void warn(String format, Object arg) { if (logger.isEnabledFor(Level.WARN)) { FormattingTuple ft = MessageFormatter.format(format, arg); logger.log(FQCN, Level.WARN, ft.getMessage(), ft.getThrowable()); } } /** * Log a message at the WARN level according to the specified format and * arguments. * * <p> * This form avoids superfluous object creation when the logger is disabled * for the WARN level. * </p> * * @param format * the format string * @param arg1 * the first argument * @param arg2 * the second argument */ public void warn(String format, Object arg1, Object arg2) { if (logger.isEnabledFor(Level.WARN)) { FormattingTuple ft = MessageFormatter.format(format, arg1, arg2); logger.log(FQCN, Level.WARN, ft.getMessage(), ft.getThrowable()); } } /** * Log a message at level WARN according to the specified format and * arguments. * * <p> * This form avoids superfluous object creation when the logger is disabled * for the WARN level. * </p> * * @param format * the format string * @param argArray * an array of arguments */ public void warn(String format, Object... argArray) { if (logger.isEnabledFor(Level.WARN)) { FormattingTuple ft = MessageFormatter.arrayFormat(format, argArray); logger.log(FQCN, Level.WARN, ft.getMessage(), ft.getThrowable()); } } /** * Log an exception (throwable) at the WARN level with an accompanying * message. * * @param msg * the message accompanying the exception * @param t * the exception (throwable) to log */ public void warn(String msg, Throwable t) { logger.log(FQCN, Level.WARN, msg, t); } /** * Is this logger instance enabled for level ERROR? * * @return True if this Logger is enabled for level ERROR, false otherwise. */ public boolean isErrorEnabled() { return logger.isEnabledFor(Level.ERROR); } /** * Log a message object at the ERROR level. * * @param msg * - the message object to be logged */ public void error(String msg) { logger.log(FQCN, Level.ERROR, msg, null); } /** * Log a message at the ERROR level according to the specified format and * argument. * * <p> * This form avoids superfluous object creation when the logger is disabled * for the ERROR level. * </p> * * @param format * the format string * @param arg * the argument */ public void error(String format, Object arg) { if (logger.isEnabledFor(Level.ERROR)) { FormattingTuple ft = MessageFormatter.format(format, arg); logger.log(FQCN, Level.ERROR, ft.getMessage(), ft.getThrowable()); } } /** * Log a message at the ERROR level according to the specified format and * arguments. * * <p> * This form avoids superfluous object creation when the logger is disabled * for the ERROR level. * </p> * * @param format * the format string * @param arg1 * the first argument * @param arg2 * the second argument */ public void error(String format, Object arg1, Object arg2) { if (logger.isEnabledFor(Level.ERROR)) { FormattingTuple ft = MessageFormatter.format(format, arg1, arg2); logger.log(FQCN, Level.ERROR, ft.getMessage(), ft.getThrowable()); } } /** * Log a message at level ERROR according to the specified format and * arguments. * * <p> * This form avoids superfluous object creation when the logger is disabled * for the ERROR level. * </p> * * @param format * the format string * @param argArray * an array of arguments */ public void error(String format, Object... argArray) { if (logger.isEnabledFor(Level.ERROR)) { FormattingTuple ft = MessageFormatter.arrayFormat(format, argArray); logger.log(FQCN, Level.ERROR, ft.getMessage(), ft.getThrowable()); } } /** * Log an exception (throwable) at the ERROR level with an accompanying * message. * * @param msg * the message accompanying the exception * @param t * the exception (throwable) to log */ public void error(String msg, Throwable t) { logger.log(FQCN, Level.ERROR, msg, t); } public void log(Marker marker, String callerFQCN, int level, String msg, Object[] argArray, Throwable t) { Level log4jLevel; switch (level) { case LocationAwareLogger.TRACE_INT: log4jLevel = traceCapable ? Level.TRACE : Level.DEBUG; break; case LocationAwareLogger.DEBUG_INT: log4jLevel = Level.DEBUG; break; case LocationAwareLogger.INFO_INT: log4jLevel = Level.INFO; break; case LocationAwareLogger.WARN_INT: log4jLevel = Level.WARN; break; case LocationAwareLogger.ERROR_INT: log4jLevel = Level.ERROR; break; default: throw new IllegalStateException("Level number " + level + " is not recognized."); } logger.log(callerFQCN, log4jLevel, msg, t); } }
你会发现 在Logger中中有的方法 在这里一一都有对应
最终的输出 是通过
org.apache.log4j.Logger对于log4j12是这样的 jcl logging logback 原理 也应该都一样
卡 终于写完了 。。。
posted on 2014-09-07 18:41 liangxinzhi 阅读(195) 评论(0) 编辑 收藏 举报