Search code examples
grailsjdbclog4jclassnotfoundexceptionappender

Grails throws ClassNotFoundException when I setup log4j with JDBCAppender


Context

I am trying to setup log4j with JDBCAppender on Grails 2.4.3, I was trying with H2, MySQL and PostgreSQL, but it throws an ClassNotFoundException exception with each driver.

Config.groovy configuration for log4j JDBCAppender:

I have tested user and password credentials information, I mean, I can connect to these databases through Datasource.groovy file.

Test1 with H2:

log4j = {
    appenders {
        jdbc name: "db",
            databaseURL: "jdbc:h2:mem:devDb;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE",
            user: "sa",
            password: "",
            driverClassName: "org.h2.Driver",
            sql: "INSERT INTO event_log (log_date, log_message) VALUES ('%d{yyyy.MM.dd HH:mm:ss}', '[%-5p]. Category: %c. Message: %m. User: %X{sessionUserName} DU:[%X{sessionUserDU}]');"
    }

root {
    info 'grails.app.controller','db'
}

}

Test2 with Postgres:

log4j = {
    appenders {
        jdbc name: "db",
            URL: "jdbc:postgresql://localhost/grailsTestDB",
            user: "userDB",
            password: "*******",
            driver: "org.postgresql.Driver",
            layout: pattern(conversionPattern: "[%t] %-5p %c{2} %x - %m%n - %X{username}'"),
            sql: "INSERT INTO event_log (accion,nivel,req,logString,usuario) VALUES('%c{2} %x','%-5p','[%t]','%m%n','%X{username}');"
    }

root {
    info 'grails.app.controller','db'
}

}

Test3 with MySQL:

The next code was taken from an Grails 1.3.8 application, in that application this code works fine.

log4j = {
    appenders {
        appender new JDBCAppender(
            name: "db",
            databaseURL: "jdbc:mysql://dbdevsie.db.hostname.com/dbdevsie",
            driver: "com.mysql.jdbc.Driver",
            user: "dbdevsie231",
            password: "********",
            layout: pattern(conversionPattern: "[%t] %-5p %c{2} %x - %m%n - %X{username}'"),
            sql: "INSERT INTO activity_log (accion,nivel,req,logString,usuario) VALUES('%c{2} %x','%-5p','[%t]','%m%n','%X{username}');"
    )
}

root {
    info 'grails.app.controller','db'
}

}

Buildconfig.groovy dependencies setup:

dependencies {
    runtime 'mysql:mysql-connector-java:5.1.29'
    runtime 'org.postgresql:postgresql:9.3-1101-jdbc41'
    test "org.grails:grails-datastore-test-support:1.0-grails-2.4"
}

Test results:

When I test h2 it throws com.mysql.jdbc.Driver exception.

When I test Mysql it throws sun.jdbc.odbc.JdbcOdbcDriver exception.

When I test Postgresql it throws org.postgresql.Driver exception.

| Error log4j:ERROR Failed to load driver
| Error java.lang.ClassNotFoundException: sun.jdbc.odbc.JdbcOdbcDriver
| Error     at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
| Error     at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
| Error     at java.security.AccessController.doPrivileged(Native Method)
| Error     at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
| Error     at java.lang.ClassLoader.loadClass(ClassLoader.java:425)
| Error     at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
| Error     at java.lang.ClassLoader.loadClass(ClassLoader.java:358)
| Error     at java.lang.Class.forName0(Native Method)
| Error     at java.lang.Class.forName(Class.java:191)
| Error     at org.apache.log4j.jdbc.JDBCAppender.setDriver(JDBCAppender.java:391)
| Error     at org.apache.log4j.jdbc.JDBCAppender.getConnection(JDBCAppender.java:248)
| Error     at org.apache.log4j.jdbc.JDBCAppender.execute(JDBCAppender.java:215)
| Error     at org.apache.log4j.jdbc.JDBCAppender.flushBuffer(JDBCAppender.java:289)
| Error     at org.apache.log4j.jdbc.JDBCAppender.append(JDBCAppender.java:186)
| Error     at org.apache.log4j.AppenderSkeleton.doAppend(AppenderSkeleton.java:251)    

Additional comments

I also test downloading log4j 1.2.17, PostgreSQL 9.3, and MySQL 5.1.34 jar files and placed them on lib folder, but I have the same result.

Could anyone help me with this thing?

thanks in advance.

Updated

This issue shows in Mac OS, however I ran the same code in linux and there is no problem with it.

  • OS X Yosemite version 10.10.1
  • Java 1.7.0_71

Solution

  • You're correct in using the DSL instead of instantiating the appender inline; dependencies and classpath haven't been resolved when your code runs in Config.groovy, so you need some way to delay the actual initialization of the appender until after that happens and the DSL config is a good option.

    I got this working, but had different failures than you. In my case both H2 and MySQL reliably crashed my 1.7 JVM early on, but it worked when I switched to 1.8 and now it works in 1.7 also even after deleting pretty much everything. Try getting the dependencies resolved independently by commenting out these config changes, then restarting with them enabled. This might also be due to forking - I almost always disable it by deleting the whole grails.project.fork block in BuildConfig.groovy - if nothing else works, see if that helps.

    This is what I had in Config.groovy:

    log4j.main = {
    
       appenders {
          jdbc name: 'jdbcAppender', driver: 'com.mysql.jdbc.Driver', user: '...',
               password: '...', URL: 'jdbc:mysql://localhost/<dbname>',
               layout: pattern(conversionPattern:
                    "insert into logs(log_date, logger, log_level, message) " +
                    "values('%d{yyyy-MM-dd HH:mm:ss}','%c','%p','%m')")
       }
    
       root {
          info 'stdout', 'jdbcAppender'
       }
    
       error 'org.codehaus.groovy.grails',
             'org.springframework',
             'org.hibernate',
             'net.sf.ehcache.hibernate'
    }
    

    and I created this table to log into:

    create table logs (
       log_date datetime not null,
       log_level varchar(10) not null,
       logger varchar(100) not null,
       message varchar(1000) not null
    ) ENGINE=InnoDB;