5
5
6
6
import json_logging
7
7
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
9
9
# http://docs.python.org/library/logging.html#logrecord-attributes
10
10
RECORD_ATTR_SKIP_LIST = [
11
11
'asctime' , 'created' , 'exc_info' , 'exc_text' , 'filename' , 'args' ,
23
23
basestring = str
24
24
25
25
if 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 ))
27
27
else :
28
28
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 ))
30
30
31
31
32
32
def _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
+ """
33
38
return record .getMessage ().replace ('\n ' , '_' ).replace ('\r ' , '_' ).replace ('\t ' , '_' )
34
39
35
40
@@ -49,31 +54,43 @@ def __init__(self, *args, **kw):
49
54
self .base_object_common ["component_instance_idx" ] = json_logging .COMPONENT_INSTANCE_INDEX
50
55
51
56
def format (self , record ):
57
+ """
58
+ Format the specified record as text. Overriding default python logging implementation
59
+ """
52
60
log_object = self ._format_log_object (record , request_util = json_logging ._request_util )
53
61
return json_logging .JSON_SERIALIZER (log_object )
54
62
55
63
def _format_log_object (self , record , request_util ):
56
64
utcnow = datetime .utcnow ()
65
+
57
66
base_obj = {
58
67
"written_at" : json_logging .util .iso_time_format (utcnow ),
59
68
"written_ts" : json_logging .util .epoch_nano_second (utcnow ),
60
69
}
70
+
61
71
base_obj .update (self .base_object_common )
62
72
# Add extra fields
63
73
base_obj .update (self ._get_extra_fields (record ))
74
+
64
75
return base_obj
65
76
66
77
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
+ """
67
83
fields = {}
68
84
69
85
if record .args :
70
86
fields ['msg' ] = record .msg
71
87
72
88
for key , value in record .__dict__ .items ():
73
89
if key not in RECORD_ATTR_SKIP_LIST :
74
- if isinstance (value , EASY_TYPES ):
90
+ if isinstance (value , EASY_SERIALIZABLE_TYPES ):
75
91
fields [key ] = value
76
92
else :
93
+ # try to cast it to a string representation
77
94
fields [key ] = repr (value )
78
95
79
96
# Always add 'props' to the root of the log, assumes props is a dict
@@ -83,46 +100,9 @@ def _get_extra_fields(self, record):
83
100
return fields
84
101
85
102
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
-
123
103
class JSONLogFormatter (BaseJSONFormatter ):
124
104
"""
125
- Formatter for non-web application log
105
+ Default formatter for non-web application log
126
106
"""
127
107
128
108
def get_exc_fields (self , record ):
@@ -141,6 +121,7 @@ def format_exception(cls, exc_info):
141
121
142
122
def _format_log_object (self , record , request_util ):
143
123
json_log_object = super (JSONLogFormatter , self )._format_log_object (record , request_util )
124
+
144
125
json_log_object .update ({
145
126
"msg" : _sanitize_log_msg (record ),
146
127
"type" : "log" ,
@@ -159,13 +140,53 @@ def _format_log_object(self, record, request_util):
159
140
160
141
class JSONLogWebFormatter (JSONLogFormatter ):
161
142
"""
162
- Formatter for web application log
143
+ Formatter for web application log with correlation-id
163
144
"""
164
145
165
146
def _format_log_object (self , record , request_util ):
166
147
json_log_object = super (JSONLogWebFormatter , self )._format_log_object (record , request_util )
148
+
167
149
if "correlation_id" not in json_log_object :
168
150
json_log_object .update ({
169
151
"correlation_id" : request_util .get_correlation_id (within_formatter = True ),
170
152
})
171
153
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