Форматирование строки журнала python

Я использую журнал python formatter для форматирования записей журнала и я имеет значение fmt

fmt = "[%(filename)s:%(lineno)s] %(message)s"

Я бы хотел, чтобы "[file.py:20]" растягивался до 10 символов (например). Если бы это было одно значение, это было бы легко, но есть ли способ растянуть всю эту структуру до определенной длины? Мне нужно что-то вроде:

tmp = "[%(filename)s:%(lineno)s]"
fmt = "%(tmp)10s %(message)s"

Я хотел бы знать, возможно ли это, используя форматирование строк, или если я могу как-то обмануть форматировщик python, чтобы получить то, что я хочу.

Ответ 1

Вариант 1

Начните здесь: http://docs.python.org/library/logging.html#formatter-objects

Вы создадите свой собственный подклассом Formatter, который предоставит ему собственный уникальный метод format.

Затем вы должны обязательно позвонить setFormatter() в каждом из ваших Handlers, чтобы они использовали ваш новый форматтер.

Вариант 2

Создайте свой собственный подкласс LogRecord с дополнительным свойством.

Подкласс Logger и переопределить makeRecord, чтобы создать новый подкласс LogRecord.

Предоставить настраиваемый формат, который использует это новое значение свойства.

Ответ 2

В качестве примера этот Formatter обеспечивает фиксированную ширину "[%(filename)s:%(lineno)s]" путем обрезания имени файла или правого заполнения (после номера строки) с пробелами.

class MyFormatter(logging.Formatter):
    width = 10

    def format(self, record):
        max_filename_width = self.width - 3 - len(str(record.lineno))
        filename = record.filename
        if len(record.filename) > max_filename_width:
            filename = record.filename[:max_filename_width]
        a = "%s:%s" % (filename, record.lineno)
        return "[%s] %s" % (a.ljust(self.width), record.msg)

if __name__ == '__main__':
    logger = logging.getLogger('simple_example')
    logger.setLevel(logging.DEBUG)
    ch = logging.StreamHandler()
    ch.setLevel(logging.DEBUG)
    formatter = MyFormatter()
    ch.setFormatter(formatter)
    logger.addHandler(ch)

    logger.debug('No one expects the spammish repetition')

EDIT:

Если вы хотите обеспечить минимальную ширину в 10 символов, пропустите файл.

def format(self, record):
    a = "%s:%s" % (record.filename, record.lineno)
    return "[%s] %s" % (a.ljust(self.width), record.msg)

Ответ 3

Используя @rob-cowie ответ в качестве основы, я нашел следующее полезным:

class MyFormatter(logging.Formatter):
    width = 24
    datefmt='%Y-%m-%d %H:%M:%S'

    def format(self, record):
        cpath = '%s:%s:%s' % (record.module, record.funcName, record.lineno)
        cpath = cpath[-self.width:].ljust(self.width)
        record.message = record.getMessage()
        s = "%-7s %s %s : %s" % (record.levelname, self.formatTime(record, self.datefmt), cpath, record.getMessage())
        if record.exc_info:
            # Cache the traceback text to avoid converting it multiple times
            # (it constant anyway)
            if not record.exc_text:
                record.exc_text = self.formatException(record.exc_info)
        if record.exc_text:
            if s[-1:] != "\n":
                s = s + "\n"
            s = s + record.exc_text
        #if record.stack_info:
        #    if s[-1:] != "\n":
        #        s = s + "\n"
        #    s = s + self.formatStack(record.stack_info)
        return s

logFormatter = MyFormatter()
logger = logging.getLogger("example")
logger.setFormatter(logFormatter)

Что дает вывод, например:

WARNING 2014-03-28 16:05:09 module:function:31       : Message
WARNING 2014-03-28 16:05:09 dule:longerfunctions:140 : Message