Coverage for src/semware/utils/logging.py: 67%

15 statements  

« prev     ^ index     » next       coverage.py v7.10.6, created at 2025-09-09 02:15 -0700

1"""Logging configuration using Loguru.""" 

2 

3import sys 

4from pathlib import Path 

5 

6from loguru import logger 

7 

8 

9def setup_logging( 

10 level: str = "INFO", 

11 log_file: str | None = None, 

12 rotation: str = "10 MB", 

13 retention: str = "1 month", 

14 compression: str = "zip", 

15) -> None: 

16 """Setup logging configuration with Loguru. 

17 

18 Args: 

19 level: Log level (DEBUG, INFO, WARNING, ERROR, CRITICAL) 

20 log_file: Path to log file, if None only console logging 

21 rotation: Log file rotation policy 

22 retention: Log file retention policy 

23 compression: Compression for rotated files 

24 """ 

25 # Remove default handler 

26 logger.remove() 

27 

28 # Add console handler with colors 

29 logger.add( 

30 sys.stderr, 

31 level=level, 

32 format="<green>{time:YYYY-MM-DD HH:mm:ss}</green> | " 

33 "<level>{level: <8}</level> | " 

34 "<cyan>{name}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> - " 

35 "<level>{message}</level>", 

36 colorize=True, 

37 ) 

38 

39 # Add file handler if specified 

40 if log_file: 

41 log_path = Path(log_file) 

42 log_path.parent.mkdir(parents=True, exist_ok=True) 

43 

44 logger.add( 

45 str(log_path), 

46 level=level, 

47 format="{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {name}:{function}:{line} - {message}", 

48 rotation=rotation, 

49 retention=retention, 

50 compression=compression, 

51 enqueue=True, # For thread safety 

52 ) 

53 

54 logger.info(f"Logging configured with level: {level}") 

55 if log_file: 

56 logger.info(f"Log file: {log_file}") 

57 

58 

59def get_logger(name: str): 

60 """Get a logger instance for the given name. 

61 

62 Args: 

63 name: Logger name, typically __name__ 

64 

65 Returns: 

66 Logger instance 

67 """ 

68 return logger.bind(name=name)