22

I am using python's logging module for logs, but needed the timestamp to include microsecond. It seems the timestamp can only get as precise as millisecond. Here's my test code

import logging

logging.basicConfig(format='%(asctime)s %(levelname)s {%(module)s} [%(funcName)s] %(message)s',

    datefmt='%Y-%m-%d,%H:%M:%S:%f', level=logging.INFO)

class log2_test():

    def test_class(self):

        logging.warning("Warning2 inside the class")

def get_started2():

    logging.info("Logged2 Here")

if __name__ == '__main__':
    get_started2()

Here's the output I get --

2015-07-09,16:36:37:f INFO {logger} [get_started2] Logged2 Here

Somehow, %f is not recognized. Python version is 2.7.6.

How do I get the timestamp to include microseconds? Thanks in advance.

Han Gu
  • 221
  • 1
  • 2
  • 3
  • @Vignesh Kalai "timestamp" is one word – TankorSmash Jul 09 '15 at 21:23
  • You should try googling 'logging datefmt', you would see this has already been extensively answered: http://stackoverflow.com/questions/6290739/python-logging-use-milliseconds-in-time-format – jonnybazookatone Jul 09 '15 at 23:27
  • The link @jonnybazookatone provided gave me the solution. Thanks – Han Gu Jul 10 '15 at 15:06
  • @HanGu Can you please post the solution you used here and mark it as answer? I am trying to get microseconds using formatter but couldn't get true microseconds with all 6 digits. For now I am using milliseconds in 6 digit form like this: `logging.Formatter('%(asctime)s.%(msecs)06d', datefmt='%Y-%m-%d %H:%M:%S')` If anyone else could post answer for getting true microseconds then it would be great as this question is showing up on google search for this topic. – 300 Nov 01 '21 at 18:16

7 Answers7

27

According to the documentation, strftime() does not support %f. The logger provides milliseconds as a separate msecs attribute, so you could just add it yourself after the existing timestamp as follows:

logging.basicConfig(format='%(asctime)s.%(msecs)03d %(levelname)s {%(module)s} [%(funcName)s] %(message)s', datefmt='%Y-%m-%d,%H:%M:%S', level=logging.INFO)

This gave me the following output using your script:

2015-07-10,09:21:16.841 INFO {test script} [get_started2] Logged2 Here
Josh Correia
  • 3,807
  • 3
  • 33
  • 50
Martin Evans
  • 45,791
  • 17
  • 81
  • 97
  • 4
    I actually need to get as precise as microsecond. – Han Gu Jul 10 '15 at 13:41
  • You would probably need to investigate sub classing and adding your own functionality. Being Python, I am not sure how precise the numbers would be. I seem to remember doing this for modifying the format. It seems to be a lot more flexible now though. – Martin Evans Jul 10 '15 at 13:45
  • Thanks Martin. I found the answer from a link someone provide in the comments above. In fact, it does involve sub classing the logging.formatter, and modifying the format. – Han Gu Jul 10 '15 at 15:08
7

I just ran into this issue - and it can be solved. It just requires a little hacking on some of the logging infrastructure. See below example:

import logging
import time

try: # Python >= 3.7
    from time import time_ns
except: # Python <= 3.6
    from time import time as _time_
    time_ns = lambda: int(_time_() * 1e9)

class LogRecord_ns(logging.LogRecord):
    def __init__(self, *args, **kwargs):
        self.created_ns = time_ns() # Fetch precise timestamp
        super().__init__(*args, **kwargs)

class Formatter_ns(logging.Formatter):
    default_nsec_format = '%s,%09d'
    def formatTime(self, record, datefmt=None):
        if datefmt is not None: # Do not handle custom formats here ...
            return super().formatTime(record, datefmt) # ... leave to original implementation
        ct = self.converter(record.created_ns / 1e9)
        t = time.strftime(self.default_time_format, ct)
        s = self.default_nsec_format % (t, record.created_ns - (record.created_ns // 10**9) * 10**9)
        return s

logging.setLogRecordFactory(LogRecord_ns)

# +++++ DEMO +++++

log_formater = Formatter_ns('%(asctime)s (%(name)s) %(message)s')

logger = logging.getLogger('demo-log')
logger.setLevel(logging.DEBUG)

ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)
ch.setFormatter(log_formater)
logger.addHandler(ch)

logger.info('foo bar')

This will happily print: 2019-04-10 14:08:28,819931368 (demo-log) foo bar

Key to this is a modified logging.Formatter class, which has a custom implementation of formatTime. Just to be on the safe side, I also recommend to use time.time_ns, which will return an integer in nano seconds in Python 3.7 and beyond. The original time.time returns a float in seconds, which therefore obviously has precision issues. Getting the more precise timestamp into a log record is achieved through a modified logging.LogRecord class, which simply fetches its created_ns field from time.time_ns in its extended constructor method.

s-m-e
  • 3,433
  • 2
  • 34
  • 71
  • > `time.time` has precision issues. Any examples? – Smart Manoj May 09 '22 at 11:37
  • 2
    @SmartManoj Take current Unix time (in seconds) as a double precision (64 bit) floating point number - it will cut off the last two digits (nano seconds and tens of nanoseconds) because of the limitation of the data type and only leave hundreds of nano seconds (rounded). The further you get away from the epoch, 1970, the more digits are cut off this way. – s-m-e May 09 '22 at 13:48
3

I didnt find a easy way to print out microsecond,but %(created).6f could be a temp solution, which will be the result of time.time(),like 1517080746.007748.

Didnt find a way to remove unnecessary part, so if you really need microsecond, but dont want to change your code too much, one easy way will be

logging.basicConfig(level=logging.INFO,format="%(asctime)s.%(msecs)03d[%(levelname)-8s]:%(created).6f %(message)s", datefmt="%Y-%m-%d %H:%M:%S")

It will give you below output,

2018-01-28 04:19:06.807[INFO    ]:1517080746.807794 buy order issued
2018-01-28 04:19:07.007[INFO    ]:1517080747.007806 buy order issued
2018-01-28 04:19:07.207[INFO    ]:1517080747.207817 buy order issued
2018-01-28 04:19:07.407[INFO    ]:1517080747.407829 buy order issued
2018-01-28 04:19:07.607[INFO    ]:1517080747.607840 buy order issued
1

Just completing @Luo_Hongshuai answer for python 3.7 :

format=%(asctime)s.%(msecs)06f
datefmt=%Y-%m-%d %H:%M:%S
John Doe
  • 1,570
  • 3
  • 13
  • 22
  • 1
    This gives me `260.363817` (i.e. 260 point 363817 milliseconds), any way of dropping the `.`? – mkst Jul 21 '20 at 11:21
  • 1
    Yes, here: https://stackoverflow.com/questions/6290739/python-logging-use-milliseconds-in-time-format/7517430#7517430 – bene Aug 19 '20 at 12:48
  • I need a timestamp in seconds from some fixed reference. Number of seconds since the programn started would be great, but any fixed point in the past would be fine, – lrhorer Feb 09 '21 at 21:53
1

one-liner monkey patch for logging.Formatter.formatTime:

logging.Formatter.formatTime = lambda self, record, datefmt=None: datetime.datetime.utcfromtimestamp(record.created).isoformat(sep='_', timespec='microseconds')
user0
  • 138
  • 1
  • 2
  • 6
0
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.

Source

Smart Manoj
  • 5,230
  • 4
  • 34
  • 59
-1

I have same question: Using logging.Formatter need timestamp in micro seconds with exact 6 digits. Something like: 2021-11-02 15:21:12.891531

After goin through the answers and checking out the other SO links mentioned here I couldn't find a way to get timestamp in this format. Does anyone know how to get timestamp in 2021-11-02 15:21:12.891531 format?

I have tried following and the comment next to each line in code is what that line prints as date.

  1 #!/bla/bla/bla/bin/python
  2
  3 import logging
  4
  5 logger = logging.getLogger(__name__)
  6 l_level = 'INFO'
  7 l_level = eval("logging." + l_level.upper())
  8 logger.setLevel(l_level)
  9
 10 handler = logging.StreamHandler()
 11 handler.setLevel(l_level)
 12
 13 #formatter = logging.Formatter('%(asctime)s|%(message)s', datefmt="%Y-%m-%d %H:%M:%S.%s") # 2021-11-02 15:12:59.1635880379
 14 #formatter = logging.Formatter('%(asctime)s.%(msecs)06d|%(message)s', datefmt="%Y-%m-%d %H:%M:%S") # 2021-11-02 15:11:50.000952
 15 #formatter = logging.Formatter('%(asctime)s.%(msecs)03d|%(message)s', datefmt="%Y-%m-%d %H:%M:%S") # 2021-11-02 15:12:10.633
 16 formatter = logging.Formatter('%(asctime)s.%(msecs)06f', datefmt="%Y-%m-%d %H:%M:%S") # 2021-11-02 15:18:04.274.372101
 17 handler.setFormatter(formatter)
 18 logger.addHandler(handler)
 19
 20 logger.info("")

I'll add more ways here if I find new options.

300
  • 965
  • 1
  • 14
  • 53