Repository: openfun/marsha

Issue:
Sentry is not configured correctly
## Bug Report

**Expected behavior/code**

When an issue is reported to sentry we want to know the environment and the release where the issue occurs

**Actual Behavior**

When an issue is caught and reported to sentry, we don't have the real environment and release information. Instead we have something like `<property object at 0x7f2fc9fe0c20>`

**Steps to Reproduce**
1. Configure your environment with a valid `SENTRY_DSN`
2. shut down the database
3. send a request to marsha. Without a database an exception will be thrown
4. look in sentry environment and release values.

**Environment**
- Marsha version: 3.9.1
- Platform: docker

**Possible Solution**
 sentry is configured in [settings.py](https://github.com/openfun/marsha/blob/a68ec82f13c766a097e6b5ccca5111ffc51393d9/src/backend/marsha/settings.py#L300-L320). The method used a `classmethod` decorator and as I understand the `cls` parameter is not an instance of the class but the uninstanciated class. To configure sentry we call methods using a `property` decorator, calling them statically like we do return a `property` object and does not call the `getter` method attached to the decorator. Creating static method can resolve the issue or we have to find a way to instantiate the class. 



Discussion:
The modification was done in this commit : https://github.com/openfun/marsha/commit/2eb8fd1f09a39c519d6eca89a69889fee83c855b

Resolving patch:
diff --git a/src/backend/marsha/settings.py b/src/backend/marsha/settings.py
--- a/src/backend/marsha/settings.py
+++ b/src/backend/marsha/settings.py
@@ -291,11 +291,16 @@ def RELEASE(self):
         """
         return get_release()
 
+    @classmethod
+    def _get_environment(cls):
+        """Environment in which the application is launched."""
+        return cls.__name__.lower()
+
     # pylint: disable=invalid-name
     @property
     def ENVIRONMENT(self):
         """Environment in which the application is launched."""
-        return self.__class__.__name__.lower()
+        return self._get_environment()
 
     @classmethod
     def post_setup(cls):
@@ -311,8 +316,8 @@ def post_setup(cls):
         if cls.SENTRY_DSN is not None:
             sentry_sdk.init(
                 dsn=cls.SENTRY_DSN,
-                environment=cls.ENVIRONMENT,
-                release=cls.RELEASE,
+                environment=cls._get_environment(),
+                release=get_release(),
                 integrations=[DjangoIntegration()],
             )
             with sentry_sdk.configure_scope() as scope:


Test patch:
diff --git a/src/backend/marsha/core/tests/test_settings.py b/src/backend/marsha/core/tests/test_settings.py
--- a/src/backend/marsha/core/tests/test_settings.py
+++ b/src/backend/marsha/core/tests/test_settings.py
@@ -3,7 +3,9 @@
 
 from django.test import TestCase
 
-from marsha.settings import get_release
+from sentry_sdk.integrations.django import DjangoIntegration
+
+from marsha.settings import Base, get_release
 
 
 # pylint: disable=unused-argument
@@ -25,3 +27,15 @@ def test_get_release_from_an_invalid_version_file(self, *args):
         """Attempt (and fail) to get release from a broken version.json file."""
         with self.assertRaises(KeyError):
             get_release()
+
+    @mock.patch("marsha.settings.sentry_sdk.init")
+    def test_init_sentry_sdk(self, sentry_sdk_mock):
+        """Configure sentry sdk in post_setup function."""
+        Base.SENTRY_DSN = "https://foo.sentry.io"
+        Base.post_setup()
+        sentry_sdk_mock.assert_called_once()
+        init_parameters = sentry_sdk_mock.call_args.kwargs
+        self.assertEqual(init_parameters.get("dsn"), "https://foo.sentry.io")
+        self.assertEqual(init_parameters.get("environment"), "base")
+        self.assertEqual(init_parameters.get("release"), "NA")
+        self.assertIsInstance(init_parameters.get("integrations")[0], DjangoIntegration)