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

1""" 

2Logging configuration for Garmin Health Sync system. 

3 

4Provides structured logging with file and console handlers. 

5""" 

6 

7import os 

8import logging 

9import sys 

10from pathlib import Path 

11from typing import Optional 

12 

13from health.config import LOGS_DIR 

14 

15DEFAULT_LOG_LEVEL = getattr(logging, os.getenv("LOG_LEVEL", "INFO").upper(), logging.INFO) 

16 

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. 

23 

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) 

28 

29 Returns: 

30 Configured logger instance 

31 """ 

32 logger = logging.getLogger(name) 

33 logger.setLevel(level) 

34 

35 # Prevent propagation to parent loggers to avoid duplicate output 

36 logger.propagate = False 

37 

38 # Avoid duplicate handlers 

39 if logger.handlers: 

40 return logger 

41 

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 ) 

47 

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) 

53 

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) 

61 

62 return logger 

63 

64 

65# Default logger for the health module 

66default_logger = setup_logger("health", log_file="health_sync.log")