~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/logging_query/logging_query.cc

  • Committer: Brian Aker
  • Date: 2009-02-02 23:10:18 UTC
  • mfrom: (779.3.40 devel)
  • Revision ID: brian@tangent.org-20090202231018-zlp0hka6kgwy1vfy
Merge from Monty

Show diffs side-by-side

added added

removed removed

Lines of Context:
22
22
#include <drizzled/gettext.h>
23
23
#include <drizzled/session.h>
24
24
 
25
 
/* todo, make this dynamic as needed */
26
 
#define MAX_MSG_LEN (32*1024)
 
25
/* TODO make this dynamic as needed */
 
26
static const int MAX_MSG_LEN= 32*1024;
27
27
 
28
 
static char* logging_query_filename= NULL;
29
 
static bool logging_query_enable= true;
30
 
static ulong logging_query_threshold_slow= 0;
31
 
static ulong logging_query_threshold_big_resultset= 0;
32
 
static ulong logging_query_threshold_big_examined= 0;
 
28
static bool sysvar_logging_query_enable= false;
 
29
static char* sysvar_logging_query_filename= NULL;
 
30
/* TODO fix these to not be unsigned long one we have sensible sys_var system */
 
31
static unsigned long sysvar_logging_query_threshold_slow= 0;
 
32
static unsigned long sysvar_logging_query_threshold_big_resultset= 0;
 
33
static unsigned long sysvar_logging_query_threshold_big_examined= 0;
33
34
 
34
35
static int fd= -1;
35
36
 
59
60
   and all the ASCII unprintable characters
60
61
   as long as we pass the high-bit bytes unchanged
61
62
   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
 
63
   we dont allow overrunning the targetbuffer
 
64
   to avoid having a very long query overwrite memory
64
65
 
65
66
   TODO consider remapping the unprintables instead to "Printable
66
67
   Representation", the Unicode characters from the area U+2400 to
73
74
static unsigned char *quotify (const unsigned char *src, size_t srclen,
74
75
                               unsigned char *dst, size_t dstlen)
75
76
{
76
 
  static char hexit[]= { '0', '1', '2', '3', '4', '5', '6', '7',
 
77
  static const char hexit[]= { '0', '1', '2', '3', '4', '5', '6', '7',
77
78
                          '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 */
 
79
  size_t dst_ndx;  /* ndx down the dst */
 
80
  size_t src_ndx;  /* ndx down the src */
80
81
 
81
82
  assert(dst);
82
83
  assert(dstlen > 0);
83
84
 
84
 
  for (dst_ndx=0,src_ndx=0; src_ndx<srclen; src_ndx++)
 
85
  for (dst_ndx= 0,src_ndx= 0; src_ndx < srclen; src_ndx++)
85
86
  {
86
87
 
87
 
    /* Worst case, need 5 dst bytes for the next src byte. 
 
88
    /* Worst case, need 5 dst bytes for the next src byte.
88
89
       backslash x hexit hexit null
89
90
       so if not enough room, just terminate the string and return
90
91
    */
91
92
    if ((dstlen - dst_ndx) < 5)
92
93
    {
93
 
      dst[dst_ndx]= (unsigned char) 0x00;
 
94
      dst[dst_ndx]= (unsigned char)0x00;
94
95
      return dst;
95
96
    }
96
97
 
105
106
    }
106
107
    else if (src[src_ndx] == 0x07)  // bell
107
108
    {
108
 
      dst[dst_ndx++]= 0x5C; dst[dst_ndx++]=  (unsigned char) 'a';
 
109
      dst[dst_ndx++]= 0x5C; dst[dst_ndx++]= (unsigned char) 'a';
109
110
    }
110
111
    else if (src[src_ndx] == 0x08)  // backspace
111
112
    {
183
184
  if (fd < 0)
184
185
    return false;
185
186
 
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.
191
 
     Big deal. */
 
187
  /* Yes, we know that checking sysvar_logging_query_enable,
 
188
     sysvar_logging_query_threshold_big_resultset, and
 
189
     sysvar_logging_query_threshold_big_examined is not threadsafe,
 
190
     because some other thread might change these sysvars.  But we
 
191
     don't care.  We might start logging a little late as it spreads
 
192
     to other threads.  Big deal. */
192
193
 
193
194
  // return if not enabled or query was too fast or resultset was too small
194
 
  if (logging_query_enable == false)
195
 
    return false;
196
 
  if (session->sent_row_count < logging_query_threshold_big_resultset)
197
 
    return false;
198
 
  if (session->examined_row_count < logging_query_threshold_big_examined)
 
195
  if (sysvar_logging_query_enable == false)
 
196
    return false;
 
197
  if (session->sent_row_count < sysvar_logging_query_threshold_big_resultset)
 
198
    return false;
 
199
  if (session->examined_row_count < sysvar_logging_query_threshold_big_examined)
199
200
    return false;
200
201
 
201
202
  // logging this is far too verbose
211
212
 
212
213
  uint64_t t_mark= get_microtime();
213
214
 
214
 
  if ((t_mark - session->start_utime) < (logging_query_threshold_slow)) return false;
 
215
  if ((t_mark - session->start_utime) < (sysvar_logging_query_threshold_slow))
 
216
    return false;
215
217
 
216
218
  // buffer to quotify the query
217
219
  unsigned char qs[255];
218
220
 
 
221
  // to avoid trying to printf %s something that is potentially NULL
 
222
  const char *dbs= (session->db) ? session->db : "";
 
223
  int dbl= 0;
 
224
  if (dbs != NULL)
 
225
    dbl= session->db_length;
 
226
 
219
227
  msgbuf_len=
220
228
    snprintf(msgbuf, MAX_MSG_LEN,
221
 
             "%lld,%ld,%ld,\"%.*s\",\"%s\",\"%.*s\",%lld,%lld,%lld,%ld,%ld\n",
222
 
             (unsigned long long) t_mark,
223
 
             (unsigned long) session->thread_id,
224
 
             (unsigned long) session->query_id,
 
229
             "%"PRIu64",%"PRIu64",%"PRIu64",\"%.*s\",\"%s\",\"%.*s\","
 
230
             "%"PRIu64",%"PRIu64",%"PRIu64",%"PRIu64",%"PRIu64"\n",
 
231
             t_mark,
 
232
             session->thread_id,
 
233
             session->query_id,
225
234
             // dont need to quote the db name, always CSV safe
226
 
             session->db_length, session->db,
 
235
             dbl, dbs,
227
236
             // do need to quote the query
228
 
             (char *) quotify((unsigned char *) session->query, session->query_length,
229
 
                              qs, sizeof(qs)),
 
237
             quotify((unsigned char *)session->query,
 
238
                     session->query_length, qs, sizeof(qs)),
230
239
             // command_name is defined in drizzled/sql_parse.cc
231
240
             // dont need to quote the command name, always CSV safe
232
 
             (int) command_name[session->command].length,
 
241
             (int)command_name[session->command].length,
233
242
             command_name[session->command].str,
234
243
             // 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),
238
 
             (unsigned long) session->sent_row_count,
239
 
             (unsigned long) session->examined_row_count);
 
244
             (t_mark - session->connect_utime),
 
245
             (t_mark - session->start_utime),
 
246
             (t_mark - session->utime_after_lock),
 
247
             session->sent_row_count,
 
248
             session->examined_row_count);
240
249
 
241
250
 
242
251
  // a single write has a kernel thread lock, thus no need mutex guard this
248
257
 
249
258
static int logging_query_plugin_init(void *p)
250
259
{
251
 
  logging_t *l= (logging_t *) p;
 
260
  logging_t *l= static_cast<logging_t *>(p);
252
261
 
253
 
  if (logging_query_filename == NULL)
 
262
  if (sysvar_logging_query_filename == NULL)
254
263
  {
255
264
    /* no destination filename was specified via system variables
256
265
       return now, dont set the callback pointers
258
267
    return 0;
259
268
  }
260
269
 
261
 
  fd= open(logging_query_filename,
 
270
  fd= open(sysvar_logging_query_filename,
262
271
           O_WRONLY | O_APPEND | O_CREAT,
263
272
           S_IRUSR|S_IWUSR);
264
273
  if (fd < 0)
265
274
  {
266
275
    errmsg_printf(ERRMSG_LVL_ERROR, _("fail open() fn=%s er=%s\n"),
267
 
                  logging_query_filename,
 
276
                  sysvar_logging_query_filename,
268
277
                  strerror(errno));
269
278
 
270
279
    /* TODO
299
308
  return 0;
300
309
}
301
310
 
 
311
static DRIZZLE_SYSVAR_BOOL(
 
312
  enable,
 
313
  sysvar_logging_query_enable,
 
314
  PLUGIN_VAR_NOCMDARG,
 
315
  N_("Enable logging to CSV file"),
 
316
  NULL, /* check func */
 
317
  NULL, /* update func */
 
318
  false /* default */);
 
319
 
302
320
static DRIZZLE_SYSVAR_STR(
303
321
  filename,
304
 
  logging_query_filename,
 
322
  sysvar_logging_query_filename,
305
323
  PLUGIN_VAR_READONLY,
306
324
  N_("File to log to"),
307
325
  NULL, /* check func */
308
326
  NULL, /* update func*/
309
327
  NULL /* default */);
310
328
 
311
 
static DRIZZLE_SYSVAR_BOOL(
312
 
  enable,
313
 
  logging_query_enable,
314
 
  PLUGIN_VAR_NOCMDARG,
315
 
  N_("Enable logging"),
316
 
  NULL, /* check func */
317
 
  NULL, /* update func */
318
 
  true /* default */);
319
 
 
320
329
static DRIZZLE_SYSVAR_ULONG(
321
330
  threshold_slow,
322
 
  logging_query_threshold_slow,
 
331
  sysvar_logging_query_threshold_slow,
323
332
  PLUGIN_VAR_OPCMDARG,
324
333
  N_("Threshold for logging slow queries, in microseconds"),
325
334
  NULL, /* check func */
326
335
  NULL, /* update func */
327
336
  0, /* default */
328
337
  0, /* min */
329
 
  ULONG_MAX, /* max */
 
338
  UINT32_MAX, /* max */
330
339
  0 /* blksiz */);
331
340
 
332
341
static DRIZZLE_SYSVAR_ULONG(
333
342
  threshold_big_resultset,
334
 
  logging_query_threshold_big_resultset,
 
343
  sysvar_logging_query_threshold_big_resultset,
335
344
  PLUGIN_VAR_OPCMDARG,
336
345
  N_("Threshold for logging big queries, for rows returned"),
337
346
  NULL, /* check func */
338
347
  NULL, /* update func */
339
348
  0, /* default */
340
349
  0, /* min */
341
 
  ULONG_MAX, /* max */
 
350
  UINT32_MAX, /* max */
342
351
  0 /* blksiz */);
343
352
 
344
353
static DRIZZLE_SYSVAR_ULONG(
345
354
  threshold_big_examined,
346
 
  logging_query_threshold_big_examined,
 
355
  sysvar_logging_query_threshold_big_examined,
347
356
  PLUGIN_VAR_OPCMDARG,
348
357
  N_("Threshold for logging big queries, for rows examined"),
349
358
  NULL, /* check func */
350
359
  NULL, /* update func */
351
360
  0, /* default */
352
361
  0, /* min */
353
 
  ULONG_MAX, /* max */
 
362
  UINT32_MAX, /* max */
354
363
  0 /* blksiz */);
355
364
 
356
365
static struct st_mysql_sys_var* logging_query_system_variables[]= {
 
366
  DRIZZLE_SYSVAR(enable),
357
367
  DRIZZLE_SYSVAR(filename),
358
 
  DRIZZLE_SYSVAR(enable),
359
368
  DRIZZLE_SYSVAR(threshold_slow),
360
369
  DRIZZLE_SYSVAR(threshold_big_resultset),
361
370
  DRIZZLE_SYSVAR(threshold_big_examined),
366
375
{
367
376
  DRIZZLE_LOGGER_PLUGIN,
368
377
  "logging_query",
369
 
  "0.1",
 
378
  "0.2",
370
379
  "Mark Atwood <mark@fallenpegasus.com>",
371
 
  N_("Log queries to a file"),
 
380
  N_("Log queries to a CSV file"),
372
381
  PLUGIN_LICENSE_GPL,
373
382
  logging_query_plugin_init,
374
383
  logging_query_plugin_deinit,