JDBC logging to file

2019-01-14 17:34发布

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.

6条回答
爷、活的狠高调
2楼-- · 2019-01-14 18:09

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!

查看更多
虎瘦雄心在
3楼-- · 2019-01-14 18:15

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).

查看更多
家丑人穷心不美
4楼-- · 2019-01-14 18:19

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.

查看更多
Emotional °昔
5楼-- · 2019-01-14 18:23

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.

查看更多
别忘想泡老子
6楼-- · 2019-01-14 18:24

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.)

查看更多
我想做一个坏孩纸
7楼-- · 2019-01-14 18:29

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..

查看更多
登录 后发表回答