diff options
| author | 2004-02-29 23:36:18 +0000 | |
|---|---|---|
| committer | 2004-02-29 23:36:18 +0000 | |
| commit | 53acb181ef04ae70a7dcfed849f7c02850781c20 (patch) | |
| tree | 3df5086ba326284771f9cb6492e975f1713b3e40 | |
| parent | b16bc88ccee527a7a9ea107c93f36264dbf82ed5 (diff) | |
separated out most mysql specific code to mod_log_sql_mysql.c
beginnings of separation of core SQL logging logic
moved DB connection paramters to a table (for cutoms params for DB drivers)
added new configuration directive to handle any DB parameter
renamed all log_sql_* vars and type to logsql_*
Added enums for opendb return codes.
organized config directives and commented for easier reading of source
| -rw-r--r-- | CHANGELOG | 5 | ||||
| -rw-r--r-- | Documentation/manual.xml | 1 | ||||
| -rw-r--r-- | Makefile.in | 6 | ||||
| -rw-r--r-- | apache13.h | 4 | ||||
| -rw-r--r-- | mod_log_sql.c | 488 | ||||
| -rw-r--r-- | mod_log_sql.h | 38 | ||||
| -rw-r--r-- | mod_log_sql.prj | 3 | ||||
| -rw-r--r-- | mod_log_sql_mysql.c | 241 | ||||
| -rw-r--r-- | mod_log_sql_ssl.c | 2 |
9 files changed, 409 insertions, 379 deletions
| @@ -1,6 +1,9 @@ | |||
| 1 | $Id: CHANGELOG,v 1.13 2004/02/12 03:21:35 urkle Exp $ | 1 | $Id: CHANGELOG,v 1.14 2004/02/29 23:36:17 urkle Exp $ |
| 2 | 1.96: ? | 2 | 1.96: ? |
| 3 | * fixed LogSQLPreserveFile config parameter | 3 | * fixed LogSQLPreserveFile config parameter |
| 4 | * reworked safe_create_tables | ||
| 5 | * renamed log_sql_* variables and typedefs to logsql_* | ||
| 6 | * beginnings of abstraction layer | ||
| 4 | 7 | ||
| 5 | 1.95: 2004-02-05 | 8 | 1.95: 2004-02-05 |
| 6 | * audit and update of extract_* functions to acheive same output as | 9 | * audit and update of extract_* functions to acheive same output as |
diff --git a/Documentation/manual.xml b/Documentation/manual.xml index 3495047..fe13daa 100644 --- a/Documentation/manual.xml +++ b/Documentation/manual.xml | |||
| @@ -16,6 +16,7 @@ | |||
| 16 | <author> | 16 | <author> |
| 17 | <firstname>Christopher</firstname> | 17 | <firstname>Christopher</firstname> |
| 18 | <othername>B.</othername> | 18 | <othername>B.</othername> |
| 19 | <surname>Powell</surname> | ||
| 19 | <contrib>Original documentation author.</contrib> | 20 | <contrib>Original documentation author.</contrib> |
| 20 | <affiliation> | 21 | <affiliation> |
| 21 | <address format="linespecific"><email>chris <at> grubbybaby <dot> com</email></address> | 22 | <address format="linespecific"><email>chris <at> grubbybaby <dot> com</email></address> |
diff --git a/Makefile.in b/Makefile.in index 1ad7562..139a715 100644 --- a/Makefile.in +++ b/Makefile.in | |||
| @@ -2,8 +2,8 @@ | |||
| 2 | 2 | ||
| 3 | # Modify these top variables. | 3 | # Modify these top variables. |
| 4 | SUBDIRS = Documentation contrib | 4 | SUBDIRS = Documentation contrib |
| 5 | SOURCES = \ | 5 | SOURCES = @PACKAGE_NAME@.c \ |
| 6 | @PACKAGE_NAME@.c | 6 | @PACKAGE_NAME@_mysql.c |
| 7 | 7 | ||
| 8 | HEADERS = mod_log_sql.h \ | 8 | HEADERS = mod_log_sql.h \ |
| 9 | functions.h \ | 9 | functions.h \ |
| @@ -22,7 +22,7 @@ EXTRA_DIST = AUTHORS INSTALL TODO LICENSE CHANGELOG make_combined_log.pl | |||
| 22 | 22 | ||
| 23 | TARGET = @PACKAGE_NAME@@APXS_EXTENSION@ | 23 | TARGET = @PACKAGE_NAME@@APXS_EXTENSION@ |
| 24 | 24 | ||
| 25 | sslSOURCES = mod_log_sql_ssl.c | 25 | sslSOURCES = @PACKAGE_NAME@_ssl.c |
| 26 | 26 | ||
| 27 | sslTARGET = @PACKAGE_NAME@_ssl@APXS_EXTENSION@ | 27 | sslTARGET = @PACKAGE_NAME@_ssl@APXS_EXTENSION@ |
| 28 | 28 | ||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* $Header: /home/cvs/mod_log_sql/apache13.h,v 1.4 2004/02/05 21:59:46 urkle Exp $ */ | 1 | /* $Header: /home/cvs/mod_log_sql/apache13.h,v 1.5 2004/02/29 23:36:17 urkle Exp $ */ |
| 2 | #ifndef APACHE13_H | 2 | #ifndef APACHE13_H |
| 3 | #define APACHE13_H | 3 | #define APACHE13_H |
| 4 | 4 | ||
| @@ -51,7 +51,9 @@ | |||
| 51 | #define apr_psprintf ap_psprintf | 51 | #define apr_psprintf ap_psprintf |
| 52 | #define apr_snprintf ap_snprintf | 52 | #define apr_snprintf ap_snprintf |
| 53 | 53 | ||
| 54 | #define apr_table_set ap_table_set | ||
| 54 | #define apr_table_get ap_table_get | 55 | #define apr_table_get ap_table_get |
| 56 | #define apr_table_make ap_make_table | ||
| 55 | 57 | ||
| 56 | #define apr_array_push ap_push_array | 58 | #define apr_array_push ap_push_array |
| 57 | #define apr_array_make ap_make_array | 59 | #define apr_array_make ap_make_array |
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. */ |
diff --git a/mod_log_sql.h b/mod_log_sql.h index f54ab54..0c59cb7 100644 --- a/mod_log_sql.h +++ b/mod_log_sql.h | |||
| @@ -1,4 +1,5 @@ | |||
| 1 | /* $Header: /home/cvs/mod_log_sql/mod_log_sql.h,v 1.3 2004/01/22 05:26:56 urkle Exp $ */ | 1 | /* $Id: mod_log_sql.h,v 1.4 2004/02/29 23:36:18 urkle Exp $ */ |
| 2 | |||
| 2 | #ifndef MOD_LOG_SQL_H | 3 | #ifndef MOD_LOG_SQL_H |
| 3 | #define MOD_LOG_SQL_H | 4 | #define MOD_LOG_SQL_H |
| 4 | 5 | ||
| @@ -23,10 +24,41 @@ | |||
| 23 | #define LOGSQL_DECLARE_DATA __declspec(dllimport) | 24 | #define LOGSQL_DECLARE_DATA __declspec(dllimport) |
| 24 | #endif | 25 | #endif |
| 25 | 26 | ||
| 26 | typedef const char *log_sql_item_func(request_rec *r, char *a); | 27 | typedef const char *logsql_item_func(request_rec *r, char *a); |
| 27 | 28 | ||
| 28 | /* Registration Function for extract functions */ | 29 | /* Registration Function for extract functions */ |
| 29 | LOGSQL_DECLARE(void) log_sql_register_item(server_rec *s, apr_pool_t *p, | 30 | LOGSQL_DECLARE(void) log_sql_register_item(server_rec *s, apr_pool_t *p, |
| 30 | char key, log_sql_item_func *func, const char *sql_field_name, | 31 | char key, logsql_item_func *func, const char *sql_field_name, |
| 31 | int want_orig_default, int string_contents); | 32 | int want_orig_default, int string_contents); |
| 33 | |||
| 34 | /* DB Connection structure holds connection status information | ||
| 35 | * and connection handle | ||
| 36 | */ | ||
| 37 | typedef struct { | ||
| 38 | int connected; /* Are we connected to the DB */ | ||
| 39 | void *handle; /* DB specific connection pointer */ | ||
| 40 | } logsql_dbconnection; | ||
| 41 | |||
| 42 | /* open db handle return values*/ | ||
| 43 | typedef enum { | ||
| 44 | LOGSQL_OPENDB_FAIL = 0, | ||
| 45 | LOGSQL_OPENDB_SUCCESS, | ||
| 46 | LOGSQL_OPENDB_ALREADY, | ||
| 47 | LOGSQL_OPENDB_PRESERVE | ||
| 48 | } logsql_opendb; | ||
| 49 | |||
| 50 | /* For passing to create_tables handler */ | ||
| 51 | typedef enum { | ||
| 52 | LOGSQL_TABLE_ACCESS = 0, | ||
| 53 | LOGSQL_TABLE_NOTES, | ||
| 54 | LOGSQL_TABLE_HEADERSOUT, | ||
| 55 | LOGSQL_TABLE_HEADERSIN, | ||
| 56 | LOGSQL_TABLE_COOKIES, | ||
| 57 | } logsql_tabletype; | ||
| 58 | |||
| 59 | /* All Tables */ | ||
| 60 | #define LOGSQL_TABLE_ALL LOGSQL_TABLE_ACCESS | LOGSQL_TABLE_NOTES | \ | ||
| 61 | LOGSQL_TABLE_HEADERSIN | LOGSQL_TABLE_HEADERSOUT | LOGSQL_TABLE_COOKIES | ||
| 62 | |||
| 63 | |||
| 32 | #endif /* MOD_LOG_SQL_H */ | 64 | #endif /* MOD_LOG_SQL_H */ |
diff --git a/mod_log_sql.prj b/mod_log_sql.prj index ad294d5..4c194ce 100644 --- a/mod_log_sql.prj +++ b/mod_log_sql.prj | |||
| @@ -68,7 +68,8 @@ module.source.files=\ | |||
| 68 | mod_log_sql.c\ | 68 | mod_log_sql.c\ |
| 69 | make_combined_log.pl\ | 69 | make_combined_log.pl\ |
| 70 | contrib/mysql_import_combined_log.pl\ | 70 | contrib/mysql_import_combined_log.pl\ |
| 71 | mod_log_sql_ssl.c | 71 | mod_log_sql_ssl.c\ |
| 72 | mod_log_sql_mysql.c | ||
| 72 | 73 | ||
| 73 | module.pixmap.name=. | 74 | module.pixmap.name=. |
| 74 | module.pixmap.type= | 75 | module.pixmap.type= |
diff --git a/mod_log_sql_mysql.c b/mod_log_sql_mysql.c new file mode 100644 index 0000000..3f05935 --- /dev/null +++ b/mod_log_sql_mysql.c | |||
| @@ -0,0 +1,241 @@ | |||
| 1 | /* $Id: mod_log_sql_mysql.c,v 1.1 2004/02/29 23:36:18 urkle Exp $ */ | ||
| 2 | #include "mysql.h" | ||
| 3 | #include "mysqld_error.h" | ||
| 4 | |||
| 5 | #if defined(WITH_APACHE20) | ||
| 6 | # include "apache20.h" | ||
| 7 | #elif defined(WITH_APACHE13) | ||
| 8 | # include "apache13.h" | ||
| 9 | #else | ||
| 10 | # error Unsupported Apache version | ||
| 11 | #endif | ||
| 12 | |||
| 13 | #ifdef HAVE_CONFIG_H | ||
| 14 | /* Undefine these to prevent conflicts between Apache ap_config_auto.h and | ||
| 15 | * my config.h. Only really needed for Apache < 2.0.48, but it can't hurt. | ||
| 16 | */ | ||
| 17 | #undef PACKAGE_BUGREPORT | ||
| 18 | #undef PACKAGE_NAME | ||
| 19 | #undef PACKAGE_STRING | ||
| 20 | #undef PACKAGE_TARNAME | ||
| 21 | #undef PACKAGE_VERSION | ||
| 22 | |||
| 23 | #include "config.h" | ||
| 24 | #endif | ||
| 25 | |||
| 26 | #include "mod_log_sql.h" | ||
| 27 | |||
| 28 | /* The enduser won't modify these */ | ||
| 29 | #define MYSQL_ERROR(mysql) ((mysql)?(mysql_error(mysql)):"MySQL server has gone away") | ||
| 30 | |||
| 31 | logsql_opendb log_sql_mysql_connect(server_rec *s, logsql_dbconnection *db, | ||
| 32 | apr_table_t *dbparms) | ||
| 33 | { | ||
| 34 | MYSQL *dblink; | ||
| 35 | char *host = apr_table_get(dbparms,"host"); | ||
| 36 | char *user = apr_table_get(dbparms,"user"); | ||
| 37 | char *passwd = apr_table_get(dbparms,"passwd"); | ||
| 38 | char *database = apr_table_get(dbparms,"database"); | ||
| 39 | char *tcpport = apr_table_get(dbparms,"tcpport"); | ||
| 40 | char *socketfile = apr_table_get(dbparms,"socketfile"); | ||
| 41 | mysql_init(&dblink); | ||
| 42 | if (mysql_real_connect(&dblink, host, user, passwd, database, tcpport, | ||
| 43 | socketfile, 0) { | ||
| 44 | log_error(APLOG_MARK,APLOG_DEBUG,s,"HOST: '%s' PORT: '%d' DB: '%s' USER: '%s' SOCKET: '%s'", | ||
| 45 | host, tcpport, database, user, socketfile); | ||
| 46 | return LOGSQL_OPENDB_SUCCESS; | ||
| 47 | } else { | ||
| 48 | log_error(APLOG_MARK,APLOG_DEBUG,s,"mod_log_sql: database connection error: %s", | ||
| 49 | MYSQL_ERROR(&dblink)); | ||
| 50 | log_error(APLOG_MARK,APLOG_DEBUG,s,"HOST: '%s' PORT: '%d' DB: '%s' USER: '%s' SOCKET: '%s'", | ||
| 51 | host, tcpport, database, user, socketfile); | ||
| 52 | return LOGSQL_OPENDB_FAIL; | ||
| 53 | } | ||
| 54 | } | ||
| 55 | |||
| 56 | /*-----------------------------------------------------* | ||
| 57 | * safe_sql_query: perform a database query with * | ||
| 58 | * a degree of safety and error checking. * | ||
| 59 | * * | ||
| 60 | * Parms: request record, SQL insert statement * | ||
| 61 | * Returns: 0 (OK) on success * | ||
| 62 | * 1 if have no log handle * | ||
| 63 | * 2 if insert delayed failed (kluge) * | ||
| 64 | * the actual MySQL return code on error * | ||
| 65 | *-----------------------------------------------------*/ | ||
| 66 | unsigned int log_sql_mysql_query(request_rec *r, const char *query) | ||
| 67 | { | ||
| 68 | int retval; | ||
| 69 | struct timespec delay, remainder; | ||
| 70 | int ret; | ||
| 71 | void (*handler) (int); | ||
| 72 | logsql_state *cls; | ||
| 73 | unsigned int real_error = 0; | ||
| 74 | const char *real_error_str = NULL; | ||
| 75 | |||
| 76 | /* A failed mysql_query() may send a SIGPIPE, so we ignore that signal momentarily. */ | ||
| 77 | handler = signal(SIGPIPE, SIG_IGN); | ||
| 78 | |||
| 79 | /* First attempt for the query */ | ||
| 80 | if (!global_config.server_p) { | ||
| 81 | signal(SIGPIPE, handler); | ||
| 82 | return 1; | ||
| 83 | } else if (!(retval = mysql_query(global_config.server_p, query))) { | ||
| 84 | signal(SIGPIPE, handler); | ||
| 85 | return 0; | ||
| 86 | } | ||
| 87 | |||
| 88 | /* If we ran the query and it returned an error, try to be robust. | ||
| 89 | * (After all, the module thought it had a valid mysql_log connection but the query | ||
| 90 | * could have failed for a number of reasons, so we have to be extra-safe and check.) */ | ||
| 91 | |||
| 92 | /* Check to see if the error is "nonexistent table" */ | ||
| 93 | if (global_config.insertdelayed) { | ||
| 94 | real_error_str = MYSQL_ERROR(global_config.server_p); | ||
| 95 | retval = (strstr(real_error_str, "Table")) && (strstr(real_error_str,"doesn't exist")); | ||
| 96 | } else { | ||
| 97 | real_error = mysql_errno(global_config.server_p); | ||
| 98 | retval = (real_error == ER_NO_SUCH_TABLE); | ||
| 99 | } | ||
| 100 | if (retval) { | ||
| 101 | log_error(APLOG_MARK,APLOG_ERR,r->server,"table does not exist, preserving query"); | ||
| 102 | preserve_entry(r, query); | ||
| 103 | /* Restore SIGPIPE to its original handler function */ | ||
| 104 | signal(SIGPIPE, handler); | ||
| 105 | return ER_NO_SUCH_TABLE; | ||
| 106 | } | ||
| 107 | |||
| 108 | /* Handle all other types of errors */ | ||
| 109 | |||
| 110 | cls = ap_get_module_config(r->server->module_config, &log_sql_module); | ||
| 111 | |||
| 112 | /* Something went wrong, so start by trying to restart the db link. */ | ||
| 113 | if (global_config.insertdelayed) { | ||
| 114 | real_error = 2; | ||
| 115 | } /*else { | ||
| 116 | real_error = mysql_errno(global_config.server_p); | ||
| 117 | }*/ | ||
| 118 | |||
| 119 | log_error(APLOG_MARK,APLOG_ERR,r->server,"first attempt failed, API said: error %d, \"%s\"", real_error, MYSQL_ERROR(global_config.server_p)); | ||
| 120 | mysql_close(global_config.server_p); | ||
| 121 | global_config.server_p = NULL; | ||
| 122 | open_logdb_link(r->server); | ||
| 123 | |||
| 124 | if (global_config.server_p == NULL) { /* still unable to link */ | ||
| 125 | signal(SIGPIPE, handler); | ||
| 126 | log_error(APLOG_MARK,APLOG_ERR,r->server,"reconnect failed, unable to reach database. SQL logging stopped until child regains a db connection."); | ||
| 127 | log_error(APLOG_MARK,APLOG_ERR,r->server,"log entries are being preserved in %s", cls->preserve_file); | ||
| 128 | return 1; | ||
| 129 | } else | ||
| 130 | log_error(APLOG_MARK,APLOG_ERR,r->server,"db reconnect successful"); | ||
| 131 | |||
| 132 | /* First sleep for a tiny amount of time. */ | ||
| 133 | delay.tv_sec = 0; | ||
| 134 | delay.tv_nsec = 250000000; /* max is 999999999 (nine nines) */ | ||
| 135 | ret = nanosleep(&delay, &remainder); | ||
| 136 | if (ret && errno != EINTR) | ||
| 137 | log_error(APLOG_MARK,APLOG_ERR,r->server,"nanosleep unsuccessful"); | ||
| 138 | |||
| 139 | /* Then make our second attempt */ | ||
| 140 | retval = mysql_query(global_config.server_p,query); | ||
| 141 | |||
| 142 | /* If this one also failed, log that and append to our local offline file */ | ||
| 143 | if (retval) { | ||
| 144 | if (global_config.insertdelayed) { | ||
| 145 | real_error = 2; | ||
| 146 | } else { | ||
| 147 | real_error = mysql_errno(global_config.server_p); | ||
| 148 | } | ||
| 149 | |||
| 150 | log_error(APLOG_MARK,APLOG_ERR,r->server,"second attempt failed, API said: error %d, \"%s\" -- preserving", real_error, MYSQL_ERROR(global_config.server_p)); | ||
| 151 | preserve_entry(r, query); | ||
| 152 | retval = real_error; | ||
| 153 | } else { | ||
| 154 | log_error(APLOG_MARK,APLOG_ERR,r->server,"second attempt successful"); | ||
| 155 | retval = 0; | ||
| 156 | } | ||
| 157 | /* Restore SIGPIPE to its original handler function */ | ||
| 158 | signal(SIGPIPE, handler); | ||
| 159 | return retval; | ||
| 160 | } | ||
| 161 | |||
| 162 | /*-----------------------------------------------------* | ||
| 163 | * safe_create_tables: create SQL table set for the * | ||
| 164 | * virtual server represented by cls. * | ||
| 165 | * * | ||
| 166 | * Parms: virtserver structure, request record, * | ||
| 167 | * tables to create * | ||
| 168 | * Returns: 0 on no errors * | ||
| 169 | * mysql error code on failure * | ||
| 170 | *-----------------------------------------------------*/ | ||
| 171 | int mod_log_mysql_create_tables(request_rec *r, logsql_tabletype table_type, | ||
| 172 | const char *table_name) | ||
| 173 | { | ||
| 174 | int retval; | ||
| 175 | |||
| 176 | char *type_suffix = NULL; | ||
| 177 | |||
| 178 | char *create_prefix = "create table if not exists `"; | ||
| 179 | char *create_suffix = NULL; | ||
| 180 | char *create_sql; | ||
| 181 | |||
| 182 | if (!global_config.createtables) { | ||
| 183 | return APR_SUCCESS; | ||
| 184 | } | ||
| 185 | |||
| 186 | switch (table_type) { | ||
| 187 | case LOGSQL_TABLE_ACCESS: | ||
| 188 | create_suffix = | ||
| 189 | "` (id char(19),\ | ||
| 190 | agent varchar(255),\ | ||
| 191 | bytes_sent int unsigned,\ | ||
| 192 | child_pid smallint unsigned,\ | ||
| 193 | cookie varchar(255),\ | ||
| 194 | machine_id varchar(25),\ | ||
| 195 | request_file varchar(255),\ | ||
| 196 | referer varchar(255),\ | ||
| 197 | remote_host varchar(50),\ | ||
| 198 | remote_logname varchar(50),\ | ||
| 199 | remote_user varchar(50),\ | ||
| 200 | request_duration smallint unsigned,\ | ||
| 201 | request_line varchar(255),\ | ||
| 202 | request_method varchar(10),\ | ||
| 203 | request_protocol varchar(10),\ | ||
| 204 | request_time char(28),\ | ||
| 205 | request_uri varchar(255),\ | ||
| 206 | request_args varchar(255),\ | ||
| 207 | server_port smallint unsigned,\ | ||
| 208 | ssl_cipher varchar(25),\ | ||
| 209 | ssl_keysize smallint unsigned,\ | ||
| 210 | ssl_maxkeysize smallint unsigned,\ | ||
| 211 | status smallint unsigned,\ | ||
| 212 | time_stamp int unsigned,\ | ||
| 213 | virtual_host varchar(255))"; | ||
| 214 | break; | ||
| 215 | case LOGSQL_TABLE_COOKIES: | ||
| 216 | case LOGSQL_TABLE_HEADERSIN: | ||
| 217 | case LOGSQL_TABLE_HEADERSOUT: | ||
| 218 | case LOGSQL_TABLE_NOTES: | ||
| 219 | create_suffix = | ||
| 220 | "` (id char(19),\ | ||
| 221 | item varchar(80),\ | ||
| 222 | val varchar(80))"; | ||
| 223 | break; | ||
| 224 | } | ||
| 225 | |||
| 226 | if (global_config.tabletype) { | ||
| 227 | type_suffix = apr_pstrcat(r->pool, " TYPE=", | ||
| 228 | global_config.tabletype, NULL); | ||
| 229 | } | ||
| 230 | /* Find memory long enough to hold the whole CREATE string + \0 */ | ||
| 231 | create_sql = apr_pstrcat(r->pool, create_prefix, table_name, create_suffix, | ||
| 232 | type_suffix, NULL); | ||
| 233 | |||
| 234 | log_error(APLOG_MARK,APLOG_DEBUG,r->server,"create string: %s", create_sql); | ||
| 235 | |||
| 236 | if ((retval = safe_sql_query(r, create_sql))) { | ||
| 237 | log_error(APLOG_MARK,APLOG_ERR,r->server,"failed to create table: %s", | ||
| 238 | table_name); | ||
| 239 | } | ||
| 240 | return retval; | ||
| 241 | } | ||
diff --git a/mod_log_sql_ssl.c b/mod_log_sql_ssl.c index c874a2b..2bdb37b 100644 --- a/mod_log_sql_ssl.c +++ b/mod_log_sql_ssl.c | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* $Header: /home/cvs/mod_log_sql/mod_log_sql_ssl.c,v 1.4 2004/01/22 05:26:56 urkle Exp $ */ | 1 | /* $Id: mod_log_sql_ssl.c,v 1.5 2004/02/29 23:36:18 urkle Exp $ */ |
| 2 | /* mod_log_sql_ssl */ | 2 | /* mod_log_sql_ssl */ |
| 3 | 3 | ||
| 4 | #if defined(WITH_APACHE20) | 4 | #if defined(WITH_APACHE20) |
