Rational
The existing sentry_tryton module, yet powerful and happily used in production environments, works with the deprecated raven package and some hacks.
Namely: only few and known logger.error calls should exist in the application codebase which are carefully skipped except for one in the trytond.protocols.dispatcher._dispatch function except block. There, the SentryTryton log handler will raise a different unchained exception that will ultimately be caught by the WSGI app error handling and serialized to the RPC client.
But
- Raising exceptions in a log handler emit method is rather unexpected: a failure in the logging system shouldn’t interrupt a service
- Custom code or third party dependencies could legitimately try to emit error log events in their exception control blocks. Or anywhere! And this would be beyond the foreseeable hardcoded skips of the SentryTryton log handler, which raises really unexpected exceptions in 3rd party code. This can only be mitigated by limiting the extent of that handler to only the logger of “qualname=trytond.protocols.dispatcher”. This is always something wise to do, but still hacky and poorly documented.
Proposal
The goal would be to distribute a Trytond server integration with the new sentry_sdk package just as other widespread Python frameworks do.
This will allow to write a wsgi.py script which initializes the sentry_sdk and then exposes the wsgi app
# wsgi.py
import sentry_sdk
import sentry_sdk.integrations.trytond
sentry_sdk.init(
"https://<key>@sentry.io/<project>",
integrations=[sentry_sdk.integrations.trytond.TrytondWSGIIntegration()]
)
from trytond.application import app as application
# ...
Which will be loaded by your favorite WSGI server. For development, a python wsgi server like gunicorn or a werkzeug script can be used to load it.
The trytond shipped binary won’t be able to start this integration unless a feature is developed so it can start arbitrary wsgi scripts. (see https://docs.djangoproject.com/en/2.2/ref/settings/#std:setting-WSGI_APPLICATION for example) But this shouldn’t be an issue since the integration is most wanted in production where the server should not be started with that binary.
Using the recently shipped error handlers feature, the sentry event id could be reported to the RPC client by registering a custom error handler with a custom message in a TrytondUserError
# wsgi.py
# ...
@application.error_handler
def _(app, request, e):
if isinstance(e, TrytondBaseException):
return
else:
event_id = sentry_sdk.last_event_id()
data = TrytondUserError('Custom Message', f'{event_id}\n{e}')
return app.make_response(request, data)
that would only report the event id for actually unhandled exceptions, but not for trytond user errors/warnings nor internally emitted error log events.
Custom UserApplication exception handling could also craft a sentry event id report shaped for custom APIs.
Implementation
A first approach can be seen here https://github.com/getsentry/sentry-python/pull/548
Tryton community feedback is very welcome!
Wishlist
After this, a trytond-cron, trytond-worker and tryton client integration (by means of plugins?) could come, also with a trytond-specific sentry context processor