title: Configuring Grails 3 for Log4j2
body: <p>We would like to use Log4j2 as the log binding with grails 3.</p>
  
  <p>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.</p>
  
  <p>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</p>
  
  <p>Do we also need to bridge the Log4j2 API to the SLF4j API?  What dependency do we need for that?  Update:  See below.</p>
  
  <p>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</p>
  
  <p>I'll post updates as we figure this out, but I bet someone has done this before.</p>
  
  <p>Update 2016-03-18:</p>
  
  <p>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')</p>
  
  <p>First, here's the default build.gradle generated via a 'grails create-app testit' command:</p>
  
  <pre><code>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
  }
  </code></pre>
  
  <p>The dependency report showed that they were being pulled in by two dependencies:</p>
  
  <pre><code>    compile "org.springframework.boot:spring-boot-starter-logging"
  </code></pre>
  
  <p>and </p>
  
  <pre><code>    compile "org.springframework.boot:spring-boot-starter-actuator"
  </code></pre>
  
  <p>So, I only had to make a couple changes to the dependencies section of the build.gradle:</p>
  
  <pre><code>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"
  }
  </code></pre>
  
  <p>In the src/main/resources, we added a log4j2.xml.</p>
  
  <p>In the groovy code, we used:</p>
  
  <pre><code>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')
  </code></pre>
  
  <p>We also put ThreadContext statements in the constructors of heavily used classes.</p>
  
  <p>That was it.  Now we're doing fast, async logging that doesn't lose any log messages upon config changes.</p>