Reputation: 1297
From what I read and understood, Python logging module by default logs to stderr.
If I run this python code:
import logging
logging.info('test')
logging.warning('test')
logging.error('test')
logging.debug('test')
as
python main.py 1> stdout.txt 2> stderr.txt
I get my logs in stderr.txt and nothing in stdout.txt - my logs are redirected to stderr.
This default behaviour is problematic when logs are streamed to logging aggregation services such as datadog or papertrail. Since its streamed to stderr, the logs are marked as errors when in reality they are not.
So I tried to create multiple log handlers as follows:
import logging
import sys
stdoutHandler = logging.StreamHandler(stream=sys.stdout)
stderrHandler = logging.StreamHandler(stream=sys.stderr)
logging.basicConfig(level=logging.DEBUG, handlers=[stdoutHandler, stderrHandler])
stdoutHandler.setLevel(logging.DEBUG)
stderrHandler.setLevel(logging.ERROR)
logging.info('test')
logging.warning('test')
logging.error('test')
logging.debug('test')
When I run this code, I get errors in sterr.txt but also all the logs in stdout.txt - I ended up having log duplication error logs appear in both the stderr and stdout streams.
Is there a better way to handle the differentiation of error logs from the rest in Python?
I tried loguru package as well, also no luck in stream separation... Thanks in advance
Upvotes: 0
Views: 377
Reputation: 1297
Following the approach described in the official documentation: https://docs.python.org/3.10/howto/logging-cookbook.html#custom-handling-of-levels
Here's my code with stream segregation:
import sys
import logging
class StdoutFilter(logging.Filter):
def filter(self, record):
return record.levelno >= ROOT_LEVEL and record.levelno < logging.ERROR
class StderrFilter(logging.Filter):
def filter(self, record):
return record.levelno >= logging.ERROR
stdoutHandler = logging.StreamHandler(stream=sys.stdout)
stdoutHandler.addFilter(StdoutFilter())
stderrHandler = logging.StreamHandler(stream=sys.stderr)
stderrHandler.addFilter(StderrFilter())
root_logger = logging.getLogger()
root_logger.setLevel(logging.DEBUG)
root_logger.addHandler(stderrHandler)
root_logger.addHandler(stdoutHandler)
Upvotes: 0
Reputation: 99415
You can probably benefit from the approach described here in the official documentation.
Upvotes: 1