TLDR: Although it's not what the OP asked for, if you want to print all log timestamps as ISO8601 with milliseconds and UTC offset you can overwrite the default formatter formatTime like this:
import logging from datetime import datetime def formatTime(self, record, datefmt=None): return datetime.fromtimestamp(record.created).astimezone().isoformat(timespec='milliseconds') logging.Formatter.formatTime = formatTime
produces logs like this
2024-01-15T19:23:01.371+01:00 INFO __main__ test 1
The %(asctime)s is formatted through logging.Formatter.formatTime(self, record), the documentation states that formatTime will use time.strftime() which is not the same as datetime.strftime(). time.strftime has no way of printing milliseconds , datetime.strftime() on the other hand has %f. So you can't use %f on the datefmt.
If you only need to change the , (comma) to a . (dot) you have the simple options from other answers combining %(asctime)s, and %(msecs)03d like so (using logging.config.dictConfig() and a YAML file)
# log_config.yml version: 1 formatters: default: format: "%(asctime)s.%(msecs)03d %(levelname)-8s %(name)-15s %(message)s" datefmt: "%Y-%m-%d %H:%M:%S"
But that will not work if you need to add the UTC offset /timezone after the milliseconds, for example.
In order to have a more sensible timestamp formatting you can implement your own formatter that subclasses logging.Formatter and just override formatTime. For example, the following formatter will produce logs with timestamps in ISO8601 including milliseconds and UTC offset by using datetime.isoformat():
# myformatter.py import logging from datetime import datetime class CustomFormatter(logging.Formatter): def formatTime(self, record, datefmt=None): return datetime.fromtimestamp(record.created).astimezone().isoformat(timespec='milliseconds')
In the code above
# log_config.yml version: 1 formatters: default: class: myformatter.CustomFormatter format: "%(asctime)s %(levelname)-8s %(name)-15s %(message)s" handlers: console: class: logging.StreamHandler stream: ext://sys.stdout formatter: default loggers: root: level: INFO handlers: [console]
The above configuration results in :
2024-01-15T18:40:42.006307+01:00 INFO __main__ test 1
where %(asctime)s value comes from CustomFormatter.formatTime()
Ultimately you can replace the logging.Formatter.formatTime with your own implementation instead of creating a new formatter:
import logging import logging.config import yaml from datetime import datetime def formatTime(self, record, datefmt=None): return datetime.fromtimestamp(record.created).astimezone().isoformat(timespec='milliseconds') logging.Formatter.formatTime = formatTime # no need for a custom formatter if we monkeypatch the default formatter with open("log_config.yml", "rt") as f: logging.config.dictConfig(yaml.safe_load(f.read())) logger = logging.getLogger(__name__) # __name__ myvar = 1 logger.info("test %s", myvar)
%fdoesn't work on python 2.7.9 or 3.5.1 eitherloggingclaims 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?