<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>custom &#8211; James Lin&#039;s Blog</title>
	<atom:link href="https://james.lin.net.nz/tag/custom/feed/" rel="self" type="application/rss+xml" />
	<link>https://james.lin.net.nz</link>
	<description>Just bits and pieces of my life</description>
	<lastBuildDate>Fri, 19 Jan 2018 22:42:50 +0000</lastBuildDate>
	<language>en-NZ</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=4.9.2</generator>
<site xmlns="com-wordpress:feed-additions:1">22801464</site>	<item>
		<title>Creating custom log handler that logs to database models in django</title>
		<link>https://james.lin.net.nz/2012/09/19/creating-custom-log-handler-that-logs-to-database-models-in-django/</link>
		<comments>https://james.lin.net.nz/2012/09/19/creating-custom-log-handler-that-logs-to-database-models-in-django/#respond</comments>
		<pubDate>Wed, 19 Sep 2012 02:31:50 +0000</pubDate>
		<dc:creator><![CDATA[James Lin]]></dc:creator>
				<category><![CDATA[Django]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[custom]]></category>
		<category><![CDATA[database]]></category>
		<category><![CDATA[django]]></category>
		<category><![CDATA[handler]]></category>
		<category><![CDATA[log]]></category>
		<category><![CDATA[model]]></category>

		<guid isPermaLink="false">http://james.lin.net.nz/?p=1221</guid>
		<description><![CDATA[I was told to create some kind of logging mechanism to insert logs into database, and make sure it&#8217;s generic. So after some thought I decided to mimic the builtin RotatingFileHandler and write a DBHandler. The RotatingFileHandler allows you to specify which file to write to and rotate files, therefore my DBHandler should also allow… <span class="read-more"><a href="https://james.lin.net.nz/2012/09/19/creating-custom-log-handler-that-logs-to-database-models-in-django/">Read More &#187;</a></span>]]></description>
				<content:encoded><![CDATA[<p>I was told to create some kind of logging mechanism to insert logs into database, and make sure it&#8217;s generic. So after some thought I decided to mimic the builtin RotatingFileHandler and write a DBHandler.</p>
<p>The RotatingFileHandler allows you to specify which file to write to and rotate files, therefore my DBHandler should also allow you to specify which model to insert to and specify expiry in settings, and best of all, on a standalone app.</p>
<p>My implementation uses a separate database for logging, which needs have a router like this:</p><pre class="crayon-plain-tag">class LogRouter(object):
    def db_for_read(self, model, **hints):
        if model._meta.app_label == 'logger':
            return 'logger'
        return None

    def db_for_write(self, model, **hints):
        if model._meta.app_label == 'logger':
            return 'logger'
        return None

    def allow_syncdb(self, db, model):
        if db == 'logger':
            return model._meta.app_label == 'logger'
        elif model._meta.app_label == 'logger':
            return False
        return None</pre><p>of course you need to tell settings you have 2 databases like this:</p><pre class="crayon-plain-tag">DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
        'NAME': '',                      # Or path to database file if using sqlite3.
        'USER': '',                      # Not used with sqlite3.
        'PASSWORD': '',                  # Not used with sqlite3.
        'HOST': '',                      # Set to empty string for localhost. Not used with sqlite3.
        'PORT': '',                      # Set to empty string for default. Not used with sqlite3.
    },
    'logger': {
        'ENGINE': 'django.db.backends.mysql', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
        'NAME': '',                      # Or path to database file if using sqlite3.
        'USER': '',                      # Not used with sqlite3.
        'PASSWORD': '',                  # Not used with sqlite3.
        'HOST': '',                      # Set to empty string for localhost. Not used with sqlite3.
        'PORT': '',                      # Set to empty string for default. Not used with sqlite3.
    }
}</pre><p>and we need to create some models:</p><pre class="crayon-plain-tag">from django.db import models

class DBLogEntry(models.Model):
    time = models.DateTimeField(auto_now_add=True)
    level = models.CharField(max_length=10)
    message = models.TextField()

    class Meta:
        abstract = True

class GeneralLog(DBLogEntry):
    pass

class SpeicalLog(DBLogEntry):
    pass</pre><p>then we need to create a custom handler, call logging.handlers.DBHandler</p><pre class="crayon-plain-tag">rom logging import Handler
from django.utils import timezone
import json, datetime, random

class DBHandler(Handler,object):
    &quot;&quot;&quot;
    This handler will add logs to a database model defined in settings.py
    If log message (pre-format) is a json string, it will try to apply the array onto the log event object
    &quot;&quot;&quot;

    model_name = None
    expiry = None

    def __init__(self, model=&quot;&quot;, expiry=0):
        super(DBHandler,self).__init__()
        self.model_name = model
        self.expiry = int(expiry)

    def emit(self,record):
        # big try block here to exit silently if exception occurred
        try:
            # instantiate the model
            try:
                model = self.get_model(self.model_name)
            except:
                from logger.models import GeneralLog as model

            log_entry = model(level=record.levelname, message=self.format(record))

            # test if msg is json and apply to log record object
            try:
                data = json.loads(record.msg)
                for key,value in data.items():
                    if hasattr(log_entry,key):
                        try:
                            setattr(log_entry,key,value)
                        except:
                            pass
            except:
                pass

            log_entry.save()

            # in 20% of time, check and delete expired logs
            if self.expiry and random.randint(1,5) == 1:
                model.objects.filter(time__lt = timezone.now() - datetime.timedelta(seconds=self.expiry)).delete()
        except:
            pass

    def get_model(self, name):
        names = name.split('.')
        mod = __import__('.'.join(names[:-1]), fromlist=names[-1:])
        return getattr(mod, names[-1])</pre><p>and go back to settings to specify the custom handler to log stuff like this</p><pre class="crayon-plain-tag">'handlers':{
    'log_db':{
            'level': 'INFO',
            'class': 'logger.handlers.DBHandler',
            'model': 'logger.models.SpecialLog',
            'expiry': 86400,
            'formatter': 'verbose',
            },
    }</pre><p></p>
]]></content:encoded>
			<wfw:commentRss>https://james.lin.net.nz/2012/09/19/creating-custom-log-handler-that-logs-to-database-models-in-django/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	<post-id xmlns="com-wordpress:feed-additions:1">1221</post-id>	</item>
	</channel>
</rss>
