py.lib.aw_log

Yohn Y. 2026-06-23 Parent:1e93862d5063 Child:e673daec06dc

8:7caffeee7dca Go to Latest

py.lib.aw_log/src/aw_log/__init__.py

.. 1.202606.2 . Проблема в разборе расширенного сообщения при некоторых параметрах

History
awgur@0 1 # coding: utf-8
awgur@0 2 """ Реализация классов логирования
awgur@0 3
awgur@0 4 Метки в журнале о уровне сообщения:
awgur@0 5 "`": Debug
awgur@0 6 ".": Info
awgur@0 7 "*": Warning
awgur@0 8 "!": Error
awgur@0 9 "#": Alert
awgur@0 10
awgur@0 11 """
awgur@0 12
awgur@0 13 from time import monotonic
awgur@0 14 from datetime import timedelta
awgur@0 15 from traceback import extract_tb, extract_stack
awgur@0 16 from typing import Optional, Any, Iterable
awgur@0 17 from sys import exc_info
awgur@0 18
awgur@0 19
awgur@8 20 class Timing:
awgur@8 21 """\
awgur@8 22 Организация работы с таймерами
awgur@8 23 """
awgur@0 24 def __init__(self, name: Optional[str] = None):
awgur@0 25 if name is None:
awgur@0 26 self.prefix = ''
awgur@0 27
awgur@0 28 else:
awgur@0 29 self.prefix = f'{name} :: '
awgur@0 30
awgur@8 31 self.ts_all = monotonic()
awgur@8 32 self.ts = self.ts_all
awgur@0 33
awgur@0 34 def get_time(self):
awgur@0 35 return monotonic() - self.ts
awgur@0 36
awgur@0 37 def reset(self):
awgur@0 38 self.ts = monotonic()
awgur@8 39 self.ts_all = self.ts
awgur@0 40
awgur@0 41 def __str__(self):
awgur@0 42 ts = monotonic()
awgur@8 43 return self.prefix + '%s(%.4f)' % (timedelta(seconds=(ts - self.ts_all)), ts - self.ts)
awgur@0 44
awgur@0 45 def __call__(self, msg):
awgur@0 46 _buf = f'{self} | {msg}'
awgur@0 47 self.ts = monotonic()
awgur@0 48 return _buf
awgur@0 49
awgur@0 50
awgur@8 51 class AbstractLogBase:
awgur@0 52 def __init__(self, prefix: str = 'main'):
awgur@0 53 self.prefix = prefix
awgur@0 54
awgur@0 55 def _write_helper(self, mark: str, msg: Any) -> Iterable[str]:
awgur@0 56 for l in str(msg).splitlines():
awgur@1 57 yield f'{mark} {self.prefix} | {l}\n'
awgur@0 58
awgur@0 59 def _write(self, mark: str, msg: Any):
awgur@0 60 raise NotImplemented(f'Метод write не определён для класса "{type(self).__name__}"')
awgur@0 61
awgur@0 62 def __call__(self, msg):
awgur@0 63 self._write('.', msg)
awgur@0 64
awgur@0 65 def err(self, msg):
awgur@0 66 self._write('!', msg)
awgur@0 67
awgur@0 68 def warn(self, msg):
awgur@0 69 self._write('*', msg)
awgur@0 70
awgur@0 71 def alert(self, msg):
awgur@0 72 self._write('#', msg)
awgur@0 73
awgur@0 74 def debug(self, msg):
awgur@0 75 self._write('`', msg)
awgur@0 76
awgur@0 77 @staticmethod
awgur@0 78 def get_timing(name: Optional[str] = None):
awgur@0 79 return Timing(name)
awgur@0 80
awgur@8 81 @staticmethod
awgur@8 82 def format_msg(msg: str, **kwa) -> str:
awgur@8 83 """\
awgur@8 84 Создаём сообщение, более дружелюбное к средствам разбора логов.
awgur@8 85 Ориентир на ``victoria_logs`` и её ``unpack_logfmt``
awgur@8 86
awgur@8 87 :param msg: Основное сообщение
awgur@8 88 :param kwa: Набор ключ-значение, для добавления в сообщения в качестве
awgur@8 89 разбираемых системой элементов, пригодных для фильтрации
awgur@8 90 :returns: Строку, которую необходимо отправить в лог методом с нужным уровнем важности.
awgur@8 91 """
awgur@8 92 data = ''
awgur@8 93 for k, v in kwa.items():
awgur@8 94 _v = str(v)
awgur@8 95 if v.find(' ') != -1:
awgur@8 96 v = f'"{v}"'
awgur@8 97
awgur@8 98 data += f' {k}={v}'
awgur@8 99
awgur@8 100 if not data:
awgur@8 101 return msg
awgur@8 102
awgur@8 103 else:
awgur@8 104 return f'{msg} |{data}'
awgur@8 105
awgur@0 106 def sub_log(self, name: str):
awgur@0 107 return self.__class__(f'{self.prefix}/{name}')
awgur@0 108
awgur@0 109 def excpt(self, msg, e_class=None, e_obj=None, e_tb=None, stack_skip=0):
awgur@0 110 if e_class is None:
awgur@0 111 e_class, e_obj, e_tb = exc_info()
awgur@0 112
awgur@0 113 tb_data_tb = list(extract_tb(e_tb))[::-1]
awgur@0 114 tb_data_stack = list(extract_stack())[::-1][(2 + stack_skip):]
awgur@5 115 self.alert(msg)
awgur@5 116 self.alert('--- EXCEPTION ---')
awgur@5 117 self.alert(f' {e_class.__name__} ({e_obj})')
awgur@5 118 self.alert('--- TRACEBACK ---')
awgur@0 119 for _tb_file, _tb_line, _tb_func, _tb_text in tb_data_tb:
awgur@5 120 self.alert(f'File: {_tb_file}, line {_tb_line} in {_tb_func}')
awgur@5 121 self.alert(f' {_tb_text}')
awgur@0 122
awgur@0 123 self.err('>>> Exception Handler <<<')
awgur@0 124 for _tb_file, _tb_line, _tb_func, _tb_text in tb_data_stack:
awgur@5 125 self.alert(f'File: {_tb_file}, line {_tb_line} in {_tb_func}')
awgur@5 126 self.alert(f' {_tb_text}')
awgur@5 127
awgur@5 128 self.alert('--- END EXCEPTION ---')
awgur@5 129
awgur@5 130
awgur@5 131 class NullLog(AbstractLogBase):
awgur@5 132 def _write(self, mark: str, msg: Any):
awgur@5 133 pass
awgur@5 134
awgur@5 135 def __init__(self, *a, **kwa):
awgur@5 136 super().__init__('n')
awgur@0 137
awgur@5 138 def sub_log(self, name: str):
awgur@5 139 return self
awgur@5 140
awgur@5 141 @classmethod
awgur@5 142 def make(cls, *a, **kwa):
awgur@5 143 return cls()
awgur@5 144
awgur@5 145 def flush(self, *a, **kwa):
awgur@5 146 pass
awgur@5 147
awgur@5 148 @staticmethod
awgur@5 149 def init_syslog(ident):
awgur@5 150 pass