~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
 *
1999.6.1 by kalebral at gmail
update Copyright strings to a more common format to help with creating the master debian copyright file
4
 *  Copyright (C) 2008, 2009 Sun Microsystems, Inc.
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
1241.9.36 by Monty Taylor
ZOMG. I deleted drizzled/server_includes.h.
20
#include "config.h"
1130.1.1 by Monty Taylor
Merged in plugin-slot-reorg patches.
21
#include <drizzled/plugin/logging.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
1259.7.4 by Monty Taylor
Fixed namespace and include issues in some plugins we hadn't been building.
25
#include <limits.h>
26
#include <sys/time.h>
27
#include <sys/types.h>
28
#include <sys/stat.h>
29
#include <fcntl.h>
1607.1.1 by David Shrewsbury
Replace static buffers with std::string.
30
#include <string>
31
#include <boost/format.hpp>
1660.7.1 by Vijay Samuel
Merge re factored commandline for logging_query using boost::program_options
32
#include <boost/program_options.hpp>
33
#include <drizzled/module/option_map.h>
1502.3.1 by iwamatsu at nigauri
Add cstdio include to files needing it. Fixes the build on some debian
34
#include <cstdio>
1702.3.3 by LinuxJedi
Fix errors in FreeBSD build
35
#include <cerrno>
1259.7.4 by Monty Taylor
Fixed namespace and include issues in some plugins we hadn't been building.
36
1660.7.1 by Vijay Samuel
Merge re factored commandline for logging_query using boost::program_options
37
namespace po= boost::program_options;
1259.7.4 by Monty Taylor
Fixed namespace and include issues in some plugins we hadn't been building.
38
using namespace drizzled;
1607.1.1 by David Shrewsbury
Replace static buffers with std::string.
39
using namespace std;
383.6.1 by Mark Atwood
add pluggable logging
40
1607.1.1 by David Shrewsbury
Replace static buffers with std::string.
41
#define ESCAPE_CHAR      '\\'
42
#define SEPARATOR_CHAR   ','
383.6.3 by Mark Atwood
more work on plugable logging
43
1964.2.17 by Monty Taylor
Did logging_query. Fixed rabbitmq.
44
namespace drizzle_plugin
45
{
46
812.1.6 by Mark Atwood
logging to syslog
47
static bool sysvar_logging_query_enable= false;
1039.4.5 by Mark Atwood
add PCRE matching to logging to file
48
/* TODO fix these to not be unsigned long once we have sensible sys_var system */
1964.2.17 by Monty Taylor
Did logging_query. Fixed rabbitmq.
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;
438.2.2 by Mark Atwood
sysvar for filename for pluggable query logging to log to
52
812.1.1 by Mark Atwood
fixup logging plugin, make it compile in, and make it do CSV
53
/* quote a string to be safe to include in a CSV line
54
   that means backslash quoting all commas, doublequotes, backslashes,
55
   and all the ASCII unprintable characters
56
   as long as we pass the high-bit bytes unchanged
57
   this is safe to do to a UTF8 string
812.1.6 by Mark Atwood
logging to syslog
58
   we dont allow overrunning the targetbuffer
59
   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
60
61
   TODO consider remapping the unprintables instead to "Printable
62
   Representation", the Unicode characters from the area U+2400 to
63
   U+2421 reserved for representing control characters when it is
64
   necessary to print or display them rather than have them perform
65
   their intended function.
66
67
*/
68
1607.1.1 by David Shrewsbury
Replace static buffers with std::string.
69
static void quotify(const string &src, string &dst)
812.1.1 by Mark Atwood
fixup logging plugin, make it compile in, and make it do CSV
70
{
779.5.1 by Monty Taylor
Merged Mark.
71
  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
72
			  '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
1607.1.1 by David Shrewsbury
Replace static buffers with std::string.
73
  string::const_iterator src_iter;
74
  
75
  for (src_iter= src.begin(); src_iter < src.end(); ++src_iter)
812.1.3 by Mark Atwood
fix style
76
  {
1607.1.1 by David Shrewsbury
Replace static buffers with std::string.
77
    if (static_cast<unsigned char>(*src_iter) > 0x7f)
78
    {
79
      dst.push_back(*src_iter);
80
    }
81
    else if (*src_iter == 0x00)  // null
82
    {
83
      dst.push_back(ESCAPE_CHAR); dst.push_back('0');
84
    }
85
    else if (*src_iter == 0x07)  // bell
86
    {
87
      dst.push_back(ESCAPE_CHAR); dst.push_back('a');
88
    }
89
    else if (*src_iter == 0x08)  // backspace
90
    {
91
      dst.push_back(ESCAPE_CHAR); dst.push_back('b');
92
    }
93
    else if (*src_iter == 0x09)  // horiz tab
94
    {
95
      dst.push_back(ESCAPE_CHAR); dst.push_back('t');
96
    }
97
    else if (*src_iter == 0x0a)  // line feed
98
    {
99
      dst.push_back(ESCAPE_CHAR); dst.push_back('n');
100
    }
101
    else if (*src_iter == 0x0b)  // vert tab
102
    {
103
      dst.push_back(ESCAPE_CHAR); dst.push_back('v');
104
    }
105
    else if (*src_iter == 0x0c)  // formfeed
106
    {
107
      dst.push_back(ESCAPE_CHAR); dst.push_back('f');
108
    }
109
    else if (*src_iter == 0x0d)  // carrage return
110
    {
111
      dst.push_back(ESCAPE_CHAR); dst.push_back('r');
112
    }
113
    else if (*src_iter == 0x1b)  // escape
114
    {
115
      dst.push_back(ESCAPE_CHAR); dst.push_back('e');
116
    }
117
    else if (*src_iter == 0x22)  // quotation mark
118
    {
119
      dst.push_back(ESCAPE_CHAR); dst.push_back(0x22);
120
    }
121
    else if (*src_iter == SEPARATOR_CHAR)
122
    {
123
      dst.push_back(ESCAPE_CHAR); dst.push_back(SEPARATOR_CHAR);
124
    }
125
    else if (*src_iter == ESCAPE_CHAR)
126
    {
127
      dst.push_back(ESCAPE_CHAR); dst.push_back(ESCAPE_CHAR);
128
    }
129
    else if ((*src_iter < 0x20) || (*src_iter == 0x7F))  // other unprintable ASCII
130
    {
131
      dst.push_back(ESCAPE_CHAR);
132
      dst.push_back('x');
133
      dst.push_back(hexit[(*src_iter >> 4) & 0x0f]);
134
      dst.push_back(hexit[*src_iter & 0x0f]);
812.1.3 by Mark Atwood
fix style
135
    }
136
    else  // everything else
137
    {
1607.1.1 by David Shrewsbury
Replace static buffers with std::string.
138
      dst.push_back(*src_iter);
812.1.3 by Mark Atwood
fix style
139
    }
812.1.1 by Mark Atwood
fixup logging plugin, make it compile in, and make it do CSV
140
  }
141
}
142
143
1130.1.1 by Monty Taylor
Merged in plugin-slot-reorg patches.
144
class Logging_query: public drizzled::plugin::Logging
958.1.1 by Monty Taylor
Made logging plugin class based.
145
{
1964.2.17 by Monty Taylor
Did logging_query. Fixed rabbitmq.
146
  const std::string _filename;
147
  const std::string _query_pcre;
1039.4.6 by Mark Atwood
make logging_query be more C++ ish
148
  int fd;
149
  pcre *re;
150
  pcre_extra *pe;
151
1607.1.2 by David Shrewsbury
Made the boost::format object reusable.
152
  /** Format of the output string */
153
  boost::format formatter;
154
968.2.33 by Monty Taylor
Removed plugin_foreach from logging_handler.
155
public:
1039.4.6 by Mark Atwood
make logging_query be more C++ ish
156
1964.2.17 by Monty Taylor
Did logging_query. Fixed rabbitmq.
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")
1039.4.6 by Mark Atwood
make logging_query be more C++ ish
165
  {
166
167
    /* if there is no destination filename, dont bother doing anything */
1964.2.17 by Monty Taylor
Did logging_query. Fixed rabbitmq.
168
    if (_filename.empty())
1039.4.6 by Mark Atwood
make logging_query be more C++ ish
169
      return;
170
1964.2.17 by Monty Taylor
Did logging_query. Fixed rabbitmq.
171
    fd= open(_filename.c_str(),
1039.4.6 by Mark Atwood
make logging_query be more C++ ish
172
             O_WRONLY | O_APPEND | O_CREAT,
173
             S_IRUSR|S_IWUSR);
174
    if (fd < 0)
175
    {
1702.3.2 by LinuxJedi
Migrate the rest of strerror to strerror_r
176
      char errmsg[STRERROR_MAX];
177
      strerror_r(errno, errmsg, sizeof(errmsg));
1039.4.6 by Mark Atwood
make logging_query be more C++ ish
178
      errmsg_printf(ERRMSG_LVL_ERROR, _("fail open() fn=%s er=%s\n"),
1964.2.17 by Monty Taylor
Did logging_query. Fixed rabbitmq.
179
                    _filename.c_str(),
1702.3.2 by LinuxJedi
Migrate the rest of strerror to strerror_r
180
                    errmsg);
1039.4.6 by Mark Atwood
make logging_query be more C++ ish
181
      return;
182
    }
183
1964.2.17 by Monty Taylor
Did logging_query. Fixed rabbitmq.
184
    if (not _query_pcre.empty())
1039.4.6 by Mark Atwood
make logging_query be more C++ ish
185
    {
186
      const char *this_pcre_error;
187
      int this_pcre_erroffset;
1964.2.17 by Monty Taylor
Did logging_query. Fixed rabbitmq.
188
      re= pcre_compile(_query_pcre.c_str(), 0, &this_pcre_error,
1039.4.6 by Mark Atwood
make logging_query be more C++ ish
189
                       &this_pcre_erroffset, NULL);
190
      pe= pcre_study(re, 0, &this_pcre_error);
191
      /* TODO emit error messages if there is a problem */
192
    }
193
  }
968.2.33 by Monty Taylor
Removed plugin_foreach from logging_handler.
194
1039.4.8 by Mark Atwood
add destructor to logging_query, to close filehandle and clean up PCRE stuff
195
  ~Logging_query()
196
  {
197
    if (fd >= 0)
198
    {
199
      close(fd);
200
    }
201
202
    if (pe != NULL)
203
    {
204
      pcre_free(pe);
205
    }
206
207
    if (re != NULL)
208
    {
209
      pcre_free(re);
210
    }
211
  }
212
958.1.1 by Monty Taylor
Made logging plugin class based.
213
  virtual bool post (Session *session)
214
  {
1607.1.1 by David Shrewsbury
Replace static buffers with std::string.
215
    size_t wrv;
958.1.1 by Monty Taylor
Made logging plugin class based.
216
217
    assert(session != NULL);
218
219
    if (fd < 0)
220
      return false;
221
222
    /* Yes, we know that checking sysvar_logging_query_enable,
223
       sysvar_logging_query_threshold_big_resultset, and
224
       sysvar_logging_query_threshold_big_examined is not threadsafe,
225
       because some other thread might change these sysvars.  But we
226
       don't care.  We might start logging a little late as it spreads
227
       to other threads.  Big deal. */
228
229
    // return if not enabled or query was too fast or resultset was too small
230
    if (sysvar_logging_query_enable == false)
231
      return false;
1964.2.17 by Monty Taylor
Did logging_query. Fixed rabbitmq.
232
    if (session->sent_row_count < sysvar_logging_query_threshold_big_resultset.get())
958.1.1 by Monty Taylor
Made logging plugin class based.
233
      return false;
1964.2.17 by Monty Taylor
Did logging_query. Fixed rabbitmq.
234
    if (session->examined_row_count < sysvar_logging_query_threshold_big_examined.get())
958.1.1 by Monty Taylor
Made logging plugin class based.
235
      return false;
236
2040.4.3 by Brian Aker
Scale down the calls to universal_time().
237
    /*
238
      TODO, the session object should have a "utime command completed"
239
      inside itself, so be more accurate, and so this doesnt have to
240
      keep calling current_utime, which can be slow.
241
    */
242
    uint64_t t_mark= session->getCurrentTimestamp(false);
1878.10.1 by Billy Earney
removed my_micro_time, my_micro_time_and_time, along with my_getsystime and replaced with boost:date_time for compatibility between OS.
243
2040.4.4 by Brian Aker
Make more time usage private.
244
    if (session->getElapsedTime() < (sysvar_logging_query_threshold_slow.get()))
958.1.1 by Monty Taylor
Made logging plugin class based.
245
      return false;
1039.4.5 by Mark Atwood
add PCRE matching to logging to file
246
1921.4.13 by Brian Aker
Fix issue where session info might not be correct.
247
    Session::QueryString query_string(session->getQueryString());
1039.4.5 by Mark Atwood
add PCRE matching to logging to file
248
    if (re)
249
    {
250
      int this_pcre_rc;
1921.4.13 by Brian Aker
Fix issue where session info might not be correct.
251
      this_pcre_rc= pcre_exec(re, pe, query_string->c_str(), query_string->length(), 0, 0, NULL, 0);
1039.4.5 by Mark Atwood
add PCRE matching to logging to file
252
      if (this_pcre_rc < 0)
253
        return false;
254
    }
255
958.1.1 by Monty Taylor
Made logging plugin class based.
256
    // buffer to quotify the query
1607.1.1 by David Shrewsbury
Replace static buffers with std::string.
257
    string qs;
258
    
259
    // Since quotify() builds the quoted string incrementally, we can
260
    // avoid some reallocating if we reserve some space up front.
1921.4.13 by Brian Aker
Fix issue where session info might not be correct.
261
    qs.reserve(query_string->length());
1607.1.1 by David Shrewsbury
Replace static buffers with std::string.
262
    
1921.4.13 by Brian Aker
Fix issue where session info might not be correct.
263
    quotify(*query_string, qs);
1607.1.1 by David Shrewsbury
Replace static buffers with std::string.
264
    
958.1.1 by Monty Taylor
Made logging plugin class based.
265
    // to avoid trying to printf %s something that is potentially NULL
1976.5.2 by Brian Aker
This resolves the issue where one thread may be looking at schema while
266
    util::string::const_shared_ptr schema(session->schema());
267
    const char *dbs= (schema and not schema->empty()) ? schema->c_str() : "";
1607.1.1 by David Shrewsbury
Replace static buffers with std::string.
268
269
    formatter % t_mark
270
              % session->thread_id
271
              % session->getQueryId()
272
              % dbs
273
              % qs
274
              % command_name[session->command].str
275
              % (t_mark - session->getConnectMicroseconds())
2040.4.4 by Brian Aker
Make more time usage private.
276
              % session->getElapsedTime()
1607.1.1 by David Shrewsbury
Replace static buffers with std::string.
277
              % (t_mark - session->utime_after_lock)
278
              % session->sent_row_count
279
              % session->examined_row_count
280
              % session->tmp_table
281
              % session->total_warn_count
282
              % session->getServerId()
283
              % glob_hostname;
284
285
    string msgbuf= formatter.str();
286
958.1.1 by Monty Taylor
Made logging plugin class based.
287
    // a single write has a kernel thread lock, thus no need mutex guard this
1607.1.1 by David Shrewsbury
Replace static buffers with std::string.
288
    wrv= write(fd, msgbuf.c_str(), msgbuf.length());
289
    assert(wrv == msgbuf.length());
290
958.1.1 by Monty Taylor
Made logging plugin class based.
291
    return false;
292
  }
293
};
383.6.1 by Mark Atwood
add pluggable logging
294
1530.2.6 by Monty Taylor
Moved plugin::Context to module::Context.
295
static int logging_query_plugin_init(drizzled::module::Context &context)
383.6.1 by Mark Atwood
add pluggable logging
296
{
1660.7.1 by Vijay Samuel
Merge re factored commandline for logging_query using boost::program_options
297
298
  const module::option_map &vm= context.getOptions();
1964.2.17 by Monty Taylor
Did logging_query. Fixed rabbitmq.
299
300
  if (vm.count("filename") > 0)
301
  {
302
    context.add(new Logging_query(vm["filename"].as<string>(),
303
                                  vm["pcre"].as<string>()));
304
    context.registerVariable(new sys_var_bool_ptr("enable", &sysvar_logging_query_enable));
305
    context.registerVariable(new sys_var_const_string_val("filename", vm["filename"].as<string>()));
306
    context.registerVariable(new sys_var_const_string_val("pcre", vm["pcre"].as<string>()));
307
    context.registerVariable(new sys_var_constrained_value<uint32_t>("threshold_slow", sysvar_logging_query_threshold_slow));
308
    context.registerVariable(new sys_var_constrained_value<uint32_t>("threshold_big_resultset", sysvar_logging_query_threshold_big_resultset));
309
    context.registerVariable(new sys_var_constrained_value<uint32_t>("threshold_big_examined", sysvar_logging_query_threshold_big_examined));
310
  }
383.6.1 by Mark Atwood
add pluggable logging
311
312
  return 0;
313
}
314
1660.7.1 by Vijay Samuel
Merge re factored commandline for logging_query using boost::program_options
315
static void init_options(drizzled::module::option_context &context)
316
{
317
  context("enable",
318
          po::value<bool>(&sysvar_logging_query_enable)->default_value(false)->zero_tokens(),
2068.4.1 by Andrew Hutchings
Fix intl domain
319
          _("Enable logging to CSV file"));
1964.2.17 by Monty Taylor
Did logging_query. Fixed rabbitmq.
320
  context("filename",
321
          po::value<string>(),
2068.4.1 by Andrew Hutchings
Fix intl domain
322
          _("File to log to"));
1964.2.17 by Monty Taylor
Did logging_query. Fixed rabbitmq.
323
  context("pcre",
324
          po::value<string>()->default_value(""),
2068.4.1 by Andrew Hutchings
Fix intl domain
325
          _("PCRE to match the query against"));
1660.7.1 by Vijay Samuel
Merge re factored commandline for logging_query using boost::program_options
326
  context("threshold-slow",
1964.2.17 by Monty Taylor
Did logging_query. Fixed rabbitmq.
327
          po::value<uint32_constraint>(&sysvar_logging_query_threshold_slow)->default_value(0),
2068.4.1 by Andrew Hutchings
Fix intl domain
328
          _("Threshold for logging slow queries, in microseconds"));
1660.7.1 by Vijay Samuel
Merge re factored commandline for logging_query using boost::program_options
329
  context("threshold-big-resultset",
1964.2.17 by Monty Taylor
Did logging_query. Fixed rabbitmq.
330
          po::value<uint32_constraint>(&sysvar_logging_query_threshold_big_resultset)->default_value(0),
2068.4.1 by Andrew Hutchings
Fix intl domain
331
          _("Threshold for logging big queries, for rows returned"));
1660.7.1 by Vijay Samuel
Merge re factored commandline for logging_query using boost::program_options
332
  context("threshold-big-examined",
1964.2.17 by Monty Taylor
Did logging_query. Fixed rabbitmq.
333
          po::value<uint32_constraint>(&sysvar_logging_query_threshold_big_examined)->default_value(0),
2068.4.1 by Andrew Hutchings
Fix intl domain
334
          _("Threshold for logging big queries, for rows examined"));
1660.7.1 by Vijay Samuel
Merge re factored commandline for logging_query using boost::program_options
335
}
336
1964.2.17 by Monty Taylor
Did logging_query. Fixed rabbitmq.
337
} /* namespace drizzle_plugin */
438.2.2 by Mark Atwood
sysvar for filename for pluggable query logging to log to
338
1228.1.5 by Monty Taylor
Merged in some naming things.
339
DRIZZLE_DECLARE_PLUGIN
383.6.1 by Mark Atwood
add pluggable logging
340
{
1241.10.2 by Monty Taylor
Added support for embedding the drizzle version number in the plugin file.
341
  DRIZZLE_VERSION_ID,
1660.7.1 by Vijay Samuel
Merge re factored commandline for logging_query using boost::program_options
342
  "logging-query",
812.1.6 by Mark Atwood
logging to syslog
343
  "0.2",
383.6.1 by Mark Atwood
add pluggable logging
344
  "Mark Atwood <mark@fallenpegasus.com>",
812.1.6 by Mark Atwood
logging to syslog
345
  N_("Log queries to a CSV file"),
383.6.1 by Mark Atwood
add pluggable logging
346
  PLUGIN_LICENSE_GPL,
1964.2.17 by Monty Taylor
Did logging_query. Fixed rabbitmq.
347
  drizzle_plugin::logging_query_plugin_init,
348
  NULL,
349
  drizzle_plugin::init_options
383.6.1 by Mark Atwood
add pluggable logging
350
}
1228.1.5 by Monty Taylor
Merged in some naming things.
351
DRIZZLE_DECLARE_PLUGIN_END;