🏋️♀️
aws lambda(python)に最適なlogging classの作成
概要・背景
aws lambda(python)で関数をいくつか作成しています。
毎度、関数の作成時にloggingの処理を入れるのが面倒でclass化したい思いが膨らんできました。
でもaws lambdaはcloud watch logsへのログ出力があるためfile出力はできません。
webでの参考になるサイトなどから学習し個人的にいい感じの範囲で共通化&class化しました。
作成したクラス
Logging_Class.py
import logging
#コメントアウトのフォーマットは全項目出力版フォーマット
#LOG_FORMAT = '%(asctime)s - %(created)f - %(filename)s - %(funcName)s - %(levelname)s - %(levelno)s - %(lineno)d - %(message)s - %(module)s - %(msecs)d - %(name)s - %(pathname)s - %(process)d - %(processName)s - %(relativeCreated)d - %(thread)d - %(threadName)s'
#チェックした結果使えるフォーマット
LOG_FORMAT = '[%(levelname)s] %(asctime)s %(name)s %(message)s'
class Logger:
def __init__(self,name,lvl):
"""コンストラクター
Args:
name (str): logging名
lvl (str): 出力レベル
"""
self.logger = logging.getLogger(name)
self.logger.setLevel(lvl)
self.defaultlevel = lvl
self.logger.propagate = False
if not self.logger.hasHandlers():
sh = logging.StreamHandler()
handler_format = logging.Formatter(LOG_FORMAT)
sh.setFormatter(handler_format)
self.logger.addHandler(sh)
#infoメッセージ
def info(self,message):
self.logger.info(message)
#exceptionメッセージ
def exception(self,message):
self.logger.exception(message)
#warningメッセージ
def warning(self,message):
self.logger.warning(message)
#debugメッセージ
def debug(self,message):
self.logger.debug(message)
#criticalメッセージ
def critical(self,message):
self.logger.critical(message)
このクラスを呼び出すlambdaをテストで作成
lambda_function.py
import LoggingClass as lc
import common_function as cm
lg = lc.Logger(__name__,'DEBUG')
def lambda_handler(event, context):
lg.info('infoテストです')
lg.debug('debugテストです')
fnc()
cm.fnc_a()
def fnc():
lg.info('fnc呼び出し')
別ファイルの関数を呼び出した時の出力項目を確認するためにcommon_function.pyを作成。
common_function.py
import LoggingClass as lc
mylg = lc.Logger(__name__,'DEBUG')
def fnc_a():
mylg.warning('fnc_aの呼び出し(warning)')
出力結果フォーマット
[INFO] 2023-09-17 12:43:22,126 lambda_function infoテストです
[DEBUG] 2023-09-17 12:43:22,126 lambda_function debugテストです
[INFO] 2023-09-17 12:43:22,127 lambda_function fnc呼び出し
[WARNING] 2023-09-17 12:43:22,127 common_function fnc_aの呼び出し(warning)
こだわりポイント
loggingで準備されているフォーマットはいくつもあるがlambdaで使える項目は限定的である。
ですので、出力項目を使える項目だけにし、フォーマットを作成しました。
テストのために使用した全項目出力版もコメントアウトしてあるのでご自身で内容を確認するときなどにお使いください。
Format | 内容 | テスト結果(sample値) | 所感 |
---|---|---|---|
%(asctime)s | ログの出力時刻 | 2023-09-17 11:23:07,161 | 普通にlambdaで出力できたので使用できる値と判定 |
%(created)f | ログ出力時刻(time.time()によって返される形式) | 1694915993.637037 | UNIX時間?普通には使えない。 |
%(filename)s | pathname のファイル名部分。 | LoggingClass.py | 別ファイルの関数を呼び出しても部品化してしまったことで使えない値。 |
%(funcName)s | ロギングの呼び出しを含む関数の名前。 | info | lambdaだとlog levelが出力されてしまい意味がない。 |
%(levelname)s | メッセージのための文字のロギングレベル (‘DEBUG’, ‘INFO’, ‘WARNING’, ‘ERROR’, ‘CRITICAL’)。 | INFO | ロギングレベルはこれが一番使える。 |
%(levelno)s | メッセージのための数値のロギングレベル (DEBUG, INFO, WARNING, ERROR, CRITICAL)。 | 20 | 上の項目のラベルが使用できるので不要。 |
%(lineno)d | ロギングの呼び出しが発せられたソース行番号 (利用できる場合のみ) | 24 | class化してしまったことで共通classの業弁号が出力されてしまう。使えない。出てほしい! |
%(message)s | msg % args として求められた、ログメッセージ。 | message内容 | これはメインとなるメッセージなので必須です。 |
%(module)s | モジュール (filename の名前部分)。 | LoggingClass | 共通class化してしまったことで使えない項目。 |
%(msecs)d | LogRecord が生成された時刻のミリ秒部分 | 637 | これだけでは何も使えないのでは? |
%(name)s | ロギングに使われたロガーの名前。 | lambda_function | getLogger呼び出し時に__name__を設定すれば有効と判断 |
%(pathname)s | ロギングの呼び出しが発せられたファイルの完全なパス名 (利用できる場合のみ) | /var/task/LoggingClass.py | ロガー名を__name__にすれば不要。 |
%(process)d | プロセス ID (利用可能な場合のみ)。 | 1 | プロセス管理する場合は必要だが、通常処理では不要 |
%(processName)s | プロセス名 (利用可能な場合のみ)。 | MainProcess | 上記理由より同様。 |
%(thread)d | スレッド ID (利用可能な場合のみ)。 | 140220845348288 | マルチスレッド処理を使う場合は必要かも |
%(threadName)s | スレッド名 (利用可能な場合のみ)。 | MainThread | マルチスレッド処理を使う場合は必要かも |
参考url
Discussion