Closed
Description
I'm looking to upgrade from raven-python[flask] to sentry-sdk[flask]. We previous had two DSNs for our backend: one for errors and one to log performance issues (e.g. slow requests / high DB query count).
We were previously able to configure this via:
from raven.contrib.flask import Sentry
from raven.handlers.logging import SentryHandler
performance_logger = logging.getLogger("benchling.performance")
performance_logger.setLevel(logging.WARNING)
sentry = Sentry(logging=True, level=logging.WARNING)
def init_sentry(app):
sentry.init_app(app, dsn=app.config["SENTRY_DSN_SERVER"])
performance_handler = SentryHandler(dsn=app.config["SENTRY_DSN_BACKEND_PERFORMANCE"])
performance_logger.addHandler(performance_handler)
With the new architecture, this seems hard to do since the DSN is configured once via sentry_sdk.init where the LoggingIntegration simply listens to the root logger. I was able to hack around this by monkey-patching the logging_integration's handler as follows:
import logging
import sentry_sdk
from sentry_sdk.client import Client
from sentry_sdk.hub import Hub
from sentry_sdk.integrations.celery import CeleryIntegration
from sentry_sdk.integrations.flask import FlaskIntegration
from sentry_sdk.integrations.logging import LoggingIntegration
def register_clients_for_loggers(logger_name_to_client):
"""Monkeypatch LoggingIntegration's EventHandler to override the Client based on the record's logger"""
hub = Hub.current
logging_integration = hub.get_integration(LoggingIntegration)
if not logging_integration:
return
handler = logging_integration._handler
old_emit = handler.emit
def new_emit(record):
new_client = logger_name_to_client.get(record.name)
previous_client = hub.client
should_bind = new_client is not None
try:
if should_bind:
hub.bind_client(new_client)
old_emit(record)
finally:
if should_bind:
hub.bind_client(previous_client)
handler.emit = new_emit
def init_sentry(app):
sentry_sdk.init(
dsn=app.config["SENTRY_DSN_SERVER"],
release=app.config["SENTRY_RELEASE"],
environment=app.config["SENTRY_ENVIRONMENT"],
integrations=[
LoggingIntegration(
level=logging.WARNING, # Capture info and above as breadcrumbs
event_level=logging.WARNING, # Send warnings and errors as events
),
CeleryIntegration(),
FlaskIntegration(),
],
)
performance_logger = logging.getLogger("benchling.performance")
performance_logger.setLevel(logging.WARNING)
perf_client = Client(
dsn=app.config["SENTRY_DSN_BACKEND_PERFORMANCE"],
release=app.config["SENTRY_RELEASE"],
environment=app.config["SENTRY_ENVIRONMENT"],
)
register_clients_for_loggers({performance_logger.name: perf_client})
Two questions:
- Does this approach seem reasonable, or is there a better way to handle this?
- If there isn't a better way, would it be possible to have
sentry_sdk.init
let you specify this mapping?
Metadata
Metadata
Assignees
Labels
No labels