nekop's blog

OpenShift / JBoss / WildFly / Infinispanの中の人 http://twitter.com/nekop

JBoss AS7のロギング事情

JBoss Advent Calendar 2012の3日目のエントリです。

ログというのはディスクなどのハードウェアリソースを使うものなので、基本的にデータベースコネクションやスレッド数などと同じように、ミドルウェアリソースに位置づけられ、アプリケーションサーバで一括管理できるようになっています。

と言いたいところですが、現実的にはLog4j, commons-logging, JUL(java.util.logging), SLF4J, Logbackなどログライブラリは乱立しており、各アプリでは異なるログライブラリが利用され、ログ出力設定もバラバラになされていて実際には一元管理するのはすごく大変でカオスな状態です。

JBoss ASは6までLog4jをログ実装として利用していましたが、AS7ではJBoss LogManagerというJULをベースとした実装に変更されました。これに伴い、どのメジャーなログインタフェースを利用してもJBoss LogManagerに出力されるようになったので、AS7からはモジュール化の恩恵もあり、キレイに一元管理できるようになりました。めでたし。

実際にどのようになっているか確かめてみましょう。(ひどいコードですが)とりあえず以下のようなJSPを作ってwarにしてデプロイします。

<p><%= java.util.logging.Logger.getLogger("foo") %></p>
<p><%= java.util.logging.Logger.getLogger("foo").getClass() %></p>
<p><%= java.util.logging.Logger.getLogger("foo").getClass().getClassLoader() %></p>

<p><%= org.apache.log4j.Logger.getLogger("foo") %></p>
<p><%= org.apache.log4j.Logger.getLogger("foo").getClass() %></p>
<p><%= org.apache.log4j.Logger.getLogger("foo").getClass().getClassLoader() %></p>

<p><%= org.slf4j.LoggerFactory.getLogger("foo") %></p>
<p><%= org.slf4j.LoggerFactory.getLogger("foo").getClass() %></p>
<p><%= org.slf4j.LoggerFactory.getLogger("foo").getClass().getClassLoader() %></p>

<p><%= org.apache.commons.logging.LogFactory.getLog("foo") %></p>
<p><%= org.apache.commons.logging.LogFactory.getLog("foo").getClass() %></p>
<p><%= org.apache.commons.logging.LogFactory.getLog("foo").getClass().getClassLoader() %></p>

結果はこうなります。特にロギングライブラリをwarに入れてないのに全て自動的に利用可能になっています。逆に、ロギングライブラリをwarとかに入れてもさっくり無視されます(どうしても、という場合はごちゃごちゃ設定すればできますけど一元管理を破壊します)。

Logger 'foo' in context org.jboss.logmanager.LogContext@47cbe5dc
class org.jboss.logmanager.Logger
ModuleClassLoader for Module "org.jboss.logmanager:main" from local module loader @2b20bf2c (roots: /home/nekop/eap600/modules)
org.apache.log4j.Logger@782be176
class org.apache.log4j.Logger
ModuleClassLoader for Module "org.jboss.log4j.logmanager:main" from local module loader @2b20bf2c (roots: /home/nekop/eap600/modules)
org.slf4j.impl.Slf4jLogger(foo)
class org.slf4j.impl.Slf4jLogger
ModuleClassLoader for Module "org.slf4j.impl:main" from local module loader @2b20bf2c (roots: /home/nekop/eap600/modules)
org.apache.commons.logging.impl.SLF4JLocationAwareLog@253be03d
class org.apache.commons.logging.impl.SLF4JLocationAwareLog
ModuleClassLoader for Module "org.slf4j.jcl-over-slf4j:main" from local module loader @2b20bf2c (roots: /home/nekop/eap600/modules)

JULはJBoss LogManagerの実装クラスが返却されています。Log4jlog4j-jboss-logmanager、SLF4Jはslf4j-jboss-logmanagerにそれぞれ経由されてJBoss LogManagerに。Commons LoggingはSLF4J添付されてるブリッジでSLF4Jにリダイレクトされるので、SLF4Jと同じパスを辿ります。LogbackはログインタフェースとしてSLF4Jが使われ、直接使われることは基本的にないのでここには出てきません。

こうしてAS7ではログインタフェースへの出力は全てJBoss LogManagerに集約され、ログ出力の制御が一元化できるようになっています。

ちなみにJBoss AS7の内部ではログインタフェースにjboss-loggingが利用されています。