# Copyright 2016-2017 Versada # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). import logging import urllib.parse import odoo.http _logger = logging.getLogger(__name__) try: from raven.handlers.logging import SentryHandler from raven.processors import SanitizePasswordsProcessor from raven.utils.wsgi import get_environ, get_headers except ImportError: _logger.debug('Cannot import "raven". Please make sure it is installed.') SentryHandler = object SanitizePasswordsProcessor = object def get_request_info(request): ''' Returns context data extracted from :param:`request`. Heavily based on flask integration for Sentry: https://git.io/vP4i9. ''' urlparts = urllib.parse.urlsplit(request.url) return { 'url': '%s://%s%s' % (urlparts.scheme, urlparts.netloc, urlparts.path), 'query_string': urlparts.query, 'method': request.method, 'headers': dict(get_headers(request.environ)), 'env': dict(get_environ(request.environ)), } def get_extra_context(): ''' Extracts additional context from the current request (if such is set). ''' request = odoo.http.request try: session = getattr(request, 'session', {}) except RuntimeError: ctx = {} else: ctx = { 'tags': { 'database': session.get('db', None), }, 'user': { 'login': session.get('login', None), 'uid': session.get('uid', None), }, 'extra': { 'context': session.get('context', {}), }, } if request.httprequest: ctx.update({ 'request': get_request_info(request.httprequest), }) return ctx class LoggerNameFilter(logging.Filter): ''' Custom :class:`logging.Filter` which allows to filter loggers by name. ''' def __init__(self, loggers, name=''): super(LoggerNameFilter, self).__init__(name=name) self._exclude_loggers = set(loggers) def filter(self, event): return event.name not in self._exclude_loggers class OdooSentryHandler(SentryHandler): ''' Customized :class:`raven.handlers.logging.SentryHandler`. Allows to add additional Odoo and HTTP request data to the event which is sent to Sentry. ''' def __init__(self, include_extra_context, *args, **kwargs): super(OdooSentryHandler, self).__init__(*args, **kwargs) self.include_extra_context = include_extra_context def emit(self, record): if self.include_extra_context: self.client.context.merge(get_extra_context()) return super(OdooSentryHandler, self).emit(record) class SanitizeOdooCookiesProcessor(SanitizePasswordsProcessor): ''' Custom :class:`raven.processors.Processor`. Allows to sanitize sensitive Odoo cookies, namely the "session_id" cookie. ''' KEYS = FIELDS = frozenset([ 'session_id', ])