James Allman
James Allman

Reputation: 41168

Grails log4j SMTPAppender NoClassDefFoundError

How do I configure SMTPAppender in a new Grails 2.4.5 project? I receive a NoClassDefFoundError when running in the development environment:

| Error log4j:ERROR Error initializing log4j: javax/mail/Message

| Error java.lang.NoClassDefFoundError: javax/mail/Message

Gist: Detailed stacktrace

I have configured a dependency for javax.mail and configured log4j as follows:

dependencies {
    provided 'javax.mail:mail:1.4.7'
}

log4j = {
    appenders {
        appender new org.apache.log4j.net.SMTPAppender(
            name: 'smtp',
            layout: pattern(conversionPattern: '%d{MM-dd-yyyy HH:mm:ss.SSS} [%t] %c %M %x%n%p: %m%n')
            to: '[email protected]',
            from: '[email protected]',
            subject: 'Grails Message',
            SMTPHost: '127.0.0.1')
        )
    }
}

GitHub: Example Project

Upvotes: 5

Views: 610

Answers (2)

andres.arslanian
andres.arslanian

Reputation: 101

I know this post is old, but I struggled with the same till I found a solution that is at least working for me (not with SMTPAppender but with Sentry - same purpose).

The explanation I found with the errors you where receiving

Error log4j:ERROR Error initializing log4j: javax/mail/Message

Error java.lang.NoClassDefFoundError: javax/mail/Message

Come from this piece of code:

dependencies {
    provided 'javax.mail:mail:1.4.7'
}

The thing is that when you compile things work, when you try to do grails run-app you receive this error.

The explanation I found is that the log4j initializes before the maven dependency is resolved.

I wrote a comment of how I've used Sentry as an appender. https://github.com/getsentry/raven-java/issues/184#issuecomment-259432057

Basically, instead of adding the maven dependency I've downloaded the java file, and added it to the grails project in src/java

So for Sentry por example I added the SentryAppender.java to my.package.sentry so then in log4j I added:

  appenders {
    environments {
        // This block is set up to use the stock raven SentryAppender in
        // production. Sentry Appender runs into all kinds of
        // class loading weirdness when used in a forked grails environment
        production {
            appender new my.package.sentry.SentryAppender(
                name: 'sentry',
                dsn: 'REDACTED',                
                threshold: org.apache.log4j.Level.WARN
            )
        }

        // Uncomment this block if you need to test sentry
        // in a dev environment
        development {
            appender new my.package.sentry.SentryAppender(
                name: 'sentry',
                dsn: 'REDACTED',                
                threshold: org.apache.log4j.Level.WARN
            )
        }
    }    

  }

  root {
    warn 'stdout', 'sentry'
    error 'stdout', 'sentry'
    additivity = false
  }

in that way, it does not depend on an external dependency.

I guess that you could do something similar to the mail dependency and add the java files to the src folder.

I hope it helps!

Upvotes: 2

Burt Beckwith
Burt Beckwith

Reputation: 75671

That looks weird - are you combining the dependencies block and the log4j block here unintenionally, or are they in the same file in your app? The dependency should be in BuildConfig.groovy and the log4j block should be in Config.groovy. Also, it shouldn't be log4j { but rather log4j = {.

This is likely a timing issue. If Config.groovy is parsed before the Javamail dependency is resolved, it will fail. Try commenting out the parts that reference the Javamail classes and run grails clean and grails compile. That will resolve dependencies and add that jar to the classpath. Then you can uncomment that code and run grails compile again.

Upvotes: 1

Related Questions