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