diff options
Diffstat (limited to 'mod_log_sql.c')
-rw-r--r-- | mod_log_sql.c | 488 |
1 files changed, 119 insertions, 369 deletions
diff --git a/mod_log_sql.c b/mod_log_sql.c index 564f3fc..50c7964 100644 --- a/mod_log_sql.c +++ b/mod_log_sql.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $Header: /home/cvs/mod_log_sql/mod_log_sql.c,v 1.15 2004/02/12 03:18:18 urkle Exp $ */ | 1 | /* $Id $ */ |
2 | /* --------* | 2 | /* --------* |
3 | * DEFINES * | 3 | * DEFINES * |
4 | * --------*/ | 4 | * --------*/ |
@@ -6,15 +6,6 @@ | |||
6 | /* The enduser may wish to modify this */ | 6 | /* The enduser may wish to modify this */ |
7 | #define DEBUG | 7 | #define DEBUG |
8 | 8 | ||
9 | /* The enduser won't modify these */ | ||
10 | #define MYSQL_ERROR(mysql) ((mysql)?(mysql_error(mysql)):"MySQL server has gone away") | ||
11 | |||
12 | /* ---------* | ||
13 | * INCLUDES * | ||
14 | * ---------*/ | ||
15 | #include "mysql.h" | ||
16 | #include "mysqld_error.h" | ||
17 | |||
18 | #if defined(WITH_APACHE20) | 9 | #if defined(WITH_APACHE20) |
19 | # include "apache20.h" | 10 | # include "apache20.h" |
20 | #elif defined(WITH_APACHE13) | 11 | #elif defined(WITH_APACHE13) |
@@ -69,17 +60,9 @@ typedef struct { | |||
69 | int massvirtual; | 60 | int massvirtual; |
70 | int createtables; | 61 | int createtables; |
71 | int forcepreserve; | 62 | int forcepreserve; |
72 | char *tabletype; | ||
73 | char *dbname; | ||
74 | char *dbhost; | ||
75 | char *dbuser; | ||
76 | char *dbpwd; | ||
77 | char *machid; | 63 | char *machid; |
78 | char *socketfile; | 64 | apr_table_t *dbparams; |
79 | unsigned int tcpport; | 65 | logsql_dbconnection db; |
80 | int insertdelayed; | ||
81 | MYSQL server; | ||
82 | MYSQL *server_p; | ||
83 | } global_config_t; | 66 | } global_config_t; |
84 | 67 | ||
85 | static global_config_t global_config; | 68 | static global_config_t global_config; |
@@ -87,11 +70,11 @@ static global_config_t global_config; | |||
87 | /* structure to hold helper function info */ | 70 | /* structure to hold helper function info */ |
88 | typedef struct { | 71 | typedef struct { |
89 | char key; /* item letter character */ | 72 | char key; /* item letter character */ |
90 | log_sql_item_func *func; /* its extraction function */ | 73 | logsql_item_func *func; /* its extraction function */ |
91 | const char *sql_field_name; /* its column in SQL */ | 74 | const char *sql_field_name; /* its column in SQL */ |
92 | int want_orig_default; /* if it requires the original request prior to internal redirection */ | 75 | int want_orig_default; /* if it requires the original request prior to internal redirection */ |
93 | int string_contents; /* if it returns a string */ | 76 | int string_contents; /* if it returns a string */ |
94 | } log_sql_item; | 77 | } logsql_item; |
95 | 78 | ||
96 | /* But the contents of this structure will vary by virtual server. | 79 | /* But the contents of this structure will vary by virtual server. |
97 | * This permits each virtual server to vary its configuration slightly | 80 | * This permits each virtual server to vary its configuration slightly |
@@ -114,33 +97,28 @@ typedef struct { | |||
114 | const char *transfer_table_name; | 97 | const char *transfer_table_name; |
115 | const char *transfer_log_format; | 98 | const char *transfer_log_format; |
116 | apr_pool_t *parsed_pool; | 99 | apr_pool_t *parsed_pool; |
117 | log_sql_item **parsed_log_format; | 100 | logsql_item **parsed_log_format; |
118 | const char *preserve_file; | 101 | const char *preserve_file; |
119 | const char *cookie_name; | 102 | const char *cookie_name; |
120 | } logsql_state; | 103 | } logsql_state; |
121 | 104 | ||
122 | 105 | ||
123 | /* -----------------* | 106 | /* list of "handlers" for log types */ |
124 | * HELPER FUNCTIONS * | 107 | static apr_array_header_t *logsql_item_list; |
125 | * -----------------*/ | ||
126 | |||
127 | static int safe_create_tables(logsql_state *cls, request_rec *r); | ||
128 | |||
129 | static apr_array_header_t *log_sql_item_list; | ||
130 | 108 | ||
131 | /* Registration Function for extract functions * | 109 | /* Registration Function for extract functions * |
132 | * and update parse cache for transfer_log_format * | 110 | * and update parse cache for transfer_log_format * |
133 | * this is exported from the module */ | 111 | * this is exported from the module */ |
134 | LOGSQL_DECLARE(void) log_sql_register_item(server_rec *s, apr_pool_t *p, | 112 | LOGSQL_DECLARE(void) log_sql_register_item(server_rec *s, apr_pool_t *p, |
135 | char key, log_sql_item_func *func, const char *sql_field_name, | 113 | char key, logsql_item_func *func, const char *sql_field_name, |
136 | int want_orig_default, int string_contents) | 114 | int want_orig_default, int string_contents) |
137 | { | 115 | { |
138 | server_rec *ts; | 116 | server_rec *ts; |
139 | log_sql_item *item; | 117 | logsql_item *item; |
140 | if (!log_sql_item_list) | 118 | if (!logsql_item_list) |
141 | log_sql_item_list = apr_array_make(p,10, sizeof(log_sql_item)); | 119 | logsql_item_list = apr_array_make(p,10, sizeof(logsql_item)); |
142 | 120 | ||
143 | item= apr_array_push(log_sql_item_list); | 121 | item= apr_array_push(logsql_item_list); |
144 | item->key = key; | 122 | item->key = key; |
145 | item->func = func; | 123 | item->func = func; |
146 | item->sql_field_name = sql_field_name; | 124 | item->sql_field_name = sql_field_name; |
@@ -189,7 +167,7 @@ static const char *escape_query(const char *from_str, apr_pool_t *p) | |||
189 | return from_str; | 167 | return from_str; |
190 | } | 168 | } |
191 | 169 | ||
192 | if (!global_config.server_p) { | 170 | if (!global_config.db.connected) { |
193 | /* Well, I would have liked to use the current database charset. mysql is | 171 | /* Well, I would have liked to use the current database charset. mysql is |
194 | * unavailable, however, so I fall back to the slightly less respectful | 172 | * unavailable, however, so I fall back to the slightly less respectful |
195 | * mysql_escape_string() function that uses the default charset. | 173 | * mysql_escape_string() function that uses the default charset. |
@@ -199,7 +177,7 @@ static const char *escape_query(const char *from_str, apr_pool_t *p) | |||
199 | /* MySQL is available, so I'll go ahead and respect the current charset when | 177 | /* MySQL is available, so I'll go ahead and respect the current charset when |
200 | * I perform the escape. | 178 | * I perform the escape. |
201 | */ | 179 | */ |
202 | retval = mysql_real_escape_string(global_config.server_p, to_str, from_str, length); | 180 | retval = mysql_real_escape_string(global_config.db.handle, to_str, from_str, length); |
203 | } | 181 | } |
204 | 182 | ||
205 | if (retval) | 183 | if (retval) |
@@ -209,42 +187,19 @@ static const char *escape_query(const char *from_str, apr_pool_t *p) | |||
209 | } | 187 | } |
210 | } | 188 | } |
211 | 189 | ||
212 | static int open_logdb_link(server_rec* s) | 190 | static logsql_opendb open_logdb_link(server_rec* s) |
213 | { | 191 | { |
214 | /* Returns: | ||
215 | 3 if preserve forced | ||
216 | 2 if already connected | ||
217 | 1 if successful | ||
218 | 0 if unsuccessful | ||
219 | */ | ||
220 | |||
221 | if (global_config.forcepreserve) | 192 | if (global_config.forcepreserve) |
222 | return 3; | 193 | return LOGSQL_OPENDB_PRESERVE; |
223 | 194 | ||
224 | if (global_config.server_p) | 195 | if (global_config.db.connected) |
225 | return 2; | 196 | return LOGSQL_OPENDB_ALREADY; |
226 | 197 | ||
227 | if ((global_config.dbname) && (global_config.dbhost) && (global_config.dbuser) && (global_config.dbpwd)) { | 198 | if ((global_config.dbname) && (global_config.dbhost) && (global_config.dbuser) && (global_config.dbpwd)) { |
228 | mysql_init(&global_config.server); | 199 | log_sql_mysql_connect(); |
229 | global_config.server_p = mysql_real_connect(&global_config.server, global_config.dbhost, global_config.dbuser, global_config.dbpwd, global_config.dbname, global_config.tcpport, global_config.socketfile, 0); | ||
230 | |||
231 | if (global_config.server_p) { | ||
232 | #ifdef DEBUG | ||
233 | log_error(APLOG_MARK,APLOG_DEBUG,s,"HOST: '%s' PORT: '%d' DB: '%s' USER: '%s' SOCKET: '%s'", | ||
234 | global_config.dbhost, global_config.tcpport, global_config.dbname, global_config.dbuser, global_config.socketfile); | ||
235 | #endif | ||
236 | return 1; | ||
237 | } else { | ||
238 | #ifdef DEBUG | ||
239 | log_error(APLOG_MARK,APLOG_DEBUG,s,"mod_log_sql: database connection error: %s",MYSQL_ERROR(&global_config.server)); | ||
240 | log_error(APLOG_MARK,APLOG_DEBUG,s,"HOST: '%s' PORT: '%d' DB: '%s' USER: '%s' SOCKET: '%s'", | ||
241 | global_config.dbhost, global_config.tcpport, global_config.dbname, global_config.dbuser, global_config.socketfile); | ||
242 | #endif | ||
243 | return 0; | ||
244 | } | ||
245 | } else { | 200 | } else { |
246 | log_error(APLOG_MARK,APLOG_ERR,s,"mod_log_sql: insufficient configuration info to establish database link"); | 201 | log_error(APLOG_MARK,APLOG_ERR,s,"mod_log_sql: insufficient configuration info to establish database link"); |
247 | return 0; | 202 | return LOGSQL_OPENDB_FAIL; |
248 | } | 203 | } |
249 | } | 204 | } |
250 | 205 | ||
@@ -286,245 +241,6 @@ static void preserve_entry(request_rec *r, const char *query) | |||
286 | } | 241 | } |
287 | 242 | ||
288 | 243 | ||
289 | /*-----------------------------------------------------* | ||
290 | * safe_sql_query: perform a database query with * | ||
291 | * a degree of safety and error checking. * | ||
292 | * * | ||
293 | * Parms: request record, SQL insert statement * | ||
294 | * Returns: 0 (OK) on success * | ||
295 | * 1 if have no log handle * | ||
296 | * 2 if insert delayed failed (kluge) * | ||
297 | * the actual MySQL return code on error * | ||
298 | *-----------------------------------------------------*/ | ||
299 | static unsigned int safe_sql_query(request_rec *r, const char *query) | ||
300 | { | ||
301 | int retval; | ||
302 | struct timespec delay, remainder; | ||
303 | int ret; | ||
304 | void (*handler) (int); | ||
305 | logsql_state *cls; | ||
306 | unsigned int real_error = 0; | ||
307 | const char *real_error_str = NULL; | ||
308 | |||
309 | /* A failed mysql_query() may send a SIGPIPE, so we ignore that signal momentarily. */ | ||
310 | handler = signal(SIGPIPE, SIG_IGN); | ||
311 | |||
312 | /* First attempt for the query */ | ||
313 | if (!global_config.server_p) { | ||
314 | signal(SIGPIPE, handler); | ||
315 | return 1; | ||
316 | } else if (!(retval = mysql_query(global_config.server_p, query))) { | ||
317 | signal(SIGPIPE, handler); | ||
318 | return 0; | ||
319 | } | ||
320 | |||
321 | /* If we ran the query and it returned an error, try to be robust. | ||
322 | * (After all, the module thought it had a valid mysql_log connection but the query | ||
323 | * could have failed for a number of reasons, so we have to be extra-safe and check.) */ | ||
324 | if (global_config.insertdelayed) { | ||
325 | real_error_str = MYSQL_ERROR(global_config.server_p); | ||
326 | } else { | ||
327 | real_error = mysql_errno(global_config.server_p); | ||
328 | } | ||
329 | |||
330 | /* Check to see if the error is "nonexistent table" */ | ||
331 | if (global_config.insertdelayed) { | ||
332 | retval = (strstr(real_error_str, "Table")) && (strstr(real_error_str,"doesn't exist")); | ||
333 | } else { | ||
334 | retval = (real_error == ER_NO_SUCH_TABLE); | ||
335 | } | ||
336 | if (retval) { | ||
337 | if (global_config.createtables) { | ||
338 | log_error(APLOG_MARK,APLOG_ERR,r->server,"mod_log_sql: table doesn't exist...creating now"); | ||
339 | cls = ap_get_module_config(r->server->module_config, &log_sql_module); | ||
340 | if (safe_create_tables(cls, r)) { | ||
341 | log_error(APLOG_MARK,APLOG_ERR,r->server,"mod_log_sql: child attempted but failed to create one or more tables for %s, preserving query", ap_get_server_name(r)); | ||
342 | preserve_entry(r, query); | ||
343 | retval = mysql_errno(global_config.server_p); | ||
344 | } else { | ||
345 | log_error(APLOG_MARK,APLOG_ERR,r->server,"mod_log_sql: tables successfully created - retrying query"); | ||
346 | if (mysql_query(global_config.server_p, query)) { | ||
347 | log_error(APLOG_MARK,APLOG_ERR,r->server,"mod_log_sql: giving up, preserving query"); | ||
348 | preserve_entry(r, query); | ||
349 | retval = mysql_errno(global_config.server_p); | ||
350 | } else | ||
351 | log_error(APLOG_MARK,APLOG_ERR,r->server,"mod_log_sql: query successful after table creation"); | ||
352 | retval = 0; | ||
353 | } | ||
354 | } else { | ||
355 | log_error(APLOG_MARK,APLOG_ERR,r->server,"mod_log_sql, table doesn't exist, creation denied by configuration, preserving query"); | ||
356 | preserve_entry(r, query); | ||
357 | retval = ER_NO_SUCH_TABLE; | ||
358 | } | ||
359 | /* Restore SIGPIPE to its original handler function */ | ||
360 | signal(SIGPIPE, handler); | ||
361 | return retval; | ||
362 | } | ||
363 | |||
364 | /* Handle all other types of errors */ | ||
365 | |||
366 | cls = ap_get_module_config(r->server->module_config, &log_sql_module); | ||
367 | |||
368 | /* Something went wrong, so start by trying to restart the db link. */ | ||
369 | if (global_config.insertdelayed) { | ||
370 | real_error = 2; | ||
371 | } else { | ||
372 | real_error = mysql_errno(global_config.server_p); | ||
373 | } | ||
374 | |||
375 | log_error(APLOG_MARK,APLOG_ERR,r->server,"mod_log_sql: first attempt failed, API said: error %d, \"%s\"", real_error, MYSQL_ERROR(global_config.server_p)); | ||
376 | mysql_close(global_config.server_p); | ||
377 | global_config.server_p = NULL; | ||
378 | open_logdb_link(r->server); | ||
379 | |||
380 | if (global_config.server_p == NULL) { /* still unable to link */ | ||
381 | signal(SIGPIPE, handler); | ||
382 | log_error(APLOG_MARK,APLOG_ERR,r->server,"mod_log_sql: reconnect failed, unable to reach database. SQL logging stopped until child regains a db connection."); | ||
383 | log_error(APLOG_MARK,APLOG_ERR,r->server,"mod_log_sql: log entries are being preserved in %s", cls->preserve_file); | ||
384 | return 1; | ||
385 | } else | ||
386 | log_error(APLOG_MARK,APLOG_ERR,r->server,"mod_log_sql: db reconnect successful"); | ||
387 | |||
388 | /* First sleep for a tiny amount of time. */ | ||
389 | delay.tv_sec = 0; | ||
390 | delay.tv_nsec = 250000000; /* max is 999999999 (nine nines) */ | ||
391 | ret = nanosleep(&delay, &remainder); | ||
392 | if (ret && errno != EINTR) | ||
393 | log_error(APLOG_MARK,APLOG_ERR,r->server,"mod_log_sql: nanosleep unsuccessful"); | ||
394 | |||
395 | /* Then make our second attempt */ | ||
396 | retval = mysql_query(global_config.server_p,query); | ||
397 | |||
398 | /* If this one also failed, log that and append to our local offline file */ | ||
399 | if (retval) { | ||
400 | if (global_config.insertdelayed) { | ||
401 | real_error = 2; | ||
402 | } else { | ||
403 | real_error = mysql_errno(global_config.server_p); | ||
404 | } | ||
405 | |||
406 | log_error(APLOG_MARK,APLOG_ERR,r->server,"mod_log_sql: second attempt failed, API said: error %d, \"%s\" -- preserving", real_error, MYSQL_ERROR(global_config.server_p)); | ||
407 | preserve_entry(r, query); | ||
408 | retval = real_error; | ||
409 | } else | ||
410 | log_error(APLOG_MARK,APLOG_ERR,r->server,"mod_log_sql: second attempt successful"); | ||
411 | |||
412 | /* Restore SIGPIPE to its original handler function */ | ||
413 | signal(SIGPIPE, handler); | ||
414 | return retval; | ||
415 | } | ||
416 | |||
417 | /*-----------------------------------------------------* | ||
418 | * safe_create_tables: create SQL table set for the * | ||
419 | * virtual server represented by cls. * | ||
420 | * * | ||
421 | * Parms: virtserver structure, request record * | ||
422 | * Returns: 0 on no errors * | ||
423 | * mysql error code on failure * | ||
424 | *-----------------------------------------------------*/ | ||
425 | static int safe_create_tables(logsql_state *cls, request_rec *r) | ||
426 | { | ||
427 | int retval; | ||
428 | unsigned int create_results; | ||
429 | char *create_access = NULL; | ||
430 | char *create_notes = NULL; | ||
431 | char *create_hout = NULL; | ||
432 | char *create_hin = NULL; | ||
433 | char *create_cookies = NULL; | ||
434 | |||
435 | char *type_suffix = NULL; | ||
436 | |||
437 | char *createprefix = "create table if not exists `"; | ||
438 | char *access_suffix = | ||
439 | "` (id char(19),\ | ||
440 | agent varchar(255),\ | ||
441 | bytes_sent int unsigned,\ | ||
442 | child_pid smallint unsigned,\ | ||
443 | cookie varchar(255),\ | ||
444 | machine_id varchar(25),\ | ||
445 | request_file varchar(255),\ | ||
446 | referer varchar(255),\ | ||
447 | remote_host varchar(50),\ | ||
448 | remote_logname varchar(50),\ | ||
449 | remote_user varchar(50),\ | ||
450 | request_duration smallint unsigned,\ | ||
451 | request_line varchar(255),\ | ||
452 | request_method varchar(10),\ | ||
453 | request_protocol varchar(10),\ | ||
454 | request_time char(28),\ | ||
455 | request_uri varchar(255),\ | ||
456 | request_args varchar(255),\ | ||
457 | server_port smallint unsigned,\ | ||
458 | ssl_cipher varchar(25),\ | ||
459 | ssl_keysize smallint unsigned,\ | ||
460 | ssl_maxkeysize smallint unsigned,\ | ||
461 | status smallint unsigned,\ | ||
462 | time_stamp int unsigned,\ | ||
463 | virtual_host varchar(255))"; | ||
464 | |||
465 | char *notes_suffix = | ||
466 | "` (id char(19),\ | ||
467 | item varchar(80),\ | ||
468 | val varchar(80))"; | ||
469 | |||
470 | char *headers_suffix = | ||
471 | "` (id char(19),\ | ||
472 | item varchar(80),\ | ||
473 | val varchar(80))"; | ||
474 | |||
475 | char *cookies_suffix = | ||
476 | "` (id char(19),\ | ||
477 | item varchar(80),\ | ||
478 | val varchar(80))"; | ||
479 | if (global_config.tabletype) { | ||
480 | type_suffix = apr_pstrcat(r->pool, " TYPE=", global_config.tabletype, NULL); | ||
481 | } | ||
482 | /* Find memory long enough to hold the whole CREATE string + \0 */ | ||
483 | create_access = apr_pstrcat(r->pool, createprefix, cls->transfer_table_name, access_suffix, type_suffix, NULL); | ||
484 | create_notes = apr_pstrcat(r->pool, createprefix, cls->notes_table_name, notes_suffix, type_suffix, NULL); | ||
485 | create_hout = apr_pstrcat(r->pool, createprefix, cls->hout_table_name, headers_suffix, type_suffix, NULL); | ||
486 | create_hin = apr_pstrcat(r->pool, createprefix, cls->hin_table_name, headers_suffix, type_suffix, NULL); | ||
487 | create_cookies= apr_pstrcat(r->pool, createprefix, cls->cookie_table_name, cookies_suffix, type_suffix, NULL); | ||
488 | |||
489 | #ifdef DEBUG | ||
490 | log_error(APLOG_MARK,APLOG_DEBUG,r->server,"mod_log_sql: create string: %s", create_access); | ||
491 | log_error(APLOG_MARK,APLOG_DEBUG,r->server,"mod_log_sql: create string: %s", create_notes); | ||
492 | log_error(APLOG_MARK,APLOG_DEBUG,r->server,"mod_log_sql: create string: %s", create_hout); | ||
493 | log_error(APLOG_MARK,APLOG_DEBUG,r->server,"mod_log_sql: create string: %s", create_hin); | ||
494 | log_error(APLOG_MARK,APLOG_DEBUG,r->server,"mod_log_sql: create string: %s", create_cookies); | ||
495 | #endif | ||
496 | |||
497 | /* Assume that things worked unless told otherwise */ | ||
498 | retval = 0; | ||
499 | |||
500 | if ((create_results = safe_sql_query(r, create_access))) { | ||
501 | log_error(APLOG_MARK,APLOG_ERR,r->server,"mod_log_sql: failed to create access table"); | ||
502 | retval = create_results; | ||
503 | } | ||
504 | |||
505 | if ((create_results = safe_sql_query(r, create_notes))) { | ||
506 | log_error(APLOG_MARK,APLOG_ERR,r->server,"mod_log_sql: failed to create notes table"); | ||
507 | retval = create_results; | ||
508 | } | ||
509 | |||
510 | if ((create_results = safe_sql_query(r, create_hin))) { | ||
511 | log_error(APLOG_MARK,APLOG_ERR,r->server,"mod_log_sql: failed to create header_in table"); | ||
512 | retval = create_results; | ||
513 | } | ||
514 | |||
515 | if ((create_results = safe_sql_query(r, create_hout))) { | ||
516 | log_error(APLOG_MARK,APLOG_ERR,r->server,"mod_log_sql: failed to create header_out table"); | ||
517 | retval = create_results; | ||
518 | } | ||
519 | |||
520 | if ((create_results = safe_sql_query(r, create_cookies))) { | ||
521 | log_error(APLOG_MARK,APLOG_ERR,r->server,"mod_log_sql: failed to create cookies table"); | ||
522 | retval = create_results; | ||
523 | } | ||
524 | |||
525 | return retval; | ||
526 | } | ||
527 | |||
528 | /* ------------------------------------------------* | 244 | /* ------------------------------------------------* |
529 | * Command handlers that are called according * | 245 | * Command handlers that are called according * |
530 | * to the directives found at Apache runtime. * | 246 | * to the directives found at Apache runtime. * |
@@ -567,7 +283,6 @@ static const char *set_global_string_slot(cmd_parms *cmd, | |||
567 | *(const char **)((char *)ptr + offset) = apr_pstrdup(cmd->pool,arg); | 283 | *(const char **)((char *)ptr + offset) = apr_pstrdup(cmd->pool,arg); |
568 | return NULL; | 284 | return NULL; |
569 | } | 285 | } |
570 | |||
571 | static const char *set_server_string_slot(cmd_parms *cmd, | 286 | static const char *set_server_string_slot(cmd_parms *cmd, |
572 | void *struct_ptr, | 287 | void *struct_ptr, |
573 | const char *arg) | 288 | const char *arg) |
@@ -591,7 +306,7 @@ static const char *set_logformat_slot(cmd_parms *cmd, | |||
591 | cfg->transfer_log_format = arg; | 306 | cfg->transfer_log_format = arg; |
592 | /* apr_pool_clear(cfg->parsed_pool);*/ | 307 | /* apr_pool_clear(cfg->parsed_pool);*/ |
593 | cfg->parsed_log_format = apr_pcalloc(cfg->parsed_pool, | 308 | cfg->parsed_log_format = apr_pcalloc(cfg->parsed_pool, |
594 | strlen(arg) * sizeof(log_sql_item *)); | 309 | strlen(arg) * sizeof(logsql_item *)); |
595 | return NULL; | 310 | return NULL; |
596 | } | 311 | } |
597 | 312 | ||
@@ -607,16 +322,38 @@ static const char *set_server_nmv_string_slot(cmd_parms *parms, | |||
607 | return set_server_string_slot(parms,struct_ptr,arg); | 322 | return set_server_string_slot(parms,struct_ptr,arg); |
608 | } | 323 | } |
609 | 324 | ||
610 | static const char *set_log_sql_info(cmd_parms *cmd, void *dummy, const char *host, const char *user, const char *pwd) | 325 | /* Set a DB connection parameter */ |
326 | static void set_dbparam(apr_pool_t *p, const char *key, | ||
327 | const char *val); | ||
328 | { | ||
329 | if (!global_config.dbparams) { | ||
330 | global_config.dbparams = apr_table_make(p,5); | ||
331 | } | ||
332 | apr_table_set(global_config.dbparams,key,val); | ||
333 | } | ||
334 | |||
335 | static const char *set_dbparam_slot(cmd_params *cmd, | ||
336 | void *struct_ptr, | ||
337 | const char *arg) | ||
338 | { | ||
339 | const char *param = (char *)cmd->info; | ||
340 | set_dbparam(cmd->pool,param,arg); | ||
341 | return NULL; | ||
342 | } | ||
343 | |||
344 | /* Sets basic connection info */ | ||
345 | static const char *set_log_sql_info(cmd_parms *cmd, void *dummy, | ||
346 | const char *host, const char *user, const char *pwd) | ||
611 | { | 347 | { |
612 | if (*host != '.') { | 348 | if (*host != '.') { |
613 | global_config.dbhost = apr_pstrdup(cmd->pool,host); | 349 | set_db_param_slot(cmd->pool, "host", host); |
614 | } | 350 | } |
615 | if (*user != '.') { | 351 | if (*user != '.') { |
352 | set_db_param_slot(cmd->pool, "user", user); | ||
616 | global_config.dbuser = apr_pstrdup(cmd->pool,user); | 353 | global_config.dbuser = apr_pstrdup(cmd->pool,user); |
617 | } | 354 | } |
618 | if (*pwd != '.') { | 355 | if (*pwd != '.') { |
619 | global_config.dbpwd = apr_pstrdup(cmd->pool,pwd); | 356 | set_db_param_slot(cmd->pool, "passwd", pwd); |
620 | } | 357 | } |
621 | return NULL; | 358 | return NULL; |
622 | } | 359 | } |
@@ -673,37 +410,26 @@ static int log_sql_open(apr_pool_t *pc, apr_pool_t *p, apr_pool_t *pt, server_re | |||
673 | static void log_sql_child_init(server_rec *s, apr_pool_t *p) | 410 | static void log_sql_child_init(server_rec *s, apr_pool_t *p) |
674 | #endif | 411 | #endif |
675 | { | 412 | { |
676 | int retval; | 413 | logsql_opendb retval; |
677 | /* Open a link to the database */ | 414 | /* Open a link to the database */ |
678 | retval = open_logdb_link(s); | 415 | retval = open_logdb_link(s); |
679 | if (!retval) | 416 | switch (retval) { |
417 | case LOGSQL_OPENDB_FAIL: | ||
680 | log_error(APLOG_MARK,APLOG_ERR,s,"mod_log_sql: child spawned but unable to open database link"); | 418 | log_error(APLOG_MARK,APLOG_ERR,s,"mod_log_sql: child spawned but unable to open database link"); |
681 | 419 | break; | |
682 | #ifdef DEBUG | 420 | case LOGSQL_OPENDB_SUCCESS: |
683 | if ( (retval == 1) || (retval == 2) ) | 421 | case LOGSQL_OPENDB_ALREADY: |
684 | log_error(APLOG_MARK,APLOG_DEBUG,s,"mod_log_sql: open_logdb_link successful"); | 422 | log_error(APLOG_MARK,APLOG_DEBUG,s,"mod_log_sql: open_logdb_link successful"); |
685 | if (retval == 3) | 423 | break; |
424 | case LOGSQL_OPENDB_PRESERVE: | ||
686 | log_error(APLOG_MARK,APLOG_DEBUG,s,"mod_log_sql: open_logdb_link said that preservation is forced"); | 425 | log_error(APLOG_MARK,APLOG_DEBUG,s,"mod_log_sql: open_logdb_link said that preservation is forced"); |
687 | #endif | 426 | break; |
427 | } | ||
688 | #if defined(WITH_APACHE20) | 428 | #if defined(WITH_APACHE20) |
689 | return OK; | 429 | return OK; |
690 | #endif | 430 | #endif |
691 | } | 431 | } |
692 | /* | ||
693 | void *log_sql_initializer(server_rec *main_server, apr_pool_t *p) | ||
694 | { | ||
695 | server_rec *s; | ||
696 | |||
697 | logsql_state main_conf = ap_get_module_config(main_server->module_config, &log_sql_module); | ||
698 | 432 | ||
699 | for (server_rec *s = main_server; s; s = s->next) { | ||
700 | conf = ap_get_module_config(s->module_config, &log_sql_module); | ||
701 | if (conf->transfer_log_format == NULL && s != main_server) { | ||
702 | *conf = *main_conf; | ||
703 | } | ||
704 | |||
705 | } | ||
706 | */ | ||
707 | /* post_config / module_init */ | 433 | /* post_config / module_init */ |
708 | #if defined(WITH_APACHE20) | 434 | #if defined(WITH_APACHE20) |
709 | static int log_sql_post_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s) | 435 | static int log_sql_post_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s) |
@@ -748,6 +474,20 @@ static void log_sql_module_init(server_rec *s, apr_pool_t *p) | |||
748 | #endif | 474 | #endif |
749 | } | 475 | } |
750 | 476 | ||
477 | /* This function handles calling the DB module, handling errors | ||
478 | * of missing tables and lost DB connections, and falling back to | ||
479 | * preserving the DB query. | ||
480 | * | ||
481 | * Parms: request record, table type, table name, and the full SQL command | ||
482 | */ | ||
483 | |||
484 | static void safe_sql_insert(request_rec *r, logsql_tabletype table_type, | ||
485 | const char *table_name, const char *sql) { | ||
486 | int result; | ||
487 | if (!global_config.connected) { | ||
488 | } | ||
489 | } | ||
490 | |||
751 | /* This function gets called to create a per-server configuration | 491 | /* This function gets called to create a per-server configuration |
752 | * record. It will always be called for the main server and | 492 | * record. It will always be called for the main server and |
753 | * for each virtual server that is established. Each server maintains | 493 | * for each virtual server that is established. Each server maintains |
@@ -764,7 +504,7 @@ static void *log_sql_make_state(apr_pool_t *p, server_rec *s) | |||
764 | cls->transfer_log_format = DEFAULT_TRANSFER_LOG_FMT; | 504 | cls->transfer_log_format = DEFAULT_TRANSFER_LOG_FMT; |
765 | apr_pool_create(&cls->parsed_pool, p); | 505 | apr_pool_create(&cls->parsed_pool, p); |
766 | cls->parsed_log_format = apr_pcalloc(cls->parsed_pool, | 506 | cls->parsed_log_format = apr_pcalloc(cls->parsed_pool, |
767 | strlen(cls->transfer_log_format) * sizeof(log_sql_item *)); | 507 | strlen(cls->transfer_log_format) * sizeof(logsql_item *)); |
768 | cls->notes_table_name = DEFAULT_NOTES_TABLE_NAME; | 508 | cls->notes_table_name = DEFAULT_NOTES_TABLE_NAME; |
769 | cls->hin_table_name = DEFAULT_HIN_TABLE_NAME; | 509 | cls->hin_table_name = DEFAULT_HIN_TABLE_NAME; |
770 | cls->hout_table_name = DEFAULT_HOUT_TABLE_NAME; | 510 | cls->hout_table_name = DEFAULT_HOUT_TABLE_NAME; |
@@ -801,7 +541,7 @@ static void *log_sql_merge_state(apr_pool_t *p, void *basev, void *addv) | |||
801 | child->transfer_log_format = parent->transfer_log_format; | 541 | child->transfer_log_format = parent->transfer_log_format; |
802 | /*apr_pool_clear(child->parsed_pool);*/ | 542 | /*apr_pool_clear(child->parsed_pool);*/ |
803 | child->parsed_log_format = apr_pcalloc(child->parsed_pool, | 543 | child->parsed_log_format = apr_pcalloc(child->parsed_pool, |
804 | strlen(child->transfer_log_format) * sizeof(log_sql_item *)); | 544 | strlen(child->transfer_log_format) * sizeof(logsql_item *)); |
805 | } | 545 | } |
806 | 546 | ||
807 | if (child->preserve_file == DEFAULT_PRESERVE_FILE) | 547 | if (child->preserve_file == DEFAULT_PRESERVE_FILE) |
@@ -961,7 +701,7 @@ static int log_sql_transaction(request_rec *orig) | |||
961 | * what the user has configured. */ | 701 | * what the user has configured. */ |
962 | length = strlen(cls->transfer_log_format); | 702 | length = strlen(cls->transfer_log_format); |
963 | for (i = 0; i<length; i++) { | 703 | for (i = 0; i<length; i++) { |
964 | log_sql_item *item = cls->parsed_log_format[i]; | 704 | logsql_item *item = cls->parsed_log_format[i]; |
965 | if (item==NULL) { | 705 | if (item==NULL) { |
966 | log_error(APLOG_MARK, APLOG_ERR, orig->server, | 706 | log_error(APLOG_MARK, APLOG_ERR, orig->server, |
967 | "Log Format '%c' unknown",cls->transfer_log_format[i]); | 707 | "Log Format '%c' unknown",cls->transfer_log_format[i]); |
@@ -1175,7 +915,11 @@ static int log_sql_transaction(request_rec *orig) | |||
1175 | /* ---> i.e. we have a good MySQL connection. <--- */ | 915 | /* ---> i.e. we have a good MySQL connection. <--- */ |
1176 | 916 | ||
1177 | /* Make the access-table insert */ | 917 | /* Make the access-table insert */ |
1178 | safe_sql_query(orig, access_query); | 918 | if (safe_create_tables(orig, LOGSQL_TABLE_ACCESS, transfer_tablename)==APR_SUCCESS) { |
919 | safe_sql_query(orig, access_query); | ||
920 | } else { | ||
921 | preserve_entry(orig, access_query); | ||
922 | } | ||
1179 | 923 | ||
1180 | /* Log the optional notes, headers, etc. */ | 924 | /* Log the optional notes, headers, etc. */ |
1181 | if (note_query) | 925 | if (note_query) |
@@ -1199,6 +943,7 @@ static int log_sql_transaction(request_rec *orig) | |||
1199 | * Structure: command, function called, NULL, where available, how many arguments, verbose description | 943 | * Structure: command, function called, NULL, where available, how many arguments, verbose description |
1200 | */ | 944 | */ |
1201 | static const command_rec log_sql_cmds[] = { | 945 | static const command_rec log_sql_cmds[] = { |
946 | /* Table names */ | ||
1202 | AP_INIT_TAKE1("LogSQLTransferLogTable", set_server_nmv_string_slot, | 947 | AP_INIT_TAKE1("LogSQLTransferLogTable", set_server_nmv_string_slot, |
1203 | (void *)APR_OFFSETOF(logsql_state, transfer_table_name), RSRC_CONF, | 948 | (void *)APR_OFFSETOF(logsql_state, transfer_table_name), RSRC_CONF, |
1204 | "The database table that holds the transfer log") | 949 | "The database table that holds the transfer log") |
@@ -1219,14 +964,21 @@ static const command_rec log_sql_cmds[] = { | |||
1219 | (void *)APR_OFFSETOF(logsql_state, cookie_table_name), RSRC_CONF, | 964 | (void *)APR_OFFSETOF(logsql_state, cookie_table_name), RSRC_CONF, |
1220 | "The database table that holds the cookie info") | 965 | "The database table that holds the cookie info") |
1221 | , | 966 | , |
967 | AP_INIT_FLAG("LogSQLMassVirtualHosting", set_global_flag_slot, | ||
968 | (void *)APR_OFFSETOF(global_config_t, massvirtual), RSRC_CONF, | ||
969 | "Activates option(s) useful for ISPs performing mass virutal hosting") | ||
970 | , | ||
971 | /* Log format */ | ||
1222 | AP_INIT_TAKE1("LogSQLTransferLogFormat", set_logformat_slot, | 972 | AP_INIT_TAKE1("LogSQLTransferLogFormat", set_logformat_slot, |
1223 | NULL, RSRC_CONF, | 973 | NULL, RSRC_CONF, |
1224 | "Instruct the module what information to log to the database transfer log") | 974 | "Instruct the module what information to log to the database transfer log") |
1225 | , | 975 | , |
976 | /* Machine ID */ | ||
1226 | AP_INIT_TAKE1("LogSQLMachineID", set_global_string_slot, | 977 | AP_INIT_TAKE1("LogSQLMachineID", set_global_string_slot, |
1227 | (void *)APR_OFFSETOF(global_config_t, machid), RSRC_CONF, | 978 | (void *)APR_OFFSETOF(global_config_t, machid), RSRC_CONF, |
1228 | "Machine ID that the module will log, useful in web clusters to differentiate machines") | 979 | "Machine ID that the module will log, useful in web clusters to differentiate machines") |
1229 | , | 980 | , |
981 | /* Limits on logging */ | ||
1230 | AP_INIT_ITERATE("LogSQLRequestAccept", add_server_string_slot, | 982 | AP_INIT_ITERATE("LogSQLRequestAccept", add_server_string_slot, |
1231 | (void *)APR_OFFSETOF(logsql_state, transfer_accept_list), RSRC_CONF, | 983 | (void *)APR_OFFSETOF(logsql_state, transfer_accept_list), RSRC_CONF, |
1232 | "List of URIs to accept for logging. Accesses that don't match will not be logged") | 984 | "List of URIs to accept for logging. Accesses that don't match will not be logged") |
@@ -1239,48 +991,14 @@ static const command_rec log_sql_cmds[] = { | |||
1239 | (void *)APR_OFFSETOF(logsql_state, remhost_ignore_list), RSRC_CONF, | 991 | (void *)APR_OFFSETOF(logsql_state, remhost_ignore_list), RSRC_CONF, |
1240 | "List of remote hosts to ignore. Accesses that match will not be logged to database") | 992 | "List of remote hosts to ignore. Accesses that match will not be logged to database") |
1241 | , | 993 | , |
1242 | AP_INIT_TAKE1("LogSQLDatabase", set_global_string_slot, | ||
1243 | (void *)APR_OFFSETOF(global_config_t, dbname), RSRC_CONF, | ||
1244 | "The name of the database database for logging") | ||
1245 | , | ||
1246 | AP_INIT_TAKE1("LogSQLWhichCookie", set_server_string_slot, | 994 | AP_INIT_TAKE1("LogSQLWhichCookie", set_server_string_slot, |
1247 | (void *)APR_OFFSETOF(logsql_state, cookie_name), RSRC_CONF, | 995 | (void *)APR_OFFSETOF(logsql_state, cookie_name), RSRC_CONF, |
1248 | "The single cookie that you want logged in the access_log when using the 'c' config directive") | 996 | "The single cookie that you want logged in the access_log when using the 'c' config directive") |
1249 | , | 997 | , |
1250 | AP_INIT_TAKE3("LogSQLLoginInfo", set_log_sql_info, NULL, RSRC_CONF, | ||
1251 | "The database host, user-id and password for logging") | ||
1252 | , | ||
1253 | AP_INIT_FLAG("LogSQLCreateTables", set_global_nmv_flag_slot, | ||
1254 | (void *)APR_OFFSETOF(global_config_t, createtables), RSRC_CONF, | ||
1255 | "Turn on module's capability to create its SQL tables on the fly") | ||
1256 | , | ||
1257 | AP_INIT_FLAG("LogSQLMassVirtualHosting", set_global_flag_slot, | ||
1258 | (void *)APR_OFFSETOF(global_config_t, massvirtual), RSRC_CONF, | ||
1259 | "Activates option(s) useful for ISPs performing mass virutal hosting") | ||
1260 | , | ||
1261 | AP_INIT_FLAG("LogSQLDelayedInserts", set_global_flag_slot, | ||
1262 | (void *)APR_OFFSETOF(global_config_t, insertdelayed), RSRC_CONF, | ||
1263 | "Whether to use delayed inserts") | ||
1264 | , | ||
1265 | AP_INIT_FLAG("LogSQLForcePreserve", set_global_flag_slot, | ||
1266 | (void *)APR_OFFSETOF(global_config_t, forcepreserve), RSRC_CONF, | ||
1267 | "Forces logging to preserve file and bypasses database") | ||
1268 | , | ||
1269 | AP_INIT_TAKE1("LogSQLPreserveFile", set_server_string_slot, | 998 | AP_INIT_TAKE1("LogSQLPreserveFile", set_server_string_slot, |
1270 | (void *)APR_OFFSETOF(logsql_state,preserve_file), RSRC_CONF, | 999 | (void *)APR_OFFSETOF(logsql_state,preserve_file), RSRC_CONF, |
1271 | "Name of the file to use for data preservation during database downtime") | 1000 | "Name of the file to use for data preservation during database downtime") |
1272 | , | 1001 | , |
1273 | AP_INIT_TAKE1("LogSQLSocketFile", set_global_string_slot, | ||
1274 | (void *)APR_OFFSETOF(global_config_t, socketfile), RSRC_CONF, | ||
1275 | "Name of the file to employ for socket connections to database") | ||
1276 | , | ||
1277 | AP_INIT_TAKE1("LogSQLTableType", set_global_string_slot, | ||
1278 | (void *)APR_OFFSETOF(global_config_t, tabletype), RSRC_CONF, | ||
1279 | "What kind of table to create (MyISAM, InnoDB,...) when creating tables") | ||
1280 | , | ||
1281 | AP_INIT_TAKE1("LogSQLTCPPort", set_log_sql_tcp_port, NULL, RSRC_CONF, | ||
1282 | "Port number to use for TCP connections to database, defaults to 3306 if not set") | ||
1283 | , | ||
1284 | AP_INIT_ITERATE("LogSQLWhichNotes", add_server_string_slot, | 1002 | AP_INIT_ITERATE("LogSQLWhichNotes", add_server_string_slot, |
1285 | (void *)APR_OFFSETOF(logsql_state, notes_list), RSRC_CONF, | 1003 | (void *)APR_OFFSETOF(logsql_state, notes_list), RSRC_CONF, |
1286 | "Notes that you would like to log in a separate table") | 1004 | "Notes that you would like to log in a separate table") |
@@ -1297,6 +1015,38 @@ static const command_rec log_sql_cmds[] = { | |||
1297 | (void *)APR_OFFSETOF(logsql_state, cookie_list), RSRC_CONF, | 1015 | (void *)APR_OFFSETOF(logsql_state, cookie_list), RSRC_CONF, |
1298 | "The cookie(s) that you would like to log in a separate table") | 1016 | "The cookie(s) that you would like to log in a separate table") |
1299 | , | 1017 | , |
1018 | /* DB connection parameters */ | ||
1019 | AP_INIT_FLAG("LogSQLForcePreserve", set_global_flag_slot, | ||
1020 | (void *)APR_OFFSETOF(global_config_t, forcepreserve), RSRC_CONF, | ||
1021 | "Forces logging to preserve file and bypasses database") | ||
1022 | , | ||
1023 | AP_INIT_FLAG("LogSQLCreateTables", set_global_nmv_flag_slot, | ||
1024 | (void *)APR_OFFSETOF(global_config_t, createtables), RSRC_CONF, | ||
1025 | "Turn on module's capability to create its SQL tables on the fly") | ||
1026 | , | ||
1027 | AP_INIT_TAKE3("LogSQLLoginInfo", set_log_sql_info, NULL, RSRC_CONF, | ||
1028 | "The database host, user-id and password for logging") | ||
1029 | , | ||
1030 | AP_INIT_TAKE1("LogSQLDatabase", set_dbparam_slot, | ||
1031 | (void *)"database", RSRC_CONF, | ||
1032 | "The name of the database database for logging") | ||
1033 | , | ||
1034 | AP_INIT_TAKE1("LogSQLDelayedInserts", set_dbparam_slot, | ||
1035 | (void *)"insertdelayed", RSRC_CONF, | ||
1036 | "Whether to use delayed inserts") | ||
1037 | , | ||
1038 | AP_INIT_TAKE1("LogSQLTableType", set_dbparam_slot, | ||
1039 | (void *)"tabletype", RSRC_CONF, | ||
1040 | "What kind of table to create (MyISAM, InnoDB,...) when creating tables") | ||
1041 | , | ||
1042 | AP_INIT_TAKE1("LogSQLSocketFile", set_dbparam_slot, | ||
1043 | (void *)"socketfile", RSRC_CONF, | ||
1044 | "Name of the file to employ for socket connections to database") | ||
1045 | , | ||
1046 | AP_INIT_TAKE1("LogSQLTCPPort", set_dbparam_slot, | ||
1047 | (void *)"tcpport", RSRC_CONF, | ||
1048 | "Port number to use for TCP connections to database, defaults to 3306 if not set") | ||
1049 | , | ||
1300 | {NULL} | 1050 | {NULL} |
1301 | }; | 1051 | }; |
1302 | /* The configuration array that sets up the hooks into the module. */ | 1052 | /* The configuration array that sets up the hooks into the module. */ |