Python日志字符串格式化

12 投票
3 回答
27012 浏览
提问于 2025-04-16 21:30

我正在使用Python的日志格式化工具来格式化日志记录,我有一个格式设置的值:

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

我希望"[file.py:20]"这个部分能扩展到10个字符宽(比如说)。如果只是一个值,那还简单,但有没有办法把整个结构扩展到指定的长度呢?我想要的效果是这样的:

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

我想知道是否可以通过字符串格式化来实现,或者有没有办法让Python的格式化工具以某种方式达到我想要的效果……

3 个回答

2

根据@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's 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
13

举个例子,这个格式化器会确保显示的内容宽度是固定的,格式是 "[%(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')

编辑:

如果你想确保显示的内容至少有10个字符宽,就不需要管文件名的部分了。

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

选项 1

可以从这里开始了解:http://docs.python.org/library/logging.html#formatter-objects

你需要创建一个自己的格式化器子类,也就是从 Formatter 这个类派生出来,给它一个独特的 format 方法。

然后,你必须在每个 Handlers 中调用 setFormatter(),这样它们才能使用你新创建的格式化器。

选项 2

创建一个自己的 LogRecord 子类,并添加额外的属性。

再从 Logger 这个类派生出一个子类,并重写 makeRecord 方法,以便创建你新的 LogRecord 子类。

提供一个自定义的格式,用来使用这个新属性的值。

撰写回答