Coverage for yasmon/loggers.py: 100%
87 statements
« prev ^ index » next coverage.py v7.2.2, created at 2023-03-28 10:57 +0000
« prev ^ index » next coverage.py v7.2.2, created at 2023-03-28 10:57 +0000
1from loguru import logger
2from abc import ABC, abstractmethod
3import sys
4import yaml
5import systemd.journal
8class LoggerSyntaxError(Exception):
9 """
10 Raised on logger syntax error
11 """
13 def __init__(self, message="logger syntax error"):
14 self.message = message
15 super().__init__(self.message)
18class AbstractLogger(ABC):
19 """
20 Abstract class from which all logger classes are derived.
22 The preferred way to instatiate a logger is from class
23 method :func:`~from_yaml`.
24 """
26 @abstractmethod
27 def __init__(self):
28 self.check_imp_level()
29 self.id = self.add_logger()
30 logger.info(f'logger ({self.__class__}) initialized')
32 @classmethod
33 @abstractmethod
34 def from_yaml(cls, data: str):
35 """
36 A class method for constructing a logger from a YAML document.
38 :param data: yaml data
40 :return: new instance
41 """
43 logger.debug(f'logger defined form yaml \n{data}')
45 def add_logger(self):
46 """
47 Add logger with logging level.
49 :param level: logging level (lower case)
50 """
52 return logger.add(self.handler,
53 format=self.format,
54 level=self.level.upper())
56 def check_imp_level(self):
57 imp_levels = [
58 'trace',
59 'debug',
60 'info',
61 'success',
62 'warning',
63 'error',
64 'critical'
65 ]
67 if self.level not in imp_levels:
68 raise LoggerSyntaxError(f"""\
69 in {self.__class__} invalid logger level {self.level}
70 """)
73class StdErrLogger(AbstractLogger):
74 """
75 `stderr` logger.
77 The preferred way to instatiate is from class
78 method :func:`~from_yaml`.
79 """
81 def __init__(self, level: str = 'debug', format: str = (
82 "<level>{level: <8}</level> | "
83 "<cyan>{name}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> | " # noqa
84 "<level>{message}</level>"
85 )):
86 self.handler = sys.stderr
87 self.level = level
88 self.format = format
89 super().__init__()
91 @classmethod
92 def from_yaml(cls, data: str):
93 """
94 A class method for constructing a stderr logger from a YAML document.
96 :param data: yaml data
98 :return: new instance
99 """
101 try:
102 parsed = yaml.safe_load(data)
103 super().from_yaml(data)
104 except yaml.YAMLError as err:
105 raise LoggerSyntaxError(err)
107 if parsed is not None and 'level' in parsed:
108 if isinstance(parsed['level'], str):
109 return cls(parsed['level'])
110 else:
111 raise LoggerSyntaxError('in log_stderr expected '
112 'level to be of type str')
113 else:
114 return cls()
117class FileLogger(AbstractLogger):
118 """
119 Logger logging into a file
121 The preferred way to instatiate is from class
122 method :func:`~from_yaml`.
123 """
125 def __init__(self, path: str, level: str = 'debug',
126 format: str = ("<level>{level: <8}</level> | "
127 "<cyan>{name}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> | " # noqa
128 "<level>{message}</level>")):
129 self.handler = path
130 self.path = path
131 self.level = level
133 self.format = format
134 super().__init__()
136 @classmethod
137 def from_yaml(cls, data: str):
138 """
139 A class method for constructing a stderr logger from a YAML document.
141 :param data: yaml data
143 :return: new instance
144 """
146 try:
147 parsed = yaml.safe_load(data)
148 super().from_yaml(data)
149 except yaml.YAMLError as err:
150 raise LoggerSyntaxError(err)
152 if parsed is not None and 'path' in parsed:
153 path = parsed['path']
154 if not isinstance(path, str):
155 raise LoggerSyntaxError('in log_file expected '
156 'path to be of type str')
157 else:
158 raise LoggerSyntaxError('in logger log_file path is missing')
160 if parsed is not None and 'level' in parsed:
161 level = parsed['level']
162 if not isinstance(level, str):
163 raise LoggerSyntaxError('in log_file expected '
164 'level to be of type str')
166 return cls(path, level)
168 return cls(path)
171class JournalLogger(AbstractLogger):
172 """
173 System journal logger.
175 The preferred way to instatiate is from class
176 method :func:`~from_yaml`.
177 """
179 def __init__(self, level: str = 'debug', format: str = (
180 "<level>{level: <8}</level> | "
181 "<cyan>{name}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> | " # noqa
182 "<level>{message}</level>"
183 )):
184 self.handler = systemd.journal.JournalHandler()
185 self.level = level
186 self.format = format
187 super().__init__()
189 @classmethod
190 def from_yaml(cls, data: str):
191 """
192 A class method for constructing a system journal
193 logger from a YAML document.
195 :param data: yaml data
197 :return: new instance
198 """
200 try:
201 parsed = yaml.safe_load(data)
202 super().from_yaml(data)
203 except yaml.YAMLError as err:
204 raise LoggerSyntaxError(f'in log_journal {err}')
206 if parsed is not None and 'level' in parsed:
207 level = parsed['level']
208 if not isinstance(level, str):
209 raise LoggerSyntaxError('in log_journal expected '
210 'level to be of type str')
211 else:
212 return cls(level)
214 return cls()