Хорошо, вот один способ, который дает мне ПОЧТИ то, что мне нужно.Подкласс LogRecord для перезаписи getMessage для вставки отступа и регистратора подкласса для makeRecord с ним:
import logging
import logging.config
################################################################################
class IndentingLogger(logging.Logger):
"""A Logger subclass to add indent on top of any logger output
"""
############################################################################
def __init__(self, name = 'root', logging_level = logging.NOTSET):
"Constructor to keep indent persistent"
logging.Logger.__init__(self, name, logging_level)
self.indenter = IndentedRecord("", logging.NOTSET, "", 0, None, None, None, None, None)
############################################################################
def makeRecord(self, name, level, fn, lno, msg, args, exc_info, func=None, extra=None):
return self.indenter.set_record(name, level, fn, lno, msg, args, exc_info, func, extra)
################################################################################
class IndentedRecord(logging.LogRecord):
"""A LogRecord subclass to add indent on top of any logger output
"""
######## Class data #########
DEFAULT_INDENT_STR = ' '
############################################################################
def __init__(self, name, level, fn, lno, msg, args, exc_info, func=None, extra=None):
"Constructor"
logging.LogRecord.__init__(self, name, level, fn, lno, msg, args, exc_info, func)
self._indent_level = 0
self._indent_str_base = IndentedRecord.DEFAULT_INDENT_STR
self._indent_str = "" # cache it
############################################################################
def set_record(self, name, level, fn, lno, msg, args, exc_info, func=None, extra=None):
"Constructs the base record"
logging.LogRecord.__init__(self, name, level, fn, lno, msg, args, exc_info, func)
return self
################################################################################
def getMessage(self):
"Adds indent on top of the normal getMessage result"
# Call base class to get the formatted message
message = logging.LogRecord.getMessage(self)
# Now insert the indent
return self._indent_str + message
################################################################################
def indent(self, step = 1):
"Change the current indent level by the step (use negative to decrease)"
self._indent_level += step
if self._indent_level < 0:
self._indent_level = 0
self._indent_str = self._indent_str_base * self._indent_level
################################################################################
def set_indent_str(self, chars):
"Change the current indent string"
if not isinstance(chars, str):
raise ValueError("Argument must be a string. Got %s" % chars)
self._indent_str_base = chars
logging.config.fileConfig("reporter.conf")
logging.setLoggerClass(IndentingLogger)
logger = logging.getLogger('root') # will be wrong logger, if without argument
logger.debug("debug message")
logger.info("info message")
logger.indenter.indent(+1)
logger.warn("Indented? warn message")
logger.indenter.set_indent_str("***")
logger.error("Indented? error message: %s", "Oops, I did it again!")
logger.indenter.indent(+1)
logger.error("Indented? error message: %s", "Oops, I did it again!")
logger.indenter.indent(-1)
logger.critical("No indent; critical message")
Результат (окрашен в реальности):
Debug: debug message
Info: info message
Warning: Indented? warn message
Error: Indented? error message: Oops, I did it again!
Error: ******Indented? error message: Oops, I did it again!
Internal Error: ***No indent; critical message
Каким-то образом строка уровня журнала все ещеподкрадывается к фронту, так что это не совсем то, что я хочу.Кроме того, это неудобно - слишком много для такой простой функции :(
Лучшие идеи?