默认情况下logging.Formatter('%(asctime)s')打印如下格式:

2011-06-09 10:54:40,638

638是毫秒。我需要把逗号换成一个点:

2011-06-09 10:54:40.638

格式化我可以使用的时间:

logging.Formatter(fmt='%(asctime)s',datestr=date_format_str)

但是,文档没有指定如何格式化毫秒。我发现了这个SO问题,它谈论的是微秒,但是a)我更喜欢毫秒,b)由于%f,下面的问题在Python 2.6(我正在工作)上不起作用:

logging.Formatter(fmt='%(asctime)s',datefmt='%Y-%m-%d,%H:%M:%S.%f')

当前回答

在消耗了我宝贵的时间之后,下面的方法对我有用。我刚刚在settings.py中更新了我的格式化程序,并将datefmt添加为%y/%b/% y %H:%M:%S,并将毫秒追加到asctime,如{asctime}.{msecs:0<3.0f}

E.G:

    'formatters': {
        'verbose': {
            'format': '[{asctime}.{msecs:0<3.0f}] {levelname} [{threadName:s}] {module} → {message}',
            'datefmt': "%y/%b/%Y %H:%M:%S",
            'style': '{',
        },
    }

其他回答

这里有许多过时的、过于复杂和奇怪的答案。原因是文档是不充分的,简单的解决方案是使用basicConfig(),并设置如下:

logging.basicConfig(datefmt='%Y-%m-%d %H:%M:%S', format='{asctime}.{msecs:0<3.0f} {name} {threadName} {levelname}: {message}', style='{')

这里的技巧是,你还必须设置datefmt参数,因为默认的参数会把它弄乱,并且不是(目前)在python指南文档中显示的内容。所以还是看这里吧。


另一种可能更干净的方法是覆盖default_msec_format变量:

formatter = logging.Formatter('%(asctime)s')
formatter.default_msec_format = '%s.%03d'

然而,由于未知的原因,这并没有起作用。

PS.我使用的是Python 3.8。

使用这个智能答案的时区和选择的答案,你可以用你想要的格式构建毫秒和时区:

import logging
import time

if __name__ == "__main__":
    tz = time.strftime('%z')
    logging.basicConfig(
        format=(
            "%(asctime)s.%(msecs)03d" + tz + " %(levelname)s "
            "%(pathname)s:%(lineno)d[%(threadName)s]: %(message)s"
        ),
        level=logging.DEBUG,
        datefmt="%Y-%m-%dT%H:%M:%S",
    )
    logging.info("log example")

就我个人而言,我喜欢以UTC格式保存所有日志,但在日志中显式地将其作为没有时区的datetime,这在多区域应用程序中是没有意义的:

    logging.Formatter.converter = time.gmtime
    logging.basicConfig(
        format=(
            "%(asctime)s.%(msecs)03d+0000 %(levelname)s "
            "%(pathname)s:%(lineno)d[%(threadName)s]: %(message)s"
        ),
        level=logging.DEBUG,
        datefmt="%Y-%m-%dT%H:%M:%S",
    )

我找到的最简单的方法是覆盖default_msec_format:

formatter = logging.Formatter('%(asctime)s')
formatter.default_msec_format = '%s.%03d'

我想出了一个双行程序,让Python日志模块输出RFC 3339 (ISO 1801兼容)格式的时间戳,有正确格式化的毫秒和时区,并且没有外部依赖:

import datetime
import logging

# Output timestamp, as the default format string does not include it
logging.basicConfig(format="%(asctime)s: level=%(levelname)s module=%(module)s msg=%(message)s")

# Produce RFC 3339 timestamps
logging.Formatter.formatTime = (lambda self, record, datefmt=None: datetime.datetime.fromtimestamp(record.created, datetime.timezone.utc).astimezone().isoformat())

例子:

>>> logging.getLogger().error("Hello, world!")
2021-06-03T13:20:49.417084+02:00: level=ERROR module=<stdin> msg=Hello, world!

或者,最后一行可以写成这样:

def formatTime_RFC3339(self, record, datefmt=None):
    return (
        datetime.datetime.fromtimestamp(record.created, datetime.timezone.utc)
        .astimezone()
        .isoformat()
    )

logging.Formatter.formatTime = formatTime_RFC3339

该方法也可以用于特定的格式化程序实例,而不是在类级别上重写,在这种情况下,您将需要从方法签名中删除self。

到目前为止,下面的代码与python3完全兼容。

         logging.basicConfig(level=logging.DEBUG,
                     format='%(asctime)s %(levelname)-8s %(message)s',
                     datefmt='%Y/%m/%d %H:%M:%S.%03d',
                     filename=self.log_filepath,
                     filemode='w')

给出以下输出

2020/01/11 18:51:19.011信息