py.lib.aw_log
py.lib.aw_log/src/aw_log/__init__.py
.. 1.202606.2 . Проблема в разборе расширенного сообщения при некоторых параметрах
| 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 |