🔥
Pythonでjson形式のログを出力する
1. loggingモジュール と jsonモジュールを使う
ソースコード
import logging
import json
class JsonFormatter(logging.Formatter):
def format(self, record):
# JSONに含めたいフィールドを辞書として定義
log_record = {
"timestamp": self.formatTime(record),
"logger": record.name,
"level": record.levelname,
"message": record.getMessage(),
}
# record.__dict__から追加情報を取得し、log_recordに追加
log_record.update({key: value for key, value in record.__dict__.items() if key not in log_record})
return json.dumps(log_record)
# ロガーの設定
logger = logging.getLogger("json_logger")
logger.setLevel(logging.DEBUG)
# ハンドラーとフォーマッタの設定
handler = logging.StreamHandler()
handler.setFormatter(JsonFormatter())
logger.addHandler(handler)
# ログ出力(追加情報を渡す例)
logger.debug("This is a DEBUG message", extra={"user_id": 123, "transaction_id": "abc123"})
logger.info("This is an INFO message", extra={"user_id": 456, "transaction_id": "def456"})
logger.warning("This is a WARNING message")
logger.error("This is an ERROR message", extra={"error_code": 500})
logger.critical("This is a CRITICAL message", extra={"urgent": True})
出力結果
{"timestamp": "2024-11-04 22:23:53,338", "logger": "json_logger", "level": "DEBUG", "message": "This is a DEBUG message", "name": "json_logger", "msg": "This is a DEBUG message", "args": [], "levelname": "DEBUG", "levelno": 10, "pathname": "<ipython-input-1-4ca55e575783>", "filename": "<ipython-input-1-4ca55e575783>", "module": "<ipython-input-1-4ca55e575783>", "exc_info": null, "exc_text": null, "stack_info": null, "lineno": 28, "funcName": "<module>", "created": 1730726633.338757, "msecs": 338.0, "relativeCreated": 1819.5860385894775, "thread": 8681610752, "threadName": "MainThread", "processName": "MainProcess", "process": 47518, "taskName": null, "user_id": 123, "transaction_id": "abc123"}
{"timestamp": "2024-11-04 22:23:53,338", "logger": "json_logger", "level": "INFO", "message": "This is an INFO message", "name": "json_logger", "msg": "This is an INFO message", "args": [], "levelname": "INFO", "levelno": 20, "pathname": "<ipython-input-1-4ca55e575783>", "filename": "<ipython-input-1-4ca55e575783>", "module": "<ipython-input-1-4ca55e575783>", "exc_info": null, "exc_text": null, "stack_info": null, "lineno": 29, "funcName": "<module>", "created": 1730726633.338881, "msecs": 338.0, "relativeCreated": 1819.7100162506104, "thread": 8681610752, "threadName": "MainThread", "processName": "MainProcess", "process": 47518, "taskName": null, "user_id": 456, "transaction_id": "def456"}
{"timestamp": "2024-11-04 22:23:53,339", "logger": "json_logger", "level": "WARNING", "message": "This is a WARNING message", "name": "json_logger", "msg": "This is a WARNING message", "args": [], "levelname": "WARNING", "levelno": 30, "pathname": "<ipython-input-1-4ca55e575783>", "filename": "<ipython-input-1-4ca55e575783>", "module": "<ipython-input-1-4ca55e575783>", "exc_info": null, "exc_text": null, "stack_info": null, "lineno": 30, "funcName": "<module>", "created": 1730726633.3390179, "msecs": 339.0, "relativeCreated": 1819.8468685150146, "thread": 8681610752, "threadName": "MainThread", "processName": "MainProcess", "process": 47518, "taskName": null}
{"timestamp": "2024-11-04 22:23:53,339", "logger": "json_logger", "level": "ERROR", "message": "This is an ERROR message", "name": "json_logger", "msg": "This is an ERROR message", "args": [], "levelname": "ERROR", "levelno": 40, "pathname": "<ipython-input-1-4ca55e575783>", "filename": "<ipython-input-1-4ca55e575783>", "module": "<ipython-input-1-4ca55e575783>", "exc_info": null, "exc_text": null, "stack_info": null, "lineno": 31, "funcName": "<module>", "created": 1730726633.339106, "msecs": 339.0, "relativeCreated": 1819.9350833892822, "thread": 8681610752, "threadName": "MainThread", "processName": "MainProcess", "process": 47518, "taskName": null, "error_code": 500}
{"timestamp": "2024-11-04 22:23:53,339", "logger": "json_logger", "level": "CRITICAL", "message": "This is a CRITICAL message", "name": "json_logger", "msg": "This is a CRITICAL message", "args": [], "levelname": "CRITICAL", "levelno": 50, "pathname": "<ipython-input-1-4ca55e575783>", "filename": "<ipython-input-1-4ca55e575783>", "module": "<ipython-input-1-4ca55e575783>", "exc_info": null, "exc_text": null, "stack_info": null, "lineno": 32, "funcName": "<module>", "created": 1730726633.339234, "msecs": 339.0, "relativeCreated": 1820.0631141662598, "thread": 8681610752, "threadName": "MainThread", "processName": "MainProcess", "process": 47518, "taskName": null, "urgent": true}
2. loggingモジュール と python-json-loggerモジュールを使う
- python-json-logger 2023年2月22日 v2.0.7 リリース以降更新が止まっていそう
ソースコード
import logging
from pythonjsonlogger import jsonlogger
# ロガーの設定
logger = logging.getLogger("json_logger")
logger.setLevel(logging.DEBUG)
# ハンドラーとフォーマッタの設定
handler = logging.StreamHandler()
formatter = jsonlogger.JsonFormatter(
fmt="%(asctime)s %(name)s %(levelname)s %(message)s"
)
handler.setFormatter(formatter)
logger.addHandler(handler)
# ログ出力(追加情報を渡す例)
logger.debug("This is a DEBUG message", extra={"user_id": 123, "transaction_id": "abc123"})
logger.info("This is an INFO message", extra={"user_id": 456, "transaction_id": "def456"})
logger.warning("This is a WARNING message")
logger.error("This is an ERROR message", extra={"error_code": 500})
logger.critical("This is a CRITICAL message", extra={"urgent": True})
出力結果
{"asctime": "2024-11-04 22:32:40,700", "name": "json_logger", "levelname": "DEBUG", "message": "This is a DEBUG message", "taskName": null, "user_id": 123, "transaction_id": "abc123"}
{"asctime": "2024-11-04 22:32:40,700", "name": "json_logger", "levelname": "INFO", "message": "This is an INFO message", "taskName": null, "user_id": 456, "transaction_id": "def456"}
{"asctime": "2024-11-04 22:32:40,700", "name": "json_logger", "levelname": "WARNING", "message": "This is a WARNING message", "taskName": null}
{"asctime": "2024-11-04 22:32:40,700", "name": "json_logger", "levelname": "ERROR", "message": "This is an ERROR message", "taskName": null, "error_code": 500}
{"asctime": "2024-11-04 22:32:40,700", "name": "json_logger", "levelname": "CRITICAL", "message": "This is a CRITICAL message", "taskName": null, "urgent": true}
3. structlogを使う
- structlog 2024年7月17日 v24.4.0 リリース
ソースコード
import structlog
import logging
# Pythonの標準ログをJSONに出力するための設定
logging.basicConfig(level=logging.DEBUG)
structlog.configure(
processors=[
structlog.processors.TimeStamper(fmt="iso", utc=False),
structlog.processors.JSONRenderer()
],
logger_factory=structlog.stdlib.LoggerFactory(),
)
# ロガーの取得
logger = structlog.get_logger("json_logger")
# ログ出力(追加情報を渡す例)
logger.debug("This is a DEBUG message", user_id=123, transaction_id="abc123")
logger.info("This is an INFO message", user_id=456, transaction_id="def456")
logger.warning("This is a WARNING message")
logger.error("This is an ERROR message", error_code=500)
logger.critical("This is a CRITICAL message", urgent=True)
出力結果
DEBUG:json_logger:{"user_id": 123, "transaction_id": "abc123", "event": "This is a DEBUG message", "timestamp": "2024-11-04T22:37:43.273906"}
INFO:json_logger:{"user_id": 456, "transaction_id": "def456", "event": "This is an INFO message", "timestamp": "2024-11-04T22:37:43.274380"}
WARNING:json_logger:{"event": "This is a WARNING message", "timestamp": "2024-11-04T22:37:43.274477"}
ERROR:json_logger:{"error_code": 500, "event": "This is an ERROR message", "timestamp": "2024-11-04T22:37:43.274561"}
CRITICAL:json_logger:{"urgent": true, "event": "This is a CRITICAL message", "timestamp": "2024-11-04T22:37:43.274663"}
ソースコード 2
import structlog
import logging
from pythonjsonlogger import jsonlogger
# 標準の logging の設定
log_handler = logging.StreamHandler()
formatter = jsonlogger.JsonFormatter(
fmt='%(asctime)s %(name)s %(levelname)s %(message)s'
)
log_handler.setFormatter(formatter)
logging.basicConfig(handlers=[log_handler], level=logging.DEBUG)
# structlog の設定
structlog.configure(
processors=[
structlog.processors.TimeStamper(fmt="iso"),
structlog.stdlib.add_logger_name,
structlog.stdlib.add_log_level,
structlog.processors.JSONRenderer()
],
wrapper_class=structlog.make_filtering_bound_logger(logging.DEBUG),
context_class=dict,
logger_factory=structlog.stdlib.LoggerFactory(),
cache_logger_on_first_use=True,
)
# ロガーの取得
logger = structlog.get_logger("json_logger")
# ログ出力例
logger.debug("This is a DEBUG message", user_id=123, transaction_id="abc123")
logger.info("This is an INFO message", user_id=456, transaction_id="def456")
logger.warning("This is a WARNING message")
logger.error("This is an ERROR message", error_code=500)
logger.critical("This is a CRITICAL message", urgent=True)
出力結果2
{"asctime": "2024-11-04 22:41:59,173", "name": "json_logger", "levelname": "DEBUG", "message": "{\"user_id\": 123, \"transaction_id\": \"abc123\", \"event\": \"This is a DEBUG message\", \"timestamp\": \"2024-11-04T13:41:59.172661Z\", \"logger\": \"json_logger\", \"level\": \"debug\"}", "taskName": null}
{"asctime": "2024-11-04 22:41:59,173", "name": "json_logger", "levelname": "INFO", "message": "{\"user_id\": 456, \"transaction_id\": \"def456\", \"event\": \"This is an INFO message\", \"timestamp\": \"2024-11-04T13:41:59.173167Z\", \"logger\": \"json_logger\", \"level\": \"info\"}", "taskName": null}
{"asctime": "2024-11-04 22:41:59,173", "name": "json_logger", "levelname": "WARNING", "message": "{\"event\": \"This is a WARNING message\", \"timestamp\": \"2024-11-04T13:41:59.173267Z\", \"logger\": \"json_logger\", \"level\": \"warning\"}", "taskName": null}
{"asctime": "2024-11-04 22:41:59,173", "name": "json_logger", "levelname": "ERROR", "message": "{\"error_code\": 500, \"event\": \"This is an ERROR message\", \"timestamp\": \"2024-11-04T13:41:59.173346Z\", \"logger\": \"json_logger\", \"level\": \"error\"}", "taskName": null}
{"asctime": "2024-11-04 22:41:59,173", "name": "json_logger", "levelname": "CRITICAL", "message": "{\"urgent\": true, \"event\": \"This is a CRITICAL message\", \"timestamp\": \"2024-11-04T13:41:59.173423Z\", \"logger\": \"json_logger\", \"level\": \"critical\"}", "taskName": null}
4. django-structlogを使う
- django-structlog 2024年11月時点でレポジトリ更新されている
Discussion