Projet

Général

Profil

0001-logging-append-connector-response-to-ressource-log-3.patch

Nicolas Roche, 15 novembre 2019 11:26

Télécharger (7,51 ko)

Voir les différences:

Subject: [PATCH] logging: append connector response to ressource log (#31774)

 passerelle/base/models.py      | 18 ++++++++++--------
 passerelle/views.py            | 20 +++++++++++++++++++-
 tests/test_generic_endpoint.py | 21 +++++++++++++++++++++
 3 files changed, 50 insertions(+), 9 deletions(-)
passerelle/base/models.py
770 770

  
771 771
    def _log(self, levelname, message, *args, **kwargs):
772 772
        force = kwargs.pop('force', False)
773
        ressource_log = None
773 774
        if self.connector.down() and not force:
774 775
            # don't log if the connector is known to be down
775 776
            return
......
825 826
                (exc_type, exc_value, tb) = sys.exc_info()
826 827
                attr['extra']['error_summary'] = traceback.format_exception_only(exc_type, exc_value)
827 828

  
828
            ResourceLog.objects.create(**attr)
829
            ressource_log = ResourceLog.objects.create(**attr)
829 830

  
830 831
        admins = settings.ADMINS
831 832
        logging_parameters = self.connector.logging_parameters
......
833 834
            admins = [('', x) for x in logging_parameters.trace_emails.splitlines()]
834 835
        with override_settings(ADMINS=admins):
835 836
            getattr(self._logger, levelname.lower())(message, *args, **kwargs)
837
        return ressource_log
836 838

  
837 839
    def exception(self, message, *args, **kwargs):
838 840
        kwargs['exc_info'] = 1
839
        self._log('ERROR', message, *args, **kwargs)
841
        return self._log('ERROR', message, *args, **kwargs)
840 842

  
841 843
    def debug(self, message, *args, **kwargs):
842
        self._log('DEBUG', message, *args, **kwargs)
844
        return self._log('DEBUG', message, *args, **kwargs)
843 845

  
844 846
    def info(self, message, *args, **kwargs):
845
        self._log('INFO', message, *args, **kwargs)
847
        return self._log('INFO', message, *args, **kwargs)
846 848

  
847 849
    def warning(self, message, *args, **kwargs):
848
        self._log('WARNING', message, *args, **kwargs)
850
        return self._log('WARNING', message, *args, **kwargs)
849 851

  
850 852
    def critical(self, message, *args, **kwargs):
851
        self._log('CRITICAL', message, *args, **kwargs)
853
        return self._log('CRITICAL', message, *args, **kwargs)
852 854

  
853 855
    def error(self, message, *args, **kwargs):
854
        self._log('ERROR', message, *args, **kwargs)
856
        return self._log('ERROR', message, *args, **kwargs)
855 857

  
856 858
    def fatal(self, message, *args, **kwargs):
857
        self._log('FATAL', message, *args, **kwargs)
859
        return self._log('FATAL', message, *args, **kwargs)
858 860

  
859 861

  
860 862
class HTTPResource(models.Model):
passerelle/views.py
18 18
import hashlib
19 19
import inspect
20 20
import json
21
from exceptions import UnicodeDecodeError
21 22

  
22 23
from django.apps import apps
23 24
from django.conf.urls import url
......
26 27
from django.contrib.auth import logout as auth_logout
27 28
from django.contrib.auth import views as auth_views
28 29
from django.db import transaction
30
from django.db.utils import DataError
29 31
from django.http import HttpResponse, HttpResponseRedirect, Http404
30 32
from django.views.decorators.csrf import csrf_exempt
31 33
from django.views.generic import (
......
421 423
            payload.decode('utf-8')
422 424
        except UnicodeDecodeError:
423 425
            payload = '<BINARY PAYLOAD>'
424
        connector.logger.info('endpoint %s %s (%r) ' %
426
        ressource_log = connector.logger.info('endpoint %s %s (%r) ' %
425 427
                              (request.method, url, payload),
426 428
                              extra={
427 429
                                  'request': request,
......
432 434
                                  'connector_payload': payload
433 435
                              })
434 436

  
437
        def log_connector_response(value, from_cache=False):
438
            if not ressource_log:
439
                return
440
            if from_cache:
441
                ressource_log.extra['from_cache'] = True
442
            response = str(value)[:connector.logging_parameters.responses_max_size]
443
            ressource_log.extra['response'] = force_text(response, errors='ignore')
444
            try:
445
                with transaction.atomic():
446
                    ressource_log.save()
447
            except DataError:
448
                ressource_log.extra['response'] = '<binary>'
449
                ressource_log.save()
450

  
435 451
        params = self.get_params(request, *args, **kwargs)
436 452
        if request.method == 'GET' and self.endpoint.endpoint_info.cache_duration:
437 453
            cache_key = hashlib.md5(
438 454
                repr(self.get_object().slug) + repr(self.endpoint) + repr(params)).hexdigest()
439 455
            result = cache.get(cache_key)
440 456
            if result is not None:
457
                log_connector_response(result, from_cache=True)
441 458
                return result
442 459

  
443 460
        result = self.endpoint(request, **params)
444 461
        if request.method == 'GET' and self.endpoint.endpoint_info.cache_duration:
445 462
            cache.set(cache_key, result, self.endpoint.endpoint_info.cache_duration)
463
        log_connector_response(result)
446 464
        return result
447 465

  
448 466
    def get(self, request, *args, **kwargs):
tests/test_generic_endpoint.py
115 115
    assert log.extra['connector'] == 'arcgis'
116 116
    assert log.extra['connector_endpoint'] == 'district'
117 117
    assert log.extra['connector_endpoint_method'] == 'GET'
118
    assert "'text': u'HAUSSONVILLE / BLANDAN / MON DESERT / SAURUPT'" in log.extra['response']
118 119
    assert '/arcgis/test/district?' in log.extra['connector_endpoint_url']
119 120

  
120 121
    # Resource Generic Logger
......
142 143
    assert ResourceLog.objects.last().message == 'first warning'
143 144
    assert ResourceLog.objects.last().levelno == 30
144 145

  
146
    # troncate connector response on Resource Custom DB Logger
147
    ResourceLog.objects.all().delete()
148
    parameters = arcgis.logging_parameters
149
    parameters.responses_max_size = 20
150
    parameters.save()
151
    app.get('/arcgis/test/district', params={'lon': 6.172122, 'lat': 48.673836}, status=200)
152
    assert ResourceLog.objects.count() == 1
153
    log = ResourceLog.objects.filter(appname='arcgis', slug='test').first()
154
    assert len(log.extra['response']) == 20
155
    assert log.extra.get('from_cache') == None
156

  
157
    # check connector response returned by cache
158
    ResourceLog.objects.all().delete()
159
    arcgis.district.endpoint_info.cache_duration = 5
160
    app.get('/arcgis/test/district', params={'lon': 6.172122, 'lat': 48.673836}, status=200)
161
    app.get('/arcgis/test/district', params={'lon': 6.172122, 'lat': 48.673836}, status=200)
162
    assert ResourceLog.objects.count() == 2
163
    log = ResourceLog.objects.filter(appname='arcgis', slug='test').all()[1]
164
    assert len(log.extra['response']) == 20
165
    assert log.extra['from_cache'] == True
145 166

  
146 167
class FakeConnectorBase(object):
147 168
    slug = 'connector'
148
-