~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/logging_query/logging_query.cc

  • Committer: Brian Aker
  • Date: 2010-10-22 17:44:34 UTC
  • mto: This revision was merged to the branch mainline in revision 1873.
  • Revision ID: brian@tangent.org-20101022174434-q8fjovcpclzqer7n
TableShare is no longer in the house (i.e. we no longer directly have a copy
of it in cursor).

One more bit of the knot now gone.

Show diffs side-by-side

added added

removed removed

Lines of Context:
41
41
#define ESCAPE_CHAR      '\\'
42
42
#define SEPARATOR_CHAR   ','
43
43
 
44
 
namespace drizzle_plugin
45
 
{
46
 
 
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;
 
51
 
 
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 */
 
55
 
 
56
static uint64_t get_microtime()
 
57
{
 
58
#if defined(HAVE_GETHRTIME)
 
59
  return gethrtime()/1000;
 
60
#else
 
61
  uint64_t newtime;
 
62
  struct timeval t;
 
63
  /*
 
64
    The following loop is here because gettimeofday may fail on some systems
 
65
  */
 
66
  while (gettimeofday(&t, NULL) != 0) {}
 
67
  newtime= (uint64_t)t.tv_sec * 1000000 + t.tv_usec;
 
68
  return newtime;
 
69
#endif  /* defined(HAVE_GETHRTIME) */
 
70
}
52
71
 
53
72
/* quote a string to be safe to include in a CSV line
54
73
   that means backslash quoting all commas, doublequotes, backslashes,
143
162
 
144
163
class Logging_query: public drizzled::plugin::Logging
145
164
{
146
 
  const std::string _filename;
147
 
  const std::string _query_pcre;
148
165
  int fd;
149
166
  pcre *re;
150
167
  pcre_extra *pe;
154
171
 
155
172
public:
156
173
 
157
 
  Logging_query(const std::string &filename,
158
 
                const std::string &query_pcre) :
159
 
    drizzled::plugin::Logging("Logging_query"),
160
 
    _filename(filename),
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")
 
174
  Logging_query()
 
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")
165
179
  {
166
180
 
167
181
    /* if there is no destination filename, dont bother doing anything */
168
 
    if (_filename.empty())
 
182
    if (sysvar_logging_query_filename == NULL)
169
183
      return;
170
184
 
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);
174
188
    if (fd < 0)
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"),
179
 
                    _filename.c_str(),
 
193
                    sysvar_logging_query_filename,
180
194
                    errmsg);
181
195
      return;
182
196
    }
183
197
 
184
 
    if (not _query_pcre.empty())
 
198
    if (sysvar_logging_query_pcre != NULL)
185
199
    {
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)
231
245
      return 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)
233
247
      return false;
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)
235
249
      return false;
236
250
 
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 */
240
254
  
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();
244
 
 
245
 
    if ((t_mark - session->start_utime) < (sysvar_logging_query_threshold_slow.get()))
 
255
    uint64_t t_mark= get_microtime();
 
256
  
 
257
    if ((t_mark - session->start_utime) < (sysvar_logging_query_threshold_slow))
246
258
      return false;
247
259
 
248
 
    Session::QueryString query_string(session->getQueryString());
249
260
    if (re)
250
261
    {
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)
254
265
        return false;
255
266
    }
259
270
    
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());
263
274
    
264
 
    quotify(*query_string, qs);
 
275
    quotify(session->getQueryString(), qs);
265
276
    
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();
269
279
 
270
280
    formatter % t_mark
271
281
              % session->thread_id
293
303
  }
294
304
};
295
305
 
 
306
static Logging_query *handler= NULL;
 
307
 
296
308
static int logging_query_plugin_init(drizzled::module::Context &context)
297
309
{
298
310
 
299
311
  const module::option_map &vm= context.getOptions();
300
 
 
301
 
  if (vm.count("filename") > 0)
302
 
  {
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));
311
 
  }
 
312
  if (vm.count("threshold-slow"))
 
313
  {
 
314
    if (sysvar_logging_query_threshold_slow > UINT32_MAX)
 
315
    {
 
316
      errmsg_printf(ERRMSG_LVL_ERROR, _("Invalid value for threshold-slow"));
 
317
      exit(-1);
 
318
    }
 
319
  }
 
320
 
 
321
  if (vm.count("threshold-big-resultset"))
 
322
  {
 
323
    if (sysvar_logging_query_threshold_big_resultset > UINT32_MAX)
 
324
    {
 
325
      errmsg_printf(ERRMSG_LVL_ERROR, _("Invalid value for threshold-big-resultset"));
 
326
      exit(-1);
 
327
    }
 
328
  }
 
329
 
 
330
  if (vm.count("threshold-big-examined"))
 
331
  {
 
332
    if (sysvar_logging_query_threshold_big_examined > UINT32_MAX)
 
333
    {
 
334
      errmsg_printf(ERRMSG_LVL_ERROR, _("Invalid value for threshold-big-examined"));
 
335
      exit(-1);
 
336
    }
 
337
  }
 
338
  handler= new Logging_query();
 
339
  context.add(handler);
312
340
 
313
341
  return 0;
314
342
}
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"));
321
 
  context("filename",
322
 
          po::value<string>(),
323
 
          N_("File to log to"));
324
 
  context("pcre",
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"));
336
358
}
337
359
 
338
 
} /* namespace drizzle_plugin */
 
360
static DRIZZLE_SYSVAR_BOOL(
 
361
  enable,
 
362
  sysvar_logging_query_enable,
 
363
  PLUGIN_VAR_NOCMDARG,
 
364
  N_("Enable logging to CSV file"),
 
365
  NULL, /* check func */
 
366
  NULL, /* update func */
 
367
  false /* default */);
 
368
 
 
369
static DRIZZLE_SYSVAR_STR(
 
370
  filename,
 
371
  sysvar_logging_query_filename,
 
372
  PLUGIN_VAR_READONLY,
 
373
  N_("File to log to"),
 
374
  NULL, /* check func */
 
375
  NULL, /* update func*/
 
376
  NULL /* default */);
 
377
 
 
378
static DRIZZLE_SYSVAR_STR(
 
379
  pcre,
 
380
  sysvar_logging_query_pcre,
 
381
  PLUGIN_VAR_READONLY,
 
382
  N_("PCRE to match the query against"),
 
383
  NULL, /* check func */
 
384
  NULL, /* update func*/
 
385
  NULL /* default */);
 
386
 
 
387
static DRIZZLE_SYSVAR_ULONG(
 
388
  threshold_slow,
 
389
  sysvar_logging_query_threshold_slow,
 
390
  PLUGIN_VAR_OPCMDARG,
 
391
  N_("Threshold for logging slow queries, in microseconds"),
 
392
  NULL, /* check func */
 
393
  NULL, /* update func */
 
394
  0, /* default */
 
395
  0, /* min */
 
396
  UINT32_MAX, /* max */
 
397
  0 /* blksiz */);
 
398
 
 
399
static DRIZZLE_SYSVAR_ULONG(
 
400
  threshold_big_resultset,
 
401
  sysvar_logging_query_threshold_big_resultset,
 
402
  PLUGIN_VAR_OPCMDARG,
 
403
  N_("Threshold for logging big queries, for rows returned"),
 
404
  NULL, /* check func */
 
405
  NULL, /* update func */
 
406
  0, /* default */
 
407
  0, /* min */
 
408
  UINT32_MAX, /* max */
 
409
  0 /* blksiz */);
 
410
 
 
411
static DRIZZLE_SYSVAR_ULONG(
 
412
  threshold_big_examined,
 
413
  sysvar_logging_query_threshold_big_examined,
 
414
  PLUGIN_VAR_OPCMDARG,
 
415
  N_("Threshold for logging big queries, for rows examined"),
 
416
  NULL, /* check func */
 
417
  NULL, /* update func */
 
418
  0, /* default */
 
419
  0, /* min */
 
420
  UINT32_MAX, /* max */
 
421
  0 /* blksiz */);
 
422
 
 
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),
 
430
  NULL
 
431
};
339
432
 
340
433
DRIZZLE_DECLARE_PLUGIN
341
434
{
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,
349
 
  NULL,
350
 
  drizzle_plugin::init_options
 
441
  logging_query_plugin_init,
 
442
  logging_query_system_variables,
 
443
  init_options
351
444
}
352
445
DRIZZLE_DECLARE_PLUGIN_END;