3 Commits

Author SHA1 Message Date
arthur_blake 48cb541e58 update 1.6 JDK, increase amount of memory for 1.6 javadoc, and fix outdated javadoc 2008-11-08 22:30:50 +00:00
arthur_blake 201d3b974b update doc in preparation for 1.2 alpha 1 release 2008-11-08 22:01:57 +00:00
arthur_blake 007ff20ed1 initial features and improvements for 1.2 version 2008-09-20 02:52:00 +00:00
33 changed files with 1500 additions and 371 deletions
+63
View File
@@ -1,3 +1,66 @@
2008-11-08 1.2 alpha 1 Release
o added a new logger "jdbc.connection" to dump connection open and
close events as well as dumping all open connection numbers. This
is very useful for hunting down connection leak problems.
o several new options to produce better SQL output:
log4jdbc.dump.booleanastruefalse - many RDBMS's don't have a
native boolean type and store booleans as a 1 or 0. Setting this
option to false will show boolean bind variables as 1 or 0.
Setting this to true will show the boolean as true or false.
(Note that the default for this setting is false, contrary to the
previous way log4jdbc worked.)
log4jdbc.dump.sql.maxlinelength - can be used to insert line
breaks into long running SQL (at white space positions.)
previous versions of log4jdbc did this automatically with a value
of 90 (the default value is 90.) This line breaking can be turned
off completely by setting this to 0.
log4jdbc.dump.fulldebugstacktrace - can be used in extreme
debugging circumstances when you want to be able to see the full
stack trace in the debug output. Be extra careful when using
this as it will obviously produce much much more logging output.
o dump a null bind variable as NULL instead of <null> for more
accurate and reuseable SQL output.
o several new options for controlling what types of SQL statements are
logged:
log4jdbc.dump.sql.select default value is true
log4jdbc.dump.sql.insert default value is true
log4jdbc.dump.sql.update default value is true
log4jdbc.dump.sql.delete default value is true
log4jdbc.dump.sql.create default value is true
The default values for all of these are true, but they can be
selectively turned on and off to filter out unwanted types of sql
statements. For example, setting log4jdbc.dump.sql.delete will
cause all DELETE sql commands to not be logged.
o A new option to add a semi colon to the end of the dumped sql:
log4jdbc.dump.sql.addsemicolon default value is false
Sometimes it's useful to use log4jdbc to produce sql scripts that
can later be fed back into a SQL tool to execute against a
database and this option can help to produce more re-useable sql
output script data from a log file.
o added Microsoft SQL Server 2005 Driver
(com.microsoft.sqlserver.jdbc.SQLServerDriver) to
list of "well known" drivers that log4jdbc looks for at startup.
(thanks to Rob Richards for pointing this out)
Note that the SQL Server 2000 Driver with the confusing name
of (com.microsoft.jdbc.sqlserver.SQLServerDriver) is also still
supported.
o other miscellaneous improvements.
2008-04-11 1.1 Release
o upgrade to SLF4J 1.5. Note that log4jdbc should still work with
+347 -101
View File
File diff suppressed because it is too large Load Diff
+12
View File
@@ -30,6 +30,11 @@ log4j.additivity.jdbc.sqlonly=false
log4j.logger.jdbc.sqltiming=DEBUG,sqltiming
log4j.additivity.jdbc.sqltiming=false
! Log connection open/close events and connection number dump
log4j.logger.jdbc.connection=FATAL,connection
log4j.additivity.jdbc.connection=false
! the appender used for the JDBC API layer call logging above, sql only
log4j.appender.sql=org.apache.log4j.FileAppender
log4j.appender.sql.File=./logs/sql.log
@@ -50,3 +55,10 @@ log4j.appender.jdbc.File=./logs/jdbc.log
log4j.appender.jdbc.Append=false
log4j.appender.jdbc.layout=org.apache.log4j.PatternLayout
log4j.appender.jdbc.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss.SSS} %m%n
! the appender used for the JDBC Connection open and close events
log4j.appender.connection=org.apache.log4j.FileAppender
log4j.appender.connection.File=./logs/connection.log
log4j.appender.connection.Append=false
log4j.appender.connection.layout=org.apache.log4j.PatternLayout
log4j.appender.connection.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss.SSS} %m%n
+16 -3
View File
@@ -37,15 +37,23 @@
</layout>
</appender>
<appender name="jdbc-connection" class="org.apache.log4j.FileAppender">
<param name="File" value="./logs/connection.log"/>
<param name="Append" value="false"/>
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS} %m%n"/>
</layout>
</appender>
<!--
The Following 4 logs can be turned on and off while the server is running
The Following 5 logs can be turned on and off while the server is running
LIVE in order to trace the SQL and/or all JDBC coming out of the application.
To turn a log on, set the level value to INFO or DEBUG (to see class name and
line number information in the log) The DEBUG setting is much more inefficient
but the output is much more useful.
To turn off JDBC logging completely, you must set all 4 logs to a level higher
To turn off JDBC logging completely, you must set all 5 logs to a level higher
than ERROR (FATAL is suggested.)
-->
@@ -75,7 +83,12 @@
<level value="fatal"/>
<appender-ref ref="jdbc-appender"/>
</logger>
<!-- log connection open/close events and dump of all open connection numbers -->
<logger name="jdbc.connection" additivity="false">
<level value="fatal"/>
<appender-ref ref="connection-appender"/>
</logger>
<!-- this log is for internal debugging of log4jdbc, itself -->
<!-- debug logging for log4jdbc itself -->
+4 -1
View File
@@ -26,7 +26,10 @@ code,pre {color:navy;background-color:beige;font-size:11pt;}
pre {border:2px dashed navy;margin-left:3em;margin-right:4em;margin-top:1em;margin-bottom:1em;white-space:pre-line;}
.ad {font-size:0.8em;color:blue}
.copyright {font-size:0.8m;text-align:center}
.copyright a {color:#ef39e9}
.sflogo {float:right; margin-right:30px;}
table.options {margin-left:40px;margin-right:20px;border:1px solid black;border-collapse:collapse;}
table.options thead th {text-align:center;border:1px solid black; padding:5px}
table.options tbody td {text-align:left;border:1px solid black; padding:5px}
+4
View File
@@ -0,0 +1,4 @@
To build log4jdbc, you must have Ant 1.6.5 or later installed,
and JDK 1.4 and JDK 1.6 installed.
The build.cmd file is useful for building both the jdbc 3 version (JDK 1.4) and the jdbc 4 version (under JDK 1.6) under windows.
+1 -1
View File
@@ -11,7 +11,7 @@ call java -version
call ant -Djdbc.level=3 all
set JAVA_HOME=C:\jdk1.6.0_03
set JAVA_HOME=C:\jdk1.6.0_10
set PATH=%JAVA_HOME%\bin;%ANT_HOME%\bin
call java -version
+3 -2
View File
@@ -48,7 +48,7 @@
<!-- release version -->
<property name="version" value="1.1"/>
<property name="version" value="1.2alpha1"/>
<target name="all" depends="cleancompile,compile,cleanjar,jar"/>
@@ -194,6 +194,7 @@
<property name="ps" value="${path.separator}"/>
<javadoc destdir="${apidocs}" packagenames="net.sf.log4jdbc.*"
maxmemory="512m"
Windowtitle="log4${jdbc.prefix} ${version}"
Header="&lt;b&gt;&lt;a href=&quot;http://log4jdbc.sourceforge.net&quot;&gt;log4${jdbc.prefix} ${version}&lt;/a&gt;&lt;/b&gt;"
Use="true" breakiterator="true">
@@ -208,7 +209,7 @@
<!-- note that the jdk source code is referenced here so that javadoc will be generated from
interface class methods when none is specified in the implementation -->
<sourcepath path="/jdk1.6.0_03/src"/>
<sourcepath path="/jdk1.6.0_10/src"/>
<link href="http://java.sun.com/javase/6/docs/api/"/>
<!--
<link href="http://java.sun.com/j2ee/1.4/docs/api/"/>
+2 -1
View File
@@ -5,6 +5,7 @@ rem run ydoc for jdbc 3 with jdk 1.4 and
rem run ydoc for jdbc 4 with jdk 1.6
set ANT_HOME=c:\apache-ant-1.6.5
set ANT_OPTS=-Xmx512m
set JAVA_HOME=C:\j2sdk1.4.2_13
set PATH=%JAVA_HOME%\bin;%ANT_HOME%\bin
@@ -12,7 +13,7 @@ call java -version
call ant -Djdbc.level=3 ydoc.3
set JAVA_HOME=c:\jdk1.6.0_03
set JAVA_HOME=c:\jdk1.6.0_10
set PATH=%JAVA_HOME%\bin;%ANT_HOME%\bin
call java -version
+1 -1
View File
@@ -25,4 +25,4 @@ rem * profiling output report.
rem * *
rem *************************************************************************************************
java -Xmx1024m -classpath ..\build\log4jdbc3-1.1.jar net.sf.log4jdbc.PostLogProfilerProcessor %*
java -Xmx1024m -classpath ..\build\log4jdbc3-1.2alpha1.jar net.sf.log4jdbc.PostLogProfilerProcessor %*
+1 -1
View File
@@ -25,4 +25,4 @@
# * *
# *************************************************************************************************
java -Xmx1024m -classpath ../build/log4jdbc3-1.1.jar net.sf.log4jdbc.PostLogProfilerProcessor $@
java -Xmx1024m -classpath ../build/log4jdbc3-1.2alpha1.jar net.sf.log4jdbc.PostLogProfilerProcessor $@
@@ -39,8 +39,6 @@ import java.util.Map;
*/
public class CallableStatementSpy extends PreparedStatementSpy implements CallableStatement
{
private final SpyLogDelegator log;
protected void reportAllReturns(String methodCall, String msg)
{
log.methodReturned(this, methodCall, msg);
@@ -52,7 +50,7 @@ public class CallableStatementSpy extends PreparedStatementSpy implements Callab
private CallableStatement realCallableStatement;
/**
* Create a CallableStatementSpy to spy upon a CallableStatement.
* Create a CallableStatementSpy (JDBC 3 version) to spy upon a CallableStatement.
*
* @param sql The SQL used for this CallableStatement
* @param connectionSpy The ConnectionSpy which produced this CallableStatementSpy
@@ -62,7 +60,6 @@ public class CallableStatementSpy extends PreparedStatementSpy implements Callab
{
super(sql, connectionSpy, realCallableStatement);
this.realCallableStatement = realCallableStatement;
log = SpyLogFactory.getSpyLogDelegator();
}
public String getClassType()
@@ -624,6 +621,7 @@ public class CallableStatementSpy extends PreparedStatementSpy implements Callab
public void setBytes(String parameterName, byte[] x) throws SQLException
{
//todo: dump byte array?
String methodCall = "setBytes(" + parameterName + ", " + x + ")";
try
{
@@ -1040,7 +1038,6 @@ public class CallableStatementSpy extends PreparedStatementSpy implements Callab
reportException(methodCall, s);
throw s;
}
}
public void registerOutParameter(String parameterName, int sqlType, String typeName) throws SQLException
+72 -17
View File
@@ -23,10 +23,19 @@ import java.sql.SQLException;
import java.sql.SQLWarning;
import java.sql.Savepoint;
import java.sql.Statement;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
/**
* Wraps a JDBC Connection and reports method calls, returns and exceptions.
*
* This version is for jdbc 3.
*
* @author Arthur Blake
*/
public class ConnectionSpy implements Connection, Spy
@@ -35,9 +44,51 @@ public class ConnectionSpy implements Connection, Spy
private SpyLogDelegator log;
private int connectionNumber;
private final Integer connectionNumber;
private static int lastConnectionNumber = 0;
private static final Object connectionNumberLock = new Object();
/**
* Contains a Mapping of connectionNumber to currently open ConnectionSpy
* objects.
*/
private static final Map connectionTracker = new HashMap();
/**
* Get a dump of how many connections are open, and which connection numbers
* are open.
*
* @return an open connection dump.
*/
public static String getOpenConnectionsDump()
{
StringBuffer dump = new StringBuffer();
int size;
Integer[] keysArr;
synchronized (connectionTracker)
{
size = connectionTracker.size();
if (size==0)
{
return "open connections: none";
}
Set keys = connectionTracker.keySet();
keysArr = (Integer[]) keys.toArray(new Integer[keys.size()]);
}
Arrays.sort(keysArr);
dump.append("open connections: ");
for (int i=0; i < keysArr.length; i++)
{
dump.append(keysArr[i]);
dump.append(" ");
}
dump.append("(");
dump.append(size);
dump.append(")");
return dump.toString();
}
/**
* Create a new ConnectionSpy that wraps a given Connection.
@@ -46,18 +97,7 @@ public class ConnectionSpy implements Connection, Spy
*/
public ConnectionSpy(Connection realConnection)
{
setRdbmsSpecifics(DriverSpy.defaultRdbmsSpecifics); // just in case it's not initialized
if (realConnection == null)
{
throw new IllegalArgumentException("Must pass in a non null real Connection");
}
this.realConnection = realConnection;
log = SpyLogFactory.getSpyLogDelegator();
synchronized (connectionNumberLock)
{
connectionNumber = ++lastConnectionNumber;
}
this(realConnection, DriverSpy.defaultRdbmsSpecifics);
}
/**
@@ -68,6 +108,10 @@ public class ConnectionSpy implements Connection, Spy
*/
public ConnectionSpy(Connection realConnection, RdbmsSpecifics rdbmsSpecifics)
{
if (rdbmsSpecifics == null)
{
rdbmsSpecifics = DriverSpy.defaultRdbmsSpecifics;
}
setRdbmsSpecifics(rdbmsSpecifics);
if (realConnection == null)
{
@@ -76,10 +120,13 @@ public class ConnectionSpy implements Connection, Spy
this.realConnection = realConnection;
log = SpyLogFactory.getSpyLogDelegator();
synchronized (connectionNumberLock)
synchronized (connectionTracker)
{
connectionNumber = ++lastConnectionNumber;
connectionNumber = new Integer(++lastConnectionNumber);
connectionTracker.put(connectionNumber, this);
}
log.connectionOpened(this);
reportReturn("new Connection");
}
private RdbmsSpecifics rdbmsSpecifics;
@@ -104,7 +151,7 @@ public class ConnectionSpy implements Connection, Spy
return rdbmsSpecifics;
}
public int getConnectionNumber()
public Integer getConnectionNumber()
{
return connectionNumber;
}
@@ -685,6 +732,14 @@ public class ConnectionSpy implements Connection, Spy
reportException(methodCall, s);
throw s;
}
finally
{
synchronized (connectionTracker)
{
connectionTracker.remove(connectionNumber);
}
log.connectionClosed(this);
}
reportReturn(methodCall);
}
}
+143 -1
View File
@@ -45,10 +45,13 @@ import java.util.TreeSet;
* <li>com.sybase.jdbc2.jdbc.SybDriver</li>
* <li>net.sourceforge.jtds.jdbc.Driver</li>
* <li>com.microsoft.jdbc.sqlserver.SQLServerDriver</li>
* <li>com.microsoft.sqlserver.jdbc.SQLServerDriver</li>
* <li>weblogic.jdbc.sqlserver.SQLServerDriver</li>
* <li>com.informix.jdbc.IfxDriver</li>
* <li>org.apache.derby.jdbc.ClientDriver</li>
* <li>org.apache.derby.jdbc.EmbeddedDriver</li>
* <li>com.mysql.jdbc.Driver</li>
* <li>org.postgresql.Driver</li>
* <li>org.hsqldb.jdbcDriver</li>
* <li>org.h2.Driver</li>
* </ul>
@@ -137,6 +140,47 @@ public class DriverSpy implements Driver
*/
static long SqlTimingErrorThresholdMsec;
/**
* When dumping boolean values, dump them as 'true' or 'false'.
* If this option is not set, they will be dumped as 1 or 0 as many
* databases do not have a boolean type, and this allows for more
* portable sql dumping.
*/
static boolean DumpBooleanAsTrueFalse;
/**
* When dumping SQL, if this is greater than 0, than the SQL will
* be broken up into lines that are no longer than this value.
*/
static int DumpSqlMaxLineLength;
/**
* Options to more finely control which types of SQL statements will
* be dumped, when dumping SQL.
* By default all 5 of the following will be true. If any one is set to
* false, then that particular type of SQL will not be dumped.
*/
static boolean DumpSqlSelect;
static boolean DumpSqlInsert;
static boolean DumpSqlUpdate;
static boolean DumpSqlDelete;
static boolean DumpSqlCreate;
// only true if one ore more of the above 4 flags are false.
static boolean DumpSqlFilteringOn;
/**
* If true, add a semilcolon to the end of each SQL dump.
*/
static boolean DumpSqlAddSemicolon;
/**
* If dumping in debug mode, dump the full stack trace.
* This will result in a VERY voluminous output, but can be very useful
* under some circumstances.
*/
static boolean DumpFullDebugStackTrace;
/**
* Get a Long option from a system property and
* log a debug message about this.
@@ -164,7 +208,42 @@ public class DriverSpy implements Driver
catch (NumberFormatException n)
{
log.debug("x " + propName + " \"" + propValue +
"\" is not a valid long value");
"\" is not a valid number");
}
}
return longPropValue;
}
/**
* Get a Long option from a system property and
* log a debug message about this.
*
* @param propName System property key.
*
* @return the value of that System property key, converted
* to a Long. Or null if not defined or is invalid.
*/
private static Long getLongOption(String propName, long defaultValue)
{
String propValue = System.getProperty(propName);
Long longPropValue;
if (propValue == null)
{
log.debug("x " + propName + " is not defined (using default of " + defaultValue +")");
longPropValue = new Long(defaultValue);
}
else
{
try
{
longPropValue = new Long(Long.parseLong(propValue));
log.debug(" " + propName + " = " + longPropValue);
}
catch (NumberFormatException n)
{
log.debug("x " + propName + " \"" + propValue +
"\" is not a valid number (using default of " + defaultValue +")");
longPropValue = new Long(defaultValue);
}
}
return longPropValue;
@@ -192,6 +271,43 @@ public class DriverSpy implements Driver
return propValue;
}
/**
* Get a boolean option from a system property and
* log a debug message about this.
*
* @param propName property name to get.
* @param defaultValue default value to use if undefined.
*
* @return boolean value found in property, or defaultValue if no property
* found.
*/
private static boolean getBooleanOption(String propName, boolean defaultValue)
{
String propValue = System.getProperty(propName);
boolean val;
if (propValue == null)
{
log.debug("x " + propName + " is not defined (using default value " +
defaultValue + ")");
return defaultValue;
}
else
{
propValue = propValue.trim().toLowerCase();
if (propValue.length() == 0)
{
val = defaultValue;
}
else
{
val= "true".equals(propValue) ||
"yes".equals(propValue) || "on".equals(propValue);
}
}
log.debug(" " + propName + " = " + val);
return val;
}
static
{
log.debug("... log4jdbc initializing ...");
@@ -214,6 +330,26 @@ public class DriverSpy implements Driver
SqlTimingErrorThresholdMsec = thresh.longValue();
}
DumpBooleanAsTrueFalse =
getBooleanOption("log4jdbc.dump.booleanastruefalse",false);
DumpSqlMaxLineLength = getLongOption("log4jdbc.dump.sql.maxlinelength", 90L).
intValue();
DumpFullDebugStackTrace =
getBooleanOption("log4jdbc.dump.fulldebugstacktrace",false);
DumpSqlSelect = getBooleanOption("log4jdbc.dump.sql.select",true);
DumpSqlInsert = getBooleanOption("log4jdbc.dump.sql.insert",true);
DumpSqlUpdate = getBooleanOption("log4jdbc.dump.sql.update",true);
DumpSqlDelete = getBooleanOption("log4jdbc.dump.sql.delete",true);
DumpSqlCreate = getBooleanOption("log4jdbc.dump.sql.create",true);
DumpSqlFilteringOn = !(DumpSqlSelect && DumpSqlInsert && DumpSqlUpdate &&
DumpSqlDelete && DumpSqlCreate);
DumpSqlAddSemicolon = getBooleanOption("log4jdbc.dump.sql.addsemicolon",false);
// The Set of drivers that the log4jdbc driver will preload at instantiation
// time. The driver can spy on any driver type, it's just a little bit
// easier to configure log4jdbc if it's one of these types!
@@ -222,7 +358,13 @@ public class DriverSpy implements Driver
subDrivers.add("oracle.jdbc.driver.OracleDriver");
subDrivers.add("com.sybase.jdbc2.jdbc.SybDriver");
subDrivers.add("net.sourceforge.jtds.jdbc.Driver");
// MS driver for Sql Server 2000
subDrivers.add("com.microsoft.jdbc.sqlserver.SQLServerDriver");
// MS driver for Sql Server 2005
subDrivers.add("com.microsoft.sqlserver.jdbc.SQLServerDriver");
subDrivers.add("weblogic.jdbc.sqlserver.SQLServerDriver");
subDrivers.add("com.informix.jdbc.IfxDriver");
subDrivers.add("org.apache.derby.jdbc.ClientDriver");
@@ -33,7 +33,6 @@ import java.sql.Time;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.StringTokenizer;
import java.util.List;
/**
@@ -44,8 +43,6 @@ import java.util.List;
public class PreparedStatementSpy extends StatementSpy implements PreparedStatement
{
private final SpyLogDelegator log;
/**
* holds list of bind variables for tracing
*/
@@ -65,6 +62,8 @@ public class PreparedStatementSpy extends StatementSpy implements PreparedStatem
*/
protected void argTraceSet(int i, String typeHelper, Object arg)
{
String tracedArg = rdbmsSpecifics.formatParameterObject(arg);
i--; // make the index 0 based
synchronized (argTrace)
{
@@ -75,15 +74,11 @@ public class PreparedStatementSpy extends StatementSpy implements PreparedStatem
}
if (!showTypeHelp || typeHelper == null)
{
typeHelper = "";
}
if (arg != null)
{
argTrace.set(i, typeHelper + arg.toString());
argTrace.set(i, tracedArg);
}
else
{
argTrace.set(i, typeHelper + "null");
argTrace.set(i, typeHelper + tracedArg);
}
}
}
@@ -128,30 +123,8 @@ public class PreparedStatementSpy extends StatementSpy implements PreparedStatem
{
dumpSql.append(sql.substring(lastPos, sql.length())); // dump last segment
}
// insert line breaks into sql to make it more readable
StringBuffer output = new StringBuffer();
StringTokenizer st = new StringTokenizer(dumpSql.toString());
String token;
int linelength = 0;
while (st.hasMoreElements())
{
token = (String) st.nextElement();
output.append(token);
linelength += token.length();
output.append(" ");
linelength++;
if (linelength > 90)
{
output.append("\n");
linelength = 0;
}
}
return output.toString();
return dumpSql.toString();
}
protected void reportAllReturns(String methodCall, String msg)
@@ -170,7 +143,7 @@ public class PreparedStatementSpy extends StatementSpy implements PreparedStatem
protected RdbmsSpecifics rdbmsSpecifics;
/**
* Create a prepared statement spy for logging activity of another PreparedStatement.
* Create a PreparedStatementSpy (JDBC 3 version) for logging activity of another PreparedStatement.
*
* @param sql SQL for the prepared statement that is being spied upon.
* @param connectionSpy ConnectionSpy that was called to produce this PreparedStatement.
@@ -181,7 +154,6 @@ public class PreparedStatementSpy extends StatementSpy implements PreparedStatem
super(connectionSpy, realPreparedStatement); // does null check for us
this.sql = sql;
this.realPreparedStatement = realPreparedStatement;
log = SpyLogFactory.getSpyLogDelegator();
rdbmsSpecifics = connectionSpy.getRdbmsSpecifics();
}
@@ -243,7 +215,7 @@ public class PreparedStatementSpy extends StatementSpy implements PreparedStatem
public void setNull(int parameterIndex, int sqlType) throws SQLException
{
String methodCall = "setNull(" + parameterIndex + ", " + sqlType + ")";
argTraceSet(parameterIndex, null, "null");
argTraceSet(parameterIndex, null, null);
try
{
realPreparedStatement.setNull(parameterIndex, sqlType);
@@ -259,7 +231,7 @@ public class PreparedStatementSpy extends StatementSpy implements PreparedStatem
public void setNull(int paramIndex, int sqlType, String typeName) throws SQLException
{
String methodCall = "setNull(" + paramIndex + ", " + sqlType + ", " + typeName + ")";
argTraceSet(paramIndex, null, "null");
argTraceSet(paramIndex, null, null);
try
{
realPreparedStatement.setNull(paramIndex, sqlType, typeName);
@@ -291,7 +263,7 @@ public class PreparedStatementSpy extends StatementSpy implements PreparedStatem
public void setBoolean(int parameterIndex, boolean x) throws SQLException
{
String methodCall = "setBoolean(" + parameterIndex + ", " + x + ")";
argTraceSet(parameterIndex, "(boolean)", Boolean.toString(x));
argTraceSet(parameterIndex, "(boolean)", x?Boolean.TRUE:Boolean.FALSE);
try
{
realPreparedStatement.setBoolean(parameterIndex, x);
@@ -355,7 +327,7 @@ public class PreparedStatementSpy extends StatementSpy implements PreparedStatem
public void setByte(int parameterIndex, byte x) throws SQLException
{
String methodCall = "setByte(" + parameterIndex + ", " + x + ")";
argTraceSet(parameterIndex, "(byte)", Byte.toString(x));
argTraceSet(parameterIndex, "(byte)", new Byte(x));
try
{
realPreparedStatement.setByte(parameterIndex, x);
@@ -390,7 +362,7 @@ public class PreparedStatementSpy extends StatementSpy implements PreparedStatem
public void setShort(int parameterIndex, short x) throws SQLException
{
String methodCall = "setShort(" + parameterIndex + ", " + x + ")";
argTraceSet(parameterIndex, "(short)", Short.toString(x));
argTraceSet(parameterIndex, "(short)", new Short(x));
try
{
realPreparedStatement.setShort(parameterIndex, x);
@@ -425,7 +397,7 @@ public class PreparedStatementSpy extends StatementSpy implements PreparedStatem
public void setInt(int parameterIndex, int x) throws SQLException
{
String methodCall = "setInt(" + parameterIndex + ", " + x + ")";
argTraceSet(parameterIndex, "(int)", Integer.toString(x));
argTraceSet(parameterIndex, "(int)", new Integer(x));
try
{
realPreparedStatement.setInt(parameterIndex, x);
@@ -441,7 +413,7 @@ public class PreparedStatementSpy extends StatementSpy implements PreparedStatem
public void setLong(int parameterIndex, long x) throws SQLException
{
String methodCall = "setLong(" + parameterIndex + ", " + x + ")";
argTraceSet(parameterIndex, "(long)", Long.toString(x));
argTraceSet(parameterIndex, "(long)", new Long(x));
try
{
realPreparedStatement.setLong(parameterIndex, x);
@@ -457,7 +429,7 @@ public class PreparedStatementSpy extends StatementSpy implements PreparedStatem
public void setFloat(int parameterIndex, float x) throws SQLException
{
String methodCall = "setFloat(" + parameterIndex + ", " + x + ")";
argTraceSet(parameterIndex, "(float)", Float.toString(x));
argTraceSet(parameterIndex, "(float)", new Float(x));
try
{
realPreparedStatement.setFloat(parameterIndex, x);
@@ -473,7 +445,7 @@ public class PreparedStatementSpy extends StatementSpy implements PreparedStatem
public void setDouble(int parameterIndex, double x) throws SQLException
{
String methodCall = "setDouble(" + parameterIndex + ", " + x + ")";
argTraceSet(parameterIndex, "(double)", Double.toString(x));
argTraceSet(parameterIndex, "(double)", new Double(x));
try
{
realPreparedStatement.setDouble(parameterIndex, x);
@@ -505,7 +477,6 @@ public class PreparedStatementSpy extends StatementSpy implements PreparedStatem
public void setURL(int parameterIndex, URL x) throws SQLException
{
String methodCall = "setURL(" + parameterIndex + ", " + x + ")";
argTraceSet(parameterIndex, "(URL)", x);
try
@@ -523,8 +494,7 @@ public class PreparedStatementSpy extends StatementSpy implements PreparedStatem
public void setString(int parameterIndex, String x) throws SQLException
{
String methodCall = "setString(" + parameterIndex + ", \"" + x + "\")";
argTraceSet(parameterIndex, "(String)", rdbmsSpecifics.formatParameterObject(x));
argTraceSet(parameterIndex, "(String)", x);
try
{
@@ -540,6 +510,7 @@ public class PreparedStatementSpy extends StatementSpy implements PreparedStatem
public void setBytes(int parameterIndex, byte[] x) throws SQLException
{
//todo: dump array?
String methodCall = "setBytes(" + parameterIndex + ", " + x + ")";
argTraceSet(parameterIndex, "(byte[])", "<byte[]>");
try
@@ -557,7 +528,7 @@ public class PreparedStatementSpy extends StatementSpy implements PreparedStatem
public void setDate(int parameterIndex, Date x) throws SQLException
{
String methodCall = "setDate(" + parameterIndex + ", " + x + ")";
argTraceSet(parameterIndex, "(Date)", rdbmsSpecifics.formatParameterObject(x));
argTraceSet(parameterIndex, "(Date)", x);
try
{
realPreparedStatement.setDate(parameterIndex, x);
@@ -587,7 +558,7 @@ public class PreparedStatementSpy extends StatementSpy implements PreparedStatem
public void setDate(int parameterIndex, Date x, Calendar cal) throws SQLException
{
String methodCall = "setDate(" + parameterIndex + ", " + x + ", " + cal + ")";
argTraceSet(parameterIndex, "(Date)", rdbmsSpecifics.formatParameterObject(x));
argTraceSet(parameterIndex, "(Date)", x);
try
{
@@ -636,7 +607,7 @@ public class PreparedStatementSpy extends StatementSpy implements PreparedStatem
public void setObject(int parameterIndex, Object x, int targetSqlType, int scale) throws SQLException
{
String methodCall = "setObject(" + parameterIndex + ", " + x + ", " + targetSqlType + ", " + scale + ")";
argTraceSet(parameterIndex, getTypeHelp(x), rdbmsSpecifics.formatParameterObject(x));
argTraceSet(parameterIndex, getTypeHelp(x), x);
try
{
@@ -653,7 +624,7 @@ public class PreparedStatementSpy extends StatementSpy implements PreparedStatem
public void setObject(int parameterIndex, Object x, int targetSqlType) throws SQLException
{
String methodCall = "setObject(" + parameterIndex + ", " + x + ", " + targetSqlType + ")";
argTraceSet(parameterIndex, getTypeHelp(x), rdbmsSpecifics.formatParameterObject(x));
argTraceSet(parameterIndex, getTypeHelp(x), x);
try
{
realPreparedStatement.setObject(parameterIndex, x, targetSqlType);
@@ -669,7 +640,7 @@ public class PreparedStatementSpy extends StatementSpy implements PreparedStatem
public void setObject(int parameterIndex, Object x) throws SQLException
{
String methodCall = "setObject(" + parameterIndex + ", " + x + ")";
argTraceSet(parameterIndex, getTypeHelp(x), rdbmsSpecifics.formatParameterObject(x));
argTraceSet(parameterIndex, getTypeHelp(x), x);
try
{
realPreparedStatement.setObject(parameterIndex, x);
@@ -685,7 +656,7 @@ public class PreparedStatementSpy extends StatementSpy implements PreparedStatem
public void setTimestamp(int parameterIndex, Timestamp x) throws SQLException
{
String methodCall = "setTimestamp(" + parameterIndex + ", " + x + ")";
argTraceSet(parameterIndex, "(Date)", rdbmsSpecifics.formatParameterObject(x));
argTraceSet(parameterIndex, "(Date)", x);
try
{
realPreparedStatement.setTimestamp(parameterIndex, x);
@@ -701,7 +672,7 @@ public class PreparedStatementSpy extends StatementSpy implements PreparedStatem
public void setTimestamp(int parameterIndex, Timestamp x, Calendar cal) throws SQLException
{
String methodCall = "setTimestamp(" + parameterIndex + ", " + x + ", " + cal + ")";
argTraceSet(parameterIndex, "(Timestamp)", rdbmsSpecifics.formatParameterObject(x));
argTraceSet(parameterIndex, "(Timestamp)", x);
try
{
realPreparedStatement.setTimestamp(parameterIndex, x, cal);
@@ -736,7 +707,7 @@ public class PreparedStatementSpy extends StatementSpy implements PreparedStatem
public void setAsciiStream(int parameterIndex, InputStream x, int length) throws SQLException
{
String methodCall = "setAsciiStream(" + parameterIndex + ", " + x + ", " + length + ")";
argTraceSet(parameterIndex, "(Ascii InputStream)", "<Ascii InputStream of length " + x + ">");
argTraceSet(parameterIndex, "(Ascii InputStream)", "<Ascii InputStream of length " + length + ">");
try
{
realPreparedStatement.setAsciiStream(parameterIndex, x, length);
@@ -46,12 +46,13 @@ class RdbmsSpecifics
{
if (object == null)
{
return "<null>";
return "NULL";
}
else
{
if (object instanceof String)
{
// todo: need to handle imbedded quotes??
return "'" + object + "'";
}
else if (object instanceof Date)
@@ -62,6 +63,12 @@ class RdbmsSpecifics
{
return object.toString();
}
else if (object instanceof Boolean)
{
return DriverSpy.DumpBooleanAsTrueFalse?
((Boolean)object).booleanValue()?"true":"false"
:((Boolean)object).booleanValue()?"1":"0";
}
else
{
return object.toString();
+7 -1
View File
@@ -37,6 +37,8 @@ import java.util.Map;
/**
* Wraps a ResultSet and reports method calls, returns and exceptions.
*
* JDBC 3 version.
*
* @author Arthur Blake
*/
public class ResultSetSpy implements ResultSet, Spy
@@ -84,6 +86,7 @@ public class ResultSetSpy implements ResultSet, Spy
this.realResultSet = realResultSet;
this.parent = parent;
log = SpyLogFactory.getSpyLogDelegator();
reportReturn("new ResultSet");
}
/**
@@ -96,7 +99,7 @@ public class ResultSetSpy implements ResultSet, Spy
return classTypeDescription;
}
public int getConnectionNumber()
public Integer getConnectionNumber()
{
return parent.getConnectionNumber();
}
@@ -1328,6 +1331,7 @@ public class ResultSetSpy implements ResultSet, Spy
}
else
{
//todo: what's going on here?
return (Statement) reportReturn(methodCall, new StatementSpy(new ConnectionSpy(s.getConnection()), s));
}
}
@@ -1456,6 +1460,7 @@ public class ResultSetSpy implements ResultSet, Spy
public void updateBytes(int columnIndex, byte[] x) throws SQLException
{
// todo: dump array?
String methodCall = "updateBytes(" + columnIndex + ", " + x + ")";
try
{
@@ -1471,6 +1476,7 @@ public class ResultSetSpy implements ResultSet, Spy
public void updateBytes(String columnName, byte[] x) throws SQLException
{
// todo: dump array?
String methodCall = "updateBytes(" + columnName + ", " + x + ")";
try
{
@@ -15,6 +15,8 @@
*/
package net.sf.log4jdbc;
import java.util.StringTokenizer;
import org.slf4j.LoggerFactory;
import org.slf4j.Logger;
@@ -53,6 +55,12 @@ public class Slf4jSpyLogDelegator implements SpyLogDelegator
* Logger that shows the SQL timing, post execution
*/
private final Logger sqlTimingLogger = LoggerFactory.getLogger("jdbc.sqltiming");
/**
* Logger that shows connection open and close events as well as current number
* of open connections.
*/
private final Logger connectionLogger = LoggerFactory.getLogger("jdbc.connection");
// admin/setup logging for log4jdbc.
@@ -70,7 +78,7 @@ public class Slf4jSpyLogDelegator implements SpyLogDelegator
public boolean isJdbcLoggingEnabled()
{
return jdbcLogger.isErrorEnabled() || resultSetLogger.isErrorEnabled() || sqlOnlyLogger.isErrorEnabled() ||
sqlTimingLogger.isErrorEnabled();
sqlTimingLogger.isErrorEnabled() || connectionLogger.isErrorEnabled();
}
/**
@@ -86,7 +94,7 @@ public class Slf4jSpyLogDelegator implements SpyLogDelegator
public void exceptionOccured(Spy spy, String methodCall, Exception e, String sql, long execTime)
{
String classType = spy.getClassType();
int spyNo = spy.getConnectionNumber();
Integer spyNo = spy.getConnectionNumber();
String header = spyNo + ". " + classType + "." + methodCall;
if (sql == null)
{
@@ -132,7 +140,7 @@ public class Slf4jSpyLogDelegator implements SpyLogDelegator
public void methodReturned(Spy spy, String methodCall, String returnMsg)
{
String classType = spy.getClassType();
int spyNo = spy.getConnectionNumber();
Integer spyNo = spy.getConnectionNumber();
String header = spyNo + ". " + classType + "." + methodCall + " returned " + returnMsg;
if (ResultSetSpy.classTypeDescription.equals(classType))
{
@@ -170,6 +178,34 @@ public class Slf4jSpyLogDelegator implements SpyLogDelegator
}
private static String nl = System.getProperty("line.separator");
/**
* Determine if the given sql should be logged or not
* based on the various DumpSqlXXXXXX flags.
*
* @param sql SQL to test.
* @return true if the SQL should be logged, false if not.
*/
private boolean shouldSqlBeLogged(String sql)
{
if (sql == null)
{
return false;
}
sql = sql.trim();
if (sql.length()<6)
{
return false;
}
sql = sql.substring(0,6).toLowerCase();
return
(DriverSpy.DumpSqlSelect && "select".equals(sql)) ||
(DriverSpy.DumpSqlInsert && "insert".equals(sql)) ||
(DriverSpy.DumpSqlUpdate && "update".equals(sql)) ||
(DriverSpy.DumpSqlDelete && "delete".equals(sql)) ||
(DriverSpy.DumpSqlCreate && "create".equals(sql));
}
/**
* Special call that is called only for JDBC method calls that contain SQL.
@@ -180,16 +216,72 @@ public class Slf4jSpyLogDelegator implements SpyLogDelegator
*/
public void sqlOccured(Spy spy, String methodCall, String sql)
{
int spyNo = spy.getConnectionNumber();
if (!DriverSpy.DumpSqlFilteringOn || shouldSqlBeLogged(sql))
{
sql = processSql(sql);
if (sqlOnlyLogger.isDebugEnabled())
{
sqlOnlyLogger.debug(getDebugInfo() + nl + spy.getConnectionNumber() + ". " + sql);
}
else if (sqlOnlyLogger.isInfoEnabled())
{
sqlOnlyLogger.info(sql);
}
}
}
if (sqlOnlyLogger.isDebugEnabled())
/**
* Break an SQL statement up into multiple lines in an attempt to make it
* more readable
*
* @param sql SQL to break up.
* @return SQL broken up into multiple lines
*/
private String processSql(String sql)
{
if (sql==null)
{
sqlOnlyLogger.debug(getDebugInfo() + nl + spyNo + ". " + sql);
return null;
}
else if (sqlOnlyLogger.isInfoEnabled())
sql = sql.trim();
StringBuffer output = new StringBuffer();
if (DriverSpy.DumpSqlMaxLineLength <= 0)
{
sqlOnlyLogger.info(sql);
output.append(sql);
}
else
{
// insert line breaks into sql to make it more readable
StringTokenizer st = new StringTokenizer(sql);
String token;
int linelength = 0;
while (st.hasMoreElements())
{
token = (String) st.nextElement();
output.append(token);
linelength += token.length();
output.append(" ");
linelength++;
if (linelength > 90)
{
output.append("\n");
linelength = 0;
}
}
}
if (DriverSpy.DumpSqlAddSemicolon)
{
output.append(";");
}
return output.toString();
}
/**
@@ -206,10 +298,8 @@ public class Slf4jSpyLogDelegator implements SpyLogDelegator
*/
public void sqlTimingOccured(Spy spy, long execTime, String methodCall, String sql)
{
// un-comment to simulate random delay to make testing easier
//execTime = execTime + (long)(Math.random() * 5000);
if (sqlTimingLogger.isErrorEnabled())
if (sqlTimingLogger.isErrorEnabled() &&
(!DriverSpy.DumpSqlFilteringOn || shouldSqlBeLogged(sql)))
{
if (DriverSpy.SqlTimingErrorThresholdEnabled &&
execTime >= DriverSpy.SqlTimingErrorThresholdMsec)
@@ -268,6 +358,13 @@ public class Slf4jSpyLogDelegator implements SpyLogDelegator
out.append(spy.getConnectionNumber());
out.append(". ");
}
// NOTE: if both sql dump and sql timing dump are on, the processSql
// algorithm will run TWICE once at the beginning and once at the end
// this is not very efficient but usually
// only one or the other dump should be on and not both.
sql = processSql(sql);
out.append(sql);
out.append(" {executed in ");
@@ -292,39 +389,72 @@ public class Slf4jSpyLogDelegator implements SpyLogDelegator
{
Throwable t = new Throwable();
t.fillInStackTrace();
StackTraceElement[] stackTrace = t.getStackTrace();
if (stackTrace != null)
{
int firstLog4jdbcCall = 0;
int lastApplicationCall = 0;
String className;
for (int i = 0; i < stackTrace.length; i++)
StringBuffer dump = new StringBuffer();
/**
* The DumpFullDebugStackTrace option is useful in some situations when
* we want to see the full stack trace in the debug info- watch out
* though as this will make the logs HUGE!
*/
if (DriverSpy.DumpFullDebugStackTrace)
{
className = stackTrace[i].getClassName();
if (className.startsWith("net.sf.log4jdbc"))
boolean first=true;
for (int i = 0; i < stackTrace.length; i++)
{
firstLog4jdbcCall = i;
}
else if (DriverSpy.TraceFromApplication &&
className.startsWith(DriverSpy.DebugStackPrefix))
{
lastApplicationCall = i;
break;
className = stackTrace[i].getClassName();
if (!className.startsWith("net.sf.log4jdbc"))
{
if (first)
{
first = false;
}
else
{
dump.append(" ");
}
dump.append("at ");
dump.append(stackTrace[i]);
dump.append(nl);
}
}
}
StringBuffer dump = new StringBuffer(" ");
int j = lastApplicationCall;
if (j == 0) // if app not found, then use whoever was the last guy that called a log4jdbc class.
else
{
j = 1 + firstLog4jdbcCall;
}
dump.append(" ");
int firstLog4jdbcCall = 0;
int lastApplicationCall = 0;
dump.append(stackTrace[j].getClassName()).append(".").append(stackTrace[j].getMethodName()).append("(").
append(stackTrace[j].getFileName()).append(":").append(stackTrace[j].getLineNumber()).append(")");
for (int i = 0; i < stackTrace.length; i++)
{
className = stackTrace[i].getClassName();
if (className.startsWith("net.sf.log4jdbc"))
{
firstLog4jdbcCall = i;
}
else if (DriverSpy.TraceFromApplication &&
className.startsWith(DriverSpy.DebugStackPrefix))
{
lastApplicationCall = i;
break;
}
}
int j = lastApplicationCall;
if (j == 0) // if app not found, then use whoever was the last guy that called a log4jdbc class.
{
j = 1 + firstLog4jdbcCall;
}
dump.append(stackTrace[j].getClassName()).append(".").append(stackTrace[j].getMethodName()).append("(").
append(stackTrace[j].getFileName()).append(":").append(stackTrace[j].getLineNumber()).append(")");
}
return dump.toString();
}
@@ -343,5 +473,42 @@ public class Slf4jSpyLogDelegator implements SpyLogDelegator
{
debugLogger.debug(msg);
}
}
/**
* Called whenever a new connection spy is created.
*
* @param spy ConnectionSpy that was created.
*/
public void connectionOpened(Spy spy)
{
if (connectionLogger.isDebugEnabled())
{
connectionLogger.info(spy.getConnectionNumber() + ". Connection opened " +
getDebugInfo());
connectionLogger.debug(ConnectionSpy.getOpenConnectionsDump());
}
else
{
connectionLogger.info(spy.getConnectionNumber() + ". Connection opened");
}
}
/**
* Called whenever a connection spy is closed.
*
* @param spy ConnectionSpy that was closed.
*/
public void connectionClosed(Spy spy)
{
if (connectionLogger.isDebugEnabled())
{
connectionLogger.info(spy.getConnectionNumber() + ". Connection closed " +
getDebugInfo());
connectionLogger.debug(ConnectionSpy.getOpenConnectionsDump());
}
else
{
connectionLogger.info(spy.getConnectionNumber() + ". Connection closed");
}
}
}
+1 -1
View File
@@ -39,5 +39,5 @@ public interface Spy
*
* @return the connection instance number.
*/
public int getConnectionNumber();
public Integer getConnectionNumber();
}
+14 -2
View File
@@ -24,7 +24,6 @@ package net.sf.log4jdbc;
*/
public interface SpyLogDelegator
{
/**
* Determine if any of the jdbc or sql loggers are turned on.
*
@@ -54,7 +53,6 @@ public interface SpyLogDelegator
*/
public void methodReturned(Spy spy, String methodCall, String returnMsg);
/**
* Called when a spied upon object is constructed.
*
@@ -82,6 +80,20 @@ public interface SpyLogDelegator
*/
public void sqlTimingOccured(Spy spy, long execTime, String methodCall, String sql);
/**
* Called whenever a new connection spy is created.
*
* @param spy ConnectionSpy that was created.
*/
public void connectionOpened(Spy spy);
/**
* Called whenever a connection spy is closed.
*
* @param spy ConnectionSpy that was closed.
*/
public void connectionClosed(Spy spy);
/**
* Log a Setup and/or administrative log message for log4jdbc.
*

Some files were not shown because too many files have changed in this diff Show More