# 第10章 JMXコンフィギュレーター

名前のとおり、`JMXConfigurator`を使うとJMX経由でlogbackを設定することができます。つまり、デフォルトの設定ファイルで設定されたlogbackを、指定したパスやURLに配置した設定ファイルの内容で再設定したり、ロガーの一覧を取得したり、ロガーのレベルを変更することができるのです。

### JMXコンフィギュレーターを使用する

サーバーを実行しているJVMがJDK1.6以降なら、コマンドラインから`jconsole`コマンドを実行するだけで、実行中のサーバーのMBeanServerにアクセスすることができます。古いJVMで実行している場合はサーバーでJMXを有効化するのセクションを読んでおいてください。

次のように設定ファイルに1行追加するだけで`JMXConfigurator`が有効になります。

    <configuration>
      <jmxConfigurator />

      <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
        <layout class="ch.qos.logback.classic.PatternLayout">
          <Pattern>%date [%thread] %-5level %logger{25} - %msg%n</Pattern>
        </layout>
      </appender>

      <root level="debug">
        <appender-ref ref="console" />
      </root>
    </configuration>

jconsoleでサーバーに接続すれば、MBeans タブに表示される "ch.qos.logback.classic.jmx.Configurator" フォルダの下にいろいろなコマンドがぶら下がっているのが確認できます。スクリーンショットを見てください。

### `jconsole`で`JMXConfigurator`を表示している様子

次のような操作を実行することができます。

- デフォルトの設定ファイルを使用してlogbackを再設定します。
- URLに配置された設定ファイルを使用して再設定します。
- ファイルパスに配置された設定ファイルを使用して再設定します。
- 指定したロガーのレベルを設定します。nullを設定するには文字列"null"を指定します。
- 指定したロガーのレベルを取得します。nullになることがあります。
- 指定したロガーの有効レベルを取得します。

`JMXConfigurator`はAttributesとして存在しているロガーの一覧と、ステータスの一覧を公開します。

ステータスの一覧は、logbackの内部状態を診断するのに役立ちます。

### メモリリークを避ける

アプリケーションがWebサーバーやアプリケーションサーバにデプロイされているときは、`JMXConfigurator`のインスタンスをJVMのMBeanサーバーに登録すると、システムクラスローダーの参照をアプリケーションが持つようになってしまいます。これはアプリケーションが停止したり再デプロイされたときにJMXConfiguratorがガベージコレクションされてしまうのを防ぐためですが、そのせいで深刻なメモリリークが生じてしまいます。

したがって、スタンドアローンなJavaアプリケーションではないときは、必ず`JMXConfigurator`のインスタンスの登録をJVMのMBeanサーバーから解除しなければなりません。適切な`LoggerContetext`の`reset()`メソッドを呼べば、すべてのJMXConfiguratorのインスタンスは自動的に解除されるはずです。ロガーコンテキストを初期化するなら、`javax.servlet.ServletContextListener`の`contextDestroyed()`メソッドがちょうど良い場所です。サンプルコードを見てみましょう。

    import javax.servlet.ServletContextEvent;
    import javax.servlet.ServletContextListener;

    import org.slf4j.LoggerFactory;
    import ch.qos.logback.classic.LoggerContext;

    public class MyContextListener implements ServletContextListener {

      public void contextDestroyed(ServletContextEvent sce) {
        LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
        lc.stop();
      }

      public void contextInitialized(ServletContextEvent sce) {
      }
    }

## 複数のWebアプリケーションで`JMXConfigurator`を使用する

複数のアプリケーションを同じサーバーにデプロイしている、コンテキストセレクタを上書きせずデフォルトのまま使っている、それぞれのアプリケーションのWEB-INF/libフォルダにlogback-*.jarとslf4j-api.jarを置いている、これらが全て当てはまるなら、それぞれのアプリケーションの`JMXConfigurator`のインスタンスは同じ名前（"ch.qos.logback.classic:Name=default,Type=ch.qos.logback.classic.jmx.JMXConfigurator"）で登録されてしまうでしょう。言い換えると、何もしなければそれぞれのアプリケーションのロガーコンテキストに関連付けられた`JMXConfigurator`のインスタンスは衝突してしまうのです。

衝突を避けるには、単にアプリケーションのロガーコンテキストに名前を付けるだけでよいのです。そうすれば、`JMXConfigurator`には自動的にその名前が設定されます。

たとえば、それぞれ"コアラ"と"コウモリ"という名前のアプリケーションをデプロイしているものとします。そして、コアラのlogback.xmlには次のような設定がされているとしましょう。

    <configuration>
      <contextName>Koala</contextName>
      <jmxConfigurator/>
      ...
    <configuration>

また、コウモリのlogback.xmlには次のように設定がされていることにします。

    <configuration>
      <contextName>Wombat</contextName>x
      <jmxConfigurator/>
      ...
    <configuration>

そうすると、jconsoleのMBeanタブには、次のように二つの独立した`JMXConfigurator`のインスタンスが表示されるはずです。

MBeanサーバーに登録されるJMXConfiguratorの名前は、`jmxConfigurator要素`の"objectName"属性で指定することができます。

### JMXを有効化する

JDK1.6以降のJVMでサーバーを実行している場合はデフォルトでJMXが有効になっています。

JDK1.6以前の古いJVMを使っている場合は、サーバーのJMX関連のドキュメントを確認することをおすすめします。たとえばTomcatやJettyにはドキュメントがあります。それはさておき、このドキュメントではTomcatとJettyの設定方法を簡単に説明していきます。

#### JettyでJMXを有効にする（JDK 1.5およびJDK 1.6で動作確認済み）

以降の設定はJDK1.5とJDK1.6で動作確認しています。JDK1.6以降のJVMでは、デフォルトでJMXが有効になっています。以降の設定をしてもよいですが、特に何も変わりません。JDK1.5のJVMで実行するJettyでJMXを有効にするには、設定ファイル$JETTY_HOME/etc/jetty.xmlにいくつか設定を追加する必要があります。追加するのは次の設定です。

    <Call id="MBeanServer" class="java.lang.management.ManagementFactory"
          name="getPlatformMBeanServer"/>

    <Get id="Container" name="container">
      <Call name="addEventListener">
        <Arg>
          <New class="org.mortbay.management.MBeanContainer">
            <Arg><Ref id="MBeanServer"/></Arg>
            <Call name="start" />
          </New>
        </Arg>
      </Call>
    </Get>

Jettyの公開するMBeanに`jconsole`でアクセスしたいときは、Jettyを実行するJVMにシステムプロパティ"com.sun.management.jmxremote"を指定しておかなければなりません。

スタンドアローン版のJettyなら次のように実行します。

java -Dcom.sun.management.jmxremote -jar start.jar [config files]

MavenのプラグインからJettyを実行する場合は、システムプロパティ"com.sun.management.jmxremote"をシェル変数`MAVEN_OPTS`で指定しなければなりません。

MAVEN_OPTS="-Dcom.sun.management.jmxremote" mvn jetty:run

そうすれば、`jconsole`でJettyの公開するMBeanとして`JMXConfigurator`にアクセスすることができます。

接続したら、前のスクリーンショットのように`JMXConfigurator`にアクセスできるはずです。

#### JettyにMX4Jを入れる（JDK 1.5およびJDK 1.6で動作確認済み）

MX4JのHTTPインターフェイスを経由して`JMXConfigurator`にアクセスしたいときは、前に説明した設定ファイルに管理ポート番号の設定を追加します。MX4Jはすでにダウンロード済みであることにします。

    <Call id="MBeanServer"
        class="java.lang.management.ManagementFactory"
        name="getPlatformMBeanServer"/>

    <Get id="Container" name="container">
      <Call name="addEventListener">
        <Arg>
          <New class="org.mortbay.management.MBeanContainer">
            <Arg><Ref id="MBeanServer"/></Arg>
            <Set name="managementPort">8082</Set>
            <Call name="start" />
          </New>
        </Arg>
      </Call>
    </Get>

なお、mx4j-tools.jarはJettyのクラスパス上に配置しておいてください。

MavenのプラグインからJettyを実行する場合は、依存関係にmx4j-toolsを追加してください。

    <plugin>
      <groupId>org.mortbay.jetty</groupId>
      <artifactId>maven-jetty-plugin</artifactId>
      <configuration>
        <jettyConfig>path/to/jetty.xml</jettyConfig>
        ...
      </configuration>
      <dependencies>
        <dependency>
          <groupId>mx4j</groupId>
          <artifactId>mx4j-tools</artifactId>
          <version>3.0.1</version>
        </dependency>
      </dependencies>
    </plugin>

この設定でJettyを起動すると、ブラウザで次のURLから`JMXConfigurator`にアクセスできるようになります。アクセスした後は "ch.qos.logback.classic" を探してください。

http://localhost:8082/

MX4Jにアクセスしているところのスクリーンショットです。

#### Tomcat用のJMXの設定（JDK 1.5およびJDK 1.6で動作確認済み）

JDK1.6以降のJVMを使用しているならJMXはデフォルトで有効になっているので以降の設定をする必要はありません。JDK1.5の場合は$TOMCAT_HOME/bin/catalina.sh（Windowsの場合はcatalina.bat）の適切な場所に次の設定を追加する必要があります。

CATALINA_OPTS="-Dcom.sun.management.jmxremote"

そうすれば、`jconsole`を使ってTomcatの公開するMBeanとして`JMXConfigurator`にアクセスできるようになります。

接続したら、前のスクリーンショットのように`JMXConfigurator`にアクセスできるはずです。

#### TomcatにMX4Jを入れる（JDK 1.5およびJDK 1.6で動作確認済み）

MX4JのWebインターフェイスを使ってJMXのコンポーネントにアクセスしたくなるかもしれません。そうするために必要な設定方法を説明します。

MX4Jはすでにダウンロードしてあることにしましょう。mx4j-tools.jarを$TOMCAT_HOME/binフォルダーにおいてください。それから、$TOMCAT_HOME/bin/catalina.sh（Windowsの場合はcatalina.bat）の適切な場所に次の設定を追加します。

<!-- at the beginning of the file --> CATALINA_OPTS="-Dcom.sun.management.jmxremote" <!-- in the "Add on extra jar files to CLASSPATH" section --> CLASSPATH="$CLASSPATH":"$CATALINA_HOME"/bin/mx4j-tools.jar

最後に、$TOMCAT_HOME/conf/server.xmlで新しい`Connector要素`を宣言します。

    <Connector port="0"
      handler.list="mx"
      mx.enabled="true"
      mx.httpHost="localhost"
      mx.httpPort="8082"
      protocol="AJP/1.3" />

Tomcatを起動したら、ブラウザで次のURLからJMXConfiguratorにアクセスできるようになります。アクセスした後は "ch.qos.logback.classic" を探してください。

http://localhost:8082/

MX4Jにアクセスしているところのスクリーンショットです。