Skip to content

Commit 2f52078

Browse files
committed
Merge PR OCA#2888 into 14.0
Signed-off-by moylop260
2 parents 989863f + f3dd4d9 commit 2f52078

File tree

2 files changed

+136
-21
lines changed

2 files changed

+136
-21
lines changed

sentry/const.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,11 @@ def get_sentry_logging(level=DEFAULT_LOG_LEVEL):
6969
if level not in LOG_LEVEL_MAP:
7070
level = DEFAULT_LOG_LEVEL
7171

72-
return LoggingIntegration(level=LOG_LEVEL_MAP[level], event_level=logging.WARNING)
72+
return LoggingIntegration(
73+
# Gather warnings into breadcrumbs regardless of actual logging level
74+
level=logging.WARNING,
75+
event_level=LOG_LEVEL_MAP[level],
76+
)
7377

7478

7579
def get_sentry_options():

sentry/tests/test_client.py

+131-20
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
from odoo.tests import TransactionCase
1313
from odoo.tools import config
1414

15+
from ..const import to_int_if_defined
1516
from ..hooks import initialize_sentry
1617

1718
GIT_SHA = "d670460b4b4aece5915caf5c68d12f560a9fe3e4"
@@ -56,22 +57,49 @@ def kill(self, *args, **kwargs):
5657
pass
5758

5859

59-
class TestClientSetup(TransactionCase):
60+
class NoopHandler(logging.Handler):
61+
"""
62+
A Handler subclass that does nothing with any given log record.
63+
64+
Sentry's log patching works by having the integration process things after
65+
the normal log handlers are run, so we use this handler to do nothing and
66+
move to Sentry logic ASAP.
67+
"""
68+
69+
def emit(self, record):
70+
pass
71+
72+
73+
class TestSentryCommon(TransactionCase):
6074
def setUp(self):
61-
super(TestClientSetup, self).setUp()
75+
super().setUp()
6276
self.dsn = "http://public:secret@example.com/1"
77+
78+
def assertEventCaptured(self, client, event_level, event_msg):
79+
self.assertTrue(
80+
client.transport.has_event(event_level, event_msg),
81+
msg='Event: "%s" was not captured' % event_msg,
82+
)
83+
84+
def assertEventNotCaptured(self, client, event_level, event_msg):
85+
self.assertFalse(
86+
client.transport.has_event(event_level, event_msg),
87+
msg='Event: "%s" was captured' % event_msg,
88+
)
89+
90+
91+
class TestClientSetupStartup(TestSentryCommon):
92+
def setUp(self):
93+
super().setUp()
6394
config.options["sentry_enabled"] = True
6495
config.options["sentry_dsn"] = self.dsn
96+
config.options["sentry_logging_level"] = "info"
6597
with patch(
6698
"odoo.addons.sentry.const.select_transport", return_value=InMemoryTransport
6799
):
68100
self.client = initialize_sentry(config)._client
69101
self.handler = self.client.integrations["logging"]._handler
70102

71-
def log(self, level, msg, exc_info=None):
72-
record = logging.LogRecord(__name__, level, __file__, 42, msg, (), exc_info)
73-
self.handler.emit(record)
74-
75103
def assertEventCaptured(self, client, event_level, event_msg):
76104
self.assertTrue(
77105
client.transport.has_event(event_level, event_msg),
@@ -97,53 +125,132 @@ def test_startup_event_disabled(self):
97125
self.client = initialize_sentry(config)._client
98126
self.assertEventNotCaptured(self.client, "info", "Starting Odoo Server")
99127

128+
def test_startup_event_disabled_if_warning_level(self):
129+
config.options["sentry_enabled"] = True
130+
config.options["sentry_dsn"] = self.dsn
131+
config.options["sentry_ignore_startup_event"] = True
132+
config.options["sentry_logging_level"] = "warning"
133+
with patch(
134+
"odoo.addons.sentry.const.select_transport", return_value=InMemoryTransport
135+
):
136+
self.client = initialize_sentry(config)._client
137+
self.assertEventNotCaptured(self.client, "info", "Starting Odoo Server")
138+
139+
140+
class TestClientSetup(TestSentryCommon):
141+
def setUp(self):
142+
super().setUp()
143+
self.patch_config(
144+
{
145+
"sentry_enabled": True,
146+
"sentry_dsn": self.dsn,
147+
"sentry_logging_level": "error",
148+
}
149+
)
150+
self.client = initialize_sentry(config)._client
151+
self.client.transport = InMemoryTransport({"dsn": self.dsn})
152+
153+
# Setup our own logger so we don't flood stderr with error logs
154+
self.logger = logging.getLogger("odoo.sentry.test.logger")
155+
# Do not mutate list while iterating it
156+
handlers = [handler for handler in self.logger.handlers]
157+
for handler in handlers:
158+
self.logger.removeHandler(handler)
159+
self.logger.addHandler(NoopHandler())
160+
self.logger.propagate = False
161+
162+
def patch_config(self, options: dict):
163+
"""
164+
Patch Odoo's config with the given `options`, ensuring that the patch
165+
is undone when the test completes.
166+
"""
167+
_config_patcher = patch.dict(
168+
in_dict=config.options,
169+
values=options,
170+
)
171+
_config_patcher.start()
172+
self.addCleanup(_config_patcher.stop)
173+
174+
def log(self, level, msg, exc_info=None):
175+
self.logger.log(level, msg, exc_info=exc_info)
176+
100177
def test_initialize_raven_sets_dsn(self):
101178
self.assertEqual(self.client.dsn, self.dsn)
102179

103-
def test_capture_event(self):
180+
def test_ignore_low_level_event(self):
104181
level, msg = logging.WARNING, "Test event, can be ignored"
105182
self.log(level, msg)
106183
level = "warning"
184+
self.assertEventNotCaptured(self.client, level, msg)
185+
186+
def test_capture_event(self):
187+
level, msg = logging.ERROR, "Test event, should be captured"
188+
self.log(level, msg)
189+
level = "error"
107190
self.assertEventCaptured(self.client, level, msg)
108191

109192
def test_capture_event_exc(self):
110-
level, msg = logging.WARNING, "Test event, can be ignored exception"
193+
level, msg = logging.ERROR, "Test event, can be ignored exception"
111194
try:
112195
raise TestException(msg)
113196
except TestException:
114197
exc_info = sys.exc_info()
115198
self.log(level, msg, exc_info)
116-
level = "warning"
199+
level = "error"
117200
self.assertEventCaptured(self.client, level, msg)
118201

119202
def test_ignore_exceptions(self):
120-
config.options["sentry_ignore_exceptions"] = "odoo.exceptions.UserError"
203+
self.patch_config(
204+
{
205+
"sentry_ignore_exceptions": "odoo.exceptions.UserError",
206+
}
207+
)
121208
client = initialize_sentry(config)._client
122209
client.transport = InMemoryTransport({"dsn": self.dsn})
123-
level, msg = logging.WARNING, "Test exception"
210+
level, msg = logging.ERROR, "Test exception"
124211
try:
125212
raise exceptions.UserError(msg)
126213
except exceptions.UserError:
127214
exc_info = sys.exc_info()
128215
self.log(level, msg, exc_info)
129-
level = "warning"
216+
level = "error"
130217
self.assertEventNotCaptured(client, level, msg)
131218

132219
def test_exclude_logger(self):
133-
config.options["sentry_enabled"] = True
134-
config.options["sentry_exclude_loggers"] = __name__
220+
self.patch_config(
221+
{
222+
"sentry_enabled": True,
223+
"sentry_exclude_loggers": self.logger.name,
224+
}
225+
)
135226
client = initialize_sentry(config)._client
136227
client.transport = InMemoryTransport({"dsn": self.dsn})
137-
level, msg = logging.WARNING, "Test exclude logger %s" % __name__
228+
level, msg = logging.ERROR, "Test exclude logger %s" % __name__
138229
self.log(level, msg)
139-
level = "warning"
230+
level = "error"
140231
# Revert ignored logger so it doesn't affect other tests
141-
remove_handler_ignore(__name__)
232+
remove_handler_ignore(self.logger.name)
142233
self.assertEventNotCaptured(client, level, msg)
143234

235+
def test_invalid_logging_level(self):
236+
self.patch_config(
237+
{
238+
"sentry_logging_level": "foo_bar",
239+
}
240+
)
241+
client = initialize_sentry(config)._client
242+
client.transport = InMemoryTransport({"dsn": self.dsn})
243+
level, msg = logging.WARNING, "Test we use the default"
244+
self.log(level, msg)
245+
level = "warning"
246+
self.assertEventCaptured(client, level, msg)
247+
248+
def test_undefined_to_int(self):
249+
self.assertIsNone(to_int_if_defined(""))
250+
144251
@patch("odoo.addons.sentry.hooks.get_odoo_commit", return_value=GIT_SHA)
145252
def test_config_odoo_dir(self, get_odoo_commit):
146-
config.options["sentry_odoo_dir"] = "/opt/odoo/core"
253+
self.patch_config({"sentry_odoo_dir": "/opt/odoo/core"})
147254
client = initialize_sentry(config)._client
148255

149256
self.assertEqual(
@@ -154,8 +261,12 @@ def test_config_odoo_dir(self, get_odoo_commit):
154261

155262
@patch("odoo.addons.sentry.hooks.get_odoo_commit", return_value=GIT_SHA)
156263
def test_config_release(self, get_odoo_commit):
157-
config.options["sentry_odoo_dir"] = "/opt/odoo/core"
158-
config.options["sentry_release"] = RELEASE
264+
self.patch_config(
265+
{
266+
"sentry_odoo_dir": "/opt/odoo/core",
267+
"sentry_release": RELEASE,
268+
}
269+
)
159270
client = initialize_sentry(config)._client
160271

161272
self.assertEqual(

0 commit comments

Comments
 (0)