log日志框架和LocationAwareLogger问题
2013-02-10 19:09
260 查看
今天启动tomcat服务失败,碰到异常情况如下
java.lang.NoSuchMethodError: org.slf4j.spi.LocationAwareLogger.log(Lorg/slf4j/Marker;Ljava/lang/String;ILjava/lang/String;Ljava/lang/Throwable;)V
at org.apache.commons.logging.impl.SLF4JLocationAwareLog.info(SLF4JLocationAwareLog.java:159)
Commons-log + log4j 这黄金搭档一直以来都让我们很省心,很好的完成了日志的需求。但是随着技术的变更和对性能的追求,slf4j 和 logback 这对后起之秀的到来好像打破了原本很平静的日志系统,频繁的出现包冲突...
和平的日子不在了,让我们一起来看看究竟发生了什么...
首先看看这些个包,特别是slf4j引入后就引入了一大堆包之后就有点懵了。
很清晰的可以看到jcl-over-slf4j 重写了 commons-logging...
其实就这么简单,往往看了代码之后才发现错误是这么显而易见。。。
Java代码
package com.taobao.wuzhong.log;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* DESC:
*
* Copyright: Copyright 2011 m.taobao.com
*
* @author wuzhong@taobao.com
* @time 2011-4-6 下午03:42:11
* @version 1.0
**/
public class LogTest {
// Logback tries to find a file called logback.groovy in the classpath.
// If no such file is found, logback tries to find a file called
// logback-test.xml in the classpath.
// If no such file is found, it checks for the file logback.xml in the
// classpath..
// If neither file is found, logback configures itself automatically using
// the BasicConfigurator which will cause logging output to be directed to
// the console.
@Test
public void test() {
//commons-logging的方式获取
Log log = LogFactory.getLog(LogTest.class);
//slf4j直接的方式获取,推荐用这个
Logger log2 = LoggerFactory.getLogger(LogTest.class);
log.debug("eeeeee {} {} {}");
log2.debug("{} {} {}", new String[] {
"a", "b",
"c" });
}
}
logFactory.getLog 会调用内部静态变量 Slf4jLogFactory.getInstance方法,如下:
public Log getInstance(String name) throws LogConfigurationException {
Java代码
Log instance = null;
// protect against concurrent access of loggerMap
synchronized (this) {
instance = (Log) loggerMap.get(name);
if (instance == null) {
Logger logger = LoggerFactory.getLogger(name); //slf4j的方式,代理过去了
if(logger instanceof LocationAwareLogger) {
instance = new SLF4JLocationAwareLog((LocationAwareLogger) logger);
//包装了一层,做适配
} else {
instance = new SLF4JLog(logger);
}
loggerMap.put(name, instance);
}
}
return (instance);
loggerFactory 会调用getILoggerFactory().getlOgger()
Java代码
LoggerFactory.java
public static ILoggerFactory getILoggerFactory() {
if (INITIALIZATION_STATE == UNINITIALIZED) {
INITIALIZATION_STATE = ONGOING_INITILIZATION;
performInitialization();
}
switch (INITIALIZATION_STATE) {
case SUCCESSFUL_INITILIZATION:
return getSingleton().getLoggerFactory();
case FAILED_INITILIZATION:
throw new IllegalStateException(UNSUCCESSFUL_INIT_MSG);
case ONGOING_INITILIZATION:
// support re-entrant behavior.
// See also http://bugzilla.slf4j.org/show_bug.cgi?id=106
return TEMP_FACTORY;
}
throw new IllegalStateException("Unreachable code");
}
private final
static void performInitialization() {
bind();
versionSanityCheck();
singleImplementationSanityCheck();
}
static {
SINGLETON.init();
}
/**
* Package access for testing purposes.
*/
void init() {
try {
try {
new ContextInitializer(defaultLoggerContext).autoConfig();
} catch (JoranException je) {
Util.reportFailure("Failed to auto configure default logger context",
je);
}
StatusPrinter.printInCaseOfErrorsOrWarnings(defaultLoggerContext);
contextSelectorBinder.init(defaultLoggerContext, KEY);
initialized = true;
} catch (Throwable t) {
// we should never get here
Util.reportFailure("Failed to instantiate ["
+ LoggerContext.class.getName() +
"]", t);
}
}
获取配置信息初始化
java.lang.NoSuchMethodError: org.slf4j.spi.LocationAwareLogger.log(Lorg/slf4j/Marker;Ljava/lang/String;ILjava/lang/String;Ljava/lang/Throwable;)V
at org.apache.commons.logging.impl.SLF4JLocationAwareLog.info(SLF4JLocationAwareLog.java:159)
Commons-log + log4j 这黄金搭档一直以来都让我们很省心,很好的完成了日志的需求。但是随着技术的变更和对性能的追求,slf4j 和 logback 这对后起之秀的到来好像打破了原本很平静的日志系统,频繁的出现包冲突...
和平的日子不在了,让我们一起来看看究竟发生了什么...
首先看看这些个包,特别是slf4j引入后就引入了一大堆包之后就有点懵了。
为什么commons-logging和jcl-over-slf4j会有冲突呢?看一下它们的类结构
很清晰的可以看到jcl-over-slf4j 重写了 commons-logging...
还有slf4j-api的实现呢,同样看类:
其实就这么简单,往往看了代码之后才发现错误是这么显而易见。。。
顺着研究,继续看一下slf4j的源码及流程
1.测试类Java代码
package com.taobao.wuzhong.log;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* DESC:
*
* Copyright: Copyright 2011 m.taobao.com
*
* @author wuzhong@taobao.com
* @time 2011-4-6 下午03:42:11
* @version 1.0
**/
public class LogTest {
// Logback tries to find a file called logback.groovy in the classpath.
// If no such file is found, logback tries to find a file called
// logback-test.xml in the classpath.
// If no such file is found, it checks for the file logback.xml in the
// classpath..
// If neither file is found, logback configures itself automatically using
// the BasicConfigurator which will cause logging output to be directed to
// the console.
@Test
public void test() {
//commons-logging的方式获取
Log log = LogFactory.getLog(LogTest.class);
//slf4j直接的方式获取,推荐用这个
Logger log2 = LoggerFactory.getLogger(LogTest.class);
log.debug("eeeeee {} {} {}");
log2.debug("{} {} {}", new String[] {
"a", "b",
"c" });
}
}
package com.taobao.wuzhong.log; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * DESC: * * Copyright: Copyright 2011 m.taobao.com * * @author wuzhong@taobao.com * @time 2011-4-6 下午03:42:11 * @version 1.0 **/ public class LogTest { // Logback tries to find a file called logback.groovy in the classpath. // If no such file is found, logback tries to find a file called // logback-test.xml in the classpath. // If no such file is found, it checks for the file logback.xml in the // classpath.. // If neither file is found, logback configures itself automatically using // the BasicConfigurator which will cause logging output to be directed to // the console. @Test public void test() { //commons-logging的方式获取 Log log = LogFactory.getLog(LogTest.class); //slf4j直接的方式获取,推荐用这个 Logger log2 = LoggerFactory.getLogger(LogTest.class); log.debug("eeeeee {} {} {}"); log2.debug("{} {} {}", new String[] { "a", "b", "c" }); } }
logFactory.getLog 会调用内部静态变量 Slf4jLogFactory.getInstance方法,如下:
public Log getInstance(String name) throws LogConfigurationException {
Java代码
Log instance = null;
// protect against concurrent access of loggerMap
synchronized (this) {
instance = (Log) loggerMap.get(name);
if (instance == null) {
Logger logger = LoggerFactory.getLogger(name); //slf4j的方式,代理过去了
if(logger instanceof LocationAwareLogger) {
instance = new SLF4JLocationAwareLog((LocationAwareLogger) logger);
//包装了一层,做适配
} else {
instance = new SLF4JLog(logger);
}
loggerMap.put(name, instance);
}
}
return (instance);
Log instance = null; // protect against concurrent access of loggerMap synchronized (this) { instance = (Log) loggerMap.get(name); if (instance == null) { Logger logger = LoggerFactory.getLogger(name); //slf4j的方式,代理过去了 if(logger instanceof LocationAwareLogger) { instance = new SLF4JLocationAwareLog((LocationAwareLogger) logger); //包装了一层,做适配 } else { instance = new SLF4JLog(logger); } loggerMap.put(name, instance); } } return (instance);
loggerFactory 会调用getILoggerFactory().getlOgger()
Java代码
LoggerFactory.java
public static ILoggerFactory getILoggerFactory() {
if (INITIALIZATION_STATE == UNINITIALIZED) {
INITIALIZATION_STATE = ONGOING_INITILIZATION;
performInitialization();
}
switch (INITIALIZATION_STATE) {
case SUCCESSFUL_INITILIZATION:
return getSingleton().getLoggerFactory();
case FAILED_INITILIZATION:
throw new IllegalStateException(UNSUCCESSFUL_INIT_MSG);
case ONGOING_INITILIZATION:
// support re-entrant behavior.
// See also http://bugzilla.slf4j.org/show_bug.cgi?id=106
return TEMP_FACTORY;
}
throw new IllegalStateException("Unreachable code");
}
private final
static void performInitialization() {
bind();
versionSanityCheck();
singleImplementationSanityCheck();
}
LoggerFactory.java public static ILoggerFactory getILoggerFactory() { if (INITIALIZATION_STATE == UNINITIALIZED) { INITIALIZATION_STATE = ONGOING_INITILIZATION; performInitialization(); } switch (INITIALIZATION_STATE) { case SUCCESSFUL_INITILIZATION: return getSingleton().getLoggerFactory(); case FAILED_INITILIZATION: throw new IllegalStateException(UNSUCCESSFUL_INIT_MSG); case ONGOING_INITILIZATION: // support re-entrant behavior. // See also http://bugzilla.slf4j.org/show_bug.cgi?id=106 return TEMP_FACTORY; } throw new IllegalStateException("Unreachable code"); } private final static void performInitialization() { bind(); versionSanityCheck(); singleImplementationSanityCheck(); }
这里的bind很关键,这里动态的绑定了slf4j-api的实现机制
Java代码static {
SINGLETON.init();
}
/**
* Package access for testing purposes.
*/
void init() {
try {
try {
new ContextInitializer(defaultLoggerContext).autoConfig();
} catch (JoranException je) {
Util.reportFailure("Failed to auto configure default logger context",
je);
}
StatusPrinter.printInCaseOfErrorsOrWarnings(defaultLoggerContext);
contextSelectorBinder.init(defaultLoggerContext, KEY);
initialized = true;
} catch (Throwable t) {
// we should never get here
Util.reportFailure("Failed to instantiate ["
+ LoggerContext.class.getName() +
"]", t);
}
}
static { SINGLETON.init(); } /** * Package access for testing purposes. */ void init() { try { try { new ContextInitializer(defaultLoggerContext).autoConfig(); } catch (JoranException je) { Util.reportFailure("Failed to auto configure default logger context", je); } StatusPrinter.printInCaseOfErrorsOrWarnings(defaultLoggerContext); contextSelectorBinder.init(defaultLoggerContext, KEY); initialized = true; } catch (Throwable t) { // we should never get here Util.reportFailure("Failed to instantiate [" + LoggerContext.class.getName() + "]", t); } }
获取配置信息初始化
相关文章推荐
- log日志框架和LocationAwareLogger问题
- 使用ACE日志策略时遇到的问题:DLL::open failed for ACE: Error: check log for details Unable to find service 'Logger'
- Java日志管理:Logger.getLogger()和LogFactory.getLog()的区别(详解Log4j)
- iOS中解决Xcode9的Log日志无法输出中文的问题小结
- CI框架中 日志输出方法log_message()只允许输出字符串解决方案
- 魅族手机无法打印Log日志的问题
- 自定义注解日志功能与shrio框架冲突的问题
- 错误日志System.log写入问题
- Logger:封装系统log的日志打印工具
- 华为手机app闪退重启清空log日志问题
- android中无法在华为手机输出Log.v和Log.d级别的日志问题总结
- ELK(+Redis)+LogAnalyzer解决企业日志问题
- mysql dba系统学习(11)管理innodb引擎的redo log日志的一个问题
- 用NSIS安装日志install。log解决了一个安装出现隐蔽的问题、不用看代码,可以节省大把时间!开心!
- Log打印日志遇到的问题
- 关于Logger日志的控制台输出问题
- android orhanobut logger打印那个类第几行调用log输出,在输出日志上上点击跳转到源代码
- dubbo框架中一行日志代码引发的超时问题
- /var/log/secure 日志不记录问题
- Tomcat遇到”Error listenerStart”或”Error filterStart”问题且无详细日志时的log配置.