21 #include <drizzled/item.h>
22 #include <drizzled/plugin.h>
23 #include <drizzled/plugin/logging.h>
24 #include <drizzled/gettext.h>
25 #include <drizzled/session.h>
26 #include <drizzled/session/times.h>
27 #include <drizzled/sql_parse.h>
31 #include <sys/types.h>
35 #include <boost/format.hpp>
36 #include <boost/program_options.hpp>
41 namespace po= boost::program_options;
45 #define ESCAPE_CHAR '\\'
46 #define SEPARATOR_CHAR ','
49 namespace logging_query {
52 static bool sysvar_logging_query_enable=
false;
78 static void quotify(
const string &src,
string &dst)
80 static const char hexit[]= {
'0',
'1',
'2',
'3',
'4',
'5',
'6',
'7',
81 '8',
'9',
'a',
'b',
'c',
'd',
'e',
'f' };
82 string::const_iterator src_iter;
84 for (src_iter= src.begin(); src_iter < src.end(); ++src_iter)
86 if (static_cast<unsigned char>(*src_iter) > 0x7f)
88 dst.push_back(*src_iter);
90 else if (*src_iter == 0x00)
92 dst.push_back(ESCAPE_CHAR); dst.push_back(
'0');
94 else if (*src_iter == 0x07)
96 dst.push_back(ESCAPE_CHAR); dst.push_back(
'a');
98 else if (*src_iter == 0x08)
100 dst.push_back(ESCAPE_CHAR); dst.push_back(
'b');
102 else if (*src_iter == 0x09)
104 dst.push_back(ESCAPE_CHAR); dst.push_back(
't');
106 else if (*src_iter == 0x0a)
108 dst.push_back(ESCAPE_CHAR); dst.push_back(
'n');
110 else if (*src_iter == 0x0b)
112 dst.push_back(ESCAPE_CHAR); dst.push_back(
'v');
114 else if (*src_iter == 0x0c)
116 dst.push_back(ESCAPE_CHAR); dst.push_back(
'f');
118 else if (*src_iter == 0x0d)
120 dst.push_back(ESCAPE_CHAR); dst.push_back(
'r');
122 else if (*src_iter == 0x1b)
124 dst.push_back(ESCAPE_CHAR); dst.push_back(
'e');
126 else if (*src_iter == 0x22)
128 dst.push_back(ESCAPE_CHAR); dst.push_back(0x22);
130 else if (*src_iter == SEPARATOR_CHAR)
132 dst.push_back(ESCAPE_CHAR); dst.push_back(SEPARATOR_CHAR);
134 else if (*src_iter == ESCAPE_CHAR)
136 dst.push_back(ESCAPE_CHAR); dst.push_back(ESCAPE_CHAR);
138 else if ((*src_iter < 0x20) || (*src_iter == 0x7F))
140 dst.push_back(ESCAPE_CHAR);
142 dst.push_back(hexit[(*src_iter >> 4) & 0x0f]);
143 dst.push_back(hexit[*src_iter & 0x0f]);
147 dst.push_back(*src_iter);
155 std::string sysvar_filename;
156 std::string sysvar_pcre;
167 const std::string &query_pcre) :
169 sysvar_filename(filename),
170 sysvar_pcre(query_pcre),
171 fd(-1), re(NULL), pe(NULL),
172 formatter(
"%1%,%2%,%3%,\"%4%\",\"%5%\",\"%6%\",%7%,%8%,"
173 "%9%,%10%,%11%,%12%,%13%,%14%,\"%15%\"\n")
177 if (sysvar_filename.empty())
180 fd= open(sysvar_filename.c_str(),
181 O_WRONLY | O_APPEND | O_CREAT,
186 sql_perror( _(
"fail open()"), sysvar_filename);
190 if (not sysvar_pcre.empty())
192 const char *this_pcre_error;
193 int this_pcre_erroffset;
194 re= pcre_compile(sysvar_pcre.c_str(), 0, &this_pcre_error,
195 &this_pcre_erroffset, NULL);
196 pe= pcre_study(re, 0, &this_pcre_error);
209 if (new_filename.empty())
212 int tmp_fd= open(new_filename.c_str(),
213 O_WRONLY | O_APPEND | O_CREAT,
218 sql_perror( _(
"fail open()"), new_filename);
226 sysvar_filename= new_filename;
237 if (not new_pcre.empty())
249 const char *tmp_this_pcre_error;
250 int tmp_this_pcre_erroffset;
251 re= pcre_compile(new_pcre.c_str(), 0, &tmp_this_pcre_error,
252 &tmp_this_pcre_erroffset, NULL);
253 pe= pcre_study(re, 0, &tmp_this_pcre_error);
256 sysvar_pcre= new_pcre;
267 return sysvar_filename;
298 virtual bool post (
Session *session)
302 assert(session != NULL);
315 if (sysvar_logging_query_enable ==
false)
317 if (session->
sent_row_count < sysvar_logging_query_threshold_big_resultset.get())
327 uint64_t t_mark= session->times.getCurrentTimestamp(
false);
329 if (session->times.getElapsedTime() < sysvar_logging_query_threshold_slow.get())
333 if (query_string == NULL)
341 this_pcre_rc= pcre_exec(re, pe, query_string->c_str(), query_string->length(), 0, 0, NULL, 0);
342 if (this_pcre_rc < 0)
351 qs.reserve(query_string->length());
353 quotify(*query_string, qs);
356 util::string::ptr schema(session->schema());
360 % (schema ? schema->c_str() :
"")
362 % getCommandName(session->
command)
363 % (t_mark - session->times.getConnectMicroseconds())
364 % session->times.getElapsedTime()
365 % (t_mark - session->times.utime_after_lock)
369 % session->total_warn_count
371 % getServerHostname();
373 string msgbuf= formatter.str();
376 wrv= write(fd, msgbuf.c_str(), msgbuf.length());
378 assert(wrv == msgbuf.length());
384 static Logging_query *handler= NULL;
395 std::string new_filename(var->value->
str_value.data());
396 if (handler->setFileName(new_filename))
401 errmsg_printf(error::ERROR, _(
"logging_query_filename cannot be NULL"));
414 std::string new_pcre(var->value->
str_value.data());
415 if (handler->setPCRE(new_pcre))
427 if (vm.count(
"filename"))
429 handler=
new Logging_query(vm[
"filename"].as<string>(),
430 vm[
"pcre"].as<string>());
432 context.add(handler);
433 context.registerVariable(
new sys_var_bool_ptr(
"enable", &sysvar_logging_query_enable));
434 context.registerVariable(
new sys_var_std_string(
"filename", handler->getFileName(), NULL, &updateFileName));
435 context.registerVariable(
new sys_var_std_string(
"pcre", handler->getPCRE(), NULL, &updatePCRE));
447 po::value<bool>(&sysvar_logging_query_enable)->default_value(
false)->zero_tokens(),
448 _(
"Enable logging to CSV file"));
451 _(
"File to log to"));
453 po::value<string>()->default_value(
""),
454 _(
"PCRE to match the query against"));
455 context(
"threshold-slow",
456 po::value<uint32_constraint>(&sysvar_logging_query_threshold_slow)->default_value(0),
457 _(
"Threshold for logging slow queries, in microseconds"));
458 context(
"threshold-big-resultset",
459 po::value<uint32_constraint>(&sysvar_logging_query_threshold_big_resultset)->default_value(0),
460 _(
"Threshold for logging big queries, for rows returned"));
461 context(
"threshold-big-examined",
462 po::value<uint32_constraint>(&sysvar_logging_query_threshold_big_examined)->default_value(0),
463 _(
"Threshold for logging big queries, for rows examined"));
470 DRIZZLE_DECLARE_PLUGIN
476 N_(
"Logs queries to a CSV file"),
478 drizzle_plugin::logging_query::init,
480 drizzle_plugin::logging_query::init_options
482 DRIZZLE_DECLARE_PLUGIN_END;
ha_rows examined_row_count
TODO: Rename this file - func.h is stupid.
bool setFileName(std::string new_filename)
std::string & getFileName()
An Proxy Wrapper around boost::program_options::variables_map.
boost::shared_ptr< const std::string > QueryString
query_id_t getQueryId() const
enum_server_command command
uint32_t getServerId() const
bool setPCRE(std::string new_pcre)