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
20
/* need to define DRIZZLE_SERVER to get inside the Session */
21
#define DRIZZLE_SERVER 1
22
#include <drizzled/server_includes.h>
23
#include <drizzled/plugin_logging.h>
24
#include <drizzled/gettext.h>
25
#include <drizzled/session.h>
27
/* todo, make this dynamic as needed */
28
#define MAX_MSG_LEN (32*1024)
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;
37
// copied from drizzled/sql_parse.cc
38
const LEX_STRING command_name[]={
39
{ C_STRING_WITH_LEN("Sleep") },
40
{ C_STRING_WITH_LEN("Quit") },
41
{ C_STRING_WITH_LEN("InitDB") },
42
{ C_STRING_WITH_LEN("Query") },
43
{ C_STRING_WITH_LEN("FieldList") },
44
{ C_STRING_WITH_LEN("CreateDB") },
45
{ C_STRING_WITH_LEN("DropDB") },
46
{ C_STRING_WITH_LEN("Refresh") },
47
{ C_STRING_WITH_LEN("Shutdown") },
48
{ C_STRING_WITH_LEN("Processlist") },
49
{ C_STRING_WITH_LEN("Connect") },
50
{ C_STRING_WITH_LEN("Kill") },
51
{ C_STRING_WITH_LEN("Ping") },
52
{ C_STRING_WITH_LEN("Time") },
53
{ C_STRING_WITH_LEN("ChangeUser") },
54
{ C_STRING_WITH_LEN("BinlogDump") },
55
{ C_STRING_WITH_LEN("ConnectOut") },
56
{ C_STRING_WITH_LEN("RegisterSlave") },
57
{ C_STRING_WITH_LEN("SetOption") },
58
{ C_STRING_WITH_LEN("Daemon") },
59
{ C_STRING_WITH_LEN("Error") }
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()
70
#if defined(HAVE_GETHRTIME)
71
return gethrtime()/1000;
76
The following loop is here because gettimeofday may fail on some systems
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)))
92
bool logging_query_func_post (Session *session)
94
char msgbuf[MAX_MSG_LEN];
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();
120
snprintf(msgbuf, MAX_MSG_LEN,
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);
137
/* a single write has a OS level thread lock
138
so there is no need to have mutexes guarding this write,
140
wrv= write(fd, msgbuf, msgbuf_len);
141
assert(wrv == msgbuf_len);
146
static int logging_query_plugin_init(void *p)
148
logging_t *l= (logging_t *) p;
150
if (logging_query_filename == NULL)
152
/* no destination filename was specified via system variables
153
return now, dont set the callback pointers
158
fd= open(logging_query_filename, O_WRONLY | O_APPEND | O_CREAT,
162
sql_print_error(_("fail open() fn=%s er=%s\n"),
163
logging_query_filename,
167
we should return an error here, so the plugin doesnt load
168
but this causes Drizzle to crash
169
so until that is fixed,
170
just return a success,
171
but leave the function pointers as NULL and the fd as -1
176
l->logging_pre= logging_query_func_pre;
177
l->logging_post= logging_query_func_post;
182
static int logging_query_plugin_deinit(void *p)
184
logging_st *l= (logging_st *) p;
192
l->logging_pre= NULL;
193
l->logging_post= NULL;
198
static DRIZZLE_SYSVAR_STR(
200
logging_query_filename,
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 */
268
static struct st_mysql_sys_var* logging_query_system_variables[]= {
269
DRIZZLE_SYSVAR(filename),
270
DRIZZLE_SYSVAR(enable),
271
DRIZZLE_SYSVAR(enable_time),
272
DRIZZLE_SYSVAR(threshold_big_resultset),
276
mysql_declare_plugin(logging_query)
278
DRIZZLE_LOGGER_PLUGIN,
281
"Mark Atwood <mark@fallenpegasus.com>",
282
N_("Log queries to a file"),
284
logging_query_plugin_init,
285
logging_query_plugin_deinit,
286
NULL, /* status variables */
287
logging_query_system_variables,
290
mysql_declare_plugin_end;