41
41
#define ESCAPE_CHAR '\\'
42
42
#define SEPARATOR_CHAR ','
44
namespace drizzle_plugin
47
44
static bool sysvar_logging_query_enable= false;
45
static char* sysvar_logging_query_filename= NULL;
46
static char* sysvar_logging_query_pcre= NULL;
48
47
/* TODO fix these to not be unsigned long once we have sensible sys_var system */
49
static uint32_constraint sysvar_logging_query_threshold_slow;
50
static uint32_constraint sysvar_logging_query_threshold_big_resultset;
51
static uint32_constraint sysvar_logging_query_threshold_big_examined;
48
static unsigned long sysvar_logging_query_threshold_slow= 0;
49
static unsigned long sysvar_logging_query_threshold_big_resultset= 0;
50
static unsigned long sysvar_logging_query_threshold_big_examined= 0;
52
/* stolen from mysys/my_getsystime
53
until the Session has a good utime "now" we can use
54
will have to use this instead */
56
static uint64_t get_microtime()
58
#if defined(HAVE_GETHRTIME)
59
return gethrtime()/1000;
64
The following loop is here because gettimeofday may fail on some systems
66
while (gettimeofday(&t, NULL) != 0) {}
67
newtime= (uint64_t)t.tv_sec * 1000000 + t.tv_usec;
69
#endif /* defined(HAVE_GETHRTIME) */
53
72
/* quote a string to be safe to include in a CSV line
54
73
that means backslash quoting all commas, doublequotes, backslashes,
157
Logging_query(const std::string &filename,
158
const std::string &query_pcre) :
159
drizzled::plugin::Logging("Logging_query"),
161
_query_pcre(query_pcre),
162
fd(-1), re(NULL), pe(NULL),
163
formatter("%1%,%2%,%3%,\"%4%\",\"%5%\",\"%6%\",%7%,%8%,"
164
"%9%,%10%,%11%,%12%,%13%,%14%,\"%15%\"\n")
175
: drizzled::plugin::Logging("Logging_query"),
176
fd(-1), re(NULL), pe(NULL),
177
formatter("%1%,%2%,%3%,\"%4%\",\"%5%\",\"%6%\",%7%,%8%,"
178
"%9%,%10%,%11%,%12%,%13%,%14%,\"%15%\"\n")
167
181
/* if there is no destination filename, dont bother doing anything */
168
if (_filename.empty())
182
if (sysvar_logging_query_filename == NULL)
171
fd= open(_filename.c_str(),
185
fd= open(sysvar_logging_query_filename,
172
186
O_WRONLY | O_APPEND | O_CREAT,
173
187
S_IRUSR|S_IWUSR);
176
190
char errmsg[STRERROR_MAX];
177
191
strerror_r(errno, errmsg, sizeof(errmsg));
178
192
errmsg_printf(ERRMSG_LVL_ERROR, _("fail open() fn=%s er=%s\n"),
193
sysvar_logging_query_filename,
184
if (not _query_pcre.empty())
198
if (sysvar_logging_query_pcre != NULL)
186
200
const char *this_pcre_error;
187
201
int this_pcre_erroffset;
188
re= pcre_compile(_query_pcre.c_str(), 0, &this_pcre_error,
202
re= pcre_compile(sysvar_logging_query_pcre, 0, &this_pcre_error,
189
203
&this_pcre_erroffset, NULL);
190
204
pe= pcre_study(re, 0, &this_pcre_error);
191
205
/* TODO emit error messages if there is a problem */
229
243
// return if not enabled or query was too fast or resultset was too small
230
244
if (sysvar_logging_query_enable == false)
232
if (session->sent_row_count < sysvar_logging_query_threshold_big_resultset.get())
246
if (session->sent_row_count < sysvar_logging_query_threshold_big_resultset)
234
if (session->examined_row_count < sysvar_logging_query_threshold_big_examined.get())
248
if (session->examined_row_count < sysvar_logging_query_threshold_big_examined)
237
251
/* TODO, the session object should have a "utime command completed"
238
252
inside itself, so be more accurate, and so this doesnt have to
239
253
keep calling current_utime, which can be slow */
241
boost::posix_time::ptime mytime(boost::posix_time::microsec_clock::local_time());
242
boost::posix_time::ptime epoch(boost::gregorian::date(1970,1,1));
243
uint64_t t_mark= (mytime-epoch).total_microseconds();
245
if ((t_mark - session->start_utime) < (sysvar_logging_query_threshold_slow.get()))
255
uint64_t t_mark= get_microtime();
257
if ((t_mark - session->start_utime) < (sysvar_logging_query_threshold_slow))
248
Session::QueryString query_string(session->getQueryString());
251
262
int this_pcre_rc;
252
this_pcre_rc= pcre_exec(re, pe, query_string->c_str(), query_string->length(), 0, 0, NULL, 0);
263
this_pcre_rc= pcre_exec(re, pe, session->query.c_str(), session->query.length(), 0, 0, NULL, 0);
253
264
if (this_pcre_rc < 0)
260
271
// Since quotify() builds the quoted string incrementally, we can
261
272
// avoid some reallocating if we reserve some space up front.
262
qs.reserve(query_string->length());
273
qs.reserve(session->getQueryLength());
264
quotify(*query_string, qs);
275
quotify(session->getQueryString(), qs);
266
277
// to avoid trying to printf %s something that is potentially NULL
267
util::string::const_shared_ptr schema(session->schema());
268
const char *dbs= (schema and not schema->empty()) ? schema->c_str() : "";
278
const char *dbs= session->db.empty() ? "" : session->db.c_str();
270
280
formatter % t_mark
271
281
% session->thread_id
306
static Logging_query *handler= NULL;
296
308
static int logging_query_plugin_init(drizzled::module::Context &context)
299
311
const module::option_map &vm= context.getOptions();
301
if (vm.count("filename") > 0)
303
context.add(new Logging_query(vm["filename"].as<string>(),
304
vm["pcre"].as<string>()));
305
context.registerVariable(new sys_var_bool_ptr("enable", &sysvar_logging_query_enable));
306
context.registerVariable(new sys_var_const_string_val("filename", vm["filename"].as<string>()));
307
context.registerVariable(new sys_var_const_string_val("pcre", vm["pcre"].as<string>()));
308
context.registerVariable(new sys_var_constrained_value<uint32_t>("threshold_slow", sysvar_logging_query_threshold_slow));
309
context.registerVariable(new sys_var_constrained_value<uint32_t>("threshold_big_resultset", sysvar_logging_query_threshold_big_resultset));
310
context.registerVariable(new sys_var_constrained_value<uint32_t>("threshold_big_examined", sysvar_logging_query_threshold_big_examined));
312
if (vm.count("threshold-slow"))
314
if (sysvar_logging_query_threshold_slow > UINT32_MAX)
316
errmsg_printf(ERRMSG_LVL_ERROR, _("Invalid value for threshold-slow"));
321
if (vm.count("threshold-big-resultset"))
323
if (sysvar_logging_query_threshold_big_resultset > UINT32_MAX)
325
errmsg_printf(ERRMSG_LVL_ERROR, _("Invalid value for threshold-big-resultset"));
330
if (vm.count("threshold-big-examined"))
332
if (sysvar_logging_query_threshold_big_examined > UINT32_MAX)
334
errmsg_printf(ERRMSG_LVL_ERROR, _("Invalid value for threshold-big-examined"));
338
handler= new Logging_query();
339
context.add(handler);
318
346
context("enable",
319
347
po::value<bool>(&sysvar_logging_query_enable)->default_value(false)->zero_tokens(),
320
348
N_("Enable logging to CSV file"));
323
N_("File to log to"));
325
po::value<string>()->default_value(""),
326
N_("PCRE to match the query against"));
327
349
context("threshold-slow",
328
po::value<uint32_constraint>(&sysvar_logging_query_threshold_slow)->default_value(0),
350
po::value<unsigned long>(&sysvar_logging_query_threshold_slow)->default_value(0),
329
351
N_("Threshold for logging slow queries, in microseconds"));
330
352
context("threshold-big-resultset",
331
po::value<uint32_constraint>(&sysvar_logging_query_threshold_big_resultset)->default_value(0),
353
po::value<unsigned long>(&sysvar_logging_query_threshold_big_resultset)->default_value(0),
332
354
N_("Threshold for logging big queries, for rows returned"));
333
355
context("threshold-big-examined",
334
po::value<uint32_constraint>(&sysvar_logging_query_threshold_big_examined)->default_value(0),
356
po::value<unsigned long>(&sysvar_logging_query_threshold_big_examined)->default_value(0),
335
357
N_("Threshold for logging big queries, for rows examined"));
338
} /* namespace drizzle_plugin */
360
static DRIZZLE_SYSVAR_BOOL(
362
sysvar_logging_query_enable,
364
N_("Enable logging to CSV file"),
365
NULL, /* check func */
366
NULL, /* update func */
367
false /* default */);
369
static DRIZZLE_SYSVAR_STR(
371
sysvar_logging_query_filename,
373
N_("File to log to"),
374
NULL, /* check func */
375
NULL, /* update func*/
378
static DRIZZLE_SYSVAR_STR(
380
sysvar_logging_query_pcre,
382
N_("PCRE to match the query against"),
383
NULL, /* check func */
384
NULL, /* update func*/
387
static DRIZZLE_SYSVAR_ULONG(
389
sysvar_logging_query_threshold_slow,
391
N_("Threshold for logging slow queries, in microseconds"),
392
NULL, /* check func */
393
NULL, /* update func */
396
UINT32_MAX, /* max */
399
static DRIZZLE_SYSVAR_ULONG(
400
threshold_big_resultset,
401
sysvar_logging_query_threshold_big_resultset,
403
N_("Threshold for logging big queries, for rows returned"),
404
NULL, /* check func */
405
NULL, /* update func */
408
UINT32_MAX, /* max */
411
static DRIZZLE_SYSVAR_ULONG(
412
threshold_big_examined,
413
sysvar_logging_query_threshold_big_examined,
415
N_("Threshold for logging big queries, for rows examined"),
416
NULL, /* check func */
417
NULL, /* update func */
420
UINT32_MAX, /* max */
423
static drizzle_sys_var* logging_query_system_variables[]= {
424
DRIZZLE_SYSVAR(enable),
425
DRIZZLE_SYSVAR(filename),
426
DRIZZLE_SYSVAR(pcre),
427
DRIZZLE_SYSVAR(threshold_slow),
428
DRIZZLE_SYSVAR(threshold_big_resultset),
429
DRIZZLE_SYSVAR(threshold_big_examined),
340
433
DRIZZLE_DECLARE_PLUGIN
345
438
"Mark Atwood <mark@fallenpegasus.com>",
346
439
N_("Log queries to a CSV file"),
347
440
PLUGIN_LICENSE_GPL,
348
drizzle_plugin::logging_query_plugin_init,
350
drizzle_plugin::init_options
441
logging_query_plugin_init,
442
logging_query_system_variables,
352
445
DRIZZLE_DECLARE_PLUGIN_END;