😊
AWS LambdaのCloudWatchログへの記録にはリクエストIDをつけようと思う(Pythonでの実装)
はじめに
AWS Lambdaで、手間を掛けずに簡単に出力するのであれば難しいライブラリ等を使わなくてもprint()
を使えばCloudWatchログへ記録されて確認できますが、単一アプリケーションとしてLambdaを実装し、ルーティングして処理を実行する場合(API Gatewayから入る複数のAPIを1つのLambda関数でメソッドやIDで振り分けて処理するなど)などに問題となるのが、『ログが入り乱れる』件ですよね。
そこで、ログ記録の際にリクエストIDをつけると障害発生時にトレースしやすくなるので実装しました。サンプルコードも載せてます。
リクエストIDってなに
Lambda で関数が実行されると、コンテキストオブジェクトがハンドラーに渡されます。
このプロパティで提供されているリクエストIDのことです。
- aws_request_id - 呼び出しリクエストのID。
Python の AWS Lambda context オブジェクト
CloudWatchログを確認すると、出ているこれですね。
このリクエストIDをログにつける
このリクエストIDを自身のアプリケーションが出力するログにもつけておいてあげることで、
障害発生時にトレースしやすくなります。
ログ出力処理の実装
ログ出力処理実装のサンプルです。
inspectでファイル名、関数名、行数を取得して同時に記録してます。
common.py
import os
import inspect
class SampleLog:
'''ロケーションデータをまとめる'''
pass
def get_location():
'''ファイル名、関数名、行数を返す関数'''
location = SampleLog()
frame = inspect.currentframe().f_back
location.filename = os.path.basename(frame.f_code.co_filename)
location.name = frame.f_code.co_name
location.lineno = frame.f_lineno
return location
def save_log(requestid,location,*args):
'''与えられたパラメタでprintする関数'''
print("[{}][{} {}() L{}]{}".format(requestid,location.filename,location.name,location.lineno,args))
呼び出し元
sample.py
loginfo = "[Exception:DoesNotExist]userid:{}, todid:{}, e:{}".format(request.userid,request.todoid, e)
common.save_log(context.aws_request_id,common.get_location(),loginfo)
context.aws_request_idはselfとかに入れておいてgetする形で使った方が良いですね。
ログ出力例
リクエストIDでフィルタすると絞り込めます。
けっこう良くないですか?
最後に
AWS LambdaのCloudWatchログへの記録時にリクエストIDをつける方法を紹介しました。
書いている途中で思ったのですが、CloudWatchログのログイベントのフィルターでリクエストIDで絞り込めたらこんなことしなくていいですね。。。
見た限りできなさそうでですが。その辺り調べて分かり次第、追記します。
Discussion