JavaMelodyでintra-martシステムを監視する

## はじめに

[JavaMelody](https://github.com/javamelody/javamelody/wiki)を使用して、[intra-mart Accel Platform](http://www.intra-mart.jp/products/iap/)（以下iAP）システムのリソース使用状況を監視する方法について記載します。

アプリケーションサーバには、Resinを使用する前提です。

JavaMelodyは、Java EEアプリケーションにおける様々なリソースの使用状況を監視するためのツールです。同様のツールとして[New Relic](https://newrelic.com/)などがありますが、JavaMelodyはApache Licenseであり、データはローカルに格納されますので、業務システムの開発時にも気楽に使用することができると思います[^overhead]。

[^overhead]: JavaMelodyが統計を取得する処理にオーバーヘッドが多少は発生しますので、運用環境では使用しない方がよいと思います（[参考](https://github.com/javamelody/javamelody/wiki/Overhead)）。

## セットアップ

構築済みのiAP環境に、JavaMelodyを導入する方法を説明します。

参考: https://github.com/javamelody/javamelody/wiki/UserGuide#javamelody-setup

以下の説明では、コンテキストパスを「`imart`」とします。

### jarの配置

以下のGitHubのreleaseページから、`javamelody-*.zip`をダウンロードします。
https://github.com/javamelody/javamelody/releases

zipを展開して、中に含まれる`javamelody.jar`と`jrobin-*.jar`を、iAPの`webapps/imart/WEB-INF/lib`フォルダに配置します。

レポートをPDFで出力したい場合は、iTextのjarも配置します（iAPのモジュール構成によっては、既にiTextのjarが含まれているかもしれません）。
http://search.maven.org/remotecontent?filepath=com/lowagie/itext/2.1.7/itext-2.1.7.jar

### resin-web-pre.xmlの編集

iAPの`webapps/imart/WEB-INF/`配下に、`resin-web-pre.xml`というファイルを以下の内容で作成します（既存のものがある場合は追記）[^resin-web-pre]。

[^resin-web-pre]: `<filter-mapping>`は既存の設定よりも前に記述しないと正常に動作しない模様です。この理由により、`resin-web.xml`に設定を記述することはできません。

```resin-web-pre.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	metadata-complete="false" version="3.0"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">

  <filter>
    <filter-name>javamelody</filter-name>
    <filter-class>net.bull.javamelody.MonitoringFilter</filter-class>
    <async-supported>true</async-supported>
  </filter>

  <listener>
    <listener-class>net.bull.javamelody.SessionListener</listener-class>
  </listener>

  <filter-mapping>
    <filter-name>javamelody</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>REQUEST</dispatcher>
    <dispatcher>ASYNC</dispatcher>
  </filter-mapping>

</web-app>
```

基本的には、これだけで動作します。

### オプション設定

#### 静的コンテンツを除外

HTTP統計（Statistics http）から、js・css等の静的コンテンツファイルを除外する場合は、以下のように`MonitoringFilter`の初期パラメータ`url-exclude-pattern`に正規表現で設定します。

```resin-web-pre.xml
<filter>
  <filter-name>javamelody</filter-name>
  <filter-class>net.bull.javamelody.MonitoringFilter</filter-class>
  <async-supported>true</async-supported>
  <init-param>
    <param-name>url-exclude-pattern</param-name>
    <param-value>.+\.(js|css|png|ico|gif|jpg)$</param-value>
  </init-param>
</filter>
```

### 実行

Resinを(再)起動した後、ブラウザで次のURLを開きます。

http://hostname:port/imart/monitoring

![image.png](https://qiita-image-store.s3.amazonaws.com/0/27823/d7c2eef8-b074-9fd3-98b3-1a86e865a2cc.png)

## モニタリング画面

### グラフの上にあるリンク

| 項目 | 説明 |
|:-----|:----|
| Update | ページ全体を更新します（ブラウザリロードと同じ） |
| PDF | 現在の表示内容をPDFにしてダウンロードします（iTextのライブラリを追加していない場合は表示されません） |
| Online help | JavaMelodyのヘルプページが開かれます |
| Desktop | Java Web Startでモニタリング画面を開きます（事前に権限設定が必要） |
| Choice of period |  統計の表示期間を変更できます。使用開始直後は、Dayなどの短い期間にしないとグラフに何も表示されない場合があります。 |

### グラフ

JVM、Java EE管理リソース、OSリソースの使用量の平均/最大の推移がグラフで表示されます（クリックすると拡大表示）。

| グラフ名 | 説明 |
|:--------|:-----|
| Used memory | メモリ（Javaヒープ）の使用量 |
| % CPU | JavaプロセスのCPU使用率 |
| Http sessions | HTTPセッションの数 |
| Active threads | アクティブスレッドの数（または接続ユーザ数） |
| Active jdbc connections | アクティブJDBCコネクションの数（または同時リクエスト数） |
| Used jdbc connections | 使用されたJDBCコネクションの数（またはSQLトランザクションの数） |
| Http hits per minute | 1分あたりのHTTPリクエスト数 |
| Http mean times (ms) | HTTPリクエストの応答時間（ミリ秒） |
| % of http errors | HTTPエラー（レスポンスコードが4xx,5xx）の割合 |
| Sql hits per minute | 1分あたりのSQL発行数 |
| Sql mean times (ms) | SQLの平均処理時間（ミリ秒） |
| % of sql errors | SQLエラーの割合 |

以下のグラフは、[Other charts]をクリックすると表示されます。

| グラフ名 | 説明 |
|:--------|:-----|
| % Garbage Collector time | GCにかかったCPU時間の割合 |
| Thread count | JVMのスレッド数 |
| Loaded classes count | JVMにロードされたクラス数 |
| Used buffered memory | buffered memoryの使用量 |
| Used non heap memory | JVMの非ヒープメモリの使用量 |
| Used physical memory | OSの物理メモリの使用量 |
| Used swap space | OSのスワップスペースの使用量 |
| Mean age of http sessions (min) | HTTPセッションの平均存続時間（分） |
| Transactions per minute | 1分あたりのトランザクション数（正確には、開かれたJDBCコネクションの数） |
| Free disk space  | フリーディスクスペース |
| % System CPU | OS全体のCPU使用率 |

### Statistics http

HTTPリクエストの統計情報（リクエスト件数やレスポンスタイムなど）が表示されます。

* 「http global」の行は、全体の統計
* 「http warning」の行は、全体平均 + 標準偏差の1倍～2倍
* 「http severe」の行は、全体平均 + 標準偏差の2倍～

「Details」をクリックすると、リクエストパス毎の統計情報の一覧が表示されます。
（ここに限らず、一覧はヘッダをクリックするとその列でソートが行われますので、遅いリクエストなどを見つけることができます）

![statistics_http.png](https://qiita-image-store.s3.amazonaws.com/0/27823/3a98d20d-6d6e-3271-2bc3-378edd3b66fa.png)

また、「Request」列のリンクをクリックすると、当該のリクエスト処理において発行されたSQLの一覧が表示されます。

![statistics_http_detail.png](https://qiita-image-store.s3.amazonaws.com/0/27823/c7ae1202-139b-0e19-101b-fa3d8d4cce4e.png)

### Statistics sql

SQLの統計情報（発行数や処理時間）が表示されます。
global/warning/severeの意味は、Statistics httpと同様です。

「Details」をクリックすると、SQL毎の統計情報の一覧が表示されます。

![statistics_sql.png](https://qiita-image-store.s3.amazonaws.com/0/27823/fee69981-cbe0-cfac-3545-e2712608c526.png)

また、「Request」列のリンクをクリックすると、当該のSQLに関する時間推移のグラフが表示されます。
さらに、「Find usages」をクリックすると、そのSQLが発行されたHTTPリクエストを調べることができます。

![statistics_sql_find_usages.png](https://qiita-image-store.s3.amazonaws.com/0/27823/d0315c7f-ac04-517a-b70a-6a0c3e1774bd.png)

### Statistics jsp

jspだけではなく、実際はincludeやforwardでディスパッチされたリクエストの統計が表示されます。

### Statistics http system errors

エラー毎の統計が表示されます。
ここでいうエラーとは、サーブレットが例外をスローした場合や、400番台/500番台のレスポンスコードを返した場合です。

### Statistics system errors logs

warningレベルやerrorレベルで出力されたログが表示されます。

### Current request

現在実行中のリクエスト（レスポンスが返されていないもの）の一覧が表示されます。

![current_request.png](https://qiita-image-store.s3.amazonaws.com/0/27823/0dd263df-48fc-ce03-b81c-ec529f2e2a33.png)

「Thread」列にマウスカーソルを乗せると、スレッドのコールスタックが表示されます。
「Kill」列のアイコンをクリックすると、スレッドを強制終了させることができますが、データ不整合や異常動作が発生する可能性があります。

### System information

ここでは、JVMはOSの情報を参照したり、操作を行うことができます。

#### Execute the garbage collector

Full GCを実行します。

#### Generate a heap dump

ヒープダンプを取得します。
ファイルは、一時フォルダ（システムプロパティ`-Djava.io.tmpdir`）直下に出力されます。

#### View memory histogram

ヒープ上のオブジェクトの統計が表示されます。
初期表示では、Javaの基本クラスだけですが、「Details」をクリックすると他のクラスの統計も表示されます（多少時間はかかります）。

![memory_histogram.png](https://qiita-image-store.s3.amazonaws.com/0/27823/c43a138d-7028-f786-fb35-62d63eaf6d1f.png)

#### Invalidate http sessions

全てのHTTPセッションが破棄されます。

#### View http sessions

HTTPセッションの一覧が表示されます。
「Invalidate」列のアイコンをクリックすると、特定のセッションのみを破棄できます。

![http_sessions.png](https://qiita-image-store.s3.amazonaws.com/0/27823/72099787-ac75-9daf-87c4-55fa9763fbc7.png)

「Session id」列をクリックすると、そのセッションに格納されたSession attributesの一覧が表示されます（「Content」列は格納されたオブジェクトの`toString()`の値のようです）。

![http_session_attributes.png](https://qiita-image-store.s3.amazonaws.com/0/27823/1f500ad7-e259-4c3b-f5e7-df91ea2b6d0f.png)

#### View deployment descriptor

web.xmlの内容を参照できます。

#### MBeans

MBeansの内容を参照できます。
操作はできません。

#### View OS processes

OSのプロセス一覧が表示されます。

#### JNDI tree

登録されたJNDIを参照できます。

####  Opened jdbc connections

実行中のJDBCコネクションが表示されます。
コネクションプールに戻されたコネクションは表示されません。
マウスカーソルを乗せると、スレッドのコールスタックが表示されます。

#### Database

データベースの統計情報が表示されます。
データベースから提供される情報であるため、使用しているデータベースによって表示内容は異なると思われます。

### Threads

JVM上の全スレッドの一覧が表示されます。
「Thread」列にマウスカーソルを乗せると、スレッドのコールスタックが表示されます。
「Kill」列のアイコンをクリックすると、スレッドを強制停止することができますが、データ不整合や異常動作が発生する可能性があります。

![threads.png](https://qiita-image-store.s3.amazonaws.com/0/27823/dfe67ef0-7eb5-1d8b-bc46-8a1236e4d758.png)

一覧の下の「Dump threads as text」をクリックすると、ブラウザ上にスレッドダンプがテキストデータで表示されます。
（jstack等のフォーマットとは異なるため、[侍](http://samuraism.jp/samurai/ja/index.html)等の分析ツールにかけることはできません）

### Jobs

登録されたジョブネット（Quatz）の一覧が表示されます。
iAPでは、Mean time（平均処理時間）は表示されない模様です。

![jobs.png](https://qiita-image-store.s3.amazonaws.com/0/27823/82e92403-8864-7cbb-f179-196b3dea6ec1.png)

「Pause」「Resume」ボタンによって、ジョブ実行の停止や再開を行うことができるのですが、実行中のジョブスレッドが停止される訳ではなく、次回の実行が抑止されることになります。

### Statistics job

ジョブ毎の統計情報ですが、iAPでは取得されない模様です。

### Data caches

EhCacheの統計情報（キャッシュされたオブジェクト数）が表示されます。
「Clear」列をクリックすると、キャッシュをクリアすることができます。

EhCacheにおいて、キャッシュの統計情報を取得する設定にした場合には、ヒット率も表示されます。
iAPではこの設定がハードコーディングで無効になっていますので、有効にするには以下のようにソースに手を入れます。

**jp.co.intra_mart.system.cache.ehcache.EhcacheManagerProvider**

```EhcacheManagerProvider.java
    private net.sf.ehcache.config.CacheConfiguration cacheConfiguration(final DefaultCache defaultCache, final Cache cache) {

        // ...略

        // ここを追加
        cacheConfiguration.setStatistics(true);

        return cacheConfiguration;
    }
```

![data_caches.png](https://qiita-image-store.s3.amazonaws.com/0/27823/2603117f-4ffc-a70a-7c96-f6590cf64817.png)

「% of efficiency of memory cache (memory hits/hits)」と「% of efficiency of cache (hits/accesses)」の列は、EhCacheの統計を有効にしていない場合は表示されません。

## 統計データのリセット方法

一時フォルダ（システムプロパティ`-Djava.io.tmpdir`）に作られる`javamelody`というフォルダを削除して再起動するとすると、全てリセットされます。

Choice of periodを「All」にすると、各一覧の下に「Clear」というリンクが表示されますが、ここをクリックしても何も起こらない模様です。

---