py.lib
2019-10-01
Parent:b18b6e30d6ba
py.lib/syslogger.py
+ Модуль - сосуд всяких идей по рабоче с SSH. Вообще нужно разобрать его
| awgur@9 | 1 #!/usr/bin/env python |
| awgur@9 | 2 # -*- coding: utf-8 -*- |
| awgur@9 | 3 """ Логирование в системный журнал Unix |
| awgur@9 | 4 |
| awgur@9 | 5 Метки в журнале о уровне сообщения: |
| awgur@9 | 6 "`": Debug |
| awgur@9 | 7 ".": Info |
| awgur@9 | 8 "*": Warning |
| awgur@9 | 9 "!": Error |
| awgur@9 | 10 "#": Alert |
| awgur@9 | 11 """ |
| awgur@9 | 12 import syslog |
| awgur@9 | 13 from sys import argv, version_info, exc_info |
| awgur@9 | 14 from time import time |
| awgur@9 | 15 from traceback import extract_tb |
| awgur@9 | 16 |
| awgur@9 | 17 LOG_FACILITY = { |
| awgur@9 | 18 'auth': syslog.LOG_AUTH, |
| awgur@9 | 19 'authpriv': syslog.LOG_AUTH, |
| awgur@9 | 20 'cron': syslog.LOG_CRON, |
| awgur@9 | 21 'daemon': syslog.LOG_DAEMON, |
| awgur@9 | 22 'ftp': syslog.LOG_DAEMON, |
| awgur@9 | 23 'kern': syslog.LOG_KERN, |
| awgur@9 | 24 'lpr': syslog.LOG_LPR, |
| awgur@9 | 25 'mail': syslog.LOG_MAIL, |
| awgur@9 | 26 'news': syslog.LOG_NEWS, |
| awgur@9 | 27 'syslog': syslog.LOG_SYSLOG, |
| awgur@9 | 28 'user': syslog.LOG_USER, |
| awgur@9 | 29 'uucp': syslog.LOG_UUCP, |
| awgur@9 | 30 'local0': syslog.LOG_LOCAL0, |
| awgur@9 | 31 'local1': syslog.LOG_LOCAL1, |
| awgur@9 | 32 'local2': syslog.LOG_LOCAL2, |
| awgur@9 | 33 'local3': syslog.LOG_LOCAL3, |
| awgur@9 | 34 'local4': syslog.LOG_LOCAL4, |
| awgur@9 | 35 'local5': syslog.LOG_LOCAL5, |
| awgur@9 | 36 'local6': syslog.LOG_LOCAL6, |
| awgur@9 | 37 'local7': syslog.LOG_LOCAL7 |
| awgur@9 | 38 } |
| awgur@9 | 39 |
| awgur@9 | 40 # --- INTERFACE --- # |
| awgur@9 | 41 FACILITY = LOG_FACILITY['user'] |
| awgur@9 | 42 def logPrep(ident, facility='user'): |
| awgur@9 | 43 global FACILITY |
| awgur@9 | 44 if not facility.lower() in LOG_FACILITY: |
| awgur@9 | 45 raise LoggerError('Unknown facility') |
| awgur@9 | 46 syslog.openlog(ident, syslog.LOG_PID) |
| awgur@9 | 47 |
| awgur@9 | 48 FACILITY = LOG_FACILITY[facility] |
| awgur@9 | 49 |
| awgur@9 | 50 |
| awgur@9 | 51 # --- ABSTRACT PART --- # |
| awgur@9 | 52 |
| awgur@9 | 53 LOG_DEBUG = "`" |
| awgur@9 | 54 LOG_INFO = "." |
| awgur@9 | 55 LOG_WARN = "*" |
| awgur@9 | 56 LOG_ERR = "!" |
| awgur@9 | 57 LOG_ALERT = "#" |
| awgur@9 | 58 |
| awgur@9 | 59 class LoggerError(Exception): pass |
| awgur@9 | 60 |
| awgur@9 | 61 if version_info.major == 3: |
| awgur@9 | 62 def _strWrap(msg): |
| awgur@9 | 63 return str(msg) |
| awgur@9 | 64 elif version_info.major == 2: |
| awgur@9 | 65 def _strWrap(msg): |
| awgur@9 | 66 if isinstance(msg, unicode): |
| awgur@9 | 67 return msg |
| awgur@9 | 68 else: |
| awgur@9 | 69 return str(msg).decode('utf-8') |
| awgur@9 | 70 else: |
| awgur@9 | 71 raise LoggerError('Unknown major version of Python') |
| awgur@9 | 72 |
| awgur@9 | 73 |
| awgur@9 | 74 def _splitLines(obj): |
| awgur@9 | 75 if isinstance(obj, (list, tuple)): |
| awgur@9 | 76 for i in _parseList(obj): |
| awgur@9 | 77 yield i |
| awgur@9 | 78 elif isinstance(obj, dict): |
| awgur@9 | 79 for i in _parseDict(obj): |
| awgur@9 | 80 yield i |
| awgur@9 | 81 else: |
| awgur@9 | 82 buf = _strWrap(obj).splitlines() |
| awgur@9 | 83 for i in buf: |
| awgur@9 | 84 if len(i) < 401: |
| awgur@9 | 85 yield i |
| awgur@9 | 86 else: |
| awgur@9 | 87 i = '<| ' + i + ' |>' |
| awgur@9 | 88 lenI = len(i) |
| awgur@9 | 89 c = 0 |
| awgur@9 | 90 while (c + 401) < lenI: |
| awgur@9 | 91 yield i[c:c+401] |
| awgur@9 | 92 c += 401 |
| awgur@9 | 93 yield i[c:] |
| awgur@9 | 94 |
| awgur@9 | 95 def _parseList(lst): |
| awgur@9 | 96 for i in lst: |
| awgur@9 | 97 i = _splitLines(i) |
| awgur@9 | 98 try: |
| awgur@9 | 99 yield '- %s' % next(i) |
| awgur@9 | 100 for l in i: |
| awgur@9 | 101 yield ' %s' % l |
| awgur@9 | 102 except StopIteration: pass |
| awgur@9 | 103 |
| awgur@9 | 104 def _parseDict(dct): |
| awgur@9 | 105 for key in sorted(dct): |
| awgur@9 | 106 yield '%s:' % key |
| awgur@9 | 107 for l in _splitLines(dct[key]): |
| awgur@9 | 108 yield ' %s' % l |
| awgur@9 | 109 |
| awgur@9 | 110 def _parseArgs(a, kwa): |
| awgur@9 | 111 if a: |
| awgur@9 | 112 yield '| --- ARGS:' |
| awgur@9 | 113 for i in _parseList(a): |
| awgur@9 | 114 yield '| %s' % i |
| awgur@9 | 115 |
| awgur@9 | 116 if kwa: |
| awgur@9 | 117 yield '| --- NAMED ARGS:' |
| awgur@9 | 118 for i in _parseDict(kwa): |
| awgur@9 | 119 yield '| %s' % i |
| awgur@9 | 120 |
| awgur@9 | 121 if a or kwa: |
| awgur@9 | 122 yield '| ---' |
| awgur@9 | 123 |
| awgur@9 | 124 class TimingLog(): |
| awgur@9 | 125 def __init__(self, logproc, opName): |
| awgur@9 | 126 self.logproc = logproc |
| awgur@9 | 127 self.opName = opName |
| awgur@9 | 128 self.dt = time() |
| awgur@9 | 129 |
| awgur@9 | 130 def __str__(self): |
| awgur@9 | 131 return '%s :: %.4f' % (self.opName, (time() - self.dt)) |
| awgur@9 | 132 |
| awgur@9 | 133 def __call__(self, msg, *a, **kwa): |
| awgur@9 | 134 self.logproc('%s | %s' % (self, msg)) |
| awgur@9 | 135 for i in _parseArgs(a, kwa): |
| awgur@9 | 136 self.logproc('%s | %s' % (self, i)) |
| awgur@9 | 137 |
| awgur@9 | 138 def reset(self): |
| awgur@9 | 139 self.dt = time() |
| awgur@9 | 140 |
| awgur@9 | 141 |
| awgur@9 | 142 class OperationContext(object): |
| awgur@9 | 143 def __init__(self, log, opName): |
| awgur@9 | 144 self.opName = opName |
| awgur@9 | 145 self.log = log |
| awgur@9 | 146 self.msgBuf = [] |
| awgur@9 | 147 |
| awgur@9 | 148 def __call__(self, msg, *a, **kwa): |
| awgur@9 | 149 self.msgBuf.append((msg, [ i for i in map(_strWrap, a)])) |
| awgur@9 | 150 |
| awgur@9 | 151 def __enter__(self): |
| awgur@9 | 152 return self |
| awgur@9 | 153 |
| awgur@9 | 154 def __exit__(self, exc_type, exc_val, exc_tb): |
| awgur@9 | 155 if exc_type is not None: |
| awgur@9 | 156 self.log.err("Operation '%s' fail" % self.opName) |
| awgur@9 | 157 self.log.excpt_handler(exc_type, exc_val, exc_tb) |
| awgur@9 | 158 |
| awgur@9 | 159 if self.msgBuf: |
| awgur@9 | 160 self.log.err('--- MESSAGES ---') |
| awgur@9 | 161 for msg, a, kwa in self.msgBuf: |
| awgur@9 | 162 self.log.err(msg, a) |
| awgur@9 | 163 self.log.err('--- END MESSAGES ---') |
| awgur@9 | 164 |
| awgur@9 | 165 |
| awgur@9 | 166 class AbstractLogger(object): |
| awgur@9 | 167 def err(self, msg, *a, **kwa): |
| awgur@9 | 168 raise LoggerError('NotImplemented') |
| awgur@9 | 169 |
| awgur@9 | 170 def __call__(self, msg, *a, **kwa): |
| awgur@9 | 171 raise LoggerError('NotImplemented') |
| awgur@9 | 172 |
| awgur@9 | 173 def excpt_handler(self, eType, eObj, eTb): |
| awgur@9 | 174 eTb = extract_tb(eTb) |
| awgur@9 | 175 eType = str(eType) |
| awgur@9 | 176 try: |
| awgur@9 | 177 eType = eType.split("'")[1] |
| awgur@9 | 178 except IndexError: |
| awgur@9 | 179 pass |
| awgur@9 | 180 |
| awgur@9 | 181 try: |
| awgur@9 | 182 eArgs = eObj.args[1:] |
| awgur@9 | 183 except: |
| awgur@9 | 184 eArgs = [] |
| awgur@9 | 185 |
| awgur@9 | 186 try: |
| awgur@9 | 187 eKwa = eObj.kwa |
| awgur@9 | 188 except: |
| awgur@9 | 189 eKwa = {} |
| awgur@9 | 190 |
| awgur@9 | 191 eObj = str(eObj) |
| awgur@9 | 192 |
| awgur@9 | 193 self.err('--- EXCEPTION ---') |
| awgur@9 | 194 self.err(eType) |
| awgur@9 | 195 |
| awgur@9 | 196 for l in _splitLines(eObj): |
| awgur@9 | 197 self.err(' ' + l) |
| awgur@9 | 198 |
| awgur@9 | 199 for l in _parseArgs(eArgs, eKwa): |
| awgur@9 | 200 self.err(l) |
| awgur@9 | 201 |
| awgur@9 | 202 self.err('--- TRACEBACK ---') |
| awgur@9 | 203 for _tbFile, _tbLine, _tbFunc, _tbText in eTb: |
| awgur@9 | 204 self.err('File: %s, line %s in %s' % (_tbFile, _tbLine, _tbFunc)) |
| awgur@9 | 205 self.err(' %s' % _tbText) |
| awgur@9 | 206 self.err('--- END EXCEPTION ---') |
| awgur@9 | 207 |
| awgur@9 | 208 def excpt(self, msg, *a, **kwa): |
| awgur@9 | 209 eType, eObj, eTb = exc_info() |
| awgur@9 | 210 self.err(msg, *a, **kwa) |
| awgur@9 | 211 self.excpt_handler(eType, eObj, eTb) |
| awgur@9 | 212 |
| awgur@9 | 213 def cntxt(self, opName): |
| awgur@9 | 214 """ |
| awgur@9 | 215 Если операцию нужно залогировать но при этом совершенно не хочется покрывать код |
| awgur@9 | 216 толстым слоем try ... except можно завернуть операцию в контекст, и даже сохранить |
| awgur@9 | 217 возвращаемом логером объекте отладочную информацию. При падении и только при нём |
| awgur@9 | 218 это обязательно попадёт в лог. |
| awgur@9 | 219 |
| awgur@9 | 220 ОСТОРОЖНО ПАМЯТЬ!!!!! |
| awgur@9 | 221 Объект копирует себе все переданные данные и опреобразует их сразу в строки |
| awgur@9 | 222 Если объекту передать одни и те же параметры они всё равно будут храниться |
| awgur@9 | 223 по копии на каждый вызов в виде строк, что может сьесть много памяти и вызвать |
| awgur@9 | 224 болезненное её особождение. |
| awgur@9 | 225 |
| awgur@9 | 226 :param opName: членораздельное имя операции |
| awgur@9 | 227 """ |
| awgur@9 | 228 return OperationContext(self, opName) |
| awgur@9 | 229 |
| awgur@9 | 230 def getTiming(self, opName): |
| awgur@9 | 231 return TimingLog(self, opName) |
| awgur@9 | 232 |
| awgur@9 | 233 def dumpDict(self, msg, dct): |
| awgur@9 | 234 self('--- ' + _strWrap(msg)) |
| awgur@9 | 235 for i in _parseDict(dct): |
| awgur@9 | 236 self('| ' + i) |
| awgur@9 | 237 self('---') |
| awgur@9 | 238 |
| awgur@9 | 239 @staticmethod |
| awgur@9 | 240 def logPrep(*a, **kwa): |
| awgur@9 | 241 logPrep(*a, **kwa) |
| awgur@9 | 242 |
| awgur@9 | 243 # --- END ABSTRACT PART --- # |
| awgur@9 | 244 |
| awgur@9 | 245 class Logger(AbstractLogger): |
| awgur@9 | 246 facility = FACILITY |
| awgur@9 | 247 def __init__(self, modName = 'main'): |
| awgur@9 | 248 self.name = modName |
| awgur@9 | 249 |
| awgur@9 | 250 def _write(self, flags, prefix, msg): |
| awgur@9 | 251 syslog.syslog(flags, u"%s %s: %s" % (prefix, self.name, msg)) |
| awgur@9 | 252 |
| awgur@9 | 253 def __call__(self, msg, *a, **kwa): |
| awgur@9 | 254 _flags = self.facility | syslog.LOG_INFO |
| awgur@9 | 255 _prefix = LOG_INFO + ' ' + self.name + ': ' |
| awgur@9 | 256 syslog.syslog(_flags, _prefix + _strWrap(msg)) |
| awgur@9 | 257 for i in _parseArgs(a, kwa): |
| awgur@9 | 258 syslog.syslog(_flags, _prefix + i) |
| awgur@9 | 259 |
| awgur@9 | 260 def warn(self, msg, *a, **kwa): |
| awgur@9 | 261 _flags = self.facility | syslog.LOG_WARNING |
| awgur@9 | 262 _prefix = LOG_WARN + ' ' + self.name + ': ' |
| awgur@9 | 263 syslog.syslog(_flags, _prefix + _strWrap(msg)) |
| awgur@9 | 264 for i in _parseArgs(a, kwa): |
| awgur@9 | 265 syslog.syslog(_flags, _prefix + i) |
| awgur@9 | 266 |
| awgur@9 | 267 def err(self, msg, *a, **kwa): |
| awgur@9 | 268 _flags = self.facility | syslog.LOG_ERR |
| awgur@9 | 269 _prefix = LOG_ERR + ' ' + self.name + ': ' |
| awgur@9 | 270 syslog.syslog(_flags, _prefix + _strWrap(msg)) |
| awgur@9 | 271 for i in _parseArgs(a, kwa): |
| awgur@9 | 272 syslog.syslog(_flags, _prefix + i) |
| awgur@9 | 273 |
| awgur@9 | 274 |
| awgur@9 | 275 |
| awgur@9 | 276 |
| awgur@9 | 277 |
| awgur@9 | 278 |