読者です 読者をやめる 読者になる 読者になる

ログ出力 "したい" 時と "したくない" 時を実装

log4jでログ出力してて、例えばコンソールアプリケーションを作ってる時に、
あるアプリではコンソール+ログファイル両方出力したいけど、
もう一方のアプリではコンソールには出さなくて、ログファイルにだけ出したい、ってときがある。

そしてその2つのアプリは同じロジックを呼ぶ、つまり呼ばれるロジックはログを出力する時としない時がある。
うーん、log4jの標準機能ではクラス単位での切替くらいしかできないよなー、ってことで、こんな感じにしたらできたのでご紹介。
# もっとCoolにできるなら教えてください。


clashm45/log4j_mute · GitHub

MyLoggerクラスを作って、

public class MyLogger {
  private Logger logger = null;
  private static final String NoConsole = "NoConsole";
  
  private MyLogger(Class<?> clazz){
    logger = Logger.getLogger(clazz.getName());
  }

  private MyLogger(String prefix, Class<?> clazz){
    logger = Logger.getLogger(prefix+"."+clazz.getName());
  }

  public static MyLogger getInstans(Class<?> clazz){
    return new MyLogger(clazz);
  }

  public static MyLogger getInstansNoConsole(Class<?> clazz){
    return new MyLogger(NoConsole, clazz);
  }

  public void info(String msg){
    logger.info(msg);
  }
~~~
}

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="stdout" class="org.apache.log4j.ConsoleAppender">
    <param name="Target" value="System.out" />
    <layout class="org.apache.log4j.PatternLayout">
      <param name="ConversionPattern" value="%d %5p %c - %m%n" />
    </layout>
  </appender>

  <appender name="file" class="org.apache.log4j.FileAppender">
    <param name="File" value="target/App.log" />
    <param name="Append" value="true"/>
    <layout class="org.apache.log4j.PatternLayout">
      <param name="ConversionPattern" value="%d %5p %c - %m%n" />
    </layout>
  </appender>

  <category name="log4j_mute">
    <priority value="info"/>
    <appender-ref ref="stdout"/>
    <appender-ref ref="file"/>
  </category>

  <category name="NoConsole">
    <priority value="info"/>
    <appender-ref ref="file"/>
  </category>

</log4j:configuration>

こんなロジッククラスを作る。
LogicA

public class LogicA {
  private static MyLogger logger = MyLogger.getInstans(LogicA.class);
  public static void process(){
    logger.info("処理A!!");
  }
}

LogicB

public class LogicB {
  private static MyLogger logger = MyLogger.getInstans(LogicB.class);
  public static void process(){
    logger.info("処理B!!");
  }

  public static void mute(){
    logger = MyLogger.getInstansNoConsole(LogicB.class);
  }
}

そしてロジックを利用するアプリケーションでこんな風にする。

public class App{
  public static void main( String[] args ) {
    LogicA.process();
    LogicB.process();
    LogicB.mute();
    LogicB.process();
  }
}

処理結果:コンソール

$ java -cp "src/main/resources;target/log4j_mute-1.0-SNAPSHOT-jar-with-dependencies.jar" log4j_mute.App
2012-12-18 14:39:29,461 INFO log4j_mute.LogicA - 処理A!!
2012-12-18 14:39:29,462 INFO log4j_mute.LogicB - 処理B!!

処理結果:ログファイル

$ cat target/App.log
2012-12-18 14:39:29,461 INFO log4j_mute.LogicA - 処理A!!
2012-12-18 14:39:29,462 INFO log4j_mute.LogicB - 処理B!!
2012-12-18 14:39:29,463 INFO NoConsole.log4j_mute.LogicB - 処理B!!

カテゴリを使ってログ出力方法を変えてるわけです。