Coverage for src/pytribeam/GUI/common/logging_config.py: 0%

44 statements  

« prev     ^ index     » next       coverage.py v7.6.1, created at 2026-06-16 18:30 +0000

1"""Logging configuration for GUI application. 

2 

3This module provides standardized logging setup for the pytribeam GUI, 

4including file and console handlers with appropriate formatting. 

5""" 

6 

7import logging 

8import os 

9from datetime import datetime 

10from pathlib import Path 

11from typing import Optional 

12 

13 

14def setup_logging( 

15 log_dir: Optional[Path] = None, 

16 level: int = logging.INFO, 

17 console_level: int = logging.WARNING, 

18 log_prefix: str = "pytribeam_gui", 

19) -> logging.Logger: 

20 """Configure logging for the GUI application. 

21 

22 Sets up both file and console logging with appropriate formatting. 

23 Log files are named with timestamps to avoid overwriting. 

24 

25 Args: 

26 log_dir: Directory to store log files. If None, uses LOCALAPPDATA/pytribeam/logs 

27 level: Logging level for file handler (default: INFO) 

28 console_level: Logging level for console handler (default: WARNING) 

29 log_prefix: Prefix for log filenames (default: 'pytribeam_gui') 

30 

31 Returns: 

32 Configured logger instance 

33 

34 Example: 

35 logger = setup_logging() 

36 logger.info("Application started") 

37 logger.error("An error occurred", exc_info=True) 

38 """ 

39 # Determine log directory 

40 if log_dir is None: 

41 base_dir = os.getenv("LOCALAPPDATA", os.path.expanduser("~/.local/share")) 

42 log_dir = Path(base_dir) / "pytribeam" / "logs" 

43 

44 log_dir = Path(log_dir) 

45 log_dir.mkdir(parents=True, exist_ok=True) 

46 

47 # Create log filename with timestamp 

48 timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") 

49 log_file = log_dir / f"{log_prefix}_{timestamp}.log" 

50 

51 # Create formatters 

52 file_formatter = logging.Formatter( 

53 fmt="%(asctime)s - %(name)s - %(levelname)s - %(message)s", 

54 datefmt="%Y-%m-%d %H:%M:%S", 

55 ) 

56 

57 console_formatter = logging.Formatter( 

58 fmt="%(levelname)s: %(message)s", 

59 ) 

60 

61 # Create file handler 

62 file_handler = logging.FileHandler(log_file, encoding="utf-8") 

63 file_handler.setLevel(level) 

64 file_handler.setFormatter(file_formatter) 

65 

66 # Create console handler 

67 console_handler = logging.StreamHandler() 

68 console_handler.setLevel(console_level) 

69 console_handler.setFormatter(console_formatter) 

70 

71 # Configure root logger for pytribeam 

72 logger = logging.getLogger("pytribeam.GUI") 

73 logger.setLevel(level) 

74 

75 # Remove existing handlers to avoid duplicates 

76 logger.handlers.clear() 

77 

78 # Add handlers 

79 logger.addHandler(file_handler) 

80 logger.addHandler(console_handler) 

81 

82 logger.info(f"Logging initialized. Log file: {log_file}") 

83 

84 return logger 

85 

86 

87def get_logger(name: str) -> logging.Logger: 

88 """Get a logger instance for a specific module. 

89 

90 This should be called at the module level to get a properly 

91 namespaced logger. 

92 

93 Args: 

94 name: Module name (typically __name__) 

95 

96 Returns: 

97 Logger instance 

98 

99 Example: 

100 logger = get_logger(__name__) 

101 logger.debug("Debug message") 

102 """ 

103 return logging.getLogger(f"pytribeam.GUI.{name}") 

104 

105 

106def cleanup_old_logs(log_dir: Optional[Path] = None, keep_days: int = 30): 

107 """Remove log files older than specified days. 

108 

109 Args: 

110 log_dir: Directory containing log files. If None, uses default location 

111 keep_days: Number of days to keep logs (default: 30) 

112 """ 

113 if log_dir is None: 

114 base_dir = os.getenv("LOCALAPPDATA", os.path.expanduser("~/.local/share")) 

115 log_dir = Path(base_dir) / "pytribeam" / "logs" 

116 

117 log_dir = Path(log_dir) 

118 if not log_dir.exists(): 

119 return 

120 

121 cutoff_time = datetime.now().timestamp() - (keep_days * 24 * 60 * 60) 

122 

123 for log_file in log_dir.glob("*.log"): 

124 if log_file.stat().st_mtime < cutoff_time: 

125 try: 

126 log_file.unlink() 

127 except OSError: 

128 pass # Ignore errors during cleanup