diff -r 9485165435e4 Lib/logging/__init__.py --- a/Lib/logging/__init__.py Wed Sep 28 23:17:12 2016 -0700 +++ b/Lib/logging/__init__.py Thu Sep 29 17:01:11 2016 +0100 @@ -273,6 +273,7 @@ and args[0]): args = args[0] self.args = args + self.kwargs = kwargs self.levelname = getLevelName(level) self.levelno = level self.pathname = pathname @@ -1397,13 +1398,13 @@ return rv def makeRecord(self, name, level, fn, lno, msg, args, exc_info, - func=None, extra=None, sinfo=None): + func=None, extra=None, sinfo=None, **kwargs): """ A factory method which can be overridden in subclasses to create specialized LogRecords. """ rv = _logRecordFactory(name, level, fn, lno, msg, args, exc_info, func, - sinfo) + sinfo, **kwargs) if extra is not None: for key in extra: if (key in ["message", "asctime"]) or (key in rv.__dict__): @@ -1411,7 +1412,8 @@ rv.__dict__[key] = extra[key] return rv - def _log(self, level, msg, args, exc_info=None, extra=None, stack_info=False): + def _log(self, level, msg, args, exc_info=None, extra=None, stack_info=False, + **kwargs): """ Low-level logging routine which creates a LogRecord and then calls all the handlers of this logger to handle the record. @@ -1433,7 +1435,7 @@ elif not isinstance(exc_info, tuple): exc_info = sys.exc_info() record = self.makeRecord(self.name, level, fn, lno, msg, args, - exc_info, func, extra, sinfo) + exc_info, func, extra, sinfo, **kwargs) self.handle(record) def handle(self, record): diff -r 9485165435e4 Lib/test/test_logging.py --- a/Lib/test/test_logging.py Wed Sep 28 23:17:12 2016 -0700 +++ b/Lib/test/test_logging.py Thu Sep 29 17:01:11 2016 +0100 @@ -4297,6 +4297,29 @@ msg = 'Record not found in event log, went back %d records' % GO_BACK self.assertTrue(found, msg=msg) +class RecordKwargTest(BaseTest): + """Test to check arbitrary kwargs can be attached to record, can be used to filter record""" + def filterfunc(self, record): + return record.kwargs.get('fish') + + def test_record_kwargs_filterable(self): + handler = self.root_logger.handlers[0] + try: + handler.addFilter(self.filterfunc) + spam = logging.getLogger("spam") + spam_eggs = logging.getLogger("spam.eggs") + + spam.info(self.next_message(), fish=True) + spam_eggs.info(self.next_message(), fish=True) + spam.info(self.next_message(), ) + spam_eggs.info(self.next_message()) + + self.assert_log_lines([ + ('spam', 'INFO', '1'), + ('spam.eggs', 'INFO', '2'), + ]) + finally: + handler.removeFilter(self.filterfunc) class MiscTestCase(unittest.TestCase): def test__all__(self):