Author: fhanik
Date: Fri Aug 8 00:04:51 2014
New Revision: 1616644
URL: http://svn.apache.org/r1616644
Log:
Fix https://issues.apache.org/bugzilla/show_bug.cgi?id=56318
Contribution by Danila Galimov
Ability to log statement creation stacks
Modified:
tomcat/trunk/modules/jdbc-pool/doc/jdbc-pool.xml
tomcat/trunk/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/StatementFinalizer.java
Modified: tomcat/trunk/modules/jdbc-pool/doc/jdbc-pool.xml
URL:
http://svn.apache.org/viewvc/tomcat/trunk/modules/jdbc-pool/doc/jdbc-pool.xml?rev=1616644&r1=1616643&r2=1616644&view=diff
==============================================================================
--- tomcat/trunk/modules/jdbc-pool/doc/jdbc-pool.xml (original)
+++ tomcat/trunk/modules/jdbc-pool/doc/jdbc-pool.xml Fri Aug 8 00:04:51 2014
@@ -608,6 +608,13 @@
and closes these statements when the connection is returned to the pool.
</p>
<attributes>
+ <attribute name="trace" required="false">
+ <p>(boolean as String) Enable tracing of unclosed statements.
+ When enabled and a connection is closed, and statements are not
closed,
+ the interceptor will log all stack traces.
+ The default value is <code>false</code>.
+ </p>
+ </attribute>
</attributes>
</subsection>
<subsection name="org.apache.tomcat.jdbc.pool.interceptor.StatementCache">
Modified:
tomcat/trunk/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/StatementFinalizer.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/StatementFinalizer.java?rev=1616644&r1=1616643&r2=1616644&view=diff
==============================================================================
---
tomcat/trunk/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/StatementFinalizer.java
(original)
+++
tomcat/trunk/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/interceptor/StatementFinalizer.java
Fri Aug 8 00:04:51 2014
@@ -19,6 +19,7 @@ package org.apache.tomcat.jdbc.pool.inte
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
import org.apache.tomcat.jdbc.pool.ConnectionPool;
+import org.apache.tomcat.jdbc.pool.PoolProperties;
import org.apache.tomcat.jdbc.pool.PooledConnection;
import java.lang.ref.WeakReference;
@@ -26,6 +27,8 @@ import java.lang.reflect.Method;
import java.sql.Statement;
import java.util.LinkedList;
import java.util.List;
+import java.util.Map;
+
/**
* Keeps track of statements associated with a connection and invokes close
upon {@link java.sql.Connection#close()}
* Useful for applications that dont close the associated statements after
being done with a connection.
@@ -34,13 +37,15 @@ import java.util.List;
public class StatementFinalizer extends AbstractCreateStatementInterceptor {
private static final Log log = LogFactory.getLog(StatementFinalizer.class);
- protected List<WeakReference<Statement>> statements = new LinkedList<>();
-
+ protected List<WeakReference<StatementEntry>> statements = new
LinkedList<>();
+
+ private boolean logCreationStack = false;
+
@Override
public Object createStatement(Object proxy, Method method, Object[] args,
Object statement, long time) {
try {
if (statement instanceof Statement)
- statements.add(new WeakReference<>((Statement)statement));
+ statements.add(new WeakReference<>(new
StatementEntry((Statement)statement)));
}catch (ClassCastException x) {
//ignore this one
}
@@ -50,25 +55,58 @@ public class StatementFinalizer extends
@Override
public void closeInvoked() {
while (statements.size()>0) {
- WeakReference<Statement> ws = statements.remove(0);
- Statement st = ws.get();
+ WeakReference<StatementEntry> ws = statements.remove(0);
+ StatementEntry st = ws.get();
if (st!=null) {
try {
- st.close();
+ st.getStatement().close();
} catch (Exception ignore) {
if (log.isDebugEnabled()) {
log.debug("Unable to closed statement upon connection
close.",ignore);
}
}
+ if (logCreationStack) {
+ log.warn("Statement created, but was not closed at:",
st.getAllocationStack());
+ }
}
}
}
@Override
+ public void setProperties(Map<String, PoolProperties.InterceptorProperty>
properties) {
+ super.setProperties(properties);
+
+ PoolProperties.InterceptorProperty logProperty =
properties.get("trace");
+ if (null != logProperty) {
+ logCreationStack = logProperty.getValueAsBoolean(logCreationStack);
+ }
+ }
+
+ @Override
public void reset(ConnectionPool parent, PooledConnection con) {
statements.clear();
super.reset(parent, con);
}
+ protected class StatementEntry {
+ private Statement statement;
+ private Throwable allocationStack;
+
+ public StatementEntry(Statement statement) {
+ this.statement = statement;
+ if (logCreationStack) {
+ this.allocationStack = new Throwable();
+ }
+ }
+
+ public Statement getStatement() {
+ return statement;
+ }
+
+ public Throwable getAllocationStack() {
+ return allocationStack;
+ }
+ }
+
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]