2
* Copyright (c) 2010, Joseph Daly <skinny.moey@gmail.com>
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted provided that the following conditions are met:
8
* * Redistributions of source code must retain the above copyright notice,
9
* this list of conditions and the following disclaimer.
10
* * Redistributions in binary form must reproduce the above copyright notice,
11
* this list of conditions and the following disclaimer in the documentation
12
* and/or other materials provided with the distribution.
13
* * Neither the name of Joseph Daly nor the names of its contributors
14
* may be used to endorse or promote products derived from this software
15
* without specific prior written permission.
17
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27
* THE POSSIBILITY OF SUCH DAMAGE.
33
* This plugin tracks session and global statistics, as well as user statistics.
34
* The commands are logged using the post() and postEnd() logging APIs.
35
* The statistics are stored in a Scoreboard where each active session owns a
36
* ScoreboardSlot during the sessions active lifetime.
40
* The scoreboard is a pre-allocated vector of vectors of ScoreboardSlots. It
41
* can be thought of as a vector of buckets where each bucket contains
42
* pre-allocated ScoreboardSlots. To determine which bucket gets used for
43
* recording statistics the modulus operator is used on the session_id. This
44
* will result in a bucket to search for a unused ScoreboardSlot. Once a
45
* ScoreboardSlot is found the index of the slot is stored in the Session
50
* Each vector in the Scoreboard has its own lock. This allows session 2
51
* to not have to wait for session 1 to locate a slot to use, as they
52
* will be in different buckets. A lock is taken to locate a open slot
53
* in the scoreboard. Subsequent queries by the session will not take
56
* A read lock is taken on the scoreboard vector when the table is queried
57
* in the data_dictionary. The "show status" and "show global status" do
58
* not take a read lock when the data_dictionary table is queried, the
59
* user is not displayed in these results so it is not necessary.
63
* The cumulative statistics use atomics, for the index into the vector
64
* marking the last index that is used by a user. New users will increment
65
* the atomic and claim the slot for use.
69
* logging_stats_scoreboard_size - the size of the scoreboard this corresponds
70
* to the maximum number of concurrent connections that can be tracked
72
* logging_stats_max_user_count - this is used for cumulative statistics it
73
* represents the maximum users that can be tracked
75
* logging_stats_bucket_count - the number of buckets to have in the scoreboard
76
* this splits up locking across several buckets so the entire scoreboard is
77
* not locked at a single point in time.
79
* logging_stats_enabled - enable/disable plugin
83
* Allow expansion of Scoreboard and cumulative vector
88
#include "user_commands.h"
89
#include "status_vars.h"
90
#include "global_stats.h"
91
#include "logging_stats.h"
92
#include "status_tool.h"
93
#include "stats_schema.h"
94
#include <boost/program_options.hpp>
95
#include <drizzled/module/option_map.h>
96
#include <drizzled/session.h>
98
namespace po= boost::program_options;
99
using namespace drizzled;
100
using namespace plugin;
103
static bool sysvar_logging_stats_enabled= true;
105
static uint32_t sysvar_logging_stats_scoreboard_size= 2000;
107
static uint32_t sysvar_logging_stats_max_user_count= 500;
109
static uint32_t sysvar_logging_stats_bucket_count= 10;
111
LoggingStats::LoggingStats(string name_arg) : Logging(name_arg)
113
current_scoreboard= new Scoreboard(sysvar_logging_stats_scoreboard_size,
114
sysvar_logging_stats_bucket_count);
116
cumulative_stats= new CumulativeStats(sysvar_logging_stats_max_user_count);
119
LoggingStats::~LoggingStats()
121
delete current_scoreboard;
122
delete cumulative_stats;
125
void LoggingStats::updateCurrentScoreboard(ScoreboardSlot *scoreboard_slot,
128
enum_sql_command sql_command= session->lex->sql_command;
130
scoreboard_slot->getUserCommands()->logCommand(sql_command);
132
/* If a flush occurred copy over values before setting new values */
133
if (scoreboard_slot->getStatusVars()->hasBeenFlushed(session))
135
cumulative_stats->logGlobalStatusVars(scoreboard_slot);
137
scoreboard_slot->getStatusVars()->logStatusVar(session);
140
bool LoggingStats::resetGlobalScoreboard()
142
cumulative_stats->getGlobalStatusVars()->reset();
143
cumulative_stats->getGlobalStats()->getUserCommands()->reset();
145
ScoreBoardVectors *vector_of_scoreboard_vectors=
146
current_scoreboard->getVectorOfScoreboardVectors();
148
ScoreBoardVectors::iterator v_of_scoreboard_v_begin_it= vector_of_scoreboard_vectors->begin();
150
ScoreBoardVectors::iterator v_of_scoreboard_v_end_it= vector_of_scoreboard_vectors->end();
152
for (; v_of_scoreboard_v_begin_it != v_of_scoreboard_v_end_it; ++v_of_scoreboard_v_begin_it)
154
vector<ScoreboardSlot* > *scoreboard_vector= *v_of_scoreboard_v_begin_it;
156
vector<ScoreboardSlot* >::iterator scoreboard_vector_it= scoreboard_vector->begin();
157
vector<ScoreboardSlot* >::iterator scoreboard_vector_end= scoreboard_vector->end();
158
for (; scoreboard_vector_it != scoreboard_vector_end; ++scoreboard_vector_it)
160
ScoreboardSlot *scoreboard_slot= *scoreboard_vector_it;
161
scoreboard_slot->getStatusVars()->reset();
162
scoreboard_slot->getUserCommands()->reset();
169
bool LoggingStats::post(Session *session)
171
if (! isEnabled() || (session->getSessionId() == 0))
176
ScoreboardSlot *scoreboard_slot= current_scoreboard->findScoreboardSlotToLog(session);
178
/* Its possible that the scoreboard is full with active sessions in which case
179
this could be null */
182
updateCurrentScoreboard(scoreboard_slot, session);
187
bool LoggingStats::postEnd(Session *session)
189
if (! isEnabled() || (session->getSessionId() == 0))
194
bool isInScoreboard= false;
195
ScoreboardSlot *scoreboard_slot= current_scoreboard->findOurScoreboardSlot(session);
199
isInScoreboard= true;
203
/* the session did not have a slot reserved, that could be because the scoreboard was
204
full, but most likely its a failed authentication so post() is never called where
205
the slot is assigned. Log the global status values below, and if the user has a slot
206
log to it, but do not reserve a new slot for a user. If it was a failed authentication
207
the scoreboard would be filled up quickly with invalid users.
209
scoreboard_slot= new ScoreboardSlot();
210
scoreboard_slot->setUser(session->getSecurityContext().getUser());
211
scoreboard_slot->setIp(session->getSecurityContext().getIp());
214
scoreboard_slot->getStatusVars()->logStatusVar(session);
215
scoreboard_slot->getStatusVars()->getStatusVarCounters()->connection_time= time(NULL) - session->start_time;
217
cumulative_stats->logUserStats(scoreboard_slot, isInScoreboard);
218
cumulative_stats->logGlobalStats(scoreboard_slot);
219
cumulative_stats->logGlobalStatusVars(scoreboard_slot);
223
scoreboard_slot->reset();
227
delete scoreboard_slot;
233
/* Plugin initialization and system variables */
235
static LoggingStats *logging_stats= NULL;
237
static CurrentCommandsTool *current_commands_tool= NULL;
239
static CumulativeCommandsTool *cumulative_commands_tool= NULL;
241
static GlobalStatementsTool *global_statements_tool= NULL;
243
static SessionStatementsTool *session_statements_tool= NULL;
245
static StatusTool *global_status_tool= NULL;
247
static StatusTool *session_status_tool= NULL;
249
static CumulativeUserStatsTool *cumulative_user_stats_tool= NULL;
251
static ScoreboardStatsTool *scoreboard_stats_tool= NULL;
253
static void enable(Session *,
260
if (*(bool *)save != false)
262
logging_stats->enable();
263
*(bool *) var_ptr= (bool) true;
267
logging_stats->disable();
268
*(bool *) var_ptr= (bool) false;
273
static bool initTable()
275
current_commands_tool= new(nothrow)CurrentCommandsTool(logging_stats);
277
if (! current_commands_tool)
282
cumulative_commands_tool= new(nothrow)CumulativeCommandsTool(logging_stats);
284
if (! cumulative_commands_tool)
289
global_statements_tool= new(nothrow)GlobalStatementsTool(logging_stats);
291
if (! global_statements_tool)
296
session_statements_tool= new(nothrow)SessionStatementsTool(logging_stats);
298
if (! session_statements_tool)
303
session_status_tool= new(nothrow)StatusTool(logging_stats, true);
305
if (! session_status_tool)
310
global_status_tool= new(nothrow)StatusTool(logging_stats, false);
312
if (! global_status_tool)
317
cumulative_user_stats_tool= new(nothrow)CumulativeUserStatsTool(logging_stats);
319
if (! cumulative_user_stats_tool)
324
scoreboard_stats_tool= new(nothrow)ScoreboardStatsTool(logging_stats);
326
if (! scoreboard_stats_tool)
334
static int init(drizzled::module::Context &context)
336
const module::option_map &vm= context.getOptions();
338
sysvar_logging_stats_enabled= (vm.count("disable")) ? false : true;
340
if (vm.count("max-user-count"))
342
if (sysvar_logging_stats_max_user_count < 100 || sysvar_logging_stats_max_user_count > 50000)
344
errmsg_printf(ERRMSG_LVL_ERROR, _("Invalid value for max-user-count\n"));
348
if (vm.count("bucket-count"))
350
if (sysvar_logging_stats_bucket_count < 5 || sysvar_logging_stats_bucket_count > 500)
352
errmsg_printf(ERRMSG_LVL_ERROR, _("Invalid value for bucket-count\n"));
357
if (vm.count("scoreboard-size"))
359
if (sysvar_logging_stats_scoreboard_size < 10 || sysvar_logging_stats_scoreboard_size > 50000)
361
errmsg_printf(ERRMSG_LVL_ERROR, _("Invalid value for scoreboard-size\n"));
365
sysvar_logging_stats_scoreboard_size= vm["scoreboard-size"].as<uint32_t>();
368
logging_stats= new LoggingStats("logging_stats");
375
context.add(logging_stats);
376
context.add(current_commands_tool);
377
context.add(cumulative_commands_tool);
378
context.add(global_statements_tool);
379
context.add(session_statements_tool);
380
context.add(session_status_tool);
381
context.add(global_status_tool);
382
context.add(cumulative_user_stats_tool);
383
context.add(scoreboard_stats_tool);
385
if (sysvar_logging_stats_enabled)
387
logging_stats->enable();
393
static DRIZZLE_SYSVAR_UINT(max_user_count,
394
sysvar_logging_stats_max_user_count,
396
N_("Max number of users that will be logged"),
397
NULL, /* check func */
398
NULL, /* update func */
404
static DRIZZLE_SYSVAR_UINT(bucket_count,
405
sysvar_logging_stats_bucket_count,
407
N_("Max number of range locks to use for Scoreboard"),
408
NULL, /* check func */
409
NULL, /* update func */
415
static DRIZZLE_SYSVAR_UINT(scoreboard_size,
416
sysvar_logging_stats_scoreboard_size,
418
N_("Max number of concurrent sessions that will be logged"),
419
NULL, /* check func */
420
NULL, /* update func */
426
static DRIZZLE_SYSVAR_BOOL(enable,
427
sysvar_logging_stats_enabled,
429
N_("Enable Logging Statistics Collection"),
430
NULL, /* check func */
431
enable, /* update func */
434
static void init_options(drizzled::module::option_context &context)
436
context("max-user-count",
437
po::value<uint32_t>(&sysvar_logging_stats_max_user_count)->default_value(500),
438
N_("Max number of users that will be logged"));
439
context("bucket-count",
440
po::value<uint32_t>(&sysvar_logging_stats_bucket_count)->default_value(10),
441
N_("Max number of range locks to use for Scoreboard"));
442
context("scoreboard-size",
443
po::value<uint32_t>(&sysvar_logging_stats_scoreboard_size)->default_value(2000),
444
N_("Max number of concurrent sessions that will be logged"));
445
context("disable", N_("Enable Logging Statistics Collection"));
448
static drizzle_sys_var* system_var[]= {
449
DRIZZLE_SYSVAR(max_user_count),
450
DRIZZLE_SYSVAR(bucket_count),
451
DRIZZLE_SYSVAR(scoreboard_size),
452
DRIZZLE_SYSVAR(enable),
456
DRIZZLE_DECLARE_PLUGIN
462
N_("User Statistics as DATA_DICTIONARY tables"),
464
init, /* Plugin Init */
465
system_var, /* system variables */
466
init_options /* config options */
468
DRIZZLE_DECLARE_PLUGIN_END;