9
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

サブスクリプションフィルターで、あるLambdaの出力したログを、別のLambdaに渡す

Last updated at Posted at 2021-12-22

フューチャー Advent Calendar 2021の23日目の記事です。

昨日は、@hayao0727 さんによる
AxumでGoのチュートリアル「Writing Web Application」をやってみた でした。

私自身、今年のフューチャーのアドカレ枠では既に2本投稿しているのですが、ラストに向けてガンバっていきます。

投稿した2本はこちら

はじめに

みなさんは、CloudWatch Logsの便利機能である「サブスクリプションフィルター」を利用したことはありますか?

ざっくりと

  • 1つのロググループに、最大2つまで設定可能である
  • 予め指定した「フィルターパターン」に一致する文字列が、ログに出力されたら起動する
  • Lambda, Kinesis, Kinesis Data Firehose に向けて、フィルターがキャッチした文字列(正確には文字列を含むログ全文)を配信する

という機能です。

「特定のログが出力されたら、追加処理を実行したい」という要件が出てきた場合(例えば、error の文字列がログ出力されたら、チケットを起票するなど)、コンピュートリソース自体に追加処理を加えずとも、サブスクリプションフィルターを設定するだけで、欲しいログを Lambda や Kinesis に送信できます。

今回は以下のシステム構成で

Screen Shot 2021-12-22 at 23.40.52.png

  • main-lambda の出力したログを
  • サブスクリプションフィルターで拾い上げて
  • sub-lambda で取得する

までの流れを追っていきます。

環境用意

今回の検証環境は

  1. main-lambda
  2. sub-lambda
  3. main-lambda → sub-lambda に向けたサブスクリプションフィルターの設定

という流れで準備していきます。

main-lambdaの作成

1つ目のLambdaを作成して、メッセージ文をログ出力する処理を追加します。

lambda_handler.py
import json

def lambda_handler(event, context):
    message = "Hello CloudWatch Logs subscription filters."
    print(message)
    
    return {
        'statusCode': 200,
        'body': json.dumps(message)
    }

Lambda のデプロイ後、コンソール画面でテスト実行 or awscliコマンドで実行すると、自動で /aws/lambda/main-lambda のロググループが作成されます。
CloudWatch のコンソール画面からロググループを手動追加しても問題ありませんが、面倒なので Lambda を手動テスト起動して、ロググループを自動生成します。

sub-lambdaの作成

次は、サブスクリプションフィルターの配信を受ける側の Lambda を作成していきます。

lambda_handler.py
import json
import base64
import gzip

def lambda_handler(event, context):
    # base64 デコード
    decoded_data = base64.b64decode(event['awslogs']['data'])
    
    # gzip 解凍
    decompressed_data = gzip.decompress(decoded_data)
    json_data = json.loads(decompressed_data)
    
    message = json_data['logEvents'][0]['message']
    print(message)

    return {
        'statusCode': 200,
        'body': json.dumps(message)
    }

コード解説

サブスクリプションフィルターでの配信データは、{ "awslogs": {"data": "BASE64ENCODED_GZIP_COMPRESSED_DATA"} } という形式であり、data キーは

  • gzip 形式で圧縮
  • Base64 でエンコード

された状態で届きます。

そのため、生データを取得するには、受け手側で「Base64 のデコード、gzip の解凍」処理が必要です。
生データ取得後の処理内容は、サブスクリプションフィルターの設定内容が影響するため、後半のパートで説明します。

サブスクリプションフィルターの設定

CloudWatch のコンソール画面から、/aws/lambda/main-lambda のログループに移動して、サブスクリプションフィルターの設定を選択します。

Screen Shot 2021-12-23 at 0.16.38.png

いくつかの項目選択画面が表示されるため、以下情報を入力します。

送信先を選択

  • Lambda 関数: sub-lambda

ログ形式とフィルターを設定

  • ログの形式: AWS Lambda
  • サブスクリプションフィルターのパターン: Hello
  • サブスクリプションフィルター名: Detect Hello

Screen Shot 2021-12-23 at 0.19.30.png

今回は「サブスクリプションフィルターのパターン」を Hello で設定したので、/aws/lambda/main-lambda のログに Hello の文字列が出力されたとき、サブスクリプションフィルターが起動し、sub-lambda が起動する、という起動フローになります。

項目入力後、「ストリーミングの開始」を選択すると、フィルターの設定状況が確認できます。

Screen Shot 2021-12-23 at 0.25.05.png

以上により、環境準備は完了です。

実行

現状をおさらいすると、

  • Hello の文字列を含むログが /aws/lambda/main-lambda に出力されたとき、サブスクリプションフィルターが起動して、sub-lambda が起動する

という状態です。

Screen Shot 2021-12-22 at 23.40.52.png

つまり、main-lambda が Hello の文字列をログ出力さえすれば、後は後続処理が自動で動く状態になっています。
さっそく main-lambda をテスト起動して、ログを出力させます。

(手動起動後の出力ログ)

Screen Shot 2021-12-23 at 0.38.40.png

想定どおり、Hello の文字列が出力されていますね。

このとき、サブスクリプションフィルター → sub-lambda には、以下フォーマットの jsonデータ が渡されます。

raw.json
{
    "messageType": "DATA_MESSAGE",
    "owner": "<aws account>",
    "logGroup": "/aws/lambda/main-lambda",
    "logStream": "2021/12/22/[$LATEST]8ac0982efa7e40e78d6702702b842a7e",
    "subscriptionFilters": [
        "Detect Hello"
    ],
    "logEvents": [
        {
            "id": "<log events id>",
            "timestamp": 1640181063036,
            "message": "Hello CloudWatch Logs subscription filters.\n"
        }
    ]
}

前半の sub-lambda のコードで、以下のような処理がありました。

lambda_handler.py
message = json_data['logEvents'][0]['message']
print(message)

この参照は、サブスクリプションフィルターが渡す jsonデータ に依拠したもので、sub-lambda が受け取ったメッセージを表示するためのものです。

ログを見ると、サブスクリプションフィルターの送信データが、sub-lambda 側で受信できていることが確認できました。
Hello という特定の文字列だけを拾うのではなく、「Hello 文字列を含めた、ログイベントに出力された全文」が渡っていることも分かります。

Screen Shot 2021-12-23 at 0.46.14.png

以上で、
「サブスクリプションフィルターで、あるLambdaの出力したログを、別のLambdaに渡す」
の動作検証は終了です。

おわりに

本記事では、サブスクリプションフィルターを利用して、Lambda のログを配信し、別の Lambda に渡す処理を見ていきました。
既にこの機能を知っている人からすれば「何を今更」という感じかもしれませんが、AWS 初心者が意外と知らずに苦労していたりするケースが見られたので、ブログ化してみました。

以上、長文にお付き合いいただき、ありがとうございました。

明日は、@kmd252525 さんです!

9
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?