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: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org