Posted at

logbackでレベルごとに出力するファイルを分ける

More than 3 years have passed since last update.


やりたいこと

運用をしていると、エラーを調査するために膨大なログの中からgrepすることが多々あります。

特に統計情報や、運用のためにInfoレベルでログに書き込んでいる情報がある場合、ログの出力数が多くなり、エラー情報をgrepするのに時間がかかることが多いです。

そんな場合には、レベルごとに出力するファイルを分けることで、grepする時間を少なくすることができます。

また分け方や運用方法によっては、監視用スクリプトの設定を容易にすることもできると思います


やりかた

フィルターのLevelFilterを使用することで可能となります。


logger.xml

<filter class="ch.qos.logback.classic.filter.LevelFilter">

<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>



設定してみる

PlayFrameworkを使ったアプリケーションで、Trace以外のレベルごとにファイルを分けた設定例です。


logger.xml

<configuration>

<conversionRule conversionWord="coloredLevel" converterClass="play.api.Logger$ColoredLevel" />

<appender name="FILE_ERROR" class="ch.qos.logback.core.FileAppender">
<file>${application.home}/logs/error.log</file>
<encoder>
<pattern>%date{yyyy-MM-dd'T'HH:mm:ssZ,GMT} [%level] %logger %replace(%message){'\n', '\\n'} %replace(%xException){'\n', '\\n'}%n</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>

<appender name="FILE_INFO" class="ch.qos.logback.core.FileAppender">
<file>${application.home}/logs/info.log</file>
<encoder>
<pattern>%date{yyyy-MM-dd'T'HH:mm:ssZ,GMT} [%level] %logger %replace(%message){'\n', '\\n'} %replace(%xException){'\n', '\\n'}%n</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>

<appender name="FILE_WARN" class="ch.qos.logback.core.FileAppender">
<file>${application.home}/logs/warn.log</file>
<encoder>
<pattern>%date{yyyy-MM-dd'T'HH:mm:ssZ,GMT} [%level] %logger %replace(%message){'\n', '\\n'} %replace(%xException){'\n', '\\n'}%n</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>WARN</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>

<appender name="FILE_DEBUG" class="ch.qos.logback.core.FileAppender">
<file>${application.home}/logs/debug.log</file>
<encoder>
<pattern>%date{yyyy-MM-dd'T'HH:mm:ssZ,GMT} [%level] %logger %message %xException%n</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>DEBUG</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>

<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%coloredLevel %logger{15} - %message%n%xException{5}</pattern>
</encoder>
</appender>

<logger name="play" level="INFO" />
<logger name="application" level="DEBUG" />

<!-- Off these ones as they are annoying, and anyway we manage configuration ourself -->
<logger name="com.avaje.ebean.config.PropertyMapLoader" level="OFF" />
<logger name="com.avaje.ebeaninternal.server.core.XmlConfigLoader" level="OFF" />
<logger name="com.avaje.ebeaninternal.server.lib.BackgroundThread" level="OFF" />
<logger name="com.gargoylesoftware.htmlunit.javascript" level="OFF" />

<root level="ERROR">
<appender-ref ref="STDOUT" />
<appender-ref ref="FILE_ERROR" />
<appender-ref ref="FILE_WARN" />
<appender-ref ref="FILE_INFO" />
<appender-ref ref="FILE_DEBUG" />
</root>

</configuration>



動かしてみる


実行

Logger.debug("debug")

Logger.info("info")
Logger.warn("warn")
Logger.error("error")


ファイルへの出力内容

tail -n 1 logs/{debug,info,warn,error}.log

==> logs/debug.log <==
2015-01-17T15:48:23+0000 [DEBUG] application debug

==> logs/info.log <==
2015-01-17T15:48:23+0000 [INFO] application info

==> logs/warn.log <==
2015-01-17T15:48:23+0000 [WARN] application warn

==> logs/error.log <==
2015-01-17T15:48:23+0000 [ERROR] application error



おわり

EvaluatorFilterを使って、書込内容ごとにログ出力先を分けることも可能ですが、それはまた別ライブラリー紹介と一緒に投稿したいと思います。