CLOVER🍀

That was when it all began.

JBoss LoggingとJBoss Logging Toolsでログ出力

けっこう前から気になっていたロギングライブラリ、JBoss Loggingを使ってみました。

JBoss ASやWildFlyなど、JBoss関連のプロダクトで使われているロギングライブラリです。

まあ、興味を持ったのはInfinispanでも使われているからですが。

JBoss Loggingって?

JBoss Logging自体は、Commmons LoggingやSLF4Jのような、ログの実装に対するインターフェースを提供するプロダクトです。

JBoss Logging
https://github.com/jboss-logging/jboss-logging

単体では、以下の優先順位でクラスパス上からログ実装を探していき、最初に見つかったものを採用します。

この探索をしているコードは、このあたりになります。

3.1.4.GAの場合
https://github.com/jboss-logging/jboss-logging/blob/3.1.4.GA/src/main/java/org/jboss/logging/LoggerProviders.java#L37

master branch
https://github.com/jboss-logging/jboss-logging/blob/master/src/main/java/org/jboss/logging/LoggerProviders.java#L38

JBoss Log Managerは、java.util.loggingを拡張した実装で、JBoss ASやWildFlyなどで使用されているようです。これを使用するには、クラスパスに存在する以外に、java.util.logging.LogManager#getLogManagerが、JBoss Log Managerのクラスとなっている必要があります(システムプロパティで、java.util.logging.managerでorg.jboss.logmanager.LogManagerを指定)。

が、設定をあんまり追いきれなかったので、今回はパス。

まあ、今回はJBoss Logging単体で使ってみましょう。

依存関係の定義

まずは、JBoss Loggingの依存関係を定義します。

    <dependency>
      <groupId>org.jboss.logging</groupId>
      <artifactId>jboss-logging</artifactId>
      <!-- <version>3.1.4.GA</version> -->  <!-- 安定版 -->
      <version>3.2.0.Beta1</version>  <!-- Log4j2を使いたい場合、こちら -->
    </dependency>

最新安定版は3.1.4.GAですが、Log4j 2を裏で使いたい場合は、3.2系になります。

サンプルコード

サンプルコードは、こんな感じで用意しました。
src/main/java/org/littlewings/jbosslogging/JBossLoggingExample.java

package org.littlewings.jbosslogging;

import org.jboss.logging.Logger;

public class JBossLoggingExample {
    public static void main(String... args) {
        Logger logger = Logger.getLogger(JBossLoggingExample.class);

        System.out.printf("Logger Class[%s]%n", logger.getClass());

        System.out.println("========== Trace start ==========");

        logger.trace("こんにちは、世界 at Trace");
        logger.trace("こんにちは、世界 at Trace", new Exception());
        logger.tracev("こんにちは、{0} {1} at Trace", "世界", "!!");
        logger.tracef("こんにちは、%s %s at Trace", "世界", "!!");

        System.out.println("========== Trace end ==========");


        System.out.println("========== Debug start ==========");

        logger.debug("こんにちは、世界 at Debug");
        logger.debug("こんにちは、世界 at Debug", new Exception());
        logger.debugv("こんにちは、{0} {1} at Debug", "世界", "!!");
        logger.debugf("こんにちは、%s %s at Debug", "世界", "!!");

        System.out.println("========== Debug end ==========");


        System.out.println("========== Info start ==========");

        logger.info("こんにちは、世界 at Info");
        logger.info("こんにちは、世界 at Info", new Exception());
        logger.infov("こんにちは、{0} {1} at Info", "世界", "!!");
        logger.infof("こんにちは、%s %s at Info", "世界", "!!");

        System.out.println("========== Info end ==========");


        System.out.println("========== Warn start ==========");

        logger.warn("こんにちは、世界 at Warn");
        logger.warn("こんにちは、世界 at Warn", new Exception());
        logger.warnv("こんにちは、{0} {1} at Warn", "世界", "!!");
        logger.warnf("こんにちは、%s %s at Warn", "世界", "!!");

        System.out.println("========== Error end ==========");


        System.out.println("========== Error start ==========");

        logger.error("こんにちは、世界 at Error");
        logger.error("こんにちは、世界 at Error", new Exception());
        logger.errorv("こんにちは、{0} {1} at Error", "世界", "!!");
        logger.errorf("こんにちは、%s %s at Error", "世界", "!!");

        System.out.println("========== Error end ==========");


        System.out.println("========== Fatal start ==========");

        logger.fatal("こんにちは、世界 at Fatal");
        logger.fatal("こんにちは、世界 at Fatal", new Exception());
        logger.fatalv("こんにちは、{0} {1} at Fatal", "世界", "!!");
        logger.fatalf("こんにちは、%s %s at Fatal", "世界", "!!");

        System.out.println("========== Fatal end ==========");
    }
}

では、簡単に説明を。

まずは、import文。単純に使うのなら、これだけでよさそうです。

immort org.jboss.logging.Logger;

Loggerの取得は、ClassクラスまたはLoggerの名前をStringで渡して行います。

        Logger logger = Logger.getLogger(JBossLoggingExample.class);

今回は、Classクラスを使用しました。

使えるログレベルは、

  • TRACE
  • DEBUG
  • INFO
  • WARN
  • ERROR
  • FATAL

となります。Log4jと一緒ですねー。

あとは、ログレベルに合わせてメソッドを呼び出します。こんな感じで。

        logger.info("こんにちは、世界 at Info");
        logger.info("こんにちは、世界 at Info", new Exception());
        logger.infov("こんにちは、{0} {1} at Info", "世界", "!!");
        logger.infof("こんにちは、%s %s at Info", "世界", "!!");

infoのようなメソッドは、メッセージとしてObjectを取り、その他Throwableを渡せたりもできます。
infovのような「v」が付くメソッドは、java.text.MessageFormatで解析可能な書式文字列とパラメータを渡すことができます。例外も渡せます。
infovにような「f」が付くメソッドは、String#formatで解析可能な書式文字列を渡すことができます。

実は、「v」が付かない方もMessageFormatを使うことができるみたいですが、FQCNを渡さないものは非推奨になっているようなので、ここでは置いておきます。

java.util.loggingをログ実装として使用する

このまま依存関係を何も追加せず起動すると、java.util.loggingを使用してログ出力を行います。

とりあえず設定ファイルを用意して。
src/main/resources/javalogging.properties

handlers=java.util.logging.ConsoleHandler
.level=FINEST

java.util.logging.ConsoleHandler.level=FINEST
java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter
java.util.logging.SimpleFormatter.format=[%1$tc] %4$s - %5$s %6$s %n

実行。

$ mvn compile && mvn exec:java -Dexec.mainClass=org.littlewings.jbosslogging.JBossLoggingExample -Djava.util.logging.config.file=src/main/resources/javalogging.properties

利用されるJBoss Loggingのクラスは、JDKLoggerが選択されます。

Logger Class[class org.jboss.logging.JDKLogger]

INFOレベルのものだけ抜き出すと、こんな感じで出力されます。

========== Info start ==========
[日 6 08 02:06:47 JST 2014] INFO - こんにちは、世界 at Info  
[日 6 08 02:06:47 JST 2014] INFO - こんにちは、世界 at Info 
java.lang.Exception
	at org.littlewings.jbosslogging.JBossLoggingExample.main(JBossLoggingExample.java:34)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:483)
	at org.codehaus.mojo.exec.ExecJavaMojo$1.run(ExecJavaMojo.java:293)
	at java.lang.Thread.run(Thread.java:745)
 
[日 6 08 02:06:47 JST 2014] INFO - こんにちは、世界 !! at Info  
[日 6 08 02:06:47 JST 2014] INFO - こんにちは、世界 !! at Info  
========== Info end ==========

Log4j 2をログ実装として使用する

続いて、Log4j 2。これを使うためには、JBoss Loggingは3.2系である必要があります。

依存関係に、以下を追加。

    <dependency>
      <groupId>org.apache.logging.log4j</groupId>
      <artifactId>log4j-core</artifactId>
      <version>2.0-rc1</version>
    </dependency>

設定ファイル。
src/main/resources/log4j2.xml

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
  <Appenders>
    <Console name="Console" target="SYSTEM_OUT">
      <PatternLayout pattern="%d{yyy/MM/dd HH:mm:ss.SSS} %-5level - %msg%n"/>
    </Console>
  </Appenders>

  <Loggers>
    <Root level="trace">
      <AppenderRef ref="Console"/>
    </Root>
  </Loggers>
</Configuration>

実行。

$ mvn compile && mvn exec:java -Dexec.mainClass=org.littlewings.jbosslogging.JBossLoggingExample

*今度は、設定ファイルの指定は不要なので

選択されたLogger。

Logger Class[class org.jboss.logging.Log4j2Logger]

出力例。

========== Info start ==========
2014/06/08 02:09:46.944 INFO  - こんにちは、世界 at Info
2014/06/08 02:09:46.944 INFO  - こんにちは、世界 at Info
java.lang.Exception
	at org.littlewings.jbosslogging.JBossLoggingExample.main(JBossLoggingExample.java:34) [classes/:?]
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_05]
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_05]
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_05]
	at java.lang.reflect.Method.invoke(Method.java:483) ~[?:1.8.0_05]
	at org.codehaus.mojo.exec.ExecJavaMojo$1.run(ExecJavaMojo.java:293) [exec-maven-plugin-1.3.jar:?]
	at java.lang.Thread.run(Thread.java:745) [?:1.8.0_05]
2014/06/08 02:09:46.948 INFO  - こんにちは、世界 !! at Info
2014/06/08 02:09:46.948 INFO  - こんにちは、世界 !! at Info
========== Info end ==========

スタックトレースに、どこからクラスがロードされているか、出力されるんですね…。

Log4jをログ実装として使用する

Log4jを使う場合。

先ほどのLog4j 2の依存関係定義を外して、Log4jを追加します。

    <dependency>
      <groupId>log4j</groupId>
      <artifactId>log4j</artifactId>
      <version>1.2.17</version>
    </dependency>

設定。
src/main/resources/log4j.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/" >
  <appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender">
    <param name="target" value="System.out" /> 
    <layout class="org.apache.log4j.PatternLayout">
      <param name="conversionPattern" value="[%d{yyyy/MM/dd HH:mm:ss,SSS}] %-5p - %m%n" />
    </layout>
  </appender>

  <root>
    <priority value="trace" />
    <appender-ref ref="CONSOLE" />
  </root>
</log4j:configuration>

選択されたLogger。

Logger Class[class org.jboss.logging.Log4jLogger]

結果。

========== Info start ==========
[2014/06/08 02:12:35,222] INFO  - こんにちは、世界 at Info
[2014/06/08 02:12:35,222] INFO  - こんにちは、世界 at Info
java.lang.Exception
	at org.littlewings.jbosslogging.JBossLoggingExample.main(JBossLoggingExample.java:34)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:483)
	at org.codehaus.mojo.exec.ExecJavaMojo$1.run(ExecJavaMojo.java:293)
	at java.lang.Thread.run(Thread.java:745)
[2014/06/08 02:12:35,223] INFO  - こんにちは、世界 !! at Info
[2014/06/08 02:12:35,223] INFO  - こんにちは、世界 !! at Info
========== Info end ==========

SLF4J&Logbackをログ実装として使用する

最後は、SLF4JとLogbackです。これらは、JBoss Loggingで使う場合は、合わせて使用します。

    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-api</artifactId>
      <version>1.7.7</version>
    </dependency>
    <dependency>
      <groupId>ch.qos.logback</groupId>
      <artifactId>logback-core</artifactId>
      <version>1.1.2</version>
    </dependency>
    <dependency>
      <groupId>ch.qos.logback</groupId>
      <artifactId>logback-classic</artifactId>
      <version>1.1.2</version>
    </dependency>

設定。
src/main/resources/logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>%d{yyyy/MM/dd HH:mm:ss.SSS} %-5level - %msg%n</pattern>
    </encoder>
  </appender>

  <root level="trace">
    <appender-ref ref="STDOUT" />
  </root>
</configuration>

選択されたLogger。

Logger Class[class org.jboss.logging.Slf4jLocationAwareLogger]

結果。

========== Info start ==========
2014/06/08 02:15:27.523 INFO  - こんにちは、世界 at Info
2014/06/08 02:15:27.525 INFO  - こんにちは、世界 at Info
java.lang.Exception: null
	at org.littlewings.jbosslogging.JBossLoggingExample.main(JBossLoggingExample.java:34) ~[classes/:na]
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_05]
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_05]
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_05]
	at java.lang.reflect.Method.invoke(Method.java:483) ~[na:1.8.0_05]
	at org.codehaus.mojo.exec.ExecJavaMojo$1.run(ExecJavaMojo.java:293) ~[na:na]
	at java.lang.Thread.run(Thread.java:745) ~[na:1.8.0_05]
2014/06/08 02:15:27.526 INFO  - こんにちは、世界 !! at Info
2014/06/08 02:15:27.526 INFO  - こんにちは、世界 !! at Info
========== Info end ==========

Logbackも、スタックトレースでどこからクラスがロードされたか出力されるんですね。

何気に、SLF4JとLogback、初めて使ってます…。

ところで、SLF4JにFATALがないため、JBoss LoggingでFATALを使用すると、裏のSLF4J&LogbackにはERRORとして出力されてしまいます。

========== Fatal start ==========
2014/06/08 02:15:27.541 ERROR - こんにちは、世界 at Fatal
2014/06/08 02:15:27.548 ERROR - こんにちは、世界 at Fatal
java.lang.Exception: null
	at org.littlewings.jbosslogging.JBossLoggingExample.main(JBossLoggingExample.java:64) ~[classes/:na]
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_05]
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_05]
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_05]
	at java.lang.reflect.Method.invoke(Method.java:483) ~[na:1.8.0_05]
	at org.codehaus.mojo.exec.ExecJavaMojo$1.run(ExecJavaMojo.java:293) ~[na:na]
	at java.lang.Thread.run(Thread.java:745) ~[na:1.8.0_05]
2014/06/08 02:15:27.549 ERROR - こんにちは、世界 !! at Fatal
2014/06/08 02:15:27.549 ERROR - こんにちは、世界 !! at Fatal
========== Fatal end ==========

まあ、ないものはないですからね…。

ここまでで、JBoss Loggingの触り的な感じで。

JBoss Logging Toolsを使用する

話は変わって、今度はJBoss Logging Toolsを使用してみます。

JBoss Logging Annotation Processor
https://github.com/jboss-logging/jboss-logging-tools

JBoss Logging Toolsは、アノテーションを使用してタイプセーフなログ出力を行うことができるライブラリです。

参考になるものとしては、こちらだそうで。

https://github.com/jboss-developer/jboss-eap-quickstarts/tree/6.3.x/logging-tools

では、使ってみましょう。

Mavenの依存関係に、JBoss Logging Toolsを追加します。

    <dependency>
      <groupId>org.jboss.logging</groupId>
      <artifactId>jboss-logging-processor</artifactId>
      <version>1.2.0.Final</version>
      <scope>provided</scope>
    </dependency>

Scopeは、providedで大丈夫です。

そして、アノテーションを付与したインターフェースを作成します。
src/main/java/org/littlewings/jbosslogging/Log.java

package org.littlewings.jbosslogging;

import org.jboss.logging.BasicLogger;
import org.jboss.logging.Logger.Level;
import org.jboss.logging.annotations.Cause;
import org.jboss.logging.annotations.LogMessage;
import org.jboss.logging.annotations.Message;
import org.jboss.logging.annotations.MessageLogger;

@MessageLogger(projectCode = "")
public interface Log { // extends BasicLogger {  // BasicLoggerインターフェースを実装していれば、普通のLoggerとしても使えそう…
    @LogMessage(level = Level.INFO)  // Default
    @Message(value = "こんにちは、世界")
    void helloWorldLog();

    @LogMessage(level = Level.ERROR)
    @Message(value = "例外が発生しました")
    void exceptionLog(@Cause Exception e);

    @LogMessage(level = Level.WARN)
    @Message(value = "引数に誤りがあります。指定値=[%s]")
    void argsExceptionLog(String value, @Cause IllegalArgumentException e);

    @LogMessage(level = Level.INFO)
    @Message(value = "メッセージ=[%s], サイズ=[%d]")
    void argsLog1(String word, int size);

    @LogMessage(level = Level.INFO)
    @Message(value = "サイズ=[%2$d], メッセージ=[%1$s]")
    void argsLog2(String word, int size);

    @LogMessage(level = Level.INFO)
    @Message(value = "メッセージ=[{0}], サイズ=[{1}]、MessageFormat版", format = Message.Format.MESSAGE_FORMAT)
    void argsLog3(String word, int size);
}

インターフェースには@MessageLoggerアノテーションを付与し、メソッドには@LogMessageおよび@Messageアノテーションを付与します。

@LogMessageアノテーションでは主にログレベルを、@Messageでは書式文字列とフォーマットを指定します。デフォルトでは、String#formatです。

ここで@Messageに指定した書式文字列内に、宣言したメソッドの引数を使用することができるため、タイプセーフにログ出力を行うことができます。その他、国際化などあるようですが、今回はパス…。

例外を受け取る場合は、@Causeアノテーションを付与します。

    @LogMessage(level = Level.ERROR)
    @Message(value = "例外が発生しました")
    void exceptionLog(@Cause Exception e);

    @LogMessage(level = Level.WARN)
    @Message(value = "引数に誤りがあります。指定値=[%s]")
    void argsExceptionLog(String value, @Cause IllegalArgumentException e);

用意するインターフェースは、特に何か別のインターフェースを実装する必要はないみたいですが、org.jboss.logging.BasicLoggerインターフェースを実装しておくと、通常のLoggerとしても使えそうな感じです。

利用側は、こんな感じになります。

        System.out.println("========== JBoss Logging Processor start ==========");

        Log log = Logger.getMessageLogger(Log.class, JBossLoggingExample.class.getName());
        log.helloWorldLog();
        log.exceptionLog(new Exception("エラー"));
        log.argsExceptionLog("bad value", new IllegalArgumentException("エラー"));
        log.argsLog1("JBoss Logging", 10);
        log.argsLog2("JBoss Logging", 10);
        log.argsLog3("JBoss Logging", 10);

        System.out.println("========== JBoss Logging Processor end ==========");

先ほどとは違い、Logger#getMessageLoggerでLoggerを取得します。コンパイル時にJBoss Logging Toolsがクラスを生成するため、メソッドの実装をしていませんが、このまま呼び出すことができます。

実行結果。
*ログ実装は、java.util.loggingです

========== JBoss Logging Processor start ==========
[日 6 08 02:34:20 JST 2014] INFO - こんにちは、世界  
[日 6 08 02:34:20 JST 2014] ERROR - 例外が発生しました 
java.lang.Exception: エラー
	at org.littlewings.jbosslogging.JBossLoggingExample.main(JBossLoggingExample.java:75)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:483)
	at org.codehaus.mojo.exec.ExecJavaMojo$1.run(ExecJavaMojo.java:293)
	at java.lang.Thread.run(Thread.java:745)
 
[日 6 08 02:34:20 JST 2014] WARN - 引数に誤りがあります。指定値=[bad value] 
java.lang.IllegalArgumentException: エラー
	at org.littlewings.jbosslogging.JBossLoggingExample.main(JBossLoggingExample.java:76)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:483)
	at org.codehaus.mojo.exec.ExecJavaMojo$1.run(ExecJavaMojo.java:293)
	at java.lang.Thread.run(Thread.java:745)
 
[日 6 08 02:34:20 JST 2014] INFO - メッセージ=[JBoss Logging], サイズ=[10]  
[日 6 08 02:34:20 JST 2014] INFO - サイズ=[10], メッセージ=[JBoss Logging]  
[日 6 08 02:34:20 JST 2014] INFO - メッセージ=[JBoss Logging], サイズ=[10]、MessageFormat版  
========== JBoss Logging Processor end ==========

ちゃんと出力されていますね。

また、@MessageLoggerのprojectCodeに接頭辞を

@MessageLogger(projectCode = "JBL")

@Messageのidに数字を指定するとログ出力のメッセージにID付与を行うことができます。

    @LogMessage(level = Level.INFO)  // Default
    @Message(value = "こんにちは、世界", id = 1)
    void helloWorldLog();

こんな感じに定義して

@MessageLogger(projectCode = "JBL")
public interface Log { // extends BasicLogger {  // BasicLoggerインターフェースを実装していれば、普通のLoggerとしても使えそう…
    @LogMessage(level = Level.INFO)  // Default
    @Message(value = "こんにちは、世界", id = 1)
    void helloWorldLog();

    @LogMessage(level = Level.ERROR)
    @Message(value = "例外が発生しました", id = 2)
    void exceptionLog(@Cause Exception e);

    @LogMessage(level = Level.WARN)
    @Message(value = "引数に誤りがあります。指定値=[%s]", id = 3)
    void argsExceptionLog(String value, @Cause IllegalArgumentException e);

    @LogMessage(level = Level.INFO)
    @Message(value = "メッセージ=[%s], サイズ=[%d]", id = 4)
    void argsLog1(String word, int size);

    @LogMessage(level = Level.INFO)
    @Message(value = "サイズ=[%2$d], メッセージ=[%1$s]", id = 5)
    void argsLog2(String word, int size);

    @LogMessage(level = Level.INFO)
    @Message(value = "メッセージ=[{0}], サイズ=[{1}]、MessageFormat版", format = Message.Format.MESSAGE_FORMAT, id = 6)
    void argsLog3(String word, int size);
}

実行。

========== JBoss Logging Processor start ==========
[日 6 08 02:35:27 JST 2014] INFO - JBL000001: こんにちは、世界  
[日 6 08 02:35:27 JST 2014] ERROR - JBL000002: 例外が発生しました 
java.lang.Exception: エラー
	at org.littlewings.jbosslogging.JBossLoggingExample.main(JBossLoggingExample.java:75)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:483)
	at org.codehaus.mojo.exec.ExecJavaMojo$1.run(ExecJavaMojo.java:293)
	at java.lang.Thread.run(Thread.java:745)
 
[日 6 08 02:35:27 JST 2014] WARN - JBL000003: 引数に誤りがあります。指定値=[bad value] 
java.lang.IllegalArgumentException: エラー
	at org.littlewings.jbosslogging.JBossLoggingExample.main(JBossLoggingExample.java:76)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:483)
	at org.codehaus.mojo.exec.ExecJavaMojo$1.run(ExecJavaMojo.java:293)
	at java.lang.Thread.run(Thread.java:745)
 
[日 6 08 02:35:27 JST 2014] INFO - JBL000004: メッセージ=[JBoss Logging], サイズ=[10]  
[日 6 08 02:35:27 JST 2014] INFO - JBL000005: サイズ=[10], メッセージ=[JBoss Logging]  
[日 6 08 02:35:27 JST 2014] INFO - JBL000006: メッセージ=[JBoss Logging], サイズ=[10]、MessageFormat版  
========== JBoss Logging Processor end ==========

こんな感じで、IDが追加されましたね。

[日 6 08 02:35:27 JST 2014] INFO - JBL000001: こんにちは、世界

ロギングライブラリ、なにがいいんでしょうと思うのですが、JBoss Loggingもいいなぁと思う次第です。