log4jを設定する(1.2)

Javaで標準的なApache Log4j(1.2)でロギングする。 ただし、最新は2.x系で1.2とは大きく異なるらしい、なので少ししたら2.x系へ移行する。

開発,試験ではデバッグに用い、運用ではコード修正・データ修正・再実行など緊急対応への情報提供が必要になる。 そのため開発,試験時には DEBUG レベルで全て出力して、運用では INFO レベルで出力するのを標準とする。 ただし本番の運用中には、出力レベルをコンポーネント単位で DEBUG に引き上げたり出来ると嬉しい。 (JVMのデバッグツールを調べたら、もしかしたらアプリケーション側でログレベルを変更出来るようにしなくても良いかも知れない)

設定ファイルの配置を忘れても安全に稼働して欲しい。

方針

  • 外部の設定ファイルがなくても動く様にjarに最低限の設定を含める
  • confディレクトリ内で log4j.{var}.properties があれば優先する
  • var には3つの可能性があり、前から overwrite,{env}, common の順番で優先されて採用される
    • ログ設定の一時的な変更用途として log4j.overwrite.propertiesconf ディレクトリに配置できるようにした
    • アプリケーションのフラグとして環境情報を与える(-e, --env)(詳細には触れない)

実装

下のような配置にした。

1
2
3
4
5
6
7
8
9
.
├── conf
│   ├── log4j.common.properties
│   └── log4j.dev.properties
├── src
│   ├── main
│   │   ├── kotlin
│   │   └── resources
│   │       └── log4j.properties

build.gradle

1
2
3
dependencies {
    compile group: "log4j", name: "log4j", version: "1.2.17"
}

設定ファイル

ファイルの中身はだいたい、こんな感じ。 appender を作って rootLogger に登録している。出力先ごとにログレベルに制約を加えるために Threshold を設定している。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
### direct log messages to stdout ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.Threshold=INFO
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %5p %c{1} - %m%n

### direct messages to file logs/sample-app.log ###
log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File=log/sample-app.log
log4j.appender.file.Append=true
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d %5p %c{1} - %m%n

log4j.throwableRenderer=org.apache.log4j.EnhancedThrowableRenderer
log4j.rootLogger=DEBUG, stdout, file
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
### direct log messages to stdout ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.Threshold=INFO
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %5p %c{1} - %m%n

### direct messages to file logs/sample-app.log ###
log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File=log/dataprocessor-preprocess.log
log4j.appender.file.Append=true
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d %5p %c{1} - %m%n

log4j.throwableRenderer=org.apache.log4j.EnhancedThrowableRenderer
log4j.rootLogger=DEBUG, stdout, file

本番環境ではSentryなどログ収集サービスを利用する。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
### direct log messages to stdout ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.Threshold=INFO
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %5p %c{1} - %m%n

### direct messages to file logs/data.log ###
log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File=log/sample-app.log
log4j.appender.file.Append=true
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d %5p %c{1} - %m%n

log4j.appender.sentry=io.sentry.log4j.SentryAppender
log4j.appender.sentry.threshold=ERROR

log4j.throwableRenderer=org.apache.log4j.EnhancedThrowableRenderer
log4j.rootLogger=DEBUG, stdout, file, sentry

log4jの初期化コード

みたいなコードを書いた。下のコードは、コピペ後に記事内で編集してるので動かないと思われ。。。

PropertyConfigurator() は外部から設定を反映するために利用している。 実際に設定を反映させる先は LogManager.getLoggerRepository() で取得している。

 0
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
package me.masu_mi.sample

import org.apache.log4j.LogManager
import org.apache.log4j.PropertyConfigurator


class SampleApp() {
    private fun initLogging(confRoot: String) {
        for (file in listOf(
            getPropertiesFile(confRoot, "log4j.overwrite"),
            getPropertiesFile(confRoot, "log4j.${opt.getEnvironment()}"),
            getPropertiesFile(confRoot, "log4j.common"))) {
            if (file.exists()) {
                PropertyConfigurator().doConfigure(file.path, LogManager.getLoggerRepository())
                return
            }
        }
    }
    private fun getPropertiesFile(confRoot: String, name: String): File {
        return File(confRoot, "$name.properties")
    }
}

出力内容

%d %5p %c{4} - %m%n ととても基本的な事を出力している。 古いからか検索能力が低いからか、公式を見つけられなかった。 なので、レイアウトを参考にする。

この後のこと

log4j-2.xに乗り換える。log4jでMDC,NDCを使ってメタ情報も記録する。JMXを使って conf ディレクトリの変更を検知して設定変更を行う。

comments powered by Disqus