この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
コンバンハ、千葉(幸)です。
Lambda 関数の実行ログは/aws/lambda/<Lambda関数名>
という CloudWatch Logs ロググループに出力されます。
ロググループ内でログストリームが動的に生成され、その中に出力されていきます。ログストリーム名は以下の命名規則になっています。
YYYY/MM/DD/[<Lambda関数 のバージョン>]<ランダムな識別子>
以下のイメージです。
このログストリーム名を動的に取得したい、ということで Lambda コンテキストを使用してみました。
やりたいこと
以下のスクリプトのように Lambda 関数の実行とログ取得を行いたいです。
#!/bin/bash
aws lambda invoke --function-name my-function --cli-binary-format raw-in-base64-out --payload '{"key": "value"}' out
sed -i'' -e 's/"//g' out
sleep 15
aws logs get-log-events --log-group-name /aws/lambda/my-function --log-stream-name $(cat out) --limit 5
ここでは Lambda 関数の返り値としてログストリーム名が返ってくることが前提になっています。そのために Lambda コンテキストを使用します。
Lambda 関数の作成
今回は設計図hello-world-python
を用いて Lambda 関数を作成しました。
- 関数名:hello-world-python
- ランタイム:Python 3.7
- IAM ロール:自動作成に任せる
コードの中身は以下です。
import json
print('Loading function')
def lambda_handler(event, context):
print("Received event: " + json.dumps(event, indent=2))
print("value1 = " + event['key1'])
print("value2 = " + event['key2'])
print("value3 = " + event['key3'])
return event['key1'] # Echo back the first key value
#raise Exception('Something went wrong')
渡されたイベントの key1 の値を返すようになっています。
Lambda 関数の実行
上記の状態で AWS CLI から Lambda 関数を実行してみます。
まず環境変数を格納。
FUNCTION_NAME=hello-world-python
PAYLOAD=$(cat <<EOM
{
"key1": "value1",
"key2": "value2",
"key3": "value3"
}
EOM
)
上記を引数に使用して実行します。
$ aws lambda invoke --function-name $FUNCTION_NAME --cli-binary-format raw-in-base64-out --payload "$PAYLOAD" out
{
"StatusCode": 200,
"ExecutedVersion": "$LATEST"
}
--cli-binary-format raw-in-base64-out
を指定しないとペイロードが base64 エンコードされたテキストとして扱われるため、それを回避するために指定します。
outfile として指定したout
にはreturn event['key1']
の内容が格納されています。
$ cat out
"value1"
Lambda コンテキストの使用
コードの内容を以下に書き換えます。return で返す内容をcontext.log_stream_name
に変更しています。
import json
print('Loading function')
def lambda_handler(event, context):
print("Received event: " + json.dumps(event, indent=2))
print("value1 = " + event['key1'])
print("value2 = " + event['key2'])
print("value3 = " + event['key3'])
# return event['key1'] # Echo back the first key value
return context.log_stream_name
#raise Exception('Something went wrong')
ここではlog_stream_name
を指定しましたが、他にも利用できる Lambda コンテキストオブジェクトがあります。
Lambda コンテキストによるログストリーム名の取得
コードを修正した状態で再度 Lambda 関数を実行します。
$ aws lambda invoke --function-name $FUNCTION_NAME --cli-binary-format raw-in-base64-out --payload "$PAYLOAD" out
{
"StatusCode": 200,
"ExecutedVersion": "$LATEST"
}
$ cat out
"2022/03/21/[$LATEST]7d0c88909f86424bbe40b4c0cfcdb08f"
ログストリーム名が返り値として取得できていることが分かります。
冒頭のスクリプトと同等のコマンドを実行します。2 行目の sed の処理は"
を除去するためのものです。
aws lambda invoke --function-name $FUNCTION_NAME --cli-binary-format raw-in-base64-out --payload "$PAYLOAD" out
sed -i'' -e 's/"//g' out
sleep 15
aws logs get-log-events --log-group-name /aws/lambda/$FUNCTION_NAME --log-stream-name $(cat out) --limit 5
実行するときちんとログストリーム内のログイベントが取得できました。
$ aws lambda invoke --function-name $FUNCTION_NAME --cli-binary-format raw-in-base64-out --payload "$PAYLOAD" out
sed -i'' -e 's/"//g' out
sleep 15
aws logs get-log-events --log-group-name /aws/lambda/$FUNCTION_NAME --log-stream-name $(cat out) --limit 5
{
"StatusCode": 200,
"ExecutedVersion": "$LATEST"
}
{
"events": [
{
"timestamp": 1647838819665,
"message": "value1 = value1\n",
"ingestionTime": 1647838828689
},
{
"timestamp": 1647838819665,
"message": "value2 = value2\n",
"ingestionTime": 1647838828689
},
{
"timestamp": 1647838819665,
"message": "value3 = value3\n",
"ingestionTime": 1647838828689
},
{
"timestamp": 1647838819666,
"message": "END RequestId: 37e94215-8d36-4ea8-a5cd-b850f20217a5\n",
"ingestionTime": 1647838828689
},
{
"timestamp": 1647838819666,
"message": "REPORT RequestId: 37e94215-8d36-4ea8-a5cd-b850f20217a5\tDuration: 1.51 ms\tBilled Duration: 2 ms\tMemory Size: 128 MB\tMax Memory Used: 36 MB\t\n",
"ingestionTime": 1647838828689
}
],
"nextForwardToken": "f/36748033645618918877095797763546468513774900547129573386/s",
"nextBackwardToken": "b/36748033645596618131897267140404932795502252185623592966/s"
}
ちなみに
Lambda コンソールから実行した場合は以下のように見えます。
「テスト」タブから実行した場合。
「コード」タブから実行した場合。
終わりに
Lambda コンテキストによりログ出力先のログストリーム名を取得してみました。今回は Python の例を試したましたが、他の言語のランタイムでも同様のことが実現できます。
こういったこともできる、と覚えておくとどこかで役に立つかもしれません。
以上、 チバユキ (@batchicchi) がお送りしました。