Skip to content

SentryLogsHandler.emit formats every log record before checking has_logs_enabled #7402

Description

@lesnik512

Summary

SentryLogsHandler.emit calls self.format(record) before it checks whether Sentry Logs are enabled, so every logging record in the process pays a full Formatter.format even when the feature is off. Measured at ~1.9 µs per log record on CPython 3.14 / Apple M2.

Where

sentry_sdk/integrations/logging.py:

class SentryLogsHandler(_BaseHandler):
    def emit(self, record):
        with capture_internal_exceptions():
            self.format(record)              # <-- unconditional
            if not self._can_record(record):
                return
            client = sentry_sdk.get_client()
            if not client.is_active():
                return
            if not has_logs_enabled(client.options):   # <-- the cheap check comes last
                return
            self._capture_log_from_record(client, record)

LoggingIntegration.__init__ defaults sentry_logs_level=DEFAULT_LEVEL (INFO), so the handler is installed for every user, and LoggingIntegration is a default integration. Applications that never set enable_logs - the default - format every INFO+ record for nothing.

BreadcrumbHandler.emit has the same shape, but there the formatting is actually used to build the breadcrumb, so only this one is wasted work.

Suggested fix

Move the three guards above the format() call:

def emit(self, record):
    with capture_internal_exceptions():
        if not self._can_record(record):
            return
        client = sentry_sdk.get_client()
        if not client.is_active() or not has_logs_enabled(client.options):
            return
        self.format(record)
        self._capture_log_from_record(client, record)

_capture_log_from_record reads record.message, which format() sets, so it has to stay before that call - just not before the guards.

Impact

Measured on a FastAPI endpoint emitting three log records per request, in-process, SDK otherwise at defaults:

config added µs/req
defaults +99.7
LoggingIntegration(sentry_logs_level=None) +92.9
LoggingIntegration(level=None, sentry_logs_level=None) +73.3

The first delta (6.8 µs over three records) is this bug. Small per record, but it scales with log volume and applies to every application that has not opted into Sentry Logs.

Environment: CPython 3.14.7, sentry-sdk 2.67.1, fastapi 0.141.1, Apple M2.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions