Skip to content

Instantly share code, notes, and snippets.

@sloanlance
Last active November 25, 2021 03:28
Show Gist options
  • Save sloanlance/c8afc5da9847597bb54b52b9904994ba to your computer and use it in GitHub Desktop.
Save sloanlance/c8afc5da9847597bb54b52b9904994ba to your computer and use it in GitHub Desktop.
Python: A logging Formatter class giving timestamps in a more common ISO 8601 format.
class Iso8601UTCTimeFormatter(logging.Formatter):
"""
A logging Formatter class giving timestamps in a more common ISO 8601 format.
The default logging.Formatter class **claims** to give timestamps in ISO 8601 format
if it is not initialized with a different timestamp format string. However, its
format, "YYYY-MM-DD hh:mm:ss,sss", is much less common than, "YYYY-MM-DDThh:mm:ss.sss".
That is, the separator between date and time is a space instead of the letter "T"
and the separator for fractional seconds is a comma instead of a period (full stop).
While these differences may not be strictly *wrong*, it makes the formatted timestamp
*unusual*.
This formatter class removes some of the differences by using Python's own
datetime.datetime.isoformat() method. That method uses "T" as the default separator
between date and time. And it always uses a period (full stop) for fractional
seconds, even if a comma is normally used for fractional numbers in the current
locale.
This class also assumes the timestamp should use the UTC timezone.
"""
def __init__(self, logFormat=None, timeFormat=None):
"""
The purpose of this constructor is to set the timezone to UTC for later use.
:param logFormat: Log record formatting string.
:type logFormat: str
:param timeFormat: Time formatting string. You probably **DO NOT** want one.
:type timeFormat: str
"""
super(Iso8601UTCTimeFormatter, self).__init__(logFormat, timeFormat)
from dateutil.tz import tzutc
self._TIMEZONE_UTC = tzutc()
def formatTime(self, record, timeFormat=None):
"""
In the event that a timeFormat string is given, this method will use the
formatTime() method of the superclass (logging.Formatter) instead. That's
because this method doesn't need timeFormat. So, other than this solution,
the options for handling that argument were to ignore it or raise an exception,
either of which probably violate the principle of least astonishment (POLA).
:param record: Record of the current log entry
:type record: logging.LogRecord
:param timeFormat: Time formatting string. You probably **DO NOT** want one.
:type timeFormat: str
:return: Log record's timestamp in ISO 8601 format
:rtype: str or unicode
"""
if timeFormat is not None:
return super(Iso8601UTCTimeFormatter, self).formatTime(record, timeFormat)
return datetime.datetime.fromtimestamp(record.created, self._TIMEZONE_UTC).isoformat()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment