2011-04-10 7 views
11

Voglio salvare tutto ciò che può essere utilizzato per le statistiche, come ad esempio referrer, os, browser ecc. Cosa è disponibile e qual è il modo migliore per memorizzarlo?Django salva l'intera richiesta di statistiche, che cosa è disponibile?

Questo è importante solo per 1 applicazione (1 pagina) nel progetto, mentre nelle altre pagine verrà utilizzato un prodotto di analisi standard come google analytics.

Ho dato un'occhiata a django-tracking, ma sembra che questo sia eccessivo visto che voglio usarlo solo su 1 vista. La situazione ideale sarebbe passare l'intero oggetto della richiesta a un TaskQue e eseguire l'elaborazione in un secondo momento. Quindi l'utente viene reindirizzato per primo e l'elaborazione analitica verrà eseguita dietro le quinte.

risposta

12

Utilizziamo alcuni semplici middleware .. di seguito è riportato un estratto. È possibile modificarlo per utilizzare direttamente all'interno di una vista.

class WebRequest(models.Model): 
    time = models.DateTimeField(auto_now_add=True) 
    host = models.CharField(max_length=1000) 
    path = models.CharField(max_length=1000) 
    method = models.CharField(max_length=50) 
    uri = models.CharField(max_length=2000) 
    status_code = models.IntegerField() 
    user_agent = models.CharField(max_length=1000,blank=True,null=True) 
    remote_addr = models.IPAddressField() 
    remote_addr_fwd = models.IPAddressField(blank=True,null=True) 
    meta = models.TextField() 
    cookies = models.TextField(blank=True,null=True) 
    get = models.TextField(blank=True,null=True) 
    post = models.TextField(blank=True,null=True) 
    raw_post = models.TextField(blank=True,null=True) 
    is_secure = models.BooleanField() 
    is_ajax = models.BooleanField() 
    user = models.ForeignKey(User,blank=True,null=True) 

def dumps(value): 
    return json.dumps(value,default=lambda o:None) 

class WebRequestMiddleware(object): 
    def process_view(self, request, view_func, view_args, view_kwargs): 
     setattr(request,'hide_post',view_kwargs.pop('hide_post',False)) 


    def process_response(self, request, response): 

     if request.path.endswith('/favicon.ico'): 
      return response 

     if type(response) == HttpResponsePermanentRedirect and settings.APPEND_SLASH: 
      new_location = response.get('location',None) 
      content_length = response.get('content-length',None) 

      if new_location and content_length is '0': 
       new_parsed = urlparse(new_location) 

       old = (('http','https')[request.is_secure()], request.get_host(), '{0}/'.format(request.path), request.META['QUERY_STRING']) 
       new = (new_parsed.scheme, new_parsed.netloc, new_parsed.path, new_parsed.query) 

       if old == new: 
        #dont log - it's just adding a/
        return response 
     try: 
      self.save(request, response) 
     except Exception as e: 
      print >> sys.stderr, "Error saving request log", e 

     return response 

    def save(self, request, response): 
     if hasattr(request, 'user'): 
      user = request.user if type(request.user) == User else None 
     else: 
      user = None 

     meta = request.META.copy() 
     meta.pop('QUERY_STRING',None) 
     meta.pop('HTTP_COOKIE',None) 
     remote_addr_fwd = None 

     if 'HTTP_X_FORWARDED_FOR' in meta: 
      remote_addr_fwd = meta['HTTP_X_FORWARDED_FOR'].split(",")[0].strip() 
      if remote_addr_fwd == meta['HTTP_X_FORWARDED_FOR']: 
       meta.pop('HTTP_X_FORWARDED_FOR') 

     post = None 
     uri = request.build_absolute_uri() 
     if request.POST and uri != '/login/': 
      post = dumps(request.POST) 

     models.WebRequest(
      host = request.get_host(), 
      path = request.path, 
      method = request.method, 
      uri = request.build_absolute_uri(), 
      status_code = response.status_code, 
      user_agent = meta.pop('HTTP_USER_AGENT',None), 
      remote_addr = meta.pop('REMOTE_ADDR',None), 
      remote_addr_fwd = remote_addr_fwd, 
      meta = None if not meta else dumps(meta), 
      cookies = None if not request.COOKIES else dumps(request.COOKIES), 
      get = None if not request.GET else dumps(request.GET), 
      post = None if (not request.POST or getattr(request,'hide_post') == True) else dumps(request.POST), 
      raw_post = None if getattr(request,'hide_post') else request.raw_post_data, 
      is_secure = request.is_secure(), 
      is_ajax = request.is_ajax(), 
      user = user 
     ).save() 
+0

Grazie questo è sorprendente il codice. Mi farà risparmiare un sacco di lavoro! Solo una domanda sui modelli. Stai usando MySQL? Questo creerà VARCHAR (1000)? Basta dare un'occhiata alla documentazione qui: http://docs.djopoproject.com/en/dev/ref/databases/#notes-on-specific-fields –

+0

In realtà utilizziamo Oracle, quindi il campo di testo (se questo è quello che tu? riferimento a) è un NLOB. –

+0

Mi riferivo a host = models.CharField (max_length = 1000). Inoltre perché copi esplicitamente il META? meta = request.META.copy() –

1

Estrarre manualmente dalla richiesta.

I documenti delinea molte delle informazioni che è possibile estrarre dall'oggetto richiesta.

Per esempio, le intestazioni sono memorizzati in request.META, GET params in request.GET, ecc
http://docs.djangoproject.com/en/dev/ref/request-response/#django.http.HttpRequest.META

Qual è il modo migliore per conservarlo? Dipende da cosa stai facendo. Registralo, salvalo in un DB, invialo da qualche altra parte ... Dici per le statistiche, quindi un database sembra un buon posto dove metterlo, poiché è facile interrogarlo.

+0

Quale database MySQL o MongoDB come i dati saranno enormi? O più database MySQL, uno specifico per la memorizzazione dei dati delle richieste? –

0

Risposta estensione a Josh, è possibile utilizzare JSONField per i dati dei post se si utilizza Postgres come back-end. Aiuterà a gestire direttamente JSON piuttosto che caricarlo manualmente.

saperne di più: https://docs.djangoproject.com/en/2.0/ref/contrib/postgres/fields/#jsonfield

si potrebbe fare qualcosa di simile

from django.contrib.postgres.fields import JSONField 

class WebRequest(models.Model): 
    post = JSONField(default=dict)