summaryrefslogtreecommitdiffstatsabout
path: root/mod_log_sql.c
diff options
context:
space:
mode:
Diffstat (limited to 'mod_log_sql.c')
-rw-r--r--mod_log_sql.c195
1 files changed, 138 insertions, 57 deletions
diff --git a/mod_log_sql.c b/mod_log_sql.c
index 6780b74..61c1ed9 100644
--- a/mod_log_sql.c
+++ b/mod_log_sql.c
@@ -1,10 +1,13 @@
1/* $Id: mod_log_sql.c,v 1.5 2002/01/15 18:40:14 helios Exp $ */ 1/* $Id: mod_log_sql.c,v 1.6 2002/04/02 20:19:30 helios Exp $ */
2 2
3 3
4/* DEFINES */ 4/* DEFINES */
5#define MYSQL_ERROR(mysql) ((mysql)?(mysql_error(mysql)):"MySQL server has gone away") 5#define MYSQL_ERROR(mysql) ((mysql)?(mysql_error(mysql)):"MySQL server has gone away")
6#define ERRLEVEL APLOG_ERR|APLOG_NOERRNO 6#define ERRLEVEL APLOG_ERR|APLOG_NOERRNO
7#define WARNINGLEVEL APLOG_WARNING|APLOG_NOERRNO
8#define NOTICELEVEL APLOG_NOTICE|APLOG_NOERRNO
7#define DEBUGLEVEL APLOG_INFO|APLOG_NOERRNO 9#define DEBUGLEVEL APLOG_INFO|APLOG_NOERRNO
10#define PRESERVEFILE "/tmp/mysql-preserve"
8/* (MYSQLSOCKET, DEBUG and WANT_SSL_LOGGING are defined in the Makefile DEFS line.) */ 11/* (MYSQLSOCKET, DEBUG and WANT_SSL_LOGGING are defined in the Makefile DEFS line.) */
9 12
10 13
@@ -463,15 +466,35 @@ const char *mysql_escape_log(const char *str, pool *p)
463 } 466 }
464} 467}
465 468
466void open_logdb_link() 469int open_logdb_link()
467{ 470{
468 if (mysql_log != NULL) { /* virtual database link shared with main server */ 471 if (mysql_log != NULL) {
469 return; 472 return 2;
470 } 473 }
471 if (db_name) { /* open an SQL link */ 474
475 if (db_name) {
472 mysql_init(&sql_server); 476 mysql_init(&sql_server);
473 mysql_log = mysql_real_connect(&sql_server, db_host, db_user, db_pwd, db_name, 0, MYSQLSOCKET, 0); 477 mysql_log = mysql_real_connect(&sql_server, db_host, db_user, db_pwd, db_name, 0, MYSQLSOCKET, 0);
478
479 if (mysql_log != NULL) {
480 return 1;
481 } else {
482 return 0;
483 }
474 } 484 }
485 return 0;
486}
487
488void preserve_entry(request_rec *r, const char *query)
489{
490 FILE *fp;
491
492 fp = fopen(PRESERVEFILE, "a");
493 if (fp == NULL)
494 ap_log_error(APLOG_MARK,ERRLEVEL,r->server,"MySQL: attempted append of local offline file but failed.");
495 else
496 fprintf(fp,"%s\n", query);
497 fclose(fp);
475} 498}
476 499
477int safe_mysql_query(request_rec *r, const char *query) 500int safe_mysql_query(request_rec *r, const char *query)
@@ -481,57 +504,61 @@ int safe_mysql_query(request_rec *r, const char *query)
481 int ret; 504 int ret;
482 char *str; 505 char *str;
483 void (*handler) (int); 506 void (*handler) (int);
507
484 508
485 /* A failed mysql_query() may send a SIGPIPE, so we ignore that signal momentarily. */ 509 /* A failed mysql_query() may send a SIGPIPE, so we ignore that signal momentarily. */
486 handler = signal(SIGPIPE, SIG_IGN); 510 handler = signal(SIGPIPE, SIG_IGN);
487 511
488 /* If there's no DB link, or if we run the query and it gacks, try to be graceful */ 512 /* First attempt for the query */
489 if ( !mysql_log || 513 retval = mysql_query(mysql_log, query);
490 ( 514
491 (retval = mysql_query(mysql_log, query)) && 515 /* If we ran the query and it returned an error, try to be graceful.
492 (mysql_errno(mysql_log) != 0) 516 * We only reach this point if the module thinks it has a valid connection to the
493 ) 517 * database (i.e. mysql_log is non-null). But that connection could go sour
494 ) 518 * at any time, hence the check. */
495 519 if ( retval != 0 )
496 { /* We need to restart the server link */ 520 {
497 mysql_log = NULL; 521 /* Something went wrong, so start by trying to restart the db link. */
498 ap_log_error(APLOG_MARK,ERRLEVEL,r->server,"MySQL: connection lost, attempting reconnect"); 522 ap_log_error(APLOG_MARK,ERRLEVEL,r->server,"MySQL: attempting reconnect because API said: %s", MYSQL_ERROR(mysql_log));
499 523
524 mysql_log = NULL;
500 open_logdb_link(); 525 open_logdb_link();
501 526
502 if (mysql_log == NULL) { /* still unable to link */ 527 if (mysql_log == NULL) { /* still unable to link */
503 signal(SIGPIPE, handler); 528 signal(SIGPIPE, handler);
504 ap_log_error(APLOG_MARK,ERRLEVEL,r->server,"MySQL: reconnect failed"); 529 ap_log_error(APLOG_MARK,ERRLEVEL,r->server,"MySQL: httpd child reconnect failed, unable to reach database. SQL logging stopped until an httpd child regains a db connection.");
530 ap_log_error(APLOG_MARK,ERRLEVEL,r->server,"MySQL: log entries are being preserved in %s",PRESERVEFILE);
505 return retval; 531 return retval;
506 } 532 } else {
533 ap_log_error(APLOG_MARK,ERRLEVEL,r->server,"MySQL: reconnect successful.");
534 }
507 535
508 ap_log_error(APLOG_MARK,ERRLEVEL,r->server,"MySQL: reconnect successful"); 536 /* Attempt a single re-try... First sleep for a tiny amount of time. */
509 retval = mysql_query(mysql_log, query); 537 delay.tv_sec = 0;
538 delay.tv_nsec = 500000000; /* max is 999999999 (nine nines) */
539 ret = nanosleep(&delay, &remainder);
540 if (ret && errno != EINTR)
541 perror("nanosleep");
542
543 /* Now make our second attempt */
544 retval = mysql_query(mysql_log,query);
545
546 /* If this one also failed, log that and append to our local offline file */
547 if ( retval != 0 )
548 {
549 str = pstrcat(r->pool, "MySQL delayed insert attempt failed, API said: ", MYSQL_ERROR(mysql_log), NULL);
550 ap_log_error(APLOG_MARK,ERRLEVEL,r->server,str);
551
552 preserve_entry(r, query);
553 ap_log_error(APLOG_MARK,ERRLEVEL,r->server,"MySQL: entry preserved in %s",PRESERVEFILE);
554 } else {
555 ap_log_error(APLOG_MARK,ERRLEVEL,r->server,"MySQL: insert successful after a delayed retry.");
556 }
510 } 557 }
511 558
512 /* Restore SIGPIPE to its original handler function */ 559 /* Restore SIGPIPE to its original handler function */
513 signal(SIGPIPE, handler); 560 signal(SIGPIPE, handler);
514 561
515 if (retval) {
516 /* Attempt a single re-try... First sleep for a tiny amount of time. */
517 delay.tv_sec = 0;
518 delay.tv_nsec = 500000000; /* max is 999999999 (nine nines) */
519 ret = nanosleep(&delay, &remainder);
520 if (ret && errno != EINTR)
521 perror("nanosleep");
522
523 /* Now re-attempt */
524 retval = mysql_query(mysql_log,query);
525
526 if (retval) {
527 str = pstrcat(r->pool, "MySQL insert failed: ", query, NULL);
528 ap_log_error(APLOG_MARK,ERRLEVEL,r->server,str);
529 str = pstrcat(r->pool, "MySQL failure reason: ", MYSQL_ERROR(mysql_log), NULL);
530 ap_log_error(APLOG_MARK,ERRLEVEL,r->server,str);
531 } else {
532 ap_log_error(APLOG_MARK,ERRLEVEL,r->server,"MySQL: insert successful after a delayed retry.");
533 }
534 }
535 return retval; 562 return retval;
536} 563}
537 564
@@ -657,7 +684,7 @@ void *log_mysql_make_state(pool *p, server_rec *s)
657 684
658 685
659/* Setup of the available httpd.conf configuration commands. 686/* Setup of the available httpd.conf configuration commands.
660 * command, function called, NULL, where available, how many arguments, verbose description 687 * Structure: command, function called, NULL, where available, how many arguments, verbose description
661 */ 688 */
662command_rec log_mysql_cmds[] = { 689command_rec log_mysql_cmds[] = {
663 {"MySQLRefererLogTable", set_referer_log_mysql_table, NULL, RSRC_CONF, TAKE1, 690 {"MySQLRefererLogTable", set_referer_log_mysql_table, NULL, RSRC_CONF, TAKE1,
@@ -708,7 +735,8 @@ int log_mysql_transaction(request_rec *orig)
708 request_rec *r; 735 request_rec *r;
709 int retvalue = DECLINED; 736 int retvalue = DECLINED;
710 int referer_needed, agent_needed, transfer_needed; 737 int referer_needed, agent_needed, transfer_needed;
711 738
739
712 /* Are there configuration directives for these SQL logs? For each found 740 /* Are there configuration directives for these SQL logs? For each found
713 * config directive that is found, mark that type as 'needed'. 741 * config directive that is found, mark that type as 'needed'.
714 */ 742 */
@@ -719,13 +747,7 @@ int log_mysql_transaction(request_rec *orig)
719 if (!referer_needed && !agent_needed && !transfer_needed) { 747 if (!referer_needed && !agent_needed && !transfer_needed) {
720 return OK; 748 return OK;
721 } 749 }
722 750
723 if (mysql_log == NULL) { /* mysql link not up, hopefully we can do something about it */
724 open_logdb_link();
725 if (mysql_log == NULL) {
726 return OK;
727 }
728 }
729 751
730 for (r = orig; r->next; r = r->next) { 752 for (r = orig; r->next; r = r->next) {
731 continue; 753 continue;
@@ -750,7 +772,20 @@ int log_mysql_transaction(request_rec *orig)
750 } 772 }
751 } 773 }
752 str = pstrcat(orig->pool, "insert into ", cls->referer_table_name, " (referer,url,time_stamp) values ('", mysql_escape_log(referer, orig->pool), "','", mysql_escape_log(r->uri, orig->pool), "',unix_timestamp(now()) )", NULL); 774 str = pstrcat(orig->pool, "insert into ", cls->referer_table_name, " (referer,url,time_stamp) values ('", mysql_escape_log(referer, orig->pool), "','", mysql_escape_log(r->uri, orig->pool), "',unix_timestamp(now()) )", NULL);
753 safe_mysql_query(orig, str); 775
776 if (mysql_log == NULL) { /* child's mysql link not up, re-establish it */
777 open_logdb_link();
778 if (mysql_log == NULL) {
779 preserve_entry(r, str);
780 return OK;
781 } else {
782 ap_log_error(APLOG_MARK,NOTICELEVEL,orig->server,"MySQL: httpd child established database connection");
783 safe_mysql_query(orig, str);
784 }
785 } else {
786 safe_mysql_query(orig, str);
787 }
788
754 } 789 }
755 } 790 }
756 791
@@ -763,7 +798,19 @@ int log_mysql_transaction(request_rec *orig)
763 798
764 if (agent != NULL) { 799 if (agent != NULL) {
765 str = pstrcat(orig->pool, "insert into ", cls->agent_table_name, "(agent,time_stamp) values ('", mysql_escape_log(agent, orig->pool), "',unix_timestamp(now()) )", NULL); 800 str = pstrcat(orig->pool, "insert into ", cls->agent_table_name, "(agent,time_stamp) values ('", mysql_escape_log(agent, orig->pool), "',unix_timestamp(now()) )", NULL);
766 safe_mysql_query(orig, str); 801
802 if (mysql_log == NULL) { /* child's mysql link not up, re-establish it */
803 open_logdb_link();
804 if (mysql_log == NULL) {
805 preserve_entry(r, str);
806 return OK;
807 } else {
808 ap_log_error(APLOG_MARK,NOTICELEVEL,orig->server,"MySQL: httpd child established database connection");
809 safe_mysql_query(orig, str);
810 }
811 } else {
812 safe_mysql_query(orig, str);
813 }
767 } 814 }
768 } 815 }
769 816
@@ -771,7 +818,7 @@ int log_mysql_transaction(request_rec *orig)
771 if (transfer_needed) { 818 if (transfer_needed) {
772 const char *thehost; 819 const char *thehost;
773 820
774 char *fields = "", *values = "", *query; 821 char *fields = "", *values = "";
775 const char *formatted_item; 822 const char *formatted_item;
776 int i, j, length; 823 int i, j, length;
777 824
@@ -840,8 +887,29 @@ int log_mysql_transaction(request_rec *orig)
840 } 887 }
841 888
842 /* Set up the actual INSERT statement and execute it. */ 889 /* Set up the actual INSERT statement and execute it. */
843 query = pstrcat(orig->pool, "insert into ", cls->transfer_table_name, " (", fields, ") values (", values, ")", NULL); 890 str = pstrcat(orig->pool, "insert into ", cls->transfer_table_name, " (", fields, ") values (", values, ")", NULL);
844 safe_mysql_query(orig, query); 891
892
893 /* How's our mysql link integrity? */
894 if (mysql_log == NULL) {
895
896 /* Try to regain the link */
897 open_logdb_link();
898
899 if (mysql_log == NULL) {
900 /* Unable to re-establish a DB link, so assume that it's really
901 * gone and send the entry to the preserve file instead. */
902 preserve_entry(r, str);
903 return OK;
904 } else {
905 /* Whew, we got the DB link back */
906 ap_log_error(APLOG_MARK,NOTICELEVEL,orig->server,"MySQL: httpd child established database connection");
907 safe_mysql_query(orig, str);
908 }
909 } else {
910 /* Everything was fine */
911 safe_mysql_query(orig, str);
912 }
845 913
846 } 914 }
847 return retvalue; 915 return retvalue;
@@ -851,7 +919,20 @@ int log_mysql_transaction(request_rec *orig)
851/* Called on the exit of an httpd child process */ 919/* Called on the exit of an httpd child process */
852static void log_mysql_child_exit(server_rec *s, pool *p) 920static void log_mysql_child_exit(server_rec *s, pool *p)
853{ 921{
854 mysql_close(mysql_log); 922 mysql_close(mysql_log);
923}
924
925/* Called on the init of an httpd child process */
926static void log_mysql_child_init(server_rec *s, pool *p)
927{
928 int retval;
929
930 retval = open_logdb_link();
931 #ifdef DEBUG
932 if (retval > 0) {
933 ap_log_error(APLOG_MARK,DEBUGLEVEL,s,"MySQL: open_logdb_link successful");
934 }
935 #endif
855} 936}
856 937
857 938
@@ -874,7 +955,7 @@ module mysql_log_module = {
874 log_mysql_transaction, /* logger */ 955 log_mysql_transaction, /* logger */
875 NULL, /* header parser */ 956 NULL, /* header parser */
876#if MODULE_MAGIC_NUMBER >= 19970728 /* 1.3-dev or later support these additionals... */ 957#if MODULE_MAGIC_NUMBER >= 19970728 /* 1.3-dev or later support these additionals... */
877 NULL, /* child_init */ 958 log_mysql_child_init, /* child_init */
878 log_mysql_child_exit, /* process exit/cleanup */ 959 log_mysql_child_exit, /* process exit/cleanup */
879 NULL /* [#0] post read-request */ 960 NULL /* [#0] post read-request */
880#endif 961#endif