Skip to content

Commit

Permalink
Merge pull request #124 from plone/wsgi_sentry_support
Browse files Browse the repository at this point in the history
Add Sentry support
  • Loading branch information
zopyx authored Aug 22, 2019
2 parents c111ccd + 633c15e commit c76e817
Show file tree
Hide file tree
Showing 6 changed files with 184 additions and 4 deletions.
19 changes: 19 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,25 @@ access-log-custom
Like `event-log-custom`, a custom section for the access logger, to be able
to use another event logger than `logfile`. Used for ZServer only, not WSGI.

sentry_dsn
Provide a Sentry DSN here to enable basic Sentry logging documented
in `<https://docs.sentry.io/platforms/python/logging/>`_. You will need to add the
Python Sentry SDK, either by adding it to your eggs section directly or by adding
`plone.recipe.zope2instance[sentry]`.
Available for WSGI only.

sentry_level
Set the logging level for Sentry breadcrumbs.
Available for WSGI only.

sentry_event_level
Set the logging level for Sentry events.
Available for WSGI only.

sentry_ignore
Set the (space separated list of) logger names that are ignored by Sentry.
Available for WSGI only.

Load non-setuptools compatible Python libraries
-----------------------------------------------

Expand Down
1 change: 1 addition & 0 deletions news/124.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add Sentry support by adding a new filter to the WSGI pipeline.
6 changes: 6 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@
'test': [
'zope.testrunner',
],
'sentry': [
'sentry-sdk',
]
},
zip_safe=False,
entry_points={
Expand All @@ -60,5 +63,8 @@
'paste.server_factory': [
'main=plone.recipe.zope2instance.ctl:server_factory',
],
'paste.filter_factory': [
'sentry=plone.recipe.zope2instance.sentry:sdk_init',
],
},
)
29 changes: 26 additions & 3 deletions src/plone/recipe/zope2instance/recipe.py
Original file line number Diff line number Diff line change
Expand Up @@ -743,12 +743,24 @@ def build_wsgi_ini(self):
'access-log-level',
options.get('z2-log-level', 'INFO'))

pipeline = []
if accesslog_name.lower() == 'disable':
pipeline = '\n '.join(['egg:Zope#httpexceptions', 'zope'])
pipeline = [
'egg:Zope#httpexceptions']
event_handlers = ''
else:
pipeline = '\n '.join(
['translogger', 'egg:Zope#httpexceptions', 'zope'])
pipeline = [
'translogger', 'egg:Zope#httpexceptions']

sentry_dsn = options.get('sentry_dsn', '')
if sentry_dsn:
pipeline.append('sentry')
sentry_level = options.get('sentry_level', 'INFO')
sentry_event_level = options.get('sentry_event_level', 'ERROR')
sentry_ignore = options.get('sentry_ignore', '')

pipeline.append('zope')
pipeline = '\n '.join(pipeline)
options = {
'location': options['location'],
'http_address': listen,
Expand All @@ -761,6 +773,10 @@ def build_wsgi_ini(self):
'pipeline': pipeline,
'eventlog_level': eventlog_level,
'accesslog_level': accesslog_level,
'sentry_dsn': sentry_dsn,
'sentry_level': sentry_level,
'sentry_event_level': sentry_event_level,
'sentry_ignore': sentry_ignore,
}
wsgi_ini = wsgi_ini_template % options
with open(wsgi_ini_path, 'w') as f:
Expand Down Expand Up @@ -1302,6 +1318,13 @@ def render_file_storage(self, file_storage, blob_storage,
use = egg:Paste#translogger
setup_console_handler = False
[filter:sentry]
use = egg:plone.recipe.zope2instance#sentry
dsn = %(sentry_dsn)s
level = %(sentry_level)s
event_level = %(sentry_event_level)s
ignorelist = %(sentry_ignore)s
[pipeline:main]
pipeline =
%(pipeline)s
Expand Down
22 changes: 22 additions & 0 deletions src/plone/recipe/zope2instance/sentry.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import logging
import sentry_sdk
from sentry_sdk.integrations.logging import LoggingIntegration, ignore_logger


def sdk_init(
global_conf,
dsn,
level='INFO',
event_level='ERROR',
ignorelist=''):
sentry_logging = LoggingIntegration(
level=logging.__dict__[level],
event_level=logging.__dict__[event_level]
)
for logger in ignorelist.split():
ignore_logger(logger)

def filter(app):
sentry_sdk.init(dsn=dsn, integrations=[sentry_logging])
return app
return filter
111 changes: 110 additions & 1 deletion src/plone/recipe/zope2instance/tests/wsgi.txt
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ The buildout has also created an INI file containing the waitress configuration:
[filter:translogger]
use = egg:Paste#translogger
setup_console_handler = False
<BLANKLINE>
...
[pipeline:main]
pipeline =
translogger
Expand Down Expand Up @@ -372,3 +372,112 @@ The buildout has updated our INI file:
handlers =
qualname = waitress
...

Sentry support
==============

We want to sent logging events to Sentry.
Let's create a buildout:

>>> write('buildout.cfg',
... '''
... [buildout]
... parts = instance
... find-links = %(sample_buildout)s/eggs
...
... [instance]
... recipe = plone.recipe.zope2instance
... eggs =
... plone.recipe.zope2instance[sentry]
... user = me:me
... sentry_dsn = https://[email protected]/9999
... ''' % options)

Let's run it::

>>> print(system(join('bin', 'buildout'))),
Uninstalling instance.
Installing instance.
Getting distribution for 'sentry-sdk'.
...
Generated script '.../sample-buildout/bin/instance'.
...

The buildout has updated our INI file:

>>> instance = os.path.join(sample_buildout, 'parts', 'instance')
>>> wsgi_ini = open(os.path.join(instance, 'etc', 'wsgi.ini')).read()
>>> print(wsgi_ini)
[server:main]
paste.server_factory = plone.recipe.zope2instance:main
use = egg:plone.recipe.zope2instance#main
...
[filter:sentry]
use = egg:plone.recipe.zope2instance#sentry
dsn = https://[email protected]/9999
level = INFO
event_level = ERROR
ignorelist =
<BLANKLINE>
[pipeline:main]
pipeline =
translogger
egg:Zope#httpexceptions
sentry
zope
<BLANKLINE>
[loggers]
...

Let's update our buildout with some Sentry options:

>>> write('buildout.cfg',
... '''
... [buildout]
... parts = instance
... find-links = %(sample_buildout)s/eggs
...
... [instance]
... recipe = plone.recipe.zope2instance
... eggs =
... plone.recipe.zope2instance[sentry]
... user = me:me
... sentry_dsn = https://[email protected]/9999
... sentry_level = DEBUG
... sentry_event_level = WARNING
... sentry_ignore = waitress.queue foo
... ''' % options)

Let's run it::

>>> print(system(join('bin', 'buildout'))),
Uninstalling instance.
Installing instance.
Generated script '.../sample-buildout/bin/instance'.
...

The buildout has updated our INI file:

>>> instance = os.path.join(sample_buildout, 'parts', 'instance')
>>> wsgi_ini = open(os.path.join(instance, 'etc', 'wsgi.ini')).read()
>>> print(wsgi_ini)
[server:main]
paste.server_factory = plone.recipe.zope2instance:main
use = egg:plone.recipe.zope2instance#main
...
[filter:sentry]
use = egg:plone.recipe.zope2instance#sentry
dsn = https://[email protected]/9999
level = DEBUG
event_level = WARNING
ignorelist = waitress.queue foo
<BLANKLINE>
[pipeline:main]
pipeline =
translogger
egg:Zope#httpexceptions
sentry
zope
<BLANKLINE>
[loggers]
...

0 comments on commit c76e817

Please sign in to comment.