ECS on Fargate で awslogs ログドライバーの "awslogs-multiline-pattern" オプションを使ってみる。

記事タイトルとURLをコピーする

こんにちは。
技術課の山本です。

Fargate タスクのログ出力で困っていることがあり、"awslogs-multiline-pattern" オプションを試してみたのですが、java の場合だと解決策にならなそうでした。
誰かの役には立ちそうなので、検証したことを書き残します。

追記:困っていることは以下のブログ記事の方法で解決できました。

blog.serverworks.co.jp

困っていること

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 クラスを交互に呼び出して、ログ出力がどうなるか確認できます。
      • 必要に応じて行を増やしたり、コメントアウトを外します。
#!/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月の写真を見返していたら、遠くから鹿に見つめられている写真が出てきました。

それではまた、お会いしましょう。

山本 哲也 (記事一覧)

カスタマーサクセス部のエンジニア(一応)

好きなサービス:ECS、ALB

趣味:トレラン、登山(たまに)