forked from onemoretime/mySQLHandler
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmySQLHandler.py
More file actions
244 lines (221 loc) · 6.86 KB
/
mySQLHandler.py
File metadata and controls
244 lines (221 loc) · 6.86 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
# -*- coding: utf-8 -*-
'''
Created on 02/01/2014
'''
import MySQLdb
import _mysql_exceptions
import logging
import time
import six
class mySQLHandler(logging.Handler):
"""
Logging handler for MySQL.
Based on Vinay Sajip's DBHandler class (http://www.red-dove.com/python_logging.html)
forked from ykessler/gae_handler.py (https://gist.github.com/ykessler/2662203)
<from ykessler/gae_handler.py>
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.
</from>
<from onemoretime>
please see:
https://github.com/onemoretime/mySQLHandler for more up-to-date version
README.md
LICENSE
</from>
@todo: create SQL table if necessary, try/except when execute sql, ...
@author: "onemoretime"
@copyright: "Copyright 2014, onemoretime"
@license: "WTFPL."
@version: "0.1"
@contact: "onemoretime"
@email: "onemoretime@cyber.world.universe"
@status: "Alpha"
"""
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):
"""
Constructor
@param db: ['host','port','dbuser', 'dbpassword', 'dbname']
@return: mySQLHandler
"""
logging.Handler.__init__(self)
self.db = db
# Try to connect to DB
# Check if 'log' table in db already exists
result = self.checkTablePresence()
# If not exists, then create the table
if not result:
try:
conn=MySQLdb.connect(host=self.db['host'],port=self.db['port'],user=self.db['dbuser'],passwd=self.db['dbpassword'],db=self.db['dbname'])
except _mysql_exceptions, e:
raise Exception(e)
exit(-1)
else:
cur = conn.cursor()
try:
cur.execute(mySQLHandler.initial_sql)
except _mysql_exceptions as e:
conn.rollback()
cur.close()
conn.close()
raise Exception(e)
exit(-1)
else:
conn.commit()
finally:
cur.close()
conn.close()
def checkTablePresence(self):
try:
conn=MySQLdb.connect(host=self.db['host'],port=self.db['port'],user=self.db['dbuser'],passwd=self.db['dbpassword'],db=self.db['dbname'])
except _mysql_exceptions, e:
raise Exception(e)
exit(-1)
else:
# Check if 'log' table in db already exists
cur = conn.cursor()
stmt = "SHOW TABLES LIKE 'log';"
cur.execute(stmt)
result = cur.fetchone()
cur.close()
conn.close()
if not result:
return 0
else:
return 1
def createTableLog(self):
pass
def formatDBTime(self, record):
"""
Time formatter
@param record:
@return: nothing
"""
record.dbtime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(record.created))
def emit(self, record):
"""
Connect to DB, execute SQL Request, disconnect from DB
@param record:
@return:
"""
# 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:
try:
conn=MySQLdb.connect(host=self.db['host'],port=self.db['port'],user=self.db['dbuser'],passwd=self.db['dbpassword'],db=self.db['dbname'])
except _mysql_exceptions, e:
from pprint import pprint
print("The Exception during db.connect")
pprint(e)
raise Exception(e)
exit(-1)
# escape the message to allow for SQL special chars
if isinstance(record.msg, six.string_types):# check is a string
record.msg=conn.escape_string(record.msg)
sql = mySQLHandler.insertion_sql % record.__dict__
cur = conn.cursor()
try:
cur.execute(sql)
except _mysql_exceptions.ProgrammingError as e:
errno, errstr = e.args
if not errno == 1146:
raise
cur.close() # close current cursor
cur = conn.cursor() # recreate it (is it mandatory?)
try: # try to recreate table
cur.execute(mySQLHandler.initial_sql)
except _mysql_exceptions as e:
# definitly can't work...
conn.rollback()
cur.close()
conn.close()
raise Exception(e)
exit(-1)
else: # if recreate log table is ok
conn.commit()
cur.close()
cur = conn.cursor()
cur.execute(sql)
conn.commit()
# then Exception vanished
except _mysql_exceptions, e:
conn.rollback()
cur.close()
conn.close()
raise Exception(e)
exit(-1)
else:
conn.commit()
finally:
cur.close()
conn.close()
def main():
def print_all_log(oLog):
# Print all log levels
oLog.debug('debug')
oLog.info('info')
oLog.warning('warning')
oLog.error('error')
oLog.critical('critical')
logger = logging.getLogger('simple_example')
logger.setLevel(logging.DEBUG)
db = {'host':'localhost', 'port': 3306, 'dbuser':'logger', 'dbpassword':'loggerpasswd', 'dbname':'logger'}
sqlh = mySQLHandler(db)
logger.addHandler(sqlh)
# In main Thread
print_all_log(logger)
if __name__ == '__main__':
main()