@@ -82,36 +82,43 @@ def __init__(self, fmt=None, datefmt=None, style="%", logger_name="Dockerflow"):
82
82
self .logger_name = logger_name
83
83
self .hostname = socket .gethostname ()
84
84
85
- def format (self , record ):
85
+ def is_value_jsonlike (self , value ):
86
+ """
87
+ Return True if the value looks like JSON. Use only on strings.
88
+ """
89
+ return value .startswith ('{' ) and value .endswith ('}' )
90
+
91
+ def convert_record (self , record ):
86
92
"""
87
- Map from Python LogRecord attributes to JSON log format fields
93
+ Convert a Python LogRecord attribute into a dict that follows MozLog
94
+ application logging standard.
88
95
89
96
* from - https://docs.python.org/3/library/logging.html#logrecord-attributes
90
97
* to - https://wiki.mozilla.org/Firefox/Services/Logging
91
98
"""
92
- out = dict (
93
- Timestamp = int (record .created * 1e9 ),
94
- Type = record .name ,
95
- Logger = self .logger_name ,
96
- Hostname = self .hostname ,
97
- EnvVersion = self .LOGGING_FORMAT_VERSION ,
98
- Severity = self .SYSLOG_LEVEL_MAP .get (
99
+ out = {
100
+ ' Timestamp' : int (record .created * 1e9 ),
101
+ ' Type' : record .name ,
102
+ ' Logger' : self .logger_name ,
103
+ ' Hostname' : self .hostname ,
104
+ ' EnvVersion' : self .LOGGING_FORMAT_VERSION ,
105
+ ' Severity' : self .SYSLOG_LEVEL_MAP .get (
99
106
record .levelno , self .DEFAULT_SYSLOG_LEVEL
100
107
),
101
- Pid = record .process ,
102
- )
108
+ ' Pid' : record .process ,
109
+ }
103
110
104
111
# Include any custom attributes set on the record.
105
112
# These would usually be collected metrics data.
106
- fields = dict ()
113
+ fields = {}
107
114
for key , value in record .__dict__ .items ():
108
115
if key not in self .EXCLUDED_LOGRECORD_ATTRS :
109
116
fields [key ] = value
110
117
111
118
# Only include the 'msg' key if it has useful content
112
119
# and is not already a JSON blob.
113
120
message = record .getMessage ()
114
- if message and not message . startswith ( "{" ) and not message . endswith ( "}" ):
121
+ if message and not self . is_value_jsonlike ( message ):
115
122
fields ["msg" ] = message
116
123
117
124
# If there is an error, format it for nice output.
@@ -120,7 +127,14 @@ def format(self, record):
120
127
fields ["traceback" ] = safer_format_traceback (* record .exc_info )
121
128
122
129
out ["Fields" ] = fields
130
+ return out
123
131
132
+ def format (self , record ):
133
+ """
134
+ Format a Python LogRecord into a JSON string following MozLog
135
+ application logging standard.
136
+ """
137
+ out = self .convert_record (record )
124
138
return json .dumps (out , cls = SafeJSONEncoder )
125
139
126
140
0 commit comments