summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG45
-rw-r--r--INSTALL45
-rw-r--r--Makefile26
-rw-r--r--README151
-rw-r--r--mod_log_sql.c674
5 files changed, 493 insertions, 448 deletions
diff --git a/CHANGELOG b/CHANGELOG
index a1cab46..a5a4c4f 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,14 +1,55 @@
1$Id: CHANGELOG,v 1.8 2002/04/08 06:35:04 helios Exp $ 1$Id: CHANGELOG,v 1.9 2002/04/21 23:01:52 helios Exp $
2 2
3 3
4TODO: 4TODO:
5* Full commenting of the code. 5* Full commenting of the code.
6* Rethink documentation flow and rewrite? 6* Rethink documentation flow and rewrite?
7* Port connection portion to other DBMS? Genericize the module? 7* Port connection portion to other DBMS? Genericize the module? Start with PostgreSQL.
8* Fully test create-table
9* Document new features
10* preserve and socket configurable in .conf
11* segfault when mvh on
8 12
9 13
10CHANGES: 14CHANGES:
11 15
161.16:
17* Moved all the user DEFINEs inside the .c file -- splitting them
18 between the C and the Makefile was getting just too cumbersome.
19* A new MySQLPreserveFile runtime config directive. In the last
20 version the name of the preserve-file was hardcoded and therefore
21 global across all Apache virtual servers. Now the user can configure
22 this on a per-virthost basis. It defaults to a hardcoded value
23 if the user does not define it.
24* A new MySQLSocketFile runtime config directive. In the last
25 version the name of the MySQL socket was hardcoded. Now the user
26 can configure this at Apache runtime. However, it is a global
27 setting (set once) just like the rest of the actual database info is.
28 It defaults ot a hardcoded value if the user does not define it.
29* A new MySQLCreateTables runtime config directive. Module can now
30 create the access table on-the-fly. Table creation takes place
31 during the virtual server's first request and is flagged after that.
32* A new MySQLMassVirtualHosting runtime config directive. This flag
33 currently only activates a single feature: each virtual server
34 gets its very own exclusive table prefixed 'access_' with the
35 server's name following. It also implies MySQLCreateTables On.
36* escape_query (was mysql_escape_log) is now called on every item
37 rather than first checking to see if it needs to be called, which
38 was probably a big waste of time. Furthermore the routine now
39 uses a native MySQL API call to do the escaping instead of doing
40 this 'manually.' It attempts to use the charset-respectful MySQL
41 call first, but falls back on a more generic call if the MySQL
42 server is unavailable (e.g. if it goes offline).
43* Open preserve file with pfopen instead of regular fopen to
44 take advantage of pool structure.
45* As forewarned, I finally got rid of the code to support separate
46 Referer and Agent logs.
47* Finally brought the make process up-to-date with the way Apache
48 likes modules to be done.
49* Cookies are now configurable on a per-virtualserver basis. Before
50 they were on a global basis.
51
52
121.15: 531.15:
13* Vastly improved error reporting is a lot clearer about lost db 54* Vastly improved error reporting is a lot clearer about lost db
14 connections, etc. Some unreachable code has been corrected. 55 connections, etc. Some unreachable code has been corrected.
diff --git a/INSTALL b/INSTALL
index 3226e89..c620963 100644
--- a/INSTALL
+++ b/INSTALL
@@ -1,4 +1,4 @@
1$Id: INSTALL,v 1.6 2002/04/02 20:19:30 helios Exp $ 1$Id: INSTALL,v 1.7 2002/04/21 23:01:52 helios Exp $
2 2
3 3
4Requirements 4Requirements
@@ -7,7 +7,7 @@ Requirements
7* I run a Red Hat 6.2 system, but these instructions should easily 7* I run a Red Hat 6.2 system, but these instructions should easily
8 adapt to any modern distro. 8 adapt to any modern distro.
9 9
10* Apache 1.2.x or higher installed. (I run 1.3.22 and it works fine). 10* Apache 1.2 or 1.3 installed. (I run 1.3.22 and it works fine).
11 You should have already successfully compiled Apache and know what 11 You should have already successfully compiled Apache and know what
12 you're doing there. In fact, you should already have any other 12 you're doing there. In fact, you should already have any other
13 modules and add-ons like mod_ssl or PHP configured and installed 13 modules and add-ons like mod_ssl or PHP configured and installed
@@ -15,9 +15,9 @@ Requirements
15 15
16* The MySQL development headers. (I run MySQL-devel-3.23.44-1.i386.rpm). 16* The MySQL development headers. (I run MySQL-devel-3.23.44-1.i386.rpm).
17 17
18* MySQL configured, installed and running on either localhost or an 18* MySQL >= 3.23.15 configured, installed and running on either
19 accessible networked machine. You should already have a basic 19 localhost or an accessible networked machine. You should already
20 understanding of MySQL and how it functions. 20 have a basic understanding of MySQL and how it functions.
21 21
22* Again, basic administrative skills with Apache and MySQL. I try to 22* Again, basic administrative skills with Apache and MySQL. I try to
23 make things as easy as possible in this README, but its purpose is 23 make things as easy as possible in this README, but its purpose is
@@ -55,19 +55,15 @@ For folks interested in using this module as an Apache DSO:
55 fully explained in the Makefile. 55 fully explained in the Makefile.
56 56
573) Instruct apxs to compile and install the module as a DSO. You need 573) Instruct apxs to compile and install the module as a DSO. You need
58 to know three things before you run apxs: 58 to know two things before you run apxs:
59 - The location of the apxs binary, find using 'locate apxs' 59 - The location of the apxs binary, find using 'locate apxs'
60 - The location of your MySQL libraries, find using 'locate libmysqlclient' 60 - The location of your MySQL libraries, find using 'locate libmysqlclient'
61 - The location of your mysql.sock socket file. If your MySQL is running on
62 a different machine (in other words, communication is via TCP/IP and not
63 sockets), this value will be ignored BUT IT STILL MUST BE DEFINED
64 AS SOMETHING/ANYTHING FOR COMPILATION TO WORK.
65 61
66 FORMAT: 62 FORMAT:
67 # <path>/apxs -i -c -DMYSQLSOCKET='\"/path/to/mysql.sock\"' -L/path/to/mysqllibs -lmysqlclient -lz mod_log_mysql.c 63 # <path>/apxs -i -c -L/path/to/mysqllibs -lmysqlclient -lz mod_log_mysql.c
68 64
69 EXAMPLE: 65 EXAMPLE:
70 # /usr/sbin/apxs -i -c -DMYSQLSOCKET='\"/var/lib/mysql/mysql.sock\"' -L/usr/lib/mysql -lmysqlclient -lz mod_log_mysql.c 66 # /usr/sbin/apxs -i -c -L/usr/lib/mysql -lmysqlclient -lz mod_log_mysql.c
71 67
72 You should see something like this: 68 You should see something like this:
73 69
@@ -106,8 +102,9 @@ Installation (as a static module compiled into httpd)
106 # tar zxf mod_log_mysql.tar.gz -C /usr/local/src 102 # tar zxf mod_log_mysql.tar.gz -C /usr/local/src
107 # cd /usr/local/src/mod_log_mysql 103 # cd /usr/local/src/mod_log_mysql
108 104
1092) Edit Makefile and make any adjustments for your system. These are 1052) Examine the DEFINEs at the top of mod_log_mysql.c and alter any that
110 fully explained in the Makefile. 106 you choose. Edit Makefile and make any adjustments for your system.
107 These are fully explained in the Makefile.
111 108
1123) # make all 1093) # make all
113 (You should receive NO warnings or errors of any kind. 110 (You should receive NO warnings or errors of any kind.
@@ -128,8 +125,8 @@ Installation (as a static module compiled into httpd)
128 * Append the following string to the EXTRA_LIBS= line. (/usr/lib/mysql is where your libmysqlclient.a file lives): 125 * Append the following string to the EXTRA_LIBS= line. (/usr/lib/mysql is where your libmysqlclient.a file lives):
129 -L/usr/lib/mysql -lmysqlclient -lm -lz 126 -L/usr/lib/mysql -lmysqlclient -lm -lz
130 127
131 * Add this line at the end of the file: 128 * Find the mod_log_config.o line, and add this line immediately after it:
132 Module mysql_log_module mod_log_mysql.o 129 AddModule modules/sql/mod_log_mysql.o
133 130
134 6b) # cp Configuration.apaci Configuration 131 6b) # cp Configuration.apaci Configuration
135 132
@@ -196,7 +193,10 @@ Installation (as a static module compiled into httpd)
196 AddModule mod_log_mysql.c 193 AddModule mod_log_mysql.c
197 194
198 195
19910) Create a database and table to hold the new log data. I log the 19610) If you compiled mod_log_mysql with the ability to make its own tables
197 then you can skip this step. Otherwise you need to do it by hand:
198
199 Create a database and table to hold the new log data. I log the
200 same data as the regular "combined log" plus a little extra information 200 same data as the regular "combined log" plus a little extra information
201 that can be useful. 201 that can be useful.
202 202
@@ -218,9 +218,14 @@ Installation (as a static module compiled into httpd)
218 218
21911) Create a specific MySQL userid that httpd will use to authenticate 21911) Create a specific MySQL userid that httpd will use to authenticate
220 and enter data. This userid need not be an actual Unix user. It 220 and enter data. This userid need not be an actual Unix user. It
221 is a userid internal to MySQL with specific privileges. To create a 221 is a userid internal to MySQL with specific privileges.
222 user called "loguser" with the password "l0gger" with only the 222
223 capability of INSERT to "access_log": 223 mysql> grant insert,create on apache.* to loguser@my.apachemachine.com identified by 'l0gger';
224
225 Security is a very real concern. mod_log_mysql by default is
226 set up to create the SQL tables it needs. If you have deactivated
227 this capability, then create a user called "loguser" with the password
228 "l0gger" with only the capability of INSERT to "access_log":
224 229
225 mysql> grant insert on apache.access_log to loguser@my.apachemachine.com identified by 'l0gger'; 230 mysql> grant insert on apache.access_log to loguser@my.apachemachine.com identified by 'l0gger';
226 231
diff --git a/Makefile b/Makefile
index be6f06c..6c3c98f 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,5 @@
1# $Id: Makefile,v 1.8 2002/04/08 06:37:14 helios Exp $ 1# $Id: Makefile,v 1.9 2002/04/21 23:01:52 helios Exp $
2MLMVERS = 1.15 2MLMVERS = 1.16
3 3
4# Where you unpacked your Apache tarball -- the source. 4# Where you unpacked your Apache tarball -- the source.
5APACHESOURCE = /usr/local/src/apache_1.3.22 5APACHESOURCE = /usr/local/src/apache_1.3.22
@@ -7,18 +7,9 @@ APACHESOURCE = /usr/local/src/apache_1.3.22
7# Where Apache [got|will get] installed 7# Where Apache [got|will get] installed
8APACHEINST = /usr/local/Apache 8APACHEINST = /usr/local/Apache
9 9
10# Use the first DEFS line if you want mod_log_mysql to be able to log SSL 10# Set the WANT_SSL_LOGGING define in mod_log_mysql.c if you want to log SSL
11# variables like keysize or cipher. Use the second one if you don't use SSL 11# info, or #undef it if you don't. Then use the first CFLAGS if you *do*
12# or don't care to log it. 12# WANT_SSL_LOGGING, and confirm the paths.
13#
14# If your MySQL db is running on the same machine as Apache, modify the
15# MYSQLSOCKET path to point to your MySQL socket. This define has no effect
16# if your MySQL machine is a networked (TCP/IP) machine.
17
18DEFS = -DMYSQLSOCKET="\"/var/lib/mysql/mysql.sock\"" -DWANT_SSL_LOGGING
19#DEFS = -DMYSQLSOCKET="\"/var/lib/mysql/mysql.sock\""
20
21# Use the first CFLAGS if you *do* WANT_SSL_LOGGING, and confirm the paths.
22# 13#
23# Modify "/usr/local/ssl/include" to where YOUR openssl/*.h files are, 14# Modify "/usr/local/ssl/include" to where YOUR openssl/*.h files are,
24# Modify "/usr/include/db1" to where YOUR ndbm.h can be found, 15# Modify "/usr/include/db1" to where YOUR ndbm.h can be found,
@@ -53,10 +44,13 @@ INSTALL = /usr/bin/install -m 664
53all: mod_log_mysql.o 44all: mod_log_mysql.o
54 45
55mod_log_mysql.o: mod_log_mysql.c Makefile 46mod_log_mysql.o: mod_log_mysql.c Makefile
56 $(CC) ${CFLAGS} ${DEFS} -c mod_log_mysql.c 47 $(CC) ${CFLAGS} -c mod_log_mysql.c
57 48
58install: all 49install: all
59 $(INSTALL) mod_log_mysql.o ${APACHESOURCE}/src/mod_log_mysql.o 50 $(INSTALL) -d -m 755 ${APACHESOURCE}/src/modules/sql
51 $(INSTALL) mod_log_mysql.c ${APACHESOURCE}/src/modules/sql/mod_log_mysql.c
52 $(INSTALL) Makefile ${APACHESOURCE}/src/modules/sql/Makefile
53 $(INSTALL) mod_log_mysql.o ${APACHESOURCE}/src/modules/sql/mod_log_mysql.o
60 54
61distro: all 55distro: all
62 cp -f INSTALL ${APACHEINST}/html/mod_log_mysql/ 56 cp -f INSTALL ${APACHEINST}/html/mod_log_mysql/
diff --git a/README b/README
index 977080f..7bea822 100644
--- a/README
+++ b/README
@@ -1,4 +1,4 @@
1$Id: README,v 1.4 2002/04/08 07:06:20 helios Exp $ 1$Id: README,v 1.5 2002/04/21 23:01:53 helios Exp $
2 2
3 3
4Homepage 4Homepage
@@ -13,35 +13,25 @@ Approach
13In order to save speed and overhead, links are kept alive in between 13In order to save speed and overhead, links are kept alive in between
14queries. This module uses one SQL link per httpd process. Among other 14queries. This module uses one SQL link per httpd process. Among other
15things, this means that this module supports logging into only one 15things, this means that this module supports logging into only one
16MySQL server, and for now, also, only one SQL database (although the 16MySQL server, and for now, also, only one SQL database.
17latter limitation can be relatively easily removed).
18
19Different data can be sent to different tables. i.e., it's possible to
20define one table for TransferLog, one for RefererLog, and a 3rd for
21AgentLog. [ Note: this is now deprecated behavior. Please consider
22logging Agent and Referer to the same table as your transfers. ]
23 17
24Virtual hosts are supported in the same manner they are in the regular 18Virtual hosts are supported in the same manner they are in the regular
25logging modules. If you specify a different table for a virtual 19logging modules. If you specify a different table for a virtual
26host it will be used, otherwise the 'general' would be used. Note: 20host it will be used, otherwise the 'general' would be used.
27since all 3 types of logs are implemented within the same module, if 21
28you specify an overriding table for a virtual host for one type of log, 22SQL links are opened by each child process when it is born. Error reporting
29it'll ignore any previous 'general' defaults (see the example in the 23is robust throughout and will let you know about database issues
30end). 24in the standard Apache error-log for the server or virtual server.
31 25
32SQL links are opened on demand (i.e., the first time each httpd needs 26A robust "preserve" capability has now been implemented as well. This
33to log something to SQL, the link is opened). In case the SQL server 27permits the module to preserve any failed INSERT commands to a local
34is down when trying to connect to it, the module remains silent and 28file on its machine. In any situation that the database is unavailable --
35logs no error (I didn't want thousands of error messages in the 29e.g. the network fails, you reboot the machine, etc. -- mod_log_mysql
36logfile). In case the SQL link is broken ("mysql server has gone 30will note this in the error log and begin appending its log entries to
37away") a proper error message is kept to the error log (textual :), and 31the preserve file. At the time that your MySQL server returns to service,
38the module tries to reestablish the concact (and reports whether it 32each of these preserve files is easily imported because it is stored in SQL:
39succeeded or not in the error log). If the link cannot be 33
40reestablished, the module will, again, remain silent. Technical note: 34 # mysql -uadminuser -p mydbname < /tmp/mysql-preserve
41The SQL link is registered using apache's pool mechanism, so SQL links
42are properly closed on any normal shutdown, kill -HUP or kill -TERM.
43This also means that if you restart the MySQL daemon for any reason you
44should restart Apache.
45 35
46 36
47 37
@@ -63,85 +53,22 @@ What gets logged by default?
63 53
64All the data that would be contained in the "Combined Log Format" 54All the data that would be contained in the "Combined Log Format"
65is logged by default, plus a little extra. Your best bet is to 55is logged by default, plus a little extra. Your best bet is to
66accept this default and employ the enclosed access_log.sql to 56begin by accepting this default, then later customize the log
67format your table. Customize your logging format after you've 57configuration based on your needs.
68had a chance to experiment with the default first. 58
69 59The online documentation of the run-time directives includes a full
70If you just want to log enough data to be able to reconstruct 60explanation of what you can log, including examples.
71a Combined Log Format log, log these:
72
73+------------------+------------------+
74| Field | Type |
75+------------------+------------------+
76| remote_host | varchar(50) |
77| remote_user | varchar(50) |
78| request_uri | varchar(50) |
79| virtual_host | varchar(50) |
80| time_stamp | int(10) unsigned |
81| status | smallint(6) |
82| bytes_sent | int(11) |
83| referer | varchar(255) |
84| agent | varchar(255) |
85| request_method | varchar(6) |
86| request_protocol | varchar(10) |
87+------------------+------------------+
88
89remote_host: corresponds to the Apache %h directive. Contains the remote
90 hostname or IP of the machine accessing your server.
91 Example: si4002.inktomi.com
92
93remote_user: corresponds to the Apache %u directive. Contains the
94 userid of people who have authenticated to your server, if applicable.
95 Example: freddy
96
97request_uri: corresponds to the Apache %U directive. Contains the
98 URL path requested, excluding any query string. This is different than
99 the %r information you might be used to seeing:
100
101 %r: GET /cgi-bin/neomail.pl?sessionid=freddy-session-0.742143231719&sort=date_rev HTTP/1.1
102 %U: /cgi-bin/neomail.pl
103
104 We log %U because it contains the real meat of the information that is
105 needed for log analysis, and saves the database a LOT of wasted growth
106 on unneeded bytes.
107
108virtual_host: contains the VirtualHost that is making the log entry. This
109 allows you to log multiple VirtualHosts to a single MySQL database and
110 yet still be able to extract them for separate analysis.
111 Example: www.grubbybaby.com
112
113time_stamp: contains the time that the request was logged. Please see
114 "Notes" below to get a better understanding of this.
115 Example: 1014249231
116
117status: corresponds to the Apache %t directive. Contains the HTTP status
118 of the request.
119 Example: 404
120
121bytes_sent: corresponds to the Apache %b directive. Contains the number
122 of bytes sent to service the request.
123 Example: 23123
124
125referer: corresponds to the Apache "%{Referer}i" directive. Contains the
126 referring HTML page's URL, if applicable.
127 Example: http://www.foobar.com/links.html
128
129agent: corresponds to the Apache "%{User-Agent}" directive. Contains the
130 broswer type (user agent) of the software that made the request.
131 Example: Mozilla/3.0 (Slurp/si; slurp@inktomi.com; http://www.inktomi.com/slurp.html)
132
133request_method: corresponds to the Apache %m directive. Contains the type
134 of request sent: GET, PUT, etc.
135 Example: GET
136
137request_protocol: corresponds to the Apache %H directive. Contains the HTTP
138 protocol that was used.
139 Example: HTTP/1.1
140 61
141 62
142Notes 63Notes
143----- 64-----
144 65
66* You will customarily set most of your run-time configuration directives
67 on a per-virtualserver basis, with only MySQLMassVirtualHosting,
68 MySQLLoginInfo and MySQLDatabase 'outside' in the main server config.
69 Any directives other than those in the main config do NOT get inherited
70 by the virutal servers.
71
145* The 'time_stamp' field is stored in an UNSIGNED INTEGER column, in the 72* The 'time_stamp' field is stored in an UNSIGNED INTEGER column, in the
146 standard unix "seconds since 1/1/1970 12:00:00" format. This is 73 standard unix "seconds since 1/1/1970 12:00:00" format. This is
147 superior to storing the access time as a string due to size 74 superior to storing the access time as a string due to size
@@ -161,20 +88,15 @@ Notes
161 Log Format compliant. You can then feed this to your favorite web 88 Log Format compliant. You can then feed this to your favorite web
162 log analysis tool. 89 log analysis tool.
163 90
164
165* The table's string values can be CHAR or VARCHAR, at a length of your choice. 91* The table's string values can be CHAR or VARCHAR, at a length of your choice.
166 VARCHAR is superior because it truncates long strings; CHAR types are 92 VARCHAR is superior because it truncates long strings; CHAR types are
167 fixed-length and will be padded with spaces. Just like the 93 fixed-length and will be padded with spaces. Just like the
168 time_stamp described above, that kind of space waste will add up over 94 time_stamp described above, that kind of space waste will add up over
169 thousands of records. 95 thousands of records.
170 96
171 97* Be careful not to go overboard setting fields to NOT NULL. If a field is
172* Most fields should probably be set to NOT NULL. The only ones that 98 marked NOT NULL then it must contain data in the INSERT or the INSERT
173 shouldn't are extra fields that you don't intend the logging module 99 will fail.
174 to update. (You can have other fields in the logging tables if you'd
175 like, but if they're set to NOT NULL then the logging module won't be
176 able to insert rows to these tables.)
177
178 100
179* Apache normally logs numeric fields with a '-' character to mean "not 101* Apache normally logs numeric fields with a '-' character to mean "not
180 applicable," e.g. bytes_sent on a request with a 304 response code. 102 applicable," e.g. bytes_sent on a request with a 304 response code.
@@ -183,15 +105,6 @@ Notes
183 makes perfect sense anyway. 105 makes perfect sense anyway.
184 106
185 107
186* If your database goes offline and Apache cannot log to it, mod_log_mysql
187 intelligently preserves any queries to a local text file. (By
188 default the file is /tmp/mysql-preserve.) This will allow you to not
189 miss those entries; when you bring your database back online it is a
190 simple matter to import the contents of this preserve file. To do
191 this simply copy the file to your MySQL server and run an import
192 as follows:
193 # mysql -uadminuser -p mydbname < mysql-preserve
194
195 108
196Author / Maintainer 109Author / Maintainer
197------------------- 110-------------------
@@ -202,7 +115,7 @@ text modules, so all that credit goes to the Apache Server group.
202The MySQL routines and directives were added by Zeev Suraski 115The MySQL routines and directives were added by Zeev Suraski
203<bourbon@netvision.net.il>. 116<bourbon@netvision.net.il>.
204 117
205Changes from 1.06 on and the new documentation were added by 118All changes from 1.06+ and the new documentation were added by
206Chris Powell <chris@grubbybaby.com>. It seems that the module had fallen 119Chris Powell <chris@grubbybaby.com>. It seems that the module had fallen
207into the "unmaintained" category -- it hadn't been updated since 1998 -- 120into the "unmaintained" category -- it hadn't been updated since 1998 --
208so Chris adopted it as the new maintainer. 121so Chris adopted it as the new maintainer.
diff --git a/mod_log_sql.c b/mod_log_sql.c
index 16deada..02b0dd7 100644
--- a/mod_log_sql.c
+++ b/mod_log_sql.c
@@ -1,52 +1,72 @@
1/* $Id: mod_log_sql.c,v 1.8 2002/04/08 07:06:20 helios Exp $ */ 1/* $Id: mod_log_sql.c,v 1.9 2002/04/21 23:01:53 helios Exp $ */
2 2
3/* --------*
4 * DEFINES *
5 * --------*/
3 6
4/* DEFINES */ 7/* The enduser probably won't modify these */
5#define MYSQL_ERROR(mysql) ((mysql)?(mysql_error(mysql)):"MySQL server has gone away") 8#define MYSQL_ERROR(mysql) ((mysql)?(mysql_error(mysql)):"MySQL server has gone away")
6#define ERRLEVEL APLOG_ERR|APLOG_NOERRNO 9#define ERRLEVEL APLOG_ERR|APLOG_NOERRNO
7#define WARNINGLEVEL APLOG_WARNING|APLOG_NOERRNO 10#define WARNINGLEVEL APLOG_WARNING|APLOG_NOERRNO
8#define NOTICELEVEL APLOG_NOTICE|APLOG_NOERRNO 11#define NOTICELEVEL APLOG_NOTICE|APLOG_NOERRNO
9#define DEBUGLEVEL APLOG_INFO|APLOG_NOERRNO 12#define DEBUGLEVEL APLOG_DEBUG|APLOG_NOERRNO
10#define PRESERVEFILE "/tmp/mysql-preserve"
11/* (MYSQLSOCKET, DEBUG and WANT_SSL_LOGGING are defined in the Makefile DEFS line.) */
12 13
14/* The enduser may wish to modify these */
15#define WANT_SSL_LOGGING
16#undef DEBUG
13 17
14 18
15/* INCLUDES */ 19/* ---------*
20 * INCLUDES *
21 * ---------*/
16#include <time.h> 22#include <time.h>
17#include <mysql/mysql.h> 23#include <mysql/mysql.h>
18#include <stdio.h> 24#include <stdio.h>
19
20#include "httpd.h" 25#include "httpd.h"
21#include "http_config.h" 26#include "http_config.h"
22#include "http_log.h" 27#include "http_log.h"
23#include "http_core.h" 28#include "http_core.h"
24 29
25/* M_M_N is defined in /usr/local/Apache/include/ap_mmn.h, 19990320 as of this writing. */ 30#if MODULE_MAGIC_NUMBER >= 19980324 /* M_M_N is defined in /usr/local/Apache/include/ap_mmn.h, 19990320 as of this writing. */
26#if MODULE_MAGIC_NUMBER >= 19980324 /* 1.3b6 or later */
27 #include "ap_compat.h" 31 #include "ap_compat.h"
28#endif 32#endif
29 33
30#ifdef WANT_SSL_LOGGING /* Defined in Makefile */ 34#ifdef WANT_SSL_LOGGING
31 #include "mod_ssl.h" 35 #include "mod_ssl.h"
32#endif 36#endif
33 37
34 38
39/* -------------*
40 * DECLARATIONS *
41 * -------------*/
35 42
36/* DECLARATIONS */ 43/* Declare ourselves so the configuration routines can find and know us. */
37module mysql_log_module; 44module mysql_log_module;
38 45
46/* The contents of these are known 'Apache wide' and are not variable
47 * on a per-virtual-server basis. Every virtual server 'knows' the
48 * same versions of these variables.
49 */
39MYSQL sql_server, *mysql_log = NULL; 50MYSQL sql_server, *mysql_log = NULL;
40 51
52int massvirtual = 0;
41char *db_name = NULL; 53char *db_name = NULL;
42char *db_host = NULL; 54char *db_host = NULL;
43char *db_user = NULL; 55char *db_user = NULL;
44char *db_pwd = NULL; 56char *db_pwd = NULL;
45char *cookie_name = NULL; 57char *socket_file = "/var/lib/mysql/mysql.sock";
46 58
47typedef const char *(*item_key_func) (request_rec *, char *); 59typedef const char *(*item_key_func) (request_rec *, char *);
48 60
61/* But the contents of this structure will vary by virtual server.
62 * This permits each virtual server to vary its configuration slightly
63 * for per-server customization.
64 *
65 * Each child process has its own segregated copy of this structure.
66 */
49typedef struct { 67typedef struct {
68 int create_tables;
69 int table_made;
50 char *referer_table_name; 70 char *referer_table_name;
51 char *agent_table_name; 71 char *agent_table_name;
52 char *transfer_table_name; 72 char *transfer_table_name;
@@ -54,11 +74,14 @@ typedef struct {
54 array_header *transfer_ignore_list; 74 array_header *transfer_ignore_list;
55 array_header *remhost_ignore_list; 75 array_header *remhost_ignore_list;
56 char *transfer_log_format; 76 char *transfer_log_format;
77 char *preserve_file;
78 char *cookie_name;
57} log_mysql_state; 79} log_mysql_state;
58 80
59 81
60 82/* -----------------*
61/* FUNCTIONS */ 83 * HELPER FUNCTIONS *
84 * -----------------*/
62static char *format_integer(pool *p, int i) 85static char *format_integer(pool *p, int i)
63{ 86{
64 char dummy[40]; 87 char dummy[40];
@@ -110,7 +133,7 @@ static const char *extract_ssl_keysize(request_rec *r, char *a)
110 if (ap_ctx_get(r->connection->client->ctx, "ssl") != NULL) { 133 if (ap_ctx_get(r->connection->client->ctx, "ssl") != NULL) {
111 result = ssl_var_lookup(r->pool, r->server, r->connection, r, "SSL_CIPHER_USEKEYSIZE"); 134 result = ssl_var_lookup(r->pool, r->server, r->connection, r, "SSL_CIPHER_USEKEYSIZE");
112 #ifdef DEBUG 135 #ifdef DEBUG
113 ap_log_error(APLOG_MARK,DEBUGLEVEL,r->server,"mod_log_mysql: SSL_KEYSIZE: %s", result); 136 ap_log_error(APLOG_MARK,DEBUGLEVEL,r->server,"SSL_KEYSIZE: %s", result);
114 #endif 137 #endif
115 if (result != NULL && result[0] == '\0') 138 if (result != NULL && result[0] == '\0')
116 result = NULL; 139 result = NULL;
@@ -127,7 +150,7 @@ static const char *extract_ssl_maxkeysize(request_rec *r, char *a)
127 if (ap_ctx_get(r->connection->client->ctx, "ssl") != NULL) { 150 if (ap_ctx_get(r->connection->client->ctx, "ssl") != NULL) {
128 result = ssl_var_lookup(r->pool, r->server, r->connection, r, "SSL_CIPHER_ALGKEYSIZE"); 151 result = ssl_var_lookup(r->pool, r->server, r->connection, r, "SSL_CIPHER_ALGKEYSIZE");
129 #ifdef DEBUG 152 #ifdef DEBUG
130 ap_log_error(APLOG_MARK,DEBUGLEVEL,r->server,"mod_log_mysql: SSL_ALGKEYSIZE: %s", result); 153 ap_log_error(APLOG_MARK,DEBUGLEVEL,r->server,"SSL_ALGKEYSIZE: %s", result);
131 #endif 154 #endif
132 if (result != NULL && result[0] == '\0') 155 if (result != NULL && result[0] == '\0')
133 result = NULL; 156 result = NULL;
@@ -144,7 +167,7 @@ static const char *extract_ssl_cipher(request_rec *r, char *a)
144 if (ap_ctx_get(r->connection->client->ctx, "ssl") != NULL) { 167 if (ap_ctx_get(r->connection->client->ctx, "ssl") != NULL) {
145 result = ssl_var_lookup(r->pool, r->server, r->connection, r, "SSL_CIPHER"); 168 result = ssl_var_lookup(r->pool, r->server, r->connection, r, "SSL_CIPHER");
146 #ifdef DEBUG 169 #ifdef DEBUG
147 ap_log_error(APLOG_MARK,DEBUGLEVEL,r->server,"mod_log_mysql: SSL_CIPHER: %s", result); 170 ap_log_error(APLOG_MARK,DEBUGLEVEL,r->server,"SSL_CIPHER: %s", result);
148 #endif 171 #endif
149 if (result != NULL && result[0] == '\0') 172 if (result != NULL && result[0] == '\0')
150 result = NULL; 173 result = NULL;
@@ -299,15 +322,27 @@ static const char *extract_cookie(request_rec *r, char *a)
299 char *isvalid; 322 char *isvalid;
300 char *cookiebuf; 323 char *cookiebuf;
301 324
325 log_mysql_state *cls = get_module_config(r->server->module_config, &mysql_log_module);
326
327 #ifdef DEBUG
328 ap_log_error(APLOG_MARK,DEBUGLEVEL,r->server,"watching for cookie '%s'", cls->cookie_name);
329 #endif
330
331 /* Fetch out the cookie header */
302 cookiestr = (char *)table_get(r->headers_in, "cookie2"); 332 cookiestr = (char *)table_get(r->headers_in, "cookie2");
303 if (cookiestr != NULL) { 333 if (cookiestr != NULL) {
304 #ifdef DEBUG 334 #ifdef DEBUG
305 ap_log_error(APLOG_MARK,DEBUGLEVEL,r->server,"mod_log_mysql: Cookie2: [%s]", cookiestr); 335 ap_log_error(APLOG_MARK,DEBUGLEVEL,r->server,"Cookie2: [%s]", cookiestr);
306 #endif 336 #endif
307 isvalid = strstr(cookiestr, cookie_name); 337 /* Does the cookie string contain one with our name? */
338 isvalid = strstr(cookiestr, cls->cookie_name);
308 if (isvalid != NULL) { 339 if (isvalid != NULL) {
309 isvalid += strlen(cookie_name) + 1; 340 /* Move past the cookie name and equal sign */
341 isvalid += strlen(cls->cookie_name) + 1;
342 /* Duplicate it into the pool */
310 cookiebuf = ap_pstrdup(r->pool, isvalid); 343 cookiebuf = ap_pstrdup(r->pool, isvalid);
344 /* Segregate just this cookie out of the string
345 * with a terminating nul at the first semicolon */
311 cookieend = strchr(cookiebuf, ';'); 346 cookieend = strchr(cookiebuf, ';');
312 if (cookieend != NULL) 347 if (cookieend != NULL)
313 *cookieend = '\0'; 348 *cookieend = '\0';
@@ -318,11 +353,11 @@ static const char *extract_cookie(request_rec *r, char *a)
318 cookiestr = (char *)table_get(r->headers_in, "cookie"); 353 cookiestr = (char *)table_get(r->headers_in, "cookie");
319 if (cookiestr != NULL) { 354 if (cookiestr != NULL) {
320 #ifdef DEBUG 355 #ifdef DEBUG
321 ap_log_error(APLOG_MARK,DEBUGLEVEL,r->server,"mod_log_mysql: Cookie: [%s]", cookiestr); 356 ap_log_error(APLOG_MARK,DEBUGLEVEL,r->server,"Cookie: [%s]", cookiestr);
322 #endif 357 #endif
323 isvalid = strstr(cookiestr, cookie_name); 358 isvalid = strstr(cookiestr, cls->cookie_name);
324 if (isvalid != NULL) { 359 if (isvalid != NULL) {
325 isvalid += strlen(cookie_name) + 1; 360 isvalid += strlen(cls->cookie_name) + 1;
326 cookiebuf = ap_pstrdup(r->pool, isvalid); 361 cookiebuf = ap_pstrdup(r->pool, isvalid);
327 cookieend = strchr(cookiebuf, ';'); 362 cookieend = strchr(cookiebuf, ';');
328 if (cookieend != NULL) 363 if (cookieend != NULL)
@@ -334,11 +369,11 @@ static const char *extract_cookie(request_rec *r, char *a)
334 cookiestr = table_get(r->headers_out, "set-cookie"); 369 cookiestr = table_get(r->headers_out, "set-cookie");
335 if (cookiestr != NULL) { 370 if (cookiestr != NULL) {
336 #ifdef DEBUG 371 #ifdef DEBUG
337 ap_log_error(APLOG_MARK,DEBUGLEVEL,r->server,"mod_log_mysql: Set-Cookie: [%s]", cookiestr); 372 ap_log_error(APLOG_MARK,DEBUGLEVEL,r->server,"Set-Cookie: [%s]", cookiestr);
338 #endif 373 #endif
339 isvalid = strstr(cookiestr, cookie_name); 374 isvalid = strstr(cookiestr, cls->cookie_name);
340 if (isvalid != NULL) { 375 if (isvalid != NULL) {
341 isvalid += strlen(cookie_name) + 1; 376 isvalid += strlen(cls->cookie_name) + 1;
342 cookiebuf = ap_pstrdup(r->pool, isvalid); 377 cookiebuf = ap_pstrdup(r->pool, isvalid);
343 cookieend = strchr(cookiebuf, ';'); 378 cookieend = strchr(cookiebuf, ';');
344 if (cookieend != NULL) 379 if (cookieend != NULL)
@@ -350,23 +385,6 @@ static const char *extract_cookie(request_rec *r, char *a)
350 return "-"; 385 return "-";
351} 386}
352 387
353/*
354static const char *extract_forwarded(request_rec *r, char *a)
355{
356 return table_get(r->subprocess_env, "HTTP_FORWARDED");
357}
358
359static const char *extract_via(request_rec *r, char *a)
360{
361 return table_get(r->subprocess_env, "HTTP_VIA");
362}
363
364static const char *extract_forwarded_for(request_rec *r, char *a)
365{
366 return table_get(r->subprocess_env, "HTTP_X_FORWARDED_FOR");
367}
368*/
369
370static const char *extract_request_timestamp(request_rec *r, char *a) 388static const char *extract_request_timestamp(request_rec *r, char *a)
371{ 389{
372 char tstr[32]; 390 char tstr[32];
@@ -390,11 +408,11 @@ static const char *extract_env_var(request_rec *r, char *a)
390 408
391 409
392struct log_mysql_item_list { 410struct log_mysql_item_list {
393 char ch; 411 char ch; /* its letter code */
394 item_key_func func; 412 item_key_func func; /* its extraction function */
395 const char *sql_field_name; 413 const char *sql_field_name; /* its column in SQL */
396 int want_orig_default; 414 int want_orig_default; /* if it requires the original request prior to internal redirection */
397 int string_contents; 415 int string_contents; /* if it returns a string */
398 } log_mysql_item_keys[] = { 416 } log_mysql_item_keys[] = {
399 417
400 { 'A', extract_agent, "agent", 1, 1 }, 418 { 'A', extract_agent, "agent", 1, 1 },
@@ -420,10 +438,6 @@ struct log_mysql_item_list {
420 { 'u', extract_remote_user, "remote_user", 0, 1 }, 438 { 'u', extract_remote_user, "remote_user", 0, 1 },
421 { 'U', extract_request_uri, "request_uri", 1, 1 }, 439 { 'U', extract_request_uri, "request_uri", 1, 1 },
422 { 'v', extract_virtual_host, "virtual_host", 0, 1 }, 440 { 'v', extract_virtual_host, "virtual_host", 0, 1 },
423/* { 'V', extract_via, "via", 0, 1 },
424 { 'w', extract_forwarded, "forwarded", 0, 1 },
425 { 'W', extract_forwarded_for, "forwarded_for", 0, 1 },
426 */
427 #ifdef WANT_SSL_LOGGING 441 #ifdef WANT_SSL_LOGGING
428 { 'q', extract_ssl_keysize, "ssl_keysize", 0, 1 }, 442 { 'q', extract_ssl_keysize, "ssl_keysize", 0, 1 },
429 { 'Q', extract_ssl_maxkeysize, "ssl_maxkeysize", 0, 1 }, 443 { 'Q', extract_ssl_maxkeysize, "ssl_maxkeysize", 0, 1 },
@@ -436,66 +450,54 @@ struct log_mysql_item_list {
436/* Routine to escape the 'dangerous' characters that would otherwise 450/* Routine to escape the 'dangerous' characters that would otherwise
437 * corrupt the INSERT string: ', \, and " 451 * corrupt the INSERT string: ', \, and "
438 */ 452 */
439const char *mysql_escape_log(const char *str, pool *p) 453const char *escape_query(const char *from_str, pool *p)
440{ 454{
441 register int i = 0, j = 0; 455 if (!from_str)
442 int need_to_escape = 0;
443
444 if (!str) {
445 return NULL; 456 return NULL;
446 } 457 else {
447 458 char *to_str;
448 /* First find out if we need to escape. */ 459 unsigned long length = strlen(from_str);
449 i = 0; 460 unsigned long retval;
450 while (str[i]) { 461
451 /* WAS THIS WRONG in 1.05?!? if (str[i] != '\'' || str[i] != '\\' || str[i] != '\"') { */
452 if (str[i] == '\'' || str[i] == '\\' || str[i] == '\"') {
453 need_to_escape = 1;
454 break;
455 }
456 i++;
457 }
458
459 if (need_to_escape) {
460 char *tmp_str;
461 int length = strlen(str);
462
463 /* Pre-allocate a new string that could hold twice the original, which would only 462 /* Pre-allocate a new string that could hold twice the original, which would only
464 * happen if the whole original string was 'dangerous' characters. 463 * happen if the whole original string was 'dangerous' characters.
465 */ 464 */
466 tmp_str = (char *) palloc(p, length * 2 + 1); 465 to_str = (char *) ap_palloc(p, length * 2 + 1);
467 if (!tmp_str) { 466 if (!to_str) {
468 return str; 467 return from_str;
469 } 468 }
470 469
471 /* Walk through character-by-character, escaping any dangerous characters found. */ 470 if (!mysql_log) {
472 for (i = 0, j = 0; i < length; i++, j++) { 471 /* Well, I would have liked to use the current database charset. mysql is
473 switch (str[i]) { 472 * unavailable, however, so I fall back to the slightly less respectful
474 case '\'': 473 * mysql_escape_string() function that uses the default charset.
475 case '\"': 474 */
476 case '\\': 475 retval = mysql_escape_string(to_str, from_str, length);
477 tmp_str[j] = '\\'; 476 } else {
478 j++; 477 /* MySQL is available, so I'll go ahead and respect the current charset when
479 default: 478 * I perform the escape.
480 tmp_str[j] = str[i]; 479 */
481 } 480 retval = mysql_real_escape_string(mysql_log, to_str, from_str, length);
482 } 481 }
483 tmp_str[j] = '\0'; 482
484 return tmp_str; 483 if (retval)
485 } else { 484 return to_str;
486 return str; 485 else
486 return from_str;
487 } 487 }
488} 488}
489 489
490int open_logdb_link() 490int open_logdb_link()
491{ 491{
492 /* Returns 2 if already connected, 1 if successful, 0 if unsuccessful */
493
492 if (mysql_log != NULL) { 494 if (mysql_log != NULL) {
493 return 2; 495 return 2;
494 } 496 }
495 497
496 if (db_name) { 498 if (db_name) {
497 mysql_init(&sql_server); 499 mysql_init(&sql_server);
498 mysql_log = mysql_real_connect(&sql_server, db_host, db_user, db_pwd, db_name, 0, MYSQLSOCKET, 0); 500 mysql_log = mysql_real_connect(&sql_server, db_host, db_user, db_pwd, db_name, 0, socket_file, 0);
499 501
500 if (mysql_log != NULL) { 502 if (mysql_log != NULL) {
501 return 1; 503 return 1;
@@ -509,18 +511,27 @@ int open_logdb_link()
509void preserve_entry(request_rec *r, const char *query) 511void preserve_entry(request_rec *r, const char *query)
510{ 512{
511 FILE *fp; 513 FILE *fp;
514 log_mysql_state *cls = get_module_config(r->server->module_config, &mysql_log_module);
512 515
513 fp = fopen(PRESERVEFILE, "a"); 516 fp = pfopen(r->pool, cls->preserve_file, "a");
514 if (fp == NULL) 517 if (fp == NULL)
515 ap_log_error(APLOG_MARK,ERRLEVEL,r->server,"MySQL: attempted append of local offline file but failed."); 518 ap_log_error(APLOG_MARK,ERRLEVEL,r->server,"attempted append of local offline file but failed.");
516 else 519 else
517 fprintf(fp,"%s;\n", query); 520 fprintf(fp,"%s;\n", query);
518 fclose(fp); 521 pfclose(r->pool, fp);
519} 522}
520 523
524/*-----------------------------------------------------*/
525/* safe_mysql_query: perform a database insert with */
526/* a degree of safety and error checking. */
527/* */
528/* Parms: request record, SQL insert statement */
529/* Returns: 0 (OK) on success */
530/* mysql return code on error */
531/*-----------------------------------------------------*/
521int safe_mysql_query(request_rec *r, const char *query) 532int safe_mysql_query(request_rec *r, const char *query)
522{ 533{
523 int retval = 1; 534 int retval;
524 struct timespec delay, remainder; 535 struct timespec delay, remainder;
525 int ret; 536 int ret;
526 char *str; 537 char *str;
@@ -539,19 +550,22 @@ int safe_mysql_query(request_rec *r, const char *query)
539 * at any time, hence the check. */ 550 * at any time, hence the check. */
540 if ( retval != 0 ) 551 if ( retval != 0 )
541 { 552 {
553 log_mysql_state *cls = get_module_config(r->server->module_config, &mysql_log_module);
554
542 /* Something went wrong, so start by trying to restart the db link. */ 555 /* Something went wrong, so start by trying to restart the db link. */
543 ap_log_error(APLOG_MARK,ERRLEVEL,r->server,"MySQL: attempting reconnect because API said: %s", MYSQL_ERROR(mysql_log)); 556 ap_log_error(APLOG_MARK,ERRLEVEL,r->server,"attempting reconnect because API said: %s", mysql_error(mysql_log));
544 557
545 mysql_log = NULL; 558 mysql_log = NULL;
546 open_logdb_link(); 559 open_logdb_link();
547 560
548 if (mysql_log == NULL) { /* still unable to link */ 561 if (mysql_log == NULL) { /* still unable to link */
549 signal(SIGPIPE, handler); 562 signal(SIGPIPE, handler);
550 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."); 563 ap_log_error(APLOG_MARK,ERRLEVEL,r->server,"httpd child reconnect failed, unable to reach database. SQL logging stopped until an httpd child regains a db connection.");
551 ap_log_error(APLOG_MARK,ERRLEVEL,r->server,"MySQL: log entries are being preserved in %s",PRESERVEFILE); 564 ap_log_error(APLOG_MARK,ERRLEVEL,r->server,"log entries are being preserved in %s", cls->preserve_file);
565 preserve_entry(r, query);
552 return retval; 566 return retval;
553 } else { 567 } else {
554 ap_log_error(APLOG_MARK,ERRLEVEL,r->server,"MySQL: reconnect successful."); 568 ap_log_error(APLOG_MARK,ERRLEVEL,r->server,"reconnect successful.");
555 } 569 }
556 570
557 /* Attempt a single re-try... First sleep for a tiny amount of time. */ 571 /* Attempt a single re-try... First sleep for a tiny amount of time. */
@@ -559,7 +573,7 @@ int safe_mysql_query(request_rec *r, const char *query)
559 delay.tv_nsec = 500000000; /* max is 999999999 (nine nines) */ 573 delay.tv_nsec = 500000000; /* max is 999999999 (nine nines) */
560 ret = nanosleep(&delay, &remainder); 574 ret = nanosleep(&delay, &remainder);
561 if (ret && errno != EINTR) 575 if (ret && errno != EINTR)
562 perror("nanosleep"); 576 ap_log_error(APLOG_MARK,ERRLEVEL,r->server,"nanosleep unsuccessful.");
563 577
564 /* Now make our second attempt */ 578 /* Now make our second attempt */
565 retval = mysql_query(mysql_log,query); 579 retval = mysql_query(mysql_log,query);
@@ -567,13 +581,13 @@ int safe_mysql_query(request_rec *r, const char *query)
567 /* If this one also failed, log that and append to our local offline file */ 581 /* If this one also failed, log that and append to our local offline file */
568 if ( retval != 0 ) 582 if ( retval != 0 )
569 { 583 {
570 str = pstrcat(r->pool, "MySQL delayed insert attempt failed, API said: ", MYSQL_ERROR(mysql_log), NULL); 584 str = ap_pstrcat(r->pool, "delayed insert attempt failed, API said: ", MYSQL_ERROR(mysql_log), NULL);
571 ap_log_error(APLOG_MARK,ERRLEVEL,r->server,str); 585 ap_log_error(APLOG_MARK,ERRLEVEL,r->server,str);
572 586
573 preserve_entry(r, query); 587 preserve_entry(r, query);
574 ap_log_error(APLOG_MARK,ERRLEVEL,r->server,"MySQL: entry preserved in %s",PRESERVEFILE); 588 ap_log_error(APLOG_MARK,ERRLEVEL,r->server,"entry preserved in %s", cls->preserve_file);
575 } else { 589 } else {
576 ap_log_error(APLOG_MARK,ERRLEVEL,r->server,"MySQL: insert successful after a delayed retry."); 590 ap_log_error(APLOG_MARK,ERRLEVEL,r->server,"insert successful after a delayed retry.");
577 } 591 }
578 } 592 }
579 593
@@ -584,52 +598,44 @@ int safe_mysql_query(request_rec *r, const char *query)
584} 598}
585 599
586 600
601/* ------------------------------------------------*
602 * Command handlers that are called according *
603 * to the directives found at Apache runtime. *
604 * ------------------------------------------------*/
587 605
588const char *set_referer_log_mysql_table(cmd_parms *parms, void *dummy, char *arg) 606const char *set_massvirtual(cmd_parms *parms, void *dummy, int flag)
589{ 607{
590 log_mysql_state *cls = get_module_config(parms->server->module_config, &mysql_log_module); 608 massvirtual = ( flag ? 1 : 0);
591
592 cls->referer_table_name = arg;
593 return NULL; 609 return NULL;
594} 610}
595 611
596 612const char *set_log_mysql_create(cmd_parms *parms, void *dummy, int flag)
597const char *set_agent_log_mysql_table(cmd_parms *parms, void *dummy, char *arg)
598{ 613{
599 log_mysql_state *cls = get_module_config(parms->server->module_config, &mysql_log_module); 614 log_mysql_state *cls = get_module_config(parms->server->module_config, &mysql_log_module);
600 615
601 cls->agent_table_name = arg; 616 cls->create_tables = ( flag ? 1 : 0);
602 return NULL; 617 return NULL;
603} 618}
604 619
605 620const char *set_log_mysql_db(cmd_parms *parms, void *dummy, char *arg)
606const char *set_transfer_log_mysql_table(cmd_parms *parms, void *dummy, char *arg)
607{ 621{
608 log_mysql_state *cls = get_module_config(parms->server->module_config, &mysql_log_module); 622 db_name = arg;
609
610 cls->transfer_table_name = arg;
611 return NULL; 623 return NULL;
612} 624}
613 625
614 626const char *set_log_mysql_cookie(cmd_parms *parms, void *dummy, char *arg)
615const char *set_transfer_log_format(cmd_parms *parms, void *dummy, char *arg)
616{ 627{
617 log_mysql_state *cls = get_module_config(parms->server->module_config, &mysql_log_module); 628 log_mysql_state *cls = get_module_config(parms->server->module_config, &mysql_log_module);
618 629
619 cls->transfer_log_format = arg; 630 cls->cookie_name = arg;
620 return NULL; 631 return NULL;
621} 632}
622 633
623 634const char *set_log_mysql_preserve_file(cmd_parms *parms, void *dummy, char *arg)
624const char *set_log_mysql_db(cmd_parms *parms, void *dummy, char *arg)
625{ 635{
626 db_name = arg; 636 log_mysql_state *cls = get_module_config(parms->server->module_config, &mysql_log_module);
627 return NULL;
628}
629 637
630const char *set_log_mysql_cookie(cmd_parms *parms, void *dummy, char *arg) 638 cls->preserve_file = arg;
631{
632 cookie_name = arg;
633 return NULL; 639 return NULL;
634} 640}
635 641
@@ -647,12 +653,59 @@ const char *set_log_mysql_info(cmd_parms *parms, void *dummy, char *host, char *
647 return NULL; 653 return NULL;
648} 654}
649 655
656const char *set_transfer_log_mysql_table(cmd_parms *parms, void *dummy, char *arg)
657{
658 log_mysql_state *cls = get_module_config(parms->server->module_config, &mysql_log_module);
659
660 if (massvirtual == 1) {
661 char *base = "access_";
662 char *tablename;
663 int i;
664
665 /* Find memory long enough to hold the table name + \0. */
666 /* old way: */
667 /* tablename = (char*)ap_palloc(parms->pool, (strlen(base) + strlen(parms->server->server_hostname) + 1) * sizeof(char));*/
668 /* strcpy(tablename, base);*/
669 /* strcat(tablename, parms->server->server_hostname);*/
670
671 tablename = ap_pstrcat(parms->pool, base, parms->server->server_hostname, NULL);
672
673 /* Transform any dots to underscores */
674 for (i = 0; i < strlen(tablename); i++) {
675 if (tablename[i] == '.')
676 tablename[i] = '_';
677 }
678
679 /* Tell this virtual server its transfer table name, and
680 * turn on create_tables, which is implied by massvirtual.
681 */
682 cls->transfer_table_name = tablename;
683 cls->create_tables = 1;
684 } else {
685 cls->transfer_table_name = arg;
686 }
687 return NULL;
688}
689
690const char *set_transfer_log_format(cmd_parms *parms, void *dummy, char *arg)
691{
692 log_mysql_state *cls = get_module_config(parms->server->module_config, &mysql_log_module);
693
694 cls->transfer_log_format = arg;
695 return NULL;
696}
697
698const char *set_mysql_socket_file(cmd_parms *parms, void *dummy, char *arg)
699{
700 socket_file = arg;
701
702 return NULL;
703}
650 704
651const char *add_referer_mysql_ignore(cmd_parms *parms, void *dummy, char *arg) 705const char *add_referer_mysql_ignore(cmd_parms *parms, void *dummy, char *arg)
652{ 706{
653 char **addme; 707 char **addme;
654 log_mysql_state *cls = get_module_config(parms->server->module_config, 708 log_mysql_state *cls = get_module_config(parms->server->module_config, &mysql_log_module);
655 &mysql_log_module);
656 709
657 addme = push_array(cls->referer_ignore_list); 710 addme = push_array(cls->referer_ignore_list);
658 *addme = pstrdup(cls->referer_ignore_list->pool, arg); 711 *addme = pstrdup(cls->referer_ignore_list->pool, arg);
@@ -662,8 +715,7 @@ const char *add_referer_mysql_ignore(cmd_parms *parms, void *dummy, char *arg)
662const char *add_transfer_mysql_ignore(cmd_parms *parms, void *dummy, char *arg) 715const char *add_transfer_mysql_ignore(cmd_parms *parms, void *dummy, char *arg)
663{ 716{
664 char **addme; 717 char **addme;
665 log_mysql_state *cls = get_module_config(parms->server->module_config, 718 log_mysql_state *cls = get_module_config(parms->server->module_config, &mysql_log_module);
666 &mysql_log_module);
667 719
668 addme = push_array(cls->transfer_ignore_list); 720 addme = push_array(cls->transfer_ignore_list);
669 *addme = pstrdup(cls->transfer_ignore_list->pool, arg); 721 *addme = pstrdup(cls->transfer_ignore_list->pool, arg);
@@ -673,8 +725,7 @@ const char *add_transfer_mysql_ignore(cmd_parms *parms, void *dummy, char *arg)
673const char *add_remhost_mysql_ignore(cmd_parms *parms, void *dummy, char *arg) 725const char *add_remhost_mysql_ignore(cmd_parms *parms, void *dummy, char *arg)
674{ 726{
675 char **addme; 727 char **addme;
676 log_mysql_state *cls = get_module_config(parms->server->module_config, 728 log_mysql_state *cls = get_module_config(parms->server->module_config, &mysql_log_module);
677 &mysql_log_module);
678 729
679 addme = push_array(cls->remhost_ignore_list); 730 addme = push_array(cls->remhost_ignore_list);
680 *addme = pstrdup(cls->remhost_ignore_list->pool, arg); 731 *addme = pstrdup(cls->remhost_ignore_list->pool, arg);
@@ -682,24 +733,91 @@ const char *add_remhost_mysql_ignore(cmd_parms *parms, void *dummy, char *arg)
682} 733}
683 734
684 735
685/* 736
686 * Apache-specific hooks into the module code 737
687 * that are defined in the array 'mysql_lgog_module' (at EOF) 738/*------------------------------------------------------------*
739 * Apache-specific hooks into the module code *
740 * that are defined in the array 'mysql_lgog_module' (at EOF) *
741 *------------------------------------------------------------*/
742
743
744/*
745 * This function is called during server initialisation when an heavy-weight
746 * process (such as a child) is being initialised. As with the
747 * module-initialisation function, any information that needs to be recorded
748 * must be in static cells, since there's no configuration record.
749 *
750 * There is no return value.
688 */ 751 */
752static void log_mysql_child_init(server_rec *s, pool *p)
753{
754 int retval;
755
756 retval = open_logdb_link();
757 #ifdef DEBUG
758 if (retval > 0) {
759 ap_log_error(APLOG_MARK,DEBUGLEVEL,s,"open_logdb_link successful");
760 }
761 #endif
762}
689 763
764/*
765 * This function is called when an heavy-weight process (such as a child) is
766 * being run down or destroyed. As with the child-initialisation function,
767 * any information that needs to be recorded must be in static cells, since
768 * there's no configuration record.
769 *
770 * There is no return value.
771 */
772static void log_mysql_child_exit(server_rec *s, pool *p)
773{
774 mysql_close(mysql_log);
775}
776
777
778/*
779void *log_mysql_initializer(server_rec *main_server, pool *p)
780{
781 server_rec *s;
782
783 log_mysql_state main_conf = ap_get_module_config(main_server->module_config, &mysql_log_module);
690 784
691/* Set up space for the various major configuration options */ 785 for (server_rec *s = main_server; s; s = s->next) {
786 conf = ap_get_module_config(s->module_config, &mysql_log_module);
787 if (conf->transfer_log_format == NULL && s != main_server) {
788 *conf = *main_conf;
789 }
790
791}
792 */
793
794/*
795 * This function gets called to create a per-server configuration
796 * record. It will always be called for the main server and
797 * for each virtual server that is established. Each server maintains
798 * its own state that is separate from the others' states.
799 *
800 * The return value is a pointer to the created module-specific
801 * structure.
802 */
692void *log_mysql_make_state(pool *p, server_rec *s) 803void *log_mysql_make_state(pool *p, server_rec *s)
693{ 804{
694 log_mysql_state *cls = (log_mysql_state *) palloc(p, sizeof(log_mysql_state)); 805
806 log_mysql_state *cls = (log_mysql_state *) ap_palloc(p, sizeof(log_mysql_state));
807
695 808
696 cls->referer_table_name = cls->agent_table_name = cls->transfer_table_name = ""; 809 cls->transfer_table_name = NULL;
810 cls->transfer_log_format = NULL;
697 811
698 cls->referer_ignore_list = make_array(p, 1, sizeof(char *)); 812 cls->referer_ignore_list = make_array(p, 1, sizeof(char *));
699 cls->transfer_ignore_list = make_array(p, 1, sizeof(char *)); 813 cls->transfer_ignore_list = make_array(p, 1, sizeof(char *));
700 cls->remhost_ignore_list = make_array(p, 1, sizeof(char *)); 814 cls->remhost_ignore_list = make_array(p, 1, sizeof(char *));
701 815
702 cls->transfer_log_format = ""; 816 cls->table_made = 0;
817 cls->create_tables = 0;
818
819 cls->preserve_file = "/tmp/mysql-preserve";
820
703 return (void *) cls; 821 return (void *) cls;
704} 822}
705 823
@@ -708,12 +826,6 @@ void *log_mysql_make_state(pool *p, server_rec *s)
708 * Structure: command, function called, NULL, where available, how many arguments, verbose description 826 * Structure: command, function called, NULL, where available, how many arguments, verbose description
709 */ 827 */
710command_rec log_mysql_cmds[] = { 828command_rec log_mysql_cmds[] = {
711 {"MySQLRefererLogTable", set_referer_log_mysql_table, NULL, RSRC_CONF, TAKE1,
712 "The MySQL table that holds the referer log"}
713 ,
714 {"MySQLAgentLogTable", set_agent_log_mysql_table, NULL, RSRC_CONF, TAKE1,
715 "The MySQL table that holds the agent log"}
716 ,
717 {"MySQLTransferLogTable", set_transfer_log_mysql_table, NULL, RSRC_CONF, TAKE1, 829 {"MySQLTransferLogTable", set_transfer_log_mysql_table, NULL, RSRC_CONF, TAKE1,
718 "The MySQL table that holds the transfer log"} 830 "The MySQL table that holds the transfer log"}
719 , 831 ,
@@ -738,6 +850,18 @@ command_rec log_mysql_cmds[] = {
738 {"MySQLLoginInfo", set_log_mysql_info, NULL, RSRC_CONF, TAKE3, 850 {"MySQLLoginInfo", set_log_mysql_info, NULL, RSRC_CONF, TAKE3,
739 "The MySQL host, user-id and password for logging"} 851 "The MySQL host, user-id and password for logging"}
740 , 852 ,
853 {"MySQLCreateTables", set_log_mysql_create, NULL, RSRC_CONF, FLAG,
854 "Turn on module's capability to create its SQL tables on the fly"}
855 ,
856 {"MySQLMassVirtualHosting", set_massvirtual, NULL, RSRC_CONF, FLAG,
857 "Activates option(s) useful for ISPs performing mass virutal hosting"}
858 ,
859 {"MySQLPreserveFile", set_log_mysql_preserve_file, NULL, RSRC_CONF, TAKE1,
860 "Name of the file to use for data preservation during database downtime"}
861 ,
862 {"MySQLSocketFile", set_mysql_socket_file, NULL, RSRC_CONF, TAKE1,
863 "Name of the file to employ for socket connections to MySQL"}
864 ,
741 {NULL} 865 {NULL}
742}; 866};
743 867
@@ -749,102 +873,25 @@ command_rec log_mysql_cmds[] = {
749int log_mysql_transaction(request_rec *orig) 873int log_mysql_transaction(request_rec *orig)
750{ 874{
751 char **ptrptr, **ptrptr2; 875 char **ptrptr, **ptrptr2;
752 log_mysql_state *cls = get_module_config(orig->server->module_config, 876 log_mysql_state *cls = get_module_config(orig->server->module_config, &mysql_log_module);
753 &mysql_log_module); 877 const char *str;
754 char *str;
755 const char *referer;
756 request_rec *r; 878 request_rec *r;
757 int retvalue = DECLINED;
758 int referer_needed, agent_needed, transfer_needed;
759
760 879
761 /* Are there configuration directives for these SQL logs? For each found 880 /* Are there configuration directives for these SQL logs? For each found
762 * config directive that is found, mark that type as 'needed'. 881 * config directive that is found, mark that type as 'needed'.
763 */ 882 */
764 referer_needed = ((cls->referer_table_name[0] != '\0') ? 1 : 0); 883 if ( ((cls->transfer_table_name == NULL) ? 1 : 0) ) {
765 agent_needed = ((cls->agent_table_name[0] != '\0') ? 1 : 0); 884 return DECLINED;
766 transfer_needed = ((cls->transfer_table_name[0] != '\0') ? 1 : 0); 885 } else {
767
768 if (!referer_needed && !agent_needed && !transfer_needed) {
769 return OK;
770 }
771
772
773 for (r = orig; r->next; r = r->next) {
774 continue;
775 }
776
777 /* Log the 'referer' to its own log if configured to do so. */
778 if (referer_needed) {
779 retvalue = OK;
780 referer = table_get(orig->headers_in, "Referer");
781 if (referer != NULL) {
782
783 /* The following is an upsetting mess of pointers, I'm sorry
784 * Anyone with the motiviation and/or the time should feel free
785 * to make this cleaner... */
786 ptrptr2 = (char **) (cls->referer_ignore_list->elts + (cls->referer_ignore_list->nelts * cls->referer_ignore_list->elt_size));
787
788 /* Go through each element of the ignore list and compare it to the
789 * referer_host. If we get a match, return without logging */
790 for (ptrptr = (char **) cls->referer_ignore_list->elts; ptrptr < ptrptr2; ptrptr = (char **) ((char *) ptrptr + cls->referer_ignore_list->elt_size)) {
791 if (strstr(referer, *ptrptr)) {
792 return OK;
793 }
794 }
795 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);
796
797 if (mysql_log == NULL) { /* child's mysql link not up, re-establish it */
798 open_logdb_link();
799 if (mysql_log == NULL) {
800 preserve_entry(r, str);
801 return OK;
802 } else {
803 ap_log_error(APLOG_MARK,NOTICELEVEL,orig->server,"MySQL: httpd child established database connection");
804 safe_mysql_query(orig, str);
805 }
806 } else {
807 safe_mysql_query(orig, str);
808 }
809
810 }
811 }
812
813 /* Log the 'user agent' to its own log if configured to do so. */
814 if (agent_needed) {
815 const char *agent, *str;
816
817 retvalue = OK;
818 agent = table_get(orig->headers_in, "User-Agent");
819
820 if (agent != NULL) {
821 str = pstrcat(orig->pool, "insert into ", cls->agent_table_name, "(agent,time_stamp) values ('", mysql_escape_log(agent, orig->pool), "',unix_timestamp(now()) )", NULL);
822
823 if (mysql_log == NULL) { /* child's mysql link not up, re-establish it */
824 open_logdb_link();
825 if (mysql_log == NULL) {
826 preserve_entry(r, str);
827 return OK;
828 } else {
829 ap_log_error(APLOG_MARK,NOTICELEVEL,orig->server,"MySQL: httpd child established database connection");
830 safe_mysql_query(orig, str);
831 }
832 } else {
833 safe_mysql_query(orig, str);
834 }
835 }
836 }
837
838 /* Log the transfer to its own log if configured to do so. */
839 if (transfer_needed) {
840 const char *thehost; 886 const char *thehost;
841
842 char *fields = "", *values = ""; 887 char *fields = "", *values = "";
843 const char *formatted_item; 888 const char *formatted_item;
844 int i, j, length; 889 int i, j, length;
890 char *createstring = NULL;
845 891
846 retvalue = OK; 892 for (r = orig; r->next; r = r->next) {
847 893 continue;
894 }
848 895
849 /* The following is a stolen upsetting mess of pointers, I'm sorry 896 /* The following is a stolen upsetting mess of pointers, I'm sorry
850 * Anyone with the motiviation and/or the time should feel free 897 * Anyone with the motiviation and/or the time should feel free
@@ -856,7 +903,7 @@ int log_mysql_transaction(request_rec *orig)
856 if (r->uri) { 903 if (r->uri) {
857 for (ptrptr = (char **) cls->transfer_ignore_list->elts; ptrptr < ptrptr2; ptrptr = (char **) ((char *) ptrptr + cls->transfer_ignore_list->elt_size)) { 904 for (ptrptr = (char **) cls->transfer_ignore_list->elts; ptrptr < ptrptr2; ptrptr = (char **) ((char *) ptrptr + cls->transfer_ignore_list->elt_size)) {
858 if (strstr(r->uri, *ptrptr)) { 905 if (strstr(r->uri, *ptrptr)) {
859 return retvalue; 906 return OK;
860 } 907 }
861 } 908 }
862 } 909 }
@@ -868,13 +915,13 @@ int log_mysql_transaction(request_rec *orig)
868 if (thehost) { 915 if (thehost) {
869 for (ptrptr = (char **) cls->remhost_ignore_list->elts; ptrptr < ptrptr2; ptrptr = (char **) ((char *) ptrptr + cls->remhost_ignore_list->elt_size)) { 916 for (ptrptr = (char **) cls->remhost_ignore_list->elts; ptrptr < ptrptr2; ptrptr = (char **) ((char *) ptrptr + cls->remhost_ignore_list->elt_size)) {
870 if (strstr(thehost, *ptrptr)) { 917 if (strstr(thehost, *ptrptr)) {
871 return retvalue; 918 return OK;
872 } 919 }
873 } 920 }
874 } 921 }
875 922
876 /* If not specified by the user, use the default format */ 923 /* If not specified by the user, use the default format */
877 if (cls->transfer_log_format[0] == '\0') { 924 if (cls->transfer_log_format == NULL) {
878 cls->transfer_log_format = "AbHhmRSsTUuv"; 925 cls->transfer_log_format = "AbHhmRSsTUuv";
879 } 926 }
880 length = strlen(cls->transfer_log_format); 927 length = strlen(cls->transfer_log_format);
@@ -883,8 +930,10 @@ int log_mysql_transaction(request_rec *orig)
883 * what the user has configured. */ 930 * what the user has configured. */
884 for (i = 0; i < length; i++) { 931 for (i = 0; i < length; i++) {
885 j = 0; 932 j = 0;
933
886 while (log_mysql_item_keys[j].ch) { 934 while (log_mysql_item_keys[j].ch) {
887 if (log_mysql_item_keys[j].ch == cls->transfer_log_format[i]) { 935
936 if (log_mysql_item_keys[j].ch == cls->transfer_log_format[i]) {
888 /* Yes, this key is one of the configured keys. 937 /* Yes, this key is one of the configured keys.
889 * Call the key's function and put the returned value into 'formatted_item' */ 938 * Call the key's function and put the returned value into 'formatted_item' */
890 formatted_item = log_mysql_item_keys[j].func(log_mysql_item_keys[j].want_orig_default ? orig : r, ""); 939 formatted_item = log_mysql_item_keys[j].func(log_mysql_item_keys[j].want_orig_default ? orig : r, "");
@@ -894,91 +943,134 @@ int log_mysql_transaction(request_rec *orig)
894 formatted_item = ""; 943 formatted_item = "";
895 } else if (formatted_item[0] == '-' && formatted_item[1] == '\0' && !log_mysql_item_keys[j].string_contents) { 944 } else if (formatted_item[0] == '-' && formatted_item[1] == '\0' && !log_mysql_item_keys[j].string_contents) {
896 /* If apache tried to log a '-' character for a numeric field, convert that to a zero 945 /* If apache tried to log a '-' character for a numeric field, convert that to a zero
897 * because the database expects an integer. */ 946 * because the database expects a numeral and will reject the '-' character. */
898 formatted_item = "0"; 947 formatted_item = "0";
899 } 948 }
900 949
901 /* Append the fieldname and value-to-insert to teh appropriate strings, quoting stringvals with ' as appropriate */ 950 /* Append the fieldname and value-to-insert to the appropriate strings, quoting stringvals with ' as appropriate */
902 fields = pstrcat(orig->pool, fields, (i > 0 ? "," : ""), log_mysql_item_keys[j].sql_field_name, NULL); 951 fields = pstrcat(r->pool, fields, (i > 0 ? "," : ""),
903 values = pstrcat(orig->pool, values, (i > 0 ? "," : ""), (log_mysql_item_keys[j].string_contents ? "'" : ""), mysql_escape_log(formatted_item, orig->pool), (log_mysql_item_keys[j].string_contents ? "'" : ""), NULL); 952 log_mysql_item_keys[j].sql_field_name, NULL);
953
954 values = pstrcat(r->pool, values, (i > 0 ? "," : ""),
955 (log_mysql_item_keys[j].string_contents ? "'" : ""),
956 escape_query(formatted_item, r->pool),
957 (log_mysql_item_keys[j].string_contents ? "'" : ""), NULL);
904 break; 958 break;
905 } 959 }
906 j++; 960 j++;
961
907 } 962 }
908 } 963 }
909 964
910 /* Set up the actual INSERT statement and execute it. */ 965
911 str = pstrcat(orig->pool, "insert into ", cls->transfer_table_name, " (", fields, ") values (", values, ")", NULL); 966 /* Is this virtual server's table flagged as made? We flag it as such in order
967 * to avoid extra processing with each request. If it's not flagged as made,
968 * set up the CREATE string.
969 */
970 if ((cls->table_made != 1) && (cls->create_tables != 0)) {
971 char *createprefix = "create table if not exists ";
972 char *createsuffix =
973 " (agent varchar(255),\
974 bytes_sent int unsigned,\
975 child_pid smallint unsigned,\
976 cookie varchar(255),\
977 request_file varchar(255),\
978 referer varchar(255),\
979 remote_host varchar(50),\
980 remote_logname varchar(50),\
981 remote_user varchar(50),\
982 request_duration smallint unsigned,\
983 request_line varchar(255),\
984 request_method varchar(6),\
985 request_protocol varchar(10),\
986 request_time char(28),\
987 request_uri varchar(50),\
988 server_port smallint unsigned,\
989 ssl_cipher varchar(25),\
990 ssl_keysize smallint unsigned,\
991 ssl_maxkeysize smallint unsigned,\
992 status smallint unsigned,\
993 time_stamp int unsigned,\
994 virtual_host varchar(50))";
995
996 /* Find memory long enough to hold the whole CREATE string + \0 */
997 /* old way:
998 * createstring = (char*)ap_palloc(orig->pool,(strlen(createprefix) + strlen(cls->transfer_table_name) + strlen(createsuffix) + 1) * sizeof(char));
999 * strcpy (createstring, createprefix);
1000 * strcat (createstring, cls->transfer_table_name);
1001 * strcat (createstring, createsuffix); */
1002
1003 createstring = ap_pstrcat(orig->pool, createprefix, cls->transfer_table_name, createsuffix, NULL);
1004
1005 #ifdef DEBUG
1006 ap_log_error(APLOG_MARK,DEBUGLEVEL,orig->server,"create string: %s", createstring);
1007 #endif
912 1008
1009 }
1010
1011 /* Set up the actual INSERT statement and escape it. */
1012 str = ap_pstrcat(r->pool, "insert into ", cls->transfer_table_name, " (", fields, ") values (", values, ")", NULL);
913 1013
1014 #ifdef DEBUG
1015 ap_log_error(APLOG_MARK,DEBUGLEVEL,r->server,"insert string: %s", str);
1016 #endif
1017
1018
914 /* How's our mysql link integrity? */ 1019 /* How's our mysql link integrity? */
915 if (mysql_log == NULL) { 1020 if (mysql_log == NULL) {
916 1021
917 /* Try to regain the link */ 1022 /* Make a try to establish the link */
918 open_logdb_link(); 1023 open_logdb_link();
919 1024
920 if (mysql_log == NULL) { 1025 if (mysql_log == NULL) {
921 /* Unable to re-establish a DB link, so assume that it's really 1026 /* Unable to re-establish a DB link, so assume that it's really
922 * gone and send the entry to the preserve file instead. */ 1027 * gone and send the entry to the preserve file instead.
923 preserve_entry(r, str); 1028 * Note that we don't keep logging the db error over and over. */
1029 preserve_entry(orig, str);
924 return OK; 1030 return OK;
925 } else { 1031 } else {
926 /* Whew, we got the DB link back */ 1032 /* Whew, we got the DB link back */
927 ap_log_error(APLOG_MARK,NOTICELEVEL,orig->server,"MySQL: httpd child established database connection"); 1033 ap_log_error(APLOG_MARK,NOTICELEVEL,orig->server,"httpd child established database connection");
928 safe_mysql_query(orig, str);
929 } 1034 }
930 } else {
931 /* Everything was fine */
932 safe_mysql_query(orig, str);
933 } 1035 }
1036
1037 if ((cls->table_made != 1) && (cls->create_tables != 0)) {
1038 mysql_query(mysql_log,createstring);
1039 cls->table_made = 1;
1040 }
1041
1042 /* Make the insert */
1043 safe_mysql_query(orig, str);
934 1044
1045 return OK;
935 } 1046 }
936 return retvalue;
937} 1047}
938 1048
939 1049
940/* Called on the exit of an httpd child process */
941static void log_mysql_child_exit(server_rec *s, pool *p)
942{
943 mysql_close(mysql_log);
944}
945
946/* Called on the init of an httpd child process */
947static void log_mysql_child_init(server_rec *s, pool *p)
948{
949 int retval;
950
951 retval = open_logdb_link();
952 #ifdef DEBUG
953 if (retval > 0) {
954 ap_log_error(APLOG_MARK,DEBUGLEVEL,s,"MySQL: open_logdb_link successful");
955 }
956 #endif
957}
958 1050
959 1051
960/* The configuration array that sets up the hooks into the module. */ 1052/* The configuration array that sets up the hooks into the module. */
961module mysql_log_module = { 1053module mysql_log_module = {
962 STANDARD_MODULE_STUFF, 1054 STANDARD_MODULE_STUFF,
963 NULL, /* initializer */ 1055 NULL, /* module initializer */
964 NULL, /* create per-dir config */ 1056 NULL, /* create per-dir config */
965 NULL, /* merge per-dir config */ 1057 NULL, /* merge per-dir config */
966 log_mysql_make_state, /* server config */ 1058 log_mysql_make_state, /* create server config */
967 NULL, /* merge server config */ 1059 NULL, /* merge server config */
968 log_mysql_cmds, /* command table */ 1060 log_mysql_cmds, /* config directive table */
969 NULL, /* handlers */ 1061 NULL, /* [9] content handlers */
970 NULL, /* filename translation */ 1062 NULL, /* [2] URI-to-filename translation */
971 NULL, /* check_user_id */ 1063 NULL, /* [5] check/validate user_id */
972 NULL, /* check auth */ 1064 NULL, /* [6] check authorization */
973 NULL, /* check access */ 1065 NULL, /* [4] check access by host */
974 NULL, /* type_checker */ 1066 NULL, /* [7] MIME type checker/setter */
975 NULL, /* fixups */ 1067 NULL, /* [8] fixups */
976 log_mysql_transaction, /* logger */ 1068 log_mysql_transaction, /* [10] logger */
977 NULL, /* header parser */ 1069 NULL /* [3] header parser */
978#if MODULE_MAGIC_NUMBER >= 19970728 /* 1.3-dev or later support these additionals... */ 1070#if MODULE_MAGIC_NUMBER >= 19970728 /* 1.3-dev or later support these additionals... */
979 log_mysql_child_init, /* child_init */ 1071 ,log_mysql_child_init, /* child process initializer */
980 log_mysql_child_exit, /* process exit/cleanup */ 1072 log_mysql_child_exit, /* process exit/cleanup */
981 NULL /* [#0] post read-request */ 1073 NULL /* [1] post read-request */
982#endif 1074#endif
983 1075
984}; 1076};