pythonのloggingでは、ログのタイムスタンプは time.time()
で生成されるのですが、 time
モジュールで使用可能なディレクティブの関係でタイムスタンプの形式に制限があります。
なので、 datetime
を使ってISO8601などに変換できるようにします。
(参考)
logging
モジュールでは以下でミリ秒を後から付け足す形で整形していますが、ここでは書式化演算子( %
)を使っています。
https://github.com/python/cpython/blob/v3.11.2/Lib/logging/__init__.py#L630
ミリ秒は独自で計算されている様子。
https://github.com/python/cpython/blob/v3.11.2/Lib/logging/__init__.py#L337
ISO8601にする
ハンドラにフォーマットを設定する時に、 logging.Formatter
クラスの formatTime()
をカスタムしたものを使用すればできます。
record.created
にタイムスタンプがUNIX時間(typeはfloat)で格納されています。
import logging
from datetime import datetime, timedelta, timezone
class ISOTimeFormatter(logging.Formatter):
def formatTime(self, record: logging.LogRecord, datefmt=None):
tz_jst = timezone(timedelta(hours=+9), 'JST')
ct = datetime.fromtimestamp(record.created, tz=tz_jst)
s = ct.isoformat(timespec="microseconds")
return s
logger = logging.getLogger()
fmt = ISOTimeFormatter("%(asctime)s - %(message)s") # logging.Formatterの代わりに自作のクラスを使う
sh = logging.StreamHandler()
sh.setFormatter(fmt)
logger.addHandler(sh)
logger.setLevel(logging.INFO)
あとは logger.info('hello')
などで出力するだけです。 %(asctime)s
がそのままISO8601のタイムスタンプになります。
2023-03-20T21:01:22.279373+09:00 - hello
その他の書式にする
ほとんど同じ要領ですが、 logging.Formatter
は datefmt
を指定することができるので、以下のようにしてもよいと思います。
import logging
from datetime import datetime, timedelta, timezone
class DatetimeFormatter(logging.Formatter):
def formatTime(self, record: logging.LogRecord, datefmt=None):
if datefmt is None:
datefmt = "%Y-%m-%d %H:%M:%S,%03d" # logging.Formatterのデフォルトと同じ形式
TZ_JST = timezone(timedelta(hours=+9), 'JST')
created_time = datetime.fromtimestamp(record.created, tz=TZ_JST)
s = created_time.strftime(datefmt)
return s
logger = logging.getLogger()
fmt = DatetimeFormatter("%(asctime)s - %(message)s", datefmt="%Y-%m-%dT%H:%M:%S.%f%z") # ここでフォーマットを指定する
sh = logging.StreamHandler()
sh.setFormatter(fmt)
logger.addHandler(sh)
logger.setLevel(logging.INFO)
出力すると以下のようになります。
2023-03-20T21:11:27.637558+0900 - hello