AWS活用における便利な小技を簡潔に紹介する連載「AWSチートシート」。今回は「CloudWatch Logs」の「サブスクリプションフィルター」機能の利用方法と注意点を紹介する。
この記事は会員限定です。会員登録(無料)すると全てご覧いただけます。
「Amazon Web Services」(AWS)活用における便利な小技を簡潔に紹介する連載「AWSチートシート」。今回は、「CloudWatch Logs」の「サブスクリプションフィルター」機能の利用方法と注意点を紹介します。
「サブスクリプションフィルター」はロググループ単位に設定するフィルター機能です。設定した特定文字列がログに出力された場合に、指定した後続処理(「AWS Lambda」「Amazon Kinesis」など)にログを転送します。
構築時は、とあるエラーのみ処理の中で通知する仕組みにしていたが、運用していく上で「他のエラーも同様に通知したい」「一時的にこのエラーは通知してほしい」といったことも起こります。こういった場合、大抵は処理を改修して通知する箇所を増やす必要がありますが、エラーログさえ出力していれば、元の処理を改修せずに「サブスクリプションフィルター」を使って解決できます。
図1は本記事で作成するサービスの構成イメージです。
今回は以下の手順でサービスを構築します。
こちらの記事の該当手順を参照してください。
AWSにログインし、Lambdaコンソールにアクセスして「関数の作成」をクリックします。
関数の作成画面では、下表の項目通りに設定して「関数の作成」をクリックします。なお、記載のない項目についてはデフォルトの設定のままで問題ありません。
設定項目 | 設定値 |
---|---|
オプション | 一から作成 |
関数名 | 任意(例では「subscriptionFilterToSlack」) |
ランタイム | Python 3.9 |
上記の設定が完了したら、「関数の作成」をクリックします。
作成したLambda関数の詳細ページが表示されたら、ページの中央にある「コードソース」に記載されているデフォルトのコードを下記のように書き換えて「Deploy」をクリックします。なお、コード内の「https://hooks.slack.com/services/xxx/xxx/xxx」の部分は、前の手順で取得したWebhook URLに修正してください。
import json import urllib.request import base64 import gzip from datetime import datetime def lambda_handler(event, context): # CloudWatchLogsデータをデコード decoded_data = base64.b64decode(event['awslogs']['data']) json_data = json.loads(gzip.decompress(decoded_data)) messages = [] # ロググループ名取得 messages.append('ロググループ名:' + json_data['logGroup']) messages.append('検知メッセージ:') # サブスクリプションフィルターで転送されたメッセージの取得 ※1 for log_event in json_data['logEvents']: # ログ出力時刻取得 int_timestamp = log_event['timestamp'] datetime_timestamp = datetime.fromtimestamp((int_timestamp/1000)) str_timestamp = datetime_timestamp.strftime('%Y/%m/%d %H:%M:%S.%f') # 時刻とメッセージを連結 messages.append(str_timestamp + ' ' + log_event['message']) # @channelメンションと、コードブロック付与 req = "<!channel>\n ```" + '\n'.join(messages) + "```" post_slack(req) return def post_slack(argStr): message = argStr send_data = { "text": message, } send_text = json.dumps(send_data) request = urllib.request.Request( "https://hooks.slack.com/services/xxx/xxx/xxx", data=send_text.encode('utf-8'), method="POST" ) with urllib.request.urlopen(request) as response: response_body = response.read().decode('utf-8')
作成したLambda関数をテスト実行します。「テスト」ボタンをクリックして、下記表の通りにテストイベントを設定して「保存」をクリックします。
設定項目 | 設定値 |
---|---|
イベントアクションをテスト | 新しいイベントを作成 |
イベント名 | 任意(例では「subscriptionFilterTest」) |
テンプレート | cloudwatch-logs |
テストの作成が完了したら、再度「テスト」ボタンをクリックします。Lambda関数が問題なく実行されてSlackにメッセージが送られれば、テストは成功です。
次に、監視対象となるLambda関数を作成します。今回はLambda関数を作成していますが、「cloudwatch logs」のロググループにログ出力できれば何でも構いません。
設定項目 | 設定値 |
---|---|
オプション | 一から作成 |
関数名 | 任意(例では「messageLogger」) |
ランタイム | Python 3.9 |
上記の設定が完了したら、「関数の作成」をクリックします。作成したLambda関数の詳細ページが表示されたら、ページの中央にある「コードソース」の欄に記載されているデフォルトのコードを下記のように書き換えて「Deploy」をクリックします。
def lambda_handler(event, context): print(event['key1']) print(event['key2']) print(event['key3'])
本例では、デフォルトテストテンプレートの「hello-world」実行で送信される、key1〜key3をログ出力するだけです。
作成したLambda関数をテスト実行します。「テスト」ボタンをクリックし、下記表の通りにテストイベントを設定して「保存」をクリックします。
設定項目 | 設定値 |
---|---|
イベントアクションをテスト | 新しいイベントを作成 |
イベント名 | 任意(例では「logtest」) |
テンプレート | hello-world |
テストの作成が完了したら、再度「テスト」ボタンをクリックします。図6の通りに実行結果が出力されたらテストは成功です。
設定はこれで最後です。監視対象となるLambda関数のロググループに、サブスクリプションフィルターを設定します。「CloudWatchコンソール」にアクセスして監視対象となるロググループ詳細画面に進みます。
「サブスクリプションフィルター」タブをクリックし、「作成」→「Lambdaサブスクリプションフィルターを作成」の順にクリックします。
サブスクリプションフィルターの作成画面では、下記表の項目通りに設定し、「パターンをテスト」をクリックします。
今回の設定では「value2」という文字列がログに出力されたときに、Slack通知するLambda関数を実行するように設定します。
設定項目 | 設定値 |
---|---|
Lambda 関数 | Slack通知するLambda関数名(例では「subscriptionFilterToSlack」) |
ログの形式 | その他 |
サブスクリプションフィルターのパターン | value2 |
サブスクリプションフィルター名 | 任意(例では「value2Filter」) |
テストするログデータを選択 | テスト実行した際のログストリーム名(例では「2022/09/01/[$LATEST]7b707e9b1b424fb8be65fd2e4be4cb2e」) |
「テスト結果を表示」以下が上記の通りなら、「ストリーミングを開始」をクリックします。以下の完了画面が表示されたら設定は完了です。
設定が完了したので、監視対象となるLambda関数の画面に戻り、テストを実行します。Slackに図12のように通知が来ていれば成功です。
サブスクリプションフィルターを実運用していて気付いた点を以下にまとめておきます。
これはあくまでも「呼び出せる機能が2種類」という意味です。フィルターパターンについては、下記リンクを見ていただければ分かるように、複数条件でマッチさせることが可能です。
図11を見て分かる通り、「削除」「作成」しかアクションが存在しません。つまり、フィルターパターンのみを変更したい場合、削除して作成するしか手段がありません。
起動はログストリーム単位です。つまり、Lambda関数などが多重起動して、いずれもフィルターパターンにマッチするログが出力された場合、別々にログが転送されSlack通知が届きます。
サブスクリプションフィルターは、マッチしたログを検知して即時に転送するわけではなく、最初にマッチしたログが見つかった時点から、おおむね8秒間程度待機時間が発生します。その間に再びマッチしたログが出力されたら、まとめて転送しています。
本稿の例では、複数転送されてくることも考慮して作成してあります(ソース内※1部分のループが必要)。
設定そのものは無料ですが、後続処理の利用料金はかかるので注意が必要です。
株式会社システムシェアード システム開発事業部所属。
Javaメインで10数年。お堅い企業からライトな企業までさまざまな案件に従事。ここ数年はクラウド環境のシステムで、負荷テストをしたり、運用してみたり、営業してみたりとマルチに活動。「取りあえず手を動かす」が信条
Copyright © ITmedia, Inc. All Rights Reserved.