Search code examples
javadb2log4j2websphere-libertylog4jdbc

Configuring log4jdbc-log4j2 with Liberty Profile


I have a web application that is deployed locally to a Liberty Profile server, and that is already working with log4j2. My end goal is to log all of the PreparedStatements with their parameter values included in the query string, just before they are run against a DB2 database.

I've been following the instructions at https://code.google.com/p/log4jdbc-log4j2 to set up log4jdbc-log4j2. I was able to pull down the dependency files with Maven:

<dependency>
    <groupId>org.bgee.log4jdbc-log4j2</groupId>
    <artifactId>log4jdbc-log4j2-jdbc4</artifactId>
    <version>1.16</version>
</dependency>

However, I've been stuck at steps 3.1 and 3.2 for awhile, and so far, nothing on stackoverflow or instructional blogs has helped me move forward, so I thought it was time to ask my own question.

Could someone please let me know in which file(s), and how, I should make the changes mentioned in steps 3.1 ("Change your JDBC URL") and 3.2 ("Change the driver used")? Please let me know if there's something I can clarify further in order to help get my question answered, and thank you in advance for any help or guidance you can provide.

Update

After making the changes to server.xml suggested aguibert and including all log4j*.jar files from the dependency in the db2 drivers directory, my server.xml entry looks like this:

<dataSource id="myDataSource" jndiName="jdbc/myDataSource" type="javax.sql.DataSource">
    <jdbcDriver javax.sql.DataSource="net.sf.log4jdbc.sql.jdbcapi.DataSourceSpy">
        <library>
            <fileset dir="<path to dir>/db2" includes="db2jcc_license_cisuz.jar db2jcc4.jar log4j-api-2.3.jar log4j-core-2.3.jar log4jdbc-log4j2-jdbc4-1.16-sources.jar log4jdbc-log4j2-jdbc4-1.16.jar"/>
        </library>
    </jdbcDriver>   
    <properties
        password="password"
        user="user"
        URL="jdbc:log4jdbc:db2://<normal jdbc url>" />
</dataSource>

Now, when the first query is made, I get an InstantiationException on net.sf.log4jdbc.sql.jdbcapi.DataSourceSpy:

java.lang.Exception:
    at <my files>
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:595) [com.ibm.ws.javaee.servlet.3.0_1.0.8.jar:?]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:668) [com.ibm.ws.javaee.servlet.3.0_1.0.8.jar:?]
    at com.ibm.ws.webcontainer.servlet.ServletWrapper.service(ServletWrapper.java:1285) [com.ibm.ws.webcontainer_1.0.8.jar:?]
    at com.ibm.ws.webcontainer.servlet.ServletWrapper.handleRequest(ServletWrapper.java:776) [com.ibm.ws.webcontainer_1.0.8.jar:?]
    at com.ibm.ws.webcontainer.servlet.ServletWrapper.handleRequest(ServletWrapper.java:473) [com.ibm.ws.webcontainer_1.0.8.jar:?]
    at com.ibm.ws.webcontainer.filter.WebAppFilterManager.invokeFilters(WebAppFilterManager.java:1104) [com.ibm.ws.webcontainer_1.0.8.jar:?]
    at com.ibm.ws.webcontainer.webapp.WebApp.handleRequest(WebApp.java:4845) [com.ibm.ws.webcontainer_1.0.8.jar:?]
    at com.ibm.ws.webcontainer.osgi.DynamicVirtualHost$2.handleRequest(DynamicVirtualHost.java:297) [com.ibm.ws.webcontainer_1.0.8.jar:?]
    at com.ibm.ws.webcontainer.WebContainer.handleRequest(WebContainer.java:981) [com.ibm.ws.webcontainer_1.0.8.jar:?]
    at com.ibm.ws.webcontainer.osgi.DynamicVirtualHost$2.run(DynamicVirtualHost.java:262) [com.ibm.ws.webcontainer_1.0.8.jar:?]
    at com.ibm.ws.http.dispatcher.internal.channel.HttpDispatcherLink$TaskWrapper.run(HttpDispatcherLink.java:955) [com.ibm.ws.transport.http_1.0.8.jar:?]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) [?:1.7.0_60]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) [?:1.7.0_60]
    at java.lang.Thread.run(Thread.java:745) [?:1.7.0_60]
Caused by: javax.naming.NamingException: CWWKN0008E: An object could not be obtained for name jdbc/myDataSource.
    at com.ibm.ws.jndi.internal.WSContext.resolveObject(WSContext.java:128) ~[?:?]
    at com.ibm.ws.jndi.internal.WSContext.lookup(WSContext.java:364) ~[?:?]
    at com.ibm.ws.jndi.internal.WSContext.lookup(WSContext.java:359) ~[?:?]
    at org.apache.aries.jndi.DelegateContext.lookup(DelegateContext.java:161) ~[?:?]
    at javax.naming.InitialContext.lookup(InitialContext.java:411) ~[?:1.7.0_60]
    at  <my files>
    ... 16 more
[ERROR   ] CWWKE0701E: FrameworkEvent ERROR Bundle:com.ibm.ws.jdbc(id=69) org.osgi.framework.ServiceException: Exception in com.ibm.ws.resource.internal.ResourceFactoryTrackerData$1.getService()
    at org.eclipse.osgi.internal.serviceregistry.ServiceFactoryUse.factoryGetService(ServiceFactoryUse.java:222)
    at [internal classes]
    at javax.naming.InitialContext.lookup(InitialContext.java:411)
    at  <my files>
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:595)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:668)
    at com.ibm.ws.webcontainer.servlet.ServletWrapper.service(ServletWrapper.java:1285)
    at [internal classes]
Caused by: java.lang.RuntimeException: java.sql.SQLNonTransientException: java.lang.InstantiationException: net.sf.log4jdbc.sql.jdbcapi.DataSourceSpy
    at com.ibm.ws.resource.internal.ResourceFactoryTrackerData$1.getService(ResourceFactoryTrackerData.java:109)
    ... 10 more
Caused by: java.sql.SQLNonTransientException: java.lang.InstantiationException: net.sf.log4jdbc.sql.jdbcapi.DataSourceSpy
    at com.ibm.ws.jdbc.internal.JDBCDriverService.create(JDBCDriverService.java:287)
    ... 10 more
Caused by: java.lang.InstantiationException: net.sf.log4jdbc.sql.jdbcapi.DataSourceSpy
    at java.lang.Class.newInstance(Class.java:359)
    at com.ibm.ws.jdbc.internal.JDBCDriverService$1.run(JDBCDriverService.java:228)
    ... 10 more
 Event:org.osgi.framework.FrameworkEvent[source=com.ibm.ws.jdbc_1.0.8.cl50520150305-2202 [69]]

If it looks like there's anything that I've missed, please let me know. Searching for the errors in the stack trace hasn't resulted in any solutions.

Final Status

As aguibert pointed out, it seems like a different direction will be best here. Based on a comment in Logging PreparedStatements in Java, I've decided to implement a LoggableStatement wrapper as described here: ibm.com/developerworks/java/library/j-loggable


Solution

  • For a WebSphere Liberty server, all of the global server config is done in the server.xml file (located by defualt at WLP_INSTALL/usr/servers//server.xml).

    You will probably want something along these lines in your server.xml:

    <dataSource id="myDataSource" jndiname="jdbc/myDataSource" type="javax.sql.DataSource">
        <jdbcDriver javax.sql.DataSource="net.sf.log4jdbc.sql.jdbcapi.DataSourceSpy">
          <library>
            <fileset dir="C:/path/to/libs" includes="thedb2jar.jar log4j.jar" />
          </library>
        </jdbcDriver>
        <properties user="user" password="password"
                    url="jdbc:log4jdbc:<the normal jdbc url>"/>
    </dataSource>
    

    The key parts here is that the element has the "javax.sql.DataSource" property set and the value is the name of the DataSource class for the log4j jar. Also, in the element, you'll see that the url is specified with the "jdbc:log4jdbc" prefix as described in section 3.1.

    This is untested advice, but you may need to include both jars (the db2 jar and the log4j jar) in the same folder so they are picked up in the same element.