summaryrefslogtreecommitdiffstats
path: root/modules/loggers
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-08 19:09:22 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-08 19:09:22 +0000
commit2faa747e2303ee774a4b4aace961188e950e185a (patch)
tree604e79c7481956ce48f458e3546eaf1090b3ffff /modules/loggers
parentInitial commit. (diff)
downloadapache2-2faa747e2303ee774a4b4aace961188e950e185a.tar.xz
apache2-2faa747e2303ee774a4b4aace961188e950e185a.zip
Adding upstream version 2.4.58.upstream/2.4.58
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'modules/loggers')
-rw-r--r--modules/loggers/.indent.pro54
-rw-r--r--modules/loggers/Makefile.in3
-rw-r--r--modules/loggers/NWGNUforensic258
-rw-r--r--modules/loggers/NWGNUlogdebug258
-rw-r--r--modules/loggers/NWGNUmakefile247
-rw-r--r--modules/loggers/NWGNUmodlogio258
-rw-r--r--modules/loggers/config.m420
-rw-r--r--modules/loggers/mod_log_config.c1857
-rw-r--r--modules/loggers/mod_log_config.dep62
-rw-r--r--modules/loggers/mod_log_config.dsp111
-rw-r--r--modules/loggers/mod_log_config.exp1
-rw-r--r--modules/loggers/mod_log_config.h74
-rw-r--r--modules/loggers/mod_log_config.mak353
-rw-r--r--modules/loggers/mod_log_debug.c295
-rw-r--r--modules/loggers/mod_log_debug.dep54
-rw-r--r--modules/loggers/mod_log_debug.dsp111
-rw-r--r--modules/loggers/mod_log_debug.mak325
-rw-r--r--modules/loggers/mod_log_forensic.c289
-rw-r--r--modules/loggers/mod_log_forensic.dep53
-rw-r--r--modules/loggers/mod_log_forensic.dsp111
-rw-r--r--modules/loggers/mod_log_forensic.exp1
-rw-r--r--modules/loggers/mod_log_forensic.mak353
-rw-r--r--modules/loggers/mod_logio.c284
-rw-r--r--modules/loggers/mod_logio.dep59
-rw-r--r--modules/loggers/mod_logio.dsp111
-rw-r--r--modules/loggers/mod_logio.mak353
26 files changed, 5955 insertions, 0 deletions
diff --git a/modules/loggers/.indent.pro b/modules/loggers/.indent.pro
new file mode 100644
index 0000000..a9fbe9f
--- /dev/null
+++ b/modules/loggers/.indent.pro
@@ -0,0 +1,54 @@
+-i4 -npsl -di0 -br -nce -d0 -cli0 -npcs -nfc1
+-TBUFF
+-TFILE
+-TTRANS
+-TUINT4
+-T_trans
+-Tallow_options_t
+-Tapache_sfio
+-Tarray_header
+-Tbool_int
+-Tbuf_area
+-Tbuff_struct
+-Tbuffy
+-Tcmd_how
+-Tcmd_parms
+-Tcommand_rec
+-Tcommand_struct
+-Tconn_rec
+-Tcore_dir_config
+-Tcore_server_config
+-Tdir_maker_func
+-Tevent
+-Tglobals_s
+-Thandler_func
+-Thandler_rec
+-Tjoblist_s
+-Tlisten_rec
+-Tmerger_func
+-Tmode_t
+-Tmodule
+-Tmodule_struct
+-Tmutex
+-Tn_long
+-Tother_child_rec
+-Toverrides_t
+-Tparent_score
+-Tpid_t
+-Tpiped_log
+-Tpool
+-Trequest_rec
+-Trequire_line
+-Trlim_t
+-Tscoreboard
+-Tsemaphore
+-Tserver_addr_rec
+-Tserver_rec
+-Tserver_rec_chain
+-Tshort_score
+-Ttable
+-Ttable_entry
+-Tthread
+-Tu_wide_int
+-Tvtime_t
+-Twide_int
diff --git a/modules/loggers/Makefile.in b/modules/loggers/Makefile.in
new file mode 100644
index 0000000..167b343
--- /dev/null
+++ b/modules/loggers/Makefile.in
@@ -0,0 +1,3 @@
+
+include $(top_srcdir)/build/special.mk
+
diff --git a/modules/loggers/NWGNUforensic b/modules/loggers/NWGNUforensic
new file mode 100644
index 0000000..c55f036
--- /dev/null
+++ b/modules/loggers/NWGNUforensic
@@ -0,0 +1,258 @@
+#
+# Declare the sub-directories to be built here
+#
+
+SUBDIRS = \
+ $(EOLIST)
+
+#
+# Get the 'head' of the build environment. This includes default targets and
+# paths to tools
+#
+
+include $(AP_WORK)/build/NWGNUhead.inc
+
+#
+# build this level's files
+
+#
+# Make sure all needed macro's are defined
+#
+
+#
+# These directories will be at the beginning of the include list, followed by
+# INCDIRS
+#
+XINCDIRS += \
+ $(APR)/include \
+ $(APRUTIL)/include \
+ $(AP_WORK)/include \
+ $(AP_WORK)/modules/http \
+ $(NWOS) \
+ $(EOLIST)
+
+#
+# These flags will come after CFLAGS
+#
+XCFLAGS += \
+ $(EOLIST)
+
+#
+# These defines will come after DEFINES
+#
+XDEFINES += \
+ $(EOLIST)
+
+#
+# These flags will be added to the link.opt file
+#
+XLFLAGS += \
+ $(EOLIST)
+
+#
+# These values will be appended to the correct variables based on the value of
+# RELEASE
+#
+ifeq "$(RELEASE)" "debug"
+XINCDIRS += \
+ $(EOLIST)
+
+XCFLAGS += \
+ $(EOLIST)
+
+XDEFINES += \
+ $(EOLIST)
+
+XLFLAGS += \
+ $(EOLIST)
+endif
+
+ifeq "$(RELEASE)" "noopt"
+XINCDIRS += \
+ $(EOLIST)
+
+XCFLAGS += \
+ $(EOLIST)
+
+XDEFINES += \
+ $(EOLIST)
+
+XLFLAGS += \
+ $(EOLIST)
+endif
+
+ifeq "$(RELEASE)" "release"
+XINCDIRS += \
+ $(EOLIST)
+
+XCFLAGS += \
+ $(EOLIST)
+
+XDEFINES += \
+ $(EOLIST)
+
+XLFLAGS += \
+ $(EOLIST)
+endif
+
+#
+# These are used by the link target if an NLM is being generated
+# This is used by the link 'name' directive to name the nlm. If left blank
+# TARGET_nlm (see below) will be used.
+#
+NLM_NAME = forensic
+
+#
+# This is used by the link '-desc ' directive.
+# If left blank, NLM_NAME will be used.
+#
+NLM_DESCRIPTION = Apache $(VERSION_STR) Forensic Logging Module
+
+#
+# This is used by the '-threadname' directive. If left blank,
+# NLM_NAME Thread will be used.
+#
+NLM_THREAD_NAME = Forensic Module
+
+#
+# If this is specified, it will override VERSION value in
+# $(AP_WORK)/build/NWGNUenvironment.inc
+#
+NLM_VERSION =
+
+#
+# If this is specified, it will override the default of 64K
+#
+NLM_STACK_SIZE = 8192
+
+
+#
+# If this is specified it will be used by the link '-entry' directive
+#
+NLM_ENTRY_SYM =
+
+#
+# If this is specified it will be used by the link '-exit' directive
+#
+NLM_EXIT_SYM =
+
+#
+# If this is specified it will be used by the link '-check' directive
+#
+NLM_CHECK_SYM =
+
+#
+# If these are specified it will be used by the link '-flags' directive
+#
+NLM_FLAGS =
+
+#
+# If this is specified it will be linked in with the XDCData option in the def
+# file instead of the default of $(NWOS)/apache.xdc. XDCData can be disabled
+# by setting APACHE_UNIPROC in the environment
+#
+XDCDATA =
+
+#
+# If there is an NLM target, put it here
+#
+TARGET_nlm = \
+ $(OBJDIR)/forensic.nlm \
+ $(EOLIST)
+
+#
+# If there is an LIB target, put it here
+#
+TARGET_lib = \
+ $(EOLIST)
+
+#
+# These are the OBJ files needed to create the NLM target above.
+# Paths must all use the '/' character
+#
+FILES_nlm_objs = \
+ $(OBJDIR)/mod_log_forensic.o \
+ $(EOLIST)
+
+#
+# These are the LIB files needed to create the NLM target above.
+# These will be added as a library command in the link.opt file.
+#
+FILES_nlm_libs = \
+ $(PRELUDE) \
+ $(EOLIST)
+
+#
+# These are the modules that the above NLM target depends on to load.
+# These will be added as a module command in the link.opt file.
+#
+FILES_nlm_modules = \
+ aprlib \
+ libc \
+ $(EOLIST)
+
+#
+# If the nlm has a msg file, put it's path here
+#
+FILE_nlm_msg =
+
+#
+# If the nlm has a hlp file put it's path here
+#
+FILE_nlm_hlp =
+
+#
+# If this is specified, it will override $(NWOS)\copyright.txt.
+#
+FILE_nlm_copyright =
+
+#
+# Any additional imports go here
+#
+FILES_nlm_Ximports = \
+ @aprlib.imp \
+ @httpd.imp \
+ @libc.imp \
+ $(EOLIST)
+
+#
+# Any symbols exported to here
+#
+FILES_nlm_exports = \
+ log_forensic_module \
+ $(EOLIST)
+
+#
+# These are the OBJ files needed to create the LIB target above.
+# Paths must all use the '/' character
+#
+FILES_lib_objs = \
+ $(EOLIST)
+
+#
+# implement targets and dependancies (leave this section alone)
+#
+
+libs :: $(OBJDIR) $(TARGET_lib)
+
+nlms :: libs $(TARGET_nlm)
+
+#
+# Updated this target to create necessary directories and copy files to the
+# correct place. (See $(AP_WORK)/build/NWGNUhead.inc for examples)
+#
+install :: nlms FORCE
+ $(call COPY,$(OBJDIR)/*.nlm, $(INSTALLBASE)/modules/)
+
+#
+# Any specialized rules here
+#
+
+#
+# Include the 'tail' makefile that has targets that depend on variables defined
+# in this makefile
+#
+
+include $(APBUILD)/NWGNUtail.inc
+
+
diff --git a/modules/loggers/NWGNUlogdebug b/modules/loggers/NWGNUlogdebug
new file mode 100644
index 0000000..e92839a
--- /dev/null
+++ b/modules/loggers/NWGNUlogdebug
@@ -0,0 +1,258 @@
+#
+# Declare the sub-directories to be built here
+#
+
+SUBDIRS = \
+ $(EOLIST)
+
+#
+# Get the 'head' of the build environment. This includes default targets and
+# paths to tools
+#
+
+include $(AP_WORK)/build/NWGNUhead.inc
+
+#
+# build this level's files
+
+#
+# Make sure all needed macro's are defined
+#
+
+#
+# These directories will be at the beginning of the include list, followed by
+# INCDIRS
+#
+XINCDIRS += \
+ $(APR)/include \
+ $(APRUTIL)/include \
+ $(AP_WORK)/include \
+ $(AP_WORK)/modules/http \
+ $(NWOS) \
+ $(EOLIST)
+
+#
+# These flags will come after CFLAGS
+#
+XCFLAGS += \
+ $(EOLIST)
+
+#
+# These defines will come after DEFINES
+#
+XDEFINES += \
+ $(EOLIST)
+
+#
+# These flags will be added to the link.opt file
+#
+XLFLAGS += \
+ $(EOLIST)
+
+#
+# These values will be appended to the correct variables based on the value of
+# RELEASE
+#
+ifeq "$(RELEASE)" "debug"
+XINCDIRS += \
+ $(EOLIST)
+
+XCFLAGS += \
+ $(EOLIST)
+
+XDEFINES += \
+ $(EOLIST)
+
+XLFLAGS += \
+ $(EOLIST)
+endif
+
+ifeq "$(RELEASE)" "noopt"
+XINCDIRS += \
+ $(EOLIST)
+
+XCFLAGS += \
+ $(EOLIST)
+
+XDEFINES += \
+ $(EOLIST)
+
+XLFLAGS += \
+ $(EOLIST)
+endif
+
+ifeq "$(RELEASE)" "release"
+XINCDIRS += \
+ $(EOLIST)
+
+XCFLAGS += \
+ $(EOLIST)
+
+XDEFINES += \
+ $(EOLIST)
+
+XLFLAGS += \
+ $(EOLIST)
+endif
+
+#
+# These are used by the link target if an NLM is being generated
+# This is used by the link 'name' directive to name the nlm. If left blank
+# TARGET_nlm (see below) will be used.
+#
+NLM_NAME = logdebug
+
+#
+# This is used by the link '-desc ' directive.
+# If left blank, NLM_NAME will be used.
+#
+NLM_DESCRIPTION = Apache $(VERSION_STR) Debug Logging Module
+
+#
+# This is used by the '-threadname' directive. If left blank,
+# NLM_NAME Thread will be used.
+#
+NLM_THREAD_NAME = Logdbg Module
+
+#
+# If this is specified, it will override VERSION value in
+# $(AP_WORK)/build/NWGNUenvironment.inc
+#
+NLM_VERSION =
+
+#
+# If this is specified, it will override the default of 64K
+#
+NLM_STACK_SIZE = 8192
+
+
+#
+# If this is specified it will be used by the link '-entry' directive
+#
+NLM_ENTRY_SYM =
+
+#
+# If this is specified it will be used by the link '-exit' directive
+#
+NLM_EXIT_SYM =
+
+#
+# If this is specified it will be used by the link '-check' directive
+#
+NLM_CHECK_SYM =
+
+#
+# If these are specified it will be used by the link '-flags' directive
+#
+NLM_FLAGS =
+
+#
+# If this is specified it will be linked in with the XDCData option in the def
+# file instead of the default of $(NWOS)/apache.xdc. XDCData can be disabled
+# by setting APACHE_UNIPROC in the environment
+#
+XDCDATA =
+
+#
+# If there is an NLM target, put it here
+#
+TARGET_nlm = \
+ $(OBJDIR)/$(NLM_NAME).nlm \
+ $(EOLIST)
+
+#
+# If there is an LIB target, put it here
+#
+TARGET_lib = \
+ $(EOLIST)
+
+#
+# These are the OBJ files needed to create the NLM target above.
+# Paths must all use the '/' character
+#
+FILES_nlm_objs = \
+ $(OBJDIR)/mod_log_debug.o \
+ $(EOLIST)
+
+#
+# These are the LIB files needed to create the NLM target above.
+# These will be added as a library command in the link.opt file.
+#
+FILES_nlm_libs = \
+ $(PRELUDE) \
+ $(EOLIST)
+
+#
+# These are the modules that the above NLM target depends on to load.
+# These will be added as a module command in the link.opt file.
+#
+FILES_nlm_modules = \
+ aprlib \
+ libc \
+ $(EOLIST)
+
+#
+# If the nlm has a msg file, put it's path here
+#
+FILE_nlm_msg =
+
+#
+# If the nlm has a hlp file put it's path here
+#
+FILE_nlm_hlp =
+
+#
+# If this is specified, it will override $(NWOS)\copyright.txt.
+#
+FILE_nlm_copyright =
+
+#
+# Any additional imports go here
+#
+FILES_nlm_Ximports = \
+ @aprlib.imp \
+ @httpd.imp \
+ @libc.imp \
+ $(EOLIST)
+
+#
+# Any symbols exported to here
+#
+FILES_nlm_exports = \
+ log_debug_module \
+ $(EOLIST)
+
+#
+# These are the OBJ files needed to create the LIB target above.
+# Paths must all use the '/' character
+#
+FILES_lib_objs = \
+ $(EOLIST)
+
+#
+# implement targets and dependancies (leave this section alone)
+#
+
+libs :: $(OBJDIR) $(TARGET_lib)
+
+nlms :: libs $(TARGET_nlm)
+
+#
+# Updated this target to create necessary directories and copy files to the
+# correct place. (See $(AP_WORK)/build/NWGNUhead.inc for examples)
+#
+install :: nlms FORCE
+ $(call COPY,$(OBJDIR)/*.nlm, $(INSTALLBASE)/modules/)
+
+#
+# Any specialized rules here
+#
+
+#
+# Include the 'tail' makefile that has targets that depend on variables defined
+# in this makefile
+#
+
+include $(APBUILD)/NWGNUtail.inc
+
+
diff --git a/modules/loggers/NWGNUmakefile b/modules/loggers/NWGNUmakefile
new file mode 100644
index 0000000..6154bf1
--- /dev/null
+++ b/modules/loggers/NWGNUmakefile
@@ -0,0 +1,247 @@
+#
+# Declare the sub-directories to be built here
+#
+
+SUBDIRS = \
+ $(EOLIST)
+
+#
+# Get the 'head' of the build environment. This includes default targets and
+# paths to tools
+#
+
+include $(AP_WORK)/build/NWGNUhead.inc
+
+#
+# build this level's files
+
+#
+# Make sure all needed macro's are defined
+#
+
+#
+# These directories will be at the beginning of the include list, followed by
+# INCDIRS
+#
+XINCDIRS += \
+ $(EOLIST)
+
+#
+# These flags will come after CFLAGS
+#
+XCFLAGS += \
+ $(EOLIST)
+
+#
+# These defines will come after DEFINES
+#
+XDEFINES += \
+ $(EOLIST)
+
+#
+# These flags will be added to the link.opt file
+#
+XLFLAGS += \
+ $(EOLIST)
+
+#
+# These values will be appended to the correct variables based on the value of
+# RELEASE
+#
+ifeq "$(RELEASE)" "debug"
+XINCDIRS += \
+ $(EOLIST)
+
+XCFLAGS += \
+ $(EOLIST)
+
+XDEFINES += \
+ $(EOLIST)
+
+XLFLAGS += \
+ $(EOLIST)
+endif
+
+ifeq "$(RELEASE)" "noopt"
+XINCDIRS += \
+ $(EOLIST)
+
+XCFLAGS += \
+ $(EOLIST)
+
+XDEFINES += \
+ $(EOLIST)
+
+XLFLAGS += \
+ $(EOLIST)
+endif
+
+ifeq "$(RELEASE)" "release"
+XINCDIRS += \
+ $(EOLIST)
+
+XCFLAGS += \
+ $(EOLIST)
+
+XDEFINES += \
+ $(EOLIST)
+
+XLFLAGS += \
+ $(EOLIST)
+endif
+
+#
+# These are used by the link target if an NLM is being generated
+# This is used by the link 'name' directive to name the nlm. If left blank
+# TARGET_nlm (see below) will be used.
+#
+NLM_NAME =
+
+#
+# This is used by the link '-desc ' directive.
+# If left blank, NLM_NAME will be used.
+#
+NLM_DESCRIPTION =
+
+#
+# This is used by the '-threadname' directive. If left blank,
+# NLM_NAME Thread will be used.
+#
+NLM_THREAD_NAME =
+
+#
+# If this is specified, it will override VERSION value in
+# $(AP_WORK)/build/NWGNUenvironment.inc
+#
+NLM_VERSION =
+
+#
+# If this is specified, it will override the default of 64K
+#
+NLM_STACK_SIZE =
+
+
+#
+# If this is specified it will be used by the link '-entry' directive
+#
+NLM_ENTRY_SYM =
+
+#
+# If this is specified it will be used by the link '-exit' directive
+#
+NLM_EXIT_SYM =
+
+#
+# If this is specified it will be used by the link '-check' directive
+#
+NLM_CHECK_SYM =
+
+#
+# If these are specified it will be used by the link '-flags' directive
+#
+NLM_FLAGS =
+
+#
+# If this is specified it will be linked in with the XDCData option in the def
+# file instead of the default of $(NWOS)/apache.xdc. XDCData can be disabled
+# by setting APACHE_UNIPROC in the environment
+#
+XDCDATA =
+
+#
+# If there is an NLM target, put it here
+#
+TARGET_nlm = \
+ $(OBJDIR)/modlogio.nlm \
+ $(OBJDIR)/forensic.nlm \
+ $(OBJDIR)/logdebug.nlm \
+ $(EOLIST)
+
+#
+# If there is an LIB target, put it here
+#
+TARGET_lib = \
+ $(EOLIST)
+
+#
+# These are the OBJ files needed to create the NLM target above.
+# Paths must all use the '/' character
+#
+FILES_nlm_objs = \
+ $(EOLIST)
+
+#
+# These are the LIB files needed to create the NLM target above.
+# These will be added as a library command in the link.opt file.
+#
+FILES_nlm_libs = \
+ $(EOLIST)
+
+#
+# These are the modules that the above NLM target depends on to load.
+# These will be added as a module command in the link.opt file.
+#
+FILES_nlm_modules = \
+ $(EOLIST)
+
+#
+# If the nlm has a msg file, put it's path here
+#
+FILE_nlm_msg =
+
+#
+# If the nlm has a hlp file put it's path here
+#
+FILE_nlm_hlp =
+
+#
+# If this is specified, it will override $(NWOS)\copyright.txt.
+#
+FILE_nlm_copyright =
+
+#
+# Any additional imports go here
+#
+FILES_nlm_Ximports = \
+ $(EOLIST)
+
+#
+# Any symbols exported to here
+#
+FILES_nlm_exports = \
+ $(EOLIST)
+
+#
+# These are the OBJ files needed to create the LIB target above.
+# Paths must all use the '/' character
+#
+FILES_lib_objs = \
+ $(EOLIST)
+
+#
+# implement targets and dependancies (leave this section alone)
+#
+
+libs :: $(OBJDIR) $(TARGET_lib)
+
+nlms :: libs $(TARGET_nlm)
+
+#
+# Updated this target to create necessary directories and copy files to the
+# correct place. (See $(AP_WORK)/build/NWGNUhead.inc for examples)
+#
+install :: nlms FORCE
+ $(call COPY,$(OBJDIR)/*.nlm, $(INSTALLBASE)/modules/)
+
+#
+# Any specialized rules here
+#
+
+#
+# Include the 'tail' makefile that has targets that depend on variables defined
+# in this makefile
+#
+
+include $(APBUILD)/NWGNUtail.inc
+
+
diff --git a/modules/loggers/NWGNUmodlogio b/modules/loggers/NWGNUmodlogio
new file mode 100644
index 0000000..fa376db
--- /dev/null
+++ b/modules/loggers/NWGNUmodlogio
@@ -0,0 +1,258 @@
+#
+# Declare the sub-directories to be built here
+#
+
+SUBDIRS = \
+ $(EOLIST)
+
+#
+# Get the 'head' of the build environment. This includes default targets and
+# paths to tools
+#
+
+include $(AP_WORK)/build/NWGNUhead.inc
+
+#
+# build this level's files
+
+#
+# Make sure all needed macro's are defined
+#
+
+#
+# These directories will be at the beginning of the include list, followed by
+# INCDIRS
+#
+XINCDIRS += \
+ $(APR)/include \
+ $(APRUTIL)/include \
+ $(AP_WORK)/include \
+ $(AP_WORK)/modules/http \
+ $(NWOS) \
+ $(EOLIST)
+
+#
+# These flags will come after CFLAGS
+#
+XCFLAGS += \
+ $(EOLIST)
+
+#
+# These defines will come after DEFINES
+#
+XDEFINES += \
+ $(EOLIST)
+
+#
+# These flags will be added to the link.opt file
+#
+XLFLAGS += \
+ $(EOLIST)
+
+#
+# These values will be appended to the correct variables based on the value of
+# RELEASE
+#
+ifeq "$(RELEASE)" "debug"
+XINCDIRS += \
+ $(EOLIST)
+
+XCFLAGS += \
+ $(EOLIST)
+
+XDEFINES += \
+ $(EOLIST)
+
+XLFLAGS += \
+ $(EOLIST)
+endif
+
+ifeq "$(RELEASE)" "noopt"
+XINCDIRS += \
+ $(EOLIST)
+
+XCFLAGS += \
+ $(EOLIST)
+
+XDEFINES += \
+ $(EOLIST)
+
+XLFLAGS += \
+ $(EOLIST)
+endif
+
+ifeq "$(RELEASE)" "release"
+XINCDIRS += \
+ $(EOLIST)
+
+XCFLAGS += \
+ $(EOLIST)
+
+XDEFINES += \
+ $(EOLIST)
+
+XLFLAGS += \
+ $(EOLIST)
+endif
+
+#
+# These are used by the link target if an NLM is being generated
+# This is used by the link 'name' directive to name the nlm. If left blank
+# TARGET_nlm (see below) will be used.
+#
+NLM_NAME = logio
+
+#
+# This is used by the link '-desc ' directive.
+# If left blank, NLM_NAME will be used.
+#
+NLM_DESCRIPTION = Apache $(VERSION_STR) IO Logging Module
+
+#
+# This is used by the '-threadname' directive. If left blank,
+# NLM_NAME Thread will be used.
+#
+NLM_THREAD_NAME = Logio Module
+
+#
+# If this is specified, it will override VERSION value in
+# $(AP_WORK)/build/NWGNUenvironment.inc
+#
+NLM_VERSION =
+
+#
+# If this is specified, it will override the default of 64K
+#
+NLM_STACK_SIZE = 8192
+
+
+#
+# If this is specified it will be used by the link '-entry' directive
+#
+NLM_ENTRY_SYM =
+
+#
+# If this is specified it will be used by the link '-exit' directive
+#
+NLM_EXIT_SYM =
+
+#
+# If this is specified it will be used by the link '-check' directive
+#
+NLM_CHECK_SYM =
+
+#
+# If these are specified it will be used by the link '-flags' directive
+#
+NLM_FLAGS =
+
+#
+# If this is specified it will be linked in with the XDCData option in the def
+# file instead of the default of $(NWOS)/apache.xdc. XDCData can be disabled
+# by setting APACHE_UNIPROC in the environment
+#
+XDCDATA =
+
+#
+# If there is an NLM target, put it here
+#
+TARGET_nlm = \
+ $(OBJDIR)/modlogio.nlm \
+ $(EOLIST)
+
+#
+# If there is an LIB target, put it here
+#
+TARGET_lib = \
+ $(EOLIST)
+
+#
+# These are the OBJ files needed to create the NLM target above.
+# Paths must all use the '/' character
+#
+FILES_nlm_objs = \
+ $(OBJDIR)/mod_logio.o \
+ $(EOLIST)
+
+#
+# These are the LIB files needed to create the NLM target above.
+# These will be added as a library command in the link.opt file.
+#
+FILES_nlm_libs = \
+ $(PRELUDE) \
+ $(EOLIST)
+
+#
+# These are the modules that the above NLM target depends on to load.
+# These will be added as a module command in the link.opt file.
+#
+FILES_nlm_modules = \
+ aprlib \
+ libc \
+ $(EOLIST)
+
+#
+# If the nlm has a msg file, put it's path here
+#
+FILE_nlm_msg =
+
+#
+# If the nlm has a hlp file put it's path here
+#
+FILE_nlm_hlp =
+
+#
+# If this is specified, it will override $(NWOS)\copyright.txt.
+#
+FILE_nlm_copyright =
+
+#
+# Any additional imports go here
+#
+FILES_nlm_Ximports = \
+ @aprlib.imp \
+ @httpd.imp \
+ @libc.imp \
+ $(EOLIST)
+
+#
+# Any symbols exported to here
+#
+FILES_nlm_exports = \
+ logio_module \
+ $(EOLIST)
+
+#
+# These are the OBJ files needed to create the LIB target above.
+# Paths must all use the '/' character
+#
+FILES_lib_objs = \
+ $(EOLIST)
+
+#
+# implement targets and dependancies (leave this section alone)
+#
+
+libs :: $(OBJDIR) $(TARGET_lib)
+
+nlms :: libs $(TARGET_nlm)
+
+#
+# Updated this target to create necessary directories and copy files to the
+# correct place. (See $(AP_WORK)/build/NWGNUhead.inc for examples)
+#
+install :: nlms FORCE
+ $(call COPY,$(OBJDIR)/*.nlm, $(INSTALLBASE)/modules/)
+
+#
+# Any specialized rules here
+#
+
+#
+# Include the 'tail' makefile that has targets that depend on variables defined
+# in this makefile
+#
+
+include $(APBUILD)/NWGNUtail.inc
+
+
diff --git a/modules/loggers/config.m4 b/modules/loggers/config.m4
new file mode 100644
index 0000000..762e773
--- /dev/null
+++ b/modules/loggers/config.m4
@@ -0,0 +1,20 @@
+dnl modules enabled in this directory by default
+
+dnl APACHE_MODULE(name, helptext[, objects[, structname[, default[, config]]]])
+
+APACHE_MODPATH_INIT(loggers)
+
+APACHE_MODULE(log_config, logging configuration. You won't be able to log requests to the server without this module., , , yes)
+APACHE_MODULE(log_debug, configurable debug logging, , , most)
+APACHE_MODULE(log_forensic, forensic logging)
+
+if test "x$enable_log_forensic" != "xno"; then
+ # mod_log_forensic needs test_char.h
+ APR_ADDTO(INCLUDES, [-I\$(top_builddir)/server])
+fi
+
+APACHE_MODULE(logio, input and output logging, , , most)
+
+APR_ADDTO(INCLUDES, [-I\$(top_srcdir)/$modpath_current])
+
+APACHE_MODPATH_FINISH
diff --git a/modules/loggers/mod_log_config.c b/modules/loggers/mod_log_config.c
new file mode 100644
index 0000000..5d5b73a
--- /dev/null
+++ b/modules/loggers/mod_log_config.c
@@ -0,0 +1,1857 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Modified by djm@va.pubnix.com:
+ * If no TransferLog is given explicitly, decline to log.
+ *
+ * This is module implements the TransferLog directive (same as the
+ * common log module), and additional directives, LogFormat and CustomLog.
+ *
+ *
+ * Syntax:
+ *
+ * TransferLog fn Logs transfers to fn in standard log format, unless
+ * a custom format is set with LogFormat
+ * LogFormat format Set a log format from TransferLog files
+ * CustomLog fn format
+ * Log to file fn with format given by the format
+ * argument
+ *
+ * There can be any number of TransferLog and CustomLog
+ * commands. Each request will be logged to _ALL_ the
+ * named files, in the appropriate format.
+ *
+ * If no TransferLog or CustomLog directive appears in a VirtualHost,
+ * the request will be logged to the log file(s) defined outside
+ * the virtual host section. If a TransferLog or CustomLog directive
+ * appears in the VirtualHost section, the log files defined outside
+ * the VirtualHost will _not_ be used. This makes this module compatible
+ * with the CLF and config log modules, where the use of TransferLog
+ * inside the VirtualHost section overrides its use outside.
+ *
+ * Examples:
+ *
+ * TransferLog logs/access_log
+ * <VirtualHost>
+ * LogFormat "... custom format ..."
+ * TransferLog log/virtual_only
+ * CustomLog log/virtual_useragents "%t %{user-agent}i"
+ * </VirtualHost>
+ *
+ * This will log using CLF to access_log any requests handled by the
+ * main server, while any requests to the virtual host will be logged
+ * with the "... custom format..." to virtual_only _AND_ using
+ * the custom user-agent log to virtual_useragents.
+ *
+ * Note that the NCSA referer and user-agent logs are easily added with
+ * CustomLog:
+ * CustomLog logs/referer "%{referer}i -> %U"
+ * CustomLog logs/agent "%{user-agent}i"
+ *
+ * RefererIgnore functionality can be obtained with conditional
+ * logging (SetEnvIf and CustomLog ... env=!VAR).
+ *
+ * But using this method allows much easier modification of the
+ * log format, e.g. to log hosts along with UA:
+ * CustomLog logs/referer "%{referer}i %U %h"
+ *
+ * The argument to LogFormat and CustomLog is a string, which can include
+ * literal characters copied into the log files, and '%' directives as
+ * follows:
+ *
+ * %...B: bytes sent, excluding HTTP headers.
+ * %...b: bytes sent, excluding HTTP headers in CLF format, i.e. a '-'
+ * when no bytes where sent (rather than a '0'.
+ * %...{FOOBAR}C: The contents of the HTTP cookie FOOBAR
+ * %...{FOOBAR}e: The contents of the environment variable FOOBAR
+ * %...f: filename
+ * %...h: remote host
+ * %...a: remote IP-address
+ * %...A: local IP-address
+ * %...{Foobar}i: The contents of Foobar: header line(s) in the request
+ * sent to the client.
+ * %...k: number of keepalive requests served over this connection
+ * %...l: remote logname (from identd, if supplied)
+ * %...{Foobar}n: The contents of note "Foobar" from another module.
+ * %...{Foobar}o: The contents of Foobar: header line(s) in the reply.
+ * %...p: the canonical port for the server
+ * %...{format}p: the canonical port for the server, or the actual local
+ * or remote port
+ * %...P: the process ID of the child that serviced the request.
+ * %...{format}P: the process ID or thread ID of the child/thread that
+ * serviced the request
+ * %...r: first line of request
+ * %...s: status. For requests that got internally redirected, this
+ * is status of the *original* request --- %...>s for the last.
+ * %...t: time, in common log format time format
+ * %...{format}t: The time, in the form given by format, which should
+ * be in strftime(3) format.
+ * %...T: the time taken to serve the request, in seconds.
+ * %...{s}T: the time taken to serve the request, in seconds, same as %T.
+ * %...{us}T: the time taken to serve the request, in micro seconds, same as %D.
+ * %...{ms}T: the time taken to serve the request, in milliseconds.
+ * %...D: the time taken to serve the request, in micro seconds.
+ * %...u: remote user (from auth; may be bogus if return status (%s) is 401)
+ * %...U: the URL path requested.
+ * %...v: the configured name of the server (i.e. which virtual host?)
+ * %...V: the server name according to the UseCanonicalName setting
+ * %...m: the request method
+ * %...H: the request protocol
+ * %...q: the query string prepended by "?", or empty if no query string
+ * %...X: Status of the connection.
+ * 'X' = connection aborted before the response completed.
+ * '+' = connection may be kept alive after the response is sent.
+ * '-' = connection will be closed after the response is sent.
+ * (This directive was %...c in late versions of Apache 1.3, but
+ * this conflicted with the historical ssl %...{var}c syntax.)
+ * %...L: Log-Id of the Request (or '-' if none)
+ * %...{c}L: Log-Id of the Connection (or '-' if none)
+ *
+ * The '...' can be nothing at all (e.g. "%h %u %r %s %b"), or it can
+ * indicate conditions for inclusion of the item (which will cause it
+ * to be replaced with '-' if the condition is not met). Note that
+ * there is no escaping performed on the strings from %r, %...i and
+ * %...o; some with long memories may remember that I thought this was
+ * a bad idea, once upon a time, and I'm still not comfortable with
+ * it, but it is difficult to see how to "do the right thing" with all
+ * of '%..i', unless we URL-escape everything and break with CLF.
+ *
+ * The forms of condition are a list of HTTP status codes, which may
+ * or may not be preceded by '!'. Thus, '%400,501{User-agent}i' logs
+ * User-agent: on 400 errors and 501 errors (Bad Request, Not
+ * Implemented) only; '%!200,304,302{Referer}i' logs Referer: on all
+ * requests which did *not* return some sort of normal status.
+ *
+ * The default LogFormat reproduces CLF; see below.
+ *
+ * The way this is supposed to work with virtual hosts is as follows:
+ * a virtual host can have its own LogFormat, or its own TransferLog.
+ * If it doesn't have its own LogFormat, it inherits from the main
+ * server. If it doesn't have its own TransferLog, it writes to the
+ * same descriptor (meaning the same process for "| ...").
+ *
+ * --- rst */
+
+#include "apr_strings.h"
+#include "apr_lib.h"
+#include "apr_hash.h"
+#include "apr_optional.h"
+#include "apr_anylock.h"
+
+#define APR_WANT_STRFUNC
+#include "apr_want.h"
+
+#include "ap_config.h"
+#include "mod_log_config.h"
+#include "httpd.h"
+#include "http_config.h"
+#include "http_core.h" /* For REMOTE_NAME */
+#include "http_log.h"
+#include "http_protocol.h"
+#include "util_time.h"
+#include "ap_mpm.h"
+
+#if APR_HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+
+#define DEFAULT_LOG_FORMAT "%h %l %u %t \"%r\" %>s %b"
+
+module AP_MODULE_DECLARE_DATA log_config_module;
+
+
+static int xfer_flags = (APR_WRITE | APR_APPEND | APR_CREATE | APR_LARGEFILE);
+static apr_fileperms_t xfer_perms = APR_OS_DEFAULT;
+static apr_hash_t *log_hash;
+static apr_status_t ap_default_log_writer(request_rec *r,
+ void *handle,
+ const char **strs,
+ int *strl,
+ int nelts,
+ apr_size_t len);
+static apr_status_t ap_buffered_log_writer(request_rec *r,
+ void *handle,
+ const char **strs,
+ int *strl,
+ int nelts,
+ apr_size_t len);
+static void *ap_default_log_writer_init(apr_pool_t *p, server_rec *s,
+ const char* name);
+static void *ap_buffered_log_writer_init(apr_pool_t *p, server_rec *s,
+ const char* name);
+
+static ap_log_writer_init *ap_log_set_writer_init(ap_log_writer_init *handle);
+static ap_log_writer *ap_log_set_writer(ap_log_writer *handle);
+static ap_log_writer *log_writer = ap_default_log_writer;
+static ap_log_writer_init *log_writer_init = ap_default_log_writer_init;
+static int buffered_logs = 0; /* default unbuffered */
+static apr_array_header_t *all_buffered_logs = NULL;
+
+/* POSIX.1 defines PIPE_BUF as the maximum number of bytes that is
+ * guaranteed to be atomic when writing a pipe. And PIPE_BUF >= 512
+ * is guaranteed. So we'll just guess 512 in the event the system
+ * doesn't have this. Now, for file writes there is actually no limit,
+ * the entire write is atomic. Whether all systems implement this
+ * correctly is another question entirely ... so we'll just use PIPE_BUF
+ * because it's probably a good guess as to what is implemented correctly
+ * everywhere.
+ */
+#ifdef PIPE_BUF
+#define LOG_BUFSIZE PIPE_BUF
+#else
+#define LOG_BUFSIZE (512)
+#endif
+
+/*
+ * multi_log_state is our per-(virtual)-server configuration. We store
+ * an array of the logs we are going to use, each of type config_log_state.
+ * If a default log format is given by LogFormat, store in default_format
+ * (backward compat. with mod_log_config). We also store for each virtual
+ * server a pointer to the logs specified for the main server, so that if this
+ * vhost has no logs defined, we can use the main server's logs instead.
+ *
+ * So, for the main server, config_logs contains a list of the log files
+ * and server_config_logs is empty. For a vhost, server_config_logs
+ * points to the same array as config_logs in the main server, and
+ * config_logs points to the array of logs defined inside this vhost,
+ * which might be empty.
+ */
+
+typedef struct {
+ const char *default_format_string;
+ apr_array_header_t *default_format;
+ apr_array_header_t *config_logs;
+ apr_array_header_t *server_config_logs;
+ apr_table_t *formats;
+} multi_log_state;
+
+/*
+ * config_log_state holds the status of a single log file. fname might
+ * be NULL, which means this module does no logging for this
+ * request. format might be NULL, in which case the default_format
+ * from the multi_log_state should be used, or if that is NULL as
+ * well, use the CLF.
+ * log_writer is NULL before the log file is opened and is
+ * set to a opaque structure (usually a fd) after it is opened.
+
+ */
+typedef struct {
+ apr_file_t *handle;
+ apr_size_t outcnt;
+ char outbuf[LOG_BUFSIZE];
+ apr_anylock_t mutex;
+} buffered_log;
+
+typedef struct {
+ const char *fname;
+ const char *format_string;
+ apr_array_header_t *format;
+ void *log_writer;
+ char *condition_var;
+ int inherit;
+ ap_expr_info_t *condition_expr;
+ /** place of definition or NULL if already checked */
+ const ap_directive_t *directive;
+} config_log_state;
+
+/*
+ * log_request_state holds request specific log data that is not
+ * part of the request_rec.
+ */
+typedef struct {
+ apr_time_t request_end_time;
+} log_request_state;
+
+/*
+ * Format items...
+ * Note that many of these could have ap_sprintfs replaced with static buffers.
+ */
+
+typedef struct {
+ ap_log_handler_fn_t *func;
+ char *arg;
+ int condition_sense;
+ int want_orig;
+ apr_array_header_t *conditions;
+} log_format_item;
+
+static char *pfmt(apr_pool_t *p, int i)
+{
+ if (i <= 0) {
+ return "-";
+ }
+ else {
+ return apr_itoa(p, i);
+ }
+}
+
+static const char *constant_item(request_rec *dummy, char *stuff)
+{
+ return stuff;
+}
+
+static const char *log_remote_host(request_rec *r, char *a)
+{
+ const char *remote_host;
+ if (a && !strcmp(a, "c")) {
+ remote_host = ap_get_remote_host(r->connection, r->per_dir_config,
+ REMOTE_NAME, NULL);
+ }
+ else {
+ remote_host = ap_get_useragent_host(r, REMOTE_NAME, NULL);
+ }
+ return ap_escape_logitem(r->pool, remote_host);
+}
+
+static const char *log_remote_address(request_rec *r, char *a)
+{
+ if (a && !strcmp(a, "c")) {
+ return r->connection->client_ip;
+ }
+ else {
+ return r->useragent_ip;
+ }
+}
+
+static const char *log_local_address(request_rec *r, char *a)
+{
+ return r->connection->local_ip;
+}
+
+static const char *log_remote_logname(request_rec *r, char *a)
+{
+ return ap_escape_logitem(r->pool, ap_get_remote_logname(r));
+}
+
+static const char *log_remote_user(request_rec *r, char *a)
+{
+ char *rvalue = r->user;
+
+ if (rvalue == NULL) {
+ rvalue = "-";
+ }
+ else if (strlen(rvalue) == 0) {
+ rvalue = "\"\"";
+ }
+ else {
+ rvalue = ap_escape_logitem(r->pool, rvalue);
+ }
+
+ return rvalue;
+}
+
+static const char *log_request_line(request_rec *r, char *a)
+{
+ /* NOTE: If the original request contained a password, we
+ * re-write the request line here to contain XXXXXX instead:
+ * (note the truncation before the protocol string for HTTP/0.9 requests)
+ * (note also that r->the_request contains the unmodified request)
+ */
+ return ap_escape_logitem(r->pool,
+ (r->parsed_uri.password)
+ ? apr_pstrcat(r->pool, r->method, " ",
+ apr_uri_unparse(r->pool,
+ &r->parsed_uri, 0),
+ r->assbackwards ? NULL : " ",
+ r->protocol, NULL)
+ : r->the_request);
+}
+
+static const char *log_request_file(request_rec *r, char *a)
+{
+ return ap_escape_logitem(r->pool, r->filename);
+}
+static const char *log_request_uri(request_rec *r, char *a)
+{
+ return ap_escape_logitem(r->pool, r->uri);
+}
+static const char *log_request_method(request_rec *r, char *a)
+{
+ return ap_escape_logitem(r->pool, r->method);
+}
+static const char *log_log_id(request_rec *r, char *a)
+{
+ if (a && !strcmp(a, "c")) {
+ return r->connection->log_id ? r->connection->log_id : "-";
+ }
+ else {
+ return r->log_id ? r->log_id : "-";
+ }
+}
+static const char *log_request_protocol(request_rec *r, char *a)
+{
+ return ap_escape_logitem(r->pool, r->protocol);
+}
+static const char *log_request_query(request_rec *r, char *a)
+{
+ return (r->args) ? apr_pstrcat(r->pool, "?",
+ ap_escape_logitem(r->pool, r->args), NULL)
+ : "";
+}
+static const char *log_status(request_rec *r, char *a)
+{
+ return pfmt(r->pool, r->status);
+}
+
+static const char *log_handler(request_rec *r, char *a)
+{
+ return ap_escape_logitem(r->pool, r->handler);
+}
+
+static const char *clf_log_bytes_sent(request_rec *r, char *a)
+{
+ if (!r->sent_bodyct || !r->bytes_sent) {
+ return "-";
+ }
+ else {
+ return apr_off_t_toa(r->pool, r->bytes_sent);
+ }
+}
+
+static const char *log_bytes_sent(request_rec *r, char *a)
+{
+ if (!r->sent_bodyct || !r->bytes_sent) {
+ return "0";
+ }
+ else {
+ return apr_off_t_toa(r->pool, r->bytes_sent);
+ }
+}
+
+
+static const char *log_header_in(request_rec *r, char *a)
+{
+ return ap_escape_logitem(r->pool, apr_table_get(r->headers_in, a));
+}
+
+static const char *log_trailer_in(request_rec *r, char *a)
+{
+ return ap_escape_logitem(r->pool, apr_table_get(r->trailers_in, a));
+}
+
+
+static APR_INLINE char *find_multiple_headers(apr_pool_t *pool,
+ const apr_table_t *table,
+ const char *key)
+{
+ const apr_array_header_t *elts;
+ const apr_table_entry_t *t_elt;
+ const apr_table_entry_t *t_end;
+ apr_size_t len;
+ struct sle {
+ struct sle *next;
+ const char *value;
+ apr_size_t len;
+ } *result_list, *rp;
+
+ elts = apr_table_elts(table);
+
+ if (!elts->nelts) {
+ return NULL;
+ }
+
+ t_elt = (const apr_table_entry_t *)elts->elts;
+ t_end = t_elt + elts->nelts;
+ len = 1; /* \0 */
+ result_list = rp = NULL;
+
+ do {
+ if (!ap_cstr_casecmp(t_elt->key, key)) {
+ if (!result_list) {
+ result_list = rp = apr_palloc(pool, sizeof(*rp));
+ }
+ else {
+ rp = rp->next = apr_palloc(pool, sizeof(*rp));
+ len += 2; /* ", " */
+ }
+
+ rp->next = NULL;
+ rp->value = t_elt->val;
+ rp->len = strlen(rp->value);
+
+ len += rp->len;
+ }
+ ++t_elt;
+ } while (t_elt < t_end);
+
+ if (result_list) {
+ char *result = apr_palloc(pool, len);
+ char *cp = result;
+
+ rp = result_list;
+ while (rp) {
+ if (rp != result_list) {
+ *cp++ = ',';
+ *cp++ = ' ';
+ }
+ memcpy(cp, rp->value, rp->len);
+ cp += rp->len;
+ rp = rp->next;
+ }
+ *cp = '\0';
+
+ return result;
+ }
+
+ return NULL;
+}
+
+static const char *log_header_out(request_rec *r, char *a)
+{
+ const char *cp = NULL;
+
+ if (!ap_cstr_casecmp(a, "Content-type") && r->content_type) {
+ cp = ap_field_noparam(r->pool, r->content_type);
+ }
+ else if (!ap_cstr_casecmp(a, "Set-Cookie")) {
+ cp = find_multiple_headers(r->pool, r->headers_out, a);
+ }
+ else {
+ cp = apr_table_get(r->headers_out, a);
+ }
+
+ return ap_escape_logitem(r->pool, cp);
+}
+
+static const char *log_trailer_out(request_rec *r, char *a)
+{
+ return ap_escape_logitem(r->pool, apr_table_get(r->trailers_out, a));
+}
+
+static const char *log_note(request_rec *r, char *a)
+{
+ return ap_escape_logitem(r->pool, apr_table_get(r->notes, a));
+}
+static const char *log_env_var(request_rec *r, char *a)
+{
+ return ap_escape_logitem(r->pool, apr_table_get(r->subprocess_env, a));
+}
+
+static const char *log_cookie(request_rec *r, char *a)
+{
+ const char *cookies_entry;
+
+ /*
+ * This supports Netscape version 0 cookies while being tolerant to
+ * some properties of RFC2109/2965 version 1 cookies:
+ * - case-insensitive match of cookie names
+ * - white space between the tokens
+ * It does not support the following version 1 features:
+ * - quoted strings as cookie values
+ * - commas to separate cookies
+ */
+
+ if ((cookies_entry = apr_table_get(r->headers_in, "Cookie"))) {
+ char *cookie, *last1, *last2;
+ char *cookies = apr_pstrdup(r->pool, cookies_entry);
+
+ while ((cookie = apr_strtok(cookies, ";", &last1))) {
+ char *name = apr_strtok(cookie, "=", &last2);
+ /* last2 points to the next char following an '=' delim,
+ or the trailing NUL char of the string */
+ char *value = last2;
+ if (name && *name && value && *value) {
+ char *last = value - 2;
+ /* Move past leading WS */
+ name += strspn(name, " \t");
+ while (last >= name && apr_isspace(*last)) {
+ *last = '\0';
+ --last;
+ }
+
+ if (!ap_cstr_casecmp(name, a)) {
+ /* last1 points to the next char following the ';' delim,
+ or the trailing NUL char of the string */
+ last = last1 - (*last1 ? 2 : 1);
+ /* Move past leading WS */
+ value += strspn(value, " \t");
+ while (last >= value && apr_isspace(*last)) {
+ *last = '\0';
+ --last;
+ }
+
+ return ap_escape_logitem(r->pool, value);
+ }
+ }
+ /* Iterate the remaining tokens using apr_strtok(NULL, ...) */
+ cookies = NULL;
+ }
+ }
+ return NULL;
+}
+
+static const char *log_request_time_custom(request_rec *r, char *a,
+ apr_time_exp_t *xt)
+{
+ apr_size_t retcode;
+ char tstr[MAX_STRING_LEN];
+ apr_strftime(tstr, &retcode, sizeof(tstr), a, xt);
+ return apr_pstrdup(r->pool, tstr);
+}
+
+#define DEFAULT_REQUEST_TIME_SIZE 32
+typedef struct {
+ unsigned t;
+ char timestr[DEFAULT_REQUEST_TIME_SIZE];
+ unsigned t_validate;
+} cached_request_time;
+
+#define TIME_FMT_CUSTOM 0
+#define TIME_FMT_CLF 1
+#define TIME_FMT_ABS_SEC 2
+#define TIME_FMT_ABS_MSEC 3
+#define TIME_FMT_ABS_USEC 4
+#define TIME_FMT_ABS_MSEC_FRAC 5
+#define TIME_FMT_ABS_USEC_FRAC 6
+
+#define TIME_CACHE_SIZE 4
+#define TIME_CACHE_MASK 3
+static cached_request_time request_time_cache[TIME_CACHE_SIZE];
+
+static apr_time_t get_request_end_time(request_rec *r)
+{
+ log_request_state *state = (log_request_state *)ap_get_module_config(r->request_config,
+ &log_config_module);
+ if (!state) {
+ state = apr_pcalloc(r->pool, sizeof(log_request_state));
+ ap_set_module_config(r->request_config, &log_config_module, state);
+ }
+ if (state->request_end_time == 0) {
+ state->request_end_time = apr_time_now();
+ }
+ return state->request_end_time;
+}
+
+
+static const char *log_request_time(request_rec *r, char *a)
+{
+ apr_time_exp_t xt;
+ apr_time_t request_time = r->request_time;
+ int fmt_type = TIME_FMT_CUSTOM;
+ char *fmt = a;
+
+ if (fmt && *fmt) {
+ if (!strncmp(fmt, "begin", 5)) {
+ fmt += 5;
+ if (!*fmt) {
+ fmt_type = TIME_FMT_CLF;
+ }
+ else if (*fmt == ':') {
+ fmt++;
+ a = fmt;
+ }
+ }
+ else if (!strncmp(fmt, "end", 3)) {
+ fmt += 3;
+ if (!*fmt) {
+ request_time = get_request_end_time(r);
+ fmt_type = TIME_FMT_CLF;
+ }
+ else if (*fmt == ':') {
+ fmt++;
+ a = fmt;
+ request_time = get_request_end_time(r);
+ }
+ }
+ if (!strncmp(fmt, "msec", 4)) {
+ fmt += 4;
+ if (!*fmt) {
+ fmt_type = TIME_FMT_ABS_MSEC;
+ }
+ else if (!strcmp(fmt, "_frac")) {
+ fmt_type = TIME_FMT_ABS_MSEC_FRAC;
+ }
+ }
+ else if (!strncmp(fmt, "usec", 4)) {
+ fmt += 4;
+ if (!*fmt) {
+ fmt_type = TIME_FMT_ABS_USEC;
+ }
+ else if (!strcmp(fmt, "_frac")) {
+ fmt_type = TIME_FMT_ABS_USEC_FRAC;
+ }
+ }
+ else if (!strcmp(fmt, "sec")) {
+ fmt_type = TIME_FMT_ABS_SEC;
+ }
+ else if (!*fmt) {
+ fmt_type = TIME_FMT_CLF;
+ }
+ }
+ else {
+ fmt_type = TIME_FMT_CLF;
+ }
+
+ if (fmt_type >= TIME_FMT_ABS_SEC) { /* Absolute (micro-/milli-)second time
+ * or msec/usec fraction
+ */
+ char* buf = apr_palloc(r->pool, 20);
+ switch (fmt_type) {
+ case TIME_FMT_ABS_SEC:
+ apr_snprintf(buf, 20, "%" APR_TIME_T_FMT, apr_time_sec(request_time));
+ break;
+ case TIME_FMT_ABS_MSEC:
+ apr_snprintf(buf, 20, "%" APR_TIME_T_FMT, apr_time_as_msec(request_time));
+ break;
+ case TIME_FMT_ABS_USEC:
+ apr_snprintf(buf, 20, "%" APR_TIME_T_FMT, request_time);
+ break;
+ case TIME_FMT_ABS_MSEC_FRAC:
+ apr_snprintf(buf, 20, "%03" APR_TIME_T_FMT, apr_time_msec(request_time));
+ break;
+ case TIME_FMT_ABS_USEC_FRAC:
+ apr_snprintf(buf, 20, "%06" APR_TIME_T_FMT, apr_time_usec(request_time));
+ break;
+ default:
+ return "-";
+ }
+ return buf;
+ }
+ else if (fmt_type == TIME_FMT_CUSTOM) { /* Custom format */
+ /* The custom time formatting uses a very large temp buffer
+ * on the stack. To avoid using so much stack space in the
+ * common case where we're not using a custom format, the code
+ * for the custom format in a separate function. (That's why
+ * log_request_time_custom is not inlined right here.)
+ */
+ ap_explode_recent_localtime(&xt, request_time);
+ return log_request_time_custom(r, a, &xt);
+ }
+ else { /* CLF format */
+ /* This code uses the same technique as ap_explode_recent_localtime():
+ * optimistic caching with logic to detect and correct race conditions.
+ * See the comments in server/util_time.c for more information.
+ */
+ cached_request_time* cached_time = apr_palloc(r->pool,
+ sizeof(*cached_time));
+ unsigned t_seconds = (unsigned)apr_time_sec(request_time);
+ unsigned i = t_seconds & TIME_CACHE_MASK;
+ *cached_time = request_time_cache[i];
+ if ((t_seconds != cached_time->t) ||
+ (t_seconds != cached_time->t_validate)) {
+
+ /* Invalid or old snapshot, so compute the proper time string
+ * and store it in the cache
+ */
+ char sign;
+ int timz;
+
+ ap_explode_recent_localtime(&xt, request_time);
+ timz = xt.tm_gmtoff;
+ if (timz < 0) {
+ timz = -timz;
+ sign = '-';
+ }
+ else {
+ sign = '+';
+ }
+ cached_time->t = t_seconds;
+ apr_snprintf(cached_time->timestr, DEFAULT_REQUEST_TIME_SIZE,
+ "[%02d/%s/%d:%02d:%02d:%02d %c%.2d%.2d]",
+ xt.tm_mday, apr_month_snames[xt.tm_mon],
+ xt.tm_year+1900, xt.tm_hour, xt.tm_min, xt.tm_sec,
+ sign, timz / (60*60), (timz % (60*60)) / 60);
+ cached_time->t_validate = t_seconds;
+ request_time_cache[i] = *cached_time;
+ }
+ return cached_time->timestr;
+ }
+}
+
+static const char *log_request_duration_microseconds(request_rec *r, char *a)
+{
+ return apr_psprintf(r->pool, "%" APR_TIME_T_FMT,
+ (get_request_end_time(r) - r->request_time));
+}
+
+static const char *log_request_duration_scaled(request_rec *r, char *a)
+{
+ apr_time_t duration = get_request_end_time(r) - r->request_time;
+ if (*a == '\0' || !strcasecmp(a, "s")) {
+ duration = apr_time_sec(duration);
+ }
+ else if (!strcasecmp(a, "ms")) {
+ duration = apr_time_as_msec(duration);
+ }
+ else if (!strcasecmp(a, "us")) {
+ }
+ else {
+ /* bogus format */
+ return a;
+ }
+ return apr_psprintf(r->pool, "%" APR_TIME_T_FMT, duration);
+}
+
+/* These next two routines use the canonical name:port so that log
+ * parsers don't need to duplicate all the vhost parsing crud.
+ */
+static const char *log_virtual_host(request_rec *r, char *a)
+{
+ return ap_escape_logitem(r->pool, r->server->server_hostname);
+}
+
+static const char *log_server_port(request_rec *r, char *a)
+{
+ apr_port_t port;
+
+ if (*a == '\0' || !strcasecmp(a, "canonical")) {
+ port = r->server->port ? r->server->port : ap_default_port(r);
+ }
+ else if (!strcasecmp(a, "remote")) {
+ port = r->useragent_addr->port;
+ }
+ else if (!strcasecmp(a, "local")) {
+ port = r->connection->local_addr->port;
+ }
+ else {
+ /* bogus format */
+ return a;
+ }
+ return apr_itoa(r->pool, (int)port);
+}
+
+/* This respects the setting of UseCanonicalName so that
+ * the dynamic mass virtual hosting trick works better.
+ */
+static const char *log_server_name(request_rec *r, char *a)
+{
+ return ap_escape_logitem(r->pool, ap_get_server_name(r));
+}
+
+static const char *log_pid_tid(request_rec *r, char *a)
+{
+ if (*a == '\0' || !strcasecmp(a, "pid")) {
+ return ap_append_pid(r->pool, "", "");
+ }
+ else if (!strcasecmp(a, "tid") || !strcasecmp(a, "hextid")) {
+#if APR_HAS_THREADS
+ apr_os_thread_t tid = apr_os_thread_current();
+#else
+ int tid = 0; /* APR will format "0" anyway but an arg is needed */
+#endif
+ return apr_psprintf(r->pool,
+ /* APR can format a thread id in hex */
+ *a == 'h' ? "%pt" : "%pT", &tid);
+ }
+ /* bogus format */
+ return a;
+}
+
+static const char *log_connection_status(request_rec *r, char *a)
+{
+ if (r->connection->aborted)
+ return "X";
+
+ if (r->connection->keepalive == AP_CONN_KEEPALIVE &&
+ (!r->server->keep_alive_max ||
+ (r->server->keep_alive_max - r->connection->keepalives) > 0)) {
+ return "+";
+ }
+ return "-";
+}
+
+static const char *log_requests_on_connection(request_rec *r, char *a)
+{
+ int num = r->connection->keepalives ? r->connection->keepalives - 1 : 0;
+ return apr_itoa(r->pool, num);
+}
+
+/*****************************************************************
+ *
+ * Parsing the log format string
+ */
+
+static char *parse_log_misc_string(apr_pool_t *p, log_format_item *it,
+ const char **sa)
+{
+ const char *s;
+ char *d;
+
+ it->func = constant_item;
+ it->conditions = NULL;
+
+ s = *sa;
+ while (*s && *s != '%') {
+ s++;
+ }
+ /*
+ * This might allocate a few chars extra if there's a backslash
+ * escape in the format string.
+ */
+ it->arg = apr_palloc(p, s - *sa + 1);
+
+ d = it->arg;
+ s = *sa;
+ while (*s && *s != '%') {
+ if (*s != '\\') {
+ *d++ = *s++;
+ }
+ else {
+ s++;
+ switch (*s) {
+ case '\\':
+ *d++ = '\\';
+ s++;
+ break;
+ case 'r':
+ *d++ = '\r';
+ s++;
+ break;
+ case 'n':
+ *d++ = '\n';
+ s++;
+ break;
+ case 't':
+ *d++ = '\t';
+ s++;
+ break;
+ default:
+ /* copy verbatim */
+ *d++ = '\\';
+ /*
+ * Allow the loop to deal with this *s in the normal
+ * fashion so that it handles end of string etc.
+ * properly.
+ */
+ break;
+ }
+ }
+ }
+ *d = '\0';
+
+ *sa = s;
+ return NULL;
+}
+
+static char *parse_log_item(apr_pool_t *p, log_format_item *it, const char **sa)
+{
+ const char *s = *sa;
+ ap_log_handler *handler = NULL;
+
+ if (*s != '%') {
+ return parse_log_misc_string(p, it, sa);
+ }
+
+ ++s;
+ it->condition_sense = 0;
+ it->conditions = NULL;
+
+ if (*s == '%') {
+ it->arg = "%";
+ it->func = constant_item;
+ *sa = ++s;
+
+ return NULL;
+ }
+
+ it->want_orig = -1;
+ it->arg = ""; /* For safety's sake... */
+
+ while (*s) {
+ int i;
+
+ switch (*s) {
+ case '!':
+ ++s;
+ it->condition_sense = !it->condition_sense;
+ break;
+
+ case '<':
+ ++s;
+ it->want_orig = 1;
+ break;
+
+ case '>':
+ ++s;
+ it->want_orig = 0;
+ break;
+
+ case ',':
+ ++s;
+ break;
+
+ case '{':
+ ++s;
+ it->arg = ap_getword(p, &s, '}');
+ break;
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ i = *s - '0';
+ while (apr_isdigit(*++s)) {
+ i = i * 10 + (*s) - '0';
+ }
+ if (!it->conditions) {
+ it->conditions = apr_array_make(p, 4, sizeof(int));
+ }
+ *(int *) apr_array_push(it->conditions) = i;
+ break;
+
+ default:
+ /* check for '^' + two character format first */
+ if (*s == '^' && *(s+1) && *(s+2)) {
+ handler = (ap_log_handler *)apr_hash_get(log_hash, s, 3);
+ if (handler) {
+ s += 3;
+ }
+ }
+ if (!handler) {
+ handler = (ap_log_handler *)apr_hash_get(log_hash, s++, 1);
+ }
+ if (!handler) {
+ char dummy[2];
+
+ dummy[0] = s[-1];
+ dummy[1] = '\0';
+ return apr_pstrcat(p, "Unrecognized LogFormat directive %",
+ dummy, NULL);
+ }
+ it->func = handler->func;
+ if (it->want_orig == -1) {
+ it->want_orig = handler->want_orig_default;
+ }
+ *sa = s;
+ return NULL;
+ }
+ }
+
+ return "Ran off end of LogFormat parsing args to some directive";
+}
+
+static apr_array_header_t *parse_log_string(apr_pool_t *p, const char *s, const char **err)
+{
+ apr_array_header_t *a = apr_array_make(p, 30, sizeof(log_format_item));
+ char *res;
+
+ while (*s) {
+ if ((res = parse_log_item(p, (log_format_item *) apr_array_push(a), &s))) {
+ *err = res;
+ return NULL;
+ }
+ }
+
+ s = APR_EOL_STR;
+ parse_log_item(p, (log_format_item *) apr_array_push(a), &s);
+ return a;
+}
+
+/*****************************************************************
+ *
+ * Actually logging.
+ */
+
+static const char *process_item(request_rec *r, request_rec *orig,
+ log_format_item *item)
+{
+ const char *cp;
+
+ /* First, see if we need to process this thing at all... */
+
+ if (item->conditions && item->conditions->nelts != 0) {
+ int i;
+ int *conds = (int *) item->conditions->elts;
+ int in_list = 0;
+
+ for (i = 0; i < item->conditions->nelts; ++i) {
+ if (r->status == conds[i]) {
+ in_list = 1;
+ break;
+ }
+ }
+
+ if ((item->condition_sense && in_list)
+ || (!item->condition_sense && !in_list)) {
+ return "-";
+ }
+ }
+
+ /* We do. Do it... */
+
+ cp = (*item->func) (item->want_orig ? orig : r, item->arg);
+ return cp ? cp : "-";
+}
+
+static void flush_log(buffered_log *buf)
+{
+ if (buf->outcnt && buf->handle != NULL) {
+ /* XXX: error handling */
+ apr_file_write_full(buf->handle, buf->outbuf, buf->outcnt, NULL);
+ buf->outcnt = 0;
+ }
+}
+
+
+static int config_log_transaction(request_rec *r, config_log_state *cls,
+ apr_array_header_t *default_format)
+{
+ log_format_item *items;
+ const char **strs;
+ int *strl;
+ request_rec *orig;
+ int i;
+ apr_size_t len = 0;
+ apr_array_header_t *format;
+ char *envar;
+ apr_status_t rv;
+
+ if (cls->fname == NULL) {
+ return DECLINED;
+ }
+
+ /*
+ * See if we've got any conditional envariable-controlled logging decisions
+ * to make.
+ */
+ if (cls->condition_var != NULL) {
+ envar = cls->condition_var;
+ if (*envar != '!') {
+ if (apr_table_get(r->subprocess_env, envar) == NULL) {
+ return DECLINED;
+ }
+ }
+ else {
+ if (apr_table_get(r->subprocess_env, &envar[1]) != NULL) {
+ return DECLINED;
+ }
+ }
+ }
+ else if (cls->condition_expr != NULL) {
+ const char *err;
+ int rc = ap_expr_exec(r, cls->condition_expr, &err);
+ if (rc < 0)
+ ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(00644)
+ "Error evaluating log condition: %s", err);
+ if (rc <= 0)
+ return DECLINED;
+ }
+
+ format = cls->format ? cls->format : default_format;
+
+ strs = apr_palloc(r->pool, sizeof(char *) * (format->nelts));
+ strl = apr_palloc(r->pool, sizeof(int) * (format->nelts));
+ items = (log_format_item *) format->elts;
+
+ orig = r;
+ while (orig->prev) {
+ orig = orig->prev;
+ }
+ while (r->next) {
+ r = r->next;
+ }
+
+ for (i = 0; i < format->nelts; ++i) {
+ strs[i] = process_item(r, orig, &items[i]);
+ len += strl[i] = strlen(strs[i]);
+ }
+
+ if (!log_writer) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00645)
+ "log writer isn't correctly setup");
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+ rv = log_writer(r, cls->log_writer, strs, strl, format->nelts, len);
+ if (rv != APR_SUCCESS) {
+ ap_log_rerror(APLOG_MARK, APLOG_WARNING, rv, r, APLOGNO(00646)
+ "Error writing to %s", cls->fname);
+ }
+ return OK;
+}
+
+static int multi_log_transaction(request_rec *r)
+{
+ multi_log_state *mls = ap_get_module_config(r->server->module_config,
+ &log_config_module);
+ config_log_state *clsarray;
+ int i;
+
+ /*
+ * Initialize per request state
+ */
+ log_request_state *state = apr_pcalloc(r->pool, sizeof(log_request_state));
+ ap_set_module_config(r->request_config, &log_config_module, state);
+
+ /*
+ * Log this transaction..
+ */
+ if (mls->config_logs->nelts) {
+ clsarray = (config_log_state *) mls->config_logs->elts;
+ for (i = 0; i < mls->config_logs->nelts; ++i) {
+ config_log_state *cls = &clsarray[i];
+
+ config_log_transaction(r, cls, mls->default_format);
+ }
+ }
+
+ if (mls->server_config_logs) {
+ clsarray = (config_log_state *) mls->server_config_logs->elts;
+ for (i = 0; i < mls->server_config_logs->nelts; ++i) {
+ config_log_state *cls = &clsarray[i];
+
+ if (cls->inherit || !mls->config_logs->nelts) {
+ config_log_transaction(r, cls, mls->default_format);
+ }
+ }
+ }
+
+ return OK;
+}
+
+/*****************************************************************
+ *
+ * Module glue...
+ */
+
+static void *make_config_log_state(apr_pool_t *p, server_rec *s)
+{
+ multi_log_state *mls;
+
+ mls = (multi_log_state *) apr_palloc(p, sizeof(multi_log_state));
+ mls->config_logs = apr_array_make(p, 1, sizeof(config_log_state));
+ mls->default_format_string = NULL;
+ mls->default_format = NULL;
+ mls->server_config_logs = NULL;
+ mls->formats = apr_table_make(p, 4);
+ apr_table_setn(mls->formats, "CLF", DEFAULT_LOG_FORMAT);
+
+ return mls;
+}
+
+/*
+ * Use the merger to simply add a pointer from the vhost log state
+ * to the log of logs specified for the non-vhost configuration. Make sure
+ * vhosts inherit any globally-defined format names.
+ */
+
+static void *merge_config_log_state(apr_pool_t *p, void *basev, void *addv)
+{
+ multi_log_state *base = (multi_log_state *) basev;
+ multi_log_state *add = (multi_log_state *) addv;
+
+ add->server_config_logs = base->config_logs;
+ if (!add->default_format) {
+ add->default_format_string = base->default_format_string;
+ add->default_format = base->default_format;
+ }
+ add->formats = apr_table_overlay(p, base->formats, add->formats);
+
+ return add;
+}
+
+/*
+ * Set the default logfile format, or define a nickname for a format string.
+ */
+static const char *log_format(cmd_parms *cmd, void *dummy, const char *fmt,
+ const char *name)
+{
+ const char *err_string = NULL;
+ multi_log_state *mls = ap_get_module_config(cmd->server->module_config,
+ &log_config_module);
+
+ /*
+ * If we were given two arguments, the second is a name to be given to the
+ * format. This syntax just defines the nickname - it doesn't actually
+ * make the format the default.
+ */
+ if (name != NULL) {
+ parse_log_string(cmd->pool, fmt, &err_string);
+ if (err_string == NULL) {
+ apr_table_setn(mls->formats, name, fmt);
+ }
+ }
+ else {
+ mls->default_format_string = fmt;
+ mls->default_format = parse_log_string(cmd->pool, fmt, &err_string);
+ }
+ return err_string;
+}
+
+
+static const char *add_custom_log(cmd_parms *cmd, void *dummy, const char *fn,
+ const char *fmt, const char *envclause)
+{
+ const char *err_string = NULL;
+ multi_log_state *mls = ap_get_module_config(cmd->server->module_config,
+ &log_config_module);
+ config_log_state *cls;
+
+ cls = (config_log_state *) apr_array_push(mls->config_logs);
+ cls->condition_var = NULL;
+ cls->condition_expr = NULL;
+ if (envclause != NULL) {
+ if (strncasecmp(envclause, "env=", 4) == 0) {
+ if ((envclause[4] == '\0')
+ || ((envclause[4] == '!') && (envclause[5] == '\0'))) {
+ return "missing environment variable name";
+ }
+ cls->condition_var = apr_pstrdup(cmd->pool, &envclause[4]);
+ }
+ else if (strncasecmp(envclause, "expr=", 5) == 0) {
+ const char *err;
+ if ((envclause[5] == '\0'))
+ return "missing condition";
+ cls->condition_expr = ap_expr_parse_cmd(cmd, &envclause[5],
+ AP_EXPR_FLAG_DONT_VARY,
+ &err, NULL);
+ if (err)
+ return err;
+ }
+ else {
+ return "error in condition clause";
+ }
+ }
+
+ cls->fname = fn;
+ cls->format_string = fmt;
+ cls->directive = cmd->directive;
+ if (fmt == NULL) {
+ cls->format = NULL;
+ }
+ else {
+ cls->format = parse_log_string(cmd->pool, fmt, &err_string);
+ }
+ cls->log_writer = NULL;
+
+ return err_string;
+}
+
+static const char *add_global_log(cmd_parms *cmd, void *dummy, const char *fn,
+ const char *fmt, const char *envclause) {
+ multi_log_state *mls = ap_get_module_config(cmd->server->module_config,
+ &log_config_module);
+ config_log_state *clsarray;
+ config_log_state *cls;
+ const char *ret;
+
+ const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
+
+ if (err) {
+ return err;
+ }
+
+ /* Add a custom log through the normal channel */
+ ret = add_custom_log(cmd, dummy, fn, fmt, envclause);
+
+ /* Set the inherit flag unless there was some error */
+ if (ret == NULL) {
+ clsarray = (config_log_state*)mls->config_logs->elts;
+ cls = &clsarray[mls->config_logs->nelts-1];
+ cls->inherit = 1;
+ }
+
+ return ret;
+}
+
+static const char *set_transfer_log(cmd_parms *cmd, void *dummy,
+ const char *fn)
+{
+ return add_custom_log(cmd, dummy, fn, NULL, NULL);
+}
+
+static const char *set_buffered_logs_on(cmd_parms *parms, void *dummy, int flag)
+{
+ buffered_logs = flag;
+ if (buffered_logs) {
+ ap_log_set_writer_init(ap_buffered_log_writer_init);
+ ap_log_set_writer(ap_buffered_log_writer);
+ }
+ else {
+ ap_log_set_writer_init(ap_default_log_writer_init);
+ ap_log_set_writer(ap_default_log_writer);
+ }
+ return NULL;
+}
+static const command_rec config_log_cmds[] =
+{
+AP_INIT_TAKE23("CustomLog", add_custom_log, NULL, RSRC_CONF,
+ "a file name, a custom log format string or format name, "
+ "and an optional \"env=\" or \"expr=\" clause (see docs)"),
+AP_INIT_TAKE23("GlobalLog", add_global_log, NULL, RSRC_CONF,
+ "Same as CustomLog, but forces virtualhosts to inherit the log"),
+AP_INIT_TAKE1("TransferLog", set_transfer_log, NULL, RSRC_CONF,
+ "the filename of the access log"),
+AP_INIT_TAKE12("LogFormat", log_format, NULL, RSRC_CONF,
+ "a log format string (see docs) and an optional format name"),
+AP_INIT_FLAG("BufferedLogs", set_buffered_logs_on, NULL, RSRC_CONF,
+ "Enable Buffered Logging (experimental)"),
+ {NULL}
+};
+
+static config_log_state *open_config_log(server_rec *s, apr_pool_t *p,
+ config_log_state *cls,
+ apr_array_header_t *default_format)
+{
+ if (cls->log_writer != NULL) {
+ return cls; /* virtual config shared w/main server */
+ }
+
+ if (cls->fname == NULL) {
+ return cls; /* Leave it NULL to decline. */
+ }
+
+ cls->log_writer = log_writer_init(p, s, cls->fname);
+ if (cls->log_writer == NULL)
+ return NULL;
+
+ return cls;
+}
+
+static int open_multi_logs(server_rec *s, apr_pool_t *p)
+{
+ int i;
+ multi_log_state *mls = ap_get_module_config(s->module_config,
+ &log_config_module);
+ config_log_state *clsarray;
+ const char *dummy;
+ const char *format;
+
+ if (mls->default_format_string) {
+ format = apr_table_get(mls->formats, mls->default_format_string);
+ if (format) {
+ mls->default_format = parse_log_string(p, format, &dummy);
+ }
+ }
+
+ if (!mls->default_format) {
+ mls->default_format = parse_log_string(p, DEFAULT_LOG_FORMAT, &dummy);
+ }
+
+ if (mls->config_logs->nelts) {
+ clsarray = (config_log_state *) mls->config_logs->elts;
+ for (i = 0; i < mls->config_logs->nelts; ++i) {
+ config_log_state *cls = &clsarray[i];
+
+ if (cls->format_string) {
+ format = apr_table_get(mls->formats, cls->format_string);
+ if (format) {
+ cls->format = parse_log_string(p, format, &dummy);
+ }
+ }
+
+ if (!open_config_log(s, p, cls, mls->default_format)) {
+ /* Failure already logged by open_config_log */
+ return DONE;
+ }
+ }
+ }
+ else if (mls->server_config_logs) {
+ clsarray = (config_log_state *) mls->server_config_logs->elts;
+ for (i = 0; i < mls->server_config_logs->nelts; ++i) {
+ config_log_state *cls = &clsarray[i];
+
+ if (cls->format_string) {
+ format = apr_table_get(mls->formats, cls->format_string);
+ if (format) {
+ cls->format = parse_log_string(p, format, &dummy);
+ }
+ }
+
+ if (!open_config_log(s, p, cls, mls->default_format)) {
+ /* Failure already logged by open_config_log */
+ return DONE;
+ }
+ }
+ }
+
+ return OK;
+}
+
+
+static apr_status_t flush_all_logs(void *data)
+{
+ server_rec *s = data;
+ multi_log_state *mls;
+ apr_array_header_t *log_list;
+ config_log_state *clsarray;
+ buffered_log *buf;
+ int i;
+
+ if (!buffered_logs)
+ return APR_SUCCESS;
+
+ for (; s; s = s->next) {
+ mls = ap_get_module_config(s->module_config, &log_config_module);
+ log_list = NULL;
+ if (mls->config_logs->nelts) {
+ log_list = mls->config_logs;
+ }
+ else if (mls->server_config_logs) {
+ log_list = mls->server_config_logs;
+ }
+ if (log_list) {
+ clsarray = (config_log_state *) log_list->elts;
+ for (i = 0; i < log_list->nelts; ++i) {
+ buf = clsarray[i].log_writer;
+ flush_log(buf);
+ }
+ }
+ }
+ return APR_SUCCESS;
+}
+
+
+static int init_config_log(apr_pool_t *pc, apr_pool_t *p, apr_pool_t *pt, server_rec *s)
+{
+ int res;
+
+ /* First init the buffered logs array, which is needed when opening the logs. */
+ if (buffered_logs) {
+ all_buffered_logs = apr_array_make(p, 5, sizeof(buffered_log *));
+ }
+
+ /* Next, do "physical" server, which gets default log fd and format
+ * for the virtual servers, if they don't override...
+ */
+ res = open_multi_logs(s, p);
+
+ /* Then, virtual servers */
+
+ for (s = s->next; (res == OK) && s; s = s->next) {
+ res = open_multi_logs(s, p);
+ }
+
+ return res;
+}
+
+static void init_child(apr_pool_t *p, server_rec *s)
+{
+ int mpm_threads;
+
+ ap_mpm_query(AP_MPMQ_MAX_THREADS, &mpm_threads);
+
+ /* Now register the last buffer flush with the cleanup engine */
+ if (buffered_logs) {
+ int i;
+ buffered_log **array = (buffered_log **)all_buffered_logs->elts;
+
+ apr_pool_cleanup_register(p, s, flush_all_logs, flush_all_logs);
+
+ for (i = 0; i < all_buffered_logs->nelts; i++) {
+ buffered_log *this = array[i];
+
+#if APR_HAS_THREADS
+ if (mpm_threads > 1) {
+ apr_status_t rv;
+
+ this->mutex.type = apr_anylock_threadmutex;
+ rv = apr_thread_mutex_create(&this->mutex.lock.tm,
+ APR_THREAD_MUTEX_DEFAULT,
+ p);
+ if (rv != APR_SUCCESS) {
+ ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s, APLOGNO(00647)
+ "could not initialize buffered log mutex, "
+ "transfer log may become corrupted");
+ this->mutex.type = apr_anylock_none;
+ }
+ }
+ else
+#endif
+ {
+ this->mutex.type = apr_anylock_none;
+ }
+ }
+ }
+}
+
+static void ap_register_log_handler(apr_pool_t *p, char *tag,
+ ap_log_handler_fn_t *handler, int def)
+{
+ ap_log_handler *log_struct = apr_palloc(p, sizeof(*log_struct));
+ log_struct->func = handler;
+ log_struct->want_orig_default = def;
+
+ apr_hash_set(log_hash, tag, strlen(tag), (const void *)log_struct);
+}
+static ap_log_writer_init *ap_log_set_writer_init(ap_log_writer_init *handle)
+{
+ ap_log_writer_init *old = log_writer_init;
+ log_writer_init = handle;
+
+ return old;
+
+}
+static ap_log_writer *ap_log_set_writer(ap_log_writer *handle)
+{
+ ap_log_writer *old = log_writer;
+ log_writer = handle;
+
+ return old;
+}
+
+static apr_status_t ap_default_log_writer( request_rec *r,
+ void *handle,
+ const char **strs,
+ int *strl,
+ int nelts,
+ apr_size_t len)
+
+{
+ char *str;
+ char *s;
+ int i;
+ apr_status_t rv;
+
+ /*
+ * We do this memcpy dance because write() is atomic for len < PIPE_BUF,
+ * while writev() need not be.
+ */
+ str = apr_palloc(r->pool, len + 1);
+
+ for (i = 0, s = str; i < nelts; ++i) {
+ memcpy(s, strs[i], strl[i]);
+ s += strl[i];
+ }
+
+ rv = apr_file_write((apr_file_t*)handle, str, &len);
+
+ return rv;
+}
+static void *ap_default_log_writer_init(apr_pool_t *p, server_rec *s,
+ const char* name)
+{
+ if (*name == '|') {
+ piped_log *pl;
+
+ pl = ap_open_piped_log(p, name + 1);
+ if (pl == NULL) {
+ return NULL;
+ }
+ return ap_piped_log_write_fd(pl);
+ }
+ else {
+ const char *fname = ap_server_root_relative(p, name);
+ apr_file_t *fd;
+ apr_status_t rv;
+
+ if (!fname) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, APR_EBADPATH, s, APLOGNO(00648)
+ "invalid transfer log path %s.", name);
+ return NULL;
+ }
+ rv = apr_file_open(&fd, fname, xfer_flags, xfer_perms, p);
+ if (rv != APR_SUCCESS) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(00649)
+ "could not open transfer log file %s.", fname);
+ return NULL;
+ }
+ return fd;
+ }
+}
+static void *ap_buffered_log_writer_init(apr_pool_t *p, server_rec *s,
+ const char* name)
+{
+ buffered_log *b;
+ b = apr_pcalloc(p, sizeof(buffered_log));
+ b->handle = ap_default_log_writer_init(p, s, name);
+
+ if (b->handle) {
+ *(buffered_log **)apr_array_push(all_buffered_logs) = b;
+ return b;
+ }
+ else
+ return NULL;
+}
+static apr_status_t ap_buffered_log_writer(request_rec *r,
+ void *handle,
+ const char **strs,
+ int *strl,
+ int nelts,
+ apr_size_t len)
+
+{
+ char *str;
+ char *s;
+ int i;
+ apr_status_t rv;
+ buffered_log *buf = (buffered_log*)handle;
+
+ if ((rv = APR_ANYLOCK_LOCK(&buf->mutex)) != APR_SUCCESS) {
+ return rv;
+ }
+
+ if (len + buf->outcnt > LOG_BUFSIZE) {
+ flush_log(buf);
+ }
+ if (len >= LOG_BUFSIZE) {
+ apr_size_t w;
+
+ /*
+ * We do this memcpy dance because write() is atomic for
+ * len < PIPE_BUF, while writev() need not be.
+ */
+ str = apr_palloc(r->pool, len + 1);
+ for (i = 0, s = str; i < nelts; ++i) {
+ memcpy(s, strs[i], strl[i]);
+ s += strl[i];
+ }
+ w = len;
+ rv = apr_file_write_full(buf->handle, str, w, NULL);
+
+ }
+ else {
+ for (i = 0, s = &buf->outbuf[buf->outcnt]; i < nelts; ++i) {
+ memcpy(s, strs[i], strl[i]);
+ s += strl[i];
+ }
+ buf->outcnt += len;
+ rv = APR_SUCCESS;
+ }
+
+ APR_ANYLOCK_UNLOCK(&buf->mutex);
+ return rv;
+}
+
+static int log_pre_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp)
+{
+ static APR_OPTIONAL_FN_TYPE(ap_register_log_handler) *log_pfn_register;
+
+ log_pfn_register = APR_RETRIEVE_OPTIONAL_FN(ap_register_log_handler);
+
+ if (log_pfn_register) {
+ log_pfn_register(p, "h", log_remote_host, 0);
+ log_pfn_register(p, "a", log_remote_address, 0 );
+ log_pfn_register(p, "A", log_local_address, 0 );
+ log_pfn_register(p, "l", log_remote_logname, 0);
+ log_pfn_register(p, "u", log_remote_user, 0);
+ log_pfn_register(p, "t", log_request_time, 0);
+ log_pfn_register(p, "f", log_request_file, 0);
+ log_pfn_register(p, "b", clf_log_bytes_sent, 0);
+ log_pfn_register(p, "B", log_bytes_sent, 0);
+ log_pfn_register(p, "i", log_header_in, 0);
+ log_pfn_register(p, "o", log_header_out, 0);
+ log_pfn_register(p, "n", log_note, 0);
+ log_pfn_register(p, "L", log_log_id, 1);
+ log_pfn_register(p, "e", log_env_var, 0);
+ log_pfn_register(p, "V", log_server_name, 0);
+ log_pfn_register(p, "v", log_virtual_host, 0);
+ log_pfn_register(p, "p", log_server_port, 0);
+ log_pfn_register(p, "P", log_pid_tid, 0);
+ log_pfn_register(p, "H", log_request_protocol, 0);
+ log_pfn_register(p, "m", log_request_method, 0);
+ log_pfn_register(p, "q", log_request_query, 0);
+ log_pfn_register(p, "X", log_connection_status, 0);
+ log_pfn_register(p, "C", log_cookie, 0);
+ log_pfn_register(p, "k", log_requests_on_connection, 0);
+ log_pfn_register(p, "r", log_request_line, 1);
+ log_pfn_register(p, "D", log_request_duration_microseconds, 1);
+ log_pfn_register(p, "T", log_request_duration_scaled, 1);
+ log_pfn_register(p, "U", log_request_uri, 1);
+ log_pfn_register(p, "s", log_status, 1);
+ log_pfn_register(p, "R", log_handler, 1);
+
+ log_pfn_register(p, "^ti", log_trailer_in, 0);
+ log_pfn_register(p, "^to", log_trailer_out, 0);
+ }
+
+ /* reset to default conditions */
+ ap_log_set_writer_init(ap_default_log_writer_init);
+ ap_log_set_writer(ap_default_log_writer);
+ buffered_logs = 0;
+
+ return OK;
+}
+
+static int check_log_dir(apr_pool_t *p, server_rec *s, config_log_state *cls)
+{
+ if (!cls->fname || cls->fname[0] == '|' || !cls->directive) {
+ return OK;
+ }
+ else {
+ char *abs = ap_server_root_relative(p, cls->fname);
+ char *dir = ap_make_dirstr_parent(p, abs);
+ apr_finfo_t finfo;
+ const ap_directive_t *directive = cls->directive;
+ apr_status_t rv = apr_stat(&finfo, dir, APR_FINFO_TYPE, p);
+ cls->directive = NULL; /* Don't check this config_log_state again */
+ if (rv == APR_SUCCESS && finfo.filetype != APR_DIR)
+ rv = APR_ENOTDIR;
+ if (rv != APR_SUCCESS) {
+ ap_log_error(APLOG_MARK, APLOG_STARTUP|APLOG_EMERG, rv, s,
+ APLOGNO(02297)
+ "Cannot access directory '%s' for log file '%s' "
+ "defined at %s:%d", dir, cls->fname,
+ directive->filename, directive->line_num);
+ return !OK;
+ }
+ }
+ return OK;
+}
+
+static int log_check_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s)
+{
+ int rv = OK;
+ while (s) {
+ multi_log_state *mls = ap_get_module_config(s->module_config,
+ &log_config_module);
+ /*
+ * We don't need to check mls->server_config_logs because it just
+ * points to the parent server's mls->config_logs.
+ */
+ apr_array_header_t *log_list = mls->config_logs;
+ config_log_state *clsarray = (config_log_state *) log_list->elts;
+ int i;
+ for (i = 0; i < log_list->nelts; ++i) {
+ if (check_log_dir(ptemp, s, &clsarray[i]) != OK)
+ rv = !OK;
+ }
+
+ s = s->next;
+ }
+ return rv;
+}
+
+static void register_hooks(apr_pool_t *p)
+{
+ ap_hook_pre_config(log_pre_config,NULL,NULL,APR_HOOK_REALLY_FIRST);
+ ap_hook_check_config(log_check_config,NULL,NULL,APR_HOOK_MIDDLE);
+ ap_hook_child_init(init_child,NULL,NULL,APR_HOOK_MIDDLE);
+ ap_hook_open_logs(init_config_log,NULL,NULL,APR_HOOK_MIDDLE);
+ ap_hook_log_transaction(multi_log_transaction,NULL,NULL,APR_HOOK_MIDDLE);
+
+ /* Init log_hash before we register the optional function. It is
+ * possible for the optional function, ap_register_log_handler,
+ * to be called before any other mod_log_config hooks are called.
+ * As a policy, we should init everything required by an optional function
+ * before calling APR_REGISTER_OPTIONAL_FN.
+ */
+ log_hash = apr_hash_make(p);
+ APR_REGISTER_OPTIONAL_FN(ap_register_log_handler);
+ APR_REGISTER_OPTIONAL_FN(ap_log_set_writer_init);
+ APR_REGISTER_OPTIONAL_FN(ap_log_set_writer);
+}
+
+AP_DECLARE_MODULE(log_config) =
+{
+ STANDARD20_MODULE_STUFF,
+ NULL, /* create per-dir config */
+ NULL, /* merge per-dir config */
+ make_config_log_state, /* server config */
+ merge_config_log_state, /* merge server config */
+ config_log_cmds, /* command apr_table_t */
+ register_hooks /* register hooks */
+};
+
diff --git a/modules/loggers/mod_log_config.dep b/modules/loggers/mod_log_config.dep
new file mode 100644
index 0000000..8107bd9
--- /dev/null
+++ b/modules/loggers/mod_log_config.dep
@@ -0,0 +1,62 @@
+# Microsoft Developer Studio Generated Dependency File, included by mod_log_config.mak
+
+..\..\build\win32\httpd.rc : \
+ "..\..\include\ap_release.h"\
+
+
+.\mod_log_config.c : \
+ "..\..\include\ap_config.h"\
+ "..\..\include\ap_config_layout.h"\
+ "..\..\include\ap_expr.h"\
+ "..\..\include\ap_hooks.h"\
+ "..\..\include\ap_mmn.h"\
+ "..\..\include\ap_mpm.h"\
+ "..\..\include\ap_regex.h"\
+ "..\..\include\ap_release.h"\
+ "..\..\include\apache_noprobes.h"\
+ "..\..\include\http_config.h"\
+ "..\..\include\http_core.h"\
+ "..\..\include\http_log.h"\
+ "..\..\include\http_protocol.h"\
+ "..\..\include\httpd.h"\
+ "..\..\include\os.h"\
+ "..\..\include\scoreboard.h"\
+ "..\..\include\util_cfgtree.h"\
+ "..\..\include\util_filter.h"\
+ "..\..\include\util_time.h"\
+ "..\..\srclib\apr-util\include\apr_anylock.h"\
+ "..\..\srclib\apr-util\include\apr_buckets.h"\
+ "..\..\srclib\apr-util\include\apr_hooks.h"\
+ "..\..\srclib\apr-util\include\apr_optional.h"\
+ "..\..\srclib\apr-util\include\apr_optional_hooks.h"\
+ "..\..\srclib\apr-util\include\apr_uri.h"\
+ "..\..\srclib\apr-util\include\apu.h"\
+ "..\..\srclib\apr\include\apr.h"\
+ "..\..\srclib\apr\include\apr_allocator.h"\
+ "..\..\srclib\apr\include\apr_dso.h"\
+ "..\..\srclib\apr\include\apr_errno.h"\
+ "..\..\srclib\apr\include\apr_file_info.h"\
+ "..\..\srclib\apr\include\apr_file_io.h"\
+ "..\..\srclib\apr\include\apr_general.h"\
+ "..\..\srclib\apr\include\apr_global_mutex.h"\
+ "..\..\srclib\apr\include\apr_hash.h"\
+ "..\..\srclib\apr\include\apr_inherit.h"\
+ "..\..\srclib\apr\include\apr_lib.h"\
+ "..\..\srclib\apr\include\apr_mmap.h"\
+ "..\..\srclib\apr\include\apr_network_io.h"\
+ "..\..\srclib\apr\include\apr_poll.h"\
+ "..\..\srclib\apr\include\apr_pools.h"\
+ "..\..\srclib\apr\include\apr_portable.h"\
+ "..\..\srclib\apr\include\apr_proc_mutex.h"\
+ "..\..\srclib\apr\include\apr_ring.h"\
+ "..\..\srclib\apr\include\apr_shm.h"\
+ "..\..\srclib\apr\include\apr_strings.h"\
+ "..\..\srclib\apr\include\apr_tables.h"\
+ "..\..\srclib\apr\include\apr_thread_mutex.h"\
+ "..\..\srclib\apr\include\apr_thread_proc.h"\
+ "..\..\srclib\apr\include\apr_thread_rwlock.h"\
+ "..\..\srclib\apr\include\apr_time.h"\
+ "..\..\srclib\apr\include\apr_user.h"\
+ "..\..\srclib\apr\include\apr_want.h"\
+ ".\mod_log_config.h"\
+
diff --git a/modules/loggers/mod_log_config.dsp b/modules/loggers/mod_log_config.dsp
new file mode 100644
index 0000000..2338875
--- /dev/null
+++ b/modules/loggers/mod_log_config.dsp
@@ -0,0 +1,111 @@
+# Microsoft Developer Studio Project File - Name="mod_log_config" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=mod_log_config - Win32 Release
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "mod_log_config.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "mod_log_config.mak" CFG="mod_log_config - Win32 Release"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "mod_log_config - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "mod_log_config - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "mod_log_config - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c
+# ADD CPP /nologo /MD /W3 /O2 /Oy- /Zi /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Release\mod_log_config_src" /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /fo"Release/mod_log_config.res" /i "../../include" /i "../../srclib/apr/include" /d "NDEBUG" /d BIN_NAME="mod_log_config.so" /d LONG_NAME="log_config_module for Apache"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib /nologo /subsystem:windows /dll /out:".\Release\mod_log_config.so" /base:@..\..\os\win32\BaseAddr.ref,mod_log_config.so
+# ADD LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:".\Release\mod_log_config.so" /base:@..\..\os\win32\BaseAddr.ref,mod_log_config.so /opt:ref
+# Begin Special Build Tool
+TargetPath=.\Release\mod_log_config.so
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2
+# End Special Build Tool
+
+!ELSEIF "$(CFG)" == "mod_log_config - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MDd /W3 /EHsc /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /c
+# ADD CPP /nologo /MDd /W3 /EHsc /Zi /Od /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Debug\mod_log_config_src" /FD /c
+# ADD BASE MTL /nologo /D "_DEBUG" /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /fo"Debug/mod_log_config.res" /i "../../include" /i "../../srclib/apr/include" /d "_DEBUG" /d BIN_NAME="mod_log_config.so" /d LONG_NAME="log_config_module for Apache"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:".\Debug\mod_log_config.so" /base:@..\..\os\win32\BaseAddr.ref,mod_log_config.so
+# ADD LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:".\Debug\mod_log_config.so" /base:@..\..\os\win32\BaseAddr.ref,mod_log_config.so
+# Begin Special Build Tool
+TargetPath=.\Debug\mod_log_config.so
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2
+# End Special Build Tool
+
+!ENDIF
+
+# Begin Target
+
+# Name "mod_log_config - Win32 Release"
+# Name "mod_log_config - Win32 Debug"
+# Begin Source File
+
+SOURCE=.\mod_log_config.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\build\win32\httpd.rc
+# End Source File
+# End Target
+# End Project
diff --git a/modules/loggers/mod_log_config.exp b/modules/loggers/mod_log_config.exp
new file mode 100644
index 0000000..0749e52
--- /dev/null
+++ b/modules/loggers/mod_log_config.exp
@@ -0,0 +1 @@
+log_config_module
diff --git a/modules/loggers/mod_log_config.h b/modules/loggers/mod_log_config.h
new file mode 100644
index 0000000..877a593
--- /dev/null
+++ b/modules/loggers/mod_log_config.h
@@ -0,0 +1,74 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file mod_log_config.h
+ * @brief Logging Configuration Extension Module for Apache
+ *
+ * @defgroup MOD_LOG_CONFIG mod_log_config
+ * @ingroup APACHE_MODS
+ * @{
+ */
+
+#include "apr_optional.h"
+#include "httpd.h"
+#include "scoreboard.h"
+
+#ifndef _MOD_LOG_CONFIG_H
+#define _MOD_LOG_CONFIG_H 1
+
+/**
+ * callback function prototype for a external log handler
+ */
+typedef const char *ap_log_handler_fn_t(request_rec *r, char *a);
+
+/**
+ * callback function prototype for external writer initialization.
+ */
+typedef void *ap_log_writer_init(apr_pool_t *p, server_rec *s,
+ const char *name);
+/**
+ * callback which gets called where there is a log line to write.
+ */
+typedef apr_status_t ap_log_writer(
+ request_rec *r,
+ void *handle,
+ const char **portions,
+ int *lengths,
+ int nelts,
+ apr_size_t len);
+
+typedef struct ap_log_handler {
+ ap_log_handler_fn_t *func;
+ int want_orig_default;
+} ap_log_handler;
+
+APR_DECLARE_OPTIONAL_FN(void, ap_register_log_handler,
+ (apr_pool_t *p, char *tag, ap_log_handler_fn_t *func,
+ int def));
+/**
+ * you will need to set your init handler *BEFORE* the open_logs
+ * in mod_log_config gets executed
+ */
+APR_DECLARE_OPTIONAL_FN(ap_log_writer_init*, ap_log_set_writer_init,(ap_log_writer_init *func));
+/**
+ * you should probably set the writer at the same time (ie..before open_logs)
+ */
+APR_DECLARE_OPTIONAL_FN(ap_log_writer*, ap_log_set_writer, (ap_log_writer* func));
+
+#endif /* MOD_LOG_CONFIG */
+/** @} */
+
diff --git a/modules/loggers/mod_log_config.mak b/modules/loggers/mod_log_config.mak
new file mode 100644
index 0000000..df9ddf6
--- /dev/null
+++ b/modules/loggers/mod_log_config.mak
@@ -0,0 +1,353 @@
+# Microsoft Developer Studio Generated NMAKE File, Based on mod_log_config.dsp
+!IF "$(CFG)" == ""
+CFG=mod_log_config - Win32 Release
+!MESSAGE No configuration specified. Defaulting to mod_log_config - Win32 Release.
+!ENDIF
+
+!IF "$(CFG)" != "mod_log_config - Win32 Release" && "$(CFG)" != "mod_log_config - Win32 Debug"
+!MESSAGE Invalid configuration "$(CFG)" specified.
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "mod_log_config.mak" CFG="mod_log_config - Win32 Release"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "mod_log_config - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "mod_log_config - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE
+!ERROR An invalid configuration is specified.
+!ENDIF
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE
+NULL=nul
+!ENDIF
+
+!IF "$(CFG)" == "mod_log_config - Win32 Release"
+
+OUTDIR=.\Release
+INTDIR=.\Release
+DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
+# Begin Custom Macros
+OutDir=.\Release
+# End Custom Macros
+
+!IF "$(RECURSE)" == "0"
+
+ALL : "$(OUTDIR)\mod_log_config.so" "$(DS_POSTBUILD_DEP)"
+
+!ELSE
+
+ALL : "libhttpd - Win32 Release" "libaprutil - Win32 Release" "libapr - Win32 Release" "$(OUTDIR)\mod_log_config.so" "$(DS_POSTBUILD_DEP)"
+
+!ENDIF
+
+!IF "$(RECURSE)" == "1"
+CLEAN :"libapr - Win32 ReleaseCLEAN" "libaprutil - Win32 ReleaseCLEAN" "libhttpd - Win32 ReleaseCLEAN"
+!ELSE
+CLEAN :
+!ENDIF
+ -@erase "$(INTDIR)\mod_log_config.obj"
+ -@erase "$(INTDIR)\mod_log_config.res"
+ -@erase "$(INTDIR)\mod_log_config_src.idb"
+ -@erase "$(INTDIR)\mod_log_config_src.pdb"
+ -@erase "$(OUTDIR)\mod_log_config.exp"
+ -@erase "$(OUTDIR)\mod_log_config.lib"
+ -@erase "$(OUTDIR)\mod_log_config.pdb"
+ -@erase "$(OUTDIR)\mod_log_config.so"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /MD /W3 /Zi /O2 /Oy- /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\mod_log_config_src" /FD /c
+
+.c{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.c{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+MTL=midl.exe
+MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /win32
+RSC=rc.exe
+RSC_PROJ=/l 0x409 /fo"$(INTDIR)\mod_log_config.res" /i "../../include" /i "../../srclib/apr/include" /d "NDEBUG" /d BIN_NAME="mod_log_config.so" /d LONG_NAME="log_config_module for Apache"
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\mod_log_config.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+LINK32_FLAGS=kernel32.lib /nologo /subsystem:windows /dll /incremental:no /pdb:"$(OUTDIR)\mod_log_config.pdb" /debug /out:"$(OUTDIR)\mod_log_config.so" /implib:"$(OUTDIR)\mod_log_config.lib" /base:@..\..\os\win32\BaseAddr.ref,mod_log_config.so /opt:ref
+LINK32_OBJS= \
+ "$(INTDIR)\mod_log_config.obj" \
+ "$(INTDIR)\mod_log_config.res" \
+ "..\..\srclib\apr\Release\libapr-1.lib" \
+ "..\..\srclib\apr-util\Release\libaprutil-1.lib" \
+ "..\..\Release\libhttpd.lib"
+
+"$(OUTDIR)\mod_log_config.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+TargetPath=.\Release\mod_log_config.so
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
+
+# Begin Custom Macros
+OutDir=.\Release
+# End Custom Macros
+
+"$(DS_POSTBUILD_DEP)" : "$(OUTDIR)\mod_log_config.so"
+ if exist .\Release\mod_log_config.so.manifest mt.exe -manifest .\Release\mod_log_config.so.manifest -outputresource:.\Release\mod_log_config.so;2
+ echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)"
+
+!ELSEIF "$(CFG)" == "mod_log_config - Win32 Debug"
+
+OUTDIR=.\Debug
+INTDIR=.\Debug
+DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
+# Begin Custom Macros
+OutDir=.\Debug
+# End Custom Macros
+
+!IF "$(RECURSE)" == "0"
+
+ALL : "$(OUTDIR)\mod_log_config.so" "$(DS_POSTBUILD_DEP)"
+
+!ELSE
+
+ALL : "libhttpd - Win32 Debug" "libaprutil - Win32 Debug" "libapr - Win32 Debug" "$(OUTDIR)\mod_log_config.so" "$(DS_POSTBUILD_DEP)"
+
+!ENDIF
+
+!IF "$(RECURSE)" == "1"
+CLEAN :"libapr - Win32 DebugCLEAN" "libaprutil - Win32 DebugCLEAN" "libhttpd - Win32 DebugCLEAN"
+!ELSE
+CLEAN :
+!ENDIF
+ -@erase "$(INTDIR)\mod_log_config.obj"
+ -@erase "$(INTDIR)\mod_log_config.res"
+ -@erase "$(INTDIR)\mod_log_config_src.idb"
+ -@erase "$(INTDIR)\mod_log_config_src.pdb"
+ -@erase "$(OUTDIR)\mod_log_config.exp"
+ -@erase "$(OUTDIR)\mod_log_config.lib"
+ -@erase "$(OUTDIR)\mod_log_config.pdb"
+ -@erase "$(OUTDIR)\mod_log_config.so"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /MDd /W3 /Zi /Od /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\mod_log_config_src" /FD /EHsc /c
+
+.c{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.c{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+MTL=midl.exe
+MTL_PROJ=/nologo /D "_DEBUG" /mktyplib203 /win32
+RSC=rc.exe
+RSC_PROJ=/l 0x409 /fo"$(INTDIR)\mod_log_config.res" /i "../../include" /i "../../srclib/apr/include" /d "_DEBUG" /d BIN_NAME="mod_log_config.so" /d LONG_NAME="log_config_module for Apache"
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\mod_log_config.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+LINK32_FLAGS=kernel32.lib /nologo /subsystem:windows /dll /incremental:no /pdb:"$(OUTDIR)\mod_log_config.pdb" /debug /out:"$(OUTDIR)\mod_log_config.so" /implib:"$(OUTDIR)\mod_log_config.lib" /base:@..\..\os\win32\BaseAddr.ref,mod_log_config.so
+LINK32_OBJS= \
+ "$(INTDIR)\mod_log_config.obj" \
+ "$(INTDIR)\mod_log_config.res" \
+ "..\..\srclib\apr\Debug\libapr-1.lib" \
+ "..\..\srclib\apr-util\Debug\libaprutil-1.lib" \
+ "..\..\Debug\libhttpd.lib"
+
+"$(OUTDIR)\mod_log_config.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+TargetPath=.\Debug\mod_log_config.so
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
+
+# Begin Custom Macros
+OutDir=.\Debug
+# End Custom Macros
+
+"$(DS_POSTBUILD_DEP)" : "$(OUTDIR)\mod_log_config.so"
+ if exist .\Debug\mod_log_config.so.manifest mt.exe -manifest .\Debug\mod_log_config.so.manifest -outputresource:.\Debug\mod_log_config.so;2
+ echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)"
+
+!ENDIF
+
+
+!IF "$(NO_EXTERNAL_DEPS)" != "1"
+!IF EXISTS("mod_log_config.dep")
+!INCLUDE "mod_log_config.dep"
+!ELSE
+!MESSAGE Warning: cannot find "mod_log_config.dep"
+!ENDIF
+!ENDIF
+
+
+!IF "$(CFG)" == "mod_log_config - Win32 Release" || "$(CFG)" == "mod_log_config - Win32 Debug"
+
+!IF "$(CFG)" == "mod_log_config - Win32 Release"
+
+"libapr - Win32 Release" :
+ cd ".\..\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Release"
+ cd "..\..\modules\loggers"
+
+"libapr - Win32 ReleaseCLEAN" :
+ cd ".\..\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Release" RECURSE=1 CLEAN
+ cd "..\..\modules\loggers"
+
+!ELSEIF "$(CFG)" == "mod_log_config - Win32 Debug"
+
+"libapr - Win32 Debug" :
+ cd ".\..\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Debug"
+ cd "..\..\modules\loggers"
+
+"libapr - Win32 DebugCLEAN" :
+ cd ".\..\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Debug" RECURSE=1 CLEAN
+ cd "..\..\modules\loggers"
+
+!ENDIF
+
+!IF "$(CFG)" == "mod_log_config - Win32 Release"
+
+"libaprutil - Win32 Release" :
+ cd ".\..\..\srclib\apr-util"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Release"
+ cd "..\..\modules\loggers"
+
+"libaprutil - Win32 ReleaseCLEAN" :
+ cd ".\..\..\srclib\apr-util"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Release" RECURSE=1 CLEAN
+ cd "..\..\modules\loggers"
+
+!ELSEIF "$(CFG)" == "mod_log_config - Win32 Debug"
+
+"libaprutil - Win32 Debug" :
+ cd ".\..\..\srclib\apr-util"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Debug"
+ cd "..\..\modules\loggers"
+
+"libaprutil - Win32 DebugCLEAN" :
+ cd ".\..\..\srclib\apr-util"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Debug" RECURSE=1 CLEAN
+ cd "..\..\modules\loggers"
+
+!ENDIF
+
+!IF "$(CFG)" == "mod_log_config - Win32 Release"
+
+"libhttpd - Win32 Release" :
+ cd ".\..\.."
+ $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Release"
+ cd ".\modules\loggers"
+
+"libhttpd - Win32 ReleaseCLEAN" :
+ cd ".\..\.."
+ $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Release" RECURSE=1 CLEAN
+ cd ".\modules\loggers"
+
+!ELSEIF "$(CFG)" == "mod_log_config - Win32 Debug"
+
+"libhttpd - Win32 Debug" :
+ cd ".\..\.."
+ $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Debug"
+ cd ".\modules\loggers"
+
+"libhttpd - Win32 DebugCLEAN" :
+ cd ".\..\.."
+ $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Debug" RECURSE=1 CLEAN
+ cd ".\modules\loggers"
+
+!ENDIF
+
+SOURCE=..\..\build\win32\httpd.rc
+
+!IF "$(CFG)" == "mod_log_config - Win32 Release"
+
+
+"$(INTDIR)\mod_log_config.res" : $(SOURCE) "$(INTDIR)"
+ $(RSC) /l 0x409 /fo"$(INTDIR)\mod_log_config.res" /i "../../include" /i "../../srclib/apr/include" /i "../../build\win32" /d "NDEBUG" /d BIN_NAME="mod_log_config.so" /d LONG_NAME="log_config_module for Apache" $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "mod_log_config - Win32 Debug"
+
+
+"$(INTDIR)\mod_log_config.res" : $(SOURCE) "$(INTDIR)"
+ $(RSC) /l 0x409 /fo"$(INTDIR)\mod_log_config.res" /i "../../include" /i "../../srclib/apr/include" /i "../../build\win32" /d "_DEBUG" /d BIN_NAME="mod_log_config.so" /d LONG_NAME="log_config_module for Apache" $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=.\mod_log_config.c
+
+"$(INTDIR)\mod_log_config.obj" : $(SOURCE) "$(INTDIR)"
+
+
+
+!ENDIF
+
diff --git a/modules/loggers/mod_log_debug.c b/modules/loggers/mod_log_debug.c
new file mode 100644
index 0000000..3f27a95
--- /dev/null
+++ b/modules/loggers/mod_log_debug.c
@@ -0,0 +1,295 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "apr_strings.h"
+
+#include "httpd.h"
+#include "http_config.h"
+#include "http_log.h"
+#include "http_protocol.h"
+#include "http_request.h"
+#include "ap_expr.h"
+
+extern module AP_MODULE_DECLARE_DATA log_debug_module;
+
+typedef struct {
+ ap_expr_info_t *msg_expr;
+ ap_expr_info_t *condition;
+ const char *hook;
+} msg_entry;
+
+typedef struct {
+ apr_array_header_t *entries;
+} log_debug_dirconf;
+
+static const char *allhooks = "all";
+static const char * const hooks[] = {
+ "log_transaction", /* 0 */
+ "quick_handler", /* 1 */
+ "handler", /* 2 */
+ "translate_name", /* 3 */
+ "map_to_storage", /* 4 */
+ "fixups", /* 5 */
+ "type_checker", /* 6 */
+ "check_access", /* 7 */
+ "check_access_ex", /* 8 */
+ "check_authn", /* 9 */
+ "check_authz", /* 10 */
+ "insert_filter", /* 11 */
+ "pre_translate_name", /* 12 */
+ NULL
+};
+
+static void do_debug_log(request_rec *r, const char *hookname)
+{
+ log_debug_dirconf *dconf = ap_get_module_config(r->per_dir_config, &log_debug_module);
+ int i;
+ if (dconf->entries == NULL)
+ return;
+
+ for (i = 0; i < dconf->entries->nelts; i++) {
+ const char *msg, *err;
+ msg_entry *entry = APR_ARRAY_IDX(dconf->entries, i, msg_entry *);
+ if (entry->hook != allhooks && entry->hook != hookname)
+ continue;
+ if (entry->condition) {
+ int ret = ap_expr_exec(r, entry->condition, &err);
+ if (err) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00640)
+ "Can't evaluate condition: %s", err);
+ continue;
+ }
+ if (!ret)
+ continue;
+ }
+ msg = ap_expr_str_exec(r, entry->msg_expr, &err);
+ if (err)
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00641)
+ "Can't evaluate message expression: %s", err);
+ if (APLOGrdebug(r))
+ /* Intentional no APLOGNO */
+ ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
+ "%s (%s hook, %s:%d)",
+ msg, hookname, entry->msg_expr->filename,
+ entry->msg_expr->line_number);
+ else
+ /* Intentional no APLOGNO */
+ ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
+ "%s", msg);
+ }
+}
+
+static int log_debug_log_transaction(request_rec *r)
+{
+ do_debug_log(r, hooks[0]);
+ return DECLINED;
+}
+
+static int log_debug_quick_handler(request_rec *r, int lookup_uri)
+{
+ do_debug_log(r, hooks[1]);
+ return DECLINED;
+}
+
+static int log_debug_handler(request_rec *r)
+{
+ do_debug_log(r, hooks[2]);
+ return DECLINED;
+}
+
+static int log_debug_pre_translate_name(request_rec *r)
+{
+ do_debug_log(r, hooks[12]);
+ return DECLINED;
+}
+
+static int log_debug_translate_name(request_rec *r)
+{
+ do_debug_log(r, hooks[3]);
+ return DECLINED;
+}
+
+static int log_debug_map_to_storage(request_rec *r)
+{
+ do_debug_log(r, hooks[4]);
+ return DECLINED;
+}
+
+static int log_debug_fixups(request_rec *r)
+{
+ do_debug_log(r, hooks[5]);
+ return DECLINED;
+}
+
+static int log_debug_type_checker(request_rec *r)
+{
+ do_debug_log(r, hooks[6]);
+ return DECLINED;
+}
+
+static int log_debug_check_access(request_rec *r)
+{
+ do_debug_log(r, hooks[7]);
+ return DECLINED;
+}
+
+static int log_debug_check_access_ex(request_rec *r)
+{
+ do_debug_log(r, hooks[8]);
+ return DECLINED;
+}
+
+static int log_debug_check_authn(request_rec *r)
+{
+ do_debug_log(r, hooks[9]);
+ return DECLINED;
+}
+
+static int log_debug_check_authz(request_rec *r)
+{
+ do_debug_log(r, hooks[10]);
+ return DECLINED;
+}
+
+static void log_debug_insert_filter(request_rec *r)
+{
+ do_debug_log(r, hooks[11]);
+}
+
+static void *log_debug_create_dconf(apr_pool_t *p, char *dirspec)
+{
+ log_debug_dirconf *dconf = apr_pcalloc(p, sizeof(log_debug_dirconf));
+ return dconf;
+}
+
+static void *log_debug_merge_dconf(apr_pool_t *p, void *parent_conf, void *new_conf)
+{
+ log_debug_dirconf *merged = apr_pcalloc(p, sizeof(log_debug_dirconf));
+ const log_debug_dirconf *parent = parent_conf;
+ const log_debug_dirconf *new = new_conf;
+
+ if (parent->entries == NULL)
+ merged->entries = new->entries;
+ else if (new->entries == NULL)
+ merged->entries = parent->entries;
+ else
+ /* apr_array_append actually creates a new array */
+ merged->entries = apr_array_append(p, parent->entries, new->entries);
+
+ return merged;
+}
+
+static const char *cmd_log_message(cmd_parms *cmd, void *dconf_, const char *arg1,
+ const char *arg2, const char *arg3)
+{
+ msg_entry *entry = apr_pcalloc(cmd->pool, sizeof(msg_entry));
+ log_debug_dirconf *dconf = dconf_;
+ int i, j;
+ const char *err;
+ const char *args[2];
+ args[0] = arg2;
+ args[1] = arg3;
+
+ entry->msg_expr = ap_expr_parse_cmd(cmd, arg1, AP_EXPR_FLAG_STRING_RESULT|
+ AP_EXPR_FLAG_DONT_VARY,
+ &err, NULL);
+ if (err)
+ return apr_psprintf(cmd->pool,
+ "Could not parse message expression '%s': %s",
+ arg1, err);
+
+ for (i = 0; i < 2; i++) {
+ if (args[i] == NULL)
+ break;
+
+ if (strncasecmp(args[i], "hook=", 5) == 0) {
+ const char *name = args[i] + 5;
+ j = 0;
+ while (hooks[j]) {
+ if (strcasecmp(hooks[j], name) == 0) {
+ entry->hook = hooks[j];
+ break;
+ }
+ j++;
+ }
+ if (entry->hook == NULL) {
+ if (strcmp(name, "*") == 0 || strcasecmp(name, allhooks) == 0)
+ entry->hook = allhooks;
+ else
+ return apr_psprintf(cmd->pool, "Invalid hook name: %s", name);
+ }
+ }
+ else if (strncasecmp(args[i], "expr=", 5) == 0) {
+ const char *expr = args[i] + 5;
+ entry->condition = ap_expr_parse_cmd(cmd, expr,
+ AP_EXPR_FLAG_DONT_VARY,
+ &err, NULL);
+ if (err)
+ return apr_psprintf(cmd->pool,
+ "Could not parse expression '%s': %s",
+ expr, err);
+ }
+ else {
+ return apr_psprintf(cmd->pool, "Invalid argument %s", args[i]);
+ }
+ }
+ if (entry->hook == NULL)
+ entry->hook = hooks[0];
+
+ if (!dconf->entries)
+ dconf->entries = apr_array_make(cmd->pool, 4, sizeof(msg_entry *));
+
+ APR_ARRAY_PUSH(dconf->entries, msg_entry *) = entry;
+
+ return NULL;
+}
+
+static const command_rec log_debug_cmds[] =
+{
+ AP_INIT_TAKE123("LogMessage", cmd_log_message, NULL, RSRC_CONF|ACCESS_CONF,
+ "Log a debug message to the error log if this config block is used for "
+ " a request"),
+ {NULL}
+};
+
+static void register_hooks(apr_pool_t *p)
+{
+ ap_hook_log_transaction(log_debug_log_transaction, NULL, NULL, APR_HOOK_FIRST);
+ ap_hook_quick_handler(log_debug_quick_handler, NULL, NULL, APR_HOOK_FIRST);
+ ap_hook_handler(log_debug_handler, NULL, NULL, APR_HOOK_FIRST);
+ ap_hook_pre_translate_name(log_debug_pre_translate_name, NULL, NULL, APR_HOOK_FIRST);
+ ap_hook_translate_name(log_debug_translate_name, NULL, NULL, APR_HOOK_FIRST);
+ ap_hook_map_to_storage(log_debug_map_to_storage, NULL, NULL, APR_HOOK_FIRST);
+ ap_hook_fixups(log_debug_fixups, NULL, NULL, APR_HOOK_FIRST);
+ ap_hook_type_checker(log_debug_type_checker, NULL, NULL, APR_HOOK_FIRST);
+ ap_hook_check_access(log_debug_check_access, NULL, NULL, APR_HOOK_FIRST, AP_AUTH_INTERNAL_PER_URI);
+ ap_hook_check_access_ex(log_debug_check_access_ex, NULL, NULL, APR_HOOK_FIRST, AP_AUTH_INTERNAL_PER_URI);
+ ap_hook_check_authn(log_debug_check_authn, NULL, NULL, APR_HOOK_FIRST, AP_AUTH_INTERNAL_PER_URI);
+ ap_hook_check_authz(log_debug_check_authz, NULL, NULL, APR_HOOK_FIRST, AP_AUTH_INTERNAL_PER_URI);
+ ap_hook_insert_filter(log_debug_insert_filter, NULL, NULL, APR_HOOK_FIRST);
+}
+
+AP_DECLARE_MODULE(log_debug) =
+{
+ STANDARD20_MODULE_STUFF,
+ log_debug_create_dconf, /* create per-dir config */
+ log_debug_merge_dconf, /* merge per-dir config */
+ NULL, /* server config */
+ NULL, /* merge server config */
+ log_debug_cmds, /* command apr_table_t */
+ register_hooks /* register hooks */
+};
+
diff --git a/modules/loggers/mod_log_debug.dep b/modules/loggers/mod_log_debug.dep
new file mode 100644
index 0000000..eed5a6d
--- /dev/null
+++ b/modules/loggers/mod_log_debug.dep
@@ -0,0 +1,54 @@
+# Microsoft Developer Studio Generated Dependency File, included by mod_log_debug.mak
+
+..\..\build\win32\httpd.rc : \
+ "..\..\include\ap_release.h"\
+
+
+.\mod_log_debug.c : \
+ "..\..\include\ap_config.h"\
+ "..\..\include\ap_config_layout.h"\
+ "..\..\include\ap_expr.h"\
+ "..\..\include\ap_hooks.h"\
+ "..\..\include\ap_mmn.h"\
+ "..\..\include\ap_regex.h"\
+ "..\..\include\ap_release.h"\
+ "..\..\include\apache_noprobes.h"\
+ "..\..\include\http_config.h"\
+ "..\..\include\http_log.h"\
+ "..\..\include\http_protocol.h"\
+ "..\..\include\http_request.h"\
+ "..\..\include\httpd.h"\
+ "..\..\include\os.h"\
+ "..\..\include\util_cfgtree.h"\
+ "..\..\include\util_filter.h"\
+ "..\..\srclib\apr-util\include\apr_buckets.h"\
+ "..\..\srclib\apr-util\include\apr_hooks.h"\
+ "..\..\srclib\apr-util\include\apr_optional.h"\
+ "..\..\srclib\apr-util\include\apr_optional_hooks.h"\
+ "..\..\srclib\apr-util\include\apr_uri.h"\
+ "..\..\srclib\apr-util\include\apu.h"\
+ "..\..\srclib\apr\include\apr.h"\
+ "..\..\srclib\apr\include\apr_allocator.h"\
+ "..\..\srclib\apr\include\apr_dso.h"\
+ "..\..\srclib\apr\include\apr_errno.h"\
+ "..\..\srclib\apr\include\apr_file_info.h"\
+ "..\..\srclib\apr\include\apr_file_io.h"\
+ "..\..\srclib\apr\include\apr_general.h"\
+ "..\..\srclib\apr\include\apr_global_mutex.h"\
+ "..\..\srclib\apr\include\apr_inherit.h"\
+ "..\..\srclib\apr\include\apr_mmap.h"\
+ "..\..\srclib\apr\include\apr_network_io.h"\
+ "..\..\srclib\apr\include\apr_poll.h"\
+ "..\..\srclib\apr\include\apr_pools.h"\
+ "..\..\srclib\apr\include\apr_portable.h"\
+ "..\..\srclib\apr\include\apr_proc_mutex.h"\
+ "..\..\srclib\apr\include\apr_ring.h"\
+ "..\..\srclib\apr\include\apr_shm.h"\
+ "..\..\srclib\apr\include\apr_strings.h"\
+ "..\..\srclib\apr\include\apr_tables.h"\
+ "..\..\srclib\apr\include\apr_thread_mutex.h"\
+ "..\..\srclib\apr\include\apr_thread_proc.h"\
+ "..\..\srclib\apr\include\apr_time.h"\
+ "..\..\srclib\apr\include\apr_user.h"\
+ "..\..\srclib\apr\include\apr_want.h"\
+
diff --git a/modules/loggers/mod_log_debug.dsp b/modules/loggers/mod_log_debug.dsp
new file mode 100644
index 0000000..f96e2ae
--- /dev/null
+++ b/modules/loggers/mod_log_debug.dsp
@@ -0,0 +1,111 @@
+# Microsoft Developer Studio Project File - Name="mod_log_debug" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=mod_log_debug - Win32 Release
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "mod_log_debug.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "mod_log_debug.mak" CFG="mod_log_debug - Win32 Release"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "mod_log_debug - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "mod_log_debug - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "mod_log_debug - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c
+# ADD CPP /nologo /MD /W3 /O2 /Oy- /Zi /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Release\mod_log_debug_src" /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /fo"Release/mod_log_debug.res" /i "../../include" /i "../../srclib/apr/include" /d "NDEBUG" /d BIN_NAME="mod_log_debug.so" /d LONG_NAME="log_debug_module for Apache"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib /nologo /subsystem:windows /dll /out:".\Release\mod_log_debug.so" /base:@..\..\os\win32\BaseAddr.ref,mod_log_debug.so
+# ADD LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:".\Release\mod_log_debug.so" /base:@..\..\os\win32\BaseAddr.ref,mod_log_debug.so /opt:ref
+# Begin Special Build Tool
+TargetPath=.\Release\mod_log_debug.so
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2
+# End Special Build Tool
+
+!ELSEIF "$(CFG)" == "mod_log_debug - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MDd /W3 /EHsc /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /c
+# ADD CPP /nologo /MDd /W3 /EHsc /Zi /Od /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Debug\mod_log_debug_src" /FD /c
+# ADD BASE MTL /nologo /D "_DEBUG" /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /fo"Debug/mod_log_debug.res" /i "../../include" /i "../../srclib/apr/include" /d "_DEBUG" /d BIN_NAME="mod_log_debug.so" /d LONG_NAME="log_debug_module for Apache"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:".\Debug\mod_log_debug.so" /base:@..\..\os\win32\BaseAddr.ref,mod_log_debug.so
+# ADD LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:".\Debug\mod_log_debug.so" /base:@..\..\os\win32\BaseAddr.ref,mod_log_debug.so
+# Begin Special Build Tool
+TargetPath=.\Debug\mod_log_debug.so
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2
+# End Special Build Tool
+
+!ENDIF
+
+# Begin Target
+
+# Name "mod_log_debug - Win32 Release"
+# Name "mod_log_debug - Win32 Debug"
+# Begin Source File
+
+SOURCE=.\mod_log_debug.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\build\win32\httpd.rc
+# End Source File
+# End Target
+# End Project
diff --git a/modules/loggers/mod_log_debug.mak b/modules/loggers/mod_log_debug.mak
new file mode 100644
index 0000000..94b0bee
--- /dev/null
+++ b/modules/loggers/mod_log_debug.mak
@@ -0,0 +1,325 @@
+# Microsoft Developer Studio Generated NMAKE File, Based on mod_log_debug.dsp
+!IF "$(CFG)" == ""
+CFG=mod_log_debug - Win32 Release
+!MESSAGE No configuration specified. Defaulting to mod_log_debug - Win32 Release.
+!ENDIF
+
+!IF "$(CFG)" != "mod_log_debug - Win32 Release" && "$(CFG)" != "mod_log_debug - Win32 Debug"
+!MESSAGE Invalid configuration "$(CFG)" specified.
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "mod_log_debug.mak" CFG="mod_log_debug - Win32 Release"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "mod_log_debug - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "mod_log_debug - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE
+!ERROR An invalid configuration is specified.
+!ENDIF
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE
+NULL=nul
+!ENDIF
+
+!IF "$(CFG)" == "mod_log_debug - Win32 Release"
+
+OUTDIR=.\Release
+INTDIR=.\Release
+DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
+# Begin Custom Macros
+OutDir=.\Release
+# End Custom Macros
+
+!IF "$(RECURSE)" == "0"
+
+ALL : "$(OUTDIR)\mod_log_debug.so" "$(DS_POSTBUILD_DEP)"
+
+!ELSE
+
+ALL : "libhttpd - Win32 Release" "libapr - Win32 Release" "$(OUTDIR)\mod_log_debug.so" "$(DS_POSTBUILD_DEP)"
+
+!ENDIF
+
+!IF "$(RECURSE)" == "1"
+CLEAN :"libapr - Win32 ReleaseCLEAN" "libhttpd - Win32 ReleaseCLEAN"
+!ELSE
+CLEAN :
+!ENDIF
+ -@erase "$(INTDIR)\mod_log_debug.obj"
+ -@erase "$(INTDIR)\mod_log_debug.res"
+ -@erase "$(INTDIR)\mod_log_debug_src.idb"
+ -@erase "$(INTDIR)\mod_log_debug_src.pdb"
+ -@erase "$(OUTDIR)\mod_log_debug.exp"
+ -@erase "$(OUTDIR)\mod_log_debug.lib"
+ -@erase "$(OUTDIR)\mod_log_debug.pdb"
+ -@erase "$(OUTDIR)\mod_log_debug.so"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /MD /W3 /Zi /O2 /Oy- /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\mod_log_debug_src" /FD /c
+
+.c{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.c{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+MTL=midl.exe
+MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /win32
+RSC=rc.exe
+RSC_PROJ=/l 0x409 /fo"$(INTDIR)\mod_log_debug.res" /i "../../include" /i "../../srclib/apr/include" /d "NDEBUG" /d BIN_NAME="mod_log_debug.so" /d LONG_NAME="log_debug_module for Apache"
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\mod_log_debug.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+LINK32_FLAGS=kernel32.lib /nologo /subsystem:windows /dll /incremental:no /pdb:"$(OUTDIR)\mod_log_debug.pdb" /debug /out:"$(OUTDIR)\mod_log_debug.so" /implib:"$(OUTDIR)\mod_log_debug.lib" /base:@..\..\os\win32\BaseAddr.ref,mod_log_debug.so /opt:ref
+LINK32_OBJS= \
+ "$(INTDIR)\mod_log_debug.obj" \
+ "$(INTDIR)\mod_log_debug.res" \
+ "..\..\srclib\apr\Release\libapr-1.lib" \
+ "..\..\Release\libhttpd.lib"
+
+"$(OUTDIR)\mod_log_debug.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+TargetPath=.\Release\mod_log_debug.so
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
+
+# Begin Custom Macros
+OutDir=.\Release
+# End Custom Macros
+
+"$(DS_POSTBUILD_DEP)" : "$(OUTDIR)\mod_log_debug.so"
+ if exist .\Release\mod_log_debug.so.manifest mt.exe -manifest .\Release\mod_log_debug.so.manifest -outputresource:.\Release\mod_log_debug.so;2
+ echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)"
+
+!ELSEIF "$(CFG)" == "mod_log_debug - Win32 Debug"
+
+OUTDIR=.\Debug
+INTDIR=.\Debug
+DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
+# Begin Custom Macros
+OutDir=.\Debug
+# End Custom Macros
+
+!IF "$(RECURSE)" == "0"
+
+ALL : "$(OUTDIR)\mod_log_debug.so" "$(DS_POSTBUILD_DEP)"
+
+!ELSE
+
+ALL : "libhttpd - Win32 Debug" "libapr - Win32 Debug" "$(OUTDIR)\mod_log_debug.so" "$(DS_POSTBUILD_DEP)"
+
+!ENDIF
+
+!IF "$(RECURSE)" == "1"
+CLEAN :"libapr - Win32 DebugCLEAN" "libhttpd - Win32 DebugCLEAN"
+!ELSE
+CLEAN :
+!ENDIF
+ -@erase "$(INTDIR)\mod_log_debug.obj"
+ -@erase "$(INTDIR)\mod_log_debug.res"
+ -@erase "$(INTDIR)\mod_log_debug_src.idb"
+ -@erase "$(INTDIR)\mod_log_debug_src.pdb"
+ -@erase "$(OUTDIR)\mod_log_debug.exp"
+ -@erase "$(OUTDIR)\mod_log_debug.lib"
+ -@erase "$(OUTDIR)\mod_log_debug.pdb"
+ -@erase "$(OUTDIR)\mod_log_debug.so"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /MDd /W3 /Zi /Od /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\mod_log_debug_src" /FD /EHsc /c
+
+.c{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.c{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+MTL=midl.exe
+MTL_PROJ=/nologo /D "_DEBUG" /mktyplib203 /win32
+RSC=rc.exe
+RSC_PROJ=/l 0x409 /fo"$(INTDIR)\mod_log_debug.res" /i "../../include" /i "../../srclib/apr/include" /d "_DEBUG" /d BIN_NAME="mod_log_debug.so" /d LONG_NAME="log_debug_module for Apache"
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\mod_log_debug.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+LINK32_FLAGS=kernel32.lib /nologo /subsystem:windows /dll /incremental:no /pdb:"$(OUTDIR)\mod_log_debug.pdb" /debug /out:"$(OUTDIR)\mod_log_debug.so" /implib:"$(OUTDIR)\mod_log_debug.lib" /base:@..\..\os\win32\BaseAddr.ref,mod_log_debug.so
+LINK32_OBJS= \
+ "$(INTDIR)\mod_log_debug.obj" \
+ "$(INTDIR)\mod_log_debug.res" \
+ "..\..\srclib\apr\Debug\libapr-1.lib" \
+ "..\..\Debug\libhttpd.lib"
+
+"$(OUTDIR)\mod_log_debug.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+TargetPath=.\Debug\mod_log_debug.so
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
+
+# Begin Custom Macros
+OutDir=.\Debug
+# End Custom Macros
+
+"$(DS_POSTBUILD_DEP)" : "$(OUTDIR)\mod_log_debug.so"
+ if exist .\Debug\mod_log_debug.so.manifest mt.exe -manifest .\Debug\mod_log_debug.so.manifest -outputresource:.\Debug\mod_log_debug.so;2
+ echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)"
+
+!ENDIF
+
+
+!IF "$(NO_EXTERNAL_DEPS)" != "1"
+!IF EXISTS("mod_log_debug.dep")
+!INCLUDE "mod_log_debug.dep"
+!ELSE
+!MESSAGE Warning: cannot find "mod_log_debug.dep"
+!ENDIF
+!ENDIF
+
+
+!IF "$(CFG)" == "mod_log_debug - Win32 Release" || "$(CFG)" == "mod_log_debug - Win32 Debug"
+
+!IF "$(CFG)" == "mod_log_debug - Win32 Release"
+
+"libapr - Win32 Release" :
+ cd ".\..\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Release"
+ cd "..\..\modules\loggers"
+
+"libapr - Win32 ReleaseCLEAN" :
+ cd ".\..\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Release" RECURSE=1 CLEAN
+ cd "..\..\modules\loggers"
+
+!ELSEIF "$(CFG)" == "mod_log_debug - Win32 Debug"
+
+"libapr - Win32 Debug" :
+ cd ".\..\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Debug"
+ cd "..\..\modules\loggers"
+
+"libapr - Win32 DebugCLEAN" :
+ cd ".\..\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Debug" RECURSE=1 CLEAN
+ cd "..\..\modules\loggers"
+
+!ENDIF
+
+!IF "$(CFG)" == "mod_log_debug - Win32 Release"
+
+"libhttpd - Win32 Release" :
+ cd ".\..\.."
+ $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Release"
+ cd ".\modules\loggers"
+
+"libhttpd - Win32 ReleaseCLEAN" :
+ cd ".\..\.."
+ $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Release" RECURSE=1 CLEAN
+ cd ".\modules\loggers"
+
+!ELSEIF "$(CFG)" == "mod_log_debug - Win32 Debug"
+
+"libhttpd - Win32 Debug" :
+ cd ".\..\.."
+ $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Debug"
+ cd ".\modules\loggers"
+
+"libhttpd - Win32 DebugCLEAN" :
+ cd ".\..\.."
+ $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Debug" RECURSE=1 CLEAN
+ cd ".\modules\loggers"
+
+!ENDIF
+
+SOURCE=..\..\build\win32\httpd.rc
+
+!IF "$(CFG)" == "mod_log_debug - Win32 Release"
+
+
+"$(INTDIR)\mod_log_debug.res" : $(SOURCE) "$(INTDIR)"
+ $(RSC) /l 0x409 /fo"$(INTDIR)\mod_log_debug.res" /i "../../include" /i "../../srclib/apr/include" /i "../../build\win32" /d "NDEBUG" /d BIN_NAME="mod_log_debug.so" /d LONG_NAME="log_debug_module for Apache" $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "mod_log_debug - Win32 Debug"
+
+
+"$(INTDIR)\mod_log_debug.res" : $(SOURCE) "$(INTDIR)"
+ $(RSC) /l 0x409 /fo"$(INTDIR)\mod_log_debug.res" /i "../../include" /i "../../srclib/apr/include" /i "../../build\win32" /d "_DEBUG" /d BIN_NAME="mod_log_debug.so" /d LONG_NAME="log_debug_module for Apache" $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=.\mod_log_debug.c
+
+"$(INTDIR)\mod_log_debug.obj" : $(SOURCE) "$(INTDIR)"
+
+
+
+!ENDIF
+
diff --git a/modules/loggers/mod_log_forensic.c b/modules/loggers/mod_log_forensic.c
new file mode 100644
index 0000000..4884f25
--- /dev/null
+++ b/modules/loggers/mod_log_forensic.c
@@ -0,0 +1,289 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * See also support/check_forensic.
+ * Relate the forensic log to the transfer log by including
+ * %{forensic-id}n in the custom log format, for example:
+ * CustomLog logs/custom "%h %l %u %t \"%r\" %>s %b %{forensic-id}n"
+ *
+ * Credit is due to Tina Bird <tbird precision-guesswork.com>, whose
+ * idea this module was.
+ *
+ * Ben Laurie 29/12/2003
+ */
+
+#include "httpd.h"
+#include "http_config.h"
+#include "http_log.h"
+#include "apr_strings.h"
+#include "apr_atomic.h"
+#include "http_protocol.h"
+#include "test_char.h"
+#if APR_HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+module AP_MODULE_DECLARE_DATA log_forensic_module;
+
+typedef struct fcfg {
+ const char *logname;
+ apr_file_t *fd;
+} fcfg;
+
+static apr_uint32_t next_id;
+
+static void *make_forensic_log_scfg(apr_pool_t *p, server_rec *s)
+{
+ fcfg *cfg = apr_pcalloc(p, sizeof *cfg);
+
+ cfg->logname = NULL;
+ cfg->fd = NULL;
+
+ return cfg;
+}
+
+static void *merge_forensic_log_scfg(apr_pool_t *p, void *parent, void *new)
+{
+ fcfg *cfg = apr_pcalloc(p, sizeof *cfg);
+ fcfg *pc = parent;
+ fcfg *nc = new;
+
+ cfg->logname = apr_pstrdup(p, nc->logname ? nc->logname : pc->logname);
+ cfg->fd = NULL;
+
+ return cfg;
+}
+
+static int open_log(server_rec *s, apr_pool_t *p)
+{
+ fcfg *cfg = ap_get_module_config(s->module_config, &log_forensic_module);
+
+ if (!cfg->logname || cfg->fd)
+ return 1;
+
+ if (*cfg->logname == '|') {
+ piped_log *pl;
+ const char *pname = ap_server_root_relative(p, cfg->logname + 1);
+
+ pl = ap_open_piped_log(p, pname);
+ if (pl == NULL) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(00650)
+ "couldn't spawn forensic log pipe %s", cfg->logname);
+ return 0;
+ }
+ cfg->fd = ap_piped_log_write_fd(pl);
+ }
+ else {
+ const char *fname = ap_server_root_relative(p, cfg->logname);
+ apr_status_t rv;
+
+ if ((rv = apr_file_open(&cfg->fd, fname,
+ APR_WRITE | APR_APPEND | APR_CREATE,
+ APR_OS_DEFAULT, p)) != APR_SUCCESS) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(00651)
+ "could not open forensic log file %s.", fname);
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+static int log_init(apr_pool_t *pc, apr_pool_t *p, apr_pool_t *pt,
+ server_rec *s)
+{
+ for ( ; s ; s = s->next) {
+ if (!open_log(s, p)) {
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+ }
+
+ return OK;
+}
+
+
+/* e is the first _invalid_ location in q
+ N.B. returns the terminating NUL.
+ */
+static char *log_escape(char *q, const char *e, const char *p)
+{
+ for ( ; *p ; ++p) {
+ ap_assert(q < e);
+ if (TEST_CHAR(*p, T_ESCAPE_FORENSIC)) {
+ ap_assert(q+2 < e);
+ *q++ = '%';
+ ap_bin2hex(p, 1, q);
+ q += 2;
+ }
+ else
+ *q++ = *p;
+ }
+ ap_assert(q < e);
+ *q = '\0';
+
+ return q;
+}
+
+typedef struct hlog {
+ char *log;
+ char *pos;
+ char *end;
+ apr_pool_t *p;
+ apr_size_t count;
+} hlog;
+
+static apr_size_t count_string(const char *p)
+{
+ apr_size_t n;
+
+ for (n = 0 ; *p ; ++p, ++n)
+ if (TEST_CHAR(*p, T_ESCAPE_FORENSIC))
+ n += 2;
+ return n;
+}
+
+static int count_headers(void *h_, const char *key, const char *value)
+{
+ hlog *h = h_;
+
+ h->count += count_string(key)+count_string(value)+2;
+
+ return 1;
+}
+
+static int log_headers(void *h_, const char *key, const char *value)
+{
+ hlog *h = h_;
+
+ /* note that we don't have to check h->pos here, coz its been done
+ for us by log_escape */
+ *h->pos++ = '|';
+ h->pos = log_escape(h->pos, h->end, key);
+ *h->pos++ = ':';
+ h->pos = log_escape(h->pos, h->end, value);
+
+ return 1;
+}
+
+static int log_before(request_rec *r)
+{
+ fcfg *cfg = ap_get_module_config(r->server->module_config,
+ &log_forensic_module);
+ const char *id;
+ hlog h;
+ apr_size_t n;
+ apr_status_t rv;
+
+ if (!cfg->fd || r->prev) {
+ return DECLINED;
+ }
+
+ if (!(id = apr_table_get(r->subprocess_env, "UNIQUE_ID"))) {
+ /* we make the assumption that we can't go through all the PIDs in
+ under 1 second */
+ id = apr_psprintf(r->pool, "%" APR_PID_T_FMT ":%lx:%x", getpid(),
+ time(NULL), apr_atomic_inc32(&next_id));
+ }
+ ap_set_module_config(r->request_config, &log_forensic_module, (char *)id);
+
+ h.p = r->pool;
+ h.count = 0;
+
+ apr_table_do(count_headers, &h, r->headers_in, NULL);
+
+ h.count += 1+strlen(id)+1+count_string(r->the_request)+1+1;
+ h.log = apr_palloc(r->pool, h.count);
+ h.pos = h.log;
+ h.end = h.log+h.count;
+
+ *h.pos++ = '+';
+ strcpy(h.pos, id);
+ h.pos += strlen(h.pos);
+ *h.pos++ = '|';
+ h.pos = log_escape(h.pos, h.end, r->the_request);
+
+ apr_table_do(log_headers, &h, r->headers_in, NULL);
+
+ ap_assert(h.pos < h.end);
+ *h.pos++ = '\n';
+
+ n = h.count-1;
+ rv = apr_file_write(cfg->fd, h.log, &n);
+ ap_assert(rv == APR_SUCCESS && n == h.count-1);
+
+ apr_table_setn(r->notes, "forensic-id", id);
+
+ return OK;
+}
+
+static int log_after(request_rec *r)
+{
+ fcfg *cfg = ap_get_module_config(r->server->module_config,
+ &log_forensic_module);
+ const char *id = ap_get_module_config(r->request_config,
+ &log_forensic_module);
+ char *s;
+ apr_size_t l, n;
+ apr_status_t rv;
+
+ if (!cfg->fd || id == NULL) {
+ return DECLINED;
+ }
+
+ s = apr_pstrcat(r->pool, "-", id, "\n", NULL);
+ l = n = strlen(s);
+ rv = apr_file_write(cfg->fd, s, &n);
+ ap_assert(rv == APR_SUCCESS && n == l);
+
+ return OK;
+}
+
+static const char *set_forensic_log(cmd_parms *cmd, void *dummy, const char *fn)
+{
+ fcfg *cfg = ap_get_module_config(cmd->server->module_config,
+ &log_forensic_module);
+
+ cfg->logname = fn;
+ return NULL;
+}
+
+static const command_rec forensic_log_cmds[] =
+{
+ AP_INIT_TAKE1("ForensicLog", set_forensic_log, NULL, RSRC_CONF,
+ "the filename of the forensic log"),
+ { NULL }
+};
+
+static void register_hooks(apr_pool_t *p)
+{
+ static const char * const pre[] = { "mod_unique_id.c", NULL };
+
+ ap_hook_open_logs(log_init,NULL,NULL,APR_HOOK_MIDDLE);
+ ap_hook_post_read_request(log_before,pre,NULL,APR_HOOK_REALLY_FIRST);
+ ap_hook_log_transaction(log_after,NULL,NULL,APR_HOOK_REALLY_LAST);
+}
+
+AP_DECLARE_MODULE(log_forensic) =
+{
+ STANDARD20_MODULE_STUFF,
+ NULL, /* create per-dir config */
+ NULL, /* merge per-dir config */
+ make_forensic_log_scfg, /* server config */
+ merge_forensic_log_scfg, /* merge server config */
+ forensic_log_cmds, /* command apr_table_t */
+ register_hooks /* register hooks */
+};
diff --git a/modules/loggers/mod_log_forensic.dep b/modules/loggers/mod_log_forensic.dep
new file mode 100644
index 0000000..2337156
--- /dev/null
+++ b/modules/loggers/mod_log_forensic.dep
@@ -0,0 +1,53 @@
+# Microsoft Developer Studio Generated Dependency File, included by mod_log_forensic.mak
+
+..\..\build\win32\httpd.rc : \
+ "..\..\include\ap_release.h"\
+
+
+.\mod_log_forensic.c : \
+ "..\..\include\ap_config.h"\
+ "..\..\include\ap_config_layout.h"\
+ "..\..\include\ap_hooks.h"\
+ "..\..\include\ap_mmn.h"\
+ "..\..\include\ap_regex.h"\
+ "..\..\include\ap_release.h"\
+ "..\..\include\apache_noprobes.h"\
+ "..\..\include\http_config.h"\
+ "..\..\include\http_log.h"\
+ "..\..\include\http_protocol.h"\
+ "..\..\include\httpd.h"\
+ "..\..\include\os.h"\
+ "..\..\include\util_cfgtree.h"\
+ "..\..\include\util_filter.h"\
+ "..\..\server\test_char.h"\
+ "..\..\srclib\apr-util\include\apr_buckets.h"\
+ "..\..\srclib\apr-util\include\apr_hooks.h"\
+ "..\..\srclib\apr-util\include\apr_optional_hooks.h"\
+ "..\..\srclib\apr-util\include\apr_uri.h"\
+ "..\..\srclib\apr-util\include\apu.h"\
+ "..\..\srclib\apr\include\apr.h"\
+ "..\..\srclib\apr\include\apr_allocator.h"\
+ "..\..\srclib\apr\include\apr_atomic.h"\
+ "..\..\srclib\apr\include\apr_dso.h"\
+ "..\..\srclib\apr\include\apr_errno.h"\
+ "..\..\srclib\apr\include\apr_file_info.h"\
+ "..\..\srclib\apr\include\apr_file_io.h"\
+ "..\..\srclib\apr\include\apr_general.h"\
+ "..\..\srclib\apr\include\apr_global_mutex.h"\
+ "..\..\srclib\apr\include\apr_inherit.h"\
+ "..\..\srclib\apr\include\apr_mmap.h"\
+ "..\..\srclib\apr\include\apr_network_io.h"\
+ "..\..\srclib\apr\include\apr_poll.h"\
+ "..\..\srclib\apr\include\apr_pools.h"\
+ "..\..\srclib\apr\include\apr_portable.h"\
+ "..\..\srclib\apr\include\apr_proc_mutex.h"\
+ "..\..\srclib\apr\include\apr_ring.h"\
+ "..\..\srclib\apr\include\apr_shm.h"\
+ "..\..\srclib\apr\include\apr_strings.h"\
+ "..\..\srclib\apr\include\apr_tables.h"\
+ "..\..\srclib\apr\include\apr_thread_mutex.h"\
+ "..\..\srclib\apr\include\apr_thread_proc.h"\
+ "..\..\srclib\apr\include\apr_time.h"\
+ "..\..\srclib\apr\include\apr_user.h"\
+ "..\..\srclib\apr\include\apr_want.h"\
+
diff --git a/modules/loggers/mod_log_forensic.dsp b/modules/loggers/mod_log_forensic.dsp
new file mode 100644
index 0000000..cdf7c21
--- /dev/null
+++ b/modules/loggers/mod_log_forensic.dsp
@@ -0,0 +1,111 @@
+# Microsoft Developer Studio Project File - Name="mod_log_forensic" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=mod_log_forensic - Win32 Release
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "mod_log_forensic.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "mod_log_forensic.mak" CFG="mod_log_forensic - Win32 Release"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "mod_log_forensic - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "mod_log_forensic - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "mod_log_forensic - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c
+# ADD CPP /nologo /MD /W3 /O2 /Oy- /Zi /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /I "../../server" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Release\mod_log_forensic_src" /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /fo"Release/mod_log_forensic.res" /i "../../include" /i "../../srclib/apr/include" /d "NDEBUG" /d BIN_NAME="mod_log_forensic.so" /d LONG_NAME="log_forensic_module for Apache"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib /nologo /subsystem:windows /dll /out:".\Release\mod_log_forensic.so" /base:@..\..\os\win32\BaseAddr.ref,mod_log_forensic.so
+# ADD LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:".\Release\mod_log_forensic.so" /base:@..\..\os\win32\BaseAddr.ref,mod_log_forensic.so /opt:ref
+# Begin Special Build Tool
+TargetPath=.\Release\mod_log_forensic.so
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2
+# End Special Build Tool
+
+!ELSEIF "$(CFG)" == "mod_log_forensic - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MDd /W3 /EHsc /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /c
+# ADD CPP /nologo /MDd /W3 /EHsc /Zi /Od /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /I "../../server" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Debug\mod_log_forensic_src" /FD /c
+# ADD BASE MTL /nologo /D "_DEBUG" /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /fo"Debug/mod_log_forensic.res" /i "../../include" /i "../../srclib/apr/include" /d "_DEBUG" /d BIN_NAME="mod_log_forensic.so" /d LONG_NAME="log_forensic_module for Apache"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:".\Debug\mod_log_forensic.so" /base:@..\..\os\win32\BaseAddr.ref,mod_log_forensic.so
+# ADD LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:".\Debug\mod_log_forensic.so" /base:@..\..\os\win32\BaseAddr.ref,mod_log_forensic.so
+# Begin Special Build Tool
+TargetPath=.\Debug\mod_log_forensic.so
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2
+# End Special Build Tool
+
+!ENDIF
+
+# Begin Target
+
+# Name "mod_log_forensic - Win32 Release"
+# Name "mod_log_forensic - Win32 Debug"
+# Begin Source File
+
+SOURCE=.\mod_log_forensic.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\build\win32\httpd.rc
+# End Source File
+# End Target
+# End Project
diff --git a/modules/loggers/mod_log_forensic.exp b/modules/loggers/mod_log_forensic.exp
new file mode 100644
index 0000000..92f5075
--- /dev/null
+++ b/modules/loggers/mod_log_forensic.exp
@@ -0,0 +1 @@
+log_forensic_module
diff --git a/modules/loggers/mod_log_forensic.mak b/modules/loggers/mod_log_forensic.mak
new file mode 100644
index 0000000..0ad2e54
--- /dev/null
+++ b/modules/loggers/mod_log_forensic.mak
@@ -0,0 +1,353 @@
+# Microsoft Developer Studio Generated NMAKE File, Based on mod_log_forensic.dsp
+!IF "$(CFG)" == ""
+CFG=mod_log_forensic - Win32 Release
+!MESSAGE No configuration specified. Defaulting to mod_log_forensic - Win32 Release.
+!ENDIF
+
+!IF "$(CFG)" != "mod_log_forensic - Win32 Release" && "$(CFG)" != "mod_log_forensic - Win32 Debug"
+!MESSAGE Invalid configuration "$(CFG)" specified.
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "mod_log_forensic.mak" CFG="mod_log_forensic - Win32 Release"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "mod_log_forensic - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "mod_log_forensic - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE
+!ERROR An invalid configuration is specified.
+!ENDIF
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE
+NULL=nul
+!ENDIF
+
+!IF "$(CFG)" == "mod_log_forensic - Win32 Release"
+
+OUTDIR=.\Release
+INTDIR=.\Release
+DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
+# Begin Custom Macros
+OutDir=.\Release
+# End Custom Macros
+
+!IF "$(RECURSE)" == "0"
+
+ALL : "$(OUTDIR)\mod_log_forensic.so" "$(DS_POSTBUILD_DEP)"
+
+!ELSE
+
+ALL : "libhttpd - Win32 Release" "libaprutil - Win32 Release" "libapr - Win32 Release" "$(OUTDIR)\mod_log_forensic.so" "$(DS_POSTBUILD_DEP)"
+
+!ENDIF
+
+!IF "$(RECURSE)" == "1"
+CLEAN :"libapr - Win32 ReleaseCLEAN" "libaprutil - Win32 ReleaseCLEAN" "libhttpd - Win32 ReleaseCLEAN"
+!ELSE
+CLEAN :
+!ENDIF
+ -@erase "$(INTDIR)\mod_log_forensic.obj"
+ -@erase "$(INTDIR)\mod_log_forensic.res"
+ -@erase "$(INTDIR)\mod_log_forensic_src.idb"
+ -@erase "$(INTDIR)\mod_log_forensic_src.pdb"
+ -@erase "$(OUTDIR)\mod_log_forensic.exp"
+ -@erase "$(OUTDIR)\mod_log_forensic.lib"
+ -@erase "$(OUTDIR)\mod_log_forensic.pdb"
+ -@erase "$(OUTDIR)\mod_log_forensic.so"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /MD /W3 /Zi /O2 /Oy- /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /I "../../server" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\mod_log_forensic_src" /FD /c
+
+.c{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.c{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+MTL=midl.exe
+MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /win32
+RSC=rc.exe
+RSC_PROJ=/l 0x409 /fo"$(INTDIR)\mod_log_forensic.res" /i "../../include" /i "../../srclib/apr/include" /d "NDEBUG" /d BIN_NAME="mod_log_forensic.so" /d LONG_NAME="log_forensic_module for Apache"
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\mod_log_forensic.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+LINK32_FLAGS=kernel32.lib /nologo /subsystem:windows /dll /incremental:no /pdb:"$(OUTDIR)\mod_log_forensic.pdb" /debug /out:"$(OUTDIR)\mod_log_forensic.so" /implib:"$(OUTDIR)\mod_log_forensic.lib" /base:@..\..\os\win32\BaseAddr.ref,mod_log_forensic.so /opt:ref
+LINK32_OBJS= \
+ "$(INTDIR)\mod_log_forensic.obj" \
+ "$(INTDIR)\mod_log_forensic.res" \
+ "..\..\srclib\apr\Release\libapr-1.lib" \
+ "..\..\srclib\apr-util\Release\libaprutil-1.lib" \
+ "..\..\Release\libhttpd.lib"
+
+"$(OUTDIR)\mod_log_forensic.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+TargetPath=.\Release\mod_log_forensic.so
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
+
+# Begin Custom Macros
+OutDir=.\Release
+# End Custom Macros
+
+"$(DS_POSTBUILD_DEP)" : "$(OUTDIR)\mod_log_forensic.so"
+ if exist .\Release\mod_log_forensic.so.manifest mt.exe -manifest .\Release\mod_log_forensic.so.manifest -outputresource:.\Release\mod_log_forensic.so;2
+ echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)"
+
+!ELSEIF "$(CFG)" == "mod_log_forensic - Win32 Debug"
+
+OUTDIR=.\Debug
+INTDIR=.\Debug
+DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
+# Begin Custom Macros
+OutDir=.\Debug
+# End Custom Macros
+
+!IF "$(RECURSE)" == "0"
+
+ALL : "$(OUTDIR)\mod_log_forensic.so" "$(DS_POSTBUILD_DEP)"
+
+!ELSE
+
+ALL : "libhttpd - Win32 Debug" "libaprutil - Win32 Debug" "libapr - Win32 Debug" "$(OUTDIR)\mod_log_forensic.so" "$(DS_POSTBUILD_DEP)"
+
+!ENDIF
+
+!IF "$(RECURSE)" == "1"
+CLEAN :"libapr - Win32 DebugCLEAN" "libaprutil - Win32 DebugCLEAN" "libhttpd - Win32 DebugCLEAN"
+!ELSE
+CLEAN :
+!ENDIF
+ -@erase "$(INTDIR)\mod_log_forensic.obj"
+ -@erase "$(INTDIR)\mod_log_forensic.res"
+ -@erase "$(INTDIR)\mod_log_forensic_src.idb"
+ -@erase "$(INTDIR)\mod_log_forensic_src.pdb"
+ -@erase "$(OUTDIR)\mod_log_forensic.exp"
+ -@erase "$(OUTDIR)\mod_log_forensic.lib"
+ -@erase "$(OUTDIR)\mod_log_forensic.pdb"
+ -@erase "$(OUTDIR)\mod_log_forensic.so"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /MDd /W3 /Zi /Od /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /I "../../server" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\mod_log_forensic_src" /FD /EHsc /c
+
+.c{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.c{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+MTL=midl.exe
+MTL_PROJ=/nologo /D "_DEBUG" /mktyplib203 /win32
+RSC=rc.exe
+RSC_PROJ=/l 0x409 /fo"$(INTDIR)\mod_log_forensic.res" /i "../../include" /i "../../srclib/apr/include" /d "_DEBUG" /d BIN_NAME="mod_log_forensic.so" /d LONG_NAME="log_forensic_module for Apache"
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\mod_log_forensic.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+LINK32_FLAGS=kernel32.lib /nologo /subsystem:windows /dll /incremental:no /pdb:"$(OUTDIR)\mod_log_forensic.pdb" /debug /out:"$(OUTDIR)\mod_log_forensic.so" /implib:"$(OUTDIR)\mod_log_forensic.lib" /base:@..\..\os\win32\BaseAddr.ref,mod_log_forensic.so
+LINK32_OBJS= \
+ "$(INTDIR)\mod_log_forensic.obj" \
+ "$(INTDIR)\mod_log_forensic.res" \
+ "..\..\srclib\apr\Debug\libapr-1.lib" \
+ "..\..\srclib\apr-util\Debug\libaprutil-1.lib" \
+ "..\..\Debug\libhttpd.lib"
+
+"$(OUTDIR)\mod_log_forensic.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+TargetPath=.\Debug\mod_log_forensic.so
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
+
+# Begin Custom Macros
+OutDir=.\Debug
+# End Custom Macros
+
+"$(DS_POSTBUILD_DEP)" : "$(OUTDIR)\mod_log_forensic.so"
+ if exist .\Debug\mod_log_forensic.so.manifest mt.exe -manifest .\Debug\mod_log_forensic.so.manifest -outputresource:.\Debug\mod_log_forensic.so;2
+ echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)"
+
+!ENDIF
+
+
+!IF "$(NO_EXTERNAL_DEPS)" != "1"
+!IF EXISTS("mod_log_forensic.dep")
+!INCLUDE "mod_log_forensic.dep"
+!ELSE
+!MESSAGE Warning: cannot find "mod_log_forensic.dep"
+!ENDIF
+!ENDIF
+
+
+!IF "$(CFG)" == "mod_log_forensic - Win32 Release" || "$(CFG)" == "mod_log_forensic - Win32 Debug"
+
+!IF "$(CFG)" == "mod_log_forensic - Win32 Release"
+
+"libapr - Win32 Release" :
+ cd ".\..\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Release"
+ cd "..\..\modules\loggers"
+
+"libapr - Win32 ReleaseCLEAN" :
+ cd ".\..\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Release" RECURSE=1 CLEAN
+ cd "..\..\modules\loggers"
+
+!ELSEIF "$(CFG)" == "mod_log_forensic - Win32 Debug"
+
+"libapr - Win32 Debug" :
+ cd ".\..\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Debug"
+ cd "..\..\modules\loggers"
+
+"libapr - Win32 DebugCLEAN" :
+ cd ".\..\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Debug" RECURSE=1 CLEAN
+ cd "..\..\modules\loggers"
+
+!ENDIF
+
+!IF "$(CFG)" == "mod_log_forensic - Win32 Release"
+
+"libaprutil - Win32 Release" :
+ cd ".\..\..\srclib\apr-util"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Release"
+ cd "..\..\modules\loggers"
+
+"libaprutil - Win32 ReleaseCLEAN" :
+ cd ".\..\..\srclib\apr-util"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Release" RECURSE=1 CLEAN
+ cd "..\..\modules\loggers"
+
+!ELSEIF "$(CFG)" == "mod_log_forensic - Win32 Debug"
+
+"libaprutil - Win32 Debug" :
+ cd ".\..\..\srclib\apr-util"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Debug"
+ cd "..\..\modules\loggers"
+
+"libaprutil - Win32 DebugCLEAN" :
+ cd ".\..\..\srclib\apr-util"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Debug" RECURSE=1 CLEAN
+ cd "..\..\modules\loggers"
+
+!ENDIF
+
+!IF "$(CFG)" == "mod_log_forensic - Win32 Release"
+
+"libhttpd - Win32 Release" :
+ cd ".\..\.."
+ $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Release"
+ cd ".\modules\loggers"
+
+"libhttpd - Win32 ReleaseCLEAN" :
+ cd ".\..\.."
+ $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Release" RECURSE=1 CLEAN
+ cd ".\modules\loggers"
+
+!ELSEIF "$(CFG)" == "mod_log_forensic - Win32 Debug"
+
+"libhttpd - Win32 Debug" :
+ cd ".\..\.."
+ $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Debug"
+ cd ".\modules\loggers"
+
+"libhttpd - Win32 DebugCLEAN" :
+ cd ".\..\.."
+ $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Debug" RECURSE=1 CLEAN
+ cd ".\modules\loggers"
+
+!ENDIF
+
+SOURCE=..\..\build\win32\httpd.rc
+
+!IF "$(CFG)" == "mod_log_forensic - Win32 Release"
+
+
+"$(INTDIR)\mod_log_forensic.res" : $(SOURCE) "$(INTDIR)"
+ $(RSC) /l 0x409 /fo"$(INTDIR)\mod_log_forensic.res" /i "../../include" /i "../../srclib/apr/include" /i "../../build\win32" /d "NDEBUG" /d BIN_NAME="mod_log_forensic.so" /d LONG_NAME="log_forensic_module for Apache" $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "mod_log_forensic - Win32 Debug"
+
+
+"$(INTDIR)\mod_log_forensic.res" : $(SOURCE) "$(INTDIR)"
+ $(RSC) /l 0x409 /fo"$(INTDIR)\mod_log_forensic.res" /i "../../include" /i "../../srclib/apr/include" /i "../../build\win32" /d "_DEBUG" /d BIN_NAME="mod_log_forensic.so" /d LONG_NAME="log_forensic_module for Apache" $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=.\mod_log_forensic.c
+
+"$(INTDIR)\mod_log_forensic.obj" : $(SOURCE) "$(INTDIR)"
+
+
+
+!ENDIF
+
diff --git a/modules/loggers/mod_logio.c b/modules/loggers/mod_logio.c
new file mode 100644
index 0000000..b609f7f
--- /dev/null
+++ b/modules/loggers/mod_logio.c
@@ -0,0 +1,284 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Written by Bojan Smojver <bojan rexursive.com>.
+ */
+
+#include "apr_strings.h"
+#include "apr_lib.h"
+#include "apr_hash.h"
+#include "apr_optional.h"
+
+#define APR_WANT_STRFUNC
+#include "apr_want.h"
+
+#include "ap_config.h"
+#include "mod_log_config.h"
+#include "httpd.h"
+#include "http_core.h"
+#include "http_config.h"
+#include "http_connection.h"
+#include "http_protocol.h"
+#include "http_request.h"
+
+module AP_MODULE_DECLARE_DATA logio_module;
+
+static const char logio_filter_name[] = "LOG_INPUT_OUTPUT";
+static const char logio_ttfb_filter_name[] = "LOGIO_TTFB_OUT";
+
+/*
+ * Logging of input and output config...
+ */
+
+typedef struct logio_config_t {
+ apr_off_t bytes_in;
+ apr_off_t bytes_out;
+ apr_off_t bytes_last_request;
+} logio_config_t;
+
+typedef struct logio_dirconf_t {
+ unsigned int track_ttfb:1;
+} logio_dirconf_t;
+
+typedef struct logio_req_t {
+ apr_time_t ttfb;
+} logio_req_t;
+
+
+
+/*
+ * Optional function for the core to add to bytes_out
+ */
+
+static void ap_logio_add_bytes_out(conn_rec *c, apr_off_t bytes)
+{
+ logio_config_t *cf = ap_get_module_config(c->conn_config, &logio_module);
+ cf->bytes_out += bytes;
+}
+
+/*
+ * Optional function for modules to adjust bytes_in
+ */
+
+static void ap_logio_add_bytes_in(conn_rec *c, apr_off_t bytes)
+{
+ logio_config_t *cf = ap_get_module_config(c->conn_config, &logio_module);
+
+ cf->bytes_in += bytes;
+}
+
+/*
+ * Optional function to get total byte count of last request for
+ * ap_increment_counts.
+ */
+
+static apr_off_t ap_logio_get_last_bytes(conn_rec *c)
+{
+ logio_config_t *cf = ap_get_module_config(c->conn_config, &logio_module);
+
+ return cf->bytes_last_request;
+}
+
+/*
+ * Format items...
+ */
+
+static const char *log_bytes_in(request_rec *r, char *a)
+{
+ logio_config_t *cf = ap_get_module_config(r->connection->conn_config,
+ &logio_module);
+
+ return apr_off_t_toa(r->pool, cf->bytes_in);
+}
+
+static const char *log_bytes_out(request_rec *r, char *a)
+{
+ logio_config_t *cf = ap_get_module_config(r->connection->conn_config,
+ &logio_module);
+
+ return apr_off_t_toa(r->pool, cf->bytes_out);
+}
+
+static const char *log_bytes_combined(request_rec *r, char *a)
+{
+ logio_config_t *cf = ap_get_module_config(r->connection->conn_config,
+ &logio_module);
+
+ return apr_off_t_toa(r->pool, cf->bytes_out + cf->bytes_in);
+}
+
+static const char *log_ttfb(request_rec *r, char *a)
+{
+ logio_req_t *rconf = ap_get_module_config(r->request_config,
+ &logio_module);
+
+ if (!rconf || !rconf->ttfb) {
+ return "-";
+ }
+
+ return apr_psprintf(r->pool, "%" APR_TIME_T_FMT, rconf->ttfb);
+}
+/*
+ * Reset counters after logging...
+ */
+
+static int logio_transaction(request_rec *r)
+{
+ logio_config_t *cf = ap_get_module_config(r->connection->conn_config,
+ &logio_module);
+
+ /* need to save byte count of last request for ap_increment_counts */
+ cf->bytes_last_request = cf->bytes_in + cf->bytes_out;
+ cf->bytes_in = cf->bytes_out = 0;
+
+ return OK;
+}
+
+/*
+ * Logging of input filter...
+ */
+
+static apr_status_t logio_in_filter(ap_filter_t *f,
+ apr_bucket_brigade *bb,
+ ap_input_mode_t mode,
+ apr_read_type_e block,
+ apr_off_t readbytes)
+{
+ apr_off_t length;
+ apr_status_t status;
+ logio_config_t *cf = ap_get_module_config(f->c->conn_config, &logio_module);
+
+ status = ap_get_brigade(f->next, bb, mode, block, readbytes);
+
+ apr_brigade_length (bb, 0, &length);
+
+ if (length > 0)
+ cf->bytes_in += length;
+
+ return status;
+}
+
+/*
+ * The hooks...
+ */
+
+static int logio_pre_conn(conn_rec *c, void *csd)
+{
+ logio_config_t *cf = apr_pcalloc(c->pool, sizeof(*cf));
+
+ ap_set_module_config(c->conn_config, &logio_module, cf);
+
+ ap_add_input_filter(logio_filter_name, NULL, NULL, c);
+
+ return OK;
+}
+
+static int logio_pre_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp)
+{
+ APR_OPTIONAL_FN_TYPE(ap_register_log_handler) *log_pfn_register;
+
+ log_pfn_register = APR_RETRIEVE_OPTIONAL_FN(ap_register_log_handler);
+
+ if (log_pfn_register) {
+ log_pfn_register(p, "I", log_bytes_in, 0);
+ log_pfn_register(p, "O", log_bytes_out, 0);
+ log_pfn_register(p, "S", log_bytes_combined, 0);
+ log_pfn_register(p, "^FB", log_ttfb, 0);
+ }
+
+ return OK;
+}
+
+static apr_status_t logio_ttfb_filter(ap_filter_t *f, apr_bucket_brigade *b)
+{
+ request_rec *r = f->r;
+ logio_dirconf_t *conf = ap_get_module_config(r->per_dir_config,
+ &logio_module);
+ if (conf && conf->track_ttfb) {
+ logio_req_t *rconf = ap_get_module_config(r->request_config,
+ &logio_module);
+ if (rconf == NULL) {
+ rconf = apr_pcalloc(r->pool, sizeof(logio_req_t));
+ rconf->ttfb = apr_time_now() - r->request_time;
+ ap_set_module_config(r->request_config, &logio_module, rconf);
+ }
+ }
+ ap_remove_output_filter(f);
+ return ap_pass_brigade(f->next, b);
+}
+
+static void logio_insert_filter(request_rec * r)
+{
+ logio_dirconf_t *conf = ap_get_module_config(r->per_dir_config,
+ &logio_module);
+ if (conf->track_ttfb) {
+ ap_add_output_filter(logio_ttfb_filter_name, NULL, r, r->connection);
+ }
+}
+
+static const char *logio_track_ttfb(cmd_parms *cmd, void *in_dir_config, int arg)
+{
+ logio_dirconf_t *dir_config = in_dir_config;
+ dir_config->track_ttfb = arg;
+ return NULL;
+}
+
+static void *create_logio_dirconf (apr_pool_t *p, char *dummy)
+{
+ logio_dirconf_t *new =
+ (logio_dirconf_t *) apr_pcalloc(p, sizeof(logio_dirconf_t));
+ return (void *) new;
+}
+
+
+static const command_rec logio_cmds[] = {
+ AP_INIT_FLAG ("LogIOTrackTTFB", logio_track_ttfb, NULL, OR_ALL,
+ "Set to 'ON' to enable tracking time to first byte"),
+ {NULL}
+};
+
+
+static void register_hooks(apr_pool_t *p)
+{
+ static const char *pre[] = { "mod_log_config.c", NULL };
+
+ ap_hook_pre_connection(logio_pre_conn, NULL, NULL, APR_HOOK_MIDDLE);
+ ap_hook_pre_config(logio_pre_config, NULL, NULL, APR_HOOK_REALLY_FIRST);
+ ap_hook_log_transaction(logio_transaction, pre, NULL, APR_HOOK_MIDDLE);
+
+ ap_register_input_filter(logio_filter_name, logio_in_filter, NULL,
+ AP_FTYPE_NETWORK - 1);
+
+ ap_hook_insert_filter(logio_insert_filter, NULL, NULL, APR_HOOK_LAST);
+ ap_register_output_filter(logio_ttfb_filter_name, logio_ttfb_filter, NULL,
+ AP_FTYPE_RESOURCE);
+
+ APR_REGISTER_OPTIONAL_FN(ap_logio_add_bytes_out);
+ APR_REGISTER_OPTIONAL_FN(ap_logio_add_bytes_in);
+ APR_REGISTER_OPTIONAL_FN(ap_logio_get_last_bytes);
+}
+
+AP_DECLARE_MODULE(logio) =
+{
+ STANDARD20_MODULE_STUFF,
+ create_logio_dirconf, /* create per-dir config */
+ NULL, /* merge per-dir config */
+ NULL, /* server config */
+ NULL, /* merge server config */
+ logio_cmds, /* command apr_table_t */
+ register_hooks /* register hooks */
+};
diff --git a/modules/loggers/mod_logio.dep b/modules/loggers/mod_logio.dep
new file mode 100644
index 0000000..cc70d81
--- /dev/null
+++ b/modules/loggers/mod_logio.dep
@@ -0,0 +1,59 @@
+# Microsoft Developer Studio Generated Dependency File, included by mod_logio.mak
+
+..\..\build\win32\httpd.rc : \
+ "..\..\include\ap_release.h"\
+
+
+.\mod_logio.c : \
+ "..\..\include\ap_config.h"\
+ "..\..\include\ap_config_layout.h"\
+ "..\..\include\ap_expr.h"\
+ "..\..\include\ap_hooks.h"\
+ "..\..\include\ap_mmn.h"\
+ "..\..\include\ap_regex.h"\
+ "..\..\include\ap_release.h"\
+ "..\..\include\apache_noprobes.h"\
+ "..\..\include\http_config.h"\
+ "..\..\include\http_connection.h"\
+ "..\..\include\http_core.h"\
+ "..\..\include\http_protocol.h"\
+ "..\..\include\http_request.h"\
+ "..\..\include\httpd.h"\
+ "..\..\include\os.h"\
+ "..\..\include\scoreboard.h"\
+ "..\..\include\util_cfgtree.h"\
+ "..\..\include\util_filter.h"\
+ "..\..\srclib\apr-util\include\apr_buckets.h"\
+ "..\..\srclib\apr-util\include\apr_hooks.h"\
+ "..\..\srclib\apr-util\include\apr_optional.h"\
+ "..\..\srclib\apr-util\include\apr_optional_hooks.h"\
+ "..\..\srclib\apr-util\include\apr_uri.h"\
+ "..\..\srclib\apr-util\include\apu.h"\
+ "..\..\srclib\apr\include\apr.h"\
+ "..\..\srclib\apr\include\apr_allocator.h"\
+ "..\..\srclib\apr\include\apr_dso.h"\
+ "..\..\srclib\apr\include\apr_errno.h"\
+ "..\..\srclib\apr\include\apr_file_info.h"\
+ "..\..\srclib\apr\include\apr_file_io.h"\
+ "..\..\srclib\apr\include\apr_general.h"\
+ "..\..\srclib\apr\include\apr_global_mutex.h"\
+ "..\..\srclib\apr\include\apr_hash.h"\
+ "..\..\srclib\apr\include\apr_inherit.h"\
+ "..\..\srclib\apr\include\apr_lib.h"\
+ "..\..\srclib\apr\include\apr_mmap.h"\
+ "..\..\srclib\apr\include\apr_network_io.h"\
+ "..\..\srclib\apr\include\apr_poll.h"\
+ "..\..\srclib\apr\include\apr_pools.h"\
+ "..\..\srclib\apr\include\apr_portable.h"\
+ "..\..\srclib\apr\include\apr_proc_mutex.h"\
+ "..\..\srclib\apr\include\apr_ring.h"\
+ "..\..\srclib\apr\include\apr_shm.h"\
+ "..\..\srclib\apr\include\apr_strings.h"\
+ "..\..\srclib\apr\include\apr_tables.h"\
+ "..\..\srclib\apr\include\apr_thread_mutex.h"\
+ "..\..\srclib\apr\include\apr_thread_proc.h"\
+ "..\..\srclib\apr\include\apr_time.h"\
+ "..\..\srclib\apr\include\apr_user.h"\
+ "..\..\srclib\apr\include\apr_want.h"\
+ ".\mod_log_config.h"\
+
diff --git a/modules/loggers/mod_logio.dsp b/modules/loggers/mod_logio.dsp
new file mode 100644
index 0000000..f5a8186
--- /dev/null
+++ b/modules/loggers/mod_logio.dsp
@@ -0,0 +1,111 @@
+# Microsoft Developer Studio Project File - Name="mod_logio" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=mod_logio - Win32 Release
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "mod_logio.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "mod_logio.mak" CFG="mod_logio - Win32 Release"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "mod_logio - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "mod_logio - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "mod_logio - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c
+# ADD CPP /nologo /MD /W3 /O2 /Oy- /Zi /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Release\mod_logio_src" /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /fo"Release/mod_logio.res" /i "../../include" /i "../../srclib/apr/include" /d "NDEBUG" /d BIN_NAME="mod_logio.so" /d LONG_NAME="logio_module for Apache"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib /nologo /subsystem:windows /dll /out:".\Release\mod_logio.so" /base:@..\..\os\win32\BaseAddr.ref,mod_logio.so
+# ADD LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:".\Release\mod_logio.so" /base:@..\..\os\win32\BaseAddr.ref,mod_logio.so /opt:ref
+# Begin Special Build Tool
+TargetPath=.\Release\mod_logio.so
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2
+# End Special Build Tool
+
+!ELSEIF "$(CFG)" == "mod_logio - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MDd /W3 /EHsc /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /c
+# ADD CPP /nologo /MDd /W3 /EHsc /Zi /Od /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Debug\mod_logio_src" /FD /c
+# ADD BASE MTL /nologo /D "_DEBUG" /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /fo"Debug/mod_logio.res" /i "../../include" /i "../../srclib/apr/include" /d "_DEBUG" /d BIN_NAME="mod_logio.so" /d LONG_NAME="logio_module for Apache"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:".\Debug\mod_logio.so" /base:@..\..\os\win32\BaseAddr.ref,mod_logio.so
+# ADD LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:".\Debug\mod_logio.so" /base:@..\..\os\win32\BaseAddr.ref,mod_logio.so
+# Begin Special Build Tool
+TargetPath=.\Debug\mod_logio.so
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2
+# End Special Build Tool
+
+!ENDIF
+
+# Begin Target
+
+# Name "mod_logio - Win32 Release"
+# Name "mod_logio - Win32 Debug"
+# Begin Source File
+
+SOURCE=.\mod_logio.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\build\win32\httpd.rc
+# End Source File
+# End Target
+# End Project
diff --git a/modules/loggers/mod_logio.mak b/modules/loggers/mod_logio.mak
new file mode 100644
index 0000000..363e848
--- /dev/null
+++ b/modules/loggers/mod_logio.mak
@@ -0,0 +1,353 @@
+# Microsoft Developer Studio Generated NMAKE File, Based on mod_logio.dsp
+!IF "$(CFG)" == ""
+CFG=mod_logio - Win32 Release
+!MESSAGE No configuration specified. Defaulting to mod_logio - Win32 Release.
+!ENDIF
+
+!IF "$(CFG)" != "mod_logio - Win32 Release" && "$(CFG)" != "mod_logio - Win32 Debug"
+!MESSAGE Invalid configuration "$(CFG)" specified.
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "mod_logio.mak" CFG="mod_logio - Win32 Release"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "mod_logio - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "mod_logio - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE
+!ERROR An invalid configuration is specified.
+!ENDIF
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE
+NULL=nul
+!ENDIF
+
+!IF "$(CFG)" == "mod_logio - Win32 Release"
+
+OUTDIR=.\Release
+INTDIR=.\Release
+DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
+# Begin Custom Macros
+OutDir=.\Release
+# End Custom Macros
+
+!IF "$(RECURSE)" == "0"
+
+ALL : "$(OUTDIR)\mod_logio.so" "$(DS_POSTBUILD_DEP)"
+
+!ELSE
+
+ALL : "libhttpd - Win32 Release" "libaprutil - Win32 Release" "libapr - Win32 Release" "$(OUTDIR)\mod_logio.so" "$(DS_POSTBUILD_DEP)"
+
+!ENDIF
+
+!IF "$(RECURSE)" == "1"
+CLEAN :"libapr - Win32 ReleaseCLEAN" "libaprutil - Win32 ReleaseCLEAN" "libhttpd - Win32 ReleaseCLEAN"
+!ELSE
+CLEAN :
+!ENDIF
+ -@erase "$(INTDIR)\mod_logio.obj"
+ -@erase "$(INTDIR)\mod_logio.res"
+ -@erase "$(INTDIR)\mod_logio_src.idb"
+ -@erase "$(INTDIR)\mod_logio_src.pdb"
+ -@erase "$(OUTDIR)\mod_logio.exp"
+ -@erase "$(OUTDIR)\mod_logio.lib"
+ -@erase "$(OUTDIR)\mod_logio.pdb"
+ -@erase "$(OUTDIR)\mod_logio.so"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /MD /W3 /Zi /O2 /Oy- /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\mod_logio_src" /FD /c
+
+.c{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.c{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+MTL=midl.exe
+MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /win32
+RSC=rc.exe
+RSC_PROJ=/l 0x409 /fo"$(INTDIR)\mod_logio.res" /i "../../include" /i "../../srclib/apr/include" /d "NDEBUG" /d BIN_NAME="mod_logio.so" /d LONG_NAME="logio_module for Apache"
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\mod_logio.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+LINK32_FLAGS=kernel32.lib /nologo /subsystem:windows /dll /incremental:no /pdb:"$(OUTDIR)\mod_logio.pdb" /debug /out:"$(OUTDIR)\mod_logio.so" /implib:"$(OUTDIR)\mod_logio.lib" /base:@..\..\os\win32\BaseAddr.ref,mod_logio.so /opt:ref
+LINK32_OBJS= \
+ "$(INTDIR)\mod_logio.obj" \
+ "$(INTDIR)\mod_logio.res" \
+ "..\..\srclib\apr\Release\libapr-1.lib" \
+ "..\..\srclib\apr-util\Release\libaprutil-1.lib" \
+ "..\..\Release\libhttpd.lib"
+
+"$(OUTDIR)\mod_logio.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+TargetPath=.\Release\mod_logio.so
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
+
+# Begin Custom Macros
+OutDir=.\Release
+# End Custom Macros
+
+"$(DS_POSTBUILD_DEP)" : "$(OUTDIR)\mod_logio.so"
+ if exist .\Release\mod_logio.so.manifest mt.exe -manifest .\Release\mod_logio.so.manifest -outputresource:.\Release\mod_logio.so;2
+ echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)"
+
+!ELSEIF "$(CFG)" == "mod_logio - Win32 Debug"
+
+OUTDIR=.\Debug
+INTDIR=.\Debug
+DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
+# Begin Custom Macros
+OutDir=.\Debug
+# End Custom Macros
+
+!IF "$(RECURSE)" == "0"
+
+ALL : "$(OUTDIR)\mod_logio.so" "$(DS_POSTBUILD_DEP)"
+
+!ELSE
+
+ALL : "libhttpd - Win32 Debug" "libaprutil - Win32 Debug" "libapr - Win32 Debug" "$(OUTDIR)\mod_logio.so" "$(DS_POSTBUILD_DEP)"
+
+!ENDIF
+
+!IF "$(RECURSE)" == "1"
+CLEAN :"libapr - Win32 DebugCLEAN" "libaprutil - Win32 DebugCLEAN" "libhttpd - Win32 DebugCLEAN"
+!ELSE
+CLEAN :
+!ENDIF
+ -@erase "$(INTDIR)\mod_logio.obj"
+ -@erase "$(INTDIR)\mod_logio.res"
+ -@erase "$(INTDIR)\mod_logio_src.idb"
+ -@erase "$(INTDIR)\mod_logio_src.pdb"
+ -@erase "$(OUTDIR)\mod_logio.exp"
+ -@erase "$(OUTDIR)\mod_logio.lib"
+ -@erase "$(OUTDIR)\mod_logio.pdb"
+ -@erase "$(OUTDIR)\mod_logio.so"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /MDd /W3 /Zi /Od /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\mod_logio_src" /FD /EHsc /c
+
+.c{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.c{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+MTL=midl.exe
+MTL_PROJ=/nologo /D "_DEBUG" /mktyplib203 /win32
+RSC=rc.exe
+RSC_PROJ=/l 0x409 /fo"$(INTDIR)\mod_logio.res" /i "../../include" /i "../../srclib/apr/include" /d "_DEBUG" /d BIN_NAME="mod_logio.so" /d LONG_NAME="logio_module for Apache"
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\mod_logio.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+LINK32_FLAGS=kernel32.lib /nologo /subsystem:windows /dll /incremental:no /pdb:"$(OUTDIR)\mod_logio.pdb" /debug /out:"$(OUTDIR)\mod_logio.so" /implib:"$(OUTDIR)\mod_logio.lib" /base:@..\..\os\win32\BaseAddr.ref,mod_logio.so
+LINK32_OBJS= \
+ "$(INTDIR)\mod_logio.obj" \
+ "$(INTDIR)\mod_logio.res" \
+ "..\..\srclib\apr\Debug\libapr-1.lib" \
+ "..\..\srclib\apr-util\Debug\libaprutil-1.lib" \
+ "..\..\Debug\libhttpd.lib"
+
+"$(OUTDIR)\mod_logio.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+TargetPath=.\Debug\mod_logio.so
+SOURCE="$(InputPath)"
+PostBuild_Desc=Embed .manifest
+DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep
+
+# Begin Custom Macros
+OutDir=.\Debug
+# End Custom Macros
+
+"$(DS_POSTBUILD_DEP)" : "$(OUTDIR)\mod_logio.so"
+ if exist .\Debug\mod_logio.so.manifest mt.exe -manifest .\Debug\mod_logio.so.manifest -outputresource:.\Debug\mod_logio.so;2
+ echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)"
+
+!ENDIF
+
+
+!IF "$(NO_EXTERNAL_DEPS)" != "1"
+!IF EXISTS("mod_logio.dep")
+!INCLUDE "mod_logio.dep"
+!ELSE
+!MESSAGE Warning: cannot find "mod_logio.dep"
+!ENDIF
+!ENDIF
+
+
+!IF "$(CFG)" == "mod_logio - Win32 Release" || "$(CFG)" == "mod_logio - Win32 Debug"
+
+!IF "$(CFG)" == "mod_logio - Win32 Release"
+
+"libapr - Win32 Release" :
+ cd ".\..\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Release"
+ cd "..\..\modules\loggers"
+
+"libapr - Win32 ReleaseCLEAN" :
+ cd ".\..\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Release" RECURSE=1 CLEAN
+ cd "..\..\modules\loggers"
+
+!ELSEIF "$(CFG)" == "mod_logio - Win32 Debug"
+
+"libapr - Win32 Debug" :
+ cd ".\..\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Debug"
+ cd "..\..\modules\loggers"
+
+"libapr - Win32 DebugCLEAN" :
+ cd ".\..\..\srclib\apr"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Debug" RECURSE=1 CLEAN
+ cd "..\..\modules\loggers"
+
+!ENDIF
+
+!IF "$(CFG)" == "mod_logio - Win32 Release"
+
+"libaprutil - Win32 Release" :
+ cd ".\..\..\srclib\apr-util"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Release"
+ cd "..\..\modules\loggers"
+
+"libaprutil - Win32 ReleaseCLEAN" :
+ cd ".\..\..\srclib\apr-util"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Release" RECURSE=1 CLEAN
+ cd "..\..\modules\loggers"
+
+!ELSEIF "$(CFG)" == "mod_logio - Win32 Debug"
+
+"libaprutil - Win32 Debug" :
+ cd ".\..\..\srclib\apr-util"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Debug"
+ cd "..\..\modules\loggers"
+
+"libaprutil - Win32 DebugCLEAN" :
+ cd ".\..\..\srclib\apr-util"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Debug" RECURSE=1 CLEAN
+ cd "..\..\modules\loggers"
+
+!ENDIF
+
+!IF "$(CFG)" == "mod_logio - Win32 Release"
+
+"libhttpd - Win32 Release" :
+ cd ".\..\.."
+ $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Release"
+ cd ".\modules\loggers"
+
+"libhttpd - Win32 ReleaseCLEAN" :
+ cd ".\..\.."
+ $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Release" RECURSE=1 CLEAN
+ cd ".\modules\loggers"
+
+!ELSEIF "$(CFG)" == "mod_logio - Win32 Debug"
+
+"libhttpd - Win32 Debug" :
+ cd ".\..\.."
+ $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Debug"
+ cd ".\modules\loggers"
+
+"libhttpd - Win32 DebugCLEAN" :
+ cd ".\..\.."
+ $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Debug" RECURSE=1 CLEAN
+ cd ".\modules\loggers"
+
+!ENDIF
+
+SOURCE=..\..\build\win32\httpd.rc
+
+!IF "$(CFG)" == "mod_logio - Win32 Release"
+
+
+"$(INTDIR)\mod_logio.res" : $(SOURCE) "$(INTDIR)"
+ $(RSC) /l 0x409 /fo"$(INTDIR)\mod_logio.res" /i "../../include" /i "../../srclib/apr/include" /i "../../build\win32" /d "NDEBUG" /d BIN_NAME="mod_logio.so" /d LONG_NAME="logio_module for Apache" $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "mod_logio - Win32 Debug"
+
+
+"$(INTDIR)\mod_logio.res" : $(SOURCE) "$(INTDIR)"
+ $(RSC) /l 0x409 /fo"$(INTDIR)\mod_logio.res" /i "../../include" /i "../../srclib/apr/include" /i "../../build\win32" /d "_DEBUG" /d BIN_NAME="mod_logio.so" /d LONG_NAME="logio_module for Apache" $(SOURCE)
+
+
+!ENDIF
+
+SOURCE=.\mod_logio.c
+
+"$(INTDIR)\mod_logio.obj" : $(SOURCE) "$(INTDIR)"
+
+
+
+!ENDIF
+