Skip to content

Instantly share code, notes, and snippets.

@Julien00859
Last active January 4, 2017 23:27
Show Gist options
  • Save Julien00859/7804527bf75ed1bd025bab0fa1228e27 to your computer and use it in GitHub Desktop.
Save Julien00859/7804527bf75ed1bd025bab0fa1228e27 to your computer and use it in GitHub Desktop.
Python logging handler for sqlite3
from sqlalchemy import Column, Integer, String, Numeric
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class Log(Base):
__tablename__ = "tb_log"
id = Column(Integer, primary_key=True)
created = Column(Numeric, nullable=False)
exc_text = Column(String, nullable=True)
filename = Column(String, nullable=False)
levelname = Column(String, nullable=False)
levelno = Column(Integer, nullable=False)
lineno = Column(Integer, nullable=False)
module = Column(String, nullable=False)
message = Column(String, nullable=False)
pathname = Column(String, nullable=False)
playerid = Column(Integer, nullable=True)
gameid = Column(Integer, nullable=True)
tickno = Column(Integer, nullable=True)
from logging import Handler
from queue import Queue
from threading import Thread
import sqlite3
class SQLiteHandler(Handler, Thread):
"""Logging handler for the SQLite3 database"""
create_statement = """CREATE TABLE IF NOT EXISTS {} (
created real,
exc_text text,
filename text,
funcName text,
levelname text,
levelno int,
lineno int,
module text,
message text,
name text,
pathname text
);"""
insert_statement = """INSERT INTO {} (
created,
exc_text,
filename,
funcName,
levelname,
levelno,
lineno,
module,
message,
name,
pathname
)
VALUES (
:created,
:exc_text,
:filename,
:funcName,
:levelname,
:levelno,
:lineno,
:module,
:message,
:name,
:pathname
);"""
def __init__(self, database, table):
Handler.__init__(self)
Thread.__init__(self)
# Save the args
self.database = database
self.table = table
# Create a queue with a sentinel
self.queue = Queue()
self.sentinel = object()
# Start the thread
self.start()
# override logging.Handler.emit
def emit(self, record):
"""Feed the queue with a record"""
if not hasattr(record, "message"):
record.message = self.format(record)
self.queue.put(record)
# override logging.Handler.close
def close(self):
"""Feed the queue with the sentinel and wait for the thread to stop"""
self.queue.put(self.sentinel)
self.join()
def run(self):
"""Consume the queue to insert the records in the database"""
# Insert the table in the templates
create_statement = self.create_statement.format(self.table)
insert_statement = self.insert_statement.format(self.table)
# Connect to db and create the table if it doesn't exists
conn = sqlite3.connect(self.database)
cur = conn.cursor()
cur.execute(create_statement)
conn.commit()
# Main loop
while True:
# Get a record or the sentinel
record = self.queue.get()
# If it's the sentinel, exit loop, commit and close db
if record is self.sentinel:
break
# Otherwise insert the record into the table
try:
cur.execute(insert_statement, record.__dict__)
except Exception as ex:
print(ex, record.__dict__)
self.queue.task_done()
cur.close()
conn.commit()
conn.close()
self.queue.task_done()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment