Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ClassNotFoundException Using Log4j and Grails 2.4.4 #184

Closed
matthew-gerstman opened this issue Mar 9, 2016 · 15 comments
Closed

ClassNotFoundException Using Log4j and Grails 2.4.4 #184

matthew-gerstman opened this issue Mar 9, 2016 · 15 comments

Comments

@matthew-gerstman
Copy link

I'm trying to get raven up and running in Grails 2.4.4 with Log4j. I'm able to call vanilla Raven in my source, but whenever I try and instantiate a SentryAppender I get a ClassNotFoundException.

My buildconfig.groovy and source are here:
http://pastebin.com/MuVWUpf3

Relevant stacktrace:
http://pastebin.com/dtV3Cguv

I have tried both 7.0.0 and 7.0.1-SNAPSHOT and neither work. I've also tried including just raven-log4j and both raven-log4j and raven.

@bretthoerner
Copy link

Can you try with 6.0.0 (it has a different groupId)? I'm curious if this is something I botched in the rename.

http://search.maven.org/#artifactdetails|net.kencochrane.raven|raven-log4j|6.0.0|jar

@bretthoerner bretthoerner self-assigned this Mar 10, 2016
@matthew-gerstman
Copy link
Author

I tried with both 6.0.0 and 5.0.x. with no luck.

@bretthoerner
Copy link

Yeah, I've recreated the issue locally. It seems to be related to Grails + Tomcat, it looks like people have had issues with other Appenders. I'm trying to figure out a solution now, hmm.

@bretthoerner
Copy link

OK, the only way I've been able to get it work is by disabling Grails forking in BuildConfig.groovy:

grails.project.fork = [
    // configure settings for compilation JVM, note that if you alter the Groovy version forked compilation is required
    //  compile: [maxMemory: 256, minMemory: 64, debug: false, maxPerm: 256, daemon:true],

    // configure settings for the test-app JVM, uses the daemon by default
    test: false, // [maxMemory: 768, minMemory: 64, debug: false, maxPerm: 256, daemon:true],
    // configure settings for the run-app JVM
    run: false, // [maxMemory: 768, minMemory: 64, debug: false, maxPerm: 256, forkReserve:false],
    // configure settings for the run-war JVM
    war: false, // [maxMemory: 768, minMemory: 64, debug: false, maxPerm: 256, forkReserve:false],
    // configure settings for the Console UI JVM
    console: false // [maxMemory: 768, minMemory: 64, debug: false, maxPerm: 256]
]

This is some real class loading wonkiness. It works fine in Grails 3 FWIW (though the new default is logback, but I don't think that's related).

@mattgerstman Do you mind disabling forking and let me know if it works? I'm not sure on the full repercussions yet though...?

@matthew-gerstman
Copy link
Author

Hey @bretthoerner. Disabling forking did fix the ClassNotFoundException. Forking helps us load a bunch of environmental data and also allows grails to autocompile files while we're in dev mode. It definitely wouldn't be a permanent solution.

When I loaded the sentryAppender I started running into a whole series of issues actually getting it to log properly. I'm investigating if this is an issue with my config or grails integration with raven.

I may also look into using another logger or upgrading to grails 3 (we've discussed that separately). Most likely I'll end up writing a wrapper around Raven itself to play nicely with our codebase.

@bretthoerner
Copy link

Thanks for the update @mattgerstman, do you mind letting us know if you find anything else out?

@matthew-gerstman
Copy link
Author

@bretthoerner. I finally got a chance to spend some more time looking into this. I discovered we really only use forking for our development environment NOT in production. In prod we compile a grails war and run it under tomcat which seemed to resolve all the class loading wonkiness.

I had to clone the SentryAppender file and include it directly in our package to set up sentry in development. Once I got it working locally, I removed the local version and set up an environments block to only load SentryAppender in production. Here is my appenders block for posterity:

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 com.getsentry.raven.log4j.SentryAppender(
                name: 'sentryAppender',
                dsn: 'REDACTED',                
                threshold: org.apache.log4j.Level.WARN
            )
        }

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

@bretthoerner
Copy link

Thanks for the update. I'm surprised there's not a different dependency scope in Grails/Gradle we can use. For example I recently discovered that for Gretty you need to use the gretty scope (instead of compile) to make loggers available to the application server before the application even starts. I feel like something similar would prevent you from having to copy the class.

@andresarslanian
Copy link

andresarslanian commented Nov 9, 2016

Guys, some time has passed but I found a solution based in @mattgerstman answer that might be useful for someone else. At least, something better (for me) than disabling forking.

It has nothing to be with raven but with grails the problem.

At least in my case, what I did was add the maven dependency and then try to add the appender in log4j.
The thing is that grails first executes the piece of code for the log4j initialization and then compiles the maven dependencies.
Different to what @mattgerstman did, was going to the raven-log4j github repository https://github.com/getsentry/raven-java/tree/master/raven-log4j/src/main/java/com/getsentry/raven/log4j downloaded the latest SentryAppender.java and stored it in src/java/my/package/sentry and left it there always.

Then in Config.groovy did something similar to what was suggested:

  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
  }

and it's working in development and production... I guess I could also remove the environments since the behavior is the same always.

hope it helps!

@matthew-gerstman
Copy link
Author

@andresarslanian First off. Thanks for getting involved in this. Somehow seeing this issue come back up brightened my mood on this awful day.

To clarify your solution, you downloaded the sentryAppender and checked it in to source, is that correct?

@andresarslanian
Copy link

Hi @mattgerstman

Yes. In steps:

  1. Went to https://github.com/getsentry/raven-java/tree/master/raven-log4j/src/main/java/com/getsentry/raven/log4j and downloaded the latest SentryAppender.java

  2. Added the SentryAppender.java to src/java/my/package/sentry

  3. Modified the original package name of SentryAppender.java to be my.package.sentry

  4. Modified Config.groovy in the log4j section and 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
  }
  1. Everything is working in development and production!

Hope it helps!

@matthew-gerstman
Copy link
Author

That's effectively what we ended up doing. I also modified that source a bit to do some fun stuff with tagging. I submitted a PR back to master for it, but I never got around to doing it for the other appenders so we closed it.

@bretthoerner
Copy link

Thanks for the update, both of you. Should we still consider this open or is this firmly on the Grails side of things?

@matthew-gerstman
Copy link
Author

@bretthoerner I think you can close it. This is a grails ~2.4.x issue.

@bretthoerner
Copy link

Thanks, if it comes up any more I'll try to document this. For now we'll depend on Google. ;)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants