Skip to content

Instantly share code, notes, and snippets.

@ykessler
Created May 11, 2012 20:23
Show Gist options
  • Star 30 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save ykessler/2662203 to your computer and use it in GitHub Desktop.
Save ykessler/2662203 to your computer and use it in GitHub Desktop.
Python logging handlers
class GAEHandler(logging.Handler):
"""
Logging handler for GAE DataStore
"""
def emit(self, record):
from google.appengine.ext import db
class Log(db.Model):
name = db.StringProperty()
level = db.StringProperty()
module = db.StringProperty()
func_name = db.StringProperty()
line_no = db.IntegerProperty()
thread = db.IntegerProperty()
thread_name = db.StringProperty()
process = db.IntegerProperty()
message = db.StringProperty(multiline=True)
args = db.StringProperty(multiline=True)
date = db.DateTimeProperty(auto_now_add=True)
log = Log()
log.name = record.name
log.level = record.levelname
log.module = record.module
log.func_name = record.funcName
log.line_no = record.lineno
log.thread = record.thread
log.thread_name = record.threadName
log.process = record.process
log.message = record.msg
log.args = str(record.args)
log.put()
import sqlite3
import logging
import time
class SQLiteHandler(logging.Handler):
"""
Logging handler for SQLite.
Based on Vinay Sajip's DBHandler class (http://www.red-dove.com/python_logging.html)
This version sacrifices performance for thread-safety:
Instead of using a persistent cursor, we open/close connections for each entry.
AFAIK this is necessary in multi-threaded applications,
because SQLite doesn't allow access to objects across threads.
"""
initial_sql = """CREATE TABLE IF NOT EXISTS log(
Created text,
Name text,
LogLevel int,
LogLevelName text,
Message text,
Args text,
Module text,
FuncName text,
LineNo int,
Exception text,
Process int,
Thread text,
ThreadName text
)"""
insertion_sql = """INSERT INTO log(
Created,
Name,
LogLevel,
LogLevelName,
Message,
Args,
Module,
FuncName,
LineNo,
Exception,
Process,
Thread,
ThreadName
)
VALUES (
'%(dbtime)s',
'%(name)s',
%(levelno)d,
'%(levelname)s',
'%(msg)s',
'%(args)s',
'%(module)s',
'%(funcName)s',
%(lineno)d,
'%(exc_text)s',
%(process)d,
'%(thread)s',
'%(threadName)s'
);
"""
def __init__(self, db='app.db'):
logging.Handler.__init__(self)
self.db = db
# Create table if needed:
conn = sqlite3.connect(self.db)
conn.execute(SQLiteHandler.initial_sql)
conn.commit()
def formatDBTime(self, record):
record.dbtime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(record.created))
def emit(self, record):
# Use default formatting:
self.format(record)
# Set the database time up:
self.formatDBTime(record)
if record.exc_info:
record.exc_text = logging._defaultFormatter.formatException(record.exc_info)
else:
record.exc_text = ""
# Insert log record:
sql = SQLiteHandler.insertion_sql % record.__dict__
conn = sqlite3.connect(self.db)
conn.execute(sql)
conn.commit()
@alistair-broomhead
Copy link

be aware that the string formatting method you use is incredibly brittle, and leaves you open to SQL injection - I have adapted the SQL code here to use SQL parameters: https://github.com/alistair-broomhead/pymiproxy/blob/master/src/miproxy/handlers.py

@maanas
Copy link

maanas commented Oct 27, 2013

That correct. It will cause code to break. I switch to parametisation but args is creating a problem

@jorge-lavin
Copy link

@dhruvAgarwal2173
Copy link

This may be a very naive doubt but what is 'record' here? What is it's type?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment