EC2(Amazon Linux)のWebLogicでログを管理する

このシリーズの流れ。

* [EC2(Amazon Linux)にWebLogic(12.1.x)をインストールする](http://qiita.com/m28/items/019051f2d47103015cd5)
* [EC2(Amazon Linux)でWebLogicドメインを作成する](http://qiita.com/m28/items/c3a12aff8783599bb122)

EC2のEBSに出力されたログをCloudWatch Logsから見る。

## 管理するログを決める
以下を参考にさせてもらいました。
[WebLogic Serverを基礎から学ぶシリーズ第3弾 入門！WebLogic Serverの運用監視](http://www.oracle.com/technetwork/jp/ondemand/branch/20140514-wls-2206178-ja.pdf)

これらのログを管理することに決定。

- サーバーログ
- ドメインログ
- コンソールログ
- GCログ
- HTTPアクセスログ
- アプリケーションログ

## CloudWatch Logsの設定
出力されたログをCloudWatch Logsに送信するため、まずはAWSのドキュメント[^1]に従ってEC2インスタンスへCloudWatch Logsエージェントをインストールする。ログは管理サーバーにも管理対象サーバーにも出力されるので両方へインストールを行う。

### 1. IAMロールをEC2インスタンスにアタッチ
EC2インスタンスにCloudWatch Logsへのアクセスを委任。

1. IAMロールを作成
2. 作成したロールへ、CloudWatch Logsの操作を許可するカスタムポリシーを追加
3. EC2インスタンスへロールを割り当て

### 2. CloudWatch Logs エージェントをインストール

```shell-session
$ sudo yum update -y
$ sudo yum install -y awslogs

$ sudo sed 's/^region = .*/region = ap-northeast-1/' /etc/awslogs/awscli.conf > ~/awscli.conf.tmp
$ sudo chown root:root ~/awscli.conf.tmp
$ sudo chmod 600 ~/awscli.conf.tmp
$ sudo mv ~/awscli.conf.tmp /etc/awslogs/awscli.conf
```

IAMロールをアタッチしているので認証情報の設定は不要。ただ東京リージョンのCloudWatch Logsへ送信したかったのでそこだけは設定。

### 3. awslogsサービスを開始
初期設定で/var/log/messagesを送信するようになっているので、まずはどんな感じか体験してみる。

```shell-session
$ sudo service awslogs start
```

開始後、CloudWatchコンソールを見ると…「CloudWatch > ロググループ > /var/log/messages > [インスタンスID]」にログ出てるー:v::v::v:

![](https://qiita-image-store.s3.amazonaws.com/0/109331/5591fa23-9258-09d4-81f0-29698e50bb9d.png)


### 4. 追跡するログの設定
ポイントになるのは対象ログの場所、名前、タイムスタンプのフォーマット。
管理すると決めたログについて上記を確認し設定していく。

## サーバーログ
WebLogicサーバーのイベントが記録される。起動とか停止とかアプリケーションのデプロイとか。管理サーバーと管理対象サーバーの両方に存在する。

まずはファイルパス、ファイル名、およびタイムスタンプのフォーマットを確認。

すべて管理コンソールから確認できる。ドメイン構造から「環境 → サーバー → [サーバー名]」と選択し「ロギング」タブの「一般」タブにて。（タイムスタンプのフォーマットは実際のログを見た方が早いかな）

![](https://qiita-image-store.s3.amazonaws.com/0/109331/a98e0295-f586-4c03-432f-4d25f9995c4a.png)

確認できたのでCloudWatch Logs エージェントの設定ファイルへ追跡したいログの情報を記述する。以下のようになった。（管理サーバーでの例）

```text:/etc/awslogs/awslogs.conf
[serverlog]
log_group_name = ServerLog
log_stream_name = leo1(管理サーバー)
datetime_format = ####<%b %d, %Y %I:%M:%S %p %Z>
file = /home/oracle/user_projects/domains/zodiac/servers/leo1/logs/leo1.log
multi_line_start_pattern = {datetime_format}
```

awslogsサービスを再起動して設定を反映。

```shell-session
$ sudo service awslogs restart
```

## ドメインログ
ドメイン全体のステータスを確認できるログ。各サーバーログの特定ログレベル以上のメッセージが記録される。管理サーバーにのみ存在。

まずはファイルパス、ファイル名、およびタイムスタンプのフォーマットを確認。

すべて管理コンソールから確認できる。ドメイン構造からドメイン名を選択し、「構成」タブの「ロギング」にて。

![](https://qiita-image-store.s3.amazonaws.com/0/109331/ab6a98df-2ac2-fe59-1ac3-7367c95e8a45.png)

確認できたのでCloudWatch Logs エージェントの設定ファイルへ追跡したいログの情報を記述する。以下のようになった。

```text:/etc/awslogs/awslogs.conf
[domainlog]
log_group_name = DomainLog
log_stream_name = zodiac
datetime_format = ####<%b %d, %Y %I:%M:%S %p %Z>
file = /home/oracle/user_projects/domains/zodiac/servers/leo1/logs/zodiac.log
multi_line_start_pattern = {datetime_format}
```

awslogsサービスを再起動して設定を反映。

```shell-session
$ sudo service awslogs restart
```

## コンソールログ
標準出力、標準エラー出力のログ。管理サーバーと管理対象サーバーの両方で取得する。

まずはファイルパス、ファイル名を確認、というか設定する。WebLogicの起動スクリプトに変数名「WLS_REDIRECT_LOG」で出力ファイル名を記述できるが、今回は余すことなく取得できるようスクリプト実行時にリダイレクト先を指定する方向で設定。

管理サーバーの場合：

```shell-session
$ nohup /home/oracle/user_projects/domains/zodiac/startWebLogic.sh 1>/home/oracle/user_projects/domains/zodiac/servers/leo1/logs/console.log.`date +%Y%m%d%H%M%S`.$$ 2>&1 &
```

管理対象サーバーの場合：

```shell-session
$ nohup /home/oracle/user_projects/domains/zodiac/bin/startManagedWebLogic.sh leo2 t3://leo1.example.com:7001 1>/home/oracle/user_projects/domains/zodiac/servers/leo2/logs/console.log.`date +%Y%m%d%H%M%S`.$$ 2>&1 &
```

続いてタイムスタンプのフォーマット確認、だけど雑多な内容が出ると思われるので設定しようがない感。というわけでCloudWatch Logs エージェントの設定ファイルは以下のような記述になった。（管理サーバーでの例）

```text:/etc/awslogs/awslogs.conf
[consolelog]
log_group_name = ConsoleLog
log_stream_name = leo1（管理サーバー）
file = /home/oracle/user_projects/domains/zodiac/servers/leo1/logs/console.log.*
```

awslogsサービスを再起動して設定を反映。

```shell-session
$ sudo service awslogs restart
```

ちなみにログローテーションについては、出力そんなにないだろうし内容の確認はCloudWatchコンソールから行うので今回はしなくていいんじゃないかなーって。:hamburger:

## GCログ
ガベージコレクションのログ。アプリケーションがデプロイされる管理対象サーバーでのみ取得。

まずはファイルパス、ファイル名を確認、というか設定する。管理対象サーバーの起動スクリプトへGC関連のフラグを設定。

```bash:/home/oracle/user_projects/domains/zodiac/bin/startManagedWebLogic.sh
# JAVA_OPTIONS環境変数を定義する直前にGC関連のフラグを設定
JAVA_OPTIONS="-XX:+PrintGC -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/var/log/logdemo/gc.log.%t -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=20M ${JAVA_OPTIONS}"

export JAVA_OPTIONS
```

設定したフラグは以下。

|フラグ|意味|
|:---|:---|
|-XX:+PrintGC|GCの基本的なログを出力する|
|-XX:+PrintGCDetails|GCに関する詳細なログを記録する|
|-XX:+PrintGCDateStamps|GCのログの各エントリで実際の日付を出力する|
|-Xloggc:[パス]|GCのログを標準出力から別のファイルへリダイレクトする|
|-XX:+UseGCLogFileRotation|GCのログのローテーションを行う|
|-XX:NumberOfGCLogFiles=[N]|ログローテーションで保持するログファイルの数を指定する|
|-XX:GCLogFileSize=[N]|ログファイルのサイズを指定する|

タイムスタンプのフォーマットは実際の出力を見て確認。

```text
2017-09-19T15:26:42.257+0900: 9.422: [Full GC (Metadata GC Threshold) 2017-09-19T15:26:42.257+0900: 9.422: [Tenured: 26081K->40434K(174784K), 0.1071922 secs] 94961K->40434K(253504K), [Metaspace: 58287K->58287K(1101824K)], 0.1072718 secs] [Times: user=0.10 sys=0.01, real=0.11 secs]
2017-09-19T15:26:43.770+0900: 10.934: [GC (Allocation Failure) 2017-09-19T15:26:43.770+0900: 10.934: [DefNew: 70016K->8704K(78720K), 0.0263706 secs] 110450K->50187K(253504K), 0.0264394 secs] [Times: user=0.03 sys=0.00, real=0.02 secs]
2017-09-19T15:26:45.177+0900: 12.342: [GC (Allocation Failure) 2017-09-19T15:26:45.177+0900: 12.342: [DefNew: 78720K->8704K(78720K), 0.0265826 secs] 120203K->58992K(253504K), 0.0266508 secs] [Times: user=0.02 sys=0.01, real=0.03 secs]
2017-09-19T15:26:45.673+0900: 12.837: [GC (Allocation Failure) 2017-09-19T15:26:45.673+0900: 12.837: [DefNew: 78720K->221K(78720K), 0.0097785 secs] 129008K->54214K(253504K), 0.0098368 secs] [Times: user=0.01 sys=0.00, real=0.01 secs]
2017-09-19T15:26:47.298+0900: 14.462: [GC (Allocation Failure) 2017-09-19T15:26:47.298+0900: 14.463: [DefNew: 70237K->7929K(78720K), 0.0133497 secs] 124230K->61922K(253504K), 0.0134268 secs] [Times: user=0.01 sys=0.00, real=0.02 secs]
```

確認できたのでCloudWatch Logs エージェントの設定ファイルへ追跡したいログの情報を記述する。以下のようになった。

```text:/etc/awslogs/awslogs.conf
[gclog]
log_group_name = GCLog
log_stream_name = leo2
datetime_format = %Y-%m-%dT%H:%M:%S.%f%z
file = /var/log/logdemo/gc.log.*
multi_line_start_pattern = {datetime_format}
```

awslogsサービスを再起動して設定を反映。

```shell-session
$ sudo service awslogs restart
```

GCログはCloudWatchコンソールからS3へ出力して別途ツールで眺める感じになるんじゃないかなー。

## HTTPアクセスログ
その名の通りアクセスログ。アプリケーションがデプロイされる管理対象サーバーでのみ取得。

まずはファイルパス、ファイル名、およびタイムスタンプのフォーマットを確認。

すべて管理コンソールから確認できる。ドメイン構造から「環境 → サーバー → [サーバー名]」と選択し「ロギング」タブの「HTTP」タブにて。

![](https://qiita-image-store.s3.amazonaws.com/0/109331/556a5ae6-b5af-d675-fe5e-0548e37490ff.png)

確認できたのでCloudWatch Logs エージェントの設定ファイルへ追跡したいログの情報を記述する。以下のようになった。

```text:/etc/awslogs/awslogs.conf
[accesslog]
log_group_name = AccessLog
log_stream_name = leo2
datetime_format = [%d/%b/%Y:%H:%M:%S %z]
file = /home/oracle/user_projects/domains/zodiac/servers/leo2/logs/access.log
multi_line_start_pattern = {datetime_format}
```

awslogsサービスを再起動して設定を反映。

```shell-session
$ sudo service awslogs restart
```

## アプリケーションログ
log4j2を利用してログを出力。

ファイルパス、ファイル名、およびタイムスタンプのフォーマットは設定ファイルから確認。

```xml:src/main/resources/log4j2.xml
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="off">
    <Properties>
        <Property name="loglayout">[%d{yyyy-MM-dd HH:mm:ss.SSS}] %-5p %t %c %m%n</Property>
    </Properties>
    <Appenders>
        <Console name="stdout" target="SYSTEM_OUT">
            <PatternLayout pattern="${loglayout}" />
        </Console>
        <RollingFile name="app" fileName="/var/log/logdemo/app.log" filePattern="/var/log/logdemo/app-%d{yyyy-MM-dd}-%i.log.gz">
            <PatternLayout pattern="${loglayout}" />
            <Policies>
                <OnStartupTriggeringPolicy />
                <SizeBasedTriggeringPolicy size="20 MB" />
                <TimeBasedTriggeringPolicy />
            </Policies>
            <DefaultRolloverStrategy max="10" />
        </RollingFile>
    </Appenders>
    <Loggers>
        <Root level="debug">
            <AppenderRef ref="stdout" />
        </Root>
        <Logger name="com.mycompany" level="info" additivity="false">
            <AppenderRef ref="app" />
        </Logger>
    </Loggers>
</Configuration >
```

確認できたのでCloudWatch Logs エージェントの設定ファイルへ追跡したいログの情報を記述する。以下のようになった。

```text:/etc/awslogs/awslogs.conf
[applicationlog]
log_group_name = ApplicationLog
log_stream_name = logdemo2
datetime_format = [%Y-%m-%d %H:%M:%S.%f]
file = /var/log/logdemo/app.log
multi_line_start_pattern = {datetime_format}
```

awslogsサービスを再起動して設定を反映。

```shell-session
$ sudo service awslogs restart
```

## その他情報
### CloudWatch Logs自体のログ
ログが追跡できていない時など、awslogsサービスでエラーがないか確認する際は/var/log/awslogs.logファイルを確認する。

```shell-session
$ cat /var/log/awslogs.log 
```

### WebLogic + SLF4J + Log4j2
この組み合わせでログが出なさすぎたので解決方法をメモ。

ライブラリの設定：

```xml:pom.xml
<dependencies>
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-core</artifactId>
        <version>2.8.2</version>
    </dependency>
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-slf4j-impl</artifactId>
        <version>2.8.2</version>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>1.7.21</version>
    </dependency>
</dependencies>
```
 
* log4j-core(version:2.8.2) // Log4j2本体、**version:2.9.0にすると何故かデプロイできない…**
* log4j-slf4j-impl // Log4j2へのバインディング
* slf4j-api // ログファサード

weblogic.xmlでSLF4Jのリソース定義を行う：

```xml:weblogic.xml
<container-descriptor>
    <prefer-application-packages>
        <package-name>org.slf4j.*</package-name>
    </prefer-application-packages>
    <prefer-application-resources>
        <resource-name>org/slf4j/impl/StaticLoggerBinder.class</resource-name>
    </prefer-application-resources>
</container-descriptor>
```

**StaticLoggerBinder.classを常にアプリケーションのリソースからロードされるよう設定**しないといけないらしい[^2]。わっかんねー:innocent:

[^1]: http://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/logs/QuickStartEC2Instance.html
[^2]: https://stackoverflow.com/questions/9734503/prevent-weblogic-12c-from-using-systems-slf4j-binding