Top

sentry_sdk.integrations.logging module

from __future__ import absolute_import

import logging
import datetime

from sentry_sdk.hub import Hub
from sentry_sdk.utils import (
    to_string,
    event_from_exception,
    current_stacktrace,
    capture_internal_exceptions,
)
from sentry_sdk.integrations import Integration
from sentry_sdk._compat import iteritems

from sentry_sdk._types import MYPY

if MYPY:
    from logging import LogRecord
    from typing import Any
    from typing import Dict

DEFAULT_LEVEL = logging.INFO
DEFAULT_EVENT_LEVEL = logging.ERROR

_IGNORED_LOGGERS = set(["sentry_sdk.errors"])


def ignore_logger(name):
    # type: (str) -> None
    """This disables recording (both in breadcrumbs and as events) calls to
    a logger of a specific name.  Among other uses, many of our integrations
    use this to prevent their actions being recorded as breadcrumbs. Exposed
    to users as a way to quiet spammy loggers.
    """
    _IGNORED_LOGGERS.add(name)


class LoggingIntegration(Integration):
    identifier = "logging"

    def __init__(self, level=DEFAULT_LEVEL, event_level=DEFAULT_EVENT_LEVEL):
        # type: (int, int) -> None
        self._handler = None
        self._breadcrumb_handler = None

        if level is not None:
            self._breadcrumb_handler = BreadcrumbHandler(level=level)

        if event_level is not None:
            self._handler = EventHandler(level=event_level)

    def _handle_record(self, record):
        # type: (LogRecord) -> None
        if self._handler is not None and record.levelno >= self._handler.level:
            self._handler.handle(record)

        if (
            self._breadcrumb_handler is not None
            and record.levelno >= self._breadcrumb_handler.level
        ):
            self._breadcrumb_handler.handle(record)

    @staticmethod
    def setup_once():
        # type: () -> None
        old_callhandlers = logging.Logger.callHandlers  # type: ignore

        def sentry_patched_callhandlers(self, record):
            # type: (Any, LogRecord) -> Any
            try:
                return old_callhandlers(self, record)
            finally:
                # This check is done twice, once also here before we even get
                # the integration.  Otherwise we have a high chance of getting
                # into a recursion error when the integration is resolved
                # (this also is slower).
                if record.name not in _IGNORED_LOGGERS:
                    integration = Hub.current.get_integration(LoggingIntegration)
                    if integration is not None:
                        integration._handle_record(record)

        logging.Logger.callHandlers = sentry_patched_callhandlers  # type: ignore


def _can_record(record):
    # type: (LogRecord) -> bool
    return record.name not in _IGNORED_LOGGERS


def _breadcrumb_from_record(record):
    # type: (LogRecord) -> Dict[str, Any]
    return {
        "ty": "log",
        "level": _logging_to_event_level(record.levelname),
        "category": record.name,
        "message": record.message,
        "timestamp": datetime.datetime.fromtimestamp(record.created),
        "data": _extra_from_record(record),
    }


def _logging_to_event_level(levelname):
    # type: (str) -> str
    return {"critical": "fatal"}.get(levelname.lower(), levelname.lower())


COMMON_RECORD_ATTRS = frozenset(
    (
        "args",
        "created",
        "exc_info",
        "exc_text",
        "filename",
        "funcName",
        "levelname",
        "levelno",
        "linenno",
        "lineno",
        "message",
        "module",
        "msecs",
        "msg",
        "name",
        "pathname",
        "process",
        "processName",
        "relativeCreated",
        "stack",
        "tags",
        "thread",
        "threadName",
    )
)


def _extra_from_record(record):
    # type: (LogRecord) -> Dict[str, None]
    return {
        k: v
        for k, v in iteritems(vars(record))
        if k not in COMMON_RECORD_ATTRS
        and (not isinstance(k, str) or not k.startswith("_"))
    }


class EventHandler(logging.Handler, object):
    def emit(self, record):
        # type: (LogRecord) -> Any
        with capture_internal_exceptions():
            self.format(record)
            return self._emit(record)

    def _emit(self, record):
        # type: (LogRecord) -> None
        if not _can_record(record):
            return

        hub = Hub.current
        if hub.client is None:
            return

        client_options = hub.client.options

        # exc_info might be None or (None, None, None)
        if record.exc_info is not None and record.exc_info[0] is not None:
            event, hint = event_from_exception(
                record.exc_info,
                client_options=client_options,
                mechanism={"type": "logging", "handled": True},
            )
        elif record.exc_info and record.exc_info[0] is None:
            event = {}
            hint = {}
            with capture_internal_exceptions():
                event["threads"] = {
                    "values": [
                        {
                            "stacktrace": current_stacktrace(
                                client_options["with_locals"]
                            ),
                            "crashed": False,
                            "current": True,
                        }
                    ]
                }
        else:
            event = {}
            hint = {}

        hint["log_record"] = record

        event["level"] = _logging_to_event_level(record.levelname)
        event["logger"] = record.name
        event["logentry"] = {"message": to_string(record.msg), "params": record.args}
        event["extra"] = _extra_from_record(record)

        hub.capture_event(event, hint=hint)


# Legacy name
SentryHandler = EventHandler


class BreadcrumbHandler(logging.Handler, object):
    def emit(self, record):
        # type: (LogRecord) -> Any
        with capture_internal_exceptions():
            self.format(record)
            return self._emit(record)

    def _emit(self, record):
        # type: (LogRecord) -> None
        if not _can_record(record):
            return

        Hub.current.add_breadcrumb(
            _breadcrumb_from_record(record), hint={"log_record": record}
        )

Module variables

var COMMON_RECORD_ATTRS

var DEFAULT_EVENT_LEVEL

var DEFAULT_LEVEL

var MYPY

Functions

def ignore_logger(

name)

This disables recording (both in breadcrumbs and as events) calls to a logger of a specific name. Among other uses, many of our integrations use this to prevent their actions being recorded as breadcrumbs. Exposed to users as a way to quiet spammy loggers.

def ignore_logger(name):
    # type: (str) -> None
    """This disables recording (both in breadcrumbs and as events) calls to
    a logger of a specific name.  Among other uses, many of our integrations
    use this to prevent their actions being recorded as breadcrumbs. Exposed
    to users as a way to quiet spammy loggers.
    """
    _IGNORED_LOGGERS.add(name)

Classes

class BreadcrumbHandler

Handler instances dispatch logging events to specific destinations.

The base handler class. Acts as a placeholder which defines the Handler interface. Handlers can optionally use Formatter instances to format records as desired. By default, no formatter is specified; in this case, the 'raw' message as determined by record.message is logged.

class BreadcrumbHandler(logging.Handler, object):
    def emit(self, record):
        # type: (LogRecord) -> Any
        with capture_internal_exceptions():
            self.format(record)
            return self._emit(record)

    def _emit(self, record):
        # type: (LogRecord) -> None
        if not _can_record(record):
            return

        Hub.current.add_breadcrumb(
            _breadcrumb_from_record(record), hint={"log_record": record}
        )

Ancestors (in MRO)

Static methods

def __init__(

self, level=0)

Initializes the instance - basically setting the formatter to None and the filter list to empty.

def __init__(self, level=NOTSET):
    """
    Initializes the instance - basically setting the formatter to None
    and the filter list to empty.
    """
    Filterer.__init__(self)
    self._name = None
    self.level = _checkLevel(level)
    self.formatter = None
    # Add the handler to the global _handlerList (for cleanup on shutdown)
    _addHandlerRef(self)
    self.createLock()

def acquire(

self)

Acquire the I/O thread lock.

def acquire(self):
    """
    Acquire the I/O thread lock.
    """
    if self.lock:
        self.lock.acquire()

def addFilter(

self, filter)

Add the specified filter to this handler.

def addFilter(self, filter):
    """
    Add the specified filter to this handler.
    """
    if not (filter in self.filters):
        self.filters.append(filter)

def close(

self)

Tidy up any resources used by the handler.

This version removes the handler from an internal map of handlers, _handlers, which is used for handler lookup by name. Subclasses should ensure that this gets called from overridden close() methods.

def close(self):
    """
    Tidy up any resources used by the handler.
    This version removes the handler from an internal map of handlers,
    _handlers, which is used for handler lookup by name. Subclasses
    should ensure that this gets called from overridden close()
    methods.
    """
    #get the module data lock, as we're updating a shared structure.
    _acquireLock()
    try:    #unlikely to raise an exception, but you never know...
        if self._name and self._name in _handlers:
            del _handlers[self._name]
    finally:
        _releaseLock()

def createLock(

self)

Acquire a thread lock for serializing access to the underlying I/O.

def createLock(self):
    """
    Acquire a thread lock for serializing access to the underlying I/O.
    """
    if threading:
        self.lock = threading.RLock()
    else: #pragma: no cover
        self.lock = None

def emit(

self, record)

Do whatever it takes to actually log the specified logging record.

This version is intended to be implemented by subclasses and so raises a NotImplementedError.

def emit(self, record):
    # type: (LogRecord) -> Any
    with capture_internal_exceptions():
        self.format(record)
        return self._emit(record)

def filter(

self, record)

Determine if a record is loggable by consulting all the filters.

The default is to allow the record to be logged; any filter can veto this and the record is then dropped. Returns a zero value if a record is to be dropped, else non-zero.

.. versionchanged:: 3.2

Allow filters to be just callables.

def filter(self, record):
    """
    Determine if a record is loggable by consulting all the filters.
    The default is to allow the record to be logged; any filter can veto
    this and the record is then dropped. Returns a zero value if a record
    is to be dropped, else non-zero.
    .. versionchanged:: 3.2
       Allow filters to be just callables.
    """
    rv = True
    for f in self.filters:
        if hasattr(f, 'filter'):
            result = f.filter(record)
        else:
            result = f(record) # assume callable - will raise if not
        if not result:
            rv = False
            break
    return rv

def flush(

self)

Ensure all logging output has been flushed.

This version does nothing and is intended to be implemented by subclasses.

def flush(self):
    """
    Ensure all logging output has been flushed.
    This version does nothing and is intended to be implemented by
    subclasses.
    """
    pass

def format(

self, record)

Format the specified record.

If a formatter is set, use it. Otherwise, use the default formatter for the module.

def format(self, record):
    """
    Format the specified record.
    If a formatter is set, use it. Otherwise, use the default formatter
    for the module.
    """
    if self.formatter:
        fmt = self.formatter
    else:
        fmt = _defaultFormatter
    return fmt.format(record)

def get_name(

self)

def get_name(self):
    return self._name

def handle(

self, record)

Conditionally emit the specified logging record.

Emission depends on filters which may have been added to the handler. Wrap the actual emission of the record with acquisition/release of the I/O thread lock. Returns whether the filter passed the record for emission.

def handle(self, record):
    """
    Conditionally emit the specified logging record.
    Emission depends on filters which may have been added to the handler.
    Wrap the actual emission of the record with acquisition/release of
    the I/O thread lock. Returns whether the filter passed the record for
    emission.
    """
    rv = self.filter(record)
    if rv:
        self.acquire()
        try:
            self.emit(record)
        finally:
            self.release()
    return rv

def handleError(

self, record)

Handle errors which occur during an emit() call.

This method should be called from handlers when an exception is encountered during an emit() call. If raiseExceptions is false, exceptions get silently ignored. This is what is mostly wanted for a logging system - most users will not care about errors in the logging system, they are more interested in application errors. You could, however, replace this with a custom handler if you wish. The record which was being processed is passed in to this method.

def handleError(self, record):
    """
    Handle errors which occur during an emit() call.
    This method should be called from handlers when an exception is
    encountered during an emit() call. If raiseExceptions is false,
    exceptions get silently ignored. This is what is mostly wanted
    for a logging system - most users will not care about errors in
    the logging system, they are more interested in application errors.
    You could, however, replace this with a custom handler if you wish.
    The record which was being processed is passed in to this method.
    """
    if raiseExceptions and sys.stderr:  # see issue 13807
        t, v, tb = sys.exc_info()
        try:
            sys.stderr.write('--- Logging error ---\n')
            traceback.print_exception(t, v, tb, None, sys.stderr)
            sys.stderr.write('Call stack:\n')
            # Walk the stack frame up until we're out of logging,
            # so as to print the calling context.
            frame = tb.tb_frame
            while (frame and os.path.dirname(frame.f_code.co_filename) ==
                   __path__[0]):
                frame = frame.f_back
            if frame:
                traceback.print_stack(frame, file=sys.stderr)
            else:
                # couldn't find the right stack frame, for some reason
                sys.stderr.write('Logged from file %s, line %s\n' % (
                                 record.filename, record.lineno))
            # Issue 18671: output logging message and arguments
            try:
                sys.stderr.write('Message: %r\n'
                                 'Arguments: %s\n' % (record.msg,
                                                      record.args))
            except Exception:
                sys.stderr.write('Unable to print the message and arguments'
                                 ' - possible formatting error.\nUse the'
                                 ' traceback above to help find the error.\n'
                                )
        except OSError: #pragma: no cover
            pass    # see issue 5971
        finally:
            del t, v, tb

def release(

self)

Release the I/O thread lock.

def release(self):
    """
    Release the I/O thread lock.
    """
    if self.lock:
        self.lock.release()

def removeFilter(

self, filter)

Remove the specified filter from this handler.

def removeFilter(self, filter):
    """
    Remove the specified filter from this handler.
    """
    if filter in self.filters:
        self.filters.remove(filter)

def setFormatter(

self, fmt)

Set the formatter for this handler.

def setFormatter(self, fmt):
    """
    Set the formatter for this handler.
    """
    self.formatter = fmt

def setLevel(

self, level)

Set the logging level of this handler. level must be an int or a str.

def setLevel(self, level):
    """
    Set the logging level of this handler.  level must be an int or a str.
    """
    self.level = _checkLevel(level)

def set_name(

self, name)

def set_name(self, name):
    _acquireLock()
    try:
        if self._name in _handlers:
            del _handlers[self._name]
        self._name = name
        if name:
            _handlers[name] = self
    finally:
        _releaseLock()

Instance variables

var name

class EventHandler

Handler instances dispatch logging events to specific destinations.

The base handler class. Acts as a placeholder which defines the Handler interface. Handlers can optionally use Formatter instances to format records as desired. By default, no formatter is specified; in this case, the 'raw' message as determined by record.message is logged.

class EventHandler(logging.Handler, object):
    def emit(self, record):
        # type: (LogRecord) -> Any
        with capture_internal_exceptions():
            self.format(record)
            return self._emit(record)

    def _emit(self, record):
        # type: (LogRecord) -> None
        if not _can_record(record):
            return

        hub = Hub.current
        if hub.client is None:
            return

        client_options = hub.client.options

        # exc_info might be None or (None, None, None)
        if record.exc_info is not None and record.exc_info[0] is not None:
            event, hint = event_from_exception(
                record.exc_info,
                client_options=client_options,
                mechanism={"type": "logging", "handled": True},
            )
        elif record.exc_info and record.exc_info[0] is None:
            event = {}
            hint = {}
            with capture_internal_exceptions():
                event["threads"] = {
                    "values": [
                        {
                            "stacktrace": current_stacktrace(
                                client_options["with_locals"]
                            ),
                            "crashed": False,
                            "current": True,
                        }
                    ]
                }
        else:
            event = {}
            hint = {}

        hint["log_record"] = record

        event["level"] = _logging_to_event_level(record.levelname)
        event["logger"] = record.name
        event["logentry"] = {"message": to_string(record.msg), "params": record.args}
        event["extra"] = _extra_from_record(record)

        hub.capture_event(event, hint=hint)

Ancestors (in MRO)

Static methods

def __init__(

self, level=0)

Initializes the instance - basically setting the formatter to None and the filter list to empty.

def __init__(self, level=NOTSET):
    """
    Initializes the instance - basically setting the formatter to None
    and the filter list to empty.
    """
    Filterer.__init__(self)
    self._name = None
    self.level = _checkLevel(level)
    self.formatter = None
    # Add the handler to the global _handlerList (for cleanup on shutdown)
    _addHandlerRef(self)
    self.createLock()

def acquire(

self)

Acquire the I/O thread lock.

def acquire(self):
    """
    Acquire the I/O thread lock.
    """
    if self.lock:
        self.lock.acquire()

def addFilter(

self, filter)

Add the specified filter to this handler.

def addFilter(self, filter):
    """
    Add the specified filter to this handler.
    """
    if not (filter in self.filters):
        self.filters.append(filter)

def close(

self)

Tidy up any resources used by the handler.

This version removes the handler from an internal map of handlers, _handlers, which is used for handler lookup by name. Subclasses should ensure that this gets called from overridden close() methods.

def close(self):
    """
    Tidy up any resources used by the handler.
    This version removes the handler from an internal map of handlers,
    _handlers, which is used for handler lookup by name. Subclasses
    should ensure that this gets called from overridden close()
    methods.
    """
    #get the module data lock, as we're updating a shared structure.
    _acquireLock()
    try:    #unlikely to raise an exception, but you never know...
        if self._name and self._name in _handlers:
            del _handlers[self._name]
    finally:
        _releaseLock()

def createLock(

self)

Acquire a thread lock for serializing access to the underlying I/O.

def createLock(self):
    """
    Acquire a thread lock for serializing access to the underlying I/O.
    """
    if threading:
        self.lock = threading.RLock()
    else: #pragma: no cover
        self.lock = None

def emit(

self, record)

Do whatever it takes to actually log the specified logging record.

This version is intended to be implemented by subclasses and so raises a NotImplementedError.

def emit(self, record):
    # type: (LogRecord) -> Any
    with capture_internal_exceptions():
        self.format(record)
        return self._emit(record)

def filter(

self, record)

Determine if a record is loggable by consulting all the filters.

The default is to allow the record to be logged; any filter can veto this and the record is then dropped. Returns a zero value if a record is to be dropped, else non-zero.

.. versionchanged:: 3.2

Allow filters to be just callables.

def filter(self, record):
    """
    Determine if a record is loggable by consulting all the filters.
    The default is to allow the record to be logged; any filter can veto
    this and the record is then dropped. Returns a zero value if a record
    is to be dropped, else non-zero.
    .. versionchanged:: 3.2
       Allow filters to be just callables.
    """
    rv = True
    for f in self.filters:
        if hasattr(f, 'filter'):
            result = f.filter(record)
        else:
            result = f(record) # assume callable - will raise if not
        if not result:
            rv = False
            break
    return rv

def flush(

self)

Ensure all logging output has been flushed.

This version does nothing and is intended to be implemented by subclasses.

def flush(self):
    """
    Ensure all logging output has been flushed.
    This version does nothing and is intended to be implemented by
    subclasses.
    """
    pass

def format(

self, record)

Format the specified record.

If a formatter is set, use it. Otherwise, use the default formatter for the module.

def format(self, record):
    """
    Format the specified record.
    If a formatter is set, use it. Otherwise, use the default formatter
    for the module.
    """
    if self.formatter:
        fmt = self.formatter
    else:
        fmt = _defaultFormatter
    return fmt.format(record)

def get_name(

self)

def get_name(self):
    return self._name

def handle(

self, record)

Conditionally emit the specified logging record.

Emission depends on filters which may have been added to the handler. Wrap the actual emission of the record with acquisition/release of the I/O thread lock. Returns whether the filter passed the record for emission.

def handle(self, record):
    """
    Conditionally emit the specified logging record.
    Emission depends on filters which may have been added to the handler.
    Wrap the actual emission of the record with acquisition/release of
    the I/O thread lock. Returns whether the filter passed the record for
    emission.
    """
    rv = self.filter(record)
    if rv:
        self.acquire()
        try:
            self.emit(record)
        finally:
            self.release()
    return rv

def handleError(

self, record)

Handle errors which occur during an emit() call.

This method should be called from handlers when an exception is encountered during an emit() call. If raiseExceptions is false, exceptions get silently ignored. This is what is mostly wanted for a logging system - most users will not care about errors in the logging system, they are more interested in application errors. You could, however, replace this with a custom handler if you wish. The record which was being processed is passed in to this method.

def handleError(self, record):
    """
    Handle errors which occur during an emit() call.
    This method should be called from handlers when an exception is
    encountered during an emit() call. If raiseExceptions is false,
    exceptions get silently ignored. This is what is mostly wanted
    for a logging system - most users will not care about errors in
    the logging system, they are more interested in application errors.
    You could, however, replace this with a custom handler if you wish.
    The record which was being processed is passed in to this method.
    """
    if raiseExceptions and sys.stderr:  # see issue 13807
        t, v, tb = sys.exc_info()
        try:
            sys.stderr.write('--- Logging error ---\n')
            traceback.print_exception(t, v, tb, None, sys.stderr)
            sys.stderr.write('Call stack:\n')
            # Walk the stack frame up until we're out of logging,
            # so as to print the calling context.
            frame = tb.tb_frame
            while (frame and os.path.dirname(frame.f_code.co_filename) ==
                   __path__[0]):
                frame = frame.f_back
            if frame:
                traceback.print_stack(frame, file=sys.stderr)
            else:
                # couldn't find the right stack frame, for some reason
                sys.stderr.write('Logged from file %s, line %s\n' % (
                                 record.filename, record.lineno))
            # Issue 18671: output logging message and arguments
            try:
                sys.stderr.write('Message: %r\n'
                                 'Arguments: %s\n' % (record.msg,
                                                      record.args))
            except Exception:
                sys.stderr.write('Unable to print the message and arguments'
                                 ' - possible formatting error.\nUse the'
                                 ' traceback above to help find the error.\n'
                                )
        except OSError: #pragma: no cover
            pass    # see issue 5971
        finally:
            del t, v, tb

def release(

self)

Release the I/O thread lock.

def release(self):
    """
    Release the I/O thread lock.
    """
    if self.lock:
        self.lock.release()

def removeFilter(

self, filter)

Remove the specified filter from this handler.

def removeFilter(self, filter):
    """
    Remove the specified filter from this handler.
    """
    if filter in self.filters:
        self.filters.remove(filter)

def setFormatter(

self, fmt)

Set the formatter for this handler.

def setFormatter(self, fmt):
    """
    Set the formatter for this handler.
    """
    self.formatter = fmt

def setLevel(

self, level)

Set the logging level of this handler. level must be an int or a str.

def setLevel(self, level):
    """
    Set the logging level of this handler.  level must be an int or a str.
    """
    self.level = _checkLevel(level)

def set_name(

self, name)

def set_name(self, name):
    _acquireLock()
    try:
        if self._name in _handlers:
            del _handlers[self._name]
        self._name = name
        if name:
            _handlers[name] = self
    finally:
        _releaseLock()

Instance variables

var name

class LoggingIntegration

Baseclass for all integrations.

To accept options for an integration, implement your own constructor that saves those options on self.

class LoggingIntegration(Integration):
    identifier = "logging"

    def __init__(self, level=DEFAULT_LEVEL, event_level=DEFAULT_EVENT_LEVEL):
        # type: (int, int) -> None
        self._handler = None
        self._breadcrumb_handler = None

        if level is not None:
            self._breadcrumb_handler = BreadcrumbHandler(level=level)

        if event_level is not None:
            self._handler = EventHandler(level=event_level)

    def _handle_record(self, record):
        # type: (LogRecord) -> None
        if self._handler is not None and record.levelno >= self._handler.level:
            self._handler.handle(record)

        if (
            self._breadcrumb_handler is not None
            and record.levelno >= self._breadcrumb_handler.level
        ):
            self._breadcrumb_handler.handle(record)

    @staticmethod
    def setup_once():
        # type: () -> None
        old_callhandlers = logging.Logger.callHandlers  # type: ignore

        def sentry_patched_callhandlers(self, record):
            # type: (Any, LogRecord) -> Any
            try:
                return old_callhandlers(self, record)
            finally:
                # This check is done twice, once also here before we even get
                # the integration.  Otherwise we have a high chance of getting
                # into a recursion error when the integration is resolved
                # (this also is slower).
                if record.name not in _IGNORED_LOGGERS:
                    integration = Hub.current.get_integration(LoggingIntegration)
                    if integration is not None:
                        integration._handle_record(record)

        logging.Logger.callHandlers = sentry_patched_callhandlers  # type: ignore

Ancestors (in MRO)

Class variables

var identifier

var install

Static methods

def __init__(

self, level=20, event_level=40)

Initialize self. See help(type(self)) for accurate signature.

def __init__(self, level=DEFAULT_LEVEL, event_level=DEFAULT_EVENT_LEVEL):
    # type: (int, int) -> None
    self._handler = None
    self._breadcrumb_handler = None
    if level is not None:
        self._breadcrumb_handler = BreadcrumbHandler(level=level)
    if event_level is not None:
        self._handler = EventHandler(level=event_level)

def setup_once(

)

Initialize the integration.

This function is only called once, ever. Configuration is not available at this point, so the only thing to do here is to hook into exception handlers, and perhaps do monkeypatches.

Inside those hooks Integration.current can be used to access the instance again.

@staticmethod
def setup_once():
    # type: () -> None
    old_callhandlers = logging.Logger.callHandlers  # type: ignore
    def sentry_patched_callhandlers(self, record):
        # type: (Any, LogRecord) -> Any
        try:
            return old_callhandlers(self, record)
        finally:
            # This check is done twice, once also here before we even get
            # the integration.  Otherwise we have a high chance of getting
            # into a recursion error when the integration is resolved
            # (this also is slower).
            if record.name not in _IGNORED_LOGGERS:
                integration = Hub.current.get_integration(LoggingIntegration)
                if integration is not None:
                    integration._handle_record(record)
    logging.Logger.callHandlers = sentry_patched_callhandlers  # type: ignore

class SentryHandler

Handler instances dispatch logging events to specific destinations.

The base handler class. Acts as a placeholder which defines the Handler interface. Handlers can optionally use Formatter instances to format records as desired. By default, no formatter is specified; in this case, the 'raw' message as determined by record.message is logged.

class EventHandler(logging.Handler, object):
    def emit(self, record):
        # type: (LogRecord) -> Any
        with capture_internal_exceptions():
            self.format(record)
            return self._emit(record)

    def _emit(self, record):
        # type: (LogRecord) -> None
        if not _can_record(record):
            return

        hub = Hub.current
        if hub.client is None:
            return

        client_options = hub.client.options

        # exc_info might be None or (None, None, None)
        if record.exc_info is not None and record.exc_info[0] is not None:
            event, hint = event_from_exception(
                record.exc_info,
                client_options=client_options,
                mechanism={"type": "logging", "handled": True},
            )
        elif record.exc_info and record.exc_info[0] is None:
            event = {}
            hint = {}
            with capture_internal_exceptions():
                event["threads"] = {
                    "values": [
                        {
                            "stacktrace": current_stacktrace(
                                client_options["with_locals"]
                            ),
                            "crashed": False,
                            "current": True,
                        }
                    ]
                }
        else:
            event = {}
            hint = {}

        hint["log_record"] = record

        event["level"] = _logging_to_event_level(record.levelname)
        event["logger"] = record.name
        event["logentry"] = {"message": to_string(record.msg), "params": record.args}
        event["extra"] = _extra_from_record(record)

        hub.capture_event(event, hint=hint)

Ancestors (in MRO)

Static methods

def __init__(

self, level=0)

Initializes the instance - basically setting the formatter to None and the filter list to empty.

def __init__(self, level=NOTSET):
    """
    Initializes the instance - basically setting the formatter to None
    and the filter list to empty.
    """
    Filterer.__init__(self)
    self._name = None
    self.level = _checkLevel(level)
    self.formatter = None
    # Add the handler to the global _handlerList (for cleanup on shutdown)
    _addHandlerRef(self)
    self.createLock()

def acquire(

self)

Acquire the I/O thread lock.

def acquire(self):
    """
    Acquire the I/O thread lock.
    """
    if self.lock:
        self.lock.acquire()

def addFilter(

self, filter)

Add the specified filter to this handler.

def addFilter(self, filter):
    """
    Add the specified filter to this handler.
    """
    if not (filter in self.filters):
        self.filters.append(filter)

def close(

self)

Tidy up any resources used by the handler.

This version removes the handler from an internal map of handlers, _handlers, which is used for handler lookup by name. Subclasses should ensure that this gets called from overridden close() methods.

def close(self):
    """
    Tidy up any resources used by the handler.
    This version removes the handler from an internal map of handlers,
    _handlers, which is used for handler lookup by name. Subclasses
    should ensure that this gets called from overridden close()
    methods.
    """
    #get the module data lock, as we're updating a shared structure.
    _acquireLock()
    try:    #unlikely to raise an exception, but you never know...
        if self._name and self._name in _handlers:
            del _handlers[self._name]
    finally:
        _releaseLock()

def createLock(

self)

Acquire a thread lock for serializing access to the underlying I/O.

def createLock(self):
    """
    Acquire a thread lock for serializing access to the underlying I/O.
    """
    if threading:
        self.lock = threading.RLock()
    else: #pragma: no cover
        self.lock = None

def emit(

self, record)

Do whatever it takes to actually log the specified logging record.

This version is intended to be implemented by subclasses and so raises a NotImplementedError.

def emit(self, record):
    # type: (LogRecord) -> Any
    with capture_internal_exceptions():
        self.format(record)
        return self._emit(record)

def filter(

self, record)

Determine if a record is loggable by consulting all the filters.

The default is to allow the record to be logged; any filter can veto this and the record is then dropped. Returns a zero value if a record is to be dropped, else non-zero.

.. versionchanged:: 3.2

Allow filters to be just callables.

def filter(self, record):
    """
    Determine if a record is loggable by consulting all the filters.
    The default is to allow the record to be logged; any filter can veto
    this and the record is then dropped. Returns a zero value if a record
    is to be dropped, else non-zero.
    .. versionchanged:: 3.2
       Allow filters to be just callables.
    """
    rv = True
    for f in self.filters:
        if hasattr(f, 'filter'):
            result = f.filter(record)
        else:
            result = f(record) # assume callable - will raise if not
        if not result:
            rv = False
            break
    return rv

def flush(

self)

Ensure all logging output has been flushed.

This version does nothing and is intended to be implemented by subclasses.

def flush(self):
    """
    Ensure all logging output has been flushed.
    This version does nothing and is intended to be implemented by
    subclasses.
    """
    pass

def format(

self, record)

Format the specified record.

If a formatter is set, use it. Otherwise, use the default formatter for the module.

def format(self, record):
    """
    Format the specified record.
    If a formatter is set, use it. Otherwise, use the default formatter
    for the module.
    """
    if self.formatter:
        fmt = self.formatter
    else:
        fmt = _defaultFormatter
    return fmt.format(record)

def get_name(

self)

def get_name(self):
    return self._name

def handle(

self, record)

Conditionally emit the specified logging record.

Emission depends on filters which may have been added to the handler. Wrap the actual emission of the record with acquisition/release of the I/O thread lock. Returns whether the filter passed the record for emission.

def handle(self, record):
    """
    Conditionally emit the specified logging record.
    Emission depends on filters which may have been added to the handler.
    Wrap the actual emission of the record with acquisition/release of
    the I/O thread lock. Returns whether the filter passed the record for
    emission.
    """
    rv = self.filter(record)
    if rv:
        self.acquire()
        try:
            self.emit(record)
        finally:
            self.release()
    return rv

def handleError(

self, record)

Handle errors which occur during an emit() call.

This method should be called from handlers when an exception is encountered during an emit() call. If raiseExceptions is false, exceptions get silently ignored. This is what is mostly wanted for a logging system - most users will not care about errors in the logging system, they are more interested in application errors. You could, however, replace this with a custom handler if you wish. The record which was being processed is passed in to this method.

def handleError(self, record):
    """
    Handle errors which occur during an emit() call.
    This method should be called from handlers when an exception is
    encountered during an emit() call. If raiseExceptions is false,
    exceptions get silently ignored. This is what is mostly wanted
    for a logging system - most users will not care about errors in
    the logging system, they are more interested in application errors.
    You could, however, replace this with a custom handler if you wish.
    The record which was being processed is passed in to this method.
    """
    if raiseExceptions and sys.stderr:  # see issue 13807
        t, v, tb = sys.exc_info()
        try:
            sys.stderr.write('--- Logging error ---\n')
            traceback.print_exception(t, v, tb, None, sys.stderr)
            sys.stderr.write('Call stack:\n')
            # Walk the stack frame up until we're out of logging,
            # so as to print the calling context.
            frame = tb.tb_frame
            while (frame and os.path.dirname(frame.f_code.co_filename) ==
                   __path__[0]):
                frame = frame.f_back
            if frame:
                traceback.print_stack(frame, file=sys.stderr)
            else:
                # couldn't find the right stack frame, for some reason
                sys.stderr.write('Logged from file %s, line %s\n' % (
                                 record.filename, record.lineno))
            # Issue 18671: output logging message and arguments
            try:
                sys.stderr.write('Message: %r\n'
                                 'Arguments: %s\n' % (record.msg,
                                                      record.args))
            except Exception:
                sys.stderr.write('Unable to print the message and arguments'
                                 ' - possible formatting error.\nUse the'
                                 ' traceback above to help find the error.\n'
                                )
        except OSError: #pragma: no cover
            pass    # see issue 5971
        finally:
            del t, v, tb

def release(

self)

Release the I/O thread lock.

def release(self):
    """
    Release the I/O thread lock.
    """
    if self.lock:
        self.lock.release()

def removeFilter(

self, filter)

Remove the specified filter from this handler.

def removeFilter(self, filter):
    """
    Remove the specified filter from this handler.
    """
    if filter in self.filters:
        self.filters.remove(filter)

def setFormatter(

self, fmt)

Set the formatter for this handler.

def setFormatter(self, fmt):
    """
    Set the formatter for this handler.
    """
    self.formatter = fmt

def setLevel(

self, level)

Set the logging level of this handler. level must be an int or a str.

def setLevel(self, level):
    """
    Set the logging level of this handler.  level must be an int or a str.
    """
    self.level = _checkLevel(level)

def set_name(

self, name)

def set_name(self, name):
    _acquireLock()
    try:
        if self._name in _handlers:
            del _handlers[self._name]
        self._name = name
        if name:
            _handlers[name] = self
    finally:
        _releaseLock()

Instance variables

var name

Inheritance: SentryHandler.name