diff --git a/synapse/app/_base.py b/synapse/app/_base.py
index 73ca52bd8c..32e8b8a3f5 100644
--- a/synapse/app/_base.py
+++ b/synapse/app/_base.py
@@ -25,10 +25,12 @@ from daemonize import Daemonize
from twisted.internet import error, reactor
from twisted.protocols.tls import TLSMemoryBIOFactory
+import synapse
from synapse.app import check_bind_error
from synapse.crypto import context_factory
from synapse.util import PreserveLoggingContext
from synapse.util.rlimit import change_resource_limit
+from synapse.util.versionstring import get_version_string
logger = logging.getLogger(__name__)
@@ -270,9 +272,37 @@ def start(hs, listeners=None):
# It is now safe to start your Synapse.
hs.start_listening(listeners)
hs.get_datastore().start_profiling()
+
+ setup_sentry(hs)
except Exception:
traceback.print_exc(file=sys.stderr)
reactor = hs.get_reactor()
if reactor.running:
reactor.stop()
sys.exit(1)
+
+
+def setup_sentry(hs):
+ """Enable sentry integration, if enabled in configuration
+
+ Args:
+ hs (synapse.server.HomeServer)
+ """
+
+ if not hs.config.sentry_enabled:
+ return
+
+ import sentry_sdk
+ sentry_sdk.init(
+ dsn=hs.config.sentry_dsn,
+ release=get_version_string(synapse),
+ )
+
+ # We set some default tags that give some context to this instance
+ with sentry_sdk.configure_scope() as scope:
+ scope.set_tag("matrix_server_name", hs.config.server_name)
+
+ app = hs.config.worker_app if hs.config.worker_app else "synapse.app.homeserver"
+ name = hs.config.worker_name if hs.config.worker_name else "master"
+ scope.set_tag("worker_app", app)
+ scope.set_tag("worker_name", name)
diff --git a/synapse/config/metrics.py b/synapse/config/metrics.py
index 718c43ae03..35f1074765 100644
--- a/synapse/config/metrics.py
+++ b/synapse/config/metrics.py
@@ -13,7 +13,13 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-from ._base import Config
+from ._base import Config, ConfigError
+
+MISSING_SENTRY = (
+ """Missing sentry-sdk library. This is required to enable sentry
+ integration.
+ """
+)
class MetricsConfig(Config):
@@ -23,12 +29,34 @@ class MetricsConfig(Config):
self.metrics_port = config.get("metrics_port")
self.metrics_bind_host = config.get("metrics_bind_host", "127.0.0.1")
+ self.sentry_enabled = "sentry" in config
+ if self.sentry_enabled:
+ try:
+ import sentry_sdk # noqa F401
+ except ImportError:
+ raise ConfigError(MISSING_SENTRY)
+
+ self.sentry_dsn = config["sentry"].get("dsn")
+ if not self.sentry_dsn:
+ raise ConfigError(
+ "sentry.dsn field is required when sentry integration is enabled",
+ )
+
def default_config(self, report_stats=None, **kwargs):
res = """\
## Metrics ###
# Enable collection and rendering of performance metrics
enable_metrics: False
+
+ # Enable sentry integration
+ # NOTE: While attempts are made to ensure that the logs don't contain
+ # any sensitive information, this cannot be guaranteed. By enabling
+ # this option the sentry server may therefore receive sensitive
+ # information, and it in turn may then diseminate sensitive information
+ # through insecure notification channels if so configured.
+ #sentry:
+ # dsn: "..."
"""
if report_stats is None:
diff --git a/synapse/python_dependencies.py b/synapse/python_dependencies.py
index 590ee59907..f71e21ff4d 100644
--- a/synapse/python_dependencies.py
+++ b/synapse/python_dependencies.py
@@ -86,6 +86,7 @@ CONDITIONAL_REQUIREMENTS = {
"saml2": ["pysaml2>=4.5.0"],
"url_preview": ["lxml>=3.5.0"],
"test": ["mock>=2.0", "parameterized"],
+ "sentry": ["sentry-sdk>=0.7.2"],
}
|