Reputation: 10965
In Python logging, is there a way to set the width of two combined fields?
I'm looking to combine filenames and line numbers to produce output similar to:
2011-10-14 13:47:51 main.py:12 DEBUG - Initializing cluster
2011-10-14 13:47:51 cluster.py:364 DEBUG - Starting cluster
2011-10-14 13:47:51 cluster.py:98 INFO - Starting simulation
2011-10-14 13:47:51 simulation.py:79 DEBUG - Computing parameters
How would I modify the formatting string below, to achieve this?
logging.Formatter('%(asctime)s %(filename)s:%(lineno)s %(levelname)5s - %(msg)s
UPDATE:
As @jonrsharpe points out, no out-of-the-box way to do this, so have customize the formatting.
Solution: @alecxe recommends a custom Filter
, and here is a complete example:
import logging
import logging.config
class FilenameLinenoFilter(logging.Filter):
def filter(self, record):
record.filename_lineno = '{}:{}'.format(record.filename, record.lineno)
return True
LOG_SETTINGS = {
'version': 1,
'filters': {
'filename_lineno_filter': {
'()': FilenameLinenoFilter,
},
},
'formatters': {
'standard': {
'format': '%(asctime)s %(filename_lineno)-18s %(levelname)5s - %(msg)s',
},
},
'handlers': {
'default': {
'level': 'DEBUG',
'class': 'logging.StreamHandler',
'filters': ['filename_lineno_filter'],
'formatter': 'standard',
},
},
'loggers': {
'': {
'handlers': ['default'],
'level': 'DEBUG',
},
}
}
logging.config.dictConfig(LOG_SETTINGS)
logger = logging.getLogger()
logger.debug('Debug output goes here.')
logger.info('Informational goes here.')
Upvotes: 6
Views: 2194
Reputation: 3008
A Filter
is not the right tool for the job—filters are used to decide which log records get emitted and which are silenced, not to intercept log records just to "monkeypatch" them.
Rather, as of Python 3.2, you can use the logging.setRecordFactory
function to register a custom LogRecord
subclass or factory function to add a custom attribute to every LogRecord
:
import logging
class CustomLogRecord(logging.LogRecord):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.origin = f"{self.filename}:{self.lineno}"
You can then set the width of this combined field in the format string for your logger:
logging.setLogRecordFactory(CustomLogRecord)
logging.basicConfig(
style='{',
format="{asctime} {origin:20} {levelname} - {message}",
level=logging.INFO
)
logging.info("Test")
2020-06-26 16:10:03,193 scratch_2.py:16 INFO - Test
Upvotes: 6
Reputation: 473983
You can make a combined field with the help of a custom filter:
import logging
class MyFilter(logging.Filter):
def filter(self, record):
record.filename_lineno = "%s:%d" % (record.filename, record.lineno)
return True
Then, you can reference the %(filename_lineno)s
placeholder in the formatting string.
Upvotes: 5