1
/* drizzle/plugin/logging_query/logging_query.cc */
1
/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2
* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
4
* Copyright (C) 2008 Mark Atwood
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; version 2 of the License.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program; if not, write to the Free Software
17
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
3
/* need to define DRIZZLE_SERVER to get inside the THD */
20
/* need to define DRIZZLE_SERVER to get inside the Session */
4
21
#define DRIZZLE_SERVER 1
5
22
#include <drizzled/server_includes.h>
6
23
#include <drizzled/plugin_logging.h>
24
#include <drizzled/gettext.h>
25
#include <drizzled/session.h>
27
/* todo, make this dynamic as needed */
8
28
#define MAX_MSG_LEN (32*1024)
10
30
static char* logging_query_filename= NULL;
31
static bool logging_query_enable= true;
32
static ulong logging_query_enable_time= 0;
33
static ulong logging_query_threshold_big_resultset= 0;
14
37
// copied from drizzled/sql_parse.cc
16
38
const LEX_STRING command_name[]={
17
39
{ C_STRING_WITH_LEN("Sleep") },
18
40
{ C_STRING_WITH_LEN("Quit") },
41
bool logging_query_func_pre (THD *thd)
63
/* stolen from mysys/my_getsystime
64
until the Session has a good utime "now" we can use
65
will have to use this instead */
68
static uint64_t get_microtime()
43
char msgbuf[MAX_MSG_LEN];
53
snprintf(msgbuf, MAX_MSG_LEN,
54
"log bgn thread_id=%ld query_id=%ld command=%.*s"
55
" db=\"%.*s\" query=\"%.*s\"\n",
56
(unsigned long) thd->thread_id,
57
(unsigned long) thd->query_id,
58
(uint32_t)command_name[thd->command].length, command_name[thd->command].str,
59
thd->db_length, thd->db,
60
thd->query_length, thd->query);
61
/* a single write has a OS level thread lock
62
so there is no need to have mutexes guarding this write,
70
#if defined(HAVE_GETHRTIME)
71
return gethrtime()/1000;
76
The following loop is here because gettimeofday may fail on some systems
64
wrv= write(fd, msgbuf, msgbuf_len);
65
assert(wrv == msgbuf_len);
78
while (gettimeofday(&t, NULL) != 0) {}
79
newtime= (uint64_t)t.tv_sec * 1000000 + t.tv_usec;
81
#endif /* defined(HAVE_GETHRTIME) */
84
/* we could just not have a pre entrypoint at all,
85
and have logging_pre == NULL
86
but we have this here for the sake of being an example */
87
bool logging_query_func_pre (Session *session __attribute__((unused)))
70
bool logging_query_func_post (THD *thd)
92
bool logging_query_func_post (Session *session)
72
94
char msgbuf[MAX_MSG_LEN];
76
98
if (fd < 0) return false;
100
assert(session != NULL);
103
here is some time stuff from class Session
104
uint64_t connect_utime;
105
todo, looks like this isnt being set
106
we could store the time this plugin was loaded
107
but that would just be a dumb workaround
108
uint64_t start_utime;
109
uint64_t utime_after_lock;
110
uint64_t current_utime();
111
todo, cant get to because of namemangling
114
/* todo, the Session should have a "utime command completed" inside
115
itself, so be more accurate, and so plugins dont have to keep
116
calling current_utime, which can be slow */
117
uint64_t t_mark= get_microtime();
81
120
snprintf(msgbuf, MAX_MSG_LEN,
82
"log end thread_id=%ld query_id=%ld command=%.*s"
83
" rows.sent=%ld rows.exam=%u\n",
84
(unsigned long) thd->thread_id,
85
(unsigned long) thd->query_id,
86
(uint32_t)command_name[thd->command].length, command_name[thd->command].str,
87
(unsigned long) thd->sent_row_count,
88
(uint32_t) thd->examined_row_count);
121
"thread_id=%ld query_id=%ld"
122
" t_connect=%lld t_start=%lld t_lock=%lld"
124
" rows_sent=%ld rows_examined=%u\n"
125
" db=\"%.*s\" query=\"%.*s\"\n",
126
(unsigned long) session->thread_id,
127
(unsigned long) session->query_id,
128
(unsigned long long)(t_mark - session->connect_utime),
129
(unsigned long long)(t_mark - session->start_utime),
130
(unsigned long long)(t_mark - session->utime_after_lock),
131
(uint32_t)command_name[session->command].length,
132
command_name[session->command].str,
133
(unsigned long) session->sent_row_count,
134
(uint32_t) session->examined_row_count,
135
session->db_length, session->db,
136
session->query_length, session->query);
89
137
/* a single write has a OS level thread lock
90
138
so there is no need to have mutexes guarding this write,
92
140
wrv= write(fd, msgbuf, msgbuf_len);
93
141
assert(wrv == msgbuf_len);
103
150
if (logging_query_filename == NULL)
105
152
/* no destination filename was specified via system variables
106
return now, dont set the callback pointers
153
return now, dont set the callback pointers
111
fd= open(logging_query_filename, O_WRONLY | O_APPEND | O_CREAT);
158
fd= open(logging_query_filename, O_WRONLY | O_APPEND | O_CREAT,
114
fprintf(stderr, "fail open fn=%s er=%s\n",
115
logging_query_filename,
162
sql_print_error(_("fail open() fn=%s er=%s\n"),
163
logging_query_filename,
118
/* we should return an error here, so the plugin doesnt load
167
we should return an error here, so the plugin doesnt load
119
168
but this causes Drizzle to crash
120
169
so until that is fixed,
121
170
just return a success,
149
static DRIZZLE_SYSVAR_STR(filename, logging_query_filename,
198
static DRIZZLE_SYSVAR_STR(
200
logging_query_filename,
150
201
PLUGIN_VAR_READONLY,
151
"File to log queries to.",
202
N_("File to log to"),
203
NULL, /* check func */
204
NULL, /* update func*/
207
static DRIZZLE_SYSVAR_BOOL(
209
logging_query_enable,
211
N_("Enable logging"),
212
NULL, /* check func */
213
NULL, /* update func */
216
static DRIZZLE_SYSVAR_ULONG(
218
logging_query_enable_time,
220
N_("Disable after this many seconds. Zero for forever"),
221
NULL, /* check func */
222
NULL, /* update func */
229
static DRIZZLE_SYSVAR_ULONG(
231
logging_query_threshold_slow,
233
N_("Threshold for logging slow queries, in microseconds"),
234
NULL, /* check func */
235
NULL, /* update func */
242
static DRIZZLE_SYSVAR_ULONG(
243
threshold_big_resultset,
244
logging_query_threshold_big_resultset,
246
N_("Threshold for logging big queries, for rows returned"),
247
NULL, /* check func */
248
NULL, /* update func */
255
static DRIZZLE_SYSVAR_ULONG(
256
threshhold_big_examined,
257
logging_query_threshold_big_examined,
259
N_("Threshold for logging big queries, for rows examined"),
260
NULL, /* check func */
261
NULL, /* update func */
154
268
static struct st_mysql_sys_var* logging_query_system_variables[]= {
155
269
DRIZZLE_SYSVAR(filename),
270
DRIZZLE_SYSVAR(enable),
271
DRIZZLE_SYSVAR(enable_time),
272
DRIZZLE_SYSVAR(threshold_big_resultset),