35

Is it possible to have python logging messages which are INFO or DEBUG to go to stdout and WARNING or greater to go to stderr?

vvvvv
  • 25,404
  • 19
  • 49
  • 81
crosswired
  • 1,351
  • 2
  • 11
  • 12

2 Answers2

68

This seems to do what I want:

#!/usr/bin/python
import sys
import logging


class InfoFilter(logging.Filter):
    def filter(self, rec):
        return rec.levelno in (logging.DEBUG, logging.INFO)


logger = logging.getLogger("__name__")
logger.setLevel(logging.DEBUG)

h1 = logging.StreamHandler(sys.stdout)
h1.setLevel(logging.DEBUG)
h1.addFilter(InfoFilter())
h2 = logging.StreamHandler()
h2.setLevel(logging.WARNING)

logger.addHandler(h1)
logger.addHandler(h2)
Martin Thoma
  • 124,992
  • 159
  • 614
  • 958
crosswired
  • 1,351
  • 2
  • 11
  • 12
  • 27
    Creating a filter class is actually not necessary. You can also pass a callable: `h1.addFilter(lambda record: record.levelno <= logging.INFO)` – Schiavini Mar 13 '18 at 10:43
  • @Schiavini, for what it's worth, your modification doesn't seem to work in Python 2.7.15 - `logging/__init__.py:Filterer.filter()` raises an error: `AttributeError: 'function' object has no attribute 'filter'`. The code as-written does work in this version of Python. – davidA Apr 28 '19 at 23:54
  • 1
    I've only tested with python 3. That probably means you'll need the class as mentioned in the answer. – Schiavini Apr 29 '19 at 14:17
  • Side effect: consecutive log messages may get displayed in the wrong order (e.g. when combining stdout and stderr in the console). I guess this is due to the fact that both streams may use independent buffers. I couldn't find a way to fix this yet. – Johnson_145 Sep 24 '20 at 22:27
  • 2
    Typically, you would use `logger = logging.getLogger(__name__)` (without the quotation marks) to use the name of the module. – Tom Pohl Mar 31 '22 at 13:11
-2

I thought this would help: Handler.setLevel(lvl)

Sets the threshold for this handler to lvl. Logging messages which are less severe than lvl will be ignored. When a handler is created, the level is set to NOTSET (which causes all messages to be processed).

But now I see that it wouldn't do what you want (split INFO/DEBUG from WARNING/ERROR)

That being said, you could write a custom handler (a class extending logging.StreamHandler for example), and overwrite the Handler.handle() method.

E.Z.
  • 6,393
  • 11
  • 42
  • 69