2011-04-10 5 views
11

Quiero guardar todo lo que se puede usar para las estadísticas, como referencia, sistema operativo, navegador, etc. ¿Qué hay disponible y cuál es la mejor manera de almacenarlo?Django guardando toda la solicitud de estadísticas, ¿qué hay disponible?

Esto solo es importante para 1 aplicación (1 página) en el proyecto, las otras páginas se usará algún producto de análisis estándar como Google Analytics.

He echado un vistazo a django-tracking, pero parece que es excesivo ya que solo quiero usarlo en 1 vista. La situación ideal sería pasar el objeto de solicitud completo a un TaskQue y hacer el procesamiento más tarde. Por lo tanto, primero se redirige al usuario y el procesamiento analítico se realizará tras bastidores.

Respuesta

12

Usamos algunos middleware simples .. a continuación se muestra un extracto. Puede modificarlo para usar directamente dentro de 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

Gracias esto es increíble el código. Me ahorrará mucho trabajo! Solo una pregunta sobre los modelos. ¿Estás usando MySQL? ¿Esto creará VARCHAR (1000)? Acabo de echar un vistazo a la documentación aquí: http://docs.djangoproject.com/en/dev/ref/databases/#notes-on-specific-fields –

+0

En realidad usamos Oracle, por lo que el TextField (si eso es lo que ' refiriéndose a) es un NLOB. –

+0

Me refería a host = models.CharField (max_length = 1000). Además, ¿por qué copias explícitamente el META? meta = request.META.copy() –

1

Simplemente sáquelo manualmente de la solicitud.

Los documentos describen una gran cantidad de la información que se puede extraer del objeto de solicitud.

Por ejemplo, los encabezados se almacenan en request.META, GET params en request.GET, etc.
http://docs.djangoproject.com/en/dev/ref/request-response/#django.http.HttpRequest.META

¿Cuál es la mejor manera de almacenarlo? Depende de lo que estés haciendo. Regístrelo, guárdelo en un DB, envíelo a otro lugar ... Usted dice que para las estadísticas, por lo que una base de datos parece un buen lugar para poner esto, ya que es fácil de consultar.

+0

¿Qué base de datos MySQL o MongoDB serán enormes? ¿O una base de datos MySQL múltiple, una específicamente para almacenar datos de solicitud? –

0

Extensión a la respuesta de Josh, puede utilizar JSONField para los datos de la publicación si está utilizando postgres como su back-end. Ayudará a tratar directamente con json en lugar de cargarlo manualmente.

Leer más: https://docs.djangoproject.com/en/2.0/ref/contrib/postgres/fields/#jsonfield

que podría hacer algo como esto

from django.contrib.postgres.fields import JSONField 

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