Grailsのロギング実装をLog4jからLogbackに変更する

Grailsではロギング実装としてLog4jが採用されていますが、
Log4jはもう古いし後継のLogbackを使いたくなったりしますよね?

Logback Pluginを使うことでロギング実装をLog4jからLogbackに変更できます。

プラグインのページの説明通り設定すれば簡単にできるだろうと思っていたのですが、
ハマりポイントがあったのでそれも含めて書いていきます。

プラグインのインストール

Logback Pluginはバイナリープラグインと呼ばれる種類のもので、
BuildConfig.groovypluginsブロックではなくdependenciesブロックに依存関係を書きます。

また、既存のLog4jを無効にするためにinherits('global')ブロックにも設定を追加します。

プラグインの説明のページに書いてあるのはここまでで、
これに加えてrepositoriesブロックにGrails Pluginのリポジトリを追加する必要があります。

grailsCentral()からダウンロードできそうに見えますがダメです。
本件はissueとして登録されています。

よって、Logback PluginをインストールするためにはBuildConfig.groovyに以下の設定を追加すればよいです。

...

grails.project.dependency.resolution = {
    // inherit Grails' default dependencies
    inherits("global") {
        ...
        excludes 'grails-plugin-log4j', 'log4j'
    }
    ...

    repositories {
        ...
        mavenRepo 'http://repo.grails.org/grails/repo/'
    }

    dependencies {
        ...

        compile 'org.grails.plugins:logback:0.3.1'
    }
    ...
}

設定を追加後、grails refresh-dependenciesを実行してプラグインのインストールを完了しましょう。

加えてgrails cleanを実行しておきましょう。
これはAST変換によって追加されたlogフィールドをLog4jのものからLogbackのものに置き換えるためです。
この時点でDEBUGレベルのログが大量に標準出力に出力されるようになったはずです。

17:59:00.374 [main] DEBUG o.c.g.g.i.s.PathMatchingResourcePatternResolver - Looking for matching resources in jar file [file:/Users/hideki/.grails/ivy-cache/org.grails.plugins/logback/jars/logback-0.3.1.jar]
17:59:00.379 [main] DEBUG o.c.g.g.i.s.PathMatchingResourcePatternResolver - Resolved location pattern [classpath*:META-INF/scripts/*.groovy] to resources [org.codehaus.groovy.grails.io.support.UrlResource@63beff72]
17:59:01.041 [main] DEBUG o.c.g.g.i.s.PathMatchingResourcePatternResolver - Looking for matching resources in directory tree [/Users/hideki/.grails/2.2.2/projects/grails-sample-logback/plugins/webxml-1.4.1/grails-app]
...

これは意図しない動作なので、Logbackの設定の中で併せて修正しましょう。

Logbackの設定

既存のLog4jの設定から置き換えるだけであれば、
Config.groovylog4jパラメーター名を単にlogbackに変えるだけです。

...
// logback configuration
logback = {  // ここをlog4jからlogbackに変えるだけ
    // 以下は既存のまま
    ...
    error  'org.codehaus.groovy.grails.web.servlet',        // controllers
           'org.codehaus.groovy.grails.web.pages',          // GSP
           'org.codehaus.groovy.grails.web.sitemesh',       // layouts
           'org.codehaus.groovy.grails.web.mapping.filter', // URL mapping
           'org.codehaus.groovy.grails.web.mapping',        // URL mapping
           'org.codehaus.groovy.grails.commons',            // core / classloading
           'org.codehaus.groovy.grails.plugins',            // plugins
           'org.codehaus.groovy.grails.orm.hibernate',      // hibernate integration
           'org.springframework',
           'org.hibernate',
           'net.sf.ehcache.hibernate'
}

この辺の設定をLogbackらしくするのは今回は置いておいて、
DEBUGレベルのログが出まくるのを直したいと思います。

DEBUGレベルのログの出力を抑制する

これはビルド情報のログで、上記のConfig.groovy内での設定で抑制しようとしてもできません。
ということでプラグインが介入する前のデフォルトの設定を変更することで対応します。

JIRAのチケットが上がっており、
XMLでLogbackの設定を書いておき、それをLogbackが読みこむように設定する方法が提示されています。

せっかくLogbackなのでXMLではなくGroovyで設定を書きましょう。
grails-app/conf/logback-build.groovyを作成します。(名前と場所は何でも良いです)

import static ch.qos.logback.classic.Level.*
import ch.qos.logback.classic.encoder.PatternLayoutEncoder
import ch.qos.logback.core.ConsoleAppender

appender("STDOUT", ConsoleAppender) {
    encoder(PatternLayoutEncoder) {
        pattern = "%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n"
    }
}
root(WARN, ["STDOUT"])

ポイントはroot(WARN, ["STDOUT"])でデフォルトのログレベルをWARNにしている所です。
出力フォーマットは適宜patternを変更してください。

これをBuildConfig.groovyでLogbackが読みこむように設定します。

...

System.setProperty('logback.configurationFile', "${basedir}/grails-app/conf/logback-build.groovy")

これで大量のDEBUGレベルのログが抑制されます。