Passed
Push — master ( aeb165...d9ae97 )
by Dean
03:04
created

LoggerManager.setup_warnings()   A

Complexity

Conditions 3

Size

Total Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 9.0292
Metric Value
dl 0
loc 12
ccs 1
cts 8
cp 0.125
rs 9.4285
cc 3
crap 9.0292

1 Method

Rating   Name   Duplication   Size   Complexity  
A LoggerManager.callback() 0 6 2
1 1
from plugin.core.constants import PLUGIN_IDENTIFIER
2 1
from plugin.core.environment import Environment
3 1
from plugin.core.helpers.variable import md5
4 1
from plugin.core.logger.filters import FrameworkFilter, AuthorizationFilter, RequestsLogFilter
5
6 1
from logging.handlers import RotatingFileHandler
7 1
from raven.utils import gethostname
8 1
import logging
9 1
import uuid
10 1
import warnings
11
12 1
LOG_FORMAT = '%(asctime)-15s - %(name)-32s (%(thread)x) :  %(levelname)s (%(name)s:%(lineno)d) - %(message)s'
13 1
LOG_OPTIONS = {
14
    'plex':                         'libraries',
15
    'plex_activity':                'libraries',
16
    'plex_metadata':                'libraries',
17
    'raven':                        'libraries',
18
    'requests':                     'libraries',
19
    'trakt':                        'libraries',
20
21
    'peewee':                       'peewee',
22
    'peewee_migrate':               'peewee',
23
24
    'com.plexapp.plugins.trakttv':  'plugin',
25
    'plugin':                       'plugin',
26
27
    'pyemitter':                    'pyemitter'
28
}
29
30 1
TRACE = 5
31
32 1
log = logging.getLogger(__name__)
33
34
35 1
class LogHandler(logging.Handler):
36 1
    def __init__(self, handler):
37
        super(LogHandler, self).__init__()
38
39
        self.handler = handler
40
41
        # Update formatter for log file
42
        self.handler.formatter._fmt = LOG_FORMAT
43
44 1
    @property
45
    def baseFilename(self):
46
        return self.handler.baseFilename
47
48 1
    def emit(self, record):
49
        return self.handler.emit(record)
50
51
52 1
class LoggerManager(object):
53 1
    @staticmethod
54
    def get_handler():
55 1
        logger = logging.getLogger(PLUGIN_IDENTIFIER)
56
57 1
        for h in logger.handlers:
58
            if type(h) is RotatingFileHandler:
59
                logger.handlers.remove(h)
60
                return LogHandler(h)
61
62 1
        return None
63
64 1
    @classmethod
65 1
    def setup(cls, report=True, storage=True):
66
        cls.setup_logging(report, storage)
67
        cls.setup_warnings()
68
69
        if report:
70
            cls.setup_raven()
71
72
        log.debug('Initialized logging (report: %r, storage: %r)', report, storage)
73
74 1
    @staticmethod
75 1
    def setup_logging(report=True, storage=True):
76
        # Setup root logger
77
        rootLogger = logging.getLogger()
78
79
        # Set filters
80
        rootLogger.filters = [
81
            FrameworkFilter()
82
        ]
83
84
        # Set level
85
        rootLogger.setLevel(logging.DEBUG)
86
87
        # Set handlers
88
        rootLogger.handlers = [
89
            LOG_HANDLER
90
        ]
91
92
        # Setup error reporting (if enabled)
93
        if report:
94
            from plugin.core.logger.handlers.error_reporter import ERROR_REPORTER_HANDLER
95
96
            rootLogger.handlers.append(ERROR_REPORTER_HANDLER)
97
98
        # Setup local error storage (if enabled)
99
        if storage:
100
            from plugin.core.logger.handlers.error_storage import ERROR_STORAGE_HANDLER
101
102
            rootLogger.handlers.append(ERROR_STORAGE_HANDLER)
103
104 1
    @classmethod
105
    def setup_raven(cls):
106
        from plugin.core.logger.handlers.error_reporter import RAVEN
107
108
        # Generate client identifier
109
        RAVEN.name = cls.generate_id()
110
111
        # Include server version in error reports
112
        try:
113
            RAVEN.tags.update({'server.version': Environment.platform.server_version})
114
        except Exception, ex:
115
            log.warn('Unable to retrieve server version - %s', ex, exc_info=True)
116
117 1
    @classmethod
118
    def setup_warnings(cls):
119
        logger = logging.getLogger('warnings')
120
121
        def callback(message, category, filename, lineno, file=None, line=None):
122
            if not category:
123
                logger.warn(message)
124
                return
125
126
            logger.warn('[%s] %s' % (category.__name__, message))
127
128
        warnings.showwarning = callback
129
130 1
    @staticmethod
131
    def generate_id():
132
        # Try use hashed machine identifier
133
        try:
134
            return md5(Environment.platform.machine_identifier)
135
        except Exception, ex:
136
            log.warn('Unable to generate id from machine identifier - %s', ex, exc_info=True)
137
138
        # Try use hashed hostname
139
        try:
140
            return md5(gethostname().encode('utf-8'))
141
        except Exception, ex:
142
            log.warn('Unable to generate id from hostname - %s', ex, exc_info=True)
143
144
        # Fallback to random identifier
145
        return md5(str(uuid.uuid4()))
146
147 1
    @classmethod
148
    def refresh(cls):
149
        for name, option in LOG_OPTIONS.items():
150
            logger = logging.getLogger(name)
151
152
            # Retrieve logger level, check if it has changed
153
            level = cls.get_level(option)
154
155
            if level == logger.level:
156
                continue
157
158
            # Update logger level
159
            log.debug('Changed %r logger level to %s', name, logging.getLevelName(level))
160
161
            logger.setLevel(level)
162
163 1
    @staticmethod
164
    def get_level(option):
165
        # Try retrieve preference
166
        try:
167
            value = Environment.prefs['level_%s' % option]
168
        except KeyError:
169
            # Default to "plugin" preference
170
            value = Environment.prefs['level_plugin']
171
172
        # Parse labels into level attributes
173
        if value == 'ERROR':
174
            return logging.ERROR
175
176
        if value == 'WARN' or value == 'WARNING':
177
            return logging.WARNING
178
179
        if value == 'INFO':
180
            return logging.INFO
181
182
        if value == 'DEBUG':
183
            return logging.DEBUG
184
185
        if value == "TRACE":
186
            return TRACE
187
188
        log.warn('Unknown logging level "%s"', value)
189
        return logging.DEBUG
190
191
# Get the logging file handler
192 1
LOG_HANDLER = LoggerManager.get_handler()
193
194 1
if LOG_HANDLER:
195
    LOG_HANDLER.addFilter(AuthorizationFilter())
196
    LOG_HANDLER.addFilter(RequestsLogFilter())
197