py.lib

Yohn Y. 2023-01-28 Parent:d9a3784f681b Child:bfc3a109c06c

43:6f8bea109183 Browse Files

. Наведение порядка в коде логирования

log/log_confile.py log/log_syslog.py log/slog_console.py log/slog_syslogger.py log/tiny_slog.py

     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/log/log_confile.py	Sat Jan 28 16:39:53 2023 +0300
     1.3 @@ -0,0 +1,246 @@
     1.4 +# coding: utf-8
     1.5 +""" Логирование на консоль
     1.6 +
     1.7 +Метки в журнале о уровне сообщения:
     1.8 +  "`": Debug
     1.9 +  ".": Info
    1.10 +  "*": Warning
    1.11 +  "!": Error
    1.12 +  "#": Alert
    1.13 +
    1.14 +"""
    1.15 +
    1.16 +from time import monotonic, ctime
    1.17 +from datetime import timedelta, date
    1.18 +from traceback import extract_tb, extract_stack
    1.19 +from sys import exc_info, stderr, stdout
    1.20 +from typing import Optional, TextIO, Any
    1.21 +from os.path import join as p_join, abspath
    1.22 +from threading import RLock
    1.23 +
    1.24 +
    1.25 +TIME_TO_FLUSH: int = 120    # Время по умолчанию с момента прошлого сброса лога,
    1.26 +                            # после которого, выполняется принудительный сброс буферов
    1.27 +
    1.28 +
    1.29 +class Timing(object):
    1.30 +    def __init__(self, name: Optional[str] = None):
    1.31 +        if name is None:
    1.32 +            self.prefix = ''
    1.33 +
    1.34 +        else:
    1.35 +            self.prefix = f'{name} :: '
    1.36 +
    1.37 +        self.tsAll = monotonic()
    1.38 +        self.ts = self.tsAll
    1.39 +
    1.40 +    def get_time(self):
    1.41 +        return monotonic() - self.ts
    1.42 +
    1.43 +    def reset(self):
    1.44 +        self.ts = monotonic()
    1.45 +        self.tsAll = self.ts
    1.46 +
    1.47 +    def __str__(self):
    1.48 +        ts = monotonic()
    1.49 +        return self.prefix + '%s(%.4f)' % (timedelta(seconds=(ts - self.tsAll)), ts - self.ts)
    1.50 +
    1.51 +    def __call__(self, msg):
    1.52 +        _buf = f'{self} | {msg}'
    1.53 +        self.ts = monotonic()
    1.54 +        return _buf
    1.55 +
    1.56 +
    1.57 +class NullLog(object):
    1.58 +    def __init__(self, prefix: str = 'main'):
    1.59 +        self.prefix = prefix
    1.60 +
    1.61 +    @staticmethod
    1.62 +    def _write(mark: str, msg: Any):
    1.63 +        pass     # cat > /dev/null
    1.64 +
    1.65 +    def __call__(self, msg):
    1.66 +        self._write('.', msg)
    1.67 +
    1.68 +    def err(self, msg):
    1.69 +        self._write('!', msg)
    1.70 +
    1.71 +    def warn(self, msg):
    1.72 +        self._write('*', msg)
    1.73 +
    1.74 +    def alert(self, msg):
    1.75 +        self._write('#', msg)
    1.76 +
    1.77 +    def debug(self, msg):
    1.78 +        self._write('`', msg)
    1.79 +
    1.80 +    @staticmethod
    1.81 +    def get_timing(name: Optional[str] = None):
    1.82 +        return Timing(name)
    1.83 +
    1.84 +    def sub_log(self, name: str):
    1.85 +        return self.__class__(f'{self.prefix}/{name}')
    1.86 +
    1.87 +    def excpt(self, msg, e_class=None, e_obj=None, e_tb=None, stack_skip=0):
    1.88 +        if e_class is None:
    1.89 +            e_class, e_obj, e_tb = exc_info()
    1.90 +
    1.91 +        tb_data_tb = list(extract_tb(e_tb))[::-1]
    1.92 +        tb_data_stack = list(extract_stack())[::-1][(2 + stack_skip):]
    1.93 +        self.err(msg)
    1.94 +        self.err('--- EXCEPTION ---')
    1.95 +        self.err(f' {e_class.__name__} ({e_obj})')
    1.96 +        self.err('--- TRACEBACK ---')
    1.97 +        for _tb_file, _tb_line, _tb_func, _tb_text in tb_data_tb:
    1.98 +            self.err(f'File: {_tb_file}, line {_tb_line} in {_tb_func}')
    1.99 +            self.err(f'   {_tb_text}')
   1.100 +
   1.101 +        self.err('>>> Exception Handler <<<')
   1.102 +        for _tb_file, _tb_line, _tb_func, _tb_text in tb_data_stack:
   1.103 +            self.err(f'File: {_tb_file}, line {_tb_line} in {_tb_func}')
   1.104 +            self.err(f'   {_tb_text}')
   1.105 +
   1.106 +        self.err('--- END EXCEPTION ---')
   1.107 +
   1.108 +
   1.109 +class FileLog(NullLog):
   1.110 +    @staticmethod
   1.111 +    def _open_file(file_name: str):
   1.112 +        return open(file_name, 'a', encoding='utf-8')
   1.113 +
   1.114 +    def __init__(self, prefix: str = 'main',
   1.115 +                 file_name: Optional[str] = None,
   1.116 +                 file_obj: Optional[TextIO] = None,
   1.117 +                 time_to_flush: int = TIME_TO_FLUSH
   1.118 +                 ):
   1.119 +
   1.120 +        super().__init__(prefix=prefix)
   1.121 +        self.fd: Optional[TextIO] = None
   1.122 +
   1.123 +        self.flush_time = monotonic()
   1.124 +        self.time_to_flush = time_to_flush      # Время с момента прошлого сброса лога,
   1.125 +                                                # после которого, выполняется принудительный сброс буферов
   1.126 +
   1.127 +        if file_name is not None:
   1.128 +            self.fd = self._open_file(file_name)
   1.129 +
   1.130 +        else:
   1.131 +            self.fd = file_obj
   1.132 +
   1.133 +        if self.fd is None:
   1.134 +            raise ValueError(f'Не задан файл для записи журналов')
   1.135 +
   1.136 +    def flush(self, time_mark: float = None):
   1.137 +        if time_mark is None:
   1.138 +            time_mark = monotonic()
   1.139 +
   1.140 +        self.flush_time = time_mark
   1.141 +        self.fd.flush()
   1.142 +
   1.143 +    def close(self):
   1.144 +        self.fd.flush()
   1.145 +        self.fd.close()
   1.146 +        self.fd = None
   1.147 +
   1.148 +    def __del__(self):
   1.149 +        if self.fd is not None:
   1.150 +            self.fd.flush()
   1.151 +            self.fd.close()
   1.152 +            self.fd = None
   1.153 +
   1.154 +    def flush_event(self):
   1.155 +        t = monotonic()
   1.156 +        if t - self.flush_time >= self.time_to_flush:
   1.157 +            self.flush(t)
   1.158 +
   1.159 +    def _write(self, mark: str, msg: Any):
   1.160 +        if self.fd is None:
   1.161 +            raise ValueError('Попытка использовать закрытый файл журнала')
   1.162 +
   1.163 +        t = ctime()
   1.164 +        for l in str(msg).splitlines():
   1.165 +            self.fd.write(f'{t} | {mark} {self.prefix} | {l}')
   1.166 +
   1.167 +        self.flush_event()
   1.168 +
   1.169 +    def sub_log(self, name: str):
   1.170 +        if self.fd is None:
   1.171 +            raise ValueError('Попытка использовать закрытый файл журнала')
   1.172 +
   1.173 +        return self.__class__(f'{self.prefix}/{name}', file_obj=self.fd, time_to_flush=self.time_to_flush)
   1.174 +
   1.175 +
   1.176 +class StderrLog(FileLog):
   1.177 +    def __init__(self, prefix: str = 'main'):
   1.178 +        super().__init__(prefix, file_obj=stderr)
   1.179 +
   1.180 +    def flush_event(self):
   1.181 +        pass     # нет необходимости сбрасывать буферы в консоли
   1.182 +
   1.183 +
   1.184 +class StdoutLog(FileLog):
   1.185 +    def __init__(self, prefix: str = 'main'):
   1.186 +        super().__init__(prefix, file_obj=stdout)
   1.187 +
   1.188 +    def flush_event(self):
   1.189 +        pass     # нет необходимости сбрасывать буферы в консоли
   1.190 +
   1.191 +
   1.192 +class LogrotateFile(FileLog):
   1.193 +    def __init__(self, directory: str = '.', prefix: str = 'main', time_to_flush: int = TIME_TO_FLUSH):
   1.194 +        d = date.today()
   1.195 +        directory = abspath(directory)
   1.196 +        file_name = p_join(directory, f'{prefix}-{d}.log')
   1.197 +
   1.198 +        super().__init__(prefix, file_name=file_name, time_to_flush=time_to_flush)
   1.199 +        self.logrotate_base = p_join(directory, f'{prefix}')
   1.200 +        self.logrotate_date = d
   1.201 +
   1.202 +    def flush(self, time_mark: float = None, no_rotate: bool = False):
   1.203 +        if not no_rotate:
   1.204 +            d = date.today()
   1.205 +            if self.logrotate_date != d:
   1.206 +                self.logrotate_rotate()
   1.207 +                return
   1.208 +
   1.209 +        super().flush(time_mark=time_mark)
   1.210 +
   1.211 +    def logrotate_rotate(self):
   1.212 +        d = date.today()
   1.213 +        file_name = f'{self.logrotate_base}-{d}.log'
   1.214 +        self.fd.flush()
   1.215 +        self.fd = self._open_file(file_name)
   1.216 +        self.logrotate_date = d
   1.217 +        self.flush(no_rotate=True)
   1.218 +
   1.219 +
   1.220 +class ThreadSafeFileLog(FileLog):
   1.221 +    def __int__(self, *a, **kwa):
   1.222 +        super().__init__(*a, **kwa)
   1.223 +        self.thread_safe_lock = RLock()
   1.224 +
   1.225 +    def _write(self, mark: str, msg: Any):
   1.226 +        with self.thread_safe_lock:
   1.227 +            super()._write(mark, msg)
   1.228 +
   1.229 +    def flush(self, time_mark: float = None):
   1.230 +        with self.thread_safe_lock:
   1.231 +            super().flush(time_mark)
   1.232 +
   1.233 +
   1.234 +class ThreadSafeLogrotateFile(LogrotateFile):
   1.235 +    def __init__(self, directory: str = '.', prefix: str = 'main', time_to_flush: int = TIME_TO_FLUSH):
   1.236 +        super().__init__(directory=directory, prefix=prefix, time_to_flush=time_to_flush)
   1.237 +        self.thread_safe_lock = RLock()
   1.238 +
   1.239 +    def _write(self, mark: str, msg: Any):
   1.240 +        with self.thread_safe_lock:
   1.241 +            super()._write(mark, msg)
   1.242 +
   1.243 +    def flush(self, time_mark: float = None, no_rotate: bool = False):
   1.244 +        with self.thread_safe_lock:
   1.245 +            super().flush(time_mark=time_mark, no_rotate=no_rotate)
   1.246 +
   1.247 +    def logrotate_rotate(self):
   1.248 +        with self.thread_safe_lock:
   1.249 +            super().logrotate_rotate()
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/log/log_syslog.py	Sat Jan 28 16:39:53 2023 +0300
     2.3 @@ -0,0 +1,105 @@
     2.4 +# coding: utf-8
     2.5 +"""
     2.6 +Тривиальная реализация сислоггера без блэк-джека и поэтесс
     2.7 +
     2.8 +Метки в журнале о уровне сообщения:
     2.9 +  "`": Debug
    2.10 +  ".": Info
    2.11 +  "*": Warning
    2.12 +  "!": Error
    2.13 +  "#": Alert
    2.14 +
    2.15 +"""
    2.16 +from time import monotonic
    2.17 +from datetime import timedelta
    2.18 +
    2.19 +import syslog
    2.20 +from traceback import extract_tb, extract_stack
    2.21 +from sys import exc_info
    2.22 +
    2.23 +
    2.24 +class Timing(object):
    2.25 +    def __init__(self, name=None):
    2.26 +        if name is None:
    2.27 +            self.prefix = ''
    2.28 +
    2.29 +        else:
    2.30 +            self.prefix = f'{name} :: '
    2.31 +
    2.32 +        self.tsAll = monotonic()
    2.33 +        self.ts = self.tsAll
    2.34 +
    2.35 +    def get_time(self):
    2.36 +        return monotonic() - self.ts
    2.37 +
    2.38 +    def reset(self):
    2.39 +        self.ts = monotonic()
    2.40 +        self.tsAll = self.ts
    2.41 +
    2.42 +    def __str__(self):
    2.43 +        ts = monotonic()
    2.44 +        return self.prefix + '%s(%.4f)' % (timedelta(seconds=(ts - self.tsAll)), ts - self.ts)
    2.45 +
    2.46 +    def __call__(self, msg):
    2.47 +        _buf = f'{self} | {msg}'
    2.48 +        self.ts = monotonic()
    2.49 +        return _buf
    2.50 +
    2.51 +
    2.52 +class SysLogger(object):
    2.53 +    @staticmethod
    2.54 +    def init_syslog(ident):
    2.55 +        syslog.openlog(ident, syslog.LOG_PID)
    2.56 +
    2.57 +    @staticmethod
    2.58 +    def get_timing(name=None):
    2.59 +        return Timing(name)
    2.60 +
    2.61 +    def __init__(self, prefix='main', facility=syslog.LOG_USER):
    2.62 +        self.prefix = str(prefix)
    2.63 +        self.facility = facility
    2.64 +
    2.65 +    def _write(self, flag, mark, msg):
    2.66 +        for l in str(msg).splitlines():
    2.67 +            syslog.syslog(self.facility | flag, f'{mark} {self.prefix} | {l}')
    2.68 +
    2.69 +    def __call__(self, msg):
    2.70 +        self._write(syslog.LOG_INFO, '.', msg)
    2.71 +    
    2.72 +    def err(self, msg):
    2.73 +        self._write(syslog.LOG_ERR, '!', msg)
    2.74 +    
    2.75 +    def warn(self, msg):
    2.76 +        self._write(syslog.LOG_WARNING, '*', msg)
    2.77 +    
    2.78 +    def debug(self, msg):
    2.79 +        self._write(syslog.LOG_DEBUG, '`', msg)
    2.80 +
    2.81 +    def alert(self, msg):
    2.82 +        self._write(syslog.LOG_ALERT, '#', msg)
    2.83 +
    2.84 +    def sub_log(self, prefix):
    2.85 +        return self.__class__(f'{self.prefix}/{prefix}', self.facility)
    2.86 +
    2.87 +    def excpt(self, msg, e_class=None, e_obj=None, e_tback=None, stack_skip=0):
    2.88 +        if e_class is None:
    2.89 +            e_class, e_obj, e_tback = exc_info()
    2.90 +        
    2.91 +        tb_data_tb = list(extract_tb(e_tback))[::-1]
    2.92 +        tb_data_stack = list(extract_stack())[::-1][(2 + stack_skip):]
    2.93 +
    2.94 +        self.err(msg)
    2.95 +        self.err('--- EXCEPTION ---')
    2.96 +        self.err(f' {e_class.__name__} ({e_obj})')
    2.97 +
    2.98 +        self.err('--- TRACEBACK ---')
    2.99 +        for _tb_file, _tb_line, _tb_func, _tb_text in tb_data_tb:
   2.100 +            self.err(f'File: {_tb_file}, line {_tb_line} in {_tb_func}')
   2.101 +            self.err(f'   {_tb_text}')
   2.102 +
   2.103 +        self.err('>>> Exception Handler <<<')
   2.104 +        for _tb_file, _tb_line, _tb_func, _tb_text in tb_data_stack:
   2.105 +            self.err(f'File: {_tb_file}, line {_tb_line} in {_tb_func}')
   2.106 +            self.err(f'   {_tb_text}')
   2.107 +
   2.108 +        self.err('--- END EXCEPTION ---')
     3.1 --- a/log/slog_console.py	Sat Aug 27 17:56:21 2022 +0300
     3.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.3 @@ -1,123 +0,0 @@
     3.4 -# coding: utf-8
     3.5 -""" Логирование на консоль
     3.6 -
     3.7 -Метки в журнале о уровне сообщения:
     3.8 -  "`": Debug
     3.9 -  ".": Info
    3.10 -  "*": Warning
    3.11 -  "!": Error
    3.12 -  "#": Alert
    3.13 -"""
    3.14 -
    3.15 -from time import monotonic
    3.16 -from datetime import timedelta
    3.17 -from sys import exc_info, stderr, stdout
    3.18 -from traceback import extract_tb, extract_stack
    3.19 -
    3.20 -
    3.21 -class Timing(object):
    3.22 -    def __init__(self, name=None):
    3.23 -        if name is None:
    3.24 -            self.prefix = ''
    3.25 -        else:
    3.26 -            self.prefix = '%s :: ' % name
    3.27 -        self.tsAll = monotonic()
    3.28 -        self.ts = self.tsAll
    3.29 -    
    3.30 -    def getTime(self):
    3.31 -        return monotonic() - self.ts
    3.32 -    
    3.33 -    def reset(self):
    3.34 -        self.ts = monotonic()
    3.35 -        self.tsAll = self.ts
    3.36 -    
    3.37 -    def __str__(self):
    3.38 -        ts = monotonic()
    3.39 -        return self.prefix + '%s(%.4f)' % (timedelta(seconds=(ts - self.tsAll)), ts - self.ts)
    3.40 -    
    3.41 -    def __call__(self, msg):
    3.42 -        _buf = '%s | %s' % (self, msg)
    3.43 -        self.ts = monotonic()
    3.44 -        return _buf
    3.45 -
    3.46 -
    3.47 -class ConsoleLog(object):
    3.48 -    def __init__(self, appname='main'):
    3.49 -        self.appname = appname
    3.50 -
    3.51 -    @staticmethod
    3.52 -    def _write(ItrCntnt):
    3.53 -        for l in ItrCntnt:
    3.54 -            print(l)
    3.55 -
    3.56 -    def __call__(self, msg):
    3.57 -        self._write(map(
    3.58 -                lambda x: '%3s | %s :: %s' % ('.', self.appname, x),
    3.59 -                str(msg).splitlines()
    3.60 -        ))
    3.61 -
    3.62 -    def err(self, msg):
    3.63 -        self._write(map(
    3.64 -            lambda x: '%3s | %s :: %s' % ('!', self.appname, x),
    3.65 -            str(msg).splitlines()
    3.66 -        ))
    3.67 -
    3.68 -    def warn(self, msg):
    3.69 -        self._write(map(
    3.70 -            lambda x: '%3s | %s :: %s' % ('*', self.appname, x),
    3.71 -            str(msg).splitlines()
    3.72 -        ))
    3.73 -
    3.74 -    def alert(self, msg):
    3.75 -        self._write(map(
    3.76 -            lambda x: '%3s | %s :: %s' % ('#', self.appname, x),
    3.77 -            str(msg).splitlines()
    3.78 -        ))
    3.79 -
    3.80 -    def debug(self, msg):
    3.81 -        self._write(map(
    3.82 -            lambda x: '%3s | %s :: %s' % ('`', self.appname, x),
    3.83 -            str(msg).splitlines()
    3.84 -        ))
    3.85 -
    3.86 -    @staticmethod
    3.87 -    def getTiming(name=None):
    3.88 -        return Timing(name)
    3.89 -    
    3.90 -    def sublog(self, name):
    3.91 -        return self.__class__('%s/%s' % (self.appname, name))
    3.92 -    
    3.93 -    def excpt(self, msg, eClass=None, eObj=None, eTb=None, stack_skip=0):
    3.94 -        if eClass is None:
    3.95 -            eClass, eObj, eTb = exc_info()
    3.96 -            
    3.97 -        tbData_tb = list(extract_tb(eTb))[::-1]
    3.98 -        tbData_stack = list(extract_stack())[::-1][(2 + stack_skip):]
    3.99 -        self.err(msg)
   3.100 -        self.err('--- EXCEPTION ---')
   3.101 -        self.err(' %s (%s)' % (eClass.__name__, eObj))
   3.102 -        self.err('--- TRACEBACK ---')
   3.103 -        for _tbFile, _tbLine, _tbFunc, _tbText in tbData_tb:
   3.104 -            self.err('File: %s, line %s in %s' % (_tbFile, _tbLine, _tbFunc))
   3.105 -            self.err('   %s' % _tbText)
   3.106 -        self.err('>>> Exception Handler <<<')
   3.107 -        for _tbFile, _tbLine, _tbFunc, _tbText in tbData_stack:
   3.108 -            self.err('File: %s, line %s in %s' % (_tbFile, _tbLine, _tbFunc))
   3.109 -            self.err('   %s' % _tbText)
   3.110 -        self.err('--- END EXCEPTION ---')
   3.111 -
   3.112 -
   3.113 -class StderrLog(ConsoleLog):
   3.114 -    @staticmethod
   3.115 -    def _write(msgItr):
   3.116 -        for l in msgItr:
   3.117 -            stderr.write('%s\n' % l)
   3.118 -        stderr.flush()
   3.119 -
   3.120 -
   3.121 -class StdoutLog(ConsoleLog):
   3.122 -    @staticmethod
   3.123 -    def _write(msgItr):
   3.124 -        for l in msgItr:
   3.125 -            stdout.write('%s\n' % l)
   3.126 -        stdout.flush()
     4.1 --- a/log/slog_syslogger.py	Sat Aug 27 17:56:21 2022 +0300
     4.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.3 @@ -1,151 +0,0 @@
     4.4 -# coding: utf-8
     4.5 -
     4.6 -"""\
     4.7 -Логирование в системный журнал Unix
     4.8 -
     4.9 -Метки в журнале о уровне сообщения:
    4.10 -  "`": Debug
    4.11 -  ".": Info
    4.12 -  "*": Warning
    4.13 -  "!": Error
    4.14 -  "#": Alert
    4.15 -"""
    4.16 -
    4.17 -import syslog
    4.18 -from sys import exc_info
    4.19 -from time import monotonic
    4.20 -from traceback import extract_tb, extract_stack
    4.21 -from datetime import timedelta
    4.22 -from typing import Any
    4.23 -
    4.24 -LOG_FACILITY = {
    4.25 -    'auth': syslog.LOG_AUTH,
    4.26 -    'authpriv': syslog.LOG_AUTH,
    4.27 -    'cron': syslog.LOG_CRON,
    4.28 -    'daemon': syslog.LOG_DAEMON,
    4.29 -    'ftp': syslog.LOG_DAEMON,
    4.30 -    'kern': syslog.LOG_KERN,
    4.31 -    'lpr': syslog.LOG_LPR,
    4.32 -    'mail': syslog.LOG_MAIL,
    4.33 -    'news': syslog.LOG_NEWS,
    4.34 -    'syslog': syslog.LOG_SYSLOG,
    4.35 -    'user': syslog.LOG_USER,
    4.36 -    'uucp': syslog.LOG_UUCP,
    4.37 -    'local0': syslog.LOG_LOCAL0,
    4.38 -    'local1': syslog.LOG_LOCAL1,
    4.39 -    'local2': syslog.LOG_LOCAL2,
    4.40 -    'local3': syslog.LOG_LOCAL3,
    4.41 -    'local4': syslog.LOG_LOCAL4,
    4.42 -    'local5': syslog.LOG_LOCAL5,
    4.43 -    'local6': syslog.LOG_LOCAL6,
    4.44 -    'local7': syslog.LOG_LOCAL7
    4.45 -}
    4.46 -
    4.47 -
    4.48 -class LoggerError(Exception): pass
    4.49 -
    4.50 -
    4.51 -# --- INTERFACE --- #
    4.52 -FACILITY = LOG_FACILITY['user']
    4.53 -
    4.54 -
    4.55 -def check_facility(facility: str = 'user'):
    4.56 -    if not facility.lower() in LOG_FACILITY:
    4.57 -        raise LoggerError(f'Unknown facility: {facility}')
    4.58 -
    4.59 -
    4.60 -def log_prep(ident: str, facility: str = 'user'):
    4.61 -    global FACILITY
    4.62 -    check_facility(facility)
    4.63 -
    4.64 -    syslog.openlog(ident, syslog.LOG_PID)
    4.65 -
    4.66 -    FACILITY = LOG_FACILITY[facility]
    4.67 -
    4.68 -
    4.69 -class Timing(object):
    4.70 -    def __init__(self, name: str = None):
    4.71 -        if name is None:
    4.72 -            self.prefix = ''
    4.73 -        else:
    4.74 -            self.prefix = f'{name} :: '
    4.75 -        self.tsAll = monotonic()
    4.76 -        self.ts = self.tsAll
    4.77 -
    4.78 -    def get_time(self):
    4.79 -        return monotonic() - self.ts
    4.80 -
    4.81 -    def reset(self):
    4.82 -        self.ts = monotonic()
    4.83 -        self.tsAll = self.ts
    4.84 -
    4.85 -    def __str__(self):
    4.86 -        ts = monotonic()
    4.87 -        return self.prefix + '%s(%.4f)' % (timedelta(seconds=(ts - self.tsAll)), ts - self.ts)
    4.88 -
    4.89 -    def __call__(self, msg: Any) -> str:
    4.90 -        _buf = f'{self} | {msg}'
    4.91 -        self.ts = monotonic()
    4.92 -        return _buf
    4.93 -
    4.94 -
    4.95 -class SysLogger(object):
    4.96 -    init_log = log_prep
    4.97 -
    4.98 -    @staticmethod
    4.99 -    def get_timing(name: str = None):
   4.100 -        return Timing(name)
   4.101 -
   4.102 -    def __init__(self, prefix: str = 'main', facility: int = FACILITY):
   4.103 -        self.prefix = str(prefix)
   4.104 -        self.facility = facility
   4.105 -
   4.106 -    def _write(self, flag: int, mark: str, msg: Any):
   4.107 -        for l in str(msg).splitlines():
   4.108 -            syslog.syslog(self.facility | flag, f'{mark} {self.prefix}: {l}')
   4.109 -
   4.110 -    def __call__(self, msg: Any):
   4.111 -        self._write(syslog.LOG_INFO, '.', msg)
   4.112 -
   4.113 -    def err(self, msg: Any):
   4.114 -        self._write(syslog.LOG_ERR, '!', msg)
   4.115 -
   4.116 -    def warn(self, msg: Any):
   4.117 -        self._write(syslog.LOG_WARNING, '*', msg)
   4.118 -
   4.119 -    def debug(self, msg: Any):
   4.120 -        self._write(syslog.LOG_DEBUG, '`', msg)
   4.121 -
   4.122 -    def alert(self, msg: Any):
   4.123 -        self._write(syslog.LOG_ALERT, '#', msg)
   4.124 -
   4.125 -    def sublog(self, prefix: str):
   4.126 -        return self.__class__(f'{self.prefix}/{prefix}', self.facility)
   4.127 -
   4.128 -    def excpt(self, msg: Any, e_class: type = None, e_obj: Exception = None, e_tb=None, stack_skip=0):
   4.129 -        if e_class is None:
   4.130 -            e_class, e_obj, e_tb = exc_info()
   4.131 -
   4.132 -        if e_class is None:
   4.133 -            # Если вдруг вызываем без произошедшего исключения
   4.134 -            self.err(msg)
   4.135 -        else:
   4.136 -            tb_data_tb = list(extract_tb(e_tb))[::-1]
   4.137 -            tb_data_stack = list(extract_stack())[::-1][(2 + stack_skip):]
   4.138 -
   4.139 -            self.err(msg)
   4.140 -
   4.141 -            self.err('--- EXCEPTION ---')
   4.142 -            self.err(' %s (%s)' % (e_class.__name__, e_obj))
   4.143 -
   4.144 -            self.err('--- TRACEBACK ---')
   4.145 -            for _tb_file, _tb_line, _tb_func, _tb_text in tb_data_tb:
   4.146 -                self.err('File: %s, line %s in %s' % (_tb_file, _tb_line, _tb_func))
   4.147 -                self.err('   %s' % _tb_text)
   4.148 -
   4.149 -            self.err('>>> Exception Handler <<<')
   4.150 -            for _tb_file, _tb_line, _tb_func, _tb_text in tb_data_stack:
   4.151 -                self.err('File: %s, line %s in %s' % (_tb_file, _tb_line, _tb_func))
   4.152 -                self.err('   %s' % _tb_text)
   4.153 -
   4.154 -            self.err('--- END EXCEPTION ---')
     5.1 --- a/log/tiny_slog.py	Sat Aug 27 17:56:21 2022 +0300
     5.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.3 @@ -1,103 +0,0 @@
     5.4 -# coding: utf-8
     5.5 -"""
     5.6 -Тривиальная реализация сислоггера без блэк-джека и поэтесс
     5.7 -
     5.8 -Метки в журнале о уровне сообщения:
     5.9 -  "`": Debug
    5.10 -  ".": Info
    5.11 -  "*": Warning
    5.12 -  "!": Error
    5.13 -  "#": Alert
    5.14 -
    5.15 -"""
    5.16 -from time import monotonic
    5.17 -from datetime import timedelta
    5.18 -
    5.19 -import syslog
    5.20 -from traceback import extract_tb, extract_stack
    5.21 -from sys import exc_info
    5.22 -
    5.23 -
    5.24 -class Timing(object):
    5.25 -    def __init__(self, name=None):
    5.26 -        if name is None:
    5.27 -            self.prefix = ''
    5.28 -        else:
    5.29 -            self.prefix = '%s :: ' % name
    5.30 -        self.tsAll = monotonic()
    5.31 -        self.ts = self.tsAll
    5.32 -
    5.33 -    def getTime(self):
    5.34 -        return monotonic() - self.ts
    5.35 -
    5.36 -    def reset(self):
    5.37 -        self.ts = monotonic()
    5.38 -        self.tsAll = self.ts
    5.39 -
    5.40 -    def __str__(self):
    5.41 -        ts = monotonic()
    5.42 -        return self.prefix + '%s(%.4f)' % (timedelta(seconds=(ts - self.tsAll)), ts - self.ts)
    5.43 -
    5.44 -    def __call__(self, msg):
    5.45 -        _buf = '%s | %s' % (self, msg)
    5.46 -        self.ts = monotonic()
    5.47 -        return _buf
    5.48 -
    5.49 -
    5.50 -class SimpleSysLogger(object):
    5.51 -    @staticmethod
    5.52 -    def init_syslog(ident):
    5.53 -        syslog.openlog(ident, syslog.LOG_PID)
    5.54 -
    5.55 -    @staticmethod
    5.56 -    def get_timing(name=None):
    5.57 -        return Timing(name)
    5.58 -
    5.59 -    def __init__(self, prefix='main', facility=syslog.LOG_USER):
    5.60 -        self.prefix = str(prefix)
    5.61 -        self.facility = facility
    5.62 -
    5.63 -    def _write(self, flag, mark, msg):
    5.64 -        for l in str(msg).splitlines():
    5.65 -            syslog.syslog(self.facility | flag, f'{self.prefix}: {mark} {l}')
    5.66 -
    5.67 -    def __call__(self, msg):
    5.68 -        self._write(syslog.LOG_INFO, '.', msg)
    5.69 -    
    5.70 -    def err(self, msg):
    5.71 -        self._write(syslog.LOG_ERR, '!', msg)
    5.72 -    
    5.73 -    def warn(self, msg):
    5.74 -        self._write(syslog.LOG_WARNING, '*', msg)
    5.75 -    
    5.76 -    def debug(self, msg):
    5.77 -        self._write(syslog.LOG_DEBUG, '`', msg)
    5.78 -
    5.79 -    def alert(self, msg):
    5.80 -        self._write(syslog.LOG_ALERT, '#', msg)
    5.81 -
    5.82 -    def sub_log(self, prefix):
    5.83 -        return self.__class__('%s/%s' % (self.prefix, prefix), self.facility)
    5.84 -
    5.85 -    def excpt(self, msg, e_class=None, e_obj=None, e_tback=None, stack_skip=0):
    5.86 -        if e_class is None:
    5.87 -            e_class, e_obj, e_tback = exc_info()
    5.88 -        
    5.89 -        tb_data_tb = list(extract_tb(e_tback))[::-1]
    5.90 -        tb_data_stack = list(extract_stack())[::-1][(2 + stack_skip):]
    5.91 -
    5.92 -        self.err(msg)
    5.93 -        self.err('--- EXCEPTION ---')
    5.94 -        self.err(' %s (%s)' % (e_class.__name__, e_obj))
    5.95 -
    5.96 -        self.err('--- TRACEBACK ---')
    5.97 -        for _tb_file, _tb_line, _tb_func, _tb_text in tb_data_tb:
    5.98 -            self.err('File: %s, line %s in %s' % (_tb_file, _tb_line, _tb_func))
    5.99 -            self.err('   %s' % _tb_text)
   5.100 -
   5.101 -        self.err('>>> Exception Handler <<<')
   5.102 -        for _tb_file, _tb_line, _tb_func, _tb_text in tb_data_stack:
   5.103 -            self.err('File: %s, line %s in %s' % (_tb_file, _tb_line, _tb_func))
   5.104 -            self.err('   %s' % _tb_text)
   5.105 -
   5.106 -        self.err('--- END EXCEPTION ---')