0002-logging-add-max-sizes-to-connector-log-parameters-36.patch
passerelle/base/migrations/0016_auto_20191002_1443.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
# Generated by Django 1.11.18 on 2019-10-02 12:43 |
|
3 |
from __future__ import unicode_literals |
|
4 | ||
5 |
from django.db import migrations, models |
|
6 | ||
7 | ||
8 |
class Migration(migrations.Migration): |
|
9 | ||
10 |
dependencies = [ |
|
11 |
('base', '0015_auto_20190921_0347'), |
|
12 |
] |
|
13 | ||
14 |
operations = [ |
|
15 |
migrations.AddField( |
|
16 |
model_name='loggingparameters', |
|
17 |
name='requests_max_size', |
|
18 |
field=models.PositiveIntegerField(default=5000, help_text='Maximum HTTP request size to log', verbose_name='Requests maximum size'), |
|
19 |
), |
|
20 |
migrations.AddField( |
|
21 |
model_name='loggingparameters', |
|
22 |
name='responses_max_size', |
|
23 |
field=models.PositiveIntegerField(default=5000, help_text='Maximum HTTP reponse size to log', verbose_name='Responses maximum size'), |
|
24 |
), |
|
25 |
] |
passerelle/base/models.py | ||
---|---|---|
605 | 605 |
help_text=_('One address per line (empty for site administrators)'), |
606 | 606 |
blank=True |
607 | 607 |
) |
608 |
requests_max_size = models.PositiveIntegerField( |
|
609 |
verbose_name=_('Requests maximum size'), |
|
610 |
help_text=_('Maximum HTTP request size to log'), |
|
611 |
default=settings.LOGGED_REQUESTS_MAX_SIZE |
|
612 |
) |
|
613 |
responses_max_size = models.PositiveIntegerField( |
|
614 |
verbose_name=_('Responses maximum size'), |
|
615 |
help_text=_('Maximum HTTP reponse size to log'), |
|
616 |
default=settings.LOGGED_RESPONSES_MAX_SIZE |
|
617 |
) |
|
608 | 618 | |
609 | 619 |
class Meta: |
610 | 620 |
unique_together = (('resource_type', 'resource_pk')) |
passerelle/base/views.py | ||
---|---|---|
136 | 136 |
def get_form_class(self): |
137 | 137 |
form_class = model_forms.modelform_factory( |
138 | 138 |
LoggingParameters, |
139 |
fields=['log_level', 'trace_emails']) |
|
139 |
fields=['log_level', 'trace_emails', 'requests_max_size', 'responses_max_size'])
|
|
140 | 140 |
form_class.base_fields['trace_emails'].widget.attrs['rows'] = '3' |
141 | 141 |
return form_class |
142 | 142 | |
... | ... | |
147 | 147 |
parameters = self.get_resource().logging_parameters |
148 | 148 |
d['log_level'] = parameters.log_level |
149 | 149 |
d['trace_emails'] = parameters.trace_emails |
150 |
d['requests_max_size'] = parameters.requests_max_size |
|
151 |
d['responses_max_size'] = parameters.responses_max_size |
|
150 | 152 |
return d |
151 | 153 | |
152 | 154 |
def get_resource(self): |
... | ... | |
160 | 162 |
parameters = self.get_resource().logging_parameters |
161 | 163 |
parameters.log_level = form.cleaned_data['log_level'] |
162 | 164 |
parameters.trace_emails = form.cleaned_data['trace_emails'] |
165 |
parameters.requests_max_size = form.cleaned_data['requests_max_size'] |
|
166 |
parameters.responses_max_size = form.cleaned_data['responses_max_size'] |
|
163 | 167 |
parameters.save() |
164 | 168 |
return super(LoggingParametersUpdateView, self).form_valid(form) |
165 | 169 |
passerelle/settings.py | ||
---|---|---|
209 | 209 |
) |
210 | 210 | |
211 | 211 |
# Max size of the response to log |
212 |
LOGGED_RESPONSES_MAX_SIZE = 4096
|
|
212 |
LOGGED_RESPONSES_MAX_SIZE = 5000
|
|
213 | 213 | |
214 | 214 |
# Max size of the request to log |
215 | 215 |
LOGGED_REQUESTS_MAX_SIZE = 5000 |
passerelle/utils/__init__.py | ||
---|---|---|
161 | 161 |
if logger.level == 10: # DEBUG |
162 | 162 |
extra['request_headers'] = dict(request.headers.items()) |
163 | 163 |
if request.body: |
164 |
extra['request_payload'] = repr(request.body[:settings.LOGGED_REQUESTS_MAX_SIZE]) |
|
164 |
if hasattr(logger, 'connector'): |
|
165 |
max_size = logger.connector.logging_parameters.requests_max_size |
|
166 |
else: |
|
167 |
max_size = settings.LOGGED_REQUESTS_MAX_SIZE |
|
168 |
extra['request_payload'] = repr(request.body[:max_size]) |
|
165 | 169 |
if response is not None: |
166 | 170 |
message = message + ' (=> %s)' % response.status_code |
167 | 171 |
extra['response_status'] = response.status_code |
... | ... | |
169 | 173 |
extra['response_headers'] = dict(response.headers.items()) |
170 | 174 |
# log body only if content type is allowed |
171 | 175 |
if content_type_match(response.headers.get('Content-Type')): |
172 |
content = response.content[:settings.LOGGED_RESPONSES_MAX_SIZE] |
|
176 |
if hasattr(logger, 'connector'): |
|
177 |
max_size = logger.connector.logging_parameters.responses_max_size |
|
178 |
else: |
|
179 |
max_size = settings.LOGGED_RESPONSES_MAX_SIZE |
|
180 |
content = response.content[:max_size] |
|
173 | 181 |
extra['response_content'] = repr(content) |
174 | 182 |
if response.status_code // 100 == 3: |
175 | 183 |
log_function = logger.warning |
passerelle/utils/jsonresponse.py | ||
---|---|---|
132 | 132 |
except Exception as e: |
133 | 133 |
extras = {'method': req.method, 'exception': exception_to_text(e), 'request': req} |
134 | 134 |
if req.method == 'POST': |
135 |
extras.update({'body': repr(req.body[:settings.LOGGED_REQUESTS_MAX_SIZE])}) |
|
135 |
if hasattr(logger, 'connector'): |
|
136 |
max_size = logger.connector.logging_parameters.requests_max_size |
|
137 |
else: |
|
138 |
max_size = settings.LOGGED_REQUESTS_MAX_SIZE |
|
139 |
extras.update({'body': repr(req.body[:max_size])}) |
|
136 | 140 |
if (not isinstance(e, (Http404, PermissionDenied, ObjectDoesNotExist, RequestException)) |
137 | 141 |
and getattr(e, 'log_error', True)): |
138 | 142 |
logger.exception("Error occurred while processing request", extra=extras) |
passerelle/views.py | ||
---|---|---|
408 | 408 |
connector_name, endpoint_name = kwargs['connector'], kwargs['endpoint'] |
409 | 409 |
connector = self.get_object() |
410 | 410 |
url = request.get_full_path() |
411 |
payload = request.body[:settings.LOGGED_REQUESTS_MAX_SIZE]
|
|
411 |
payload = request.body[:connector.logging_parameters.requests_max_size]
|
|
412 | 412 |
try: |
413 | 413 |
payload.decode('utf-8') |
414 | 414 |
except UnicodeDecodeError: |
tests/settings.py | ||
---|---|---|
67 | 67 |
}, |
68 | 68 |
} |
69 | 69 |
} |
70 | ||
71 |
LOGGED_REQUESTS_MAX_SIZE = 4999 |
tests/test_api_access.py | ||
---|---|---|
208 | 208 |
oxyd.set_log_level('DEBUG') # log request payload and response headers/content |
209 | 209 |
settings.LOGGED_CONTENT_TYPES_MESSAGES = 'foo/bar' # response content to log |
210 | 210 | |
211 |
assert settings.LOGGED_REQUEST_MAX_SIZE == 5000
|
|
212 |
assert settings.LOGGED_RESPONSES_MAX_SIZE == 4096
|
|
211 |
assert oxyd.logging_parameters.requests_max_size == 4999
|
|
212 |
assert oxyd.logging_parameters.responses_max_size == 5000
|
|
213 | 213 |
with utils.mock_url(oxyd.URL, response, headers=headers): |
214 | 214 |
result = app.post_json(endpoint_url, params=payload) |
215 | 215 |
assert len(ResourceLog.objects.all()) == 4 |
... | ... | |
227 | 227 |
assert len(ResourceLog.objects.all()[3].extra['body']) == 86 |
228 | 228 | |
229 | 229 |
# troncate logs |
230 |
settings.LOGGED_REQUESTS_MAX_SIZE = 10 |
|
231 |
settings.LOGGED_RESPONSES_MAX_SIZE = 20 |
|
230 |
parameters = oxyd.logging_parameters |
|
231 |
parameters.requests_max_size = 10 |
|
232 |
parameters.save() |
|
233 |
parameters = oxyd.logging_parameters |
|
234 |
parameters.responses_max_size = 20 |
|
235 |
parameters.save() |
|
232 | 236 |
with utils.mock_url(oxyd.URL, response, headers=headers): |
233 | 237 |
result = app.post_json(endpoint_url, params=payload) |
234 | 238 |
assert len(ResourceLog.objects.all()) == 8 |
tests/test_requests.py | ||
---|---|---|
105 | 105 |
assert not hasattr(record, 'response_content') |
106 | 106 |
assert not hasattr(record, 'response_headers') |
107 | 107 | |
108 |
def test_log_error_request_max_size(caplog, log_level, settings):
|
|
108 |
def test_log_error_http_max_sizes(caplog, log_level, settings):
|
|
109 | 109 |
url = 'https://httperror.org/plop' |
110 | 110 | |
111 | 111 |
logger = logging.getLogger('requests') |
112 | 112 |
logger.setLevel(log_level) |
113 | 113 | |
114 |
assert settings.LOGGED_REQUESTS_MAX_SIZE == 4999 |
|
115 |
assert settings.LOGGED_RESPONSES_MAX_SIZE == 5000 |
|
114 | 116 |
settings.LOGGED_REQUESTS_MAX_SIZE = 8 |
117 |
settings.LOGGED_RESPONSES_MAX_SIZE = 7 |
|
115 | 118 |
with HTTMock(http400_mock): |
116 | 119 |
requests = Request(logger=logger) |
117 | 120 |
response = requests.post(url, json={'name':'josh'}) |
118 | 121 | |
119 |
print logger.level |
|
120 | 122 |
if logger.level == 10: # DEBUG |
121 | 123 |
records = [record for record in caplog.records if record.name == 'requests'] |
122 | 124 |
assert records[0].request_payload == '\'{"name":\'' |
125 |
assert records[0].response_content == '\'{"foo":\'' |
|
123 | 126 | |
124 | 127 | |
125 | 128 |
@pytest.fixture(params=['xml', 'whatever', 'jpeg', 'pdf']) |
126 |
- |