diff --git a/sentry/__init__.py b/sentry/__init__.py
index 968f6ae31..ccee682e4 100644
--- a/sentry/__init__.py
+++ b/sentry/__init__.py
@@ -22,41 +22,44 @@ except ImportError:
def get_odoo_commit(odoo_dir):
- '''Attempts to get Odoo git commit from :param:`odoo_dir`.'''
+ """Attempts to get Odoo git commit from :param:`odoo_dir`."""
if not odoo_dir:
return
try:
return raven.fetch_git_sha(odoo_dir)
except raven.exceptions.InvalidGitRepository:
- _logger.debug(
- 'Odoo directory: "%s" not a valid git repository', odoo_dir)
+ _logger.debug('Odoo directory: "%s" not a valid git repository', odoo_dir)
def initialize_raven(config, client_cls=None):
- '''
+ """
Setup an instance of :class:`raven.Client`.
:param config: Sentry configuration
:param client: class used to instantiate the raven client.
- '''
- enabled = config.get('sentry_enabled', False)
+ """
+ enabled = config.get("sentry_enabled", False)
if not (HAS_RAVEN and enabled):
return
- if config.get('sentry_odoo_dir') and config.get('sentry_release'):
- _logger.debug('Both sentry_odoo_dir and sentry_release defined, choosing sentry_release')
+ if config.get("sentry_odoo_dir") and config.get("sentry_release"):
+ _logger.debug(
+ "Both sentry_odoo_dir and sentry_release defined, choosing sentry_release"
+ )
options = {
- 'release': config.get('sentry_release', get_odoo_commit(config.get('sentry_odoo_dir'))),
+ "release": config.get(
+ "sentry_release", get_odoo_commit(config.get("sentry_odoo_dir"))
+ )
}
for option in const.get_sentry_options():
- value = config.get('sentry_%s' % option.key, option.default)
+ value = config.get("sentry_%s" % option.key, option.default)
if isinstance(option.converter, collections.Callable):
value = option.converter(value)
options[option.key] = value
- level = config.get('sentry_logging_level', const.DEFAULT_LOG_LEVEL)
+ level = config.get("sentry_logging_level", const.DEFAULT_LOG_LEVEL)
exclude_loggers = const.split_multiple(
- config.get('sentry_exclude_loggers', const.DEFAULT_EXCLUDE_LOGGERS)
+ config.get("sentry_exclude_loggers", const.DEFAULT_EXCLUDE_LOGGERS)
)
if level not in const.LOG_LEVEL_MAP:
level = const.DEFAULT_LOG_LEVEL
@@ -64,18 +67,18 @@ def initialize_raven(config, client_cls=None):
client_cls = client_cls or raven.Client
client = client_cls(**options)
handler = OdooSentryHandler(
- config.get('sentry_include_context', True),
+ config.get("sentry_include_context", True),
client=client,
level=const.LOG_LEVEL_MAP[level],
)
if exclude_loggers:
- handler.addFilter(LoggerNameFilter(
- exclude_loggers, name='sentry.logger.filter'))
+ handler.addFilter(
+ LoggerNameFilter(exclude_loggers, name="sentry.logger.filter")
+ )
raven.conf.setup_logging(handler)
- wsgi_server.application = Sentry(
- wsgi_server.application, client=client)
+ wsgi_server.application = Sentry(wsgi_server.application, client=client)
- client.captureMessage('Starting Odoo Server')
+ client.captureMessage("Starting Odoo Server")
return client
diff --git a/sentry/__manifest__.py b/sentry/__manifest__.py
index d4471b69e..65048bc8b 100644
--- a/sentry/__manifest__.py
+++ b/sentry/__manifest__.py
@@ -1,24 +1,18 @@
# Copyright 2016-2017 Versada
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
{
- 'name': 'Sentry',
- 'summary': 'Report Odoo errors to Sentry',
- 'version': '12.0.1.0.0',
- 'category': 'Extra Tools',
- 'website': 'https://odoo-community.org/',
- 'author': 'Mohammed Barsi,'
- 'Versada,'
- 'Nicolas JEUDY,'
- 'Odoo Community Association (OCA)',
- 'license': 'AGPL-3',
- 'application': False,
- 'installable': True,
- 'external_dependencies': {
- 'python': [
- 'raven',
- ]
- },
- 'depends': [
- 'base',
- ],
+ "name": "Sentry",
+ "summary": "Report Odoo errors to Sentry",
+ "version": "12.0.1.0.0",
+ "category": "Extra Tools",
+ "website": "https://odoo-community.org/",
+ "author": "Mohammed Barsi,"
+ "Versada,"
+ "Nicolas JEUDY,"
+ "Odoo Community Association (OCA)",
+ "license": "AGPL-3",
+ "application": False,
+ "installable": True,
+ "external_dependencies": {"python": ["raven"]},
+ "depends": ["base"],
}
diff --git a/sentry/const.py b/sentry/const.py
index 0092d7544..8ea20aebb 100644
--- a/sentry/const.py
+++ b/sentry/const.py
@@ -14,76 +14,72 @@ except ImportError:
_logger.debug('Cannot import "raven". Please make sure it is installed.')
-def split_multiple(string, delimiter=',', strip_chars=None):
- '''Splits :param:`string` and strips :param:`strip_chars` from values.'''
+def split_multiple(string, delimiter=",", strip_chars=None):
+ """Splits :param:`string` and strips :param:`strip_chars` from values."""
if not string:
return []
return [v.strip(strip_chars) for v in string.split(delimiter)]
-SentryOption = collections.namedtuple(
- 'SentryOption', ['key', 'default', 'converter'])
+SentryOption = collections.namedtuple("SentryOption", ["key", "default", "converter"])
# Mapping of Odoo logging level -> Python stdlib logging library log level.
-LOG_LEVEL_MAP = dict([
- (getattr(odoo.loglevels, 'LOG_%s' % x), getattr(logging, x))
- for x in ('CRITICAL', 'ERROR', 'WARNING', 'INFO', 'DEBUG', 'NOTSET')
-])
-DEFAULT_LOG_LEVEL = 'warn'
+LOG_LEVEL_MAP = {
+ getattr(odoo.loglevels, "LOG_%s" % x): getattr(logging, x)
+ for x in ("CRITICAL", "ERROR", "WARNING", "INFO", "DEBUG", "NOTSET")
+}
+DEFAULT_LOG_LEVEL = "warn"
ODOO_USER_EXCEPTIONS = [
- 'odoo.exceptions.AccessDenied',
- 'odoo.exceptions.AccessError',
- 'odoo.exceptions.DeferredException',
- 'odoo.exceptions.MissingError',
- 'odoo.exceptions.RedirectWarning',
- 'odoo.exceptions.UserError',
- 'odoo.exceptions.ValidationError',
- 'odoo.exceptions.Warning',
- 'odoo.exceptions.except_orm',
+ "odoo.exceptions.AccessDenied",
+ "odoo.exceptions.AccessError",
+ "odoo.exceptions.DeferredException",
+ "odoo.exceptions.MissingError",
+ "odoo.exceptions.RedirectWarning",
+ "odoo.exceptions.UserError",
+ "odoo.exceptions.ValidationError",
+ "odoo.exceptions.Warning",
+ "odoo.exceptions.except_orm",
]
-DEFAULT_IGNORED_EXCEPTIONS = ','.join(ODOO_USER_EXCEPTIONS)
+DEFAULT_IGNORED_EXCEPTIONS = ",".join(ODOO_USER_EXCEPTIONS)
PROCESSORS = (
- 'raven.processors.SanitizePasswordsProcessor',
- 'odoo.addons.sentry.logutils.SanitizeOdooCookiesProcessor',
+ "raven.processors.SanitizePasswordsProcessor",
+ "odoo.addons.sentry.logutils.SanitizeOdooCookiesProcessor",
)
-DEFAULT_PROCESSORS = ','.join(PROCESSORS)
+DEFAULT_PROCESSORS = ",".join(PROCESSORS)
-EXCLUDE_LOGGERS = (
- 'werkzeug',
-)
-DEFAULT_EXCLUDE_LOGGERS = ','.join(EXCLUDE_LOGGERS)
+EXCLUDE_LOGGERS = ("werkzeug",)
+DEFAULT_EXCLUDE_LOGGERS = ",".join(EXCLUDE_LOGGERS)
-DEFAULT_TRANSPORT = 'threaded'
+DEFAULT_TRANSPORT = "threaded"
def select_transport(name=DEFAULT_TRANSPORT):
return {
- 'requests_synchronous': raven.transport.RequestsHTTPTransport,
- 'requests_threaded': raven.transport.ThreadedRequestsHTTPTransport,
- 'synchronous': raven.transport.HTTPTransport,
- 'threaded': raven.transport.ThreadedHTTPTransport,
+ "requests_synchronous": raven.transport.RequestsHTTPTransport,
+ "requests_threaded": raven.transport.ThreadedRequestsHTTPTransport,
+ "synchronous": raven.transport.HTTPTransport,
+ "threaded": raven.transport.ThreadedHTTPTransport,
}.get(name, DEFAULT_TRANSPORT)
def get_sentry_options():
return [
- SentryOption('dsn', '', str.strip),
- SentryOption('install_sys_hook', False, None),
- SentryOption('transport', DEFAULT_TRANSPORT, select_transport),
- SentryOption('include_paths', '', split_multiple),
- SentryOption('exclude_paths', '', split_multiple),
- SentryOption('machine', defaults.NAME, None),
- SentryOption('auto_log_stacks', defaults.AUTO_LOG_STACKS, None),
- SentryOption('capture_locals', defaults.CAPTURE_LOCALS, None),
- SentryOption('string_max_length', defaults.MAX_LENGTH_STRING, None),
- SentryOption('list_max_length', defaults.MAX_LENGTH_LIST, None),
- SentryOption('site', None, None),
- SentryOption('include_versions', True, None),
- SentryOption(
- 'ignore_exceptions', DEFAULT_IGNORED_EXCEPTIONS, split_multiple),
- SentryOption('processors', DEFAULT_PROCESSORS, split_multiple),
- SentryOption('environment', None, None),
- SentryOption('release', None, None),
+ SentryOption("dsn", "", str.strip),
+ SentryOption("install_sys_hook", False, None),
+ SentryOption("transport", DEFAULT_TRANSPORT, select_transport),
+ SentryOption("include_paths", "", split_multiple),
+ SentryOption("exclude_paths", "", split_multiple),
+ SentryOption("machine", defaults.NAME, None),
+ SentryOption("auto_log_stacks", defaults.AUTO_LOG_STACKS, None),
+ SentryOption("capture_locals", defaults.CAPTURE_LOCALS, None),
+ SentryOption("string_max_length", defaults.MAX_LENGTH_STRING, None),
+ SentryOption("list_max_length", defaults.MAX_LENGTH_LIST, None),
+ SentryOption("site", None, None),
+ SentryOption("include_versions", True, None),
+ SentryOption("ignore_exceptions", DEFAULT_IGNORED_EXCEPTIONS, split_multiple),
+ SentryOption("processors", DEFAULT_PROCESSORS, split_multiple),
+ SentryOption("environment", None, None),
+ SentryOption("release", None, None),
]
diff --git a/sentry/logutils.py b/sentry/logutils.py
index cef132bd7..93709c9ce 100644
--- a/sentry/logutils.py
+++ b/sentry/logutils.py
@@ -18,56 +18,50 @@ except ImportError:
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)),
+ "url": "{}://{}{}".format(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', {})
+ 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', {}),
+ "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),
- })
+ 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=''):
+ def __init__(self, loggers, name=""):
super(LoggerNameFilter, self).__init__(name=name)
self._exclude_loggers = set(loggers)
@@ -76,12 +70,12 @@ class LoggerNameFilter(logging.Filter):
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)
@@ -94,12 +88,10 @@ class OdooSentryHandler(SentryHandler):
class SanitizeOdooCookiesProcessor(SanitizePasswordsProcessor):
- '''
+ """
Custom :class:`raven.processors.Processor`.
Allows to sanitize sensitive Odoo cookies, namely the "session_id" cookie.
- '''
+ """
- KEYS = FIELDS = frozenset([
- 'session_id',
- ])
+ KEYS = FIELDS = frozenset(["session_id"])
diff --git a/sentry/tests/__init__.py b/sentry/tests/__init__.py
index 6955e47d5..21926387a 100644
--- a/sentry/tests/__init__.py
+++ b/sentry/tests/__init__.py
@@ -1,7 +1,4 @@
# Copyright 2016-2017 Versada
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-from . import (
- test_client,
- test_logutils,
-)
+from . import test_client, test_logutils
diff --git a/sentry/tests/test_client.py b/sentry/tests/test_client.py
index aafe9d0e7..eb68c7137 100644
--- a/sentry/tests/test_client.py
+++ b/sentry/tests/test_client.py
@@ -20,25 +20,25 @@ def log_handler_by_class(logger, handler_cls):
def remove_logging_handler(logger_name, handler_cls):
- '''Removes handlers of specified classes from a :class:`logging.Logger`
+ """Removes handlers of specified classes from a :class:`logging.Logger`
with a given name.
:param string logger_name: name of the logger
:param handler_cls: class of the handler to remove. You can pass a tuple of
classes to catch several classes
- '''
+ """
logger = logging.getLogger(logger_name)
for handler in log_handler_by_class(logger, handler_cls):
logger.removeHandler(handler)
class InMemoryClient(raven.Client):
- '''A :class:`raven.Client` subclass which simply stores events in a list.
+ """A :class:`raven.Client` subclass which simply stores events in a list.
Extended based on the one found in raven-python to avoid additional testing
dependencies: https://git.io/vyGO3
- '''
+ """
def __init__(self, **kwargs):
self.events = []
@@ -52,14 +52,12 @@ class InMemoryClient(raven.Client):
def has_event(self, event_level, event_msg):
for event in self.events:
- if (event.get('level') == event_level and
- event.get('message') == event_msg):
+ if event.get("level") == event_level and event.get("message") == event_msg:
return True
return False
class TestClientSetup(unittest.TestCase):
-
def setUp(self):
super(TestClientSetup, self).setUp()
self.logger = logging.getLogger(__name__)
@@ -68,57 +66,54 @@ class TestClientSetup(unittest.TestCase):
# when the module is loaded. After that, subsequent calls to
# setup_logging will not re-add our handler. We explicitly remove
# OdooSentryHandler handler so we can test with our in-memory client.
- remove_logging_handler('', OdooSentryHandler)
+ remove_logging_handler("", OdooSentryHandler)
def assertEventCaptured(self, client, event_level, event_msg):
self.assertTrue(
client.has_event(event_level, event_msg),
- msg='Event: "%s" was not captured' % event_msg
+ msg='Event: "%s" was not captured' % event_msg,
)
def assertEventNotCaptured(self, client, event_level, event_msg):
self.assertFalse(
client.has_event(event_level, event_msg),
- msg='Event: "%s" was captured' % event_msg
+ msg='Event: "%s" was captured' % event_msg,
)
def test_initialize_raven_sets_dsn(self):
config = {
- 'sentry_enabled': True,
- 'sentry_dsn': 'http://public:secret@example.com/1',
+ "sentry_enabled": True,
+ "sentry_dsn": "http://public:secret@example.com/1",
}
client = initialize_raven(config, client_cls=InMemoryClient)
- self.assertEqual(client.remote.base_url, 'http://example.com')
+ self.assertEqual(client.remote.base_url, "http://example.com")
def test_capture_event(self):
config = {
- 'sentry_enabled': True,
- 'sentry_dsn': 'http://public:secret@example.com/1',
+ "sentry_enabled": True,
+ "sentry_dsn": "http://public:secret@example.com/1",
}
- level, msg = logging.WARNING, 'Test event, can be ignored'
+ level, msg = logging.WARNING, "Test event, can be ignored"
client = initialize_raven(config, client_cls=InMemoryClient)
self.logger.log(level, msg)
self.assertEventCaptured(client, level, msg)
def test_ignore_exceptions(self):
config = {
- 'sentry_enabled': True,
- 'sentry_dsn': 'http://public:secret@example.com/1',
- 'sentry_ignore_exceptions': 'odoo.exceptions.UserError',
+ "sentry_enabled": True,
+ "sentry_dsn": "http://public:secret@example.com/1",
+ "sentry_ignore_exceptions": "odoo.exceptions.UserError",
}
- level, msg = logging.WARNING, 'Test UserError'
+ level, msg = logging.WARNING, "Test UserError"
client = initialize_raven(config, client_cls=InMemoryClient)
- handlers = list(
- log_handler_by_class(logging.getLogger(), OdooSentryHandler)
- )
+ handlers = list(log_handler_by_class(logging.getLogger(), OdooSentryHandler))
self.assertTrue(handlers)
handler = handlers[0]
try:
raise exceptions.UserError(msg)
except exceptions.UserError:
exc_info = sys.exc_info()
- record = logging.LogRecord(
- __name__, level, __file__, 42, msg, (), exc_info)
+ record = logging.LogRecord(__name__, level, __file__, 42, msg, (), exc_info)
handler.emit(record)
self.assertEventNotCaptured(client, level, msg)
diff --git a/sentry/tests/test_logutils.py b/sentry/tests/test_logutils.py
index bcabdcb6a..1dd20e2de 100644
--- a/sentry/tests/test_logutils.py
+++ b/sentry/tests/test_logutils.py
@@ -9,69 +9,62 @@ from ..logutils import SanitizeOdooCookiesProcessor
class TestOdooCookieSanitizer(unittest.TestCase):
-
def test_cookie_as_string(self):
data = {
- 'request': {
- 'cookies': 'website_lang=en_us;'
- 'session_id=hello;'
- 'Session_ID=hello;'
- 'foo=bar',
- },
+ "request": {
+ "cookies": "website_lang=en_us;"
+ "session_id=hello;"
+ "Session_ID=hello;"
+ "foo=bar"
+ }
}
proc = SanitizeOdooCookiesProcessor(mock.Mock())
result = proc.process(data)
- self.assertTrue('request' in result)
- http = result['request']
+ self.assertTrue("request" in result)
+ http = result["request"]
self.assertEqual(
- http['cookies'],
- 'website_lang=en_us;'
- 'session_id={m};'
- 'Session_ID={m};'
- 'foo=bar'.format(
- m=proc.MASK,
- ),
+ http["cookies"],
+ "website_lang=en_us;"
+ "session_id={m};"
+ "Session_ID={m};"
+ "foo=bar".format(m=proc.MASK),
)
def test_cookie_as_string_with_partials(self):
- data = {
- 'request': {
- 'cookies': 'website_lang=en_us;session_id;foo=bar',
- },
- }
+ data = {"request": {"cookies": "website_lang=en_us;session_id;foo=bar"}}
proc = SanitizeOdooCookiesProcessor(mock.Mock())
result = proc.process(data)
- self.assertTrue('request' in result)
- http = result['request']
+ self.assertTrue("request" in result)
+ http = result["request"]
self.assertEqual(
- http['cookies'],
- 'website_lang=en_us;session_id;foo=bar'.format(m=proc.MASK),
+ http["cookies"], "website_lang=en_us;session_id;foo=bar".format(m=proc.MASK)
)
def test_cookie_header(self):
data = {
- 'request': {
- 'headers': {
- 'Cookie': 'foo=bar;'
- 'session_id=hello;'
- 'Session_ID=hello;'
- 'a_session_id_here=hello',
- },
- },
+ "request": {
+ "headers": {
+ "Cookie": "foo=bar;"
+ "session_id=hello;"
+ "Session_ID=hello;"
+ "a_session_id_here=hello"
+ }
+ }
}
proc = SanitizeOdooCookiesProcessor(mock.Mock())
result = proc.process(data)
- self.assertTrue('request' in result)
- http = result['request']
+ self.assertTrue("request" in result)
+ http = result["request"]
self.assertEqual(
- http['headers']['Cookie'],
- 'foo=bar;'
- 'session_id={m};'
- 'Session_ID={m};'
- 'a_session_id_here={m}'.format(m=proc.MASK))
+ http["headers"]["Cookie"],
+ "foo=bar;"
+ "session_id={m};"
+ "Session_ID={m};"
+ "a_session_id_here={m}".format(m=proc.MASK),
+ )