tools.win_pg_dump_controller

Yohn Y. 2022-01-30 Child:7c93b0305522

0:be791d354d2a Go to Latest

tools.win_pg_dump_controller/win_pg_dump_controller/log_controller.py

..init

History
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/win_pg_dump_controller/log_controller.py	Sun Jan 30 22:17:39 2022 +0300
     1.3 @@ -0,0 +1,167 @@
     1.4 +# coding: utf-8
     1.5 +"""\
     1.6 +Модуль логирования
     1.7 +
     1.8 +Метки в журнале о уровне сообщения:
     1.9 +  "`": Debug
    1.10 +  ".": Info
    1.11 +  "*": Warning
    1.12 +  "!": Error
    1.13 +  "#": Alert
    1.14 +"""
    1.15 +
    1.16 +from time import time, ctime
    1.17 +from datetime import timedelta, datetime
    1.18 +from sys import exc_info
    1.19 +from os.path import join as p_join
    1.20 +from os import listdir, remove as file_remove, stat
    1.21 +from traceback import extract_tb, extract_stack
    1.22 +from typing import Optional
    1.23 +
    1.24 +from .config import Config
    1.25 +
    1.26 +
    1.27 +class Timing(object):
    1.28 +    def __init__(self, name: Optional[str] = None):
    1.29 +        if name is None:
    1.30 +            self.prefix = ''
    1.31 +        else:
    1.32 +            self.prefix = f'{name} :: '
    1.33 +        self.tsAll = time()
    1.34 +        self.ts = self.tsAll
    1.35 +
    1.36 +    def get_time(self):
    1.37 +        return time() - self.ts
    1.38 +
    1.39 +    def reset(self):
    1.40 +        self.ts = time()
    1.41 +        self.tsAll = self.ts
    1.42 +
    1.43 +    def __str__(self):
    1.44 +        ts = time()
    1.45 +        return self.prefix + '%s(%.4f)' % (timedelta(seconds=(ts - self.tsAll)), ts - self.ts)
    1.46 +
    1.47 +    def __call__(self, msg):
    1.48 +        _buf = f'{self} | {msg}'
    1.49 +        self.ts = time()
    1.50 +        return _buf
    1.51 +
    1.52 +
    1.53 +class BaseLogger(object):
    1.54 +    def __init__(self, appname='main'):
    1.55 +        self.appname = appname
    1.56 +
    1.57 +    @staticmethod
    1.58 +    def _write(itr_content):
    1.59 +        raise NotImplemented()
    1.60 +
    1.61 +    def __call__(self, msg):
    1.62 +        self._write(map(
    1.63 +            lambda x: '%3s | %s :: %s' % ('.', self.appname, x),
    1.64 +            str(msg).splitlines()
    1.65 +        ))
    1.66 +
    1.67 +    def err(self, msg):
    1.68 +        self._write(map(
    1.69 +            lambda x: '%3s | %s :: %s' % ('!', self.appname, x),
    1.70 +            str(msg).splitlines()
    1.71 +        ))
    1.72 +
    1.73 +    def warn(self, msg):
    1.74 +        self._write(map(
    1.75 +            lambda x: '%3s | %s :: %s' % ('*', self.appname, x),
    1.76 +            str(msg).splitlines()
    1.77 +        ))
    1.78 +
    1.79 +    def alert(self, msg):
    1.80 +        self._write(map(
    1.81 +            lambda x: '%3s | %s :: %s' % ('#', self.appname, x),
    1.82 +            str(msg).splitlines()
    1.83 +        ))
    1.84 +
    1.85 +    def debug(self, msg):
    1.86 +        self._write(map(
    1.87 +            lambda x: '%3s | %s :: %s' % ('`', self.appname, x),
    1.88 +            str(msg).splitlines()
    1.89 +        ))
    1.90 +
    1.91 +    @staticmethod
    1.92 +    def get_timing(name: Optional[str] = None):
    1.93 +        return Timing(name)
    1.94 +
    1.95 +    def sublog(self, name):
    1.96 +        return self.__class__(f'{self.appname}/{name}')
    1.97 +
    1.98 +    def excpt(self, msg, e_class=None, e_obj=None, e_tb=None, stack_skip=0):
    1.99 +        if e_class is None:
   1.100 +            e_class, e_obj, e_tb = exc_info()
   1.101 +
   1.102 +        tb_data_tb = list(extract_tb(e_tb))[::-1]
   1.103 +        tb_data_stack = list(extract_stack())[::-1][(2 + stack_skip):]
   1.104 +        self.err(msg)
   1.105 +        self.err('--- EXCEPTION ---')
   1.106 +        self.err(' %s (%s)' % (e_class.__name__, e_obj))
   1.107 +        self.err('--- TRACEBACK ---')
   1.108 +        for _tbFile, _tbLine, _tbFunc, _tbText in tb_data_tb:
   1.109 +            self.err('File: %s, line %s in %s' % (_tbFile, _tbLine, _tbFunc))
   1.110 +            self.err('   %s' % _tbText)
   1.111 +        self.err('>>> Exception Handler <<<')
   1.112 +        for _tbFile, _tbLine, _tbFunc, _tbText in tb_data_stack:
   1.113 +            self.err('File: %s, line %s in %s' % (_tbFile, _tbLine, _tbFunc))
   1.114 +            self.err('   %s' % _tbText)
   1.115 +        self.err('--- END EXCEPTION ---')
   1.116 +
   1.117 +
   1.118 +class NullLogger(BaseLogger):
   1.119 +    @staticmethod
   1.120 +    def _write(itr_content):
   1.121 +        pass
   1.122 +
   1.123 +
   1.124 +class FileLogger(BaseLogger):
   1.125 +    def __init__(self, filename: str, appname: str = 'main'):
   1.126 +        super().__init__(appname)
   1.127 +        self.fd = open(filename, 'a')
   1.128 +
   1.129 +    def _write(self, itr_content):
   1.130 +        cur_time = ctime()
   1.131 +        for i in itr_content:
   1.132 +            self.fd.write(f'{cur_time}{i}\n')
   1.133 +
   1.134 +        self.fd.flush()
   1.135 +
   1.136 +    def __del__(self):
   1.137 +        try:
   1.138 +            self.fd.close()
   1.139 +        except:
   1.140 +            pass
   1.141 +
   1.142 +
   1.143 +class LogController(object):
   1.144 +    def __init__(self, config: Config):
   1.145 +        self.log_dir = config.log_dir
   1.146 +        self.keep_logs_days = config.keep_logs_days
   1.147 +
   1.148 +    @staticmethod
   1.149 +    def _get_timeprefix() -> str:
   1.150 +        return datetime.now().strftime('%Y-%m-%d_%H-%M-%S')
   1.151 +
   1.152 +    def get_logger(self, name: str) -> BaseLogger:
   1.153 +        if self.log_dir is not None:
   1.154 +            return FileLogger(p_join(self.log_dir, f'{self._get_timeprefix()} - {name}.log'), appname=name)
   1.155 +        else:
   1.156 +            return NullLogger(appname=name)
   1.157 +
   1.158 +    def get_filename(self, name: str) -> Optional[str]:
   1.159 +        if self.log_dir is not None:
   1.160 +            return str(p_join(self.log_dir, f'{self._get_timeprefix()} - {name}.log'))
   1.161 +
   1.162 +    def clean(self):
   1.163 +        if self.log_dir is not None:
   1.164 +            now = time()
   1.165 +            for f in listdir(self.log_dir):
   1.166 +                f_path = p_join(self.log_dir, f)
   1.167 +                f_stat = stat(f_path)
   1.168 +
   1.169 +                if divmod(now - f_stat.st_ctime, 86400)[0] > self.keep_logs_days:
   1.170 +                    file_remove(f_path)