94
94
def __init__(self, app, conf):
96
96
self.log_hdrs = conf.get('log_headers', 'no').lower() in TRUE_VALUES
98
# The leading access_* check is in case someone assumes that
99
# log_statsd_valid_http_methods behaves like the other log_statsd_*
101
self.valid_methods = conf.get(
102
'access_log_statsd_valid_http_methods',
103
conf.get('log_statsd_valid_http_methods',
104
'GET,HEAD,POST,PUT,DELETE,COPY'))
105
self.valid_methods = [m.strip().upper() for m in
106
self.valid_methods.split(',') if m.strip()]
97
107
access_log_conf = {}
98
108
for key in ('log_facility', 'log_name', 'log_level', 'log_udp_host',
109
'log_udp_port', 'log_statsd_host', 'log_statsd_port',
110
'log_statsd_default_sample_rate',
111
'log_statsd_metric_prefix'):
100
112
value = conf.get('access_' + key, conf.get(key, None))
102
114
access_log_conf[key] = value
103
115
self.access_logger = get_logger(access_log_conf,
104
log_route='proxy-access')
116
log_route='proxy-access')
117
self.access_logger.set_statsd_prefix('proxy-server')
106
119
def log_request(self, env, status_int, bytes_received, bytes_sent,
107
120
request_time, client_disconnect):
124
137
logged_headers = None
125
138
if self.log_hdrs:
126
139
logged_headers = '\n'.join('%s: %s' % (k, v)
127
for k, v in req.headers.items())
128
self.access_logger.info(' '.join(quote(str(x) if x else '-')
140
for k, v in req.headers.items())
141
method = req.environ.get('swift.orig_req_method', req.method)
142
self.access_logger.info(' '.join(
143
quote(str(x) if x else '-')
130
145
get_remote_client(req),
132
147
time.strftime('%d/%b/%Y/%H/%M/%S', time.gmtime()),
135
150
req.environ.get('SERVER_PROTOCOL'),
145
160
'%.4f' % request_time,
146
161
req.environ.get('swift.source'),
148
self.access_logger.txn_id = None
163
# Log timing and bytes-transfered data to StatsD
164
if req.path.startswith('/v1/'):
166
stat_type = [None, 'account', 'container',
167
'object'][req.path.strip('/').count('/')]
171
stat_type = env.get('swift.source')
172
# Only log data for valid controllers (or SOS) to keep the metric count
173
# down (egregious errors will get logged by the proxy server itself).
175
stat_method = method if method in self.valid_methods \
177
metric_name = '.'.join((stat_type, stat_method, str(status_int)))
178
self.access_logger.timing(metric_name + '.timing',
180
self.access_logger.update_stats(metric_name + '.xfer',
181
bytes_received + bytes_sent)
150
183
def __call__(self, env, start_response):
151
184
start_response_args = [None]
175
208
('content-length', str(sum(len(i) for i in iterable))))
177
210
raise Exception('WSGI [proxy-logging]: No content-length '
178
'or transfer-encoding header sent and there is '
179
'content! %r' % chunk)
211
'or transfer-encoding header sent and '
212
'there is content! %r' % chunk)
180
213
start_response(*start_response_args[0])
182
215
client_disconnect = False
192
225
status_int = int(start_response_args[0][0].split(' ', 1)[0])
193
self.log_request(env, status_int,
194
input_proxy.bytes_received, bytes_sent,
195
time.time() - start_time,
196
client_disconnect or input_proxy.client_disconnect)
227
env, status_int, input_proxy.bytes_received, bytes_sent,
228
time.time() - start_time,
229
client_disconnect or input_proxy.client_disconnect)
199
232
iterable = self.app(env, my_start_response)
200
233
except Exception:
201
self.log_request(env, 500, input_proxy.bytes_received, 0,
202
time.time() - start_time, input_proxy.client_disconnect)
235
env, 500, input_proxy.bytes_received, 0,
236
time.time() - start_time, input_proxy.client_disconnect)
205
239
return iter_response(iterable)