From 90f47509f9eefae9c1ba8e2530dabaeab1a4eaa7 Mon Sep 17 00:00:00 2001 From: Andy Doan Date: Thu, 14 Aug 2014 12:13:08 -0500 Subject: api: make metric logging more robust The old method required too much manual intervention to prevent log files from growing too large. This makes the API cleaner and allows it to rotate logs on its own. Change-Id: Ib7dd9dd17b748cf2fed7b186bcd84c661ee552e5 --- license_protected_downloads/models.py | 16 ++++++++++++ license_protected_downloads/uploads.py | 47 +++++++--------------------------- 2 files changed, 25 insertions(+), 38 deletions(-) diff --git a/license_protected_downloads/models.py b/license_protected_downloads/models.py index 35ac098..22f61ca 100644 --- a/license_protected_downloads/models.py +++ b/license_protected_downloads/models.py @@ -31,3 +31,19 @@ class License(models.Model): class APIKeyStore(models.Model): key = models.CharField(max_length=80) public = models.BooleanField() + + +class APILog(models.Model): + timestamp = models.DateTimeField(auto_now_add=True) + # we are on an old version of django missing an ipv6 friendly field + # so just use a charfield to keep it simple + ip = models.CharField(max_length=40) + key = models.ForeignKey(APIKeyStore, blank=True, null=True) + label = models.CharField(max_length=32) + path = models.CharField(max_length=256) + + @staticmethod + def mark(request, label, key=None): + ip = request.META.get('REMOTE_ADDR') + ip = request.META.get('HTTP_X_FORWARDED_FOR', ip).split(',')[0] + APILog.objects.create(label=label, ip=ip, path=request.path, key=key) diff --git a/license_protected_downloads/uploads.py b/license_protected_downloads/uploads.py index b04c791..5cc6fa1 100644 --- a/license_protected_downloads/uploads.py +++ b/license_protected_downloads/uploads.py @@ -1,9 +1,6 @@ -import io -import fcntl import os import random import shutil -import time from django.views.decorators.csrf import csrf_exempt from django.http import ( @@ -13,32 +10,8 @@ from django.http import ( ) from django.conf import settings -from models import APIKeyStore -from common import safe_path_join - - -def _client_ip(request): - x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR') - if x_forwarded_for: - return x_forwarded_for.split(',')[0] - return request.META.get('REMOTE_ADDR') - - -def _log_metric(request, name, fields=None): - """Store information on a given API call. - - This allows us to get some understanding of how this API is being used. - """ - with open('/tmp/llp-stats.txt', 'a') as f: - try: - fcntl.flock(f, fcntl.LOCK_EX) - f.seek(0, io.SEEK_END) - f.write('%s: %s: %s: ' % (time.time(), _client_ip(request), name)) - if fields is not None: - f.write(','.join(fields)) - f.write('\n') - finally: - fcntl.flock(f, fcntl.LOCK_UN) +from license_protected_downloads.models import APIKeyStore, APILog +from license_protected_downloads.common import safe_path_join def upload_target_path(path, key, public): @@ -66,21 +39,19 @@ def file_server_post(request, path): """ if not ("key" in request.POST and APIKeyStore.objects.filter(key=request.POST["key"])): - _log_metric(request, 'INVALID_KEY', [path]) + APILog.mark(request, 'INVALID_KEY') return HttpResponseServerError("Invalid key") - api_key = APIKeyStore.objects.filter(key=request.POST["key"]) + api_key = APIKeyStore.objects.get(key=request.POST["key"]) if 'file' not in request.FILES or not path: - _log_metric(request, 'INVALID_ARGUMENTS', - [str(request.FILES.keys()), path, request.POST['key']]) + APILog.mark(request, 'INVALID_ARGUMENTS', api_key) return HttpResponseServerError("Invalid call") - _log_metric(request, 'FILE_UPLOAD', - [path, str(api_key[0].public), request.POST['key']]) + APILog.mark(request, 'FILE_UPLOAD', api_key) path = upload_target_path( - path, request.POST["key"], public=api_key[0].public) + path, request.POST["key"], public=api_key.public) # Create directory if required dirname = os.path.dirname(path) @@ -95,7 +66,7 @@ def file_server_post(request, path): def api_request_key(request): - _log_metric(request, 'REQUEST_KEY') + APILog.mark(request, 'REQUEST_KEY') if("key" in request.GET and request.GET["key"] == settings.MASTER_API_KEY and settings.MASTER_API_KEY): @@ -121,7 +92,7 @@ def api_request_key(request): def api_delete_key(request): - _log_metric(request, 'DELETE_KEY') + APILog.mark(request, 'DELETE_KEY') if "key" not in request.GET: return HttpResponseServerError("Invalid key") -- cgit v1.2.3