UPDATE:
The original question seems invalid as even if I managed to force logger to use datetime.now()
, it still does not solve my ultimate goal of making the logging timestamps responsive to OS timezone changes without restarting the python interpreter. I have provided the answer I found below.
How to force the logger to use datetime.now()
instead of time.asctime()
? I need the log to follow strictly the Windows OS provided time, but time.asctime()
attempts to convert the timezone if it thinks is needed. How do I override this behaviour?
Currently i use a custom logging.format subclass with the format string '{asctime}: {levelname} - {message}'
The purpose of doing this is because my python script changes the OS timezone during the execution. I want the log to immediately follow the updated timezone right after the script changes it. I have tried to define a converter
function inside the logging.format
subclass, but that resulted in the timezone in the logs not being updated even after I changed it.
The code I used (from doc https://docs.python.org/3.9/library/logging.html#logging.Formatter.formatTime):
class custom(logging.Formatter):
def converter(self, timestamp):
return datetime.now()
Tried every single answer from here: How to Change the time zone in Python logging?, non works as they all do not update to the new timezone set in the OS by my script. I tried to importlib.reload(tzlocal)
and also no use.
The only sensible answer I found was to use time.tzset()
but it apparently is not available on Windows
CodePudding user response:
After some research, I solved my own problem using ctypes
, which is inspired by this answer. Essentially, I override the logging.Formatter.formatTime
function by adding a call to Windows system API to get the current system time. This is a completely different approach than all existing python modules (time, datetime, pytz
etc.) as the timezone info is not buffered when the python interpreter is launched.
Code:
class real_time_formatter(logging.Formatter):
def formatTime(self, record, datefmt=None):
class SYSTEMTIME(ctypes.Structure):
_fields_ = [('wYear', ctypes.c_int16),
('wMonth', ctypes.c_int16),
('wDayOfWeek', ctypes.c_int16),
('wDay', ctypes.c_int16),
('wHour', ctypes.c_int16),
('wMinute', ctypes.c_int16),
('wSecond', ctypes.c_int16),
('wMilliseconds', ctypes.c_int16)]
lpSystemTime = ctypes.pointer(SystemTime)
ctypes.windll.kernel32.GetLocalTime(lpSystemTime)
year = '0' * (4 - len(str(SystemTime.wYear))) str(SystemTime.wYear)
month = '0' * (2 - len(str(SystemTime.wMonth))) str(SystemTime.wMonth)
day = '0' * (2 - len(str(SystemTime.wDay))) str(SystemTime.wDay)
hour = '0' * (2 - len(str(SystemTime.wHour))) str(SystemTime.wHour)
minute = '0' * (2 - len(str(SystemTime.wMinute))) str(SystemTime.wMinute)
second = '0' * (2 - len(str(SystemTime.wSecond))) str(SystemTime.wSecond)
ms = '0' * (3 - len(str(SystemTime.wMilliseconds))) str(SystemTime.wMilliseconds)
return f'{year}-{month}-{day} {hour}:{minute}:{second}:{ms}' # 2003-01-23 00:29:50,411
streamHandler.setFormatter(real_time_formatter())
This mimics the python {asctime}
formatting, and of course you can change it however you like, since it is just a f-string.