Python日志记录:以时间格式使用毫秒

时间:2011-06-09 09:30:08

标签: python logging time

默认情况下,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)

但是documentation没有指定如何格式化毫秒。我发现this SO question谈到了微秒,但是a)我更喜欢毫秒而且b)由于%f,以下内容对Python 2.6(我正在研究)不起作用:

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

13 个答案:

答案 0 :(得分:266)

这也应该有效:

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

答案 1 :(得分:63)

请注意Craig McDaniel's solution显然更好。


logging.Formatter的formatTime方法如下所示:

def formatTime(self, record, datefmt=None):
    ct = self.converter(record.created)
    if datefmt:
        s = time.strftime(datefmt, ct)
    else:
        t = time.strftime("%Y-%m-%d %H:%M:%S", ct)
        s = "%s,%03d" % (t, record.msecs)
    return s

注意"%s,%03d"中的逗号。这不能通过指定datefmt来修复,因为cttime.struct_time,并且这些对象不记录毫秒。

如果我们更改ct的定义以使其成为datetime对象而不是struct_time,那么(至少在现代版本的Python中)我们可以调用{{1}然后我们可以使用ct.strftime格式化微秒:

%f

或者,要获得毫秒,请将逗号更改为小数点,并省略import logging import datetime as dt class MyFormatter(logging.Formatter): converter=dt.datetime.fromtimestamp def formatTime(self, record, datefmt=None): ct = self.converter(record.created) if datefmt: s = ct.strftime(datefmt) else: t = ct.strftime("%Y-%m-%d %H:%M:%S") s = "%s,%03d" % (t, record.msecs) return s logger = logging.getLogger(__name__) logger.setLevel(logging.DEBUG) console = logging.StreamHandler() logger.addHandler(console) formatter = MyFormatter(fmt='%(asctime)s %(message)s',datefmt='%Y-%m-%d,%H:%M:%S.%f') console.setFormatter(formatter) logger.debug('Jackdaws love my big sphinx of quartz.') # 2011-06-09,07:12:36.553554 Jackdaws love my big sphinx of quartz. 参数:

datefmt

答案 2 :(得分:11)

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

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

答案 3 :(得分:11)

添加msecs是更好的选择,谢谢。 以下是我在Blender中使用Python 3.5.3的修正案

import logging
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s.%(msecs)03d %(levelname)s:\t%(message)s', datefmt='%Y-%m-%d %H:%M:%S')
log = logging.getLogger(__name__)
log.info("Logging Info")
log.debug("Logging Debug")

答案 4 :(得分:4)

实例化Formatter后,我通常设置formatter.converter = gmtime。因此,为了让@unutbu的答案在这种情况下起作用,你需要:

class MyFormatter(logging.Formatter):
    def formatTime(self, record, datefmt=None):
        ct = self.converter(record.created)
        if datefmt:
            s = time.strftime(datefmt, ct)
        else:
            t = time.strftime("%Y-%m-%d %H:%M:%S", ct)
            s = "%s.%03d" % (t, record.msecs)
        return s

答案 5 :(得分:4)

这里有许多过时、过于复杂和奇怪的答案。原因是文档不够,简单的解决办法就是直接使用basicConfig(),设置如下:

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

这里的诀窍是您还必须设置 datefmt 参数,因为默认会把它搞砸而不是 > how-to python docs 中显示的内容(当前)。所以不如看看here


另一种可能更简洁的方法是使用以下命令覆盖 default_msec_format 变量:

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

但是,由于未知原因,这不起作用

附注。我使用的是 Python 3.8。

答案 6 :(得分:2)

一个简单的扩展不需要datetime模块,并且不像其他一些解决方案那样具有障碍,就是使用简单的字符串替换:

import logging
import time

class MyFormatter(logging.Formatter):
    def formatTime(self, record, datefmt=None):
    ct = self.converter(record.created)
    if datefmt:
        if "%F" in datefmt:
            msec = "%03d" % record.msecs
            datefmt = datefmt.replace("%F", msec)
        s = time.strftime(datefmt, ct)
    else:
        t = time.strftime("%Y-%m-%d %H:%M:%S", ct)
        s = "%s,%03d" % (t, record.msecs)
    return s

通过这种方式,可以使用%F毫秒来编写日期格式,甚至可以编写区域差异。例如:

log = logging.getLogger(__name__)
log.setLevel(logging.INFO)

sh = logging.StreamHandler()
log.addHandler(sh)

fm = MyFormatter(fmt='%(asctime)s-%(levelname)s-%(message)s',datefmt='%H:%M:%S.%F')
sh.setFormatter(fm)

log.info("Foo, Bar, Baz")
# 03:26:33.757-INFO-Foo, Bar, Baz

答案 7 :(得分:1)

如果您使用的是arrow,或者您不介意使用箭头。你可以用python的时间格式代替箭头的那个。

import logging

from arrow.arrow import Arrow


class ArrowTimeFormatter(logging.Formatter):

    def formatTime(self, record, datefmt=None):
        arrow_time = Arrow.fromtimestamp(record.created)

        if datefmt:
            arrow_time = arrow_time.format(datefmt)

        return str(arrow_time)


logger = logging.getLogger(__name__)

default_handler = logging.StreamHandler()
default_handler.setFormatter(ArrowTimeFormatter(
    fmt='%(asctime)s',
    datefmt='YYYY-MM-DD HH:mm:ss.SSS'
))

logger.setLevel(logging.DEBUG)
logger.addHandler(default_handler)

现在,您可以使用datefmt属性中的所有arrow's time formatting

答案 8 :(得分:1)

我想出了一个两行代码来让 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: 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

答案 9 :(得分:1)

在消耗了我一些宝贵的时间之后,下面的 hack 对我有用。我刚刚在 todolist_id 中更新了我的格式化程序并将 settings.py 添加为 datefmt 并将毫秒附加到 asctime 像这样 %y/%b/%Y %H:%M:%S

例如:

{asctime}.{msecs:0<3.0f}

答案 10 :(得分:0)

如果您更喜欢使用style='{'fmt="{asctime}.{msecs:0<3.0f}"会将您的微秒0填充到三个位置以保持一致性。

答案 11 :(得分:-2)

tl; dr适用于在此处查找ISO格式日期的人们:

不要使用类似'%Y-%m-%d%H:%M:%S.%03d%z'之类的东西,而是按照@unutbu所示创建自己的类。这是iso日期格式的一种:

import logging
from time import gmtime, strftime

class ISOFormatter(logging.Formatter):
    def formatTime(self, record, datefmt=None):
        t = strftime("%Y-%m-%dT%H:%M:%S", gmtime(record.created))
        z = strftime("%z",gmtime(record.created))
        s = "%s.%03d%s" % (t, record.msecs,z)        
        return s

logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)

console = logging.StreamHandler()
logger.addHandler(console)

formatter = ISOFormatter(fmt='%(asctime)s - %(module)s - %(levelname)s - %(message)s')
console.setFormatter(formatter)

logger.debug('Jackdaws love my big sphinx of quartz.')
#2020-10-23T17:25:48.310-0800 - <stdin> - DEBUG - Jackdaws love my big sphinx of quartz.

答案 12 :(得分:-3)

截至目前,以下代码可与python 3完美配合。

         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信息