Skip to content

Commit

Permalink
Replace raven by sentry-sdk, and adjust config (fixes #3054) (#3055)
Browse files Browse the repository at this point in the history
* Replace raven by sentry-sdk, and adjust config (fixes #3054)

* Add Sentry to kinto.tpl

* Test that Sentry message is sent on startup

* Fix docs format

* Remove := operator since kinto supports 3.7

* Remove usage of :ref: in CHANGELOG (used in package description)

* Skip Sentry tests when monitoring deps not installed

* Add Pyramid integration

* Add test to verify that exceptions are reported
  • Loading branch information
leplatrem authored Oct 14, 2022
1 parent e7dd22e commit 1dbdb07
Show file tree
Hide file tree
Showing 11 changed files with 148 additions and 17 deletions.
34 changes: 34 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,40 @@ This document describes changes between each past release.
14.8.1 (unreleased)
-------------------

**Breaking Changes**

- ``raven`` is not installed by default anymore (fixes #3054). Sentry reporting is now enabled via settings (or environment variables).

In order to migrate from Kinto <14 to Kinto 15, remove the mention of ``sentry`` and ``raven`` from your logging configuration:

.. code-block:: diff
# kinto.ini
[logger_root]
level = INFO
- handlers = console, sentry
+ handlers = console
[handlers]
- keys = console, sentry
+ keys = console
- [handler_sentry]
- class = raven.handlers.logging.SentryHandler
- args = ('https://<key>:<secret>@app.getsentry.com/<project>',)
- level = WARNING
- formatter = generic
And add the following settings:

.. code-block:: ini
kinto.sentry_dsn = https://[email protected]/1
kinto.sentry_env = prod
For more information, see `Settings documentation <https://kinto.readthedocs.io/en/stable/configuration/settings.html#authentication>`_.

**Documentation**

- Fix ``/batch`` endpoint documentation about required authentication.
Expand Down
11 changes: 2 additions & 9 deletions docs/configuration/production.rst
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,6 @@ processed through `Kibana <https://github.com/elastic/kibana>`_ or

With the following configuration, all logs are structured in JSON and
redirected to standard output (See `12factor app <http://12factor.net/logs>`_).
A `Sentry <https://getsentry.com>`_ logger is also enabled.

.. note::

Expand All @@ -283,27 +282,21 @@ A `Sentry <https://getsentry.com>`_ logger is also enabled.
keys = root
[handlers]
keys = console, sentry
keys = console
[formatters]
keys = generic, json
[logger_root]
level = INFO
handlers = console, sentry
handlers = console
[handler_console]
class = StreamHandler
args = (sys.stdout,)
level = NOTSET
formatter = json
[handler_sentry]
class = raven.handlers.logging.SentryHandler
args = ('https://<key>:<secret>@app.getsentry.com/<project>',)
level = WARNING
formatter = generic
[formatter_json]
class = kinto.core.JsonLogFormatter
Expand Down
20 changes: 16 additions & 4 deletions docs/configuration/settings.rst
Original file line number Diff line number Diff line change
Expand Up @@ -396,17 +396,29 @@ Example output:
{"Pid": 19240, "Type": "root", "Timestamp": 1489067817834153984, "Severity": 4, "Hostname": "pluo", "Logger": "%", "EnvVersion": "2.0", "Fields": {"perm": "read", "userid": "ldap:[email protected]", "message": "Permission not granted.", "uri": "/buckets/123"}}


.. _handling-exceptions-with-sentry:

Handling exceptions with Sentry
:::::::::::::::::::::::::::::::

Requires the ``raven`` package.

Sentry logging can be enabled `as explained in official documentation
<https://raven.readthedocs.io/en/latest/integrations/pyramid.html#logger-setup>`_.
Sentry reporting can be enabled via the following settings:

.. code-block:: ini
kinto.sentry_dsn = https://[email protected]/1
kinto.sentry_env = stage
Or the equivalent environment variables:

::

SENTRY_DSN=https://[email protected]/1
SENTRY_ENV=stage

.. note::

The application sends an *INFO* message on startup (mainly for setup check).
The application sends an event on startup (mainly for setup check).


Monitoring with StatsD
Expand Down
3 changes: 3 additions & 0 deletions kinto/config/kinto.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,9 @@ kinto.bucket_create_principals = account:admin
# kinto.statsd_prefix = kinto
# kinto.statsd_url =

# kinto.sentry_dsn =
# kinto.sentry_env =

# kinto.newrelic_config =
# kinto.newrelic_env = dev

Expand Down
3 changes: 3 additions & 0 deletions kinto/core/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
"kinto.core.initialization.setup_deprecation",
"kinto.core.initialization.setup_authentication",
"kinto.core.initialization.setup_backoff",
"kinto.core.initialization.setup_sentry",
"kinto.core.initialization.setup_statsd",
"kinto.core.initialization.setup_listeners",
"kinto.core.events.setup_transaction_hook",
Expand All @@ -86,6 +87,8 @@
"retry_after_seconds": 30,
"version_prefix_redirect_ttl_seconds": -1,
"settings_prefix": "",
"sentry_dsn": None,
"sentry_env": None,
"statsd_backend": "kinto.core.statsd",
"statsd_prefix": "kinto.core",
"statsd_url": None,
Expand Down
35 changes: 34 additions & 1 deletion kinto/core/initialization.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from datetime import datetime

from dateutil import parser as dateparser
from pyramid.events import NewRequest, NewResponse
from pyramid.events import ApplicationCreated, NewRequest, NewResponse
from pyramid.exceptions import ConfigurationError
from pyramid.httpexceptions import HTTPBadRequest, HTTPGone, HTTPTemporaryRedirect
from pyramid.interfaces import IAuthenticationPolicy
Expand All @@ -26,6 +26,11 @@
from werkzeug.middleware.profiler import ProfilerMiddleware
except ImportError: # pragma: no cover
ProfilerMiddleware = False
try:
import sentry_sdk
from sentry_sdk.integrations.pyramid import PyramidIntegration
except ImportError: # pragma: no cover
sentry_sdk = None


logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -264,6 +269,34 @@ def setup_cache(config):
config.registry.heartbeats["cache"] = heartbeat


def setup_sentry(config):
settings = config.get_settings()

# Note: SENTRY_DSN and SENTRY_ENV env variables will override
# .ini values thanks to `load_default_settings()`.

dsn = settings["sentry_dsn"]
if dsn:
env_options = {}
env = settings["sentry_env"]
if env:
env_options["environment"] = env

sentry_sdk.init(
dsn,
integrations=[
PyramidIntegration(),

This comment has been minimized.

Copy link
@slav0nic

slav0nic Oct 19, 2022

Contributor

Maybe it make sense also enable SqlalchemyIntegration

This comment has been minimized.

Copy link
@leplatrem

leplatrem Oct 19, 2022

Author Contributor

Oh, true, you're right. I'll open a follow-up

],
**env_options,
)

def on_app_created(event):
msg = "Running {project_name} {project_version}.".format_map(settings)
sentry_sdk.capture_message(msg, "info")

config.add_subscriber(on_app_created, ApplicationCreated)


def setup_statsd(config):
settings = config.get_settings()
config.registry.statsd = None
Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ pyramid-multiauth==1.0.1
pyramid-tm==2.5
python-dateutil==2.8.2
python-memcached==1.59
raven==6.10.0
sentry-sdk==1.9.10
requests==2.28.1
SQLAlchemy==1.4.41
statsd==3.3.0
Expand Down
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ postgresql =
zope.sqlalchemy
monitoring =
newrelic
raven
sentry-sdk
statsd
werkzeug

Expand Down
50 changes: 50 additions & 0 deletions tests/core/test_initialization.py
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,56 @@ def test_load_default_settings_converts_to_native_correctly(self):
self.assertEqual(settings["my_cool_setting"], "1.2")


class SentryTest(unittest.TestCase):
@unittest.skipIf(initialization.sentry_sdk is None, "sentry is not installed.")
def test_sentry_not_enabled_by_default(self):
config = Configurator()
with mock.patch("sentry_sdk.init") as mocked:
kinto.core.initialize(config, "0.0.1")

self.assertFalse(mocked.called)

@unittest.skipIf(initialization.sentry_sdk is None, "sentry is not installed.")
def test_sentry_enabled_if_sentry_dsn_is_set(self):
config = Configurator(
settings={
"sentry_dsn": "https://notempty",
"sentry_env": "local",
}
)
with mock.patch("sentry_sdk.init") as mocked:
kinto.core.initialize(config, "0.0.1")

init_call = mocked.call_args_list[0]
self.assertEqual(init_call[0][0], "https://notempty")
self.assertEqual(init_call[1]["environment"], "local")

@unittest.skipIf(initialization.sentry_sdk is None, "sentry is not installed.")
def test_message_is_sent_on_startup(self):
config = Configurator(settings={**kinto.core.DEFAULT_SETTINGS})
config.add_settings(
{
"sentry_dsn": "https://notempty",
}
)

with mock.patch("sentry_sdk.init"):
kinto.core.initialize(config, "0.0.1", "name")

with mock.patch("sentry_sdk.capture_message") as mocked:
config.make_wsgi_app()

mocked.assert_called_with("Running 0.0.1.", "info")

@unittest.skipIf(initialization.sentry_sdk is None, "sentry is not installed.")
def unexpected_exceptions_are_reported(self):
with mock.patch("kinto.core.views.hello.get_eos", side_effect=ValueError):
with mock.patch("sentry_sdk.hub.Hub.capture_event") as mocked:
resp = self.app.get("/")
assert resp.status == 500
assert len(mocked.call_args_list) > 0


class StatsDConfigurationTest(unittest.TestCase):
def setUp(self):
settings = {
Expand Down
3 changes: 3 additions & 0 deletions tests/test_configuration/test.ini
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,9 @@ kinto.bucket_create_principals = account:admin
# kinto.statsd_prefix = kinto
# kinto.statsd_url =

# kinto.sentry_dsn =
# kinto.sentry_env =

# kinto.newrelic_config =
# kinto.newrelic_env = dev

Expand Down
2 changes: 1 addition & 1 deletion tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ deps =
-r{toxinidir}/dev-requirements.txt
psycopg2
newrelic
raven
sentry-sdk
statsd
install_command = pip install {opts} {packages} -c{toxinidir}/requirements.txt

Expand Down

0 comments on commit 1dbdb07

Please sign in to comment.