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