Elastic APMでWildflyで稼働するアプリケーションのパフォーマンスを監視する

# はじめに

Elastic APMを使用して、Wildflyで稼働するアプリケーションのパフォーマンスを監視する環境を構築してみます。


# 環境

使用した環境は以下のとおり。

- CentOS 7.5
- Elasticsearch 7.8
- Kibana 7.8
- APM Server 7.8
- APM Java Agent 1.18.0.RC1
- Filebeat 7.8
- Wildfly 20.0.1.Final

Elasticsearch/Kibana/Elastic APMは、「[ElasticStack 7.8 環境構築](https://qiita.com/mkyz08/items/d4eb9f20efbd9dc77547)」で構築した環境を利用しています。


# WildflyにAPM Agentを設定する。

アプリケーションのパフォーマンスに関する情報を取得するAPM AgentをWildflyに設定します。

まずはJava用のAPM Agentを以下からダウンロードします。

- https://search.maven.org/search?q=g:co.elastic.apm%20AND%20a:elastic-apm-agent

今回ダウンロードしたのは「elastic-apm-agent-1.18.0.RC1.jar」になります。
ダウンロードしたモジュールはWildflyが起動するサーバの適当な場所に格納します。

次にWildflyに対してAPM Agentの設定を行います。設定方法は以下の公式サイトを参考にして実施します。

- https://www.elastic.co/guide/en/apm/agent/java/current/setup-javaagent.html#setup-jboss-wildfly

Wildflyの設定ファイル（standalone.conf）に以下の設定を追加します。各変数の値については環境やアプリケーションに合わせて適切に設定する必要があります。

```
# vi /opt/wildfly-20.0.1.Final/bin/standalone.conf

export JAVA_OPTS="$JAVA_OPTS -javaagent:/opt/elastic-apm-agent-1.18.0.RC1.jar"
export JAVA_OPTS="$JAVA_OPTS -Delastic.apm.service_name=my-cool-service"
export JAVA_OPTS="$JAVA_OPTS -Delastic.apm.application_packages=org.example,org.another.example"
export JAVA_OPTS="$JAVA_OPTS -Delastic.apm.server_urls=http://localhost:8200"
```

設定が終わったらWildflyを起動するだけで完了です。


# Kibana APM UIでパフォーマンスに関する情報を確認する

Kibana APM UIでパフォーマンスに関する情報を確認してみます。
Kibanaの左側のメニューから「APM」を選択し、サービスを指定すると以下のように分散トレーシングが表示できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179607/6b54aa3a-2e2c-23b4-4a5b-0b659a86d8e3.png)

この分散トレーシングのトレース情報とログを関連付けることもできます。
つぎはこの関連付けの設定を実施します。


# Elasticsearch用のログフォーマットでログを出力する

Elasticsearchに取り込むためのJSONのログフォーマットでログを出力するようにWildflyの設定を変更します。

以下の公式サイトを参考に実施します。

- https://github.com/elastic/ecs-logging-java/blob/master/jboss-logmanager-ecs-formatter/README.md

まず、アプリケーションのpom.xmlに以下の内容を追加します。
これはJBoss Log Manager用のECS（Elastic Common Schema）形式のログを出力するためのFomatterです。

```
		<dependency>
			<groupId>co.elastic.logging</groupId>
			<artifactId>jboss-logmanager-ecs-formatter</artifactId>
			<version>0.5.0</version>
		</dependency>
```

これにより"jboss-logmanager-ecs-formatter-0.5.0.jar"と"ecs-logging-core-0.5.0.jar"がダウンロードされます。この2ファイルはWildflyに登録するので、アプリケーション側ではなくても動きます。そのため、ダウンロードしたらpom.xmlからは削除しても構いません。

次にWildflyの設定を変更します。
公式サイトの手順ではjboss-cli.shを使用して変更していたのですが、今回はstandalone.xmlを直接変更しています。
手順のとおりに実施するなら以下のようなコマンドになります。この場合、Logstashへ直接ログを送信することになるのですが、一旦ファイル出力し、Filebeatで送信する方式にしたかったので実行していません。

```
# ./jboss-cli.sh --connect --controller=192.168.10.126:9990 -c 'module add --name=co.elastic.logging.jboss-logmanager-ecs-formatter --resources=/opt/jboss-logmanager-ecs-formatter-0.5.0.jar:/opt/ecs-logging-core-0.5.0.jar --dependencies=org.jboss.logmanager'
# ./jboss-cli.sh --connect --controller=192.168.10.126:9990 -c '/subsystem=logging/custom-formatter=ECS:add(module=co.elastic.logging.jboss-logmanager-ecs-formatter, class=co.elastic.logging.jboss.logmanager.EcsFormatter, properties={serviceName=my-app}),/subsystem=logging/console-handler=CONSOLE:write-attribute(name=named-formatter,value=ECS)'
```

関係するモジュールを以下に格納します。場所は適当です。

```
/opt/jboss-logmanager-ecs-formatter-0.5.0.jar
/opt/ecs-logging-core-0.5.0.jar
```

以下の設定ファイルのログに関する部分を、ECSフォーマットで別のログファイル(server_json.log)へ出力するように修正します。

- /opt/wildfly-20.0.1.Final/standalone/configuration/standalone.xml

```
# vi /opt/wildfly-20.0.1.Final/standalone/configuration/standalone.xml

        <subsystem xmlns="urn:jboss:domain:logging:8.0">
            <periodic-rotating-file-handler name="logstash-handler" autoflush="true">
                <formatter>
                    <named-formatter name="ECS"/>
                </formatter>
                <file relative-to="jboss.server.log.dir" path="server_json.log"/>
                <suffix value=".yyyy-MM-dd"/>
                <append value="true"/>
            </periodic-rotating-file-handler>
            <root-logger>
                <level name="INFO"/>
                <handlers>
                    <handler name="CONSOLE"/>
                    <handler name="FILE"/>
                    <handler name="logstash-handler"/>
                </handlers>
            </root-logger>
            <formatter name="ECS">
                <custom-formatter module="co.elastic.logging.jboss-logmanager-ecs-formatter" class="co.elastic.logging.jboss.logmanager.EcsFormatter">
                    <properties/>
                </custom-formatter>
            </formatter>
```

なお、修正した内容は以下のファイルに自動で反映するようです。

- /opt/wildfly-20.0.1.Final/standalone/configuration/logging.properties


Wildflyの設定ファイル（standalone.conf）に以下の設定を追加します。

```
# vi /opt/wildfly-20.0.1.Final/bin/standalone.conf

export JAVA_OPTS="$JAVA_OPTS -Delastic.apm.enable_log_correlation=true"
```

# FilebeatでWildfly（ECS）のログをElasticsearchへ送信する

FilebeatでWildfly（ECS）のログをElasticsearchへ送信するように設定します。
/etc/filebeat/filebeat.ymlを以下のように修正します。

```yml:/etc/filebeat/filebeat.yml
filebeat.inputs:
- type: log
  enabled: true
  paths:
    - /opt/wildfly-20.0.1.Final/standalone/log/server_json.log
  json.keys_under_root: true
  json.overwrite_keys: true
output.elasticsearch:
  hosts: ["localhost:9200"]
```

設定後、以下のコマンドでFilebeatを再起動します。

```
# systemctl stop filebeat
# systemctl start filebeat
```

# Kibanaでログを確認する

アプリケーションのトレースは以下のように表示されています。ここからトレースのトランザクションに対応するログを表示します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179607/544cf365-214e-61bf-9ec8-2f071393308b.png)

Transaction detailsから[Host logs]を選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179607/31b57aee-1df5-0040-22b8-1888369800e4.png)

選択すると、トランザクションに対応するログが表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179607/7bbb6494-2c0c-5fa9-237a-9aee9820d43e.png)

逆にログから[View in APM]を選択すると、ログに対応するトランザクションのトレースを表示することができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179607/feac59ef-f006-c728-ed3b-159385659f4d.png)