~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/logging_query/logging_query.cc

  • Committer: Brian Aker
  • Date: 2008-12-16 07:07:50 UTC
  • Revision ID: brian@tangent.org-20081216070750-o5ykltxxqvn2awrx
Fixed errors test.

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 (C) 2008 Mark Atwood
 
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
 */
 
19
 
 
20
/* need to define DRIZZLE_SERVER to get inside the Session */
 
21
#define DRIZZLE_SERVER 1
 
22
#include <drizzled/server_includes.h>
 
23
#include <drizzled/plugin_logging.h>
 
24
#include <drizzled/gettext.h>
 
25
#include <drizzled/session.h>
 
26
 
 
27
/* todo, make this dynamic as needed */
 
28
#define MAX_MSG_LEN (32*1024)
 
29
 
 
30
static char* logging_query_filename= NULL;
 
31
static bool logging_query_enable= true;
 
32
static ulong logging_query_enable_time= 0;
 
33
static ulong logging_query_threshold_big_resultset= 0;
 
34
 
 
35
static int fd= -1;
 
36
 
 
37
// copied from drizzled/sql_parse.cc
 
38
const LEX_STRING command_name[]={
 
39
  { C_STRING_WITH_LEN("Sleep") },
 
40
  { C_STRING_WITH_LEN("Quit") },
 
41
  { C_STRING_WITH_LEN("InitDB") },
 
42
  { C_STRING_WITH_LEN("Query") },
 
43
  { C_STRING_WITH_LEN("FieldList") },
 
44
  { C_STRING_WITH_LEN("CreateDB") },
 
45
  { C_STRING_WITH_LEN("DropDB") },
 
46
  { C_STRING_WITH_LEN("Refresh") },
 
47
  { C_STRING_WITH_LEN("Shutdown") },
 
48
  { C_STRING_WITH_LEN("Processlist") },
 
49
  { C_STRING_WITH_LEN("Connect") },
 
50
  { C_STRING_WITH_LEN("Kill") },
 
51
  { C_STRING_WITH_LEN("Ping") },
 
52
  { C_STRING_WITH_LEN("Time") },
 
53
  { C_STRING_WITH_LEN("ChangeUser") },
 
54
  { C_STRING_WITH_LEN("BinlogDump") },
 
55
  { C_STRING_WITH_LEN("ConnectOut") },
 
56
  { C_STRING_WITH_LEN("RegisterSlave") },
 
57
  { C_STRING_WITH_LEN("SetOption") },
 
58
  { C_STRING_WITH_LEN("Daemon") },
 
59
  { C_STRING_WITH_LEN("Error") }
 
60
};
 
61
 
 
62
 
 
63
/* stolen from mysys/my_getsystime
 
64
   until the Session has a good utime "now" we can use
 
65
   will have to use this instead */
 
66
 
 
67
#include <sys/time.h>
 
68
static uint64_t get_microtime()
 
69
{
 
70
#if defined(HAVE_GETHRTIME)
 
71
  return gethrtime()/1000;
 
72
#else
 
73
  uint64_t newtime;
 
74
  struct timeval t;
 
75
  /*
 
76
    The following loop is here because gettimeofday may fail on some systems
 
77
  */
 
78
  while (gettimeofday(&t, NULL) != 0) {}
 
79
  newtime= (uint64_t)t.tv_sec * 1000000 + t.tv_usec;
 
80
  return newtime;
 
81
#endif  /* defined(HAVE_GETHRTIME) */
 
82
}
 
83
 
 
84
/* we could just not have a pre entrypoint at all,
 
85
   and have logging_pre == NULL
 
86
   but we have this here for the sake of being an example */
 
87
bool logging_query_func_pre (Session *session __attribute__((unused)))
 
88
{
 
89
  return false;
 
90
}
 
91
 
 
92
bool logging_query_func_post (Session *session)
 
93
{
 
94
  char msgbuf[MAX_MSG_LEN];
 
95
  int msgbuf_len= 0;
 
96
  int wrv;
 
97
 
 
98
  if (fd < 0) return false;
 
99
 
 
100
  assert(session != NULL);
 
101
 
 
102
  /*
 
103
    here is some time stuff from class Session
 
104
      uint64_t connect_utime;
 
105
        todo, looks like this isnt being set
 
106
        we could store the time this plugin was loaded
 
107
        but that would just be a dumb workaround
 
108
      uint64_t start_utime;
 
109
      uint64_t utime_after_lock;
 
110
      uint64_t current_utime();
 
111
        todo, cant get to because of namemangling
 
112
  */
 
113
 
 
114
  /* todo, the Session should have a "utime command completed" inside
 
115
     itself, so be more accurate, and so plugins dont have to keep
 
116
     calling current_utime, which can be slow */
 
117
  uint64_t t_mark= get_microtime();
 
118
 
 
119
  msgbuf_len=
 
120
    snprintf(msgbuf, MAX_MSG_LEN,
 
121
             "thread_id=%ld query_id=%ld"
 
122
             " t_connect=%lld t_start=%lld t_lock=%lld"
 
123
             " command=%.*s"
 
124
             " rows_sent=%ld rows_examined=%u\n"
 
125
             " db=\"%.*s\" query=\"%.*s\"\n",
 
126
             (unsigned long) session->thread_id,
 
127
             (unsigned long) session->query_id,
 
128
             (unsigned long long)(t_mark - session->connect_utime),
 
129
             (unsigned long long)(t_mark - session->start_utime),
 
130
             (unsigned long long)(t_mark - session->utime_after_lock),
 
131
             (uint32_t)command_name[session->command].length,
 
132
             command_name[session->command].str,
 
133
             (unsigned long) session->sent_row_count,
 
134
             (uint32_t) session->examined_row_count,
 
135
             session->db_length, session->db,
 
136
             session->query_length, session->query);
 
137
  /* a single write has a OS level thread lock
 
138
     so there is no need to have mutexes guarding this write,
 
139
  */
 
140
  wrv= write(fd, msgbuf, msgbuf_len);
 
141
  assert(wrv == msgbuf_len);
 
142
 
 
143
  return false;
 
144
}
 
145
 
 
146
static int logging_query_plugin_init(void *p)
 
147
{
 
148
  logging_t *l= (logging_t *) p;
 
149
 
 
150
  if (logging_query_filename == NULL)
 
151
  {
 
152
    /* no destination filename was specified via system variables
 
153
       return now, dont set the callback pointers
 
154
    */
 
155
    return 0;
 
156
  }
 
157
 
 
158
  fd= open(logging_query_filename, O_WRONLY | O_APPEND | O_CREAT,
 
159
           S_IRUSR|S_IWUSR);
 
160
  if (fd < 0)
 
161
  {
 
162
    sql_print_error(_("fail open() fn=%s er=%s\n"),
 
163
                    logging_query_filename,
 
164
                    strerror(errno));
 
165
 
 
166
    /* todo
 
167
       we should return an error here, so the plugin doesnt load
 
168
       but this causes Drizzle to crash
 
169
       so until that is fixed,
 
170
       just return a success,
 
171
       but leave the function pointers as NULL and the fd as -1
 
172
    */
 
173
    return 0;
 
174
  }
 
175
 
 
176
  l->logging_pre= logging_query_func_pre;
 
177
  l->logging_post= logging_query_func_post;
 
178
 
 
179
  return 0;
 
180
}
 
181
 
 
182
static int logging_query_plugin_deinit(void *p)
 
183
{
 
184
  logging_st *l= (logging_st *) p;
 
185
 
 
186
  if (fd >= 0)
 
187
  {
 
188
    close(fd);
 
189
    fd= -1;
 
190
  }
 
191
 
 
192
  l->logging_pre= NULL;
 
193
  l->logging_post= NULL;
 
194
 
 
195
  return 0;
 
196
}
 
197
 
 
198
static DRIZZLE_SYSVAR_STR(
 
199
  filename,
 
200
  logging_query_filename,
 
201
  PLUGIN_VAR_READONLY,
 
202
  N_("File to log to"),
 
203
  NULL, /* check func */
 
204
  NULL, /* update func*/
 
205
  NULL /* default */);
 
206
 
 
207
static DRIZZLE_SYSVAR_BOOL(
 
208
  enable,
 
209
  logging_query_enable,
 
210
  PLUGIN_VAR_NOCMDARG,
 
211
  N_("Enable logging"),
 
212
  NULL, /* check func */
 
213
  NULL, /* update func */
 
214
  true /* default */);
 
215
 
 
216
static DRIZZLE_SYSVAR_ULONG(
 
217
  enable_time,
 
218
  logging_query_enable_time,
 
219
  PLUGIN_VAR_OPCMDARG,
 
220
  N_("Disable after this many seconds. Zero for forever"),
 
221
  NULL, /* check func */
 
222
  NULL, /* update func */
 
223
  0, /* default */
 
224
  0, /* min */
 
225
  ULONG_MAX, /* max */
 
226
  0 /* blksiz */);
 
227
 
 
228
#ifdef NOT_YET
 
229
static DRIZZLE_SYSVAR_ULONG(
 
230
  threshhold_slow,
 
231
  logging_query_threshold_slow,
 
232
  PLUGIN_VAR_OPCMDARG,
 
233
  N_("Threshold for logging slow queries, in microseconds"),
 
234
  NULL, /* check func */
 
235
  NULL, /* update func */
 
236
  0, /* default */
 
237
  0, /* min */
 
238
  ULONG_MAX, /* max */
 
239
  0 /* blksiz */);
 
240
#endif
 
241
 
 
242
static DRIZZLE_SYSVAR_ULONG(
 
243
  threshold_big_resultset,
 
244
  logging_query_threshold_big_resultset,
 
245
  PLUGIN_VAR_OPCMDARG,
 
246
  N_("Threshold for logging big queries, for rows returned"),
 
247
  NULL, /* check func */
 
248
  NULL, /* update func */
 
249
  0, /* default */
 
250
  0, /* min */
 
251
  ULONG_MAX, /* max */
 
252
  0 /* blksiz */);
 
253
 
 
254
#ifdef NOT_YET
 
255
static DRIZZLE_SYSVAR_ULONG(
 
256
  threshhold_big_examined,
 
257
  logging_query_threshold_big_examined,
 
258
  PLUGIN_VAR_OPCMDARG,
 
259
  N_("Threshold for logging big queries, for rows examined"),
 
260
  NULL, /* check func */
 
261
  NULL, /* update func */
 
262
  0, /* default */
 
263
  0, /* min */
 
264
  ULONG_MAX, /* max */
 
265
  0 /* blksiz */);
 
266
#endif
 
267
 
 
268
static struct st_mysql_sys_var* logging_query_system_variables[]= {
 
269
  DRIZZLE_SYSVAR(filename),
 
270
  DRIZZLE_SYSVAR(enable),
 
271
  DRIZZLE_SYSVAR(enable_time),
 
272
  DRIZZLE_SYSVAR(threshold_big_resultset),
 
273
  NULL
 
274
};
 
275
 
 
276
mysql_declare_plugin(logging_query)
 
277
{
 
278
  DRIZZLE_LOGGER_PLUGIN,
 
279
  "logging_query",
 
280
  "0.1",
 
281
  "Mark Atwood <mark@fallenpegasus.com>",
 
282
  N_("Log queries to a file"),
 
283
  PLUGIN_LICENSE_GPL,
 
284
  logging_query_plugin_init,
 
285
  logging_query_plugin_deinit,
 
286
  NULL,   /* status variables */
 
287
  logging_query_system_variables,
 
288
  NULL
 
289
}
 
290
mysql_declare_plugin_end;