I would like to log info and warning level to stdout and error level and above to stderr how can I do it ?
code:
import os import subprocess from typing import Union import logging import yaml import logging.config with open("logging.conf", "r") as f: config = yaml.safe_load(f.read()) logging.config.dictConfig(config) logger = logging.getLogger(__name__) def run( cmd: Union[str, list[str]], *, cwd: Union[str, os.PathLike[str], None] = None, shell: bool = False, check: bool = True, capture_output: bool = True, text: bool = True, ) -> subprocess.CompletedProcess[str]: logger.info("start run!!") return subprocess.run(cmd, check=True, capture_output=capture_output, text=text) cmd = ["lxs"] def main(): try: output = run(cmd) except Exception as e: logger.error(e, exc_info=False) main()
logging.conf
version: 1 formatters: simple: format: '%(asctime)s - %(name)s - %(levelname)s - %(message)s' handlers: outconsole: class: logging.StreamHandler level: INFO formatter: simple stream: ext://sys.stdout errconsole: class: logging.StreamHandler level: WARNING formatter: simple stream: ext://sys.stderr file_handler: class: logging.FileHandler level: INFO formatter: simple filename: info.log encoding: utf8 mode: w loggers: sampleLogger: level: DEBUG handlers: [file_handler] propagate: no root: level: INFO handlers: [errconsole, outconsole, file_handler] propagate: no
and output after python3 -m tests 1> output.log 2> err.log
:
err.log
2022-10-14 14:34:02,354 - __main__ - ERROR - [Errno 2] No such file or directory: 'lxs'
output.log
2022-10-14 14:34:02,353 - __main__ - INFO - start run!! 2022-10-14 14:34:02,354 - __main__ - ERROR - [Errno 2] No such file or directory: 'lxs'
Consequently, the output on the console is:
2022-10-14 14:48:33,178 - __main__ - INFO - start run!! 2022-10-14 14:48:33,179 - __main__ - ERROR - [Errno 2] No such file or directory: 'lxs' 2022-10-14 14:48:33,179 - __main__ - ERROR - [Errno 2] No such file or directory: 'lxs'
My question is how to make the message not repeat itself ? I want ERROR on strerr and INFO on stdout.
Advertisement
Answer
Because of the way levels work in logging
, if you want to restrict stdout
to WARNING
and below and restrict stderr
to ERROR
and above, you’ll need to employ filters in the solution. One way of doing it is as follows.
First, add a filters
entry parallel to formatters
and handlers
, to define a couple of filters:
filters: warnings_and_below: "()": __main__.filter_maker level: WARNING sense: below errors_and_above: "()": __main__.filter_maker level: ERROR sense: above
and refer to them in the handler configurations:
filters: [warnings_and_below] # for outconsole
and
filters: [errors_and_above] # for errconsole
Filters are just functions, and we’ll define filter_maker
as follows:
def filter_maker(level, sense): level = getattr(logging, level) # get the actual numeric value from the string if sense == 'below': # return a function which only passes if level is at or below threshold def filter(record): return record.levelno <= level else: # return a function which only passes if level is at or above threshold def filter(record): return record.levelno >= level return filter
I’m using a small script and running it directly, and so the filter_maker
will be in the __main__
module (as indicated in the “()” lines above). You might need to change that to fit your specific situation.
Now, if I add some lines to log stuff:
logging.config.dictConfig(...) logging.debug('A DEBUG message') logging.info('An INFO message') logging.warning('A WARNING message') logging.error('An ERROR message') logging.critical('A CRITICAL message')
and suppose all this is in main.py
, then you can run
python main.py 2>stderr.log >stdout.log
and then you should see what’s expected:
$ more stdout.log 2022-10-14 16:41:09,867 - root - INFO - An INFO message 2022-10-14 16:41:09,867 - root - WARNING - A WARNING message $ more stderr.log 2022-10-14 16:41:09,868 - root - ERROR - An ERROR message 2022-10-14 16:41:09,868 - root - CRITICAL - A CRITICAL message $ more info.log 2022-10-14 16:41:09,867 - root - INFO - An INFO message 2022-10-14 16:41:09,867 - root - WARNING - A WARNING message 2022-10-14 16:41:09,868 - root - ERROR - An ERROR message 2022-10-14 16:41:09,868 - root - CRITICAL - A CRITICAL message