Skip to content

Commit 5b81eff

Browse files
authored
Merge pull request #43 from AdrianVandierAst/master
Add the possibility to modify the formatter for request logs.
2 parents bd489ca + 4178ff8 commit 5b81eff

File tree

1 file changed

+59
-73
lines changed

1 file changed

+59
-73
lines changed

json_logging/__init__.py

Lines changed: 59 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -151,22 +151,29 @@ def __init(framework_name=None, custom_formatter=None):
151151
util.update_formatter_for_loggers(existing_loggers, formatter)
152152

153153

154-
def init_request_instrument(app=None):
154+
def init_request_instrument(app=None, custom_formatter=None):
155155
"""
156156
Configure the request instrumentation logging configuration for given web app. Must be called after init method
157157
158+
If **custom_formatter** is passed, it will use this formatter over the default.
159+
158160
:param app: current web application instance
161+
:param custom_formatter: formatter to override default JSONRequestLogFormatter.
159162
"""
160163

161164
if _current_framework is None or _current_framework == '-':
162165
raise RuntimeError("please init the logging first, call init(framework_name) first")
166+
167+
if custom_formatter:
168+
if not issubclass(custom_formatter, logging.Formatter):
169+
raise ValueError('custom_formatter is not subclass of logging.Formatter', custom_formatter)
163170

164171
configurator = _current_framework['app_request_instrumentation_configurator']()
165172
configurator.config(app)
166173

167-
handlers = configurator.request_logger.handlers
168-
for handler in handlers:
169-
handler.setFormatter(JSONRequestLogFormatter())
174+
formatter = custom_formatter if custom_formatter else JSONRequestLogFormatter
175+
logger = configurator.request_logger
176+
util.update_formatter_for_loggers([logger], formatter)
170177

171178

172179
def get_request_logger():
@@ -212,25 +219,40 @@ def update_response_status(self, response):
212219
self.response_sent_at = util.iso_time_format(utcnow)
213220

214221

215-
class JSONRequestLogFormatter(logging.Formatter):
222+
class BaseJSONFormatter(logging.Formatter):
216223
"""
217-
Formatter for HTTP request instrumentation logging
224+
Base class for JSON formatters
218225
"""
219226

220227
def format(self, record):
221-
utcnow = datetime.utcnow()
222-
request = record.request_info.request
223-
request_adapter = _request_util.request_adapter
228+
log_object = self._format_log_object(record, request_util=_request_util)
229+
return JSON_SERIALIZER(log_object)
224230

225-
length = request_adapter.get_content_length(request)
226-
json_log_object = {
227-
"type": "request",
231+
def _format_log_object(self, record, request_util):
232+
utcnow = datetime.utcnow()
233+
return {
228234
"written_at": util.iso_time_format(utcnow),
229235
"written_ts": util.epoch_nano_second(utcnow),
230236
"component_id": COMPONENT_ID,
231237
"component_name": COMPONENT_NAME,
232238
"component_instance": COMPONENT_INSTANCE_INDEX,
233-
"correlation_id": _request_util.get_correlation_id(request),
239+
}
240+
241+
242+
class JSONRequestLogFormatter(BaseJSONFormatter):
243+
"""
244+
Formatter for HTTP request instrumentation logging
245+
"""
246+
247+
def _format_log_object(self, record, request_util):
248+
json_log_object = super()._format_log_object(record, request_util)
249+
request = record.request_info.request
250+
request_adapter = request_util.request_adapter
251+
252+
length = request_adapter.get_content_length(request)
253+
json_log_object.update({
254+
"type": "request",
255+
"correlation_id": request_util.get_correlation_id(request),
234256
"remote_user": request_adapter.get_remote_user(request),
235257
"request": request_adapter.get_path(request),
236258
"referer": request_adapter.get_http_header(request, 'referer', EMPTY_VALUE),
@@ -246,15 +268,17 @@ def format(self, record):
246268
"response_status": record.request_info.response_status,
247269
"response_size_b": record.request_info.response_size_b,
248270
"response_content_type": record.request_info.response_content_type,
249-
"response_sent_at": record.request_info.response_sent_at}
250-
return JSON_SERIALIZER(json_log_object)
271+
"response_sent_at": record.request_info.response_sent_at
272+
})
273+
return json_log_object
274+
251275

252276

253277
def _sanitize_log_msg(record):
254278
return record.getMessage().replace('\n', '_').replace('\r', '_').replace('\t', '_')
255279

256280

257-
class JSONLogFormatter(logging.Formatter):
281+
class JSONLogFormatter(BaseJSONFormatter):
258282
"""
259283
Formatter for non-web application log
260284
"""
@@ -271,77 +295,39 @@ def get_exc_fields(self, record):
271295

272296
@classmethod
273297
def format_exception(cls, exc_info):
274-
275298
return ''.join(traceback.format_exception(*exc_info)) if exc_info else ''
276299

277-
def format(self, record):
278-
utcnow = datetime.utcnow()
279-
json_log_object = {"type": "log",
280-
"written_at": util.iso_time_format(utcnow),
281-
"written_ts": util.epoch_nano_second(utcnow),
282-
"component_id": COMPONENT_ID,
283-
"component_name": COMPONENT_NAME,
284-
"component_instance": COMPONENT_INSTANCE_INDEX,
285-
"logger": record.name,
286-
"thread": record.threadName,
287-
"level": record.levelname,
288-
"line_no": record.lineno,
289-
"module": record.module,
290-
"msg": _sanitize_log_msg(record),
291-
}
300+
def _format_log_object(self, record, request_util):
301+
json_log_object = super()._format_log_object(record, request_util)
302+
json_log_object.update({
303+
"type": "log",
304+
"logger": record.name,
305+
"thread": record.threadName,
306+
"level": record.levelname,
307+
"module": record.module,
308+
"line_no": record.lineno,
309+
"msg": _sanitize_log_msg(record),
310+
})
292311
if hasattr(record, 'props'):
293312
json_log_object.update(record.props)
294313

295314
if record.exc_info or record.exc_text:
296315
json_log_object.update(self.get_exc_fields(record))
297316

298-
return JSON_SERIALIZER(json_log_object)
317+
return json_log_object
299318

300319

301-
class JSONLogWebFormatter(logging.Formatter):
320+
class JSONLogWebFormatter(JSONLogFormatter):
302321
"""
303322
Formatter for web application log
304323
"""
305324

306-
def get_exc_fields(self, record):
307-
if record.exc_info:
308-
exc_info = self.format_exception(record.exc_info)
309-
else:
310-
exc_info = record.exc_text
311-
return {
312-
'exc_info': exc_info,
313-
'filename': record.filename,
314-
}
315-
316-
@classmethod
317-
def format_exception(cls, exc_info):
318-
319-
return ''.join(traceback.format_exception(*exc_info)) if exc_info else ''
320-
321-
def format(self, record):
322-
utcnow = datetime.utcnow()
323-
json_log_object = {"type": "log",
324-
"written_at": util.iso_time_format(utcnow),
325-
"written_ts": util.epoch_nano_second(utcnow),
326-
"component_id": COMPONENT_ID,
327-
"component_name": COMPONENT_NAME,
328-
"component_instance": COMPONENT_INSTANCE_INDEX,
329-
"logger": record.name,
330-
"thread": record.threadName,
331-
"level": record.levelname,
332-
"module": record.module,
333-
"line_no": record.lineno,
334-
"correlation_id": _request_util.get_correlation_id(),
335-
"msg": _sanitize_log_msg(record)
336-
}
337-
338-
if hasattr(record, 'props'):
339-
json_log_object.update(record.props)
340-
341-
if record.exc_info or record.exc_text:
342-
json_log_object.update(self.get_exc_fields(record))
343-
344-
return JSON_SERIALIZER(json_log_object)
325+
def _format_log_object(self, record, request_util):
326+
json_log_object = super()._format_log_object(record, request_util)
327+
json_log_object.update({
328+
"correlation_id": request_util.get_correlation_id(),
329+
})
330+
return json_log_object
345331

346332

347333
# register flask support

0 commit comments

Comments
 (0)