Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Syncing from upstream OCA/server-tools (15.0) #1273

Merged
merged 5 commits into from
Sep 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ addon | version | maintainers | summary
[module_change_auto_install](module_change_auto_install/) | 15.0.1.0.0 | [![legalsylvain](https://github.com/legalsylvain.png?size=30px)](https://github.com/legalsylvain) | Customize auto installables modules by configuration
[onchange_helper](onchange_helper/) | 15.0.1.0.1 | | Technical module that ease execution of onchange in Python code
[scheduler_error_mailer](scheduler_error_mailer/) | 15.0.1.0.0 | | Scheduler Error Mailer
[sentry](sentry/) | 15.0.3.0.0 | [![barsi](https://github.com/barsi.png?size=30px)](https://github.com/barsi) [![naglis](https://github.com/naglis.png?size=30px)](https://github.com/naglis) [![versada](https://github.com/versada.png?size=30px)](https://github.com/versada) [![moylop260](https://github.com/moylop260.png?size=30px)](https://github.com/moylop260) [![fernandahf](https://github.com/fernandahf.png?size=30px)](https://github.com/fernandahf) | Report Odoo errors to Sentry
[sentry](sentry/) | 15.0.3.0.1 | [![barsi](https://github.com/barsi.png?size=30px)](https://github.com/barsi) [![naglis](https://github.com/naglis.png?size=30px)](https://github.com/naglis) [![versada](https://github.com/versada.png?size=30px)](https://github.com/versada) [![moylop260](https://github.com/moylop260.png?size=30px)](https://github.com/moylop260) [![fernandahf](https://github.com/fernandahf.png?size=30px)](https://github.com/fernandahf) | Report Odoo errors to Sentry
[upgrade_analysis](upgrade_analysis/) | 15.0.3.0.0 | [![StefanRijnhart](https://github.com/StefanRijnhart.png?size=30px)](https://github.com/StefanRijnhart) [![legalsylvain](https://github.com/legalsylvain.png?size=30px)](https://github.com/legalsylvain) | Performs a difference analysis between modules installed on two different Odoo instances

[//]: # (end addons)
Expand Down
2 changes: 1 addition & 1 deletion sentry/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
{
"name": "Sentry",
"summary": "Report Odoo errors to Sentry",
"version": "15.0.3.0.0",
"version": "15.0.3.0.1",
"category": "Extra Tools",
"website": "https://github.com/OCA/server-tools",
"author": "Mohammed Barsi,"
Expand Down
6 changes: 5 additions & 1 deletion sentry/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,11 @@ def get_sentry_logging(level=DEFAULT_LOG_LEVEL):
if level not in LOG_LEVEL_MAP:
level = DEFAULT_LOG_LEVEL

return LoggingIntegration(level=LOG_LEVEL_MAP[level], event_level=logging.WARNING)
return LoggingIntegration(
# Gather warnings into breadcrumbs regardless of actual logging level
level=logging.WARNING,
event_level=LOG_LEVEL_MAP[level],
)


def get_sentry_options():
Expand Down
110 changes: 91 additions & 19 deletions sentry/tests/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from odoo.tests import TransactionCase
from odoo.tools import config

from ..const import to_int_if_defined
from ..hooks import initialize_sentry

GIT_SHA = "d670460b4b4aece5915caf5c68d12f560a9fe3e4"
Expand Down Expand Up @@ -60,19 +61,56 @@ def kill(self, *args, **kwargs):
pass


class NoopHandler(logging.Handler):
"""
A Handler subclass that does nothing with any given log record.

Sentry's log patching works by having the integration process things after
the normal log handlers are run, so we use this handler to do nothing and
move to Sentry logic ASAP.
"""

def emit(self, record):
pass


class TestClientSetup(TransactionCase):
def setUp(self):
super(TestClientSetup, self).setUp()
self.dsn = "http://public:[email protected]/1"
config.options["sentry_enabled"] = True
config.options["sentry_dsn"] = self.dsn
self.patch_config(
{
"sentry_enabled": True,
"sentry_dsn": self.dsn,
"sentry_logging_level": "error",
}
)
self.client = initialize_sentry(config)._client
self.client.transport = InMemoryTransport({"dsn": self.dsn})
self.handler = self.client.integrations["logging"]._handler

# Setup our own logger so we don't flood stderr with error logs
self.logger = logging.getLogger("odoo.sentry.test.logger")
# Do not mutate list while iterating it
handlers = [handler for handler in self.logger.handlers]
for handler in handlers:
self.logger.removeHandler(handler)
self.logger.addHandler(NoopHandler())
self.logger.propagate = False

def patch_config(self, options: dict):
"""
Patch Odoo's config with the given `options`, ensuring that the patch
is undone when the test completes.
"""
_config_patcher = patch.dict(
in_dict=config.options,
values=options,
)
_config_patcher.start()
self.addCleanup(_config_patcher.stop)

def log(self, level, msg, exc_info=None):
record = logging.LogRecord(__name__, level, __file__, 42, msg, (), exc_info)
self.handler.emit(record)
self.logger.log(level, msg, exc_info=exc_info)

def assertEventCaptured(self, client, event_level, event_msg):
self.assertTrue(
Expand All @@ -89,50 +127,80 @@ def assertEventNotCaptured(self, client, event_level, event_msg):
def test_initialize_raven_sets_dsn(self):
self.assertEqual(self.client.dsn, self.dsn)

def test_capture_event(self):
def test_ignore_low_level_event(self):
level, msg = logging.WARNING, "Test event, can be ignored"
self.log(level, msg)
level = "warning"
self.assertEventNotCaptured(self.client, level, msg)

def test_capture_event(self):
level, msg = logging.ERROR, "Test event, should be captured"
self.log(level, msg)
level = "error"
self.assertEventCaptured(self.client, level, msg)

def test_capture_event_exc(self):
level, msg = logging.WARNING, "Test event, can be ignored exception"
level, msg = logging.ERROR, "Test event, can be ignored exception"
try:
raise TestException(msg)
except TestException:
exc_info = sys.exc_info()
self.log(level, msg, exc_info)
level = "warning"
level = "error"
self.assertEventCaptured(self.client, level, msg)

def test_ignore_exceptions(self):
config.options["sentry_ignore_exceptions"] = "odoo.exceptions.UserError"
self.patch_config(
{
"sentry_ignore_exceptions": "odoo.exceptions.UserError",
}
)
client = initialize_sentry(config)._client
client.transport = InMemoryTransport({"dsn": self.dsn})
level, msg = logging.WARNING, "Test exception"
level, msg = logging.ERROR, "Test exception"
try:
raise exceptions.UserError(msg)
except exceptions.UserError:
exc_info = sys.exc_info()
self.log(level, msg, exc_info)
level = "warning"
level = "error"
self.assertEventNotCaptured(client, level, msg)

def test_exclude_logger(self):
config.options["sentry_enabled"] = True
config.options["sentry_exclude_loggers"] = __name__
self.patch_config(
{
"sentry_enabled": True,
"sentry_exclude_loggers": self.logger.name,
}
)
client = initialize_sentry(config)._client
client.transport = InMemoryTransport({"dsn": self.dsn})
level, msg = logging.WARNING, "Test exclude logger %s" % __name__
level, msg = logging.ERROR, "Test exclude logger %s" % __name__
self.log(level, msg)
level = "warning"
level = "error"
# Revert ignored logger so it doesn't affect other tests
remove_handler_ignore(__name__)
remove_handler_ignore(self.logger.name)
self.assertEventNotCaptured(client, level, msg)

def test_invalid_logging_level(self):
self.patch_config(
{
"sentry_logging_level": "foo_bar",
}
)
client = initialize_sentry(config)._client
client.transport = InMemoryTransport({"dsn": self.dsn})
level, msg = logging.WARNING, "Test we use the default"
self.log(level, msg)
level = "warning"
self.assertEventCaptured(client, level, msg)

def test_undefined_to_int(self):
self.assertIsNone(to_int_if_defined(""))

@patch("odoo.addons.sentry.hooks.get_odoo_commit", return_value=GIT_SHA)
def test_config_odoo_dir(self, get_odoo_commit):
config.options["sentry_odoo_dir"] = "/opt/odoo/core"
self.patch_config({"sentry_odoo_dir": "/opt/odoo/core"})
client = initialize_sentry(config)._client

self.assertEqual(
Expand All @@ -143,8 +211,12 @@ def test_config_odoo_dir(self, get_odoo_commit):

@patch("odoo.addons.sentry.hooks.get_odoo_commit", return_value=GIT_SHA)
def test_config_release(self, get_odoo_commit):
config.options["sentry_odoo_dir"] = "/opt/odoo/core"
config.options["sentry_release"] = RELEASE
self.patch_config(
{
"sentry_odoo_dir": "/opt/odoo/core",
"sentry_release": RELEASE,
}
)
client = initialize_sentry(config)._client

self.assertEqual(
Expand Down
Loading