2026-06-15 15:53:01 +08:00
|
|
|
import logging
|
2026-06-15 16:33:33 +08:00
|
|
|
import os
|
|
|
|
|
from datetime import datetime
|
2026-06-15 15:53:01 +08:00
|
|
|
|
|
|
|
|
|
2026-06-15 16:33:33 +08:00
|
|
|
def setup_logging(log_dir=None):
|
|
|
|
|
"""Initialize file + console logging. Call once at application startup.
|
|
|
|
|
|
|
|
|
|
log_dir: absolute path to log directory. Defaults to <project_root>/logs/.
|
|
|
|
|
If the directory cannot be created, falls back to console-only logging.
|
|
|
|
|
"""
|
|
|
|
|
if log_dir is None:
|
|
|
|
|
# src/services/log_service.py -> src/services -> src -> project root
|
|
|
|
|
_here = os.path.dirname(os.path.abspath(__file__))
|
|
|
|
|
log_dir = os.path.join(os.path.dirname(os.path.dirname(_here)), "logs")
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
os.makedirs(log_dir, exist_ok=True)
|
|
|
|
|
except OSError as exc:
|
|
|
|
|
logging.basicConfig(
|
|
|
|
|
level=logging.INFO,
|
|
|
|
|
format="%(asctime)s %(name)s %(levelname)s %(message)s",
|
|
|
|
|
)
|
|
|
|
|
logging.getLogger(__name__).warning(
|
|
|
|
|
"Cannot create log directory %s: %s. Falling back to console only.", log_dir, exc
|
|
|
|
|
)
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
|
|
|
|
log_file = os.path.join(log_dir, "app_{}.log".format(timestamp))
|
|
|
|
|
|
|
|
|
|
formatter = logging.Formatter("%(asctime)s %(name)s %(levelname)s %(message)s")
|
|
|
|
|
|
|
|
|
|
root = logging.getLogger()
|
|
|
|
|
root.setLevel(logging.INFO)
|
|
|
|
|
|
|
|
|
|
fh = logging.FileHandler(log_file, encoding="utf-8")
|
|
|
|
|
fh.setFormatter(formatter)
|
|
|
|
|
root.addHandler(fh)
|
|
|
|
|
|
|
|
|
|
sh = logging.StreamHandler()
|
|
|
|
|
sh.setFormatter(formatter)
|
|
|
|
|
root.addHandler(sh)
|
|
|
|
|
|
|
|
|
|
logging.getLogger(__name__).info("Logging initialized. Log file: %s", log_file)
|