11

I need to log all the queries to an Oracle database in my project to a log file.

What would be a good solution to achieve this? Some sample usage would be appreciated.

I have looked at SLF4J with jdbcdslog, but I'm not sure how I can log to a file with it. Moreover, I would need to "filter" some of the logs (because I don't need to know when some getxxxx method get's invoked)

Preferably, I'd prefer to use java.util.logging but it is not a requirement.

Thanks.

** UPDATE **

I found this Oracle article, however it does not really tell how to programatically do the same thing.

Yanick Rochon
  • 51,409
  • 25
  • 133
  • 214

6 Answers6

11

After much reading, this is how I got things working :


NOTE : Fore more information, read the Oracle Diagnosability in JDBC document


Properties prop = new Properties();
prop.put ("user", USER);
prop.put ("password", PASS);
// prop.put(propname, propValue);

Class.forName("oracle.jdbc.driver.OracleDriver");

enableLogging(false);

conn = DriverManager.getConnection("jdbc:oracle:thin:@"+HOST+":"+PORT+":"+SID, prop);

And here's the magic :

static private void enableLogging(boolean logDriver) 
throws MalformedObjectNameException, NullPointerException, 
       AttributeNotFoundException, InstanceNotFoundException, 
       MBeanException, ReflectionException, InvalidAttributeValueException, 
       SecurityException, FileNotFoundException, IOException 
{
    oracle.jdbc.driver.OracleLog.setTrace(true);

    // compute the ObjectName
    String loader = Thread.currentThread().getContextClassLoader().toString().replaceAll("[,=:\"]+", "");
    javax.management.ObjectName name = new javax.management.ObjectName("com.oracle.jdbc:type=diagnosability,name="+loader);

    // get the MBean server
    javax.management.MBeanServer mbs = java.lang.management.ManagementFactory.getPlatformMBeanServer();

    // find out if logging is enabled or not
    System.out.println("LoggingEnabled = " + mbs.getAttribute(name, "LoggingEnabled"));

    // enable logging
    mbs.setAttribute(name, new javax.management.Attribute("LoggingEnabled", true));

    File propFile = new File("path/to/properties");
    LogManager logManager = LogManager.getLogManager();
    logManager.readConfiguration(new FileInputStream(propFile));

    if (logDriver) {
        DriverManager.setLogWriter(new PrintWriter(System.err));
    }
}

The properties file (from Oracle's documentation) :

.level=SEVERE
oracle.jdbc.level=INFO
oracle.jdbc.handlers=java.util.logging.ConsoleHandler
java.util.logging.ConsoleHandler.level=INFO
java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter

Basically, this is where the handlers are declared

oracle.jdbc.handlers=java.util.logging.ConsoleHandler

Declares the ConsoleHandler to be used by Oracle's JDBC driver. Any and any number of handlers can be declared here, one per line, with the class' full qualified name :

oracle.jdbc.handlers=java.util.logging.ConsoleHandler
oracle.jdbc.handlers=java.util.logging.FileHandler
...

One can provide their own custom made handlers with the same rule. The following lines are to setup the handler

java.util.logging.ConsoleHandler.level=INFO

will call the methode setLevel(Level.INFO) of the ConsoleHandler handler instance.

com.my.own.project.logging.handler.MyHandler.foo=Bar

will call the method setFoo("Bar") of the MyHandler handler instance. And that's it.

Happy logging!

Yanick Rochon
  • 51,409
  • 25
  • 133
  • 214
  • Hi Yanick, I followed all the steps in your solution but facing issue in enabling the logs, can you please take a look at my post and correct me where I am making mistake. --> http://stackoverflow.com/questions/27060563/enable-logging-for-jdbc – learner Nov 28 '14 at 05:57
  • Thanks for the info. Count on Oracle to turn what should be a simple thing into a 20 step procedure. – Rob H Sep 03 '15 at 18:53
2

suggest you look at jdbcdslog's user guide and discussion group.

A quick look at the user guide suggests that you can wrap (decorate) any JDBC connection with one of jdbcdslog's special logging wrappers, and it will log to whatever place you configure.

Furthermore it says it uses slf4j which supports logging to several logging engines including java.util.logging, so what you suggest seems very possible.

(But I'm not familiar with this jdbcdslog so I'm not sure how to get things configured.)

Jason S
  • 184,598
  • 164
  • 608
  • 970
  • yes, I read lots of stuff, but what I read just gives enough to understand the basics; currently, it's logging to the console, but I need to filter the logs, and I have no idea how :) – Yanick Rochon Apr 21 '11 at 00:43
  • 1
    OH! That's a logging framework question, not a jdbcdslog question. (From what I gathered from the jdbcdslog user guide, it just looks for slf4j and everything gets auto-started. At that point the configuration is handled by the logging framework.) You're probably better off using log4j, it's very easy to configure, and there are tons of good examples. – Jason S Apr 21 '11 at 11:27
1

I'm measuring the performance of my jdbc driver, this is a Tandem Non/Stop DB, and just setting the LogWriter in the DriverManager like this:

        try {
            // This will load the JDBC Driver
            Class.forName("com.tandem.t4jdbc.SQLMXDriver");
            // Here you will enable the Logging to a file.
            DriverManager.setLogWriter(new PrintWriter(new File("log/dbcLog.log")));
        } catch (ClassNotFoundException e) {
            _logger.error(e.toString());
        }

The logging on Queries started working.


Just as an update, I also found out that for some JDBC drivers the solution can NOT be accomplished programatically (by code changes). For example, I'm using a JDBC driver for Tandem t4 driver, and even though I added all what the manuals said about enabling JDBC tracing, it just worked from time to time and just for Queries..

Then, I was told to use just the following parameter (as a VM Option):

-Dt4sqlmx.T4LogFile=t4sqlmx.log -Dt4sqlmx.T4LogLevel=FINE

And it just simple started working..

user229044
  • 232,980
  • 40
  • 330
  • 338
Marco Vargas
  • 1,232
  • 13
  • 31
  • I also found out that for some JDBC drivers the solution can NOT be accomplished programatically (by code changes). For example, I'm using a JDBC driver for Tandem t4 driver, and even though I added all what the manuals said about enabling JDBC tracing, it just worked from time to time and just for Queries.. Then, I was told to use just the following parameter: **-Dt4sqlmx.T4LogFile=t4sqlmx.log -Dt4sqlmx.T4LogLevel=FINE** And it just simple started working.... – Marco Vargas May 04 '15 at 15:55
0

As an update to the answer of @Martin_Schröder, it also now exists log4jdbc-log4j2, which allows to use either slf4j or Log4j2, is available on the Maven repository, and supports JDBC 4.1 (Java 7).

FBB
  • 1,414
  • 2
  • 17
  • 29
0

If you are using Spring, then the datasource-proxy is very convenient. You can basically wrap around any DataSource and just add the logging behavior.

enter image description here

If you're using Java EE, then P6spy is a good alternative:

enter image description here

Behind the scenes, P6spy provides the statement interceptor at the Driver level, which is much more convenient for Java EE applications because the DataSource is provided by the application server.

Vlad Mihalcea
  • 142,745
  • 71
  • 566
  • 911
0

You configure where log messages are written by configuring where the underlying logging engine is sending them. Since you're talking about slf4j, that means you've got to configure the thing that it is bridging to (the java.util.logging system in your case; called JUL henceforth).

Unfortunately, JUL is among the more confusing systems to configure. Here's where I'll just cut to the chase. Create a file in your deployed classpath called logging.properties (I think; this is one of the confusing bits) which contains something like this:

handlers=java.util.logging.FileHandler
.level=ALL
java.util.logging.FileHandler.formatter=java.util.logging.SimpleFormatter

The documentation on the FileHandler class describes things that you can configure.

Donal Fellows
  • 133,037
  • 18
  • 149
  • 215
  • I prefer to log through log4j myself; I can make it produce a more compact and useful output than you can do with JUL (without custom code). The documentation is clearer too. – Donal Fellows Apr 21 '11 at 01:12
  • I agree. I couldn't figure out how to get JUL working, so I just went through slf4j+log4j. – Jason S Apr 21 '11 at 11:24