Last active
January 4, 2017 23:27
-
-
Save Julien00859/7804527bf75ed1bd025bab0fa1228e27 to your computer and use it in GitHub Desktop.
Python logging handler for sqlite3
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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