Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Configuring Grails 3 for Log4j2

We would like to use Log4j2 as the log binding with grails 3.

From what I can figure out so far. We have many subordinate dependencies that use a variety of loggers, so we need to use the SLF4J API. Then, instead of letting grails / groovy / spring re-direct the SLF4J API to the Logback binding, we need to re-direct each to the Log4j2 binding.

Since grails 3 uses the Logback binding, I am planning to go through each dependency in the build.gradle, exclude the Logback binding, and include the Log4j2 binding. Will this work? Update: Yes

Do we also need to bridge the Log4j2 API to the SLF4j API? What dependency do we need for that? Update: See below.

Finally, I assume we need to ditch the grails 3 logback.groovy configuration and just put one of the log4j2 configs in src/main/resources. Update: Yes

I'll post updates as we figure this out, but I bet someone has done this before.

Update 2016-03-18:

This turned out to be very straight-forward. I did a './gradlew dependencies' on my grails 3 project to see which dependencies were pulling in the Logback binding/implementation (group: 'ch.qos.logback', module: 'logback-classic')

First, here's the default build.gradle generated via a 'grails create-app testit' command:

buildscript {
    ext {
        grailsVersion = project.grailsVersion
    }
    repositories {
        mavenLocal()
        maven { url "https://repo.grails.org/grails/core" }
    }
    dependencies {
        classpath "org.grails:grails-gradle-plugin:$grailsVersion"
        classpath "com.bertramlabs.plugins:asset-pipeline-gradle:2.5.0"
        classpath "org.grails.plugins:hibernate4:5.0.2"
    }
}

version "0.1"
group "testit"

apply plugin:"eclipse"
apply plugin:"idea"
apply plugin:"war"
apply plugin:"org.grails.grails-web"
apply plugin:"org.grails.grails-gsp"
apply plugin:"asset-pipeline"

ext {
    grailsVersion = project.grailsVersion
    gradleWrapperVersion = project.gradleWrapperVersion
}

repositories {
    mavenLocal()
    maven { url "https://repo.grails.org/grails/core" }
}

dependencyManagement {
    imports {
        mavenBom "org.grails:grails-bom:$grailsVersion"
    }
    applyMavenExclusions false
}

dependencies {
    compile "org.springframework.boot:spring-boot-starter-logging"
    compile "org.springframework.boot:spring-boot-autoconfigure"
    compile "org.grails:grails-core"
    compile "org.springframework.boot:spring-boot-starter-actuator"
    compile "org.springframework.boot:spring-boot-starter-tomcat"
    compile "org.grails:grails-dependencies"
    compile "org.grails:grails-web-boot"
    compile "org.grails.plugins:cache"
    compile "org.grails.plugins:scaffolding"
    compile "org.grails.plugins:hibernate4"
    compile "org.hibernate:hibernate-ehcache"
    console "org.grails:grails-console"
    profile "org.grails.profiles:web:3.1.4"
    runtime "org.grails.plugins:asset-pipeline"
    runtime "com.h2database:h2"
    testCompile "org.grails:grails-plugin-testing"
    testCompile "org.grails.plugins:geb"
    testRuntime "org.seleniumhq.selenium:selenium-htmlunit-driver:2.47.1"
    testRuntime "net.sourceforge.htmlunit:htmlunit:2.18"
}

task wrapper(type: Wrapper) {
    gradleVersion = gradleWrapperVersion
}

assets {
    minifyJs = true
    minifyCss = true
}

The dependency report showed that they were being pulled in by two dependencies:

    compile "org.springframework.boot:spring-boot-starter-logging"

and

    compile "org.springframework.boot:spring-boot-starter-actuator"

So, I only had to make a couple changes to the dependencies section of the build.gradle:

dependencies {
    // commented out the original way using Logback    
    //compile "org.springframework.boot:spring-boot-starter-logging"

    // added the new way using Log4j2, yes, spring makes it easy
    compile "org.springframework.boot:spring-boot-starter-log4j2"

    // changed spring-boot-autoconfigure so that it would not
    // pull in the logback binding/implementation
    compile ('org.springframework.boot:spring-boot-autoconfigure') {
       exclude group: 'ch.qos.logback', module: 'logback-classic'
    }

    // and finally, added the log4j2 binding/implementation
    compile "org.apache.logging.log4j:log4j-api:2.5"
    compile "org.apache.logging.log4j:log4j-core:2.5"

    // the rest is unchanged
    compile "org.grails:grails-core"
    compile "org.springframework.boot:spring-boot-starter-actuator"
    compile "org.springframework.boot:spring-boot-starter-tomcat"
    compile "org.grails:grails-dependencies"
    compile "org.grails:grails-web-boot"
    compile "org.grails.plugins:cache"
    compile "org.grails.plugins:scaffolding"
    compile "org.grails.plugins:hibernate4"
    compile "org.hibernate:hibernate-ehcache"
    console "org.grails:grails-console"
    profile "org.grails.profiles:web:3.1.4"
    runtime "org.grails.plugins:asset-pipeline"
    runtime "com.h2database:h2"
    testCompile "org.grails:grails-plugin-testing"
    testCompile "org.grails.plugins:geb"
    testRuntime "org.seleniumhq.selenium:selenium-htmlunit-driver:2.47.1"
    testRuntime "net.sourceforge.htmlunit:htmlunit:2.18"
}

In the src/main/resources, we added a log4j2.xml.

In the groovy code, we used:

import org.apache.logging.log4j.Logger
import org.apache.logging.log4j.LogManager
import org.apache.logging.log4j.ThreadContext

private static final Logger log = LogManager.getLogger(getClass())

log.info('Hello World')

We also put ThreadContext statements in the constructors of heavily used classes.

That was it. Now we're doing fast, async logging that doesn't lose any log messages upon config changes.

like image 231
fcnorman Avatar asked Mar 18 '16 02:03

fcnorman


People also ask

What version of Log4j does Grails use?

Log4j v2. 17.0 addresses CVE-2021-45105. It protects against infinite recursion in lookup evaluation.

Does grails use Log4j?

Grails uses its common configuration mechanism to configure the underlying Log4j log system: simply add a log4j setting to the file grails-app/conf/Config.

What is configuration status in log4j2?

Configuration: the root element of a log4j2 configuration file; the status attribute represents the level at which internal log4j events should be logged. Appenders: this element contains a list of appenders; in our example, an appender corresponding to the System console is defined.


1 Answers

Forgot to post something as an answer. Here's an answer you can vote for, but I put all the information about the solution in the comments above.

like image 94
fcnorman Avatar answered Nov 13 '22 18:11

fcnorman