標準の出力
AWS Lambda で logging
モジュールを使用してログを使用する際、普通に以下のように出力すると、
import logging
logger = logging.getLogger()
def lambda_handler(event, context):
logger.warn('MESSAGE')
以下のようなタブ区切りフォーマットで出力されます。
[WARNING] 2018-05-19T09:25:42.272Z xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx MESSAGE
WARNING
はログレベル、その後は出力時刻(UTC)、リクエストID、メッセージ本文となっています。
ロガーのログレベルは、デフォルトでは標準通り WARNING
に設定されています。
フォーマットを変更する
出力フォーマットを変更したい場合は、以下を元にします。
import logging
logger = logging.getLogger()
formatter = logging.Formatter(
'[%(levelname)s]\t%(asctime)s.%(msecs)dZ\t%(aws_request_id)s\t%(message)s\n',
'%Y-%m-%dT%H:%M:%S'
)
for handler in logger.handlers:
handler.setFormatter(formatter)
上の Formatter
のパラメータが標準のフォーマットに対応しているので、これを変更します。例えばファイル名・関数名・行番号も記録したい場合は
formatter = logging.Formatter(
'[%(levelname)s]\t%(asctime)s.%(msecs)dZ\t%(aws_request_id)s\t%(filename)s\t%(funcName)s\t%(lineno)d\t%(message)s\n',
'%Y-%m-%dT%H:%M:%S'
)
などとすれば良いでしょう。
なお、ハンドラ自体を自分で作成して入れ替えることは避けた方が無難です。はじめから設定されているハンドラには aws_request_id
というLogRecord属性名でリクエストIDを出力するためのフィルタが追加されていますが、自分で作成したハンドラーにはこの機能が無いためです。
ログレベルを動的に変更する
コードの変更なしにログレベルを変更するには、以下のように、環境変数等の外部からレベル名を取得してロガーに設定するようにします。
import logging
import os
logger = logging.getLogger()
level_name = os.environ.get('LOG_LEVEL')
level = logging.getLevelName(level_name)
if not isinstance(level, int):
level = logging.INFO # 未設定/設定ミス時のデフォルト
logger.setLevel(level)
上記の例の場合は、環境変数 LOG_LEVEL
に DEBUG
などの文字列を設定すれば、そのレベルでロギングが行われることになります。
文字列のレベル名から logger.DEBUG
のような数値のログレベルを取得するには logging.getLevelName()
が使用できます。
これは通常はログレベルの数値から文字列表現を取得するものですが、逆に文字列を指定すると数値に変換してくれる機能もあります。None
や未対応の文字列を与えると 'Level None'
のような文字列を返すため、戻り値が数値かどうかで、正しいログレベル文字列だったかどうかが判定できます。
ドキュメントに注意があるように、この機能は 3.4 から 3.4.2 未満のバージョンでのみ動作しませんが、バージョンが固定されているLambda環境では問題にならないでしょう。
また、Python 3.2 以上であれば logger.setLevel()
のように直接 'INFO'
のような文字列を渡すこともできますが、None
や未対応の文字列を渡すと例外が発生するため、getLevelName()
の方が安全と思われます。