Coverage for src/inheritance_calculator_core/utils/logger.py: 0%
55 statements
« prev ^ index » next coverage.py v7.11.0, created at 2025-10-17 05:31 +0900
« prev ^ index » next coverage.py v7.11.0, created at 2025-10-17 05:31 +0900
1"""
2ログ管理モジュール
4アプリケーション全体で使用するロガーを提供します。
5"""
7import logging
8import sys
9from logging.handlers import RotatingFileHandler
10from pathlib import Path
11from typing import Optional
13from .config import settings
14from .exceptions import LoggingError
17def setup_logger(
18 name: str,
19 log_file: Optional[Path] = None,
20 level: Optional[str] = None,
21) -> logging.Logger:
22 """
23 ロガーをセットアップします。
25 Args:
26 name: ロガー名
27 log_file: ログファイルパス(Noneの場合は設定ファイルから取得)
28 level: ログレベル(Noneの場合は設定ファイルから取得)
30 Returns:
31 設定済みのロガー
33 Raises:
34 LoggingError: ロガーのセットアップに失敗した場合
35 """
36 try:
37 logger = logging.getLogger(name)
39 # 既にハンドラが設定されている場合はクリア(再設定可能に)
40 if logger.handlers:
41 logger.handlers.clear()
43 # ログレベルの設定
44 try:
45 log_level = level or (settings.log.level if settings else "INFO")
46 logger.setLevel(getattr(logging, log_level.upper()))
47 except AttributeError:
48 # settingsがNoneの場合のフォールバック
49 logger.setLevel(logging.INFO)
50 log_level = "INFO"
52 # フォーマッタの設定
53 formatter = logging.Formatter(
54 fmt="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
55 datefmt="%Y-%m-%d %H:%M:%S",
56 )
58 # コンソールハンドラの設定
59 console_handler = logging.StreamHandler(sys.stdout)
60 console_handler.setLevel(logging.INFO)
61 console_handler.setFormatter(formatter)
62 logger.addHandler(console_handler)
64 # ファイルハンドラの設定(settingsがある場合のみ)
65 if log_file is None and settings:
66 try:
67 log_file = settings.logs_dir / settings.log.file.split("/")[-1]
68 except AttributeError:
69 # settingsの属性にアクセスできない場合はファイルハンドラをスキップ
70 log_file = None
72 if log_file is not None:
73 try:
74 log_file.parent.mkdir(parents=True, exist_ok=True)
75 except OSError as e:
76 raise LoggingError(f"Failed to create log directory: {log_file.parent}") from e
78 try:
79 max_bytes = settings.log.max_bytes if settings else 10485760
80 backup_count = settings.log.backup_count if settings else 5
82 file_handler = RotatingFileHandler(
83 log_file,
84 maxBytes=max_bytes,
85 backupCount=backup_count,
86 encoding="utf-8",
87 )
88 file_handler.setLevel(getattr(logging, log_level.upper()))
89 file_handler.setFormatter(formatter)
90 logger.addHandler(file_handler)
91 except OSError as e:
92 raise LoggingError(f"Failed to create log file handler: {log_file}") from e
94 # プロパゲーションを無効化(重複ログ防止)
95 logger.propagate = False
97 return logger
99 except Exception as e:
100 if isinstance(e, LoggingError):
101 raise
102 raise LoggingError(f"Failed to setup logger '{name}'") from e
105# ロガーキャッシュ
106_logger_cache: dict[str, logging.Logger] = {}
108# デフォルトロガー
109default_logger = setup_logger("inheritance_calculator")
110_logger_cache["inheritance_calculator"] = default_logger
113def get_logger(name: str) -> logging.Logger:
114 """
115 指定された名前のロガーを取得します(キャッシュ付き)。
117 Args:
118 name: ロガー名
120 Returns:
121 ロガー
122 """
123 if name not in _logger_cache:
124 _logger_cache[name] = setup_logger(name)
125 return _logger_cache[name]