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


163

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

但是,文档未指定如何设置毫秒格式。我发现这太问题,其中约微秒的会谈,但)我宁愿毫秒和b)下列不上的Python 2.6(其中我的工作),由于工作的关系%f

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

1
也许更改语言环境可能会有所帮助?
pajton 2011年

1
@ pajton-在以下链接中显示“ asctime()未使用语言环境信息” -docs.python.org/library/time.html#time.asctime
Jonathan

%f有关python 2.7.9或3.5.1不工作,要么
安东尼Hatchkins

4
在这里好聊。我来这里是因为logging声称其默认时间格式遵循ISO 8601。它使用空格(而不是“ T”)将时间和逗号分隔为小数秒,而不是小数点。他们怎么会错呢?
LS

Answers:


76

请注意,克雷格·麦克丹尼尔(Craig McDaniel)的解决方案显然更好。


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"。不能通过指定a来解决此问题,datefmt因为cta是,time.struct_time并且这些对象不记录毫秒。

如果我们更改的定义ct以使其成为datetime对象而不是struct_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.

1
所以%f实际上会给出微秒而不是毫秒,对吗?
乔纳森

@乔纳森:哎呀,你是对的,%f给出了微秒。我想获得毫秒的最简单方法是将逗号更改为小数点(请参见上面的编辑)。
unutbu 2011年

3
实际上,我认为这是最好的答案,因为它使您重新使用了STANDARD格式选项。我实际上想要微秒,这是唯一可以做到的方法!
trumpetlicks

谢谢。这个答案提供了一个获得微秒的简单解决方案。
永威武

336

这也应该工作:

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

12
谢谢:这是这些文档:docs.python.org/2/library/logging.html#logrecord-attributes docs.python.org/3/library/logging.html#logrecord-attributes ..有没有办法还包括时区(%z)?... Python日志中的ISO8601格式时间(,->。)会很棒。
Wes Turner 2015年

19
该解决方案是个残疾人,因为如果你%z%Zdatefmt想要的是出现在毫秒之后,而不是之前。
wim

1
而且,如果您使用的是12时制时钟,AM或具有PM
DollarAkshay

1
(再不能编辑...)@wim作为后续行动,以我以前的评论,这里是我做了什么: from time import gmtime- # Use UTC rather than local date/time- logging.Formatter.converter = gmtime-logging.basicConfig(datefmt='%Y-%m-%dT%H:%M:%S', format='%(name)s | %(asctime)s.%(msecs)03dZ | %(message)s', level=log_level)
马克

1
@Mark您无法将时区嵌入default_msec_format(从Python 3.7开始),因为仅替换了时间和毫秒。来自logging源:self.default_msec_format % (t, record.msecs)
M. Dudley

27

添加毫秒是更好的选择,谢谢。这是我在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")

1
到目前为止,最简单,最干净的选择。不确定何时可以只调用logging.info(msg)等获取记录器,但是格式正是我想要的。寻找所有可用属性的其他人可以在这里查看:docs.python.org/3.6/library/logging.html#logrecord-attributes
naphier

嗯,有趣的一点,感谢您的评论,这肯定是值得深思的。是的,我可能只是将它添加为那里正在发生的事情的一课,并确保它在那里,因为我已经问了很多事情,所以不需要多次调用父对象(通过'。')来获取它。如果您再次调用.info或.debug,我可能会再次直接保存这些,因为您建议保存参考查找周期。[let info = logging.info]
大师詹姆斯(James)

感谢您说杰森。有时,有一种更简单的方法来观察世界,不要害怕在很多(如果没有)/每种情况下都试图发现真相。
大师詹姆斯

15

我发现的最简单的方法是覆盖default_msec_format:

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

1
有趣,谢谢。但这在Python 2.7中对我不起作用。对于x的某些值,它可能仅在Python 3.x中工作。
nealmcb

1
@nealmcb,直到文档
Mark

3

实例化后,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

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

1

如果您使用箭头,或者您不介意使用箭头。您可以将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


-1

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

datefmt:'%Y-%m-%d%H:%M:%S.%03d%z'


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


1
这是行不通的。%d正在打印日期。在您的示例中,日期印有日期前面的0。
Klik
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.