Coverage for health / utils / logging_config.py: 96%
26 statements
« prev ^ index » next coverage.py v7.13.4, created at 2026-03-02 17:44 +0800
« prev ^ index » next coverage.py v7.13.4, created at 2026-03-02 17:44 +0800
1"""
2Logging configuration for Garmin Health Sync system.
4Provides structured logging with file and console handlers.
5"""
7import os
8import logging
9import sys
10from pathlib import Path
11from typing import Optional
13from health.config import LOGS_DIR
15DEFAULT_LOG_LEVEL = getattr(logging, os.getenv("LOG_LEVEL", "INFO").upper(), logging.INFO)
17def setup_logger(
18 name: str,
19 log_file: Optional[str] = None,
20 level: int = DEFAULT_LOG_LEVEL,
21) -> logging.Logger:
22 """Set up a logger with console and optional file handlers.
24 Args:
25 name: Logger name (usually __name__)
26 log_file: Optional log file name (relative to LOGS_DIR)
27 level: Logging level (default: INFO)
29 Returns:
30 Configured logger instance
31 """
32 logger = logging.getLogger(name)
33 logger.setLevel(level)
35 # Prevent propagation to parent loggers to avoid duplicate output
36 logger.propagate = False
38 # Avoid duplicate handlers
39 if logger.handlers:
40 return logger
42 # Create formatter
43 formatter = logging.Formatter(
44 fmt="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
45 datefmt="%Y-%m-%d %H:%M:%S",
46 )
48 # Console handler
49 console_handler = logging.StreamHandler(sys.stdout)
50 console_handler.setLevel(level)
51 console_handler.setFormatter(formatter)
52 logger.addHandler(console_handler)
54 # File handler (if log_file specified)
55 if log_file:
56 log_path = LOGS_DIR / log_file
57 file_handler = logging.FileHandler(log_path, encoding="utf-8")
58 file_handler.setLevel(level)
59 file_handler.setFormatter(formatter)
60 logger.addHandler(file_handler)
62 return logger
65# Default logger for the health module
66default_logger = setup_logger("health", log_file="health_sync.log")