Skip to content

Event handlers awkward interaction with the Django RollbarNotifierMiddleware #393

@phillipuniverse

Description

@phillipuniverse

I am having an issue where it appears the only clean option to initialize Rollbar event handlers (e.g. rollbar.events.add_payload_handler) is within the RollbarNotifierMiddleware as a subclass of __init__. This does work, but it's not very clean.

Here is my ROLLBAR variable in settings.py:

ROLLBAR = {
    'access_token': env.str('ROLLBAR_ACCESS_TOKEN', ''),
    'environment': 'dev',
    'branch': master,
    'root': '/usr/src/app/',
    'enabled': ROLLBAR_ENABLED,
    'locals': {
        'enabled': True,
        'safe_repr': False,
    },
    'ignorable_404_urls': (
        re.compile('.*'),  # never report a 404 to Rollbar
    ),
}

Then at the end of settings.py I want to add a payload handler to add trace information from OpenTelemetry:

import rollbar
from django.conf import settings

def transform_rollbar_payload(
        payload: Dict[str, Any], **kwargs: Dict[str, Any]
) -> Dict[str, Any]:
    data = payload["data"]
    custom = data.get("custom", {})

    custom['service'] = settings.SERVICE
    custom['env'] = settings.ENVIRONMENT
    custom['version'] = settings.VERSION
    span = trace.get_current_span()
    if span != trace.span.INVALID_SPAN:
        ctx = span.get_span_context()
        if ctx != trace.span.INVALID_SPAN_CONTEXT:
            custom['trace_id'] = ctx.trace_id
            custom['span_id'] = ctx.span_id

    data["custom"] = custom
    return payload

rollbar.events.add_payload_handler(transform_rollbar_payload)

When I configure it like this, the RollbarNotifierMiddleware sees that there is an access token in the Rollbar settings and then unconditionally calls rollbar.init:

rollbar.init(access_token, environment, **kw)

But when this happens, the rollbar.init() calls rollbar.events.reset(). This clears out my previously-added payload handler since it was added prior to Django initializing middleware and thus the RollbarNotifierMiddleware invoking rollbar.init().

I see a few options, none of which I'm particularly thrilled about:

  1. Subclass RollbarNotifierMiddleware, call super.__init__(), and then call rollbar.events.add_payload_handler() (this is the one I went with):
    class TracedRollbarNotifierMiddleware(RollbarNotifierMiddleware):
        """
        The default RollbarNotifierMiddleware unconditionally does a rollbar.init() itself with the given access token
        """
        def __init__(self, get_response=None):
            super().__init__(get_response)
            import rollbar
            from django.conf import settings
    
            def transform_rollbar_payload(
                    payload: Dict[str, Any], **kwargs: Dict[str, Any]
            ) -> Dict[str, Any]:
                data = payload["data"]
                custom = data.get("custom", {})
    
                custom['service'] = settings.SERVICE
                custom['env'] = settings.ENVIRONMENT
                custom['version'] = settings.VERSION
                span = trace.get_current_span()
                if span != trace.span.INVALID_SPAN:
                    ctx = span.get_span_context()
                    if ctx != trace.span.INVALID_SPAN_CONTEXT:
                        custom['trace_id'] = ctx.trace_id
                        custom['span_id'] = ctx.span_id
    
                data["custom"] = custom
                return payload
    
            rollbar.events.add_payload_handler(transform_rollbar_payload)
  2. Move the event handler registration to within a Django AppConfig.ready(), I presume this happens after middleware instantiation
  3. Call rollbar.init() myself, but still set a ROLLBAR = {'access_token': 'not-used'} in settings.py so that the middleware will still be activated (RollbarNotifierMiddleware is skipped unless this is set)

So what is the intended use of event handlers with the RollbarNotifierMiddleware? Where in the lifecycle should I be adding these?

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