8000 Using multiple DSNs, choosing based on the logger · Issue #198 · getsentry/sentry-python · GitHub
[go: up one dir, main page]

Skip to content
Using multiple DSNs, choosing based on the logger #198
Closed
@saifelse

Description

@saifelse

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:

  1. Does this approach seem reasonable, or is there a better way to handle this?
  2. If there isn't a better way, would it be possible to have sentry_sdk.init let you specify this mapping?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      0