Python logging: use milliseconds in time format

127,778

Solution 1

This should work too:

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

Solution 2

Please note Craig McDaniel's solution is clearly better.


logging.Formatter's formatTime method looks like this:

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

Notice the comma in "%s,%03d". This can not be fixed by specifying a datefmt because ct is a time.struct_time and these objects do not record milliseconds.

If we change the definition of ct to make it a datetime object instead of a struct_time, then (at least with modern versions of Python) we can call ct.strftime and then we can use %f to format microseconds:

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.

Or, to get milliseconds, change the comma to a decimal point, and omit the datefmt argument:

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.

Solution 3

Adding msecs was the better option, Thanks. Here is my amendment using this with Python 3.5.3 in Blender

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")

Solution 4

The simplest way I found was to override default_msec_format:

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

Solution 5

Many outdated, over-complicated and weird answers here. The reason is that the documentation is inadequate and the simple solution is to just use basicConfig() and set it as follows:

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

The trick here was that you have to also set the datefmt argument, as the default messes it up and is not what is (currently) shown in the how-to python docs. So rather look here.


An alternative and possibly cleaner way, would have been to override the default_msec_format variable with:

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

However, that did not work for unknown reasons.

PS. I am using Python 3.8.

Share:
127,778

Related videos on Youtube

Jonathan Livni
Author by

Jonathan Livni

python, django, C++ and other vegetables...

Updated on August 10, 2021

Comments

  • Jonathan Livni
    Jonathan Livni over 2 years

    By default logging.Formatter('%(asctime)s') prints with the following format:

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

    where 638 is the millisecond. I need to change the comma to a dot:

    2011-06-09 10:54:40.638
    

    To format the time I can use:

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

    however the documentation doesn't specify how to format milliseconds. I've found this SO question which talks about microseconds, but a) I would prefer milliseconds and b) the following doesn't work on Python 2.6 (which I'm working on) due to the %f:

    logging.Formatter(fmt='%(asctime)s',datefmt='%Y-%m-%d,%H:%M:%S.%f')
    
    • Mr. Lance E Sloan
      Mr. Lance E Sloan over 7 years
      Good conversation here. I came here because logging claims its default time format follows ISO 8601. It doesn't. It uses space, not "T" to separate time and comma for fractional seconds, not decimal point. How could they be so wrong?
  • Josh Correia
    Josh Correia over 3 years
    %03d prints the date, not milliseconds.
  • Jeff Bryner
    Jeff Bryner over 3 years
    %03d is (was, see below) a string format modifier in this context for the milliseconds rather than a dateformat component as noted here: docs.python.org/3/library/… However this is mute, because this modifier apparently no longer works after 3.7 according to stackoverflow.com/questions/6290739/…
  • Jeff Bryner
    Jeff Bryner over 3 years
    updated the answer to be currently accurate using @unutbu 's starting point
  • not2qubit
    not2qubit over 3 years
    This just tacks on the ,nnn formatting (to %S part) when used in logger.Formatter(). So it need to be used in the basicConfig(datefmt=..., format=..., style='{').
  • mike rodent
    mike rodent about 3 years
    Not sure that either of your solutions works.
  • not2qubit
    not2qubit about 3 years
    @mikerodent Like I said, the first one I used and worked for me, the seconds was found in documentation and did not work. So if you're "not sure", what are you actually saying?
  • Bosco Domingo
    Bosco Domingo almost 3 years
    Doesn't print timezone, so it's not ISO8601 I'm afraid, but it works if you only need the milliseconds
  • not2qubit
    not2qubit about 2 years
    @BoscoDomingo You can adjust the datefmt string to whatever you want/need to also include TZ in ISO-8601 time format.

Related