flexget.logger
Covered: 79 lines
Missed: 39 lines
Skipped 58 lines
Percent: 66 %
  1
import logging
  2
import logging.handlers
  3
import re
  4
import sys
  5
import threading
  8
TRACE = 5
 10
VERBOSE = 15
 13
class FlexGetLogger(logging.Logger):
 14
    """Custom logger that adds feed and execution info to log records."""
 15
    local = threading.local()
 17
    def makeRecord(self, name, level, fn, lno, msg, args, exc_info, func=None, extra=None):
 18
        extra = {'feed': getattr(FlexGetLogger.local, 'feed', u''),
 19
                 'execution': getattr(FlexGetLogger.local, 'execution', '')}
 20
        return logging.Logger.makeRecord(self, name, level, fn, lno, msg, args, exc_info, func, extra)
 22
    def trace(self, msg, *args, **kwargs):
 23
        """Log at TRACE level (more detailed than DEBUG)."""
 24
        self.log(TRACE, msg, *args, **kwargs)
 26
    def verbose(self, msg, *args, **kwargs):
 27
        """Log at VERBOSE level (displayed when FlexGet is run interactively.)"""
 28
        self.log(VERBOSE, msg, *args, **kwargs)
 31
    debugall = trace
 34
class FlexGetFormatter(logging.Formatter):
 35
    """Custom formatter that can handle both regular log records and those created by FlexGetLogger"""
 36
    plain_fmt = '%(asctime)-15s %(levelname)-8s %(name)-29s %(message)s'
 37
    flexget_fmt = '%(asctime)-15s %(levelname)-8s %(name)-13s %(feed)-15s %(message)s'
 39
    def __init__(self):
 40
        logging.Formatter.__init__(self, self.plain_fmt, '%Y-%m-%d %H:%M')
 42
    def format(self, record):
 43
        if hasattr(record, 'feed'):
 44
            self._fmt = self.flexget_fmt
 45
        else:
 46
            self._fmt = self.plain_fmt
 47
        return logging.Formatter.format(self, record)
 50
def set_execution(execution):
 51
    FlexGetLogger.local.execution = execution
 54
def set_feed(feed):
 55
    FlexGetLogger.local.feed = feed
 58
class PrivacyFilter(logging.Filter):
 59
    """Edits log messages and <hides> obviously private information."""
 61
    def __init__(self):
 62
        self.replaces = []
 64
        def hide(name):
 65
            s = '([?&]%s=)\w+' % name
 66
            p = re.compile(s)
 67
            self.replaces.append(p)
 69
        for param in ['passwd', 'password', 'pw', 'pass', 'passkey',
 70
            'key', 'apikey', 'user', 'username', 'uname', 'login', 'id']:
 71
            hide(param)
 73
    def filter(self, record):
 74
        if not isinstance(record.msg, basestring):
 75
            return False
 76
        for p in self.replaces:
 77
            record.msg = p.sub(r'\g<1><hidden>', record.msg)
 78
            record.msg = record.msg
 79
        return False
 81
_logging_configured = False
 82
_mem_handler = None
 83
_logging_started = False
 86
def initialize(unit_test=False):
 87
    """Prepare logging.
 88
    """
 89
    global _logging_configured, _mem_handler
 91
    if _logging_configured:
 92
        return
 94
    logging.addLevelName(TRACE, 'TRACE')
 95
    logging.addLevelName(VERBOSE, 'VERBOSE')
 96
    _logging_configured = True
 99
    if unit_test:
100
        logging.basicConfig()
101
        return
104
    logger = logging.getLogger()
105
    formatter = FlexGetFormatter()
107
    _mem_handler = logging.handlers.MemoryHandler(1000 * 1000, 100)
108
    _mem_handler.setFormatter(formatter)
109
    logger.addHandler(_mem_handler)
116
    if '--debug' in sys.argv:
117
        logger.setLevel(logging.DEBUG)
118
    elif '--debug-trace' in sys.argv:
119
        logger.setLevel(TRACE)
120
    elif '--cron' not in sys.argv:
121
        logger.setLevel(VERBOSE)
122
    else:
123
        logger.setLevel(logging.INFO)
127
    if not '--cron' in sys.argv:
128
        console = logging.StreamHandler()
129
        console.setFormatter(formatter)
130
        logger.addHandler(console)
133
def start(filename=None, level=logging.INFO, debug=False):
134
    """After initialization, start file logging.
135
    """
136
    global _logging_started
138
    assert _logging_configured
139
    if _logging_started:
140
        return
142
    if debug:
143
        handler = logging.StreamHandler()
144
    else:
145
        handler = logging.handlers.RotatingFileHandler(filename, maxBytes=1000 * 1024, backupCount=9)
147
    handler.setFormatter(_mem_handler.formatter)
149
    _mem_handler.setTarget(handler)
152
    logger = logging.getLogger()
153
    logger.removeHandler(_mem_handler)
154
    logger.addHandler(handler)
155
    logger.addFilter(PrivacyFilter())
156
    logger.setLevel(level)
159
    _mem_handler.flush()
160
    _logging_started = True
163
def flush_logging_to_console():
164
    """Flushes memory logger to console"""
165
    console = logging.StreamHandler()
166
    console.setFormatter(_mem_handler.formatter)
167
    logger = logging.getLogger()
168
    logger.addHandler(console)
169
    if len(_mem_handler.buffer) > 0:
170
        for record in _mem_handler.buffer:
171
            console.handle(record)
172
    _mem_handler.flush()
175
logging.setLoggerClass(FlexGetLogger)