tools.win_pg_dump_controller
2022-05-05
Parent:7c93b0305522
tools.win_pg_dump_controller/win_pg_dump_controller/log_controller.py
* Орфография в `README` . Рефакторинг в полученном модуле
| awgur@0 | 1 # coding: utf-8 |
| awgur@0 | 2 """\ |
| awgur@0 | 3 Модуль логирования |
| awgur@0 | 4 |
| awgur@0 | 5 Метки в журнале о уровне сообщения: |
| awgur@0 | 6 "`": Debug |
| awgur@0 | 7 ".": Info |
| awgur@0 | 8 "*": Warning |
| awgur@0 | 9 "!": Error |
| awgur@0 | 10 "#": Alert |
| awgur@0 | 11 """ |
| awgur@0 | 12 |
| awgur@0 | 13 from time import time, ctime |
| awgur@0 | 14 from datetime import timedelta, datetime |
| awgur@0 | 15 from sys import exc_info |
| awgur@0 | 16 from os.path import join as p_join |
| awgur@0 | 17 from os import listdir, remove as file_remove, stat |
| awgur@0 | 18 from traceback import extract_tb, extract_stack |
| awgur@0 | 19 from typing import Optional |
| awgur@0 | 20 |
| awgur@0 | 21 from .config import Config |
| awgur@0 | 22 |
| awgur@0 | 23 |
| awgur@0 | 24 class Timing(object): |
| awgur@0 | 25 def __init__(self, name: Optional[str] = None): |
| awgur@0 | 26 if name is None: |
| awgur@0 | 27 self.prefix = '' |
| awgur@0 | 28 else: |
| awgur@0 | 29 self.prefix = f'{name} :: ' |
| awgur@0 | 30 self.tsAll = time() |
| awgur@0 | 31 self.ts = self.tsAll |
| awgur@0 | 32 |
| awgur@0 | 33 def get_time(self): |
| awgur@0 | 34 return time() - self.ts |
| awgur@0 | 35 |
| awgur@0 | 36 def reset(self): |
| awgur@0 | 37 self.ts = time() |
| awgur@0 | 38 self.tsAll = self.ts |
| awgur@0 | 39 |
| awgur@0 | 40 def __str__(self): |
| awgur@0 | 41 ts = time() |
| awgur@0 | 42 return self.prefix + '%s(%.4f)' % (timedelta(seconds=(ts - self.tsAll)), ts - self.ts) |
| awgur@0 | 43 |
| awgur@0 | 44 def __call__(self, msg): |
| awgur@0 | 45 _buf = f'{self} | {msg}' |
| awgur@0 | 46 self.ts = time() |
| awgur@0 | 47 return _buf |
| awgur@0 | 48 |
| awgur@0 | 49 |
| awgur@0 | 50 class BaseLogger(object): |
| awgur@0 | 51 def __init__(self, appname='main'): |
| awgur@0 | 52 self.appname = appname |
| awgur@0 | 53 |
| awgur@0 | 54 @staticmethod |
| awgur@0 | 55 def _write(itr_content): |
| awgur@0 | 56 raise NotImplemented() |
| awgur@0 | 57 |
| awgur@0 | 58 def __call__(self, msg): |
| awgur@0 | 59 self._write(map( |
| awgur@0 | 60 lambda x: '%3s | %s :: %s' % ('.', self.appname, x), |
| awgur@0 | 61 str(msg).splitlines() |
| awgur@0 | 62 )) |
| awgur@0 | 63 |
| awgur@0 | 64 def err(self, msg): |
| awgur@0 | 65 self._write(map( |
| awgur@0 | 66 lambda x: '%3s | %s :: %s' % ('!', self.appname, x), |
| awgur@0 | 67 str(msg).splitlines() |
| awgur@0 | 68 )) |
| awgur@0 | 69 |
| awgur@0 | 70 def warn(self, msg): |
| awgur@0 | 71 self._write(map( |
| awgur@0 | 72 lambda x: '%3s | %s :: %s' % ('*', self.appname, x), |
| awgur@0 | 73 str(msg).splitlines() |
| awgur@0 | 74 )) |
| awgur@0 | 75 |
| awgur@0 | 76 def alert(self, msg): |
| awgur@0 | 77 self._write(map( |
| awgur@0 | 78 lambda x: '%3s | %s :: %s' % ('#', self.appname, x), |
| awgur@0 | 79 str(msg).splitlines() |
| awgur@0 | 80 )) |
| awgur@0 | 81 |
| awgur@0 | 82 def debug(self, msg): |
| awgur@0 | 83 self._write(map( |
| awgur@0 | 84 lambda x: '%3s | %s :: %s' % ('`', self.appname, x), |
| awgur@0 | 85 str(msg).splitlines() |
| awgur@0 | 86 )) |
| awgur@0 | 87 |
| awgur@0 | 88 @staticmethod |
| awgur@0 | 89 def get_timing(name: Optional[str] = None): |
| awgur@0 | 90 return Timing(name) |
| awgur@0 | 91 |
| awgur@0 | 92 def sublog(self, name): |
| awgur@0 | 93 return self.__class__(f'{self.appname}/{name}') |
| awgur@0 | 94 |
| awgur@0 | 95 def excpt(self, msg, e_class=None, e_obj=None, e_tb=None, stack_skip=0): |
| awgur@0 | 96 if e_class is None: |
| awgur@0 | 97 e_class, e_obj, e_tb = exc_info() |
| awgur@0 | 98 |
| awgur@0 | 99 tb_data_tb = list(extract_tb(e_tb))[::-1] |
| awgur@0 | 100 tb_data_stack = list(extract_stack())[::-1][(2 + stack_skip):] |
| awgur@0 | 101 self.err(msg) |
| awgur@0 | 102 self.err('--- EXCEPTION ---') |
| awgur@0 | 103 self.err(' %s (%s)' % (e_class.__name__, e_obj)) |
| awgur@0 | 104 self.err('--- TRACEBACK ---') |
| awgur@0 | 105 for _tbFile, _tbLine, _tbFunc, _tbText in tb_data_tb: |
| awgur@0 | 106 self.err('File: %s, line %s in %s' % (_tbFile, _tbLine, _tbFunc)) |
| awgur@0 | 107 self.err(' %s' % _tbText) |
| awgur@0 | 108 self.err('>>> Exception Handler <<<') |
| awgur@0 | 109 for _tbFile, _tbLine, _tbFunc, _tbText in tb_data_stack: |
| awgur@0 | 110 self.err('File: %s, line %s in %s' % (_tbFile, _tbLine, _tbFunc)) |
| awgur@0 | 111 self.err(' %s' % _tbText) |
| awgur@0 | 112 self.err('--- END EXCEPTION ---') |
| awgur@0 | 113 |
| awgur@0 | 114 |
| awgur@0 | 115 class NullLogger(BaseLogger): |
| awgur@0 | 116 @staticmethod |
| awgur@0 | 117 def _write(itr_content): |
| awgur@0 | 118 pass |
| awgur@0 | 119 |
| awgur@0 | 120 |
| awgur@0 | 121 class FileLogger(BaseLogger): |
| awgur@0 | 122 def __init__(self, filename: str, appname: str = 'main'): |
| awgur@0 | 123 super().__init__(appname) |
| awgur@0 | 124 self.fd = open(filename, 'a') |
| awgur@0 | 125 |
| awgur@0 | 126 def _write(self, itr_content): |
| awgur@0 | 127 cur_time = ctime() |
| awgur@0 | 128 for i in itr_content: |
| awgur@0 | 129 self.fd.write(f'{cur_time}{i}\n') |
| awgur@0 | 130 |
| awgur@0 | 131 self.fd.flush() |
| awgur@0 | 132 |
| awgur@0 | 133 def __del__(self): |
| awgur@0 | 134 try: |
| awgur@0 | 135 self.fd.close() |
| awgur@0 | 136 except: |
| awgur@0 | 137 pass |
| awgur@0 | 138 |
| awgur@0 | 139 |
| awgur@0 | 140 class LogController(object): |
| awgur@0 | 141 def __init__(self, config: Config): |
| awgur@0 | 142 self.log_dir = config.log_dir |
| awgur@0 | 143 self.keep_logs_days = config.keep_logs_days |
| awgur@2 | 144 self.log_files = [] |
| awgur@2 | 145 self.main_log = None |
| awgur@0 | 146 |
| awgur@0 | 147 @staticmethod |
| awgur@0 | 148 def _get_timeprefix() -> str: |
| awgur@0 | 149 return datetime.now().strftime('%Y-%m-%d_%H-%M-%S') |
| awgur@0 | 150 |
| awgur@0 | 151 def get_logger(self, name: str) -> BaseLogger: |
| awgur@0 | 152 if self.log_dir is not None: |
| awgur@2 | 153 _log_name = p_join(self.log_dir, f'{self._get_timeprefix()} - {name}.log') |
| awgur@2 | 154 if name.lower() != 'main': |
| awgur@2 | 155 self.log_files.append(_log_name) |
| awgur@2 | 156 |
| awgur@2 | 157 else: |
| awgur@2 | 158 self.main_log = _log_name |
| awgur@2 | 159 |
| awgur@2 | 160 return FileLogger(_log_name, appname=name) |
| awgur@2 | 161 |
| awgur@0 | 162 else: |
| awgur@0 | 163 return NullLogger(appname=name) |
| awgur@0 | 164 |
| awgur@0 | 165 def get_filename(self, name: str) -> Optional[str]: |
| awgur@0 | 166 if self.log_dir is not None: |
| awgur@0 | 167 return str(p_join(self.log_dir, f'{self._get_timeprefix()} - {name}.log')) |
| awgur@0 | 168 |
| awgur@0 | 169 def clean(self): |
| awgur@0 | 170 if self.log_dir is not None: |
| awgur@0 | 171 now = time() |
| awgur@0 | 172 for f in listdir(self.log_dir): |
| awgur@0 | 173 f_path = p_join(self.log_dir, f) |
| awgur@0 | 174 f_stat = stat(f_path) |
| awgur@0 | 175 |
| awgur@0 | 176 if divmod(now - f_stat.st_ctime, 86400)[0] > self.keep_logs_days: |
| awgur@0 | 177 file_remove(f_path) |