55
66import json_logging
77
8- # The list contains all the attributes listed in
8+ # The list contains all the attributes listed in that will not be overwritten by custom extra props
99# http://docs.python.org/library/logging.html#logrecord-attributes
1010RECORD_ATTR_SKIP_LIST = [
1111 'asctime' , 'created' , 'exc_info' , 'exc_text' , 'filename' , 'args' ,
2323 basestring = str
2424
2525if sys .version_info < (3 , 0 ):
26- EASY_TYPES = (basestring , bool , dict , float , int , list , type (None ))
26+ EASY_SERIALIZABLE_TYPES = (basestring , bool , dict , float , int , list , type (None ))
2727else :
2828 RECORD_ATTR_SKIP_LIST .append ('stack_info' )
29- EASY_TYPES = (str , bool , dict , float , int , list , type (None ))
29+ EASY_SERIALIZABLE_TYPES = (str , bool , dict , float , int , list , type (None ))
3030
3131
3232def _sanitize_log_msg (record ):
33+ """
34+ Sanitize log message to make sure we can print out properly formatted JSON string
35+ :param record: log object
36+ :return: sanitized log object
37+ """
3338 return record .getMessage ().replace ('\n ' , '_' ).replace ('\r ' , '_' ).replace ('\t ' , '_' )
3439
3540
@@ -49,31 +54,43 @@ def __init__(self, *args, **kw):
4954 self .base_object_common ["component_instance_idx" ] = json_logging .COMPONENT_INSTANCE_INDEX
5055
5156 def format (self , record ):
57+ """
58+ Format the specified record as text. Overriding default python logging implementation
59+ """
5260 log_object = self ._format_log_object (record , request_util = json_logging ._request_util )
5361 return json_logging .JSON_SERIALIZER (log_object )
5462
5563 def _format_log_object (self , record , request_util ):
5664 utcnow = datetime .utcnow ()
65+
5766 base_obj = {
5867 "written_at" : json_logging .util .iso_time_format (utcnow ),
5968 "written_ts" : json_logging .util .epoch_nano_second (utcnow ),
6069 }
70+
6171 base_obj .update (self .base_object_common )
6272 # Add extra fields
6373 base_obj .update (self ._get_extra_fields (record ))
74+
6475 return base_obj
6576
6677 def _get_extra_fields (self , record ):
78+ """
79+ Get the dict of custom extra fields passed to the log statement
80+ :param record: log record
81+ :return:
82+ """
6783 fields = {}
6884
6985 if record .args :
7086 fields ['msg' ] = record .msg
7187
7288 for key , value in record .__dict__ .items ():
7389 if key not in RECORD_ATTR_SKIP_LIST :
74- if isinstance (value , EASY_TYPES ):
90+ if isinstance (value , EASY_SERIALIZABLE_TYPES ):
7591 fields [key ] = value
7692 else :
93+ # try to cast it to a string representation
7794 fields [key ] = repr (value )
7895
7996 # Always add 'props' to the root of the log, assumes props is a dict
@@ -83,46 +100,9 @@ def _get_extra_fields(self, record):
83100 return fields
84101
85102
86- class JSONRequestLogFormatter (BaseJSONFormatter ):
87- """
88- Formatter for HTTP request instrumentation logging
89- """
90-
91- def _format_log_object (self , record , request_util ):
92- json_log_object = super (JSONRequestLogFormatter , self )._format_log_object (record , request_util )
93- request_adapter = request_util .request_adapter
94- response_adapter = json_logging ._request_util .response_adapter
95- request = record .request_response_data ._request
96- response = record .request_response_data ._response
97-
98- length = request_adapter .get_content_length (request )
99-
100- json_log_object .update ({
101- "type" : "request" ,
102- "correlation_id" : request_util .get_correlation_id (request ),
103- "remote_user" : request_adapter .get_remote_user (request ),
104- "request" : request_adapter .get_path (request ),
105- "referer" : request_adapter .get_http_header (request , 'referer' , json_logging .EMPTY_VALUE ),
106- "x_forwarded_for" : request_adapter .get_http_header (request , 'x-forwarded-for' , json_logging .EMPTY_VALUE ),
107- "protocol" : request_adapter .get_protocol (request ),
108- "method" : request_adapter .get_method (request ),
109- "remote_ip" : request_adapter .get_remote_ip (request ),
110- "request_size_b" : json_logging .util .parse_int (length , - 1 ),
111- "remote_host" : request_adapter .get_remote_ip (request ),
112- "remote_port" : request_adapter .get_remote_port (request ),
113- "response_status" : response_adapter .get_status_code (response ),
114- "response_size_b" : response_adapter .get_response_size (response ),
115- "response_content_type" : response_adapter .get_content_type (response ),
116- })
117-
118- json_log_object .update (record .request_response_data )
119-
120- return json_log_object
121-
122-
123103class JSONLogFormatter (BaseJSONFormatter ):
124104 """
125- Formatter for non-web application log
105+ Default formatter for non-web application log
126106 """
127107
128108 def get_exc_fields (self , record ):
@@ -141,6 +121,7 @@ def format_exception(cls, exc_info):
141121
142122 def _format_log_object (self , record , request_util ):
143123 json_log_object = super (JSONLogFormatter , self )._format_log_object (record , request_util )
124+
144125 json_log_object .update ({
145126 "msg" : _sanitize_log_msg (record ),
146127 "type" : "log" ,
@@ -159,13 +140,53 @@ def _format_log_object(self, record, request_util):
159140
160141class JSONLogWebFormatter (JSONLogFormatter ):
161142 """
162- Formatter for web application log
143+ Formatter for web application log with correlation-id
163144 """
164145
165146 def _format_log_object (self , record , request_util ):
166147 json_log_object = super (JSONLogWebFormatter , self )._format_log_object (record , request_util )
148+
167149 if "correlation_id" not in json_log_object :
168150 json_log_object .update ({
169151 "correlation_id" : request_util .get_correlation_id (within_formatter = True ),
170152 })
171153 return json_log_object
154+
155+
156+ class JSONRequestLogFormatter (BaseJSONFormatter ):
157+ """
158+ Formatter for HTTP request instrumentation logging
159+ """
160+
161+ def _format_log_object (self , record , request_util ):
162+ json_log_object = super (JSONRequestLogFormatter , self )._format_log_object (record , request_util )
163+
164+ request_adapter = request_util .request_adapter
165+ response_adapter = json_logging ._request_util .response_adapter
166+
167+ request = record .request_response_data ._request
168+ response = record .request_response_data ._response
169+
170+ length = request_adapter .get_content_length (request )
171+
172+ json_log_object .update ({
173+ "type" : "request" ,
174+ "correlation_id" : request_util .get_correlation_id (request ),
175+ "remote_user" : request_adapter .get_remote_user (request ),
176+ "request" : request_adapter .get_path (request ),
177+ "referer" : request_adapter .get_http_header (request , 'referer' , json_logging .EMPTY_VALUE ),
178+ "x_forwarded_for" : request_adapter .get_http_header (request , 'x-forwarded-for' , json_logging .EMPTY_VALUE ),
179+ "protocol" : request_adapter .get_protocol (request ),
180+ "method" : request_adapter .get_method (request ),
181+ "remote_ip" : request_adapter .get_remote_ip (request ),
182+ "request_size_b" : json_logging .util .parse_int (length , - 1 ),
183+ "remote_host" : request_adapter .get_remote_ip (request ),
184+ "remote_port" : request_adapter .get_remote_port (request ),
185+ "response_status" : response_adapter .get_status_code (response ),
186+ "response_size_b" : response_adapter .get_response_size (response ),
187+ "response_content_type" : response_adapter .get_content_type (response ),
188+ })
189+
190+ json_log_object .update (record .request_response_data )
191+
192+ return json_log_object
0 commit comments