~drizzle-trunk/drizzle/development

2311.1.3 by Daniel Nichter
Change to GPLv3 license.
1
/* - mode: c; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2311.1.1 by Daniel Nichter
Add query_log plugin. It's tested and documented.
2
 *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
3
 *
2311.1.3 by Daniel Nichter
Change to GPLv3 license.
4
 *  Copyright 2011 Daniel Nichter
2311.1.1 by Daniel Nichter
Add query_log plugin. It's tested and documented.
5
 *
2311.1.3 by Daniel Nichter
Change to GPLv3 license.
6
 *  This program is free software: you can redistribute it and/or modify
2311.1.1 by Daniel Nichter
Add query_log plugin. It's tested and documented.
7
 *  it under the terms of the GNU General Public License as published by
2311.1.3 by Daniel Nichter
Change to GPLv3 license.
8
 *  the Free Software Foundation, either version 3 of the License, or
9
 *  (at your option) any later version.
2311.1.1 by Daniel Nichter
Add query_log plugin. It's tested and documented.
10
 *
11
 *  This program is distributed in the hope that it will be useful,
12
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 *  GNU General Public License for more details.
15
 *
16
 *  You should have received a copy of the GNU General Public License
2311.1.3 by Daniel Nichter
Change to GPLv3 license.
17
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
2311.1.1 by Daniel Nichter
Add query_log plugin. It's tested and documented.
18
 */
19
20
#include <config.h>
21
#include <string>
22
#include <boost/program_options.hpp>
23
#include <drizzled/item.h>
24
#include <drizzled/data_home.h>
25
#include <drizzled/module/option_map.h>
26
#include <drizzled/session.h>
27
#include <drizzled/plugin.h>
28
#include "query_log.h"
29
30
namespace po= boost::program_options;
31
using namespace std;
32
using namespace drizzled;
33
2385.3.30 by Olaf van der Spek
cppcheck
34
namespace drizzle_plugin {
35
2311.1.6 by Daniel Nichter
Fix -Wmissing-declarations warnings by adding forward declarations.
36
/**
37
 * Forward declarations.
38
 * Mac OS X 10.6 with gcc 4.2.1 misses this warning (but still compiles):
39
 *   configure:23893: g++ -c -Werror -pedantic -Wmissing-declarations \
40
 *     -std=gnu++98  -O0 -DDEBUG   conftest.cpp >&5
41
 *   cc1plus: warnings being treated as errors
42
 *   cc1plus: warning: command line option "-Wmissing-declarations" is valid
43
 *     for C/ObjC but not for C++
44
 */
45
bool update_file(Session *, set_var *var);
46
void update_file_enabled(Session *, sql_var_t);
2311.1.1 by Daniel Nichter
Add query_log plugin. It's tested and documented.
47
48
/**
49
 * An instance of our class, QueryLog, which implements the query_log plugin,
50
 * and an instance of the QueryLoggerClass for logging queries to a file.
51
 * These objects are global so update_file() and update_file_enabled() can
52
 * access them.  They're instantiated in init_options().
53
 */
54
static drizzled::plugin::QueryLog *query_log= NULL;
55
static QueryLoggerFile *logger_file= NULL;
56
57
/**
58
 * Sensible defaults.
59
 */
60
const char *default_file= "drizzled-queries.log"; ///< Default query log file
61
62
/**
63
 * @brief
64
 *   Update query_log_file (query_log->sysvar_file).
65
 *
66
 * @details
67
 *   When SET GLOBAL query_log_file="new-file.log" is executed by the user,
68
 *   this function is called which checkes that the new file is not NULL or
69
 *   a blank string, then calls logger_file->openLogFile, passing it the new
70
 *   log file name, e.g. "new-file.log".  If the new log file is opened, the
71
 *   system variable is updated, else it is not updated and logging continues
72
 *   to the old log file.
73
 *
74
 * @retval true  Error, log file not changed
75
 * @retval false Success, log file changed
76
 */  
77
bool update_file(Session *, set_var *var)
78
{
79
  const char *new_file= var->value->str_value.ptr();
80
2385.3.30 by Olaf van der Spek
cppcheck
81
  if (not new_file)
2311.1.1 by Daniel Nichter
Add query_log plugin. It's tested and documented.
82
  {
83
    errmsg_printf(error::ERROR, _("The query log file name must be defined."));
84
    return false;
85
  }
86
2385.3.30 by Olaf van der Spek
cppcheck
87
  if (not *new_file)
2311.1.1 by Daniel Nichter
Add query_log plugin. It's tested and documented.
88
  {
89
    errmsg_printf(error::ERROR, _("The query log file name must have a value."));
90
    return false;
91
  }
92
93
  /**
94
   * If the the log file is enabled, then try to open the new log file.
95
   * If it's not enabled, then just update query_log_file because the user
96
   * might be trying to:
97
   *   close current log file (SET GLOBAL log_file_enabled=FALSE)
98
   *   switch to new log file (SET GLOBAL log_file="new-file.log")
99
   *   enable new log file (SET GLOBAL log_file_enabled=TRUE)
100
   * (Maybe they're doing this to rotate the log?)  If this is the case,
101
   * then we don't want to open the new log file before it's enabled,
102
   * but we also don't want to leave query_log_file set to the old log
103
   * file name.  When the log file is re-enabled later, update_file_enabled()
104
   * will be called and the new log file will be opened.
105
   */
106
  if (query_log->sysvar_file_enabled)
107
  {
108
    if (logger_file->openLogFile(new_file))
109
    {
110
      errmsg_printf(error::ERROR, "Cannot open the query log file %s", new_file);
111
      return true; // error
112
    }
113
  }
114
115
  // Update query_log_file in SHOW VARIABLES.
116
  query_log->sysvar_file= new_file;
117
118
  return false;  // success
119
}
120
121
/**
122
 * @brief
123
 *   Update query_log_file_enabled (query_log->sysvar_file_enabled).
124
 *
125
 * @details
126
 *   When SET GLOBAL query_log_file_enabled=... is executed by the user,
127
 *   this function is called *after* Drizzle updates the variable with the
128
 *   new value, so in this function we have the new/current value.  If the
129
 *   log file is enabled, then open query_log_file (query_log->sysvar_file);
130
 *   else, close the log file.
131
 */  
132
void update_file_enabled(Session *, sql_var_t)
133
{
134
  if (query_log->sysvar_file_enabled)
135
  {
136
    if (logger_file->openLogFile(query_log->sysvar_file.c_str()))
137
    {
138
      errmsg_printf(error::ERROR, "Cannot enable the query log file because the query log file %s cannot be opened.", query_log->sysvar_file.c_str());
139
      query_log->sysvar_file_enabled= false;
140
    }
141
  }
142
  else
143
    logger_file->closeLogFile();
144
}
145
146
/**
147
 * @brief
148
 *   Initialize query-log command line options.
149
 *
150
 * @details
151
 *   This function is called first, before init().  We instantiate our one
152
 *   and only QueryLog object (query_log) here so that po (boost::program_options)
153
 *   can store the command line options' values in public query_log variables.
154
 *   This avoids using global variables and keeps (almost) everything encapsulated
155
 *   in query_log.
156
 */
157
static void init_options(drizzled::module::option_context &context)
158
{
159
  logger_file= new QueryLoggerFile();
160
  query_log= new drizzled::plugin::QueryLog(true, logger_file);
161
162
  context(
163
    "file-enabled",
164
    po::value<bool>(&query_log->sysvar_file_enabled)->default_value(false)->zero_tokens(),
165
    N_("Enable query logging to file"));
166
167
  context(
168
    "file",
169
    po::value<string>(&query_log->sysvar_file)->default_value(default_file),
170
    N_("Query log file"));
171
172
  context(
173
    "threshold-execution-time",
174
    po::value<uint32_constraint>(&query_log->sysvar_threshold_execution_time)->default_value(0),
175
    _("Threshold for logging slow queries, in microseconds"));
176
  
177
  context(
178
    "threshold-lock-time",
179
    po::value<uint32_constraint>(&query_log->sysvar_threshold_lock_time)->default_value(0),
180
    _("Threshold for logging long locking queries, in microseconds"));
181
  
182
  context(
183
    "threshold-rows-examined",
184
    po::value<uint32_constraint>(&query_log->sysvar_threshold_rows_examined)->default_value(0),
185
    _("Threshold for logging queries that examine too many rows, integer"));
186
  
187
  context(
188
    "threshold-rows-sent",
189
    po::value<uint32_constraint>(&query_log->sysvar_threshold_rows_sent)->default_value(0),
190
    _("Threshold for logging queries that return too many rows, integer"));
191
  
192
  context(
193
    "threshold-tmp-tables",
194
    po::value<uint32_constraint>(&query_log->sysvar_threshold_tmp_tables)->default_value(0),
195
    _("Threshold for logging queries that use too many temporary tables, integer"));
196
197
  context(
198
    "threshold-warnings",
199
    po::value<uint32_constraint>(&query_log->sysvar_threshold_warnings)->default_value(0),
200
    _("Threshold for logging queries that cause too many warnings, integer"));
201
202
  context(
203
    "threshold-session-time",
204
    po::value<uint32_constraint>(&query_log->sysvar_threshold_session_time)->default_value(0),
205
    _("Threshold for logging queries that are active too long, in seconds"));
206
207
}
208
209
/**
210
 * @brief
211
 *   Add query_log plugin to Drizzle and initalize query_log system variables.
212
 *
213
 * @details
214
 *   This is where we plug into Drizzle and register our system variables.
215
 *   Since this is called after init_options(), vm has either values from
216
 *   the command line or defaults.  System variables corresponding to
217
 *   command line options use the same public query_log variables so that
218
 *   values from vm (the command line) are automatically reflected in the
219
 *   system variable (SHOW VARIABLES).  This also makes changes to certain
220
 *   system variables automatic/instant because when they're updated (e.g.
221
 *   SET GLOBAL query_log_enabled=TRUE|FALSE) Drizzle changes the corresponding
222
 *   public query_log variable.  Certain system variables, like query_log_file,
223
 *   require more work to change, so they're handled by update functions like
224
 *   update_file().
225
 *
226
 * @retval 0 Success
227
 */
228
static int init(drizzled::module::Context &context)
229
{
230
  const module::option_map &vm= context.getOptions();
231
232
  // Open the log file now that we have either an explicit value from the
233
  // command line (--query-log.file=FILE) or the default file.
234
  if (vm["file-enabled"].as<bool>())
235
    logger_file->openLogFile(vm["file"].as<string>().c_str());
236
237
  // Plug into Drizzle!
238
  context.add(query_log);
239
240
  // Register our system variables with Drizzle, e.g. query_log_enabled,
241
  // query_log_file, etc. in SHOW VARIABLES.
242
  context.registerVariable(
243
    new sys_var_bool_ptr(
244
      "enabled", &query_log->sysvar_enabled));
245
246
  context.registerVariable(
247
    new sys_var_bool_ptr(
248
      "file_enabled", &query_log->sysvar_file_enabled, &update_file_enabled));
249
250
  context.registerVariable(
251
    new sys_var_std_string(
252
      "file", query_log->sysvar_file, NULL, &update_file));
253
254
  context.registerVariable(
255
    new sys_var_constrained_value<uint32_t>(
256
      "threshold_execution_time", query_log->sysvar_threshold_execution_time));
257
  
258
  context.registerVariable(
259
    new sys_var_constrained_value<uint32_t>(
260
      "threshold_lock_time", query_log->sysvar_threshold_lock_time));
261
  
262
  context.registerVariable(
263
    new sys_var_constrained_value<uint32_t>(
264
      "threshold_rows_examined", query_log->sysvar_threshold_rows_examined));
265
  
266
  context.registerVariable(
267
    new sys_var_constrained_value<uint32_t>(
268
      "threshold_rows_sent", query_log->sysvar_threshold_rows_sent));
269
  
270
  context.registerVariable(
271
    new sys_var_constrained_value<uint32_t>(
272
      "threshold_tmp_tables", query_log->sysvar_threshold_tmp_tables));
273
  
274
  context.registerVariable(
275
    new sys_var_constrained_value<uint32_t>(
276
      "threshold_warnings", query_log->sysvar_threshold_warnings));
277
278
  context.registerVariable(
279
    new sys_var_constrained_value<uint32_t>(
280
      "threshold_session_time", query_log->sysvar_threshold_session_time));
281
282
  return 0; // success
283
}
284
285
} /* namespace drizzle_plugin */
286
287
DRIZZLE_PLUGIN(drizzle_plugin::init, NULL, drizzle_plugin::init_options);