こんにちは。
技術課の山本です。
Fargate タスクのログ出力で困っていることがあり、"awslogs-multiline-pattern" オプションを試してみたのですが、java の場合だと解決策にならなそうでした。
誰かの役には立ちそうなので、検証したことを書き残します。
追記:困っていることは以下のブログ記事の方法で解決できました。
困っていること
ECS タスク で java を使った処理を動かしていると、複数行にわたってログが出ることがあります。
ログ監視などをしていると、検知した部分の1行のみを拾って通知が来てしまい、通知だけ見てもエラー内容がよくわからないことがあります。
エラー例:
java.nio.file.NoSuchFileException: from.txt at java.base/sun.nio.fs.UnixException.translateToIOException(UnixException.java:92) at java.base/sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:111) at java.base/sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:116) at java.base/sun.nio.fs.UnixCopyFile.copy(UnixCopyFile.java:548) at java.base/sun.nio.fs.UnixFileSystemProvider.copy(UnixFileSystemProvider.java:258) at java.base/java.nio.file.Files.copy(Files.java:1295) at FileCopy.main(FileCopy.java:1)
awslogs ログドライバーをデフォルトの設定にしていると、以下のように出力されます。
1行ごとにログに区切りが入っています。
本当は結合して取れるといいです。
awslogs ログドライバーの "awslogs-multiline-pattern" オプションを使ってみる。
"awslogs-multiline-pattern" オプションについては、下の公式ドキュメントに記述があります。 タスク定義でログ設定を指定する
このオプションでは、正規表現を使用する複数行開始パターンを定義します。ログメッセージは、パターンに一致する 1 行と、それに続くパターンに一致しない行で構成されます。
(日本語のドキュメントでは「複数行起動パターン」となってます。しかし、「複数行開始パターン」の方が適切と感じたので置き換えています。)
正規表現を使って、複数行のログを結合できる、ということですね。
設定してみる
タスク定義の中にあるコンテナ定義のログ設定を編集します。
2022/2/1 現在、新しいマネジメントコンソール(新しい ECS エクスペリエンス)だと、json で設定するしかないです。
古いほうのコンソールだと、GUIで設定できます。json で書く場合は、json での特殊文字のエスケープも意識する必要があるため、古いほうのコンソールで設定してみました。
「"java."で始まる」を表現する正規表現は以下になります。
"^java\..*",
上記で新しくタスク定義を作成すると、タスク定義の json は以下になっていました。
json なので "\" がさらにエスケープされています。(jsonで書くの辛いやつですね。)
"^java\\..*",
結果としては以下のようになりました。
一見良さそうですね。
"awslogs-multiline-pattern" オプションの難しい点
「"java."で始まる」行ではない場合は改行されないので、もしも、次の処理が「"java."で始まる」ログを出さない場合は、永遠に結合されます。
上のようになってしまうので、ログの開始パターンを全て、正規表現に詰め込む必要があります。
上のログの場合は、「"java."で始まる」パターンと、「"Welcome to Amazon"で始まる」パターンがあるので、以下のようにします。
^java\..*|^Welcome to Amazon .*
結果としては以下のようになりました。
まとめ
例えば、「ログの接頭に "INFO:" か "ERROR:" か "Warning" が必ず付く」と保証できる場合には、"awslogs-multiline-pattern" オプションは適しているようです。
しかし、ログ出力の接頭にくる文字列が予想できないような場合には、適しません。
接頭辞として登録した正規表現に一致しない場合は、区切られないで結合され続けるためです。
参考:テストに使ったDockerfile
- Dockerfile
- Hello クラスは、"Welcome to Amazon Corretto!" を出力します。
- FileCopy クラスは “from.txt“ を “to.txt“ にコピーします。しかし、コンテナ上に “from.txt“ ないため、「"java."で始まる」エラーが発生します。エラーは複数行にわたります。
- test.sh 内で、Hello クラスとFileCopy クラスを交互に呼び出して、ログ出力がどうなるか確認できます。
FROM amazoncorretto:11 RUN echo $' \ public class Hello { \ public static void main(String[] args) { \ System.out.println("Welcome to Amazon Corretto!"); \ } \ }' > Hello.java RUN javac Hello.java RUN echo $' \ import java.io.IOException; \ import java.nio.file.Files; \ import java.nio.file.Paths; \ public class FileCopy{ \ public static void main (String[] args) { \ try { \ Files.copy(Paths.get("from.txt"), Paths.get("to.txt")); \ } catch (IOException e) { \ e.printStackTrace(); \ } \ } \ } ' > FileCopy.java RUN javac FileCopy.java COPY test.sh /test.sh RUN chmod 744 /test.sh CMD ["/test.sh"]
- test.sh
- Hello クラスとFileCopy クラスを交互に呼び出して、ログ出力がどうなるか確認できます。
- 必要に応じて行を増やしたり、コメントアウトを外します。
- Hello クラスとFileCopy クラスを交互に呼び出して、ログ出力がどうなるか確認できます。
#!/bin/bash java Hello java FileCopy #java Hello #java Hello #java Hello #java Hello #java Hello #java Hello #java Hello #java Hello #java Hello #java Hello #java Hello #java Hello
余談
2月ですね。
去年の2月の写真を見返していたら、遠くから鹿に見つめられている写真が出てきました。
それではまた、お会いしましょう。
山本 哲也 (記事一覧)
カスタマーサクセス部のエンジニア。2024 Japan AWS Top Engineers に選んでもらいました。
今年の目標は Advanced Networking – Specialty と Machine Learning - Specialty を取得することです。
山を走るのが趣味です。今年の目標は 100 km と 100 mile を完走することです。 100 km は Gran Trail みなかみで完走しました。残すは OSJ koumi 100 で 100 mile 走ります。実際には 175 km らしいです。「草 100 km / mile」 もたまに企画します。
基本的にのんびりした性格です。座右の銘は「いつか着く」