py.lib

Yohn Y. 2019-11-11 Parent:af2bf518950a Child:7874a3e2281e

11:9a4eb7660c11 Browse Files

+ Добавлены простые логгеры

log/__init__.py log/slog_console.py log/slog_syslogger.py log/syslogger.py syslogger.py

     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/log/slog_console.py	Mon Nov 11 21:18:14 2019 +0300
     2.3 @@ -0,0 +1,123 @@
     2.4 +# coding: utf-8
     2.5 +""" Логирование на консоль
     2.6 +
     2.7 +Метки в журнале о уровне сообщения:
     2.8 +  "`": Debug
     2.9 +  ".": Info
    2.10 +  "*": Warning
    2.11 +  "!": Error
    2.12 +  "#": Alert
    2.13 +"""
    2.14 +
    2.15 +from time import time
    2.16 +from datetime import timedelta
    2.17 +from sys import exc_info, stderr, stdout
    2.18 +from traceback import extract_tb, extract_stack
    2.19 +
    2.20 +
    2.21 +class Timing(object):
    2.22 +    def __init__(self, name=None):
    2.23 +        if name is None:
    2.24 +            self.prefix = ''
    2.25 +        else:
    2.26 +            self.prefix = '%s :: ' % name
    2.27 +        self.tsAll = time()
    2.28 +        self.ts = self.tsAll
    2.29 +    
    2.30 +    def getTime(self):
    2.31 +        return time() - self.ts
    2.32 +    
    2.33 +    def reset(self):
    2.34 +        self.ts = time()
    2.35 +        self.tsAll = self.ts
    2.36 +    
    2.37 +    def __str__(self):
    2.38 +        ts = time()
    2.39 +        return self.prefix + '%s(%.4f)' % (timedelta(seconds=(ts - self.tsAll)), ts - self.ts)
    2.40 +    
    2.41 +    def __call__(self, msg):
    2.42 +        _buf = '%s | %s' % (self, msg)
    2.43 +        self.ts = time()
    2.44 +        return _buf
    2.45 +
    2.46 +
    2.47 +class ConsoleLog(object):
    2.48 +    def __init__(self, appname='main'):
    2.49 +        self.appname = appname
    2.50 +
    2.51 +    @staticmethod
    2.52 +    def _write(ItrCntnt):
    2.53 +        for l in ItrCntnt:
    2.54 +            print(l)
    2.55 +
    2.56 +    def __call__(self, msg):
    2.57 +        self._write(map(
    2.58 +                lambda x: '%3s | %s :: %s' % ('.', self.appname, x),
    2.59 +                str(msg).splitlines()
    2.60 +        ))
    2.61 +
    2.62 +    def err(self, msg):
    2.63 +        self._write(map(
    2.64 +            lambda x: '%3s | %s :: %s' % ('!', self.appname, x),
    2.65 +            str(msg).splitlines()
    2.66 +        ))
    2.67 +
    2.68 +    def warn(self, msg):
    2.69 +        self._write(map(
    2.70 +            lambda x: '%3s | %s :: %s' % ('*', self.appname, x),
    2.71 +            str(msg).splitlines()
    2.72 +        ))
    2.73 +
    2.74 +    def alert(self, msg):
    2.75 +        self._write(map(
    2.76 +            lambda x: '%3s | %s :: %s' % ('#', self.appname, x),
    2.77 +            str(msg).splitlines()
    2.78 +        ))
    2.79 +
    2.80 +    def debug(self, msg):
    2.81 +        self._write(map(
    2.82 +            lambda x: '%3s | %s :: %s' % ('`', self.appname, x),
    2.83 +            str(msg).splitlines()
    2.84 +        ))
    2.85 +
    2.86 +    @staticmethod
    2.87 +    def getTiming(name=None):
    2.88 +        return Timing(name)
    2.89 +    
    2.90 +    def sublog(self, name):
    2.91 +        return self.__class__('%s/%s' % (self.appname, name))
    2.92 +    
    2.93 +    def excpt(self, msg, eClass=None, eObj=None, eTb=None, stack_skip=0):
    2.94 +        if eClass is None:
    2.95 +            eClass, eObj, eTb = exc_info()
    2.96 +            
    2.97 +        tbData_tb = list(extract_tb(eTb))[::-1]
    2.98 +        tbData_stack = list(extract_stack())[::-1][(2 + stack_skip):]
    2.99 +        self.err(msg)
   2.100 +        self.err('--- EXCEPTION ---')
   2.101 +        self.err(' %s (%s)' % (eClass.__name__, eObj))
   2.102 +        self.err('--- TRACEBACK ---')
   2.103 +        for _tbFile, _tbLine, _tbFunc, _tbText in tbData_tb:
   2.104 +            self.err('File: %s, line %s in %s' % (_tbFile, _tbLine, _tbFunc))
   2.105 +            self.err('   %s' % _tbText)
   2.106 +        self.err('>>> Exception Handler <<<')
   2.107 +        for _tbFile, _tbLine, _tbFunc, _tbText in tbData_stack:
   2.108 +            self.err('File: %s, line %s in %s' % (_tbFile, _tbLine, _tbFunc))
   2.109 +            self.err('   %s' % _tbText)
   2.110 +        self.err('--- END EXCEPTION ---')
   2.111 +
   2.112 +
   2.113 +class StderrLog(ConsoleLog):
   2.114 +    @staticmethod
   2.115 +    def _write(msgItr):
   2.116 +        for l in msgItr:
   2.117 +            stderr.write('%s\n' % l)
   2.118 +        stderr.flush()
   2.119 +
   2.120 +
   2.121 +class StdoutLog(ConsoleLog):
   2.122 +    @staticmethod
   2.123 +    def _write(msgItr):
   2.124 +        for l in msgItr:
   2.125 +            stdout.write('%s\n' % l)
   2.126 +        stdout.flush()
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/log/slog_syslogger.py	Mon Nov 11 21:18:14 2019 +0300
     3.3 @@ -0,0 +1,99 @@
     3.4 +# coding: utf-8
     3.5 +"""
     3.6 +Тривиальная реализация сислоггера без блэк-джека и поэтесс
     3.7 +
     3.8 +Метки в журнале о уровне сообщения:
     3.9 +  "`": Debug
    3.10 +  ".": Info
    3.11 +  "*": Warning
    3.12 +  "!": Error
    3.13 +  "#": Alert
    3.14 +
    3.15 +"""
    3.16 +from time import time
    3.17 +from datetime import timedelta
    3.18 +
    3.19 +import syslog
    3.20 +from traceback import extract_tb, extract_stack
    3.21 +from sys import exc_info
    3.22 +
    3.23 +
    3.24 +class Timing(object):
    3.25 +    def __init__(self, name=None):
    3.26 +        if name is None:
    3.27 +            self.prefix = ''
    3.28 +        else:
    3.29 +            self.prefix = '%s :: ' % name
    3.30 +        self.tsAll = time()
    3.31 +        self.ts = self.tsAll
    3.32 +
    3.33 +    def getTime(self):
    3.34 +        return time() - self.ts
    3.35 +
    3.36 +    def reset(self):
    3.37 +        self.ts = time()
    3.38 +        self.tsAll = self.ts
    3.39 +
    3.40 +    def __str__(self):
    3.41 +        ts = time()
    3.42 +        return self.prefix + '%s(%.4f)' % (timedelta(seconds=(ts - self.tsAll)), ts - self.ts)
    3.43 +
    3.44 +    def __call__(self, msg):
    3.45 +        _buf = '%s | %s' % (self, msg)
    3.46 +        self.ts = time()
    3.47 +        return _buf
    3.48 +
    3.49 +
    3.50 +class SimpleSysLogger(object):
    3.51 +    @staticmethod
    3.52 +    def initSyslog(ident):
    3.53 +        syslog.openlog(ident, syslog.LOG_PID)
    3.54 +
    3.55 +    @staticmethod
    3.56 +    def getTiming(name=None):
    3.57 +        return Timing(name)
    3.58 +
    3.59 +    def __init__(self, prefix, facility=syslog.LOG_USER):
    3.60 +        self.prefix = str(prefix)
    3.61 +        self.facility = facility
    3.62 +
    3.63 +    def _write(self, flag, mark, msg):
    3.64 +        for l in str(msg).splitlines():
    3.65 +            syslog.syslog(self.facility | flag, '%s: %s %s' % (self.prefix, mark, l))
    3.66 +
    3.67 +    def __call__(self, msg):
    3.68 +        self._write(syslog.LOG_INFO, '.', msg)
    3.69 +    
    3.70 +    def err(self, msg):
    3.71 +        self._write(syslog.LOG_ERR, '!', msg)
    3.72 +    
    3.73 +    def warn(self, msg):
    3.74 +        self._write(syslog.LOG_WARNING, '*', msg)
    3.75 +    
    3.76 +    def debug(self, msg):
    3.77 +        self._write(syslog.LOG_DEBUG, '`', msg)
    3.78 +
    3.79 +    def alert(self, msg):
    3.80 +        self._write(syslog.LOG_ALERT, '#', msg)
    3.81 +
    3.82 +    def sublog(self, prefix):
    3.83 +        return self.__class__('%s/%s' % (self.prefix, prefix), self.facility)
    3.84 +
    3.85 +    def excpt(self, msg, eClass=None, eObj=None, eTb=None, stack_skip=0):
    3.86 +        if eClass is None:
    3.87 +            eClass, eObj, eTb = exc_info()
    3.88 +        
    3.89 +        tbData_tb = list(extract_tb(eTb))[::-1]
    3.90 +        tbData_stack = list(extract_stack())[::-1][(2 + stack_skip):]
    3.91 +        self.err(msg)
    3.92 +        self.err('--- EXCEPTION ---')
    3.93 +        self.err(' %s (%s)' % (eClass.__name__, eObj))
    3.94 +        self.err('--- TRACEBACK ---')
    3.95 +        for _tbFile, _tbLine, _tbFunc, _tbText in tbData_tb:
    3.96 +            self.err('File: %s, line %s in %s' % (_tbFile, _tbLine, _tbFunc))
    3.97 +            self.err('   %s' % _tbText)
    3.98 +        self.err('>>> Exception Handler <<<')
    3.99 +        for _tbFile, _tbLine, _tbFunc, _tbText in tbData_stack:
   3.100 +            self.err('File: %s, line %s in %s' % (_tbFile, _tbLine, _tbFunc))
   3.101 +            self.err('   %s' % _tbText)
   3.102 +        self.err('--- END EXCEPTION ---')
   3.103 \ No newline at end of file
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/log/syslogger.py	Mon Nov 11 21:18:14 2019 +0300
     4.3 @@ -0,0 +1,278 @@
     4.4 +#!/usr/bin/env python
     4.5 +# -*- coding: utf-8 -*-
     4.6 +""" Логирование в системный журнал Unix
     4.7 +
     4.8 +Метки в журнале о уровне сообщения:
     4.9 +  "`": Debug
    4.10 +  ".": Info
    4.11 +  "*": Warning
    4.12 +  "!": Error
    4.13 +  "#": Alert
    4.14 +"""
    4.15 +import syslog
    4.16 +from sys import argv, version_info, exc_info
    4.17 +from time import time
    4.18 +from traceback import extract_tb
    4.19 +
    4.20 +LOG_FACILITY = {
    4.21 +    'auth': syslog.LOG_AUTH,
    4.22 +    'authpriv': syslog.LOG_AUTH,
    4.23 +    'cron': syslog.LOG_CRON,
    4.24 +    'daemon': syslog.LOG_DAEMON,
    4.25 +    'ftp': syslog.LOG_DAEMON,
    4.26 +    'kern': syslog.LOG_KERN,
    4.27 +    'lpr': syslog.LOG_LPR,
    4.28 +    'mail': syslog.LOG_MAIL,
    4.29 +    'news': syslog.LOG_NEWS,
    4.30 +    'syslog': syslog.LOG_SYSLOG,
    4.31 +    'user': syslog.LOG_USER,
    4.32 +    'uucp': syslog.LOG_UUCP,
    4.33 +    'local0': syslog.LOG_LOCAL0,
    4.34 +    'local1': syslog.LOG_LOCAL1,
    4.35 +    'local2': syslog.LOG_LOCAL2,
    4.36 +    'local3': syslog.LOG_LOCAL3,
    4.37 +    'local4': syslog.LOG_LOCAL4,
    4.38 +    'local5': syslog.LOG_LOCAL5,
    4.39 +    'local6': syslog.LOG_LOCAL6,
    4.40 +    'local7': syslog.LOG_LOCAL7
    4.41 +}
    4.42 +
    4.43 +# --- INTERFACE --- #
    4.44 +FACILITY = LOG_FACILITY['user']
    4.45 +def logPrep(ident, facility='user'):
    4.46 +    global FACILITY
    4.47 +    if not facility.lower() in LOG_FACILITY:
    4.48 +        raise LoggerError('Unknown facility')
    4.49 +    syslog.openlog(ident, syslog.LOG_PID)
    4.50 +
    4.51 +    FACILITY = LOG_FACILITY[facility]
    4.52 +
    4.53 +
    4.54 +# --- ABSTRACT PART --- #
    4.55 +
    4.56 +LOG_DEBUG = "`"
    4.57 +LOG_INFO = "."
    4.58 +LOG_WARN = "*"
    4.59 +LOG_ERR = "!"
    4.60 +LOG_ALERT = "#"
    4.61 +
    4.62 +class LoggerError(Exception): pass
    4.63 +
    4.64 +if version_info.major == 3:
    4.65 +    def _strWrap(msg):
    4.66 +        return str(msg)
    4.67 +elif version_info.major == 2:
    4.68 +    def _strWrap(msg):
    4.69 +        if isinstance(msg, unicode):
    4.70 +            return msg
    4.71 +        else:
    4.72 +            return str(msg).decode('utf-8')
    4.73 +else:
    4.74 +    raise LoggerError('Unknown major version of Python')
    4.75 +
    4.76 +
    4.77 +def _splitLines(obj):
    4.78 +    if isinstance(obj, (list, tuple)):
    4.79 +        for i in _parseList(obj):
    4.80 +            yield i
    4.81 +    elif isinstance(obj, dict):
    4.82 +        for i in _parseDict(obj):
    4.83 +            yield i
    4.84 +    else:
    4.85 +        buf = _strWrap(obj).splitlines()
    4.86 +        for i in buf:
    4.87 +            if len(i) < 401:
    4.88 +                yield i
    4.89 +            else:
    4.90 +                i = '<| ' + i + ' |>'
    4.91 +                lenI = len(i)
    4.92 +                c = 0
    4.93 +                while (c + 401) < lenI:
    4.94 +                    yield i[c:c+401]
    4.95 +                    c += 401
    4.96 +                yield i[c:]
    4.97 +
    4.98 +def _parseList(lst):
    4.99 +    for i in lst:
   4.100 +        i = _splitLines(i)
   4.101 +        try:
   4.102 +            yield '- %s' % next(i)
   4.103 +            for l in i:
   4.104 +                yield '  %s' % l
   4.105 +        except StopIteration: pass
   4.106 +
   4.107 +def _parseDict(dct):
   4.108 +    for key in sorted(dct):
   4.109 +        yield '%s:' % key
   4.110 +        for l in _splitLines(dct[key]):
   4.111 +            yield '    %s' % l
   4.112 +
   4.113 +def _parseArgs(a, kwa):
   4.114 +    if a:
   4.115 +        yield '| --- ARGS:'
   4.116 +        for i in _parseList(a):
   4.117 +            yield '| %s' % i
   4.118 +
   4.119 +    if kwa:
   4.120 +        yield '| --- NAMED ARGS:'
   4.121 +        for i in _parseDict(kwa):
   4.122 +            yield '| %s' % i
   4.123 +
   4.124 +    if a or kwa:
   4.125 +        yield '| ---'
   4.126 +
   4.127 +class TimingLog():
   4.128 +    def __init__(self, logproc, opName):
   4.129 +        self.logproc = logproc
   4.130 +        self.opName = opName
   4.131 +        self.dt = time()
   4.132 +
   4.133 +    def __str__(self):
   4.134 +        return '%s :: %.4f' % (self.opName, (time() - self.dt))
   4.135 +
   4.136 +    def __call__(self, msg, *a, **kwa):
   4.137 +        self.logproc('%s | %s' % (self, msg))
   4.138 +        for i in _parseArgs(a, kwa):
   4.139 +            self.logproc('%s | %s' % (self, i))
   4.140 +
   4.141 +    def reset(self):
   4.142 +        self.dt = time()
   4.143 +
   4.144 +
   4.145 +class OperationContext(object):
   4.146 +    def __init__(self, log, opName):
   4.147 +        self.opName = opName
   4.148 +        self.log = log
   4.149 +        self.msgBuf = []
   4.150 +
   4.151 +    def __call__(self, msg, *a, **kwa):
   4.152 +        self.msgBuf.append((msg, [ i for i in map(_strWrap, a)]))
   4.153 +
   4.154 +    def __enter__(self):
   4.155 +        return self
   4.156 +
   4.157 +    def __exit__(self, exc_type, exc_val, exc_tb):
   4.158 +        if exc_type is not None:
   4.159 +            self.log.err("Operation '%s' fail" % self.opName)
   4.160 +            self.log.excpt_handler(exc_type, exc_val, exc_tb)
   4.161 +
   4.162 +            if self.msgBuf:
   4.163 +                self.log.err('--- MESSAGES ---')
   4.164 +                for msg, a, kwa in self.msgBuf:
   4.165 +                    self.log.err(msg, a)
   4.166 +                self.log.err('--- END MESSAGES ---')
   4.167 +
   4.168 +
   4.169 +class AbstractLogger(object):
   4.170 +    def err(self, msg, *a, **kwa):
   4.171 +        raise LoggerError('NotImplemented')
   4.172 +
   4.173 +    def __call__(self, msg, *a, **kwa):
   4.174 +        raise LoggerError('NotImplemented')
   4.175 +
   4.176 +    def excpt_handler(self, eType, eObj, eTb):
   4.177 +        eTb = extract_tb(eTb)
   4.178 +        eType = str(eType)
   4.179 +        try:
   4.180 +            eType = eType.split("'")[1]
   4.181 +        except IndexError:
   4.182 +            pass
   4.183 +
   4.184 +        try:
   4.185 +            eArgs = eObj.args[1:]
   4.186 +        except:
   4.187 +            eArgs = []
   4.188 +
   4.189 +        try:
   4.190 +            eKwa = eObj.kwa
   4.191 +        except:
   4.192 +            eKwa = {}
   4.193 +
   4.194 +        eObj = str(eObj)
   4.195 +
   4.196 +        self.err('--- EXCEPTION ---')
   4.197 +        self.err(eType)
   4.198 +
   4.199 +        for l in _splitLines(eObj):
   4.200 +            self.err('  ' + l)
   4.201 +
   4.202 +        for l in _parseArgs(eArgs, eKwa):
   4.203 +            self.err(l)
   4.204 +
   4.205 +        self.err('--- TRACEBACK ---')
   4.206 +        for _tbFile, _tbLine, _tbFunc, _tbText in eTb:
   4.207 +            self.err('File: %s, line %s in %s' % (_tbFile, _tbLine, _tbFunc))
   4.208 +            self.err('  %s' % _tbText)
   4.209 +        self.err('--- END EXCEPTION ---')
   4.210 +
   4.211 +    def excpt(self, msg, *a, **kwa):
   4.212 +        eType, eObj, eTb = exc_info()
   4.213 +        self.err(msg, *a, **kwa)
   4.214 +        self.excpt_handler(eType, eObj, eTb)
   4.215 +
   4.216 +    def cntxt(self, opName):
   4.217 +        """
   4.218 +        Если операцию нужно залогировать но при этом совершенно не хочется покрывать код
   4.219 +        толстым слоем try ... except можно завернуть операцию в контекст, и даже сохранить
   4.220 +        возвращаемом логером объекте отладочную информацию. При падении и только при нём
   4.221 +        это обязательно попадёт в лог.
   4.222 +
   4.223 +        ОСТОРОЖНО ПАМЯТЬ!!!!!
   4.224 +        Объект копирует себе все переданные данные и опреобразует их сразу в строки
   4.225 +        Если объекту передать одни и те же параметры они всё равно будут храниться
   4.226 +        по копии на каждый вызов в виде строк, что может сьесть много памяти и вызвать
   4.227 +        болезненное её особождение.
   4.228 +
   4.229 +        :param opName: членораздельное имя операции
   4.230 +        """
   4.231 +        return OperationContext(self, opName)
   4.232 +
   4.233 +    def getTiming(self, opName):
   4.234 +        return TimingLog(self, opName)
   4.235 +
   4.236 +    def dumpDict(self, msg, dct):
   4.237 +        self('--- ' + _strWrap(msg))
   4.238 +        for i in _parseDict(dct):
   4.239 +            self('| ' + i)
   4.240 +        self('---')
   4.241 +    
   4.242 +    @staticmethod
   4.243 +    def logPrep(*a, **kwa):
   4.244 +        logPrep(*a, **kwa)
   4.245 +
   4.246 +# --- END ABSTRACT PART --- #
   4.247 +
   4.248 +class Logger(AbstractLogger):
   4.249 +    facility = FACILITY
   4.250 +    def __init__(self, modName = 'main'):
   4.251 +        self.name = modName
   4.252 +
   4.253 +    def _write(self, flags, prefix, msg):
   4.254 +        syslog.syslog(flags, u"%s %s: %s" % (prefix, self.name, msg))
   4.255 +
   4.256 +    def __call__(self, msg, *a, **kwa):
   4.257 +        _flags = self.facility | syslog.LOG_INFO
   4.258 +        _prefix = LOG_INFO + ' ' + self.name + ': '
   4.259 +        syslog.syslog(_flags, _prefix + _strWrap(msg))
   4.260 +        for i in _parseArgs(a, kwa):
   4.261 +            syslog.syslog(_flags, _prefix + i)
   4.262 +
   4.263 +    def warn(self, msg, *a, **kwa):
   4.264 +        _flags = self.facility | syslog.LOG_WARNING
   4.265 +        _prefix = LOG_WARN + ' ' + self.name + ': '
   4.266 +        syslog.syslog(_flags, _prefix + _strWrap(msg))
   4.267 +        for i in _parseArgs(a, kwa):
   4.268 +            syslog.syslog(_flags, _prefix + i)
   4.269 +
   4.270 +    def err(self, msg, *a, **kwa):
   4.271 +        _flags = self.facility | syslog.LOG_ERR
   4.272 +        _prefix = LOG_ERR + ' ' + self.name + ': '
   4.273 +        syslog.syslog(_flags, _prefix + _strWrap(msg))
   4.274 +        for i in _parseArgs(a, kwa):
   4.275 +            syslog.syslog(_flags, _prefix + i)
   4.276 +
   4.277 +
   4.278 +
   4.279 +
   4.280 +
   4.281 +
     5.1 --- a/syslogger.py	Tue Oct 01 23:14:52 2019 +0300
     5.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.3 @@ -1,278 +0,0 @@
     5.4 -#!/usr/bin/env python
     5.5 -# -*- coding: utf-8 -*-
     5.6 -""" Логирование в системный журнал Unix
     5.7 -
     5.8 -Метки в журнале о уровне сообщения:
     5.9 -  "`": Debug
    5.10 -  ".": Info
    5.11 -  "*": Warning
    5.12 -  "!": Error
    5.13 -  "#": Alert
    5.14 -"""
    5.15 -import syslog
    5.16 -from sys import argv, version_info, exc_info
    5.17 -from time import time
    5.18 -from traceback import extract_tb
    5.19 -
    5.20 -LOG_FACILITY = {
    5.21 -    'auth': syslog.LOG_AUTH,
    5.22 -    'authpriv': syslog.LOG_AUTH,
    5.23 -    'cron': syslog.LOG_CRON,
    5.24 -    'daemon': syslog.LOG_DAEMON,
    5.25 -    'ftp': syslog.LOG_DAEMON,
    5.26 -    'kern': syslog.LOG_KERN,
    5.27 -    'lpr': syslog.LOG_LPR,
    5.28 -    'mail': syslog.LOG_MAIL,
    5.29 -    'news': syslog.LOG_NEWS,
    5.30 -    'syslog': syslog.LOG_SYSLOG,
    5.31 -    'user': syslog.LOG_USER,
    5.32 -    'uucp': syslog.LOG_UUCP,
    5.33 -    'local0': syslog.LOG_LOCAL0,
    5.34 -    'local1': syslog.LOG_LOCAL1,
    5.35 -    'local2': syslog.LOG_LOCAL2,
    5.36 -    'local3': syslog.LOG_LOCAL3,
    5.37 -    'local4': syslog.LOG_LOCAL4,
    5.38 -    'local5': syslog.LOG_LOCAL5,
    5.39 -    'local6': syslog.LOG_LOCAL6,
    5.40 -    'local7': syslog.LOG_LOCAL7
    5.41 -}
    5.42 -
    5.43 -# --- INTERFACE --- #
    5.44 -FACILITY = LOG_FACILITY['user']
    5.45 -def logPrep(ident, facility='user'):
    5.46 -    global FACILITY
    5.47 -    if not facility.lower() in LOG_FACILITY:
    5.48 -        raise LoggerError('Unknown facility')
    5.49 -    syslog.openlog(ident, syslog.LOG_PID)
    5.50 -
    5.51 -    FACILITY = LOG_FACILITY[facility]
    5.52 -
    5.53 -
    5.54 -# --- ABSTRACT PART --- #
    5.55 -
    5.56 -LOG_DEBUG = "`"
    5.57 -LOG_INFO = "."
    5.58 -LOG_WARN = "*"
    5.59 -LOG_ERR = "!"
    5.60 -LOG_ALERT = "#"
    5.61 -
    5.62 -class LoggerError(Exception): pass
    5.63 -
    5.64 -if version_info.major == 3:
    5.65 -    def _strWrap(msg):
    5.66 -        return str(msg)
    5.67 -elif version_info.major == 2:
    5.68 -    def _strWrap(msg):
    5.69 -        if isinstance(msg, unicode):
    5.70 -            return msg
    5.71 -        else:
    5.72 -            return str(msg).decode('utf-8')
    5.73 -else:
    5.74 -    raise LoggerError('Unknown major version of Python')
    5.75 -
    5.76 -
    5.77 -def _splitLines(obj):
    5.78 -    if isinstance(obj, (list, tuple)):
    5.79 -        for i in _parseList(obj):
    5.80 -            yield i
    5.81 -    elif isinstance(obj, dict):
    5.82 -        for i in _parseDict(obj):
    5.83 -            yield i
    5.84 -    else:
    5.85 -        buf = _strWrap(obj).splitlines()
    5.86 -        for i in buf:
    5.87 -            if len(i) < 401:
    5.88 -                yield i
    5.89 -            else:
    5.90 -                i = '<| ' + i + ' |>'
    5.91 -                lenI = len(i)
    5.92 -                c = 0
    5.93 -                while (c + 401) < lenI:
    5.94 -                    yield i[c:c+401]
    5.95 -                    c += 401
    5.96 -                yield i[c:]
    5.97 -
    5.98 -def _parseList(lst):
    5.99 -    for i in lst:
   5.100 -        i = _splitLines(i)
   5.101 -        try:
   5.102 -            yield '- %s' % next(i)
   5.103 -            for l in i:
   5.104 -                yield '  %s' % l
   5.105 -        except StopIteration: pass
   5.106 -
   5.107 -def _parseDict(dct):
   5.108 -    for key in sorted(dct):
   5.109 -        yield '%s:' % key
   5.110 -        for l in _splitLines(dct[key]):
   5.111 -            yield '    %s' % l
   5.112 -
   5.113 -def _parseArgs(a, kwa):
   5.114 -    if a:
   5.115 -        yield '| --- ARGS:'
   5.116 -        for i in _parseList(a):
   5.117 -            yield '| %s' % i
   5.118 -
   5.119 -    if kwa:
   5.120 -        yield '| --- NAMED ARGS:'
   5.121 -        for i in _parseDict(kwa):
   5.122 -            yield '| %s' % i
   5.123 -
   5.124 -    if a or kwa:
   5.125 -        yield '| ---'
   5.126 -
   5.127 -class TimingLog():
   5.128 -    def __init__(self, logproc, opName):
   5.129 -        self.logproc = logproc
   5.130 -        self.opName = opName
   5.131 -        self.dt = time()
   5.132 -
   5.133 -    def __str__(self):
   5.134 -        return '%s :: %.4f' % (self.opName, (time() - self.dt))
   5.135 -
   5.136 -    def __call__(self, msg, *a, **kwa):
   5.137 -        self.logproc('%s | %s' % (self, msg))
   5.138 -        for i in _parseArgs(a, kwa):
   5.139 -            self.logproc('%s | %s' % (self, i))
   5.140 -
   5.141 -    def reset(self):
   5.142 -        self.dt = time()
   5.143 -
   5.144 -
   5.145 -class OperationContext(object):
   5.146 -    def __init__(self, log, opName):
   5.147 -        self.opName = opName
   5.148 -        self.log = log
   5.149 -        self.msgBuf = []
   5.150 -
   5.151 -    def __call__(self, msg, *a, **kwa):
   5.152 -        self.msgBuf.append((msg, [ i for i in map(_strWrap, a)]))
   5.153 -
   5.154 -    def __enter__(self):
   5.155 -        return self
   5.156 -
   5.157 -    def __exit__(self, exc_type, exc_val, exc_tb):
   5.158 -        if exc_type is not None:
   5.159 -            self.log.err("Operation '%s' fail" % self.opName)
   5.160 -            self.log.excpt_handler(exc_type, exc_val, exc_tb)
   5.161 -
   5.162 -            if self.msgBuf:
   5.163 -                self.log.err('--- MESSAGES ---')
   5.164 -                for msg, a, kwa in self.msgBuf:
   5.165 -                    self.log.err(msg, a)
   5.166 -                self.log.err('--- END MESSAGES ---')
   5.167 -
   5.168 -
   5.169 -class AbstractLogger(object):
   5.170 -    def err(self, msg, *a, **kwa):
   5.171 -        raise LoggerError('NotImplemented')
   5.172 -
   5.173 -    def __call__(self, msg, *a, **kwa):
   5.174 -        raise LoggerError('NotImplemented')
   5.175 -
   5.176 -    def excpt_handler(self, eType, eObj, eTb):
   5.177 -        eTb = extract_tb(eTb)
   5.178 -        eType = str(eType)
   5.179 -        try:
   5.180 -            eType = eType.split("'")[1]
   5.181 -        except IndexError:
   5.182 -            pass
   5.183 -
   5.184 -        try:
   5.185 -            eArgs = eObj.args[1:]
   5.186 -        except:
   5.187 -            eArgs = []
   5.188 -
   5.189 -        try:
   5.190 -            eKwa = eObj.kwa
   5.191 -        except:
   5.192 -            eKwa = {}
   5.193 -
   5.194 -        eObj = str(eObj)
   5.195 -
   5.196 -        self.err('--- EXCEPTION ---')
   5.197 -        self.err(eType)
   5.198 -
   5.199 -        for l in _splitLines(eObj):
   5.200 -            self.err('  ' + l)
   5.201 -
   5.202 -        for l in _parseArgs(eArgs, eKwa):
   5.203 -            self.err(l)
   5.204 -
   5.205 -        self.err('--- TRACEBACK ---')
   5.206 -        for _tbFile, _tbLine, _tbFunc, _tbText in eTb:
   5.207 -            self.err('File: %s, line %s in %s' % (_tbFile, _tbLine, _tbFunc))
   5.208 -            self.err('  %s' % _tbText)
   5.209 -        self.err('--- END EXCEPTION ---')
   5.210 -
   5.211 -    def excpt(self, msg, *a, **kwa):
   5.212 -        eType, eObj, eTb = exc_info()
   5.213 -        self.err(msg, *a, **kwa)
   5.214 -        self.excpt_handler(eType, eObj, eTb)
   5.215 -
   5.216 -    def cntxt(self, opName):
   5.217 -        """
   5.218 -        Если операцию нужно залогировать но при этом совершенно не хочется покрывать код
   5.219 -        толстым слоем try ... except можно завернуть операцию в контекст, и даже сохранить
   5.220 -        возвращаемом логером объекте отладочную информацию. При падении и только при нём
   5.221 -        это обязательно попадёт в лог.
   5.222 -
   5.223 -        ОСТОРОЖНО ПАМЯТЬ!!!!!
   5.224 -        Объект копирует себе все переданные данные и опреобразует их сразу в строки
   5.225 -        Если объекту передать одни и те же параметры они всё равно будут храниться
   5.226 -        по копии на каждый вызов в виде строк, что может сьесть много памяти и вызвать
   5.227 -        болезненное её особождение.
   5.228 -
   5.229 -        :param opName: членораздельное имя операции
   5.230 -        """
   5.231 -        return OperationContext(self, opName)
   5.232 -
   5.233 -    def getTiming(self, opName):
   5.234 -        return TimingLog(self, opName)
   5.235 -
   5.236 -    def dumpDict(self, msg, dct):
   5.237 -        self('--- ' + _strWrap(msg))
   5.238 -        for i in _parseDict(dct):
   5.239 -            self('| ' + i)
   5.240 -        self('---')
   5.241 -    
   5.242 -    @staticmethod
   5.243 -    def logPrep(*a, **kwa):
   5.244 -        logPrep(*a, **kwa)
   5.245 -
   5.246 -# --- END ABSTRACT PART --- #
   5.247 -
   5.248 -class Logger(AbstractLogger):
   5.249 -    facility = FACILITY
   5.250 -    def __init__(self, modName = 'main'):
   5.251 -        self.name = modName
   5.252 -
   5.253 -    def _write(self, flags, prefix, msg):
   5.254 -        syslog.syslog(flags, u"%s %s: %s" % (prefix, self.name, msg))
   5.255 -
   5.256 -    def __call__(self, msg, *a, **kwa):
   5.257 -        _flags = self.facility | syslog.LOG_INFO
   5.258 -        _prefix = LOG_INFO + ' ' + self.name + ': '
   5.259 -        syslog.syslog(_flags, _prefix + _strWrap(msg))
   5.260 -        for i in _parseArgs(a, kwa):
   5.261 -            syslog.syslog(_flags, _prefix + i)
   5.262 -
   5.263 -    def warn(self, msg, *a, **kwa):
   5.264 -        _flags = self.facility | syslog.LOG_WARNING
   5.265 -        _prefix = LOG_WARN + ' ' + self.name + ': '
   5.266 -        syslog.syslog(_flags, _prefix + _strWrap(msg))
   5.267 -        for i in _parseArgs(a, kwa):
   5.268 -            syslog.syslog(_flags, _prefix + i)
   5.269 -
   5.270 -    def err(self, msg, *a, **kwa):
   5.271 -        _flags = self.facility | syslog.LOG_ERR
   5.272 -        _prefix = LOG_ERR + ' ' + self.name + ': '
   5.273 -        syslog.syslog(_flags, _prefix + _strWrap(msg))
   5.274 -        for i in _parseArgs(a, kwa):
   5.275 -            syslog.syslog(_flags, _prefix + i)
   5.276 -
   5.277 -
   5.278 -
   5.279 -
   5.280 -
   5.281 -