~drizzle-trunk/drizzle/development

499.2.14 by Mark Atwood
fixes as per MontyT's comments, prep for internationalization
1
/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
499.2.10 by Mark Atwood
add editor format hints, and other useful metadata comments
2
 *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
499.2.14 by Mark Atwood
fixes as per MontyT's comments, prep for internationalization
3
 *
1010 by Brian Aker
Replacing Sun employee copyright headers (aka... anything done by a Sun
4
 *  Copyright (C) 2008,2009 Sun Microsystems
499.2.10 by Mark Atwood
add editor format hints, and other useful metadata comments
5
 *
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.
9
 *
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.
14
 *
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
18
 */
383.6.1 by Mark Atwood
add pluggable logging
19
20
#include <drizzled/server_includes.h>
960.2.22 by Monty Taylor
Renamed a bunch of plugin files.
21
#include <drizzled/plugin/logging_handler.h>
549 by Monty Taylor
Took gettext.h out of header files.
22
#include <drizzled/gettext.h>
584.1.15 by Monty Taylor
The mega-patch from hell. Renamed sql_class to session (since that's what it is) and removed it and field and table from common_includes.
23
#include <drizzled/session.h>
1076.1.1 by Trond Norbye
Use PCRE_HEADER instead of <pcre.h>
24
#include PCRE_HEADER
383.6.1 by Mark Atwood
add pluggable logging
25
812.1.6 by Mark Atwood
logging to syslog
26
/* TODO make this dynamic as needed */
779.5.2 by Monty Taylor
Few more style fixes.
27
static const int MAX_MSG_LEN= 32*1024;
383.6.3 by Mark Atwood
more work on plugable logging
28
812.1.6 by Mark Atwood
logging to syslog
29
static bool sysvar_logging_query_enable= false;
30
static char* sysvar_logging_query_filename= NULL;
1039.4.5 by Mark Atwood
add PCRE matching to logging to file
31
static char* sysvar_logging_query_pcre= NULL;
32
/* TODO fix these to not be unsigned long once we have sensible sys_var system */
779.5.2 by Monty Taylor
Few more style fixes.
33
static unsigned long sysvar_logging_query_threshold_slow= 0;
34
static unsigned long sysvar_logging_query_threshold_big_resultset= 0;
35
static unsigned long sysvar_logging_query_threshold_big_examined= 0;
438.2.2 by Mark Atwood
sysvar for filename for pluggable query logging to log to
36
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
37
/* stolen from mysys/my_getsystime
520.1.21 by Brian Aker
THD -> Session rename
38
   until the Session has a good utime "now" we can use
499.2.12 by Mark Atwood
have logging_query.cc call gettimeofday, since we cant get it from the thd
39
   will have to use this instead */
40
41
#include <sys/time.h>
42
static uint64_t get_microtime()
43
{
44
#if defined(HAVE_GETHRTIME)
45
  return gethrtime()/1000;
46
#else
47
  uint64_t newtime;
48
  struct timeval t;
49
  /*
50
    The following loop is here because gettimeofday may fail on some systems
51
  */
499.2.14 by Mark Atwood
fixes as per MontyT's comments, prep for internationalization
52
  while (gettimeofday(&t, NULL) != 0) {}
499.2.12 by Mark Atwood
have logging_query.cc call gettimeofday, since we cant get it from the thd
53
  newtime= (uint64_t)t.tv_sec * 1000000 + t.tv_usec;
54
  return newtime;
55
#endif  /* defined(HAVE_GETHRTIME) */
56
}
57
812.1.1 by Mark Atwood
fixup logging plugin, make it compile in, and make it do CSV
58
/* quote a string to be safe to include in a CSV line
59
   that means backslash quoting all commas, doublequotes, backslashes,
60
   and all the ASCII unprintable characters
61
   as long as we pass the high-bit bytes unchanged
62
   this is safe to do to a UTF8 string
812.1.6 by Mark Atwood
logging to syslog
63
   we dont allow overrunning the targetbuffer
64
   to avoid having a very long query overwrite memory
812.1.1 by Mark Atwood
fixup logging plugin, make it compile in, and make it do CSV
65
66
   TODO consider remapping the unprintables instead to "Printable
67
   Representation", the Unicode characters from the area U+2400 to
68
   U+2421 reserved for representing control characters when it is
69
   necessary to print or display them rather than have them perform
70
   their intended function.
71
72
*/
73
74
static unsigned char *quotify (const unsigned char *src, size_t srclen,
75
                               unsigned char *dst, size_t dstlen)
76
{
779.5.1 by Monty Taylor
Merged Mark.
77
  static const char hexit[]= { '0', '1', '2', '3', '4', '5', '6', '7',
812.1.1 by Mark Atwood
fixup logging plugin, make it compile in, and make it do CSV
78
			  '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
812.1.6 by Mark Atwood
logging to syslog
79
  size_t dst_ndx;  /* ndx down the dst */
80
  size_t src_ndx;  /* ndx down the src */
812.1.1 by Mark Atwood
fixup logging plugin, make it compile in, and make it do CSV
81
812.1.3 by Mark Atwood
fix style
82
  assert(dst);
83
  assert(dstlen > 0);
812.1.1 by Mark Atwood
fixup logging plugin, make it compile in, and make it do CSV
84
812.1.6 by Mark Atwood
logging to syslog
85
  for (dst_ndx= 0,src_ndx= 0; src_ndx < srclen; src_ndx++)
812.1.3 by Mark Atwood
fix style
86
  {
812.1.1 by Mark Atwood
fixup logging plugin, make it compile in, and make it do CSV
87
812.1.6 by Mark Atwood
logging to syslog
88
    /* Worst case, need 5 dst bytes for the next src byte.
812.1.1 by Mark Atwood
fixup logging plugin, make it compile in, and make it do CSV
89
       backslash x hexit hexit null
90
       so if not enough room, just terminate the string and return
91
    */
812.1.3 by Mark Atwood
fix style
92
    if ((dstlen - dst_ndx) < 5)
93
    {
779.5.1 by Monty Taylor
Merged Mark.
94
      dst[dst_ndx]= (unsigned char)0x00;
812.1.3 by Mark Atwood
fix style
95
      return dst;
96
    }
812.1.1 by Mark Atwood
fixup logging plugin, make it compile in, and make it do CSV
97
812.1.3 by Mark Atwood
fix style
98
    if (src[src_ndx] > 0x7f)
99
    {
812.1.1 by Mark Atwood
fixup logging plugin, make it compile in, and make it do CSV
100
      // pass thru high bit characters, they are non-ASCII UTF8 Unicode
812.1.3 by Mark Atwood
fix style
101
      dst[dst_ndx++]= src[src_ndx];
102
    }
103
    else if (src[src_ndx] == 0x00)  // null
104
    {
105
      dst[dst_ndx++]= 0x5C; dst[dst_ndx++]= (unsigned char) '0';
106
    }
107
    else if (src[src_ndx] == 0x07)  // bell
108
    {
812.1.6 by Mark Atwood
logging to syslog
109
      dst[dst_ndx++]= 0x5C; dst[dst_ndx++]= (unsigned char) 'a';
812.1.3 by Mark Atwood
fix style
110
    }
111
    else if (src[src_ndx] == 0x08)  // backspace
112
    {
113
      dst[dst_ndx++]= 0x5C; dst[dst_ndx++]= (unsigned char) 'b';
114
    }
115
    else if (src[src_ndx] == 0x09)  // horiz tab
116
    {
117
      dst[dst_ndx++]= 0x5C; dst[dst_ndx++]= (unsigned char) 't';
118
    }
119
    else if (src[src_ndx] == 0x0a)  // line feed
120
    {
121
      dst[dst_ndx++]= 0x5C; dst[dst_ndx++]= (unsigned char) 'n';
122
    }
123
    else if (src[src_ndx] == 0x0b)  // vert tab
124
    {
125
      dst[dst_ndx++]= 0x5C; dst[dst_ndx++]= (unsigned char) 'v';
126
    }
127
    else if (src[src_ndx] == 0x0c)  // formfeed
128
    {
129
      dst[dst_ndx++]= 0x5C; dst[dst_ndx++]= (unsigned char) 'f';
130
    }
131
    else if (src[src_ndx] == 0x0d)  // carrage return
132
    {
133
      dst[dst_ndx++]= 0x5C; dst[dst_ndx++]= (unsigned char) 'r';
134
    }
135
    else if (src[src_ndx] == 0x1b)  // escape
136
    {
137
      dst[dst_ndx++]= 0x5C; dst[dst_ndx++]= (unsigned char) 'e';
138
    }
139
    else if (src[src_ndx] == 0x22)  // quotation mark
140
    {
141
      dst[dst_ndx++]= 0x5C; dst[dst_ndx++]= 0x22;
142
    }
143
    else if (src[src_ndx] == 0x2C)  // comma
144
    {
145
      dst[dst_ndx++]= 0x5C; dst[dst_ndx++]= 0x2C;
146
    }
147
    else if (src[src_ndx] == 0x5C)  // backslash
148
    {
149
      dst[dst_ndx++]= 0x5C; dst[dst_ndx++]= 0x5C;
150
    }
151
    else if ((src[src_ndx] < 0x20) || (src[src_ndx] == 0x7F))  // other unprintable ASCII
152
    {
153
      dst[dst_ndx++]= 0x5C;
154
      dst[dst_ndx++]= (unsigned char) 'x';
155
      dst[dst_ndx++]= hexit[(src[src_ndx] >> 4) & 0x0f];
156
      dst[dst_ndx++]= hexit[src[src_ndx] & 0x0f];
157
    }
158
    else  // everything else
159
    {
160
      dst[dst_ndx++]= src[src_ndx];
161
    }
162
    dst[dst_ndx]= '\0';
812.1.1 by Mark Atwood
fixup logging plugin, make it compile in, and make it do CSV
163
  }
164
  return dst;
165
}
166
167
958.1.1 by Monty Taylor
Made logging plugin class based.
168
class Logging_query: public Logging_handler
169
{
1039.4.6 by Mark Atwood
make logging_query be more C++ ish
170
  int fd;
171
  pcre *re;
172
  pcre_extra *pe;
173
968.2.33 by Monty Taylor
Removed plugin_foreach from logging_handler.
174
public:
1039.4.6 by Mark Atwood
make logging_query be more C++ ish
175
176
  Logging_query() : Logging_handler("Logging_query"), fd(-1), re(NULL), pe(NULL)
177
  {
178
179
    /* if there is no destination filename, dont bother doing anything */
180
    if (sysvar_logging_query_filename == NULL)
181
      return;
182
183
    fd= open(sysvar_logging_query_filename,
184
             O_WRONLY | O_APPEND | O_CREAT,
185
             S_IRUSR|S_IWUSR);
186
    if (fd < 0)
187
    {
188
      errmsg_printf(ERRMSG_LVL_ERROR, _("fail open() fn=%s er=%s\n"),
189
                    sysvar_logging_query_filename,
190
                    strerror(errno));
191
      return;
192
    }
193
194
    if (sysvar_logging_query_pcre != NULL)
195
    {
196
      const char *this_pcre_error;
197
      int this_pcre_erroffset;
198
      re= pcre_compile(sysvar_logging_query_pcre, 0, &this_pcre_error,
199
                       &this_pcre_erroffset, NULL);
200
      pe= pcre_study(re, 0, &this_pcre_error);
201
      /* TODO emit error messages if there is a problem */
202
    }
203
  }
968.2.33 by Monty Taylor
Removed plugin_foreach from logging_handler.
204
1039.4.8 by Mark Atwood
add destructor to logging_query, to close filehandle and clean up PCRE stuff
205
  ~Logging_query()
206
  {
207
    if (fd >= 0)
208
    {
209
      close(fd);
210
    }
211
212
    if (pe != NULL)
213
    {
214
      pcre_free(pe);
215
    }
216
217
    if (re != NULL)
218
    {
219
      pcre_free(re);
220
    }
221
  }
222
223
958.1.1 by Monty Taylor
Made logging plugin class based.
224
  virtual bool pre (Session *)
225
  {
1039.4.5 by Mark Atwood
add PCRE matching to logging to file
226
    /* we could just not have a pre entrypoint at all,
227
       and have logging_pre == NULL
228
       but we have this here for the sake of being an example */
958.1.1 by Monty Taylor
Made logging plugin class based.
229
    return false;
230
  }
231
232
  virtual bool post (Session *session)
233
  {
234
    char msgbuf[MAX_MSG_LEN];
235
    int msgbuf_len= 0;
236
    int wrv;
237
238
    assert(session != NULL);
239
240
    if (fd < 0)
241
      return false;
242
243
    /* Yes, we know that checking sysvar_logging_query_enable,
244
       sysvar_logging_query_threshold_big_resultset, and
245
       sysvar_logging_query_threshold_big_examined is not threadsafe,
246
       because some other thread might change these sysvars.  But we
247
       don't care.  We might start logging a little late as it spreads
248
       to other threads.  Big deal. */
249
250
    // return if not enabled or query was too fast or resultset was too small
251
    if (sysvar_logging_query_enable == false)
252
      return false;
253
    if (session->sent_row_count < sysvar_logging_query_threshold_big_resultset)
254
      return false;
255
    if (session->examined_row_count < sysvar_logging_query_threshold_big_examined)
256
      return false;
257
258
    /* TODO, looks like connect_utime isnt being set in the session
259
       object.  We could store the time this plugin was loaded, but that
260
       would just be a dumb workaround. */
261
    /* TODO, the session object should have a "utime command completed"
262
       inside itself, so be more accurate, and so this doesnt have to
263
       keep calling current_utime, which can be slow */
264
  
265
    uint64_t t_mark= get_microtime();
266
  
267
    if ((t_mark - session->start_utime) < (sysvar_logging_query_threshold_slow))
268
      return false;
1039.4.5 by Mark Atwood
add PCRE matching to logging to file
269
270
    if (re)
271
    {
272
      int this_pcre_rc;
273
      this_pcre_rc = pcre_exec(re, pe, session->query, session->query_length, 0, 0, NULL, 0);
274
      if (this_pcre_rc < 0)
275
        return false;
276
    }
277
958.1.1 by Monty Taylor
Made logging plugin class based.
278
    // buffer to quotify the query
279
    unsigned char qs[255];
280
  
281
    // to avoid trying to printf %s something that is potentially NULL
282
    const char *dbs= (session->db) ? session->db : "";
283
    int dbl= 0;
284
    if (dbs != NULL)
285
      dbl= session->db_length;
286
  
287
    msgbuf_len=
288
      snprintf(msgbuf, MAX_MSG_LEN,
289
               "%"PRIu64",%"PRIu64",%"PRIu64",\"%.*s\",\"%s\",\"%.*s\","
1039.4.4 by Mark Atwood
add more informatin to logging to file
290
               "%"PRIu64",%"PRIu64",%"PRIu64",%"PRIu64",%"PRIu64
291
               "%"PRIu32",%"PRIu32"\n",
958.1.1 by Monty Taylor
Made logging plugin class based.
292
               t_mark,
293
               session->thread_id,
294
               session->query_id,
295
               // dont need to quote the db name, always CSV safe
296
               dbl, dbs,
297
               // do need to quote the query
298
               quotify((unsigned char *)session->query,
299
                       session->query_length, qs, sizeof(qs)),
300
               // command_name is defined in drizzled/sql_parse.cc
301
               // dont need to quote the command name, always CSV safe
302
               (int)command_name[session->command].length,
303
               command_name[session->command].str,
304
               // counters are at end, to make it easier to add more
305
               (t_mark - session->connect_utime),
306
               (t_mark - session->start_utime),
307
               (t_mark - session->utime_after_lock),
308
               session->sent_row_count,
1039.4.4 by Mark Atwood
add more informatin to logging to file
309
               session->examined_row_count,
310
               session->tmp_table,
311
               session->total_warn_count);
958.1.1 by Monty Taylor
Made logging plugin class based.
312
  
313
    // a single write has a kernel thread lock, thus no need mutex guard this
314
    wrv= write(fd, msgbuf, msgbuf_len);
315
    assert(wrv == msgbuf_len);
316
  
317
    return false;
318
  }
319
};
383.6.1 by Mark Atwood
add pluggable logging
320
971.1.51 by Monty Taylor
New-style plugin registration now works.
321
static Logging_query *handler= NULL;
322
971.1.52 by Monty Taylor
Did the finalizers. Renamed plugin_registry.
323
static int logging_query_plugin_init(PluginRegistry &registry)
383.6.1 by Mark Atwood
add pluggable logging
324
{
971.1.51 by Monty Taylor
New-style plugin registration now works.
325
  handler= new Logging_query();
971.1.52 by Monty Taylor
Did the finalizers. Renamed plugin_registry.
326
  registry.add(handler);
383.6.1 by Mark Atwood
add pluggable logging
327
328
  return 0;
329
}
330
971.1.52 by Monty Taylor
Did the finalizers. Renamed plugin_registry.
331
static int logging_query_plugin_deinit(PluginRegistry &registry)
383.6.1 by Mark Atwood
add pluggable logging
332
{
971.1.52 by Monty Taylor
Did the finalizers. Renamed plugin_registry.
333
  registry.remove(handler);
958.1.1 by Monty Taylor
Made logging plugin class based.
334
  delete handler;
383.6.1 by Mark Atwood
add pluggable logging
335
336
  return 0;
337
}
338
812.1.6 by Mark Atwood
logging to syslog
339
static DRIZZLE_SYSVAR_BOOL(
340
  enable,
341
  sysvar_logging_query_enable,
342
  PLUGIN_VAR_NOCMDARG,
343
  N_("Enable logging to CSV file"),
344
  NULL, /* check func */
345
  NULL, /* update func */
346
  false /* default */);
347
499.2.14 by Mark Atwood
fixes as per MontyT's comments, prep for internationalization
348
static DRIZZLE_SYSVAR_STR(
349
  filename,
812.1.6 by Mark Atwood
logging to syslog
350
  sysvar_logging_query_filename,
438.2.2 by Mark Atwood
sysvar for filename for pluggable query logging to log to
351
  PLUGIN_VAR_READONLY,
499.2.14 by Mark Atwood
fixes as per MontyT's comments, prep for internationalization
352
  N_("File to log to"),
353
  NULL, /* check func */
354
  NULL, /* update func*/
355
  NULL /* default */);
356
1039.4.5 by Mark Atwood
add PCRE matching to logging to file
357
static DRIZZLE_SYSVAR_STR(
358
  pcre,
359
  sysvar_logging_query_pcre,
360
  PLUGIN_VAR_READONLY,
361
  N_("PCRE to match the query against"),
362
  NULL, /* check func */
363
  NULL, /* update func*/
364
  NULL /* default */);
365
499.2.14 by Mark Atwood
fixes as per MontyT's comments, prep for internationalization
366
static DRIZZLE_SYSVAR_ULONG(
812.1.1 by Mark Atwood
fixup logging plugin, make it compile in, and make it do CSV
367
  threshold_slow,
812.1.6 by Mark Atwood
logging to syslog
368
  sysvar_logging_query_threshold_slow,
499.2.14 by Mark Atwood
fixes as per MontyT's comments, prep for internationalization
369
  PLUGIN_VAR_OPCMDARG,
370
  N_("Threshold for logging slow queries, in microseconds"),
371
  NULL, /* check func */
372
  NULL, /* update func */
373
  0, /* default */
374
  0, /* min */
779.5.2 by Monty Taylor
Few more style fixes.
375
  UINT32_MAX, /* max */
499.2.14 by Mark Atwood
fixes as per MontyT's comments, prep for internationalization
376
  0 /* blksiz */);
377
378
static DRIZZLE_SYSVAR_ULONG(
499.2.15 by Mark Atwood
change thresh_bigexa to threadhold_big_examined. "Use English!" --BrianA
379
  threshold_big_resultset,
812.1.6 by Mark Atwood
logging to syslog
380
  sysvar_logging_query_threshold_big_resultset,
499.2.14 by Mark Atwood
fixes as per MontyT's comments, prep for internationalization
381
  PLUGIN_VAR_OPCMDARG,
382
  N_("Threshold for logging big queries, for rows returned"),
383
  NULL, /* check func */
384
  NULL, /* update func */
385
  0, /* default */
386
  0, /* min */
779.5.2 by Monty Taylor
Few more style fixes.
387
  UINT32_MAX, /* max */
499.2.14 by Mark Atwood
fixes as per MontyT's comments, prep for internationalization
388
  0 /* blksiz */);
389
390
static DRIZZLE_SYSVAR_ULONG(
812.1.1 by Mark Atwood
fixup logging plugin, make it compile in, and make it do CSV
391
  threshold_big_examined,
812.1.6 by Mark Atwood
logging to syslog
392
  sysvar_logging_query_threshold_big_examined,
499.2.14 by Mark Atwood
fixes as per MontyT's comments, prep for internationalization
393
  PLUGIN_VAR_OPCMDARG,
394
  N_("Threshold for logging big queries, for rows examined"),
395
  NULL, /* check func */
396
  NULL, /* update func */
397
  0, /* default */
398
  0, /* min */
779.5.2 by Monty Taylor
Few more style fixes.
399
  UINT32_MAX, /* max */
499.2.14 by Mark Atwood
fixes as per MontyT's comments, prep for internationalization
400
  0 /* blksiz */);
438.2.2 by Mark Atwood
sysvar for filename for pluggable query logging to log to
401
402
static struct st_mysql_sys_var* logging_query_system_variables[]= {
812.1.6 by Mark Atwood
logging to syslog
403
  DRIZZLE_SYSVAR(enable),
438.2.2 by Mark Atwood
sysvar for filename for pluggable query logging to log to
404
  DRIZZLE_SYSVAR(filename),
1039.4.5 by Mark Atwood
add PCRE matching to logging to file
405
  DRIZZLE_SYSVAR(pcre),
812.1.1 by Mark Atwood
fixup logging plugin, make it compile in, and make it do CSV
406
  DRIZZLE_SYSVAR(threshold_slow),
499.2.15 by Mark Atwood
change thresh_bigexa to threadhold_big_examined. "Use English!" --BrianA
407
  DRIZZLE_SYSVAR(threshold_big_resultset),
812.1.1 by Mark Atwood
fixup logging plugin, make it compile in, and make it do CSV
408
  DRIZZLE_SYSVAR(threshold_big_examined),
438.2.2 by Mark Atwood
sysvar for filename for pluggable query logging to log to
409
  NULL
410
};
411
813.2.1 by Toru Maesaka
Renamed mysql_declare_plugin to drizzle_declare_plugin
412
drizzle_declare_plugin(logging_query)
383.6.1 by Mark Atwood
add pluggable logging
413
{
383.6.5 by Mark Atwood
start renaming logging_noop to logging_query
414
  "logging_query",
812.1.6 by Mark Atwood
logging to syslog
415
  "0.2",
383.6.1 by Mark Atwood
add pluggable logging
416
  "Mark Atwood <mark@fallenpegasus.com>",
812.1.6 by Mark Atwood
logging to syslog
417
  N_("Log queries to a CSV file"),
383.6.1 by Mark Atwood
add pluggable logging
418
  PLUGIN_LICENSE_GPL,
383.6.5 by Mark Atwood
start renaming logging_noop to logging_query
419
  logging_query_plugin_init,
420
  logging_query_plugin_deinit,
383.6.1 by Mark Atwood
add pluggable logging
421
  NULL,   /* status variables */
438.2.2 by Mark Atwood
sysvar for filename for pluggable query logging to log to
422
  logging_query_system_variables,
423
  NULL
383.6.1 by Mark Atwood
add pluggable logging
424
}
813.2.2 by Toru Maesaka
Renamed mysql_declare_plugin_end to drizzle_declare_plugin_end
425
drizzle_declare_plugin_end;