Merge lp:~fallenpegasus/drizzle/logging_gearman into lp:~drizzle-trunk/drizzle/development

Proposed by Mark Atwood
Status: Merged
Merged at revision: not available
Proposed branch: lp:~fallenpegasus/drizzle/logging_gearman
Merge into: lp:~drizzle-trunk/drizzle/development
Diff against target: None lines
To merge this branch: bzr merge lp:~fallenpegasus/drizzle/logging_gearman
Reviewer Review Type Date Requested Status
Drizzle Developers Pending
Review via email: mp+4126@code.launchpad.net
To post a comment you must log in.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== added directory 'plugin/logging_gearman'
=== added file 'plugin/logging_gearman/AUTHORS'
--- plugin/logging_gearman/AUTHORS 1970-01-01 00:00:00 +0000
+++ plugin/logging_gearman/AUTHORS 2009-03-04 01:02:00 +0000
@@ -0,0 +1,2 @@
1Mark Atwood <mark@fallenpegasus.com>
2
03
=== added file 'plugin/logging_gearman/ChangeLog'
--- plugin/logging_gearman/ChangeLog 1970-01-01 00:00:00 +0000
+++ plugin/logging_gearman/ChangeLog 2009-03-04 01:02:00 +0000
@@ -0,0 +1,2 @@
10.1
2 - Added
03
=== added file 'plugin/logging_gearman/Makefile.am'
--- plugin/logging_gearman/Makefile.am 1970-01-01 00:00:00 +0000
+++ plugin/logging_gearman/Makefile.am 2009-03-04 01:02:00 +0000
@@ -0,0 +1,14 @@
1if BUILD_LOGGING_GEARMAN
2
3EXTRA_LTLIBRARIES = liblogging_gearman.la
4pkgplugin_LTLIBRARIES = @plugin_logging_gearman_shared_target@
5liblogging_gearman_la_LDFLAGS = -module -avoid-version -rpath $(pkgplugindir)
6liblogging_gearman_la_LIBADD= ${LIBGEARMAN}
7liblogging_gearman_la_CPPFLAGS = ${AM_CPPFLAGS} -DDRIZZLE_DYNAMIC_PLUGIN
8liblogging_gearman_la_SOURCES = logging_gearman.cc
9
10EXTRA_LIBRARIES = liblogging_gearman.a
11noinst_LIBRARIES = @plugin_logging_gearman_static_target@
12liblogging_gearman_a_SOURCES = $(liblogging_gearman_la_SOURCES)
13
14endif
015
=== added file 'plugin/logging_gearman/logging_gearman.cc'
--- plugin/logging_gearman/logging_gearman.cc 1970-01-01 00:00:00 +0000
+++ plugin/logging_gearman/logging_gearman.cc 2009-03-04 01:02:00 +0000
@@ -0,0 +1,331 @@
1/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2 * vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
3 *
4 * Copyright (C) 2008,2009 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#include <drizzled/server_includes.h>
21#include <drizzled/plugin_logging.h>
22#include <drizzled/gettext.h>
23#include <drizzled/session.h>
24
25#include <libgearman/gearman.h>
26
27
28/* TODO make this dynamic as needed */
29static const int MAX_MSG_LEN= 32*1024;
30
31static bool sysvar_logging_gearman_enable= false;
32static char* sysvar_logging_gearman_host= NULL;
33
34static gearman_client_st gearman_client;
35
36
37/* stolen from mysys/my_getsystime
38 until the Session has a good utime "now" we can use
39 will have to use this instead */
40
41#include <sys/time.h>
42static uint64_t get_microtime()
43{
44#if defined(HAVE_GETHRTIME)
45 return gethrtime()/1000;
46#else
47 uint64_t newtime;
48 struct timeval t;
49 /*
50 The following loop is here because gettimeofday may fail on some systems
51 */
52 while (gettimeofday(&t, NULL) != 0) {}
53 newtime= (uint64_t)t.tv_sec * 1000000 + t.tv_usec;
54 return newtime;
55#endif /* defined(HAVE_GETHRTIME) */
56}
57
58/* quote a string to be safe to include in a CSV line
59 that means backslash quoting all commas, doublequotes, backslashes,
60 and all the ASCII unprintable characters
61 as long as we pass the high-bit bytes unchanged
62 this is safe to do to a UTF8 string
63 we dont allow overrunning the targetbuffer
64 to avoid having a very long query overwrite memory
65
66 TODO consider remapping the unprintables instead to "Printable
67 Representation", the Unicode characters from the area U+2400 to
68 U+2421 reserved for representing control characters when it is
69 necessary to print or display them rather than have them perform
70 their intended function.
71
72*/
73static unsigned char *quotify (const unsigned char *src, size_t srclen,
74 unsigned char *dst, size_t dstlen)
75{
76 static const char hexit[]= { '0', '1', '2', '3', '4', '5', '6', '7',
77 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
78 size_t dst_ndx; /* ndx down the dst */
79 size_t src_ndx; /* ndx down the src */
80
81 assert(dst);
82 assert(dstlen > 0);
83
84 for (dst_ndx= 0,src_ndx= 0; src_ndx < srclen; src_ndx++)
85 {
86
87 /* Worst case, need 5 dst bytes for the next src byte.
88 backslash x hexit hexit null
89 so if not enough room, just terminate the string and return
90 */
91 if ((dstlen - dst_ndx) < 5)
92 {
93 dst[dst_ndx]= (unsigned char)0x00;
94 return dst;
95 }
96
97 if (src[src_ndx] > 0x7f)
98 {
99 // pass thru high bit characters, they are non-ASCII UTF8 Unicode
100 dst[dst_ndx++]= src[src_ndx];
101 }
102 else if (src[src_ndx] == 0x00) // null
103 {
104 dst[dst_ndx++]= 0x5C; dst[dst_ndx++]= (unsigned char) '0';
105 }
106 else if (src[src_ndx] == 0x07) // bell
107 {
108 dst[dst_ndx++]= 0x5C; dst[dst_ndx++]= (unsigned char) 'a';
109 }
110 else if (src[src_ndx] == 0x08) // backspace
111 {
112 dst[dst_ndx++]= 0x5C; dst[dst_ndx++]= (unsigned char) 'b';
113 }
114 else if (src[src_ndx] == 0x09) // horiz tab
115 {
116 dst[dst_ndx++]= 0x5C; dst[dst_ndx++]= (unsigned char) 't';
117 }
118 else if (src[src_ndx] == 0x0a) // line feed
119 {
120 dst[dst_ndx++]= 0x5C; dst[dst_ndx++]= (unsigned char) 'n';
121 }
122 else if (src[src_ndx] == 0x0b) // vert tab
123 {
124 dst[dst_ndx++]= 0x5C; dst[dst_ndx++]= (unsigned char) 'v';
125 }
126 else if (src[src_ndx] == 0x0c) // formfeed
127 {
128 dst[dst_ndx++]= 0x5C; dst[dst_ndx++]= (unsigned char) 'f';
129 }
130 else if (src[src_ndx] == 0x0d) // carrage return
131 {
132 dst[dst_ndx++]= 0x5C; dst[dst_ndx++]= (unsigned char) 'r';
133 }
134 else if (src[src_ndx] == 0x1b) // escape
135 {
136 dst[dst_ndx++]= 0x5C; dst[dst_ndx++]= (unsigned char) 'e';
137 }
138 else if (src[src_ndx] == 0x22) // quotation mark
139 {
140 dst[dst_ndx++]= 0x5C; dst[dst_ndx++]= 0x22;
141 }
142 else if (src[src_ndx] == 0x2C) // comma
143 {
144 dst[dst_ndx++]= 0x5C; dst[dst_ndx++]= 0x2C;
145 }
146 else if (src[src_ndx] == 0x5C) // backslash
147 {
148 dst[dst_ndx++]= 0x5C; dst[dst_ndx++]= 0x5C;
149 }
150 else if ((src[src_ndx] < 0x20) || (src[src_ndx] == 0x7F)) // other unprintable ASCII
151 {
152 dst[dst_ndx++]= 0x5C;
153 dst[dst_ndx++]= (unsigned char) 'x';
154 dst[dst_ndx++]= hexit[(src[src_ndx] >> 4) & 0x0f];
155 dst[dst_ndx++]= hexit[src[src_ndx] & 0x0f];
156 }
157 else // everything else
158 {
159 dst[dst_ndx++]= src[src_ndx];
160 }
161 dst[dst_ndx]= '\0';
162 }
163 return dst;
164}
165
166bool logging_gearman_func_post (Session *session)
167{
168 char msgbuf[MAX_MSG_LEN];
169 int msgbuf_len= 0;
170
171 assert(session != NULL);
172
173 if (sysvar_logging_gearman_enable == false)
174 return false;
175
176 // logging this is far too verbose
177 if (session->command == COM_FIELD_LIST)
178 return false;
179
180 /* TODO, looks like connect_utime isnt being set in the session
181 object. We could store the time this plugin was loaded, but that
182 would just be a dumb workaround. */
183 /* TODO, the session object should have a "utime command completed"
184 inside itself, so be more accurate, and so this doesnt have to
185 keep calling current_utime, which can be slow */
186
187 uint64_t t_mark= get_microtime();
188
189 // buffer to quotify the query
190 unsigned char qs[255];
191
192 // to avoid trying to printf %s something that is potentially NULL
193 const char *dbs= (session->db) ? session->db : "";
194 int dbl= 0;
195 if (dbs != NULL)
196 dbl= session->db_length;
197
198 // todo, add hostname, listener port, and server id to this
199
200 msgbuf_len=
201 snprintf(msgbuf, MAX_MSG_LEN,
202 "%"PRIu64",%"PRIu64",%"PRIu64",\"%.*s\",\"%s\",\"%.*s\","
203 "%"PRIu64",%"PRIu64",%"PRIu64",%"PRIu64",%"PRIu64"",
204 t_mark,
205 session->thread_id,
206 session->query_id,
207 // dont need to quote the db name, always CSV safe
208 dbl, dbs,
209 // do need to quote the query
210 quotify((unsigned char *)session->query,
211 session->query_length, qs, sizeof(qs)),
212 // command_name is defined in drizzled/sql_parse.cc
213 // dont need to quote the command name, always CSV safe
214 (int)command_name[session->command].length,
215 command_name[session->command].str,
216 // counters are at end, to make it easier to add more
217 (t_mark - session->connect_utime),
218 (t_mark - session->start_utime),
219 (t_mark - session->utime_after_lock),
220 session->sent_row_count,
221 session->examined_row_count);
222
223 char job_handle[GEARMAN_JOB_HANDLE_SIZE];
224
225 (void) gearman_client_do_background(&gearman_client,
226 "drizzlelog",
227 NULL,
228 (void *) msgbuf,
229 (size_t) msgbuf_len,
230 job_handle);
231
232 return false;
233}
234
235static int logging_gearman_plugin_init(void *p)
236{
237 logging_t *l= static_cast<logging_t *>(p);
238
239 gearman_return_t ret;
240
241 /* TODO
242 saying "return 0" means "success"
243 right now, if we return an error
244 this causes Drizzle to crash
245 so until that is fixed,
246 just return a success,
247 but leave the function pointers as NULL
248 */
249
250 if (sysvar_logging_gearman_host == NULL)
251 {
252 /* no destination gearman server host was specified via system variables
253 return now, dont set the callback pointers
254 */
255 return 0;
256 }
257
258 if (gearman_client_create(&gearman_client) == NULL)
259 {
260 errmsg_printf(ERRMSG_LVL_ERROR, _("fail gearman_client_create(): %s"),
261 strerror(errno));
262 return 0;
263 }
264
265 /* TODO, be able to override the port */
266 ret= gearman_client_add_server(&gearman_client,
267 sysvar_logging_gearman_host, 0);
268 if (ret != GEARMAN_SUCCESS)
269 {
270 errmsg_printf(ERRMSG_LVL_ERROR, _("fail gearman_client_add_server(): %s"),
271 gearman_client_error(&gearman_client));
272 return 0;
273 }
274
275 l->logging_pre= NULL;
276 l->logging_post= logging_gearman_func_post;
277
278 return 0;
279}
280
281static int logging_gearman_plugin_deinit(void *p)
282{
283 logging_st *l= (logging_st *) p;
284
285 gearman_client_free(&gearman_client);
286
287 l->logging_pre= NULL;
288 l->logging_post= NULL;
289
290 return 0;
291}
292
293static DRIZZLE_SYSVAR_BOOL(
294 enable,
295 sysvar_logging_gearman_enable,
296 PLUGIN_VAR_NOCMDARG,
297 N_("Enable logging to a gearman server"),
298 NULL, /* check func */
299 NULL, /* update func */
300 false /* default */);
301
302static DRIZZLE_SYSVAR_STR(
303 host,
304 sysvar_logging_gearman_host,
305 PLUGIN_VAR_READONLY,
306 N_("Hostname for logging to a Gearman server"),
307 NULL, /* check func */
308 NULL, /* update func*/
309 NULL /* default */);
310
311static struct st_mysql_sys_var* logging_gearman_system_variables[]= {
312 DRIZZLE_SYSVAR(enable),
313 DRIZZLE_SYSVAR(host),
314 NULL
315};
316
317drizzle_declare_plugin(logging_gearman)
318{
319 DRIZZLE_LOGGER_PLUGIN,
320 "logging_gearman",
321 "0.1",
322 "Mark Atwood <mark@fallenpegasus.com>",
323 N_("Log queries to a Gearman server"),
324 PLUGIN_LICENSE_GPL,
325 logging_gearman_plugin_init,
326 logging_gearman_plugin_deinit,
327 NULL, /* status variables */
328 logging_gearman_system_variables,
329 NULL
330}
331drizzle_declare_plugin_end;
0332
=== added file 'plugin/logging_gearman/plug.in'
--- plugin/logging_gearman/plug.in 1970-01-01 00:00:00 +0000
+++ plugin/logging_gearman/plug.in 2009-03-04 01:02:00 +0000
@@ -0,0 +1,16 @@
1DRIZZLE_PLUGIN(logging_gearman,[Gearman Logging Plugin],
2 [Logging Plugin that logs to Gearman.])
3DRIZZLE_PLUGIN_DYNAMIC(logging_gearman, [liblogging_gearman.la])
4DRIZZLE_PLUGIN_STATIC(logging_gearman, [liblogging_gearman.a])
5DRIZZLE_PLUGIN_MANDATORY(logging_gearman) dnl Default
6DRIZZLE_PLUGIN_ACTIONS(logging_gearman, [
7AC_LIB_HAVE_LINKFLAGS(gearman,,
8 [#include <libgearman/gearman.h>],
9 [
10 gearman_client_st gearman_client;
11 ])
12 AS_IF([test "x$ac_cv_libgearman" = "xno"],
13 AC_MSG_WARN([libgearman not found: not building logging_gearman plugin]))
14 DRIZZLED_PLUGIN_DEP_LIBS="${DRIZZLED_PLUGIN_DEP_LIBS} ${LIBGEARMAN}"
15 AM_CONDITIONAL(BUILD_LOGGING_GEARMAN,[test "${ac_cv_libgearman}" = "yes"])
16])