CloudWatchのメトリクスフィルターの検証と設定で大ハマりした話
前置き
参画案件の情報を伏せる意味合いもあり、アプリケーション名や文字列については実際のものとは違うものになります。
状況説明
現在参画している「AIX から AWS への全面リプレイス案件」で、CloudWatch ロググループのメトリクスフィルターを設定する作業がありました。
その中で、ABC というオンラインアプリケーションの現行 AIX の検知文字列の設定が、以下のように設定されていました:
- ABC[0-9]{4}E (ABC の後にランダムの数値 4 つと末尾に E が付くような設定値)
- CV[0-9]{4}E (CV の後にランダムの数値 4 つと末尾に E が付くような設定値)
ABC では、ログフィルターは 2 つ適用されている状況です。
AIX で設定されているログフィルターを、AWS 用に設定して実際に検知することができるかの、今回対応したものになります。
また、除外条件として、 CV9006E と CV9007E の 2 つがログとして出力された際、検出から除外しないといけないものになります。
検証前の準備
- AWS マネジメントコンソール > CloudWatch > ロググループ に遷移し、メトリクスフィルターの項目の任意のフィルターを押下(検証なのでどれでも OK)
- メトリクスフィルター > メトリクスフィルターを作成 を押下
上の順番で進めていくと、今回検証する画面に遷移します。
フィルターパターンにフィルターを作成し、イベントメッセージをログ記録にテスト用のログを入力します。
今回の検証用に、以下を用意しました:
Aug 21 10:05:42 abc ip-10-24- ABC1234E 2025/08/22 HOST接続エラーが発生しました。
Aug 21 10:05:42 abc ip-10-24- CV1234E 2025/08/22 HOST接続エラーが発生しました。
Aug 21 10:05:42 abc ip-10-24- CV9006E 2025/08/22 HOST接続エラーが発生しました。
Aug 21 10:05:42 abc ip-10-24- CV9007E 2025/08/22 HOST接続エラーが発生しました。
除外条件がない場合
もし除外条件が無い場合は、以下のようにフィルターパターンを入力すればテストとして成立します:
%ABC[0-9]{4}E|CV[0-9]{4}E%
これは 正規表現 と呼ばれるものであり、文字列を指定するときに使われる記載方法のことです。
話がずれてしまいましたが、 %ABC[0-9]{4}E|CV[0-9]{4}E% を細かく分解して解説します:
ABC[0-9]{4}E
- ABC:固定文字列「ABC」にマッチします。
- [0-9]{4}:数字(0〜9)が 4 桁続く部分にマッチします。
- E:固定文字「E」にマッチします。
つまり、テスト用のログにある %ABC1234E% のような文字列にマッチします。
%CV[0-9]{4}E
- %:文字列の先頭に「%」があることを示します。
- CV:固定文字列「CV」にマッチします。
- [0-9]{4}:数字(0〜9)が 4 桁続く部分にマッチします。
- E:固定文字「E」にマッチします。
- %:文字列の末尾に「%」があることを示します。
つまり、テスト用のログにある %CV1234E% のような文字列にマッチします。
除外条件を含めるフィルターパターン(失敗したパターン)
ここが大ハマりしてしまった箇所になります。 前段で挙げていた %ABC[0-9]{4}E|CV[0-9]{4}E% だと、今回の除外条件である CV9006E と CV9007E は CV[0-9]{4}E の正規表現にマッチしてしまう ので、表現としては正しくありません。 そこで、以下のように組んでみることにしました:
[ (a= %ABC[0-9]{4}E% || a= %CV[0-9]{4}E% ) && (a!= %CV9006E% && a!= %CV9007E%) ]
これを細かく分解して解説すると以下のようになります:
全体構造
この式は、次の 2 つの条件を AND(かつ) で結合しています:
- a が特定のパターンに一致する
- a が特定の値に一致しない(上の例で言うと a!に該当)
条件 ①:(a= %ABC[0-9]{4}E% || a= %CV[0-9]{4}E%)
これは「a が以下のいずれかの正規表現に一致する」という意味です:
- %ABC[0-9]{4}E%:ABC + 4 桁の数字 + E を % で囲んだ文字列
- 例:%ABC1234E%
- %CV[0-9]{4}E%:CV + 4 桁の数字 + E を % で囲んだ文字列
- 例:%CV5678E%
つまり、a が 「ABC または CV で始まり、4 桁の数字+ E で終わる文字列」 で、かつ % で囲まれている場合に一致 します。
条件 ②:(a!= %CV9006E% && a!= %CV9007E%)
これは「a が以下のいずれにも一致しない」という意味です:
- %CV9006E%:この文字列と完全一致しない
- %CV9007E%:この文字列と完全一致しない
メトリクスフィルターを入力してパターンをテストしてみたところ、コンソールに以下のようなポップアップが表示されました:
サブスクリプションフィルターのテスト中にエラーが発生しました。
Your input has exceeded the maximum of 2 regular expressions per filter pattern.
英語の箇所は、「入力した正規表現の数は、フィルター パターンあたりの最大数である 2 を超えています。」という意味
調査したところ、AWS 公式から以下の案内がありました:
メトリクスフィルターとサブスクリプションフィルターの特定のフィルターパターンには、2 つの正規表現パターンというクォータがあります。
引用:Amazon CloudWatch Logs、フィルターパターン構文での正規表現のサポートを発表
どうやらこれに引っかかってしまい、異常が発生したと推測しました。
除外条件を含めるフィルターパターン(成功したパターン)
結論から言いますと、a!以降の構文を修正して実行した結果、除外条件も適用されテストも正常に終了することができました:
[(a=%ABC[0-9]{4}E%||a=%CV[0-9]{4}E%)&&(a!="_CV9006E_"&&a!="_CV9007E_")]
a!以降の構文を解説します:
- " “:ダブルクォートで囲むと文字列として扱えます。
- *:ワイルドカードに近い構文になっており、今回で言うと CV9006E の前後に半角スペースが入ることを想定して記述しています。
a=から&&の間の%%で囲っている構文は、正規表現として 1 つ消費されてしまうことがわかりました。
失敗したパターンを見ると、%%で囲われている構文は 4 つある状態でテストを行ったのでエラーになってしまいました。
今回の成功パターンで見ると、a=から&&の構文では正規表現は 2 つ、a!=以降の構文はワイルドカードに近い構文なので 正規表現ではありません 。
最後に
普段の業務では正規表現を使った作業はあまり触れる機会が無く、今回はよい経験になったと思います。
ただ、今回経験したこと以外でも正規表現に触れることもあると思うので、しっかり継続して学んでいこうと思います。
この事例が、どなたかの参考になれば幸いです。