28
28
static char* logging_query_filename= NULL;
29
29
static bool logging_query_enable= true;
30
static ulong logging_query_enable_time= 0;
30
static ulong logging_query_threshold_slow= 0;
31
31
static ulong logging_query_threshold_big_resultset= 0;
32
static ulong logging_query_threshold_big_examined= 0;
35
// copied from drizzled/sql_parse.cc
36
const LEX_STRING command_name[]={
37
{ C_STRING_WITH_LEN("Sleep") },
38
{ C_STRING_WITH_LEN("Quit") },
39
{ C_STRING_WITH_LEN("InitDB") },
40
{ C_STRING_WITH_LEN("Query") },
41
{ C_STRING_WITH_LEN("FieldList") },
42
{ C_STRING_WITH_LEN("CreateDB") },
43
{ C_STRING_WITH_LEN("DropDB") },
44
{ C_STRING_WITH_LEN("Refresh") },
45
{ C_STRING_WITH_LEN("Shutdown") },
46
{ C_STRING_WITH_LEN("Processlist") },
47
{ C_STRING_WITH_LEN("Connect") },
48
{ C_STRING_WITH_LEN("Kill") },
49
{ C_STRING_WITH_LEN("Ping") },
50
{ C_STRING_WITH_LEN("Time") },
51
{ C_STRING_WITH_LEN("ChangeUser") },
52
{ C_STRING_WITH_LEN("BinlogDump") },
53
{ C_STRING_WITH_LEN("ConnectOut") },
54
{ C_STRING_WITH_LEN("RegisterSlave") },
55
{ C_STRING_WITH_LEN("SetOption") },
56
{ C_STRING_WITH_LEN("Daemon") },
57
{ C_STRING_WITH_LEN("Error") }
61
36
/* stolen from mysys/my_getsystime
62
37
until the Session has a good utime "now" we can use
63
38
will have to use this instead */
79
54
#endif /* defined(HAVE_GETHRTIME) */
57
/* quote a string to be safe to include in a CSV line
58
that means backslash quoting all commas, doublequotes, backslashes,
59
and all the ASCII unprintable characters
60
as long as we pass the high-bit bytes unchanged
61
this is safe to do to a UTF8 string
62
we have to be careful about overrunning the targetbuffer
63
or else a very long query can overwrite memory
65
TODO consider remapping the unprintables instead to "Printable
66
Representation", the Unicode characters from the area U+2400 to
67
U+2421 reserved for representing control characters when it is
68
necessary to print or display them rather than have them perform
69
their intended function.
73
static unsigned char *quotify (const unsigned char *src, size_t srclen,
74
unsigned char *dst, size_t dstlen)
76
static char hexit[]= { '0', '1', '2', '3', '4', '5', '6', '7',
77
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
78
size_t dst_ndx; /* index down the dst */
79
size_t src_ndx; /* index down the src */
84
for (dst_ndx=0,src_ndx=0; src_ndx<srclen; src_ndx++)
87
/* Worst case, need 5 dst bytes for the next src byte.
88
backslash x hexit hexit null
89
so if not enough room, just terminate the string and return
91
if ((dstlen - dst_ndx) < 5)
93
dst[dst_ndx]= (unsigned char) 0x00;
97
if (src[src_ndx] > 0x7f)
99
// pass thru high bit characters, they are non-ASCII UTF8 Unicode
100
dst[dst_ndx++]= src[src_ndx];
102
else if (src[src_ndx] == 0x00) // null
104
dst[dst_ndx++]= 0x5C; dst[dst_ndx++]= (unsigned char) '0';
106
else if (src[src_ndx] == 0x07) // bell
108
dst[dst_ndx++]= 0x5C; dst[dst_ndx++]= (unsigned char) 'a';
110
else if (src[src_ndx] == 0x08) // backspace
112
dst[dst_ndx++]= 0x5C; dst[dst_ndx++]= (unsigned char) 'b';
114
else if (src[src_ndx] == 0x09) // horiz tab
116
dst[dst_ndx++]= 0x5C; dst[dst_ndx++]= (unsigned char) 't';
118
else if (src[src_ndx] == 0x0a) // line feed
120
dst[dst_ndx++]= 0x5C; dst[dst_ndx++]= (unsigned char) 'n';
122
else if (src[src_ndx] == 0x0b) // vert tab
124
dst[dst_ndx++]= 0x5C; dst[dst_ndx++]= (unsigned char) 'v';
126
else if (src[src_ndx] == 0x0c) // formfeed
128
dst[dst_ndx++]= 0x5C; dst[dst_ndx++]= (unsigned char) 'f';
130
else if (src[src_ndx] == 0x0d) // carrage return
132
dst[dst_ndx++]= 0x5C; dst[dst_ndx++]= (unsigned char) 'r';
134
else if (src[src_ndx] == 0x1b) // escape
136
dst[dst_ndx++]= 0x5C; dst[dst_ndx++]= (unsigned char) 'e';
138
else if (src[src_ndx] == 0x22) // quotation mark
140
dst[dst_ndx++]= 0x5C; dst[dst_ndx++]= 0x22;
142
else if (src[src_ndx] == 0x2C) // comma
144
dst[dst_ndx++]= 0x5C; dst[dst_ndx++]= 0x2C;
146
else if (src[src_ndx] == 0x5C) // backslash
148
dst[dst_ndx++]= 0x5C; dst[dst_ndx++]= 0x5C;
150
else if ((src[src_ndx] < 0x20) || (src[src_ndx] == 0x7F)) // other unprintable ASCII
152
dst[dst_ndx++]= 0x5C;
153
dst[dst_ndx++]= (unsigned char) 'x';
154
dst[dst_ndx++]= hexit[(src[src_ndx] >> 4) & 0x0f];
155
dst[dst_ndx++]= hexit[src[src_ndx] & 0x0f];
157
else // everything else
159
dst[dst_ndx++]= src[src_ndx];
82
167
/* we could just not have a pre entrypoint at all,
83
168
and have logging_pre == NULL
84
169
but we have this here for the sake of being an example */
93
178
int msgbuf_len= 0;
96
if (fd < 0) return false;
98
181
assert(session != NULL);
101
here is some time stuff from class Session
102
uint64_t connect_utime;
103
todo, looks like this isnt being set
104
we could store the time this plugin was loaded
105
but that would just be a dumb workaround
106
uint64_t start_utime;
107
uint64_t utime_after_lock;
108
uint64_t current_utime();
109
todo, cant get to because of namemangling
112
/* todo, the Session should have a "utime command completed" inside
113
itself, so be more accurate, and so plugins dont have to keep
114
calling current_utime, which can be slow */
186
/* Yes, we know that checking logging_query_enable,
187
logging_query_threshold_big_resultset, and
188
logging_query_threshold_big_examined is not threadsafe, because some
189
other thread might change these sysvars. But we don't care. We
190
might start logging a little late as it spreads to other threads.
193
// return if not enabled or query was too fast or resultset was too small
194
if (logging_query_enable == false)
196
if (session->sent_row_count < logging_query_threshold_big_resultset)
198
if (session->examined_row_count < logging_query_threshold_big_examined)
201
// logging this is far too verbose
202
if (session->command == COM_FIELD_LIST)
205
/* TODO, looks like connect_utime isnt being set in the session
206
object. We could store the time this plugin was loaded, but that
207
would just be a dumb workaround. */
208
/* TODO, the session object should have a "utime command completed"
209
inside itself, so be more accurate, and so this doesnt have to
210
keep calling current_utime, which can be slow */
115
212
uint64_t t_mark= get_microtime();
214
if ((t_mark - session->start_utime) < (logging_query_threshold_slow)) return false;
216
// buffer to quotify the query
217
unsigned char qs[255];
118
220
snprintf(msgbuf, MAX_MSG_LEN,
119
"thread_id=%ld query_id=%ld"
120
" t_connect=%lld t_start=%lld t_lock=%lld"
122
" rows_sent=%ld rows_examined=%u\n"
123
" db=\"%.*s\" query=\"%.*s\"\n",
221
"%lld,%ld,%ld,\"%.*s\",\"%s\",\"%.*s\",%lld,%lld,%lld,%ld,%ld\n",
222
(unsigned long long) t_mark,
124
223
(unsigned long) session->thread_id,
125
224
(unsigned long) session->query_id,
126
(unsigned long long)(t_mark - session->connect_utime),
127
(unsigned long long)(t_mark - session->start_utime),
128
(unsigned long long)(t_mark - session->utime_after_lock),
129
(uint32_t)command_name[session->command].length,
225
// dont need to quote the db name, always CSV safe
226
session->db_length, session->db,
227
// do need to quote the query
228
(char *) quotify((unsigned char *) session->query, session->query_length,
230
// command_name is defined in drizzled/sql_parse.cc
231
// dont need to quote the command name, always CSV safe
232
(int) command_name[session->command].length,
130
233
command_name[session->command].str,
234
// counters are at end, to make it easier to add more
235
(unsigned long long) (t_mark - session->connect_utime),
236
(unsigned long long) (t_mark - session->start_utime),
237
(unsigned long long) (t_mark - session->utime_after_lock),
131
238
(unsigned long) session->sent_row_count,
132
(uint32_t) session->examined_row_count,
133
session->db_length, session->db,
134
session->query_length, session->query);
135
/* a single write has a OS level thread lock
136
so there is no need to have mutexes guarding this write,
239
(unsigned long) session->examined_row_count);
242
// a single write has a kernel thread lock, thus no need mutex guard this
138
243
wrv= write(fd, msgbuf, msgbuf_len);
139
244
assert(wrv == msgbuf_len);