py.lib.aw_log
5:1e93862d5063
Go to Latest
py.lib.aw_log/src/aw_log/file.py
.. 1.202410.1
. Изменение структуры проекта под новые вызовы SDK Python
. Убраны версии с отдельный файлов, они кажутся избыточними.
* Изменено формирование записей о исключении, для большего соответствия логике журналирования
- Перенос `NullLog` на уровень модуля и повышение его универсальности для замены других классов.
2 # devel.a0fs.ru -- aw_log.file -- v0.r202402.1
5 from time import monotonic, ctime
6 from datetime import date
7 from typing import TextIO, Optional
8 from threading import RLock
9 from os.path import join as p_join, abspath, split as p_split
11 from . import AbstractLogBase
13 TIME_TO_FLUSH: int = 120 # Время по умолчанию с момента прошлого сброса лога,
14 # после которого, выполняется принудительный сброс буферов
17 class NullLog(AbstractLogBase):
18 def _write(self, mark: str, msg: Any):
22 class AbstractFileLog(AbstractLogBase):
23 def __init__(self, prefix: str = 'main'):
24 super().__init__(prefix)
25 self.fd: Optional[TextIO] = None
28 def _write(self, mark: str, msg: Any):
30 raise ValueError(f'Не определён файл логирования')
36 for l in super()._write_helper(mark, msg):
37 self.fd.write(f'{tm} | {l}')
43 class FileLog(AbstractFileLog):
45 def _open_file(file_name: str):
46 return open(file_name, 'a', encoding='utf-8')
48 def __init__(self, prefix: str = 'main',
49 file_name: Optional[str] = None,
50 file_obj: Optional[TextIO] = None,
51 time_to_flush: int = TIME_TO_FLUSH
54 super().__init__(prefix=prefix)
55 self.fd: Optional[TextIO] = None
57 self.flush_time = monotonic()
58 self.time_to_flush = time_to_flush # Время с момента прошлого сброса лога,
59 # после которого, выполняется принудительный сброс буферов
61 if file_name is not None:
62 self.fd = self._open_file(file_name)
68 raise ValueError('Не задан файл для записи журналов')
70 def flush(self, time_mark: float = None):
72 time_mark = monotonic()
74 self.flush_time = time_mark
83 if self.fd is not None:
88 def _flush_event(self):
90 if t - self.flush_time >= self.time_to_flush:
93 def _write(self, mark: str, msg: Any):
94 super()._write(mark=mark, msg=msg)
98 def sub_log(self, name: str):
100 raise ValueError('Попытка использовать закрытый файл журнала')
102 return self.__class__(f'{self.prefix}/{name}', file_obj=self.fd, time_to_flush=self.time_to_flush)
105 class LogrotateFile(FileLog):
108 prefix: str = 'main',
109 file_obj: Optional[TextIO] = None,
110 time_to_flush: int = TIME_TO_FLUSH):
114 super().__init__(prefix=prefix, file_name=f'{file_base}-{d}.log', time_to_flush=time_to_flush)
116 super().__init__(prefix=prefix, file_obj=file_obj, time_to_flush=time_to_flush)
118 self.logrotate_base = file_base
119 self.logrotate_date = d
122 def make(cls, directory: str = '.', prefix: str = 'main', time_to_flush: int = TIME_TO_FLUSH):
123 if len(p_split(prefix)) > 1:
124 raise ValueError(f'Префикс журналирования не должен быть похож '
125 f'на пусть файловой системы, убери знак разделения директорий: {prefix}')
127 directory = abspath(directory)
128 file_base = p_join(directory, prefix)
129 return cls(prefix=prefix, file_base=file_base, time_to_flush=time_to_flush)
131 def flush(self, time_mark: float = None, no_rotate: bool = False):
134 if self.logrotate_date != d:
135 self.logrotate_rotate()
138 super().flush(time_mark=time_mark)
140 def logrotate_rotate(self):
142 file_name = f'{self.logrotate_base}-{d}.log'
144 self.fd = self._open_file(file_name)
145 self.logrotate_date = d
146 self.flush(no_rotate=True)
148 def sub_log(self, name: str):
149 return self.__class__(
150 file_base=self.logrotate_base,
151 file_obj=self.fd, prefix=f'{self.prefix}/{name}',
152 time_to_flush=self.time_to_flush