~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/query_log/module.cc

  • Committer: Mark Atwood
  • Date: 2011-08-06 22:44:31 UTC
  • mfrom: (2311.1.10 query-log-plugin)
  • Revision ID: me@mark.atwood.name-20110806224431-57s1770jarqncrl7
mergeĀ lp:~daniel-nichter/drizzle/query-log-plugin

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* - mode: c; c-basic-offset: 2; indent-tabs-mode: nil; -*-
 
2
 *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
 
3
 *
 
4
 *  Copyright 2011 Daniel Nichter
 
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, either version 3 of the License, or
 
9
 *  (at your option) any later version.
 
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
 
17
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
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
 
 
34
namespace drizzle_plugin
 
35
{
 
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);
 
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
 
 
81
  if (!new_file)
 
82
  {
 
83
    errmsg_printf(error::ERROR, _("The query log file name must be defined."));
 
84
    return false;
 
85
  }
 
86
 
 
87
  if (strlen(new_file) == 0)
 
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);