背景
普段は loguru を使っているが、外部ライブラリを追加できない環境でPython標準ライブラリの logging を使いたい。
要件は以下。
- コンソールとファイルの両方に出力
- ログファイルは
<root>/logs/yyyymmddThhmmss.log -
rootは呼び出し元からPathで渡す - ログディレクトリ名は引数で変更可能(デフォルトは
"logs") - ファイルにはミリ秒まで記録
- ミリ秒の区切りは
.にする - コンソールではミリ秒を省略
- loggingの設定は別ファイルにまとめる
構成
loggingの設定は logging_config.py に切り出す。
project/
├─ main.py
├─ logging_config.py
└─ logs/
logging_config.py
import logging
from datetime import datetime
from pathlib import Path
def setup_logging(
root: Path,
log_dir: str = "logs",
) -> None:
log_dir_path = root / log_dir
log_dir_path.mkdir(parents=True, exist_ok=True)
file_handler = logging.FileHandler(
log_dir_path / f"{datetime.now():%Y%m%dT%H%M%S}.log",
encoding="utf-8",
)
file_handler.setFormatter(logging.Formatter(
"%(asctime)s.%(msecs)03d | %(levelname)s | %(message)s",
datefmt="%Y-%m-%d %H:%M:%S",
))
console_handler = logging.StreamHandler()
console_handler.setFormatter(logging.Formatter(
"%(asctime)s | %(levelname)s | %(message)s",
datefmt="%Y-%m-%d %H:%M:%S",
))
logging.basicConfig(
level=logging.INFO,
handlers=[file_handler, console_handler],
)
main.py
呼び出し側で setup_logging() を一度実行し、logging.getLogger(__name__) でloggerを取得する。
import logging
from pathlib import Path
from logging_config import setup_logging
root = Path(__file__).resolve().parent
setup_logging(root)
logger = logging.getLogger(__name__)
logger.info("start")
logger.warning("something happened")
logger.error("failed")
デフォルトでは、以下のようなログファイルが作成される。
<root>/logs/20260906T073012.log
出力例
コンソールにはミリ秒なしで出力される。
2026-09-06 07:30:12 | INFO | start
2026-09-06 07:30:13 | WARNING | something happened
2026-09-06 07:30:14 | ERROR | failed
ログファイルにはミリ秒まで記録される。
2026-09-06 07:30:12.345 | INFO | start
2026-09-06 07:30:13.012 | WARNING | something happened
2026-09-06 07:30:14.891 | ERROR | failed
ファイル側では、
"%(asctime)s.%(msecs)03d | %(levelname)s | %(message)s"
としているため、ミリ秒まで記録される。
一方、コンソール側では %(msecs) を指定していないため、秒までの表示になる。
ログディレクトリを変更する
log_dir のデフォルトは "logs" なので、
setup_logging(root)
なら、
<root>/logs/
に出力される。
別のディレクトリに出力したければ、
setup_logging(root, log_dir="output/logs")
とする。
この場合は、
<root>/output/logs/
にログファイルが作成される。
mkdir(parents=True, exist_ok=True) としているため、途中のディレクトリも自動的に作成される。
複数モジュールから使う
setup_logging() はアプリケーションのエントリーポイントで一度だけ実行する。
例えば、
project/
├─ main.py
├─ logging_config.py
├─ loader.py
├─ analyzer.py
└─ logs/
の場合、main.py でloggingを設定する。
setup_logging(root)
logger = logging.getLogger(__name__)
loader.py や analyzer.py では設定を繰り返さず、それぞれloggerを取得するだけでよい。
import logging
logger = logging.getLogger(__name__)
def load_data() -> None:
logger.info("loading data")
logging.getLogger(__name__) とすることで、各モジュールの名前を持ったloggerを使用しつつ、エントリーポイントで設定したHandlerを共通して利用できる。
まとめ
Python標準の logging は loguru と比べると初期設定が長い。
ただし、設定部分を logging_config.py の setup_logging() にまとめてしまえば、エントリーポイント側は、
setup_logging(root)
logger = logging.getLogger(__name__)
logger.info("start")
程度で済む。
また、各モジュールでは、
logger = logging.getLogger(__name__)
だけで同じlogging設定を利用できる。
外部ライブラリを追加できない環境でも、標準ライブラリだけでコンソールとファイルへのログ出力を比較的シンプルに扱える。