Coverage for src/prosemark/adapters/logger_stdout.py: 100%

16 statements  

« prev     ^ index     » next       coverage.py v7.8.0, created at 2025-09-24 18:08 +0000

1# Copyright (c) 2024 Prosemark Contributors 

2# This software is licensed under the MIT License 

3 

4"""Standard output logger implementation.""" 

5 

6import sys 

7from typing import TextIO 

8 

9from prosemark.ports.logger import Logger 

10 

11 

12class LoggerStdout(Logger): 

13 """Standard output logger implementation. 

14 

15 This implementation provides logging to stdout/stderr streams with: 

16 - Standard log level formatting 

17 - Configurable output streams (stdout for info/debug, stderr for warning/error) 

18 - String formatting support compatible with Python's logging module 

19 - Simple, dependency-free implementation for production use 

20 

21 The logger follows common conventions: 

22 - info/debug messages go to stdout (can be redirected separately) 

23 - warning/error messages go to stderr (for proper error handling) 

24 - Consistent formatting with log level prefixes 

25 """ 

26 

27 def __init__( 

28 self, 

29 info_stream: TextIO = sys.stdout, 

30 error_stream: TextIO = sys.stderr, 

31 ) -> None: 

32 """Initialize logger with specified output streams. 

33 

34 Args: 

35 info_stream: Stream for info and debug messages (default: sys.stdout) 

36 error_stream: Stream for warning and error messages (default: sys.stderr) 

37 

38 """ 

39 self.info_stream = info_stream 

40 self.error_stream = error_stream 

41 

42 def debug(self, msg: object, *args: object, **_kwargs: object) -> None: 

43 """Log detailed diagnostic information for troubleshooting. 

44 

45 Args: 

46 msg: The log message or format string 

47 *args: Positional arguments for string formatting 

48 **kwargs: Keyword arguments (ignored in this implementation) 

49 

50 """ 

51 formatted_msg = str(msg) % args if args else str(msg) # pragma: no cover 

52 print(f'[DEBUG] {formatted_msg}', file=self.info_stream) 

53 

54 def info(self, msg: object, *args: object, **_kwargs: object) -> None: 

55 """Log general operational information. 

56 

57 Args: 

58 msg: The log message or format string 

59 *args: Positional arguments for string formatting 

60 **kwargs: Keyword arguments (ignored in this implementation) 

61 

62 """ 

63 formatted_msg = str(msg) % args if args else str(msg) # pragma: no cover 

64 print(f'[INFO] {formatted_msg}', file=self.info_stream) 

65 

66 def warning(self, msg: object, *args: object, **_kwargs: object) -> None: 

67 """Log warning messages for important events that don't prevent operation. 

68 

69 Args: 

70 msg: The log message or format string 

71 *args: Positional arguments for string formatting 

72 **kwargs: Keyword arguments (ignored in this implementation) 

73 

74 """ 

75 formatted_msg = str(msg) % args if args else str(msg) # pragma: no cover 

76 print(f'[WARNING] {formatted_msg}', file=self.error_stream) 

77 

78 def error(self, msg: object, *args: object, **_kwargs: object) -> None: 

79 """Log error conditions that prevent operations from completing. 

80 

81 Args: 

82 msg: The log message or format string 

83 *args: Positional arguments for string formatting 

84 **kwargs: Keyword arguments (ignored in this implementation) 

85 

86 """ 

87 formatted_msg = str(msg) % args if args else str(msg) # pragma: no cover 

88 print(f'[ERROR] {formatted_msg}', file=self.error_stream) 

89 

90 def exception(self, msg: object, *args: object, **_kwargs: object) -> None: 

91 """Log exception information with error level and traceback. 

92 

93 Args: 

94 msg: The log message or format string 

95 *args: Positional arguments for string formatting 

96 **kwargs: Keyword arguments (ignored in this implementation) 

97 

98 """ 

99 formatted_msg = str(msg) % args if args else str(msg) # pragma: no cover 

100 print(f'[EXCEPTION] {formatted_msg}', file=self.error_stream) # pragma: no cover