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

Python日志记录:时间格式使用毫秒,python,logging,time,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) 但是,没有指定如何格式化毫秒。我已经找到了微秒,但是a)我更喜欢毫秒,b)由于%f,以下内容在P

默认情况下,
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)
但是,没有指定如何格式化毫秒。我已经找到了微秒,但是a)我更喜欢毫秒,b)由于
%f
,以下内容在Python 2.6(我正在使用)上不起作用:

logging.Formatter(fmt='%(asctime)s',datefmt='%Y-%m-%d,%H:%M:%S.%f')
请注意,这显然更好。


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
来解决,因为
ct
time.struct\u time
并且这些对象不记录毫秒

如果我们更改
ct
的定义,使其成为
datetime
对象,而不是
struct\u time
,那么(至少在Python的现代版本中),我们可以调用
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
参数:

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

...
formatter = MyFormatter(fmt='%(asctime)s %(message)s')
...
logger.debug('Jackdaws love my big sphinx of quartz.')
# 2011-06-09 08:14:38.343 Jackdaws love my big sphinx of quartz.
这也应该起作用:

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

实例化
格式化程序后
我通常设置
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

我发现最简单的方法是覆盖默认的_msec_格式:

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

一个简单的扩展不需要
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
如果您正在使用或不介意使用箭头。可以用python的时间格式替换arrow的时间格式

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
属性中使用所有属性。

添加毫秒是更好的选择,谢谢。 下面是我在Blender中使用Python3.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")

到目前为止,以下内容可以完美地与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信息


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

不要使用类似“%Y-%m-%d%H:%m:%S.%03d%z”的内容,而是按照@unutbu的指示创建自己的类。以下是一个iso日期格式:

导入日志
从时间导入gmtime,strftime
类ISOFormatter(logging.Formatter):
def格式时间(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,记录毫秒,z)
返回s
logger=logging.getLogger(_名称__)
logger.setLevel(logging.DEBUG)
console=logging.StreamHandler()
logger.addHandler(控制台)
格式化程序=ISOFormatter(fmt='%(asctime)s-%(模块)s-%(levelname)s-%(消息)s')
console.setFormatter(格式化程序)
调试(‘寒鸦喜欢我的大石英狮身人面像’)
#2020-10-23T17:25:48.310-0800--调试-寒鸦喜欢我的石英大狮身人面像。

如果您喜欢使用
style='{'
fmt=“{asctime}.{msecs:0这里有许多过时的、过于复杂和奇怪的答案。原因是文档不充分,简单的解决方案是只使用
basicConfig()
,并将其设置如下:

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

logging.Formatter.formatTime = formatTime_RFC3339

logging.basicConfig(datefmt='%Y-%m-%d%H:%m:%S',format='{asctime}.{msecs:0我想出了一个两行程序,让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, r, _: datetime.datetime.fromtimestamp(r.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!

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

更改区域设置可能会有所帮助?@pajton-在下面的链接中,它说“asctime()不使用区域设置信息”-
%f
在python 2.7.9或3.5.1上不起作用。这里的对话很好。我来这里是因为
日志记录
声称其默认时间格式遵循ISO 8601。它不起作用。它使用空间,而不是“t”将时间和逗号分隔为小数点秒,而不是小数点。它们怎么会如此错误?因此%f实际上会给出微秒,而不是毫秒,对吗?@Jonathan:oops,你是对的,
%f
给出微秒。我想获得毫秒的最简单方法是将逗号更改为小数点(请参见上面的编辑)。事实上,我认为这是最好的答案,因为它使您能够立即使用标准格式选项。我实际上想要微秒,而这是唯一可以做到的选项!谢谢。这个答案提供了一个获取微秒的简单解决方案。谢谢:以下是这些的文档:…有没有办法仍然包括在Python日志(,->)中取消时区(%z)?…ISO8601格式时间太好了。这个解决方案是有缺陷的,因为如果您的
%z
%z
datefmt
中,您希望它出现在毫秒之后,而不是之前。此外,如果您使用的是12小时时钟,它具有
AM
PM
@wim,这是一种变通方法,但通过
日志记录使用UTC而不是本地时间.Formatter.converter=time.gmtime
则不需要使用
%z
%z
。或者,您也可以将
日志记录的
默认\u msec\u格式属性更改为%s、%03d%z或%s、%03d%Z@wim作为我之前评论的后续(无法再编辑…),以下是我所做的:
from time import gmtime
-
#使用UTC而不是本地日期/时间
-
logging.Formatter.converter=gmtime
-
logging.basicConfig(datefmt=%Y-%m-%dT%H:%m:%S',f