Skip to content

Commit 42155fd

Browse files
committed
feat: ISO8601 logging date format
1 parent b6b24d1 commit 42155fd

File tree

6 files changed

+31
-22
lines changed

6 files changed

+31
-22
lines changed

src/DIRAC/FrameworkSystem/private/standardLogging/Formatter/BaseFormatter.py

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
BaseFormatter
33
"""
44
import logging
5-
import sys
5+
import time
66

77

88
class BaseFormatter(logging.Formatter):
@@ -23,6 +23,9 @@ def __init__(self, fmt=None, datefmt=None):
2323
:param str fmt: log format: "%(asctime)s UTC %(name)s %(levelname)s: %(message)"
2424
:param str datefmt: date format: "%Y-%m-%d %H:%M:%S"
2525
"""
26+
# Initialization of the UTC time
27+
# Actually, time.gmtime is equal to UTC time: it has its DST flag to 0 which means there is no clock advance
28+
self.converter = time.gmtime
2629
super().__init__()
2730

2831
def format(self, record):
@@ -43,7 +46,7 @@ def format(self, record):
4346

4447
if record.headerIsShown:
4548
if record.timeStampIsShown:
46-
timeStamp = "%(asctime)s UTC "
49+
timeStamp = "%(asctime)s "
4750
if record.contextIsShown:
4851
contextComponentList = ["%(componentname)s%(customname)s"]
4952

@@ -63,5 +66,14 @@ def format(self, record):
6366
fmt += "%(message)s%(spacer)s%(varmessage)s"
6467

6568
self._style._fmt = fmt # pylint: disable=no-member
66-
self.datefmt = "%Y-%m-%d %H:%M:%S"
6769
return super().format(record)
70+
71+
def formatTime(self, record, datefmt=None):
72+
""":py:meth:`logging.Formatter.formatTime` with microsecond precision by default"""
73+
ct = self.converter(record.created)
74+
if datefmt:
75+
s = time.strftime(datefmt, ct)
76+
else:
77+
t = time.strftime("%Y-%m-%dT%H:%M:%S", ct)
78+
s = "%s,%06dZ" % (t, (record.created - int(record.created)) * 1e6)
79+
return s

src/DIRAC/FrameworkSystem/private/standardLogging/Formatter/MicrosecondJsonFormatter.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ def __init__(self, *args, **kwargs):
1010
Add to the list of attributes we don't want to see
1111
all the DIRAC spefic log formating instructions
1212
"""
13+
# Initialization of the UTC time
14+
# Actually, time.gmtime is equal to UTC time: it has its DST flag to 0 which means there is no clock advance
15+
self.converter = time.gmtime
16+
1317
if "reserved_attrs" not in kwargs:
1418
kwargs["reserved_attrs"] = RESERVED_ATTRS + (
1519
"spacer",
@@ -27,6 +31,6 @@ def formatTime(self, record, datefmt=None):
2731
if datefmt:
2832
s = time.strftime(datefmt, ct)
2933
else:
30-
t = time.strftime("%Y-%m-%d %H:%M:%S", ct)
31-
s = "%s,%06d" % (t, (record.created - int(record.created)) * 1e6)
34+
t = time.strftime("%Y-%m-%dT%H:%M:%S", ct)
35+
s = "%s,%06dZ" % (t, (record.created - int(record.created)) * 1e6)
3236
return s

src/DIRAC/FrameworkSystem/private/standardLogging/LoggingRoot.py

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,6 @@ def __init__(self):
5555
# root Logger level is set to INFO by default
5656
self._logger.setLevel(LogLevels.INFO)
5757

58-
# initialization of the UTC time
59-
# Actually, time.gmtime is equal to UTC time: it has its DST flag to 0 which means there is no clock advance
60-
logging.Formatter.converter = time.gmtime
61-
6258
# initialization of the default backend
6359
# use the StdoutBackend directly to avoid dependancy loop with ObjectLoader
6460
self._addBackend(StdoutBackend)
@@ -295,8 +291,9 @@ def __enableLogsFromExternalLibs(isEnabled=True):
295291
if isEnabled:
296292
logging.basicConfig(
297293
level=logging.DEBUG,
298-
format="%(asctime)s UTC ExternalLibrary/%(name)s %(levelname)s: %(message)s",
299-
datefmt="%Y-%m-%d %H:%M:%S",
294+
format="%(asctime)s,%(msecs)03dZ ExternalLibrary/%(name)s %(levelname)s: %(message)s",
295+
datefmt="%Y-%m-%dT%H:%M:%S",
300296
)
297+
rootLogger.handlers[0].formatter.converter = time.gmtime
301298
else:
302299
rootLogger.addHandler(logging.NullHandler())

src/DIRAC/FrameworkSystem/private/standardLogging/test/TestLogUtilities.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ def cleaningLog(log):
1515
"""
1616
Remove date and space from the log string
1717
"""
18-
log = log.split("UTC ")[-1]
18+
log = log.split("Z ", 1)[-1]
1919
return log
2020

2121

src/DIRAC/FrameworkSystem/private/standardLogging/test/Test_Logging_FormatOptions.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -135,21 +135,21 @@ def test_showFormatOptionsgLogger(
135135
gLogger.notice(msg)
136136
logValue = capturedBackend.getvalue()
137137
# check that timestamp is available if it has to be available
138-
assert ("UTC" in logValue) == isTimeStampAvailable
138+
assert ("Z " in logValue) == isTimeStampAvailable
139139
logstring = cleaningLog(logValue)
140140
capturedBackend.truncate(0)
141141
capturedBackend.seek(0)
142142

143143
log.notice(msg)
144144
logValue = capturedBackend.getvalue()
145-
assert ("UTC" in logValue) == isTimeStampAvailable
145+
assert ("Z " in logValue) == isTimeStampAvailable
146146
logstring += cleaningLog(logValue)
147147
capturedBackend.truncate(0)
148148
capturedBackend.seek(0)
149149

150150
sublog.notice(msg)
151151
logValue = capturedBackend.getvalue()
152-
assert ("UTC" in logValue) == isTimeStampAvailable
152+
assert ("Z " in logValue) == isTimeStampAvailable
153153
logstring += cleaningLog(logValue)
154154
capturedBackend.truncate(0)
155155
capturedBackend.seek(0)

src/DIRAC/FrameworkSystem/private/standardLogging/test/Test_Logging_GetSubLogger.py

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from DIRAC.FrameworkSystem.private.standardLogging.LogLevels import LogLevels
77

88

9-
from DIRAC.FrameworkSystem.private.standardLogging.test.TestLogUtilities import gLogger, gLoggerReset
9+
from DIRAC.FrameworkSystem.private.standardLogging.test.TestLogUtilities import gLogger, gLoggerReset, cleaningLog
1010

1111

1212
def test_getSubLoggerLogRecord():
@@ -49,10 +49,6 @@ def test_getSubLoggerObject():
4949
assert log == anotherLog
5050

5151

52-
# Run the tests for all the log levels and exceptions
53-
# We may need to rerun the test if we are unlucky and the timestamps
54-
# don't match
55-
@flaky(max_runs=3)
5652
@pytest.mark.parametrize("logLevel", ["exception"] + [lvl.lower() for lvl in LogLevels.getLevelNames()])
5753
def test_localSubLoggerObject(logLevel):
5854
"""
@@ -66,7 +62,7 @@ def test_localSubLoggerObject(logLevel):
6662
# Create a real subLogger and a localSubLogger
6763
# with the same "name"
6864
subLog = log.getSubLogger("child")
69-
localSubLog = log.getSubLogger("child")
65+
localSubLog = log.getLocalSubLogger("child")
7066

7167
# Print and capture a message with the real sublogger
7268
capturedBackend.truncate(0)
@@ -81,4 +77,4 @@ def test_localSubLoggerObject(logLevel):
8177
locMsg = capturedBackend.getvalue()
8278

8379
# Compare the output
84-
assert subMsg == locMsg
80+
assert cleaningLog(subMsg) == cleaningLog(locMsg)

0 commit comments

Comments
 (0)