~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/logging_query/logging_query.cc

Merge David

Show diffs side-by-side

added added

removed removed

Lines of Context:
27
27
#include <sys/types.h>
28
28
#include <sys/stat.h>
29
29
#include <fcntl.h>
 
30
#include <string>
 
31
#include <boost/format.hpp>
30
32
 
31
33
#include <cstdio>
32
34
 
33
35
using namespace drizzled;
 
36
using namespace std;
34
37
 
35
 
/* TODO make this dynamic as needed */
36
 
static const int MAX_MSG_LEN= 32*1024;
 
38
#define ESCAPE_CHAR      '\\'
 
39
#define SEPARATOR_CHAR   ','
37
40
 
38
41
static bool sysvar_logging_query_enable= false;
39
42
static char* sysvar_logging_query_filename= NULL;
79
82
 
80
83
*/
81
84
 
82
 
static unsigned char *quotify (const unsigned char *src, size_t srclen,
83
 
                               unsigned char *dst, size_t dstlen)
 
85
static void quotify(const string &src, string &dst)
84
86
{
85
87
  static const char hexit[]= { '0', '1', '2', '3', '4', '5', '6', '7',
86
88
                          '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
87
 
  size_t dst_ndx;  /* ndx down the dst */
88
 
  size_t src_ndx;  /* ndx down the src */
89
 
 
90
 
  assert(dst);
91
 
  assert(dstlen > 0);
92
 
 
93
 
  for (dst_ndx= 0,src_ndx= 0; src_ndx < srclen; src_ndx++)
 
89
  string::const_iterator src_iter;
 
90
  
 
91
  for (src_iter= src.begin(); src_iter < src.end(); ++src_iter)
94
92
  {
95
 
 
96
 
    /* Worst case, need 5 dst bytes for the next src byte.
97
 
       backslash x hexit hexit null
98
 
       so if not enough room, just terminate the string and return
99
 
    */
100
 
    if ((dstlen - dst_ndx) < 5)
101
 
    {
102
 
      dst[dst_ndx]= (unsigned char)0x00;
103
 
      return dst;
104
 
    }
105
 
 
106
 
    if (src[src_ndx] > 0x7f)
107
 
    {
108
 
      // pass thru high bit characters, they are non-ASCII UTF8 Unicode
109
 
      dst[dst_ndx++]= src[src_ndx];
110
 
    }
111
 
    else if (src[src_ndx] == 0x00)  // null
112
 
    {
113
 
      dst[dst_ndx++]= 0x5C; dst[dst_ndx++]= (unsigned char) '0';
114
 
    }
115
 
    else if (src[src_ndx] == 0x07)  // bell
116
 
    {
117
 
      dst[dst_ndx++]= 0x5C; dst[dst_ndx++]= (unsigned char) 'a';
118
 
    }
119
 
    else if (src[src_ndx] == 0x08)  // backspace
120
 
    {
121
 
      dst[dst_ndx++]= 0x5C; dst[dst_ndx++]= (unsigned char) 'b';
122
 
    }
123
 
    else if (src[src_ndx] == 0x09)  // horiz tab
124
 
    {
125
 
      dst[dst_ndx++]= 0x5C; dst[dst_ndx++]= (unsigned char) 't';
126
 
    }
127
 
    else if (src[src_ndx] == 0x0a)  // line feed
128
 
    {
129
 
      dst[dst_ndx++]= 0x5C; dst[dst_ndx++]= (unsigned char) 'n';
130
 
    }
131
 
    else if (src[src_ndx] == 0x0b)  // vert tab
132
 
    {
133
 
      dst[dst_ndx++]= 0x5C; dst[dst_ndx++]= (unsigned char) 'v';
134
 
    }
135
 
    else if (src[src_ndx] == 0x0c)  // formfeed
136
 
    {
137
 
      dst[dst_ndx++]= 0x5C; dst[dst_ndx++]= (unsigned char) 'f';
138
 
    }
139
 
    else if (src[src_ndx] == 0x0d)  // carrage return
140
 
    {
141
 
      dst[dst_ndx++]= 0x5C; dst[dst_ndx++]= (unsigned char) 'r';
142
 
    }
143
 
    else if (src[src_ndx] == 0x1b)  // escape
144
 
    {
145
 
      dst[dst_ndx++]= 0x5C; dst[dst_ndx++]= (unsigned char) 'e';
146
 
    }
147
 
    else if (src[src_ndx] == 0x22)  // quotation mark
148
 
    {
149
 
      dst[dst_ndx++]= 0x5C; dst[dst_ndx++]= 0x22;
150
 
    }
151
 
    else if (src[src_ndx] == 0x2C)  // comma
152
 
    {
153
 
      dst[dst_ndx++]= 0x5C; dst[dst_ndx++]= 0x2C;
154
 
    }
155
 
    else if (src[src_ndx] == 0x5C)  // backslash
156
 
    {
157
 
      dst[dst_ndx++]= 0x5C; dst[dst_ndx++]= 0x5C;
158
 
    }
159
 
    else if ((src[src_ndx] < 0x20) || (src[src_ndx] == 0x7F))  // other unprintable ASCII
160
 
    {
161
 
      dst[dst_ndx++]= 0x5C;
162
 
      dst[dst_ndx++]= (unsigned char) 'x';
163
 
      dst[dst_ndx++]= hexit[(src[src_ndx] >> 4) & 0x0f];
164
 
      dst[dst_ndx++]= hexit[src[src_ndx] & 0x0f];
 
93
    if (static_cast<unsigned char>(*src_iter) > 0x7f)
 
94
    {
 
95
      dst.push_back(*src_iter);
 
96
    }
 
97
    else if (*src_iter == 0x00)  // null
 
98
    {
 
99
      dst.push_back(ESCAPE_CHAR); dst.push_back('0');
 
100
    }
 
101
    else if (*src_iter == 0x07)  // bell
 
102
    {
 
103
      dst.push_back(ESCAPE_CHAR); dst.push_back('a');
 
104
    }
 
105
    else if (*src_iter == 0x08)  // backspace
 
106
    {
 
107
      dst.push_back(ESCAPE_CHAR); dst.push_back('b');
 
108
    }
 
109
    else if (*src_iter == 0x09)  // horiz tab
 
110
    {
 
111
      dst.push_back(ESCAPE_CHAR); dst.push_back('t');
 
112
    }
 
113
    else if (*src_iter == 0x0a)  // line feed
 
114
    {
 
115
      dst.push_back(ESCAPE_CHAR); dst.push_back('n');
 
116
    }
 
117
    else if (*src_iter == 0x0b)  // vert tab
 
118
    {
 
119
      dst.push_back(ESCAPE_CHAR); dst.push_back('v');
 
120
    }
 
121
    else if (*src_iter == 0x0c)  // formfeed
 
122
    {
 
123
      dst.push_back(ESCAPE_CHAR); dst.push_back('f');
 
124
    }
 
125
    else if (*src_iter == 0x0d)  // carrage return
 
126
    {
 
127
      dst.push_back(ESCAPE_CHAR); dst.push_back('r');
 
128
    }
 
129
    else if (*src_iter == 0x1b)  // escape
 
130
    {
 
131
      dst.push_back(ESCAPE_CHAR); dst.push_back('e');
 
132
    }
 
133
    else if (*src_iter == 0x22)  // quotation mark
 
134
    {
 
135
      dst.push_back(ESCAPE_CHAR); dst.push_back(0x22);
 
136
    }
 
137
    else if (*src_iter == SEPARATOR_CHAR)
 
138
    {
 
139
      dst.push_back(ESCAPE_CHAR); dst.push_back(SEPARATOR_CHAR);
 
140
    }
 
141
    else if (*src_iter == ESCAPE_CHAR)
 
142
    {
 
143
      dst.push_back(ESCAPE_CHAR); dst.push_back(ESCAPE_CHAR);
 
144
    }
 
145
    else if ((*src_iter < 0x20) || (*src_iter == 0x7F))  // other unprintable ASCII
 
146
    {
 
147
      dst.push_back(ESCAPE_CHAR);
 
148
      dst.push_back('x');
 
149
      dst.push_back(hexit[(*src_iter >> 4) & 0x0f]);
 
150
      dst.push_back(hexit[*src_iter & 0x0f]);
165
151
    }
166
152
    else  // everything else
167
153
    {
168
 
      dst[dst_ndx++]= src[src_ndx];
 
154
      dst.push_back(*src_iter);
169
155
    }
170
 
    dst[dst_ndx]= '\0';
171
156
  }
172
 
  return dst;
173
157
}
174
158
 
175
159
 
179
163
  pcre *re;
180
164
  pcre_extra *pe;
181
165
 
 
166
  /** Format of the output string */
 
167
  boost::format formatter;
 
168
 
182
169
public:
183
170
 
184
171
  Logging_query()
185
172
    : drizzled::plugin::Logging("Logging_query"),
186
 
      fd(-1), re(NULL), pe(NULL)
 
173
      fd(-1), re(NULL), pe(NULL),
 
174
      formatter("%1%,%2%,%3%,\"%4%\",\"%5%\",\"%6%\",%7%,%8%,"
 
175
                "%9%,%10%,%11%,%12%,%13%,%14%,\"%15%\"\n")
187
176
  {
188
177
 
189
178
    /* if there is no destination filename, dont bother doing anything */
230
219
    }
231
220
  }
232
221
 
233
 
 
234
 
  virtual bool pre (Session *)
235
 
  {
236
 
    /* we could just not have a pre entrypoint at all,
237
 
       and have logging_pre == NULL
238
 
       but we have this here for the sake of being an example */
239
 
    return false;
240
 
  }
241
 
 
242
222
  virtual bool post (Session *session)
243
223
  {
244
 
    char msgbuf[MAX_MSG_LEN];
245
 
    int msgbuf_len= 0;
246
 
    int wrv;
 
224
    size_t wrv;
247
225
 
248
226
    assert(session != NULL);
249
227
 
277
255
    if (re)
278
256
    {
279
257
      int this_pcre_rc;
280
 
      this_pcre_rc = pcre_exec(re, pe, session->query.c_str(), session->query.length(), 0, 0, NULL, 0);
 
258
      this_pcre_rc= pcre_exec(re, pe, session->query.c_str(), session->query.length(), 0, 0, NULL, 0);
281
259
      if (this_pcre_rc < 0)
282
260
        return false;
283
261
    }
284
262
 
285
263
    // buffer to quotify the query
286
 
    unsigned char qs[255];
287
 
  
 
264
    string qs;
 
265
    
 
266
    // Since quotify() builds the quoted string incrementally, we can
 
267
    // avoid some reallocating if we reserve some space up front.
 
268
    qs.reserve(session->getQueryLength());
 
269
    
 
270
    quotify(session->getQueryString(), qs);
 
271
    
288
272
    // to avoid trying to printf %s something that is potentially NULL
289
273
    const char *dbs= session->db.empty() ? "" : session->db.c_str();
290
 
  
291
 
    msgbuf_len=
292
 
      snprintf(msgbuf, MAX_MSG_LEN,
293
 
               "%"PRIu64",%"PRIu64",%"PRIu64",\"%.*s\",\"%s\",\"%.*s\","
294
 
               "%"PRIu64",%"PRIu64",%"PRIu64",%"PRIu64",%"PRIu64","
295
 
               "%"PRIu32",%"PRIu32",%"PRIu32",\"%s\"\n",
296
 
               t_mark,
297
 
               session->thread_id,
298
 
               session->getQueryId(),
299
 
               // dont need to quote the db name, always CSV safe
300
 
               (int)session->db.length(), dbs,
301
 
               // do need to quote the query
302
 
               quotify((unsigned char *)session->getQueryString().c_str(),
303
 
                       session->getQueryLength(), qs, sizeof(qs)),
304
 
               // command_name is defined in drizzled/sql_parse.cc
305
 
               // dont need to quote the command name, always CSV safe
306
 
               (int)command_name[session->command].length,
307
 
               command_name[session->command].str,
308
 
               // counters are at end, to make it easier to add more
309
 
               (t_mark - session->getConnectMicroseconds()),
310
 
               (t_mark - session->start_utime),
311
 
               (t_mark - session->utime_after_lock),
312
 
               session->sent_row_count,
313
 
               session->examined_row_count,
314
 
               session->tmp_table,
315
 
               session->total_warn_count,
316
 
               session->getServerId(),
317
 
               glob_hostname
318
 
               );
319
 
  
 
274
 
 
275
    formatter % t_mark
 
276
              % session->thread_id
 
277
              % session->getQueryId()
 
278
              % dbs
 
279
              % qs
 
280
              % command_name[session->command].str
 
281
              % (t_mark - session->getConnectMicroseconds())
 
282
              % (t_mark - session->start_utime)
 
283
              % (t_mark - session->utime_after_lock)
 
284
              % session->sent_row_count
 
285
              % session->examined_row_count
 
286
              % session->tmp_table
 
287
              % session->total_warn_count
 
288
              % session->getServerId()
 
289
              % glob_hostname;
 
290
 
 
291
    string msgbuf= formatter.str();
 
292
 
320
293
    // a single write has a kernel thread lock, thus no need mutex guard this
321
 
    wrv= write(fd, msgbuf, msgbuf_len);
322
 
    assert(wrv == msgbuf_len);
323
 
  
 
294
    wrv= write(fd, msgbuf.c_str(), msgbuf.length());
 
295
    assert(wrv == msgbuf.length());
 
296
 
324
297
    return false;
325
298
  }
326
299
};