#-*- coding: utf-8 -*- from django.conf import settings import thread,threading, time, random, base64, time, os, datetime, gzip from xml.dom.minidom import Document from django.db import connection class LoggingActivities(threading.Thread): """ Author: Julian Moritz, public@julianmoritz.de This middleware is logging the website-activities on your django-project-website. It does NOT save the users' ip-addresses (according to german law) but a unique ID for each user. Once added to your MIDDLEWARE_CLASSES, you can control it via 3 variables in your settings.py: - STATS_LOGDIR - the directory-name where it puts the logfiles into (default: logs) - STATS_BUFFER - the file-buffer-size in bytes for your logfile (default: 10MB) - STATS_TIME - the time the logfile is flushed to disk (default: 12 hours) Note: At the moment there is now import to database and evaluating script written. I will do this in time. License: http://creativecommons.org/licenses/by/2.0/de/deed.en_GB Output: Have a look at http://www.julianmoritz.de/dl/logs.xml """ def __init__(self): threading.Thread.__init__(self) try: l = settings.STATS_LOGDIR except: l = "logs" if not os.path.isdir(l): os.mkdir(l) try: b = settings.STATS_BUFFER except: b = 1024*1024*10 try: t = settings.STATS_TIME except: t = 60*60*12 self.buffer = b self.logdir = l self.time = t self.lock = thread.allocate_lock() self.__rand_id = base64.b64encode(str(random.random())) fname = base64.b64encode(str(random.random())) + ".xml" self.logfile = open(os.path.join(self.logdir, fname), "w", self.buffer) self.xmldoc = Document() self.logs = self.xmldoc.createElement("logs") self.xmldoc.appendChild(self.logs) self.start() def process_request(self,request): request.STATS = {} request.STATS["start"] = datetime.datetime.now() return None def process_view(self, request, view, args, kwargs): request.STATS["view_name"] = view.__name__ return None def process_excepton(self,request,exception): self.log_request(request,exception) return None def process_response(self,request,response): self.log_request(request) return response def log_request(self,request,exception=None): id = base64.b64encode(str(random.random())) now = int(time.mktime(datetime.datetime.now().timetuple())) try: start = request.STATS["start"] stop = datetime.datetime.now() diff = (stop - start) diffsecs = diff.seconds + diff.microseconds/1000000. except: diffsecs = 0. try: view_name = request.STATS["view_name"] except: view_name = "" user_agent = request.META["HTTP_USER_AGENT"] user_enc = request.META["HTTP_ACCEPT_ENCODING"] user_lang = request.META["HTTP_ACCEPT_LANGUAGE"] full_path = request.get_full_path() abs_uri = request.build_absolute_uri() query_count = len(connection.queries) user_id = base64.b64encode(self.__rand_id + request.META["REMOTE_ADDR"]) if exception == None: exc_msg = "" else: exc_msg = str(exception) xml_dict = {"timestamp":now, "user_id":user_id, "duration":diffsecs, "view":view_name, "http_user_agent":user_agent, "http_accept_encoding":user_enc, "http_accept_language":user_lang, "full_path":full_path, "absolute_uri":abs_uri, "query_count":query_count, "exception":exc_msg, } #create xml self.lock.acquire() log = self.xmldoc.createElement("log") log.setAttribute("id",id) for k in xml_dict: e = self.xmldoc.createElement(k) v = self.xmldoc.createTextNode(str(xml_dict[k])) e.appendChild(v) log.appendChild(e) self.logs.appendChild(log) self.lock.release() def run(self): while(True): try: #it's bedtime now! time.sleep(self.time) self.lock.acquire() #write xml to file self.xmldoc.writexml(self.logfile,indent="\t", addindent="\t", newl="\n") #flush and close file self.logfile.flush() self.logfile.close() #create new empty xml-document self.xmldoc = Document() self.logs = self.xmldoc.createElement("logs") self.xmldoc.appendChild(self.logs) #create new empty log-file oldfilename = self.logfile.name fname = base64.b64encode(str(random.random())) + ".xml" self.logfile = open(os.path.join(self.logdir, fname), "w", self.buffer) #finished writing self.lock.release() #gzip old file and delete the old xml-file r_file = open(oldfilename, 'r') w_file = gzip.GzipFile(oldfilename + '.gz', 'w', 9) w_file.write(r_file.read()) w_file.flush() w_file.close() r_file.close() os.unlink(oldfilename) except Exception, e: if self.lock.locked(): self.lock.release() break