Skip to content

Commit

Permalink
Initial Commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Alex Lovell-Troy committed Jun 24, 2013
0 parents commit 2387f3f
Show file tree
Hide file tree
Showing 7 changed files with 169 additions and 0 deletions.
28 changes: 28 additions & 0 deletions LICENSE.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
Copyright (c) 2013, Alex Lovell-Troy
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:

* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* Neither the name of the author nor the names of other
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# django-telemetry
## Record and Store all your own data

There are many external analytics packages that can tell you about your users in aggregate. We like [Google Analytics](http://google.com/analytics) for that. To store information about requests along with the users who made them, we like django-telemetry.

### Async operation with celery

If you are running a celery task queue, recording of the views in the database can be separated from the actual request.

### Middleware vs Decorator vs Mixin

Depending on your performance needs, telemetry can be recorded at different points in the request/response cycle. Middleware plays nicely with most kinds of caching and is easiest to set up. You probably want that.

If you really want to exert more control, the Mixin and Decorator are provided
Empty file added telemetry/__init__.py
Empty file.
9 changes: 9 additions & 0 deletions telemetry/middleware.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from .models import add_request


class RecordRequestMiddleware(object):
def process_request(self, request):
try:
add_request(request)
except:
pass
101 changes: 101 additions & 0 deletions telemetry/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import datetime
from django.utils.timezone import utc
from django.db import models
from django.conf import settings

# Create your models here.

class UserAgent(models.Model):
http_user_agent = models.TextField(max_length=255, unique=True)
is_spider = models.BooleanField(default=False)
first_seen = models.DateTimeField(auto_now_add=True)

@property
def request_count(self):
return len(self.requests_set.all())


class HttpReferer(models.Model):
http_referer = models.UrlField(max_length=512, unique=True)
first_seen = models.DateTimeField(auto_now_add=True)

@property
def request_count(self):
return len(self.requests_set.all())


class LiveRequestManager(models.Manager):
def get_queryset(self):
return super(LiveRequestManager, self).get_queryset().filter(http_referer__is_spider=False)


class SpiderRequestManager(models.Manager):
def get_queryset(self):
return super(SpiderRequestManager, self).get_queryset().filter(http_referer__is_spider=True)


class Request(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, default=None)
http_user_agent = models.ForeignKey(UserAgent, null=True, default=None)
http_referer = models.ForeigKey(HttpReferer, null=True, default=None)
timestamp = models.DateTimeField(auto_now_add=True)
path = models.CharField(max_length=256)
remote_addr = models.CharField(max_length=256)
server_name = models.CharField(max_length=256)
by_people = LiveRequestManager()
by_spider = SpiderRequestManager()


def add_request(request):
# grab things from the request object
tx_add_request(
path = request.path,
http_user_agent = request.META['HTTP_USER_AGENT'],
http_referer = request.META['HTTP_REFERER'],
remote_addr = request.META['REMOTE_ADDR'],
server_name = request.META['SERVER_NAME'],
timestamp = datetime.datetime.utcnow().replace(tzinfo=utc)
)


def tx_add_request(path=None,
user=None,
http_user_agent=None,
http_referer=None,
remote_addr=None,
server_name=None,
timestamp=None):
"""Made to be run within a transaction so that it all succeeds or fails together """
if not path:
return None
if http_user_agent.strip():
useragent = UserAgent.objects.get_or_create(http_user_agent=http_user_agent)
else:
useragent = None
if http_referer.strip():
referer = HttpReferer.objects.get_or_create(http_referer=http_referer)
else:
referer = None

create_dict = dict(
user = user,
http_user_agent = useragent,
http_referer = referer,
path = path
)

if remote_addr:
create_dict.update(dict(
remote_addr = remote_addr
))
if server_name:
create_dict.update(dict(
server_name = server_name
))
if timestamp:
create_dict.update(dict(
timestamp = timestamp
))

return Request.objects.create(**create_dict)

16 changes: 16 additions & 0 deletions telemetry/tests.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
"""
This file demonstrates writing tests using the unittest module. These will pass
when you run "manage.py test".
Replace this with more appropriate tests for your application.
"""

from django.test import TestCase


class SimpleTest(TestCase):
def test_basic_addition(self):
"""
Tests that 1 + 1 always equals 2.
"""
self.assertEqual(1 + 1, 2)
1 change: 1 addition & 0 deletions telemetry/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Create your views here.

0 comments on commit 2387f3f

Please # to comment.