diff --git a/docs/breadcrumbs.rst b/docs/breadcrumbs.rst index 642005dcb..c8ffa18d4 100644 --- a/docs/breadcrumbs.rst +++ b/docs/breadcrumbs.rst @@ -60,9 +60,7 @@ the :py:func:`~raven.breadcrumbs.ignore_logger` and with given arguments: `logger`, `level`, `msg`, `args` and `kwargs` which are the values passed to the logging system. If the callback returns true value the default handling is disabled. Only one callback - can be registered per one logger name. Logger tree is not traversed - so calling this method with `spammy_module` argument will not silence - messages from `spammy_module.child`. + can be registered per one logger name. Typically it makes sense to invoke :py:func:`~raven.breadcrumbs.record` from it unless you want to silence diff --git a/raven/breadcrumbs.py b/raven/breadcrumbs.py index 13987f133..33b4ed8d3 100644 --- a/raven/breadcrumbs.py +++ b/raven/breadcrumbs.py @@ -257,6 +257,17 @@ def install_logging_hook(): _patch_logger() +def resolve_child_loggers(name): + """Resolves children logger. Resolution will only work for loggers + that are registered before this function is called. + """ + children = [] + for n in logging.Logger.manager.loggerDict.keys(): + if n.startswith(name): + children.append(n) + return children + + def ignore_logger(name_or_logger, allow_level=None): """Ignores a logger during breadcrumb recording. """ @@ -273,14 +284,17 @@ def register_special_log_handler(name_or_logger, callback): with given arguments: `logger`, `level`, `msg`, `args` and `kwargs` which are the values passed to the logging system. If the callback returns true value the default handling is disabled. Only one callback - can be registered per one logger name. Logger tree is not traversed - so calling this method with `spammy_module` argument will not silence - messages from `spammy_module.child`. + can be registered per one logger name. """ if isinstance(name_or_logger, string_types): name = name_or_logger else: name = name_or_logger.name + + for c in resolve_child_loggers(name): + special_logger_handlers[c] = callback + + # always add parent logger special_logger_handlers[name] = callback diff --git a/tests/breadcrumbs/tests.py b/tests/breadcrumbs/tests.py index da291e5bd..b48515b33 100644 --- a/tests/breadcrumbs/tests.py +++ b/tests/breadcrumbs/tests.py @@ -152,6 +152,39 @@ def handler(logger, level, msg, args, kwargs): crumbs = client.context.breadcrumbs.get_buffer() assert len(crumbs) == 0 + # test child resolution + name = __name__ + logger = logging.getLogger(name) + + def handler(logger, level, msg, args, kwargs): + assert logger.name == name + assert msg == 'aha!' + return True + + breadcrumbs.register_special_log_handler(name, handler) + + client = Client('http://foo:bar@example.com/0') + with client.context: + logger.debug('aha!') + crumbs = client.context.breadcrumbs.get_buffer() + assert len(crumbs) == 0 + + logger = logging.getLogger('superspecial') + + # test positive case + def handler(logger, level, msg, args, kwargs): + assert logger.name == name + assert msg == 'aha!' + return True + + breadcrumbs.register_special_log_handler(name, handler) + + client = Client('http://foo:bar@example.com/0') + with client.context: + logger.debug('aha!') + crumbs = client.context.breadcrumbs.get_buffer() + assert len(crumbs) == 1 + def test_logging_handlers(self): name = __name__ + '.superspecial2' logger = logging.getLogger(name)