ぺーぺーSEのブログ

備忘録・メモ用サイト。

JMXによる動的なlog4j設定の変更

log4jの設定をアプリケーションを停止せずにJMXによって変更する。
ポイントはlog4jの「org.apache.log4j.jmx」パッケージ。
独自実装しなくてもlog4jで予め用意されている。

例のごとくMavenベースでサンプルプロジェクトを作る。

mvn archetype:generate -DgroupId=study
                       -DartifactId=log4JMX
                       -DarchetypeArtifactId=maven-archetype-quickstart
                       -Dversion=1.0.0

pom.xmlを下記のように作成。

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>study</groupId>
  <artifactId>Spring25HelloWorldJerseyJSON</artifactId>
  <packaging>war</packaging>
  <version>1.0.0</version>
  <name>Spring25HelloWorldJerseyJSON Maven Webapp</name>
  <url>http://maven.apache.org</url>

  <properties>
    <log4j.version>1.2.17</log4j.version>
    <commons-logging.version>1.1.1</commons-logging.version>
  </properties>

  <dependencies>
    <dependency>
      <groupId>log4j</groupId>
      <artifactId>log4j</artifactId>
      <version>${log4j.version}</version>
    </dependency>
    <dependency>
      <groupId>commons-logging</groupId>
      <artifactId>commons-logging</artifactId>
      <version>${commons-logging.version}</version>
    </dependency>
  </dependencies>

  <build>
    <finalName>log4JMX</finalName>
  </build>
</project>

src/main/resourcesディレクトリを作成し、「commons-logging.properties」と「log4j.properties」を作成する。
■commons-logging.properties

org.apache.commons.logging.Log=org.apache.commons.logging.impl.Log4JLogger

log4j.properties

log4j.rootCategory=DEBUG,CONSOLE

log4j.category.category1=DEBUG,CONSOLE
log4j.category.category1.category2=DEBUG,CONSOLE

log4j.additivity.category1=false
log4j.additivity.category1.category2=false

log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.Target=System.out
log4j.appender.CONSOLE.layout=org.apache.log4j.TTCCLayout

次のメイン一発クラスを作成して実行する。
■Log4JMXMain

package jp.sample.jmx.log4j.main;

import java.lang.management.ManagementFactory;

import javax.management.JMException;
import javax.management.MBeanServer;
import javax.management.ObjectName;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.apache.log4j.jmx.HierarchyDynamicMBean;
import org.apache.log4j.spi.LoggerRepository;

public class Log4JMXMain{

  static Log log = LogFactory.getLog(Log4JMXMain.class);
  static Log log1 = LogFactory.getLog("category1");
  static Log log2 = LogFactory.getLog("category1.category2");
  static int roopTimes = 1;

  public static void main(String[] args) throws Exception {
    MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();

    try {
      HierarchyDynamicMBean hdm = new HierarchyDynamicMBean();
      mBeanServer.registerMBean(hdm,
          new ObjectName("HierarchyDynamicMBean:name=hogehoge"));
      hdm.addLoggerMBean(Logger.getRootLogger().getName());
      LoggerRepository r = LogManager.getLoggerRepository();
      java.util.Enumeration<Logger> loggers = (java.util.Enumeration<Logger>)r.getCurrentLoggers();
      while(loggers.hasMoreElements()){
        hdm.addLoggerMBean(loggers.nextElement().getName());
      }
    } catch (JMException e) {
    }

    while (true) {
      if (log.isDebugEnabled())
        log.debug(roopTimes + " times DEBUG Message.");
      if (log.isInfoEnabled())
        log.info(roopTimes + " times INFO Message.\n\n");

      if (log1.isDebugEnabled())
        log1.debug(roopTimes + " times DEBUG Message.");
      if (log1.isInfoEnabled())
        log1.info(roopTimes + " times INFO Message.\n\n");

      if (log2.isDebugEnabled())
        log2.debug(roopTimes + " times DEBUG Message.");
      if (log2.isInfoEnabled())
        log2.info(roopTimes + " times INFO Message.\n\n");

      roopTimes++;
      Thread.sleep(5000);
    }

  }
}

5秒に1回ログを出力するアプリ。
log4j.propertiesに記述されているカテゴリーを全てLoggerDynamicMBeanとして登録する。
本アプリを起動する際は下記のJVM引数を付与する。

-Dcom.sun.management.jmxremote=true
-Dcom.sun.management.jmxremote.port=8118
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.authenticate=false

jconsoleでアプリへアクセスし、各設定を変更することができる。

jconsole localhost:8118


参考:
http://www.jroller.com/ray/entry/managing_log4j_logging_levels_for
http://www.02.246.ne.jp/~torutk/javahow2/log4j.html
http://blogs.wankuma.com/kazuki/archive/2009/06/04/174157.aspx
http://www63.tok2.com/home2/jd4/YourFirstMBean1.html