小结
log4j可以通过配置文件控制日志的输出,C3P0
是控制数据库连接池的包,现有的项目是旧版本的log4j
通过配置文件log4j.properties
控制C3P0的日志输出,完全没有问题。当log4j
升级到log4j2
,并使用log4j2.xml
配置却出现了兼容问题,查找具体原因并进行了解决。
问题
新版本的log4j2
的版本如下:
log4j-api-2.17.1.jar
log4j-core-2.17.1.jar
具体log4j2.xml的logger部分配置如下:
<Loggers>
<Root level="error" additivity="false">
<AppenderRef ref="Console"/>
</Root>
<Logger name="com.mchange" level="off" additivity="false">
<AppenderRef ref="Console" level="off"/>
<AppenderRef ref="fileAppender" level="off"/>
</Logger>
</Loggers>
理论上以上设置会将C3P0
的日志全部关闭,然后这个配置却没有生效,具体现象是在Console
中依然输出并打印了类似以下错误日志:
...
java.lang.Exception: DEBUG STACK TRACE: Overdue resource check-out stack trace.
at com.mchange.v2.resourcepool.BasicResourcePool.checkoutResource(BasicResourcePool.java:555)
at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool.checkoutAndMarkConnectionInUse(C3P0PooledConnectionPool.java:755)
at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool.checkoutPooledConnection(C3P0PooledConnectionPool.java:682)
at com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource.getConnection(AbstractPoolBackedDataSource.java:140)
at org.hibernate.c3p0.internal.C3P0ConnectionProvider.getConnection(C3P0ConnectionProvider.java:73)
at org.hibernate.internal.AbstractSessionImpl$NonContextualJdbcConnectionAccess.obtainConnection(AbstractSessionImpl.java:386)
at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.acquireConnectionIfNeeded(LogicalConnectionManagedImpl.java:87)
at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.getPhysicalConnection(LogicalConnectionManagedImpl.java:112)
at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.getConnectionForTransactionManagement(LogicalConnectionManagedImpl.java:230)
at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.begin(LogicalConnectionManagedImpl.java:237)
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.begin(JdbcResourceLocalTransactionCoordinatorImpl.java:214)
at org.hibernate.engine.transaction.internal.TransactionImpl.begin(TransactionImpl.java:52)
at org.hibernate.internal.SessionImpl.beginTransaction(SessionImpl.java:1512)
...
我的旧版本的log4j
的版本是log4j-1.2.16.jar
log4j.properties
中C3P0
部分配置如下:
log4j.logger.com.mchange=OFF
以上旧版本配置是完全没有问题的,并没有任何C3P0
的日志被漏出来输出到屏幕上。
查找原因
在程序启动初始,有以下输出:
com.mchange.v2.log.MLog.<clinit> MLog clients using java 1.4+ standard logging.
以上输出证明了log4j2的设置并没有生效,默认使用了java 1.4的日志。
解决
从最开始的的分析开始,往往是看到现象:java.lang.Exception: DEBUG STACK TRACE: Overdue resource check-out stack trace
,对于这个问题在网上众说纷纭,有些解决方案只解决了这个表面现象出现的异常,结果只是治标,没有治本。我们需要找到问题的根本,也就是最终定位到Log4j2
与C3P0
的兼容问题。这样才可以完完美,并以最小的代价来解决。
方案一
针对java.lang.Exception: DEBUG STACK TRACE: Overdue resource check-out stack trace
的异常。网上已有定论:
This is the code that triggers this log statement in C3P0:
if ( logger.isLoggable( MLevel.FINEST ) ) logger.log( MLevel.FINEST,
this + ” closed by a client.”,
new Exception(“DEBUG – CLOSE BY CLIENT STACK
TRACE”) );
Note that:
This is not an exception, the new Exception is used merely to show
execution path for debug purposes. And yes, this is only a debug
message (actually, FINEST is the lowest possible level in
java.util.logging). To wrap this up: ignore and tune your logging
levels to skip these.
也就是这本来就不是一个异常,只是一个调试的提示信息,通过设置日志级别可以屏幕这个异常打印输出信息。通过hibernate
的以下配置可以达到这个目的,一个是直接关闭,一个是增加超时时长。
<property name="hibernate.c3p0.debugUnreturnedConnectionStackTraces">false</property>
<property name="hibernate.c3p0.unreturnedConnectionTimeout">100</property>
这个解决方案只是不输出java.lang.Exception: DEBUG STACK TRACE: Overdue resource check-out stack trace
这个异常,log4j2
的设置依然无法控制C3P0的日志输出。
方案二
参考CSDN: 干掉com.mchange.v2.log.MLog
直接粗暴地修改干掉C3P0的日志输出,也就是使用java的日志级别修改C3P0
的日志级别设置。
ModifyLogLevel.java
package com.mchange.v2.log;
import java.util.logging.Level;
public class ModifyLogLevel {
public static void modifyInfoLevel(Level level) {
com.mchange.v2.log.MLevel.INFO.level=level;
}
}
直接在程序中调用:
ModifyLogLevel.modifyInfoLevel(java.util.logging.Level.ALL);
这个解决方案可以达到关闭所有C3P0
的日志输出,但是这样就没有log4j2
的任何事了,不能进行灵活配置,焊死了,如果我想要打开C3P0
的日志输出呢?那岂不是很麻烦。
方案三(推荐)
参考 System.setProperty ("com.mchange.v2.log.MLog", "com.mchange.v2.log.log4j2.Log4j2MLog");
或者 再配上log4j2.xml的设置: 修改后,期望着能一举成功,然而进行了以上设置并没有什么卵用,日志仍然使用Java自带的 此版本并不支持此操作,下载升级到: 问题最终解决了。这样,通过 CSDN: java.lang.Exception: DEBUG — CLOSE BY CLIENT STACK TRACE 的理解System.setProperty ("com.mchange.v2.log.MLog", "log4j2");
<Loggers>
<Root level="error" additivity="false">
<AppenderRef ref="Console"/>
</Root>
<Logger name="com.mchange" level="off" additivity="false">
<AppenderRef ref="Console" level="off"/>
<AppenderRef ref="fileAppender" level="off"/>
</Logger>
</Loggers>
java 1.4+ standard logging
,究其原因,原来我使用了以下版本的C3P0
:
c3p0-0.9.2.1.jar
mchange-commons-java-0.2.3.4.jar
c3p0-0.9.5.5.jar
mchange-commons-java-0.2.19.jar
log4j2.xml
的设置,可以精确控制C3P0的日志输出级别和输出位置。参考
Problem with hibernate search indexing
CSDN: c3p0连接池连接泄漏检测
CSDN: java.lang.Exception: DEBUG STACK TRACE for PoolBackedDataSource.close().
CSDN: 跟踪 C3p0 连接池连接泄漏之参数优化与日志分析
CSDN: C3P0异常:java.lang.Exception: DEBUG — CLOSE BY CLIENT STACK TRACE 解决
CSDN: 干掉com.mchange.v2.log.MLog
CSDN: Hibernate c3p0 logging不通过slf4j输出的解决办法
stackoverflow: Weird Error: CLOSE BY CLIENT STACK TRACE