You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@tomcat.apache.org by Gergely Paljak <p....@gmail.com> on 2009/01/28 11:27:40 UTC
logging outgoing requests from Tomcat to SQL
Hi,
I have encountered the following challenge regarding which I would like to
ask you!
A want to realize a logging system for tomcat that is capable of:
- logging the incoming request for Servlets (easy)
- logging the outgoing SQL queries inside Tomcat while maintaining a mapping
between the requested Servlet and the sent SQL queries
- logging the incoming SQL query results
- and logging the time when the Tomcat response is sent (easy as well)
I would like to ask for you advice on how to log the SQL part? How to match
the SQL queries with Servlets without modifying the Servlet code? Could it
be realized by a valve? I have taken a look at the valves, but I haven't
found anything useful.
All comments are welcome!
Thank you,
Gergely Paljak
Re: logging outgoing requests from Tomcat to SQL
Posted by Christopher Schultz <ch...@christopherschultz.net>.
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Gergely,
Gergely Paljak wrote:
> And it looks like more wrapping than before christmas, but I have never
> taken a close look on JDBC implementations (at least not this close).
>
> So, i'd be interested in that *super-sexy *class wrapper generator of yours!
> Also in any experience, pitfalls or sources for manuals if you might have
> some ideas!
As with most super-sexy code (!), it comes without documentation and
without warranty. It is fairly readable, though.
Enjoy!
- -chris
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.Writer;
import java.lang.reflect.*;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
public class WrapperGenerator
{
public static void main(String[] args)
throws Exception
{
String className = args[0];
Class clazz = Class.forName(className);
new WrapperGenerator(clazz).generate(System.out);
}
private static String INDENT = " ";
private final Class _class;
private final String _bareName;
public WrapperGenerator(Class clazz)
{
if(Modifier.isFinal(clazz.getModifiers()))
throw new IllegalArgumentException("Cannot wrap "
+ clazz.getName() + ":"
+ " class is final.");
_class = clazz;
_bareName = getShortName(_class);
}
public void generate(OutputStream out)
throws IOException
{
this.generate(new OutputStreamWriter(out));
}
public void generate(Writer out)
throws IOException
{
PrintWriter pout;
if(out instanceof PrintWriter)
pout = (PrintWriter)out;
else
pout = new PrintWriter(out);
generateHeader(pout);
generateWrapperMethods(pout);
generateFooter(pout);
pout.flush();
}
private void generateHeader(PrintWriter out)
throws IOException
{
// package declaration
out.println("// package ;");
out.println();
// imports
// out.print("import ");
// out.print(_class.getName());
// out.println(";");
// out.println();
// class declaration
out.println("/**");
out.print(" * A wrapper class for ");
out.print(_bareName);
out.println(" objects.");
out.println(" */");
out.print("public ");
if(Modifier.isStrict(_class.getModifiers()))
out.print("strictfp ");
out.print("class ");
out.print(_bareName);
out.println("Wrapper");
out.print(INDENT);
if(Modifier.isInterface(_class.getModifiers()))
out.print("implements ");
else
out.print("extends ");
out.println(_class.getName());
out.println("{");
// wrapped member
out.print(INDENT);
out.println("/**");
out.print(INDENT);
out.print(" * The ");
out.print(_bareName);
out.println(" being wrapped by this class.");
out.print(INDENT);
out.println(" */");
out.print(INDENT);
out.print("private ");
out.print(_class.getName());
out.println(" _wrapped;");
out.println();
out.print(INDENT);
out.println("/**");
out.print(INDENT);
out.print(" * Creates a new ");
out.print(_bareName);
out.print("Wrapper with the specified wrapped ");
out.print(_bareName);
out.println(".");
out.print(INDENT);
out.println(" *");
out.print(INDENT);
out.print(" * @param wrapped The ");
out.print(_bareName);
out.print(" being wrapped by this");
out.print("_bareName");
out.println("Wrapper.");
out.print(INDENT);
out.println(" */");
out.print(INDENT);
out.print("public ");
out.print(_bareName);
out.print("Wrapper(");
out.print(_class.getName());
out.println(" wrapped)");
out.print(INDENT);
out.println("{");
out.print(INDENT);
out.print(INDENT);
out.println("_wrapped = wrapped;");
out.print(INDENT);
out.println("}");
}
private void generateWrapperMethods(PrintWriter out)
throws IOException
{
Method[] methods = _class.getDeclaredMethods();
for(int i=0; i<methods.length; ++i)
generateMethod(methods[i], out);
}
private void generateMethod(Method method, PrintWriter out)
throws IOException
{
// signature
if(Modifier.isFinal(method.getModifiers())
&& !Modifier.isStatic(method.getModifiers()))
{
// Class cannot be extended :(
out.println("// ===========================");
out.println(" // Sorry, this class cannot be extended due
to this method:");
out.print(" // ");
out.println(method);
out.println(" // ===========================");
out.println("}");
out.flush();
System.exit(5);
}
out.println();
if(Modifier.isStatic(method.getModifiers())
|| Modifier.isFinal(method.getModifiers()))
{
out.print(INDENT);
out.print("// skipping ");
out.println(method);
return;
}
if(Modifier.isPrivate(method.getModifiers()))
{
out.print(INDENT);
out.print("// skipping ");
out.println(method);
return;
}
out.print(INDENT);
out.println("/**");
out.print(INDENT);
out.print(" * Calls ");
out.print(method.getName());
out.print(" on the ");
out.print(_bareName);
out.println(" being wrapped by this object.");
out.print(INDENT);
out.println(" *");
out.print(INDENT);
out.print(" * @see ");
out.print(_class.getName());
out.print('#');
out.println(method.getName());
out.print(INDENT);
out.println(" */");
out.print(INDENT);
if(Modifier.isPublic(method.getModifiers()))
{
out.print("public ");
}
else if(Modifier.isProtected(method.getModifiers()))
{
out.print("protected ");
}
// Note that native is okay... the superclass will have a native
method
// but the subclass's method will not be native.
else
{
out.print(INDENT);
out.print("// skipping ");
out.println(method);
return;
}
if(Modifier.isStrict(method.getModifiers()))
{
out.print("strictfp ");
}
// synchronized keyword is not necessary. if the parent class's
method
// is synchronized, the subclass's methods will be effectively
// synchronized as well (because they will pass-through to the
wrapped
// object's method, which will be synchronized).
out.print(getDataType(method.getReturnType()));
out.print(" ");
out.print(method.getName());
out.print("(");
HashSet<String> usedArgNames = new HashSet<String>();
ArrayList<String> argNames = new ArrayList<String>();
Class[] argTypes = method.getParameterTypes();
for(int i=0; i<argTypes.length; ++i)
{
out.print(getDataType(argTypes[i]));
out.print(" ");
String parameterName = getParameterName(argTypes[i],
usedArgNames);
argNames.add(parameterName);
out.print(parameterName);
if(i < (argTypes.length - 1))
out.print(", ");
}
out.println(")");
// throws
Class[] exceptions = method.getExceptionTypes();
if(0 < exceptions.length)
{
out.print(INDENT);
out.print(INDENT);
out.print("throws ");
for(int i=0; i<exceptions.length; ++i)
{
out.print(exceptions[i].getName());
if(i < (exceptions.length - 1))
out.print(", ");
}
out.println();
}
out.print(INDENT);
out.println("{");
// body
out.print(INDENT);
out.print(INDENT);
if(!Void.TYPE.equals(method.getReturnType()))
out.print("return ");
out.print("_wrapped.");
out.print(method.getName());
out.print("(");
for(Iterator<String> i=argNames.iterator(); i.hasNext(); )
{
out.print(i.next());
if(i.hasNext())
out.print(", ");
}
out.println(");");
out.print(INDENT);
out.println("}");
}
private String getShortName(Class clazz)
{
String className = getDataType(clazz);
if(className.endsWith("[]"))
className = className.substring(0, className.indexOf('[')) +
"s";
int pos = className.lastIndexOf('.');
if(0 < pos)
className = className.substring(pos + 1);
return className;
}
private String getDataType(Class clazz)
{
if(clazz.isPrimitive())
return clazz.getName();
if(clazz.isArray())
return getDataType(clazz.getComponentType()) + "[]";
if(null == clazz.getPackage())
return clazz.getName();
if("java.lang".equals(clazz.getPackage().getName()))
return clazz.getName().substring(10);
return clazz.getName();
}
private String getParameterName(Class clazz, Set<String> usedNames)
{
String simpleName = getShortName(clazz);
if(Character.isUpperCase(simpleName.charAt(0)))
simpleName = Character.toLowerCase(simpleName.charAt(0))
+ simpleName.substring(1);
String name = simpleName;
int count = 0;
while(usedNames.contains(name) || RESERVED_WORDS.contains(name))
name = simpleName + String.valueOf(count++);
usedNames.add(name);
return name;
}
private void generateFooter(PrintWriter out)
throws IOException
{
out.println("}");
}
private static final Set RESERVED_WORDS
= Collections
.unmodifiableSet(new HashSet<String>(Arrays
.asList(
"abstract",
"continue",
"for",
"new",
"switch",
"assert",
"default",
"goto",
"package",
"synchronized",
"boolean",
"do",
"if",
"private",
"this",
"break",
"double",
"implements",
"protected",
"throw",
"byte",
"else",
"import",
"public",
"throws",
"case",
"enum",
"instanceof",
"return",
"transient",
"catch",
"extends",
"int",
"short",
"try",
"char",
"final",
"interface",
"static",
"void",
"class",
"finally",
"long",
"strictfp",
"volatile",
"const",
"float",
"native",
"super",
"while")))
;
}
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (MingW32)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org
iEYEARECAAYFAkmCDSAACgkQ9CaO5/Lv0PBtQQCgtyeHwK6QL5OPdMB5mxA0wuTl
ZJUAn0mSdQUCscDGjuzg2PUQcLi/abHf
=qrmx
-----END PGP SIGNATURE-----
---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org
Re: logging outgoing requests from Tomcat to SQL
Posted by Gergely Paljak <p....@gmail.com>.
Hi Christopher,
thanks for the comment, it's really interesting!
And it looks like more wrapping than before christmas, but I have never
taken a close look on JDBC implementations (at least not this close).
So, i'd be interested in that *super-sexy *class wrapper generator of yours!
Also in any experience, pitfalls or sources for manuals if you might have
some ideas!
Thank you,
Gergely Paljak
2009/1/28 Christopher Schultz <ch...@christopherschultz.net>:
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
>
> Gergely,
>
> Gergely Paljak wrote:
>> A want to realize a logging system for tomcat that is capable of:
>> - logging the incoming request for Servlets (easy)
>> - and logging the time when the Tomcat response is sent (easy as well)
>
> As you say, these are relatively easy to accomplish.
>
>> - logging the outgoing SQL queries inside Tomcat while maintaining a
mapping
>> between the requested Servlet and the sent SQL queries
>> - logging the incoming SQL query results
>
> I think your best bet is to implement your own DataSource that extends
> Tomcat's built-in datasource (or some other one, if you like). Have your
> DataSource return Connection objects that wrap the ones provided by
> Tomcat's DataSource object.
>
> Your Connection class should produce wrapped Statement classes that log
> the statements as they are executed, and wrapped ResultSet objects that
> do ... something else. Due to the specific JDBC spec requirements about
> how results are read, you may have to settle for only reading those
> values /actually read/ by the application, instead of the entire result
set.
>
> I have implemented JDBC interface wrappers before, and they are
> completely miserable to do (just sooo much plumbing code). I wrote a
> super-sexy class wrapper generator if you're interested in doing
> something like this.
>
> - -chris
> -----BEGIN PGP SIGNATURE-----
> Version: GnuPG v1.4.9 (MingW32)
> Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org
>
> iEYEARECAAYFAkmAplsACgkQ9CaO5/Lv0PAySgCfZSTz2qkBq4yZD3HCuvAYDTBb
> 2ygAnR3SMz+fR0Ow1rBF+lJcfjm5YJEU
> =wTg7
> -----END PGP SIGNATURE-----
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
> For additional commands, e-mail: users-help@tomcat.apache.org
>
>
Re: logging outgoing requests from Tomcat to SQL
Posted by Christopher Schultz <ch...@christopherschultz.net>.
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Gergely,
Gergely Paljak wrote:
> A want to realize a logging system for tomcat that is capable of:
> - logging the incoming request for Servlets (easy)
> - and logging the time when the Tomcat response is sent (easy as well)
As you say, these are relatively easy to accomplish.
> - logging the outgoing SQL queries inside Tomcat while maintaining a mapping
> between the requested Servlet and the sent SQL queries
> - logging the incoming SQL query results
I think your best bet is to implement your own DataSource that extends
Tomcat's built-in datasource (or some other one, if you like). Have your
DataSource return Connection objects that wrap the ones provided by
Tomcat's DataSource object.
Your Connection class should produce wrapped Statement classes that log
the statements as they are executed, and wrapped ResultSet objects that
do ... something else. Due to the specific JDBC spec requirements about
how results are read, you may have to settle for only reading those
values /actually read/ by the application, instead of the entire result set.
I have implemented JDBC interface wrappers before, and they are
completely miserable to do (just sooo much plumbing code). I wrote a
super-sexy class wrapper generator if you're interested in doing
something like this.
- -chris
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (MingW32)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org
iEYEARECAAYFAkmAplsACgkQ9CaO5/Lv0PAySgCfZSTz2qkBq4yZD3HCuvAYDTBb
2ygAnR3SMz+fR0Ow1rBF+lJcfjm5YJEU
=wTg7
-----END PGP SIGNATURE-----
---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org