From aed1f25397eff242228dadb33f934d2722ba684d Mon Sep 17 00:00:00 2001 From: Christopher Powell Date: Tue, 14 May 2002 21:47:15 +0000 Subject: Added notes logging capability. This is a commit prior to a lot of work that will rename mod_log_mysql to mod_log_sql. --- CHANGELOG | 32 +++++- CONFIGURATION | 6 +- INSTALL | 46 ++++----- LICENSE | 87 ++++++++-------- Makefile | 62 +++++++---- README | 42 +++++--- access_log.sql | 26 ++--- mod_log_sql.c | 318 +++++++++++++++++++++++++++++++++++++++++---------------- 8 files changed, 404 insertions(+), 215 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 60318c2..24e56a1 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,17 +1,39 @@ -$Id: CHANGELOG,v 1.10 2002/04/23 03:46:20 helios Exp $ +$Id: CHANGELOG,v 1.11 2002/05/14 21:47:14 helios Exp $ TODO: * Full commenting of the code. * Rethink documentation flow and rewrite? * Port connection portion to other DBMS? Genericize the module? Start with PostgreSQL. -* Fully test create-table -* Document new features -* check for mandatory conf directives quit if not +* check for mandatory conf directives / syntax quit if not +* merge server config into vh config +* port to Apache 2.x CHANGES: +1.17: +* Renamed the module mod_log_sql to conform to the project goal of + database-inspecificity. +* Added capability of logging Notes field. This is useful for folks using + custom modules that provide loggable info in the notes, e.g. mod_gzip. + A new directive MySQLWhichNotes configures which notes to log to the + notes_log table. +* Fixed potential segfault in preserve file function due to silly pfclose + placement. (Only affected user if the preserve file couldn't + be opened.) +* Changed default socket file to /tmp/mysql.sock because that's the + default on a compiled MySQL. +* Also check for '-' when I'm creating the table when MySQLMassVirtualHosting + is on, and change it to underscore. (Already did this with '.') +* Took away the prepend of /tmp to the preserve filename. Now the + user can specify whatever local path they want. I figure that + filesystem permissions will prevent people from doing anything + really dumb, and people have requested this change. +* Better checking in the extract_cookie routine. Before, it could + segfault if a person specified "c" but didn't define MySQLWhichCookie. + + 1.16: * Moved all the user DEFINEs inside the .c file -- splitting them between the C and the Makefile was getting just too cumbersome. @@ -25,7 +47,7 @@ CHANGES: version the name of the MySQL socket was hardcoded. Now the user can configure this at Apache runtime. However, it is a global setting (set once) just like the rest of the actual database info is. - It defaults ot a hardcoded value if the user does not define it. + It defaults to a hardcoded value if the user does not define it. * A new MySQLCreateTables runtime config directive. Module can now create the access table on-the-fly. Table creation takes place during the virtual server's first request and is flagged after that to diff --git a/CONFIGURATION b/CONFIGURATION index 75117c3..9ce05a4 100644 --- a/CONFIGURATION +++ b/CONFIGURATION @@ -1,8 +1,8 @@ -$Id: CONFIGURATION,v 1.1 2001/11/28 05:26:54 helios Exp $ +$Id: CONFIGURATION,v 1.2 2002/05/14 21:47:14 helios Exp $ Run-time configuration directives are fully documented on the -mod_log_mysql homepage: +mod_log_sql homepage: -http://www.grubbybaby.com/mod_log_mysql/directives.html +http://www.grubbybaby.com/mod_log_sql/directives.html diff --git a/INSTALL b/INSTALL index c620963..03adc35 100644 --- a/INSTALL +++ b/INSTALL @@ -1,4 +1,4 @@ -$Id: INSTALL,v 1.7 2002/04/21 23:01:52 helios Exp $ +$Id: INSTALL,v 1.8 2002/05/14 21:47:14 helios Exp $ Requirements @@ -48,8 +48,8 @@ For folks interested in using this module as an Apache DSO: 1) Unpack the archive into a working directory. - # tar zxf mod_log_mysql.tar.gz -C /usr/local/src - # cd /usr/local/src/mod_log_mysql + # tar zxf mod_log_sql.tar.gz -C /usr/local/src + # cd /usr/local/src/mod_log_sql 2) Edit Makefile and make any adjustments for your system. These are fully explained in the Makefile. @@ -60,29 +60,29 @@ For folks interested in using this module as an Apache DSO: - The location of your MySQL libraries, find using 'locate libmysqlclient' FORMAT: - # /apxs -i -c -L/path/to/mysqllibs -lmysqlclient -lz mod_log_mysql.c + # /apxs -i -c -L/path/to/mysqllibs -lmysqlclient -lz mod_log_sql.c EXAMPLE: - # /usr/sbin/apxs -i -c -L/usr/lib/mysql -lmysqlclient -lz mod_log_mysql.c + # /usr/sbin/apxs -i -c -L/usr/lib/mysql -lmysqlclient -lz mod_log_sql.c You should see something like this: - gcc -fpic -DSHARED_MODULE -I/usr/local/Apache/include -c mod_log_mysql.c - ld -Bshareable -o mod_log_mysql.so mod_log_mysql.o - cp mod_log_mysql.so /mod_log_mysql.so - chmod 755 /mod_log_mysql.so + gcc -fpic -DSHARED_MODULE -I/usr/local/Apache/include -c mod_log_sql.c + ld -Bshareable -o mod_log_sql.so mod_log_sql.o + cp mod_log_sql.so /mod_log_sql.so + chmod 755 /mod_log_sql.so [activating module blah in /path/to/apache/etc/httpd.conf] 4) Add the following stanzas to your httpd.conf file. Put the second stanza somewhere after the ClearModuleList directive. - LoadModule mysql_log_module modules/mod_log_mysql.so + LoadModule mysql_log_module modules/mod_log_sql.so - AddModule mod_log_mysql.c + AddModule mod_log_sql.c @@ -99,16 +99,16 @@ Installation (as a static module compiled into httpd) 1) Unpack the archive into a working directory. - # tar zxf mod_log_mysql.tar.gz -C /usr/local/src - # cd /usr/local/src/mod_log_mysql + # tar zxf mod_log_sql.tar.gz -C /usr/local/src + # cd /usr/local/src/mod_log_sql -2) Examine the DEFINEs at the top of mod_log_mysql.c and alter any that +2) Examine the DEFINEs at the top of mod_log_sql.c and alter any that you choose. Edit Makefile and make any adjustments for your system. These are fully explained in the Makefile. 3) # make all (You should receive NO warnings or errors of any kind. - If you see messages like this: "mod_log_mysql.c:69: httpd.h: No such + If you see messages like this: "mod_log_sql.c:69: httpd.h: No such file or directory" then you do not have your CFLAGS correctly pointing to the right include directory.) @@ -126,7 +126,7 @@ Installation (as a static module compiled into httpd) -L/usr/lib/mysql -lmysqlclient -lm -lz * Find the mod_log_config.o line, and add this line immediately after it: - AddModule modules/sql/mod_log_mysql.o + AddModule modules/sql/mod_log_sql.o 6b) # cp Configuration.apaci Configuration @@ -144,7 +144,7 @@ Installation (as a static module compiled into httpd) Compiled-in modules: http_core.c - mod_log_mysql.c <-- That's the line you're looking for. + mod_log_sql.c <-- That's the line you're looking for. mod_env.c mod_log_config.c mod_mime.c @@ -161,7 +161,7 @@ Installation (as a static module compiled into httpd) 9) Configure your apache daemon to log to your database. Here's a very basic set of config lines to start you off. Full documentation is - available here: http://www.grubbybaby.com/mod_log_mysql/directives.html + available here: http://www.grubbybaby.com/mod_log_sql/directives.html EXAMPLE: Connect to the MySQL database called "apache" running on "dbmachine.foo.com". The module uses username "loguser" and @@ -186,14 +186,14 @@ Installation (as a static module compiled into httpd) 9a) Special step for users who have a DSO-enabled httpd: - If you you are building mod_log_mysql as a static module BUT + If you you are building mod_log_sql as a static module BUT your httpd is enabled for DSOs, add the following line to your httpd.conf: - AddModule mod_log_mysql.c + AddModule mod_log_sql.c -10) If you compiled mod_log_mysql with the ability to make its own tables +10) If you compiled mod_log_sql with the ability to make its own tables then you can skip this step. Otherwise you need to do it by hand: Create a database and table to hold the new log data. I log the @@ -208,7 +208,7 @@ Installation (as a static module compiled into httpd) mysql> create database apache; Then create the table called "access_log". I enclosed an SQL file - that will create every column type that mod_log_mysql supports. + that will create every column type that mod_log_sql supports. Unless you're just testing or playing around, this is probably NOT what you want, so edit the file first and delete the lines that don't pertain to you. Then: @@ -222,7 +222,7 @@ Installation (as a static module compiled into httpd) mysql> grant insert,create on apache.* to loguser@my.apachemachine.com identified by 'l0gger'; - Security is a very real concern. mod_log_mysql by default is + Security is a very real concern. mod_log_sql by default is set up to create the SQL tables it needs. If you have deactivated this capability, then create a user called "loguser" with the password "l0gger" with only the capability of INSERT to "access_log": diff --git a/LICENSE b/LICENSE index cd0c286..97de9c4 100644 --- a/LICENSE +++ b/LICENSE @@ -1,58 +1,55 @@ -$Id: LICENSE,v 1.1 2001/11/28 05:26:54 helios Exp $ +$Id: LICENSE,v 1.2 2002/05/14 21:47:14 helios Exp $ +Copyright (c) 2002 Christopher B. Powell. All rights reserved. +Portions copyright (c) 2000 The Apache Software Foundation. -In compliance with the requirements set forth by The Apache Group, -the original license to this code is hereby reproduced: - - -==================================================================== -Copyright (c) 1995-1997 The Apache Group. All rights reserved. - Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - + 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - -3. All advertising materials mentioning features or use of this - software must display the following acknowledgment: - "This product includes software developed by the Apache Group - for use in the Apache HTTP server project (http://www.apache.org/)." - -4. The names "Apache Server" and "Apache Group" must not be used to - endorse or promote products derived from this software without - prior written permission. - -5. Redistributions of any form whatsoever must retain the following - acknowledgment: - "This product includes software developed by the Apache Group - for use in the Apache HTTP server project (http://www.apache.org/)." - -THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY -EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + +3. The end-user documentation included with the redistribution, + if any, must include the following acknowledgment: + "This product includes software developed by the + Apache Software Foundation (http://www.apache.org/) + and by Christopher Powell, mod_log_mysql (TM) Module Maintainer + (http://www.grubbybaby.com/mod_log_mysql/)." + Alternately, this acknowledgment may appear in the software itself, + if and wherever such third-party acknowledgments normally appear. + +4. The names "mod_log_mysql" and "mod_log_sql" must + not be used to endorse or promote products derived from this + software without prior written permission. For written + permission, please contact . + +5. Products derived from this software may not be called + "mod_log_mysql" or "mod_log_sql", nor may "mod_log_mysql" or + "mod_log_sql" appear in their names, without prior written permission + of Christopher B. Powell. + +6. Redistributions of any form whatsoever must retain the following + acknowledgment: "This product includes software developed by + Christopher B. Powell for use in the + mod_log_mysql (TM) project (http://www.grubbybaby.com/mod_log_mysql/). + +THIS SOFTWARE IS PROVIDED `AS IS'' AND ANY EXPRESSED OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED -OF THE POSSIBILITY OF SUCH DAMAGE. -==================================================================== +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. -This software consists of voluntary contributions made by many -individuals on behalf of the Apache Group and was originally based -on public domain software written at the National Center for -Supercomputing Applications, University of Illinois, Urbana-Champaign. -For more information on the Apache Group and the Apache HTTP server -project, please see . - \ No newline at end of file diff --git a/Makefile b/Makefile index 6c3c98f..468f6d6 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ -# $Id: Makefile,v 1.9 2002/04/21 23:01:52 helios Exp $ -MLMVERS = 1.16 +# $Id: Makefile,v 1.10 2002/05/14 21:47:14 helios Exp $ +MLMVERS = 1.17 # Where you unpacked your Apache tarball -- the source. APACHESOURCE = /usr/local/src/apache_1.3.22 @@ -7,16 +7,28 @@ APACHESOURCE = /usr/local/src/apache_1.3.22 # Where Apache [got|will get] installed APACHEINST = /usr/local/Apache -# Set the WANT_SSL_LOGGING define in mod_log_mysql.c if you want to log SSL -# info, or #undef it if you don't. Then use the first CFLAGS if you *do* -# WANT_SSL_LOGGING, and confirm the paths. +# Do you want to log SSL information? +# Yes? +# - #define WANT_SSL_LOGGING in mod_log_sql.c +# - pick (A) below +# No? +# - #undef WANT_SSL_LOGGING in mod_log_sql.c +# - pick (B) below + + +# (A) # +# Modify "/usr/include/mysql" to where YOUR mysql.h can be found, # Modify "/usr/local/ssl/include" to where YOUR openssl/*.h files are, # Modify "/usr/include/db1" to where YOUR ndbm.h can be found, # Modify "/usr/local/src/apache_1.3.22/src/modules/ssl" to where YOUR mod_ssl.h can be found. # # How to find your directories: # +# $ locate mysql.h +# /usr/include/mysql/mysql.h +# ^^^^^^^^^^^^^^^^^^ +# # $ locate x509.h # /usr/local/ssl/include/openssl/x509.h # ^^^^^^^^^^^^^^^^^^^^^^ @@ -28,11 +40,23 @@ APACHEINST = /usr/local/Apache # $ locate mod_ssl.h # /usr/local/src/apache_1.3.22/src/modules/ssl/mod_ssl.h # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# Now uncomment this CFLAGS and comment out the one further down: -CFLAGS = -fpic -O2 -Wall -I${APACHEINST}/include -I/usr/local/ssl/include -I/usr/include/db1 -I${APACHESOURCE}/src/modules/ssl +CFLAGS = -fpic -O2 -Wall -I${APACHEINST}/include -I/usr/include/mysql -I/usr/local/ssl/include -I/usr/include/db1 -I${APACHESOURCE}/src/modules/ssl + +# (B) +# +# Modify "/usr/include/mysql" to where YOUR mysql.h can be found, +# +# How to find your directories: +# +# $ locate mysql.h +# /usr/include/mysql/mysql.h +# ^^^^^^^^^^^^^^^^^^ +# +# Comment out CFLAGS above and uncomment CFLAGS below: -# Use this CFLAGS if you don't WANT_SSL_LOGGING: -#CFLAGS = -fpic -O2 -Wall -I${APACHEINST}/include +#CFLAGS = -fpic -O2 -Wall -I${APACHEINST}/include -I/usr/include/mysql # --------------------------------------------------------- @@ -41,24 +65,24 @@ CFLAGS = -fpic -O2 -Wall -I${APACHEINST}/include -I/usr/local/ssl/include -I/ CC = gcc INSTALL = /usr/bin/install -m 664 -all: mod_log_mysql.o +all: mod_log_sql.o -mod_log_mysql.o: mod_log_mysql.c Makefile - $(CC) ${CFLAGS} -c mod_log_mysql.c +mod_log_sql.o: mod_log_sql.c Makefile + $(CC) ${CFLAGS} -c mod_log_sql.c install: all $(INSTALL) -d -m 755 ${APACHESOURCE}/src/modules/sql - $(INSTALL) mod_log_mysql.c ${APACHESOURCE}/src/modules/sql/mod_log_mysql.c + $(INSTALL) mod_log_sql.c ${APACHESOURCE}/src/modules/sql/mod_log_sql.c $(INSTALL) Makefile ${APACHESOURCE}/src/modules/sql/Makefile - $(INSTALL) mod_log_mysql.o ${APACHESOURCE}/src/modules/sql/mod_log_mysql.o + $(INSTALL) mod_log_sql.o ${APACHESOURCE}/src/modules/sql/mod_log_sql.o distro: all - cp -f INSTALL ${APACHEINST}/html/mod_log_mysql/ - cp -f README ${APACHEINST}/html/mod_log_mysql/ - cp -f CHANGELOG ${APACHEINST}/html/mod_log_mysql/ - cd ..; tar zcf mod_log_mysql-${MLMVERS}.tar.gz --exclude mod_log_mysql/CVS mod_log_mysql/; $(INSTALL) mod_log_mysql-${MLMVERS}.tar.gz ${APACHEINST}/html/mod_log_mysql/; rm -f mod_log_mysql-${MLMVERS}.tar.gz - rm -f ${APACHEINST}/html/mod_log_mysql/mod_log_mysql.tar.gz - ln -s mod_log_mysql-${MLMVERS}.tar.gz ${APACHEINST}/html/mod_log_mysql/mod_log_mysql.tar.gz + cp -f INSTALL ${APACHEINST}/html/mod_log_sql/ + cp -f README ${APACHEINST}/html/mod_log_sql/ + cp -f CHANGELOG ${APACHEINST}/html/mod_log_sql/ + cd ..; tar zcf mod_log_sql-${MLMVERS}.tar.gz --exclude mod_log_sql/CVS mod_log_sql/; $(INSTALL) mod_log_sql-${MLMVERS}.tar.gz ${APACHEINST}/html/mod_log_sql/; rm -f mod_log_sql-${MLMVERS}.tar.gz + rm -f ${APACHEINST}/html/mod_log_sql/mod_log_sql.tar.gz + ln -s mod_log_sql-${MLMVERS}.tar.gz ${APACHEINST}/html/mod_log_sql/mod_log_sql.tar.gz clean: rm -f *.o *~ diff --git a/README b/README index 7bea822..077b6c4 100644 --- a/README +++ b/README @@ -1,35 +1,42 @@ -$Id: README,v 1.5 2002/04/21 23:01:53 helios Exp $ +$Id: README,v 1.6 2002/05/14 21:47:15 helios Exp $ Homepage -------- -http://www.grubbybaby.com/mod_log_mysql/ - +http://www.grubbybaby.com/mod_log_sql/ Approach -------- +This project was formerly known as mod_log_mysql. It has been renamed +to mod_log_sql in order to reflect the project goal of +database-inspecificity. The module currently supports MySQL, and +development for other database backends is underway. In order to save speed and overhead, links are kept alive in between queries. This module uses one SQL link per httpd process. Among other things, this means that this module supports logging into only one -MySQL server, and for now, also, only one SQL database. +MySQL server, and for now, also, only one SQL database. But that's a +small tradeoff compared to the blinding speed of this module. Virtual hosts are supported in the same manner they are in the regular -logging modules. If you specify a different table for a virtual -host it will be used, otherwise the 'general' would be used. +logging modules. You define some basic 'global' directives in the +main server config, then you define more specific 'local' directives +inside each virtualhost stanza. SQL links are opened by each child process when it is born. Error reporting is robust throughout and will let you know about database issues in the standard Apache error-log for the server or virtual server. -A robust "preserve" capability has now been implemented as well. This -permits the module to preserve any failed INSERT commands to a local -file on its machine. In any situation that the database is unavailable -- -e.g. the network fails, you reboot the machine, etc. -- mod_log_mysql -will note this in the error log and begin appending its log entries to -the preserve file. At the time that your MySQL server returns to service, -each of these preserve files is easily imported because it is stored in SQL: +A robust "preserve" capability has now been implemented. This permits +the module to preserve any failed INSERT commands to a local file on +its machine. In any situation that the database is unavailable -- e.g. +the network fails, you reboot the db host, etc. -- mod_log_sql will +note this in the error log and begin appending its log entries to the +preserve file (which is created with the user & group ID of the running +Apache process, e.g. "nobody" on many Linux installations). At the time +that your MySQL server returns to service, each of these preserve files +is easily imported because it is simply a series of SQL insert statements: # mysql -uadminuser -p mydbname < /tmp/mysql-preserve @@ -41,11 +48,11 @@ Supported directives Please see the web-based documentation for full explanation of all supported run-time directives. - http://www.grubbybaby.com/mod_log_mysql/directives.html + http://www.grubbybaby.com/mod_log_sql/directives.html See the FAQ for some handy examples: - http://www.grubbybaby.com/mod_log_mysql/faq.html + http://www.grubbybaby.com/mod_log_sql/faq.html What gets logged by default? @@ -65,8 +72,9 @@ Notes * You will customarily set most of your run-time configuration directives on a per-virtualserver basis, with only MySQLMassVirtualHosting, - MySQLLoginInfo and MySQLDatabase 'outside' in the main server config. - Any directives other than those in the main config do NOT get inherited + MySQLLoginInfo, MySQLDatabase, MySQLSocketFile, MySQLCreateTables, + and MySQLMassVirtualHosting 'outside' in the main server config. Any + directives other than those in the main config do NOT get inherited by the virutal servers. * The 'time_stamp' field is stored in an UNSIGNED INTEGER column, in the diff --git a/access_log.sql b/access_log.sql index a667494..4966c62 100644 --- a/access_log.sql +++ b/access_log.sql @@ -1,25 +1,25 @@ create table access_log ( - agent varchar(255) not null, - bytes_sent int not null, + agent varchar(255) , + bytes_sent int , child_pid smallint unsigned, cookie varchar(255), request_file varchar(255), - referer varchar(255) not null, - remote_host varchar(50) not null, - remote_logname varchar(50) not null, - remote_user varchar(50) not null, - request_duration smallint not null, + referer varchar(255) , + remote_host varchar(50) , + remote_logname varchar(50) , + remote_user varchar(50) , + request_duration smallint , request_line varchar(255), - request_method varchar(6) not null, - request_protocol varchar(10) not null, + request_method varchar(6) , + request_protocol varchar(10) , request_time char(28), - request_uri varchar(50) not null, + request_uri varchar(50) , server_port smallint unsigned, ssl_cipher varchar(25), ssl_keysize smallint unsigned, ssl_maxkeysize smallint unsigned, - status smallint not null, - time_stamp int unsigned not null, - virtual_host varchar(50) not null + status smallint , + time_stamp int unsigned , + virtual_host varchar(50) ) diff --git a/mod_log_sql.c b/mod_log_sql.c index 25a5013..84c6115 100644 --- a/mod_log_sql.c +++ b/mod_log_sql.c @@ -1,4 +1,4 @@ -/* $Id: mod_log_sql.c,v 1.11 2002/04/23 17:26:15 helios Exp $ */ +/* $Id: mod_log_sql.c,v 1.12 2002/05/14 21:47:15 helios Exp $ */ /* --------* * DEFINES * @@ -20,12 +20,12 @@ * INCLUDES * * ---------*/ #include -#include #include #include "httpd.h" #include "http_config.h" #include "http_log.h" #include "http_core.h" +#include "mysql.h" #if MODULE_MAGIC_NUMBER >= 19980324 /* M_M_N is defined in /usr/local/Apache/include/ap_mmn.h, 19990320 as of this writing. */ #include "ap_compat.h" @@ -55,7 +55,7 @@ char *db_name = NULL; char *db_host = NULL; char *db_user = NULL; char *db_pwd = NULL; -char *socket_file = "/var/lib/mysql/mysql.sock"; +char *socket_file = "/tmp/mysql.sock"; typedef const char *(*item_key_func) (request_rec *, char *); @@ -67,10 +67,12 @@ typedef const char *(*item_key_func) (request_rec *, char *); */ typedef struct { int table_made; - char *transfer_table_name; array_header *referer_ignore_list; array_header *transfer_ignore_list; array_header *remhost_ignore_list; + array_header *notes_list; + char *notes_table_name; + char *transfer_table_name; char *transfer_log_format; char *preserve_file; char *cookie_name; @@ -322,64 +324,66 @@ static const char *extract_cookie(request_rec *r, char *a) log_mysql_state *cls = get_module_config(r->server->module_config, &mysql_log_module); - #ifdef DEBUG - ap_log_error(APLOG_MARK,DEBUGLEVEL,r->server,"watching for cookie '%s'", cls->cookie_name); - #endif - - /* Fetch out the cookie header */ - cookiestr = (char *)table_get(r->headers_in, "cookie2"); - if (cookiestr != NULL) { + if (cls->cookie_name != NULL) { #ifdef DEBUG - ap_log_error(APLOG_MARK,DEBUGLEVEL,r->server,"Cookie2: [%s]", cookiestr); + ap_log_error(APLOG_MARK,DEBUGLEVEL,r->server,"watching for cookie '%s'", cls->cookie_name); #endif - /* Does the cookie string contain one with our name? */ - isvalid = strstr(cookiestr, cls->cookie_name); - if (isvalid != NULL) { - /* Move past the cookie name and equal sign */ - isvalid += strlen(cls->cookie_name) + 1; - /* Duplicate it into the pool */ - cookiebuf = ap_pstrdup(r->pool, isvalid); - /* Segregate just this cookie out of the string - * with a terminating nul at the first semicolon */ - cookieend = strchr(cookiebuf, ';'); - if (cookieend != NULL) - *cookieend = '\0'; - return cookiebuf; - } - } - - cookiestr = (char *)table_get(r->headers_in, "cookie"); - if (cookiestr != NULL) { - #ifdef DEBUG - ap_log_error(APLOG_MARK,DEBUGLEVEL,r->server,"Cookie: [%s]", cookiestr); - #endif - isvalid = strstr(cookiestr, cls->cookie_name); - if (isvalid != NULL) { - isvalid += strlen(cls->cookie_name) + 1; - cookiebuf = ap_pstrdup(r->pool, isvalid); - cookieend = strchr(cookiebuf, ';'); - if (cookieend != NULL) - *cookieend = '\0'; - return cookiebuf; + + /* Fetch out the cookie header */ + cookiestr = (char *)table_get(r->headers_in, "cookie2"); + if (cookiestr != NULL) { + #ifdef DEBUG + ap_log_error(APLOG_MARK,DEBUGLEVEL,r->server,"Cookie2: [%s]", cookiestr); + #endif + /* Does the cookie string contain one with our name? */ + isvalid = strstr(cookiestr, cls->cookie_name); + if (isvalid != NULL) { + /* Move past the cookie name and equal sign */ + isvalid += strlen(cls->cookie_name) + 1; + /* Duplicate it into the pool */ + cookiebuf = ap_pstrdup(r->pool, isvalid); + /* Segregate just this cookie out of the string + * with a terminating nul at the first semicolon */ + cookieend = strchr(cookiebuf, ';'); + if (cookieend != NULL) + *cookieend = '\0'; + return cookiebuf; + } } - } - cookiestr = table_get(r->headers_out, "set-cookie"); - if (cookiestr != NULL) { - #ifdef DEBUG - ap_log_error(APLOG_MARK,DEBUGLEVEL,r->server,"Set-Cookie: [%s]", cookiestr); - #endif - isvalid = strstr(cookiestr, cls->cookie_name); - if (isvalid != NULL) { - isvalid += strlen(cls->cookie_name) + 1; - cookiebuf = ap_pstrdup(r->pool, isvalid); - cookieend = strchr(cookiebuf, ';'); - if (cookieend != NULL) - *cookieend = '\0'; - return cookiebuf; + cookiestr = (char *)table_get(r->headers_in, "cookie"); + if (cookiestr != NULL) { + #ifdef DEBUG + ap_log_error(APLOG_MARK,DEBUGLEVEL,r->server,"Cookie: [%s]", cookiestr); + #endif + isvalid = strstr(cookiestr, cls->cookie_name); + if (isvalid != NULL) { + isvalid += strlen(cls->cookie_name) + 1; + cookiebuf = ap_pstrdup(r->pool, isvalid); + cookieend = strchr(cookiebuf, ';'); + if (cookieend != NULL) + *cookieend = '\0'; + return cookiebuf; + } } - } + cookiestr = table_get(r->headers_out, "set-cookie"); + if (cookiestr != NULL) { + #ifdef DEBUG + ap_log_error(APLOG_MARK,DEBUGLEVEL,r->server,"Set-Cookie: [%s]", cookiestr); + #endif + isvalid = strstr(cookiestr, cls->cookie_name); + if (isvalid != NULL) { + isvalid += strlen(cls->cookie_name) + 1; + cookiebuf = ap_pstrdup(r->pool, isvalid); + cookieend = strchr(cookiebuf, ';'); + if (cookieend != NULL) + *cookieend = '\0'; + return cookiebuf; + } + } + } + return "-"; } @@ -393,12 +397,26 @@ static const char *extract_request_timestamp(request_rec *r, char *a) static const char *extract_note(request_rec *r, char *a) { - return table_get(r->notes, a); + return ap_table_get(r->notes, a); + + /*ap_table_do(extract_table, r, r->notes, NULL);*/ + } static const char *extract_env_var(request_rec *r, char *a) { - return table_get(r->subprocess_env, "HTTP_USER_AGENT"); + return ap_table_get(r->subprocess_env, a); +} + +static const char *extract_unique_id(request_rec *r, char *a) +{ + const char *tempid; + + tempid = ap_table_get(r->subprocess_env, "UNIQUE_ID"); + if (!tempid) + return "-"; + else + return tempid; } /* End declarations of various extract_ functions */ @@ -421,7 +439,8 @@ struct log_mysql_item_list { { 'H', extract_request_protocol, "request_protocol", 0, 1 }, { 'h', extract_remote_host, "remote_host", 0, 1 }, { 'i', extract_header_in, "header_in", 0, 1 }, - { 'l', extract_remote_logname, "remote_logname", 0, 1 }, + { 'I', extract_unique_id, "id", 0, 1 }, + { 'l', extract_remote_logname, "remote_logname", 0, 1 }, { 'm', extract_request_method, "request_method", 0, 1 }, { 'n', extract_note, "note", 0, 1 }, { 'o', extract_header_out, "header_out", 0, 1 }, @@ -506,6 +525,31 @@ int open_logdb_link() return 0; } +#ifdef DEBUG +static int trace(void *data, const char *key, const char *val) +{ + FILE *fp; + request_rec *r = (request_rec *)data; + + fp = pfopen(r->pool, "/tmp/trace", "a"); + + if (fp) { + fprintf(fp, "Field '%s' == '%s'\n", key, val); + } + + pfclose(r->pool, fp); + + return TRUE; +} +#endif + +const char *extract_table(void *data, const char *key, const char *val) +{ + request_rec *r = (request_rec *)data; + + return ap_pstrcat(r->pool, key, " = ", val, " ", NULL); +} + void preserve_entry(request_rec *r, const char *query) { FILE *fp; @@ -514,9 +558,10 @@ void preserve_entry(request_rec *r, const char *query) fp = pfopen(r->pool, cls->preserve_file, "a"); if (fp == NULL) ap_log_error(APLOG_MARK,ERRLEVEL,r->server,"attempted append of local offline file but failed."); - else + else { fprintf(fp,"%s;\n", query); - pfclose(r->pool, fp); + pfclose(r->pool, fp); + } } /*-----------------------------------------------------*/ @@ -629,11 +674,11 @@ const char *set_log_mysql_cookie(cmd_parms *parms, void *dummy, char *arg) const char *set_log_mysql_preserve_file(cmd_parms *parms, void *dummy, char *arg) { - char *pfile; + /* char *pfile; */ log_mysql_state *cls = get_module_config(parms->server->module_config, &mysql_log_module); - pfile = ap_pstrcat(parms->pool, "/tmp/", arg, NULL); - cls->preserve_file = pfile; + /* pfile = ap_pstrcat(parms->pool, "/tmp/", arg, NULL); */ + cls->preserve_file = arg; return NULL; } @@ -662,6 +707,17 @@ const char *set_transfer_log_mysql_table(cmd_parms *parms, void *dummy, char *ar return NULL; } +const char *set_notes_log_mysql_table(cmd_parms *parms, void *dummy, char *arg) +{ + log_mysql_state *cls = get_module_config(parms->server->module_config, &mysql_log_module); + + if (massvirtual != 0) + ap_log_error(APLOG_MARK,WARNINGLEVEL,parms->server,"do not set MySQLNotesLogTable when MySQLMassVirtualHosting is On. Ignoring."); + else + cls->notes_table_name = arg; + return NULL; +} + const char *set_mysql_transfer_log_format(cmd_parms *parms, void *dummy, char *arg) { log_mysql_state *cls = get_module_config(parms->server->module_config, &mysql_log_module); @@ -677,6 +733,7 @@ const char *set_mysql_socket_file(cmd_parms *parms, void *dummy, char *arg) return NULL; } + const char *add_referer_mysql_ignore(cmd_parms *parms, void *dummy, char *arg) { char **addme; @@ -707,6 +764,16 @@ const char *add_remhost_mysql_ignore(cmd_parms *parms, void *dummy, char *arg) return NULL; } +const char *add_mysql_note(cmd_parms *parms, void *dummy, char *arg) +{ + char **addme; + log_mysql_state *cls = get_module_config(parms->server->module_config, &mysql_log_module); + + addme = push_array(cls->notes_list); + *addme = pstrdup(cls->notes_list->pool, arg); + return NULL; +} + @@ -780,17 +847,18 @@ void *log_mysql_make_state(pool *p, server_rec *s) log_mysql_state *cls = (log_mysql_state *) ap_palloc(p, sizeof(log_mysql_state)); - cls->transfer_table_name = NULL; cls->transfer_log_format = NULL; + cls->notes_table_name = "notes"; cls->referer_ignore_list = make_array(p, 1, sizeof(char *)); cls->transfer_ignore_list = make_array(p, 1, sizeof(char *)); cls->remhost_ignore_list = make_array(p, 1, sizeof(char *)); - + cls->notes_list = make_array(p, 1, sizeof(char *)); cls->table_made = 0; cls->preserve_file = "/tmp/mysql-preserve"; + cls->cookie_name = NULL; return (void *) cls; } @@ -803,6 +871,9 @@ command_rec log_mysql_cmds[] = { {"MySQLTransferLogTable", set_transfer_log_mysql_table, NULL, RSRC_CONF, TAKE1, "The MySQL table that holds the transfer log"} , + {"MySQLNotesLogTable", set_notes_log_mysql_table, NULL, RSRC_CONF, TAKE1, + "The MySQL table that holds the notes"} + , {"MySQLTransferLogFormat", set_mysql_transfer_log_format, NULL, RSRC_CONF, TAKE1, "Instruct the module what information to log to the MySQL transfer log"} , @@ -836,6 +907,9 @@ command_rec log_mysql_cmds[] = { {"MySQLSocketFile", set_mysql_socket_file, NULL, RSRC_CONF, TAKE1, "Name of the file to employ for socket connections to MySQL"} , + {"MySQLWhichNotes", add_mysql_note, NULL, RSRC_CONF, ITERATE, + "Members of the 'notes' table that you would like to log"} + , {NULL} }; @@ -848,30 +922,38 @@ int log_mysql_transaction(request_rec *orig) { char **ptrptr, **ptrptr2; log_mysql_state *cls = get_module_config(orig->server->module_config, &mysql_log_module); - const char *str; + const char *access_query; request_rec *r; /* We handle mass virtual hosting differently. Dynamically determine the name * of the table from the virtual server's name, and flag it for creation. */ if (massvirtual == 1) { - char *base = "access_"; - char *tablename; + char *access_base = "access_"; + char *notes_base = "notes_"; + char *a_tablename; + char *n_tablename; int i; /* Find memory long enough to hold the table name + \0. */ - tablename = ap_pstrcat(orig->pool, base, ap_get_server_name(orig), NULL); + a_tablename = ap_pstrcat(orig->pool, access_base, ap_get_server_name(orig), NULL); + n_tablename = ap_pstrcat(orig->pool, notes_base, ap_get_server_name(orig), NULL); - /* Transform any dots to underscores */ - for (i = 0; i < strlen(tablename); i++) { - if (tablename[i] == '.') - tablename[i] = '_'; + /* Transform any dots or dashes to underscores */ + for (i = 0; i < strlen(a_tablename); i++) { + if ( (a_tablename[i] == '.') || (a_tablename[i] == '-') ) + a_tablename[i] = '_'; + } + for (i = 0; i < strlen(n_tablename); i++) { + if ( (n_tablename[i] == '.') || (n_tablename[i] == '-') ) + n_tablename[i] = '_'; } /* Tell this virtual server its transfer table name, and * turn on create_tables, which is implied by massvirtual. */ - cls->transfer_table_name = tablename; + cls->transfer_table_name = a_tablename; + cls->notes_table_name = n_tablename; create_tables = 1; } @@ -880,19 +962,27 @@ int log_mysql_transaction(request_rec *orig) return DECLINED; } else { const char *thehost; + const char *thenote; char *fields = "", *values = ""; + char *notesets = ""; + char *note_query = ""; + const char *unique_id; const char *formatted_item; int i, j, length; - char *createstring = NULL; + char *create_access = NULL; + char *create_notes = NULL; for (r = orig; r->next; r = r->next) { continue; } + #ifdef DEBUG + /*ap_table_do(trace, orig, orig->subprocess_env, NULL);*/ + #endif - /* The following is a stolen upsetting mess of pointers, I'm sorry + /* The following is a stolen upsetting mess of pointers, I'm sorry. * Anyone with the motiviation and/or the time should feel free - * to make this cleaner, and while at it, clean the same mess at the RefererLog part :) */ + * to make this cleaner. :) */ ptrptr2 = (char **) (cls->transfer_ignore_list->elts + (cls->transfer_ignore_list->nelts * cls->transfer_ignore_list->elt_size)); /* Go through each element of the ignore list and compare it to the @@ -960,14 +1050,52 @@ int log_mysql_transaction(request_rec *orig) } + /* + fields = pstrcat(r->pool, fields, ",note", NULL); + values = pstrcat(r->pool, values, ",'", NULL); + */ + + /* Work through the list of notes defined by MySQLNotesToLog */ + i = 0; + unique_id = extract_unique_id(r, ""); + + ptrptr2 = (char **) (cls->notes_list->elts + (cls->notes_list->nelts * cls->notes_list->elt_size)); + for (ptrptr = (char **) cls->notes_list->elts; ptrptr < ptrptr2; ptrptr = (char **) ((char *) ptrptr + cls->notes_list->elt_size)) { + /* If the specified note (*ptrptr) exists for the current request... */ + if ((thenote = ap_table_get(r->notes, *ptrptr))) { + notesets = ap_pstrcat(r->pool, notesets, + (i > 0 ? "," : ""), + "('", + unique_id, + "','", + escape_query(*ptrptr, r->pool), + "','", + escape_query(thenote, r->pool), + "')", + NULL); + i++; + } + } + note_query = ap_pstrcat(r->pool, note_query, "insert into ", cls->notes_table_name, " (id, item, val) values ", notesets, NULL); + #ifdef DEBUG + ap_log_error(APLOG_MARK,DEBUGLEVEL,orig->server,"note string: %s", note_query); + #endif + + /* + values = pstrcat(r->pool, values, "'", NULL); + */ + + + /* Is this virtual server's table flagged as made? We flag it as such in order * to avoid extra processing with each request. If it's not flagged as made, * set up the CREATE string. */ if ((cls->table_made != 1) && (create_tables != 0)) { char *createprefix = "create table if not exists "; - char *createsuffix = - " (agent varchar(255),\ + char *access_suffix = + " (id char(19),\ + agent varchar(255),\ bytes_sent int unsigned,\ child_pid smallint unsigned,\ cookie varchar(255),\ @@ -989,21 +1117,28 @@ int log_mysql_transaction(request_rec *orig) status smallint unsigned,\ time_stamp int unsigned,\ virtual_host varchar(50))"; - + + char *notes_suffix = + " (id char(19),\ + item varchar(80),\ + val varchar(80))"; + /* Find memory long enough to hold the whole CREATE string + \0 */ - createstring = ap_pstrcat(orig->pool, createprefix, cls->transfer_table_name, createsuffix, NULL); + create_access = ap_pstrcat(orig->pool, createprefix, cls->transfer_table_name, access_suffix, NULL); + create_notes = ap_pstrcat(orig->pool, createprefix, cls->notes_table_name, notes_suffix, NULL); #ifdef DEBUG - ap_log_error(APLOG_MARK,DEBUGLEVEL,orig->server,"create string: %s", createstring); + ap_log_error(APLOG_MARK,DEBUGLEVEL,orig->server,"create string: %s", create_access); + ap_log_error(APLOG_MARK,DEBUGLEVEL,orig->server,"create string: %s", create_notes); #endif } - /* Set up the actual INSERT statement and escape it. */ - str = ap_pstrcat(r->pool, "insert into ", cls->transfer_table_name, " (", fields, ") values (", values, ")", NULL); + /* Set up the actual INSERT statement */ + access_query = ap_pstrcat(r->pool, "insert into ", cls->transfer_table_name, " (", fields, ") values (", values, ")", NULL); #ifdef DEBUG - ap_log_error(APLOG_MARK,DEBUGLEVEL,r->server,"insert string: %s", str); + ap_log_error(APLOG_MARK,DEBUGLEVEL,r->server,"insert string: %s", access_query); #endif @@ -1017,7 +1152,8 @@ int log_mysql_transaction(request_rec *orig) /* Unable to re-establish a DB link, so assume that it's really * gone and send the entry to the preserve file instead. * Note that we don't keep logging the db error over and over. */ - preserve_entry(orig, str); + preserve_entry(orig, access_query); + preserve_entry(orig, note_query); return OK; } else { /* Whew, we got the DB link back */ @@ -1027,13 +1163,15 @@ int log_mysql_transaction(request_rec *orig) /* Make the table if we're supposed to */ if ((cls->table_made != 1) && (create_tables != 0)) { - mysql_query(mysql_log,createstring); + mysql_query(mysql_log, create_access); + mysql_query(mysql_log, create_notes); cls->table_made = 1; } /* Make the insert */ - safe_mysql_query(orig, str); - + safe_mysql_query(orig, access_query); + safe_mysql_query(orig, note_query); + return OK; } } -- cgit