akosut 96/08/19 11:12:37
Modified: src mod_log_config.c
Log:
Add CustomLog capability to mod_log_config.
Submitted by: Paul Sutton
Reviewed by: Alexei Kosut, Mark J Cox
Revision Changes Path
1.9 +231 -75 apache/src/mod_log_config.c
Index: mod_log_config.c
===================================================================
RCS file: /export/home/cvs/apache/src/mod_log_config.c,v
retrieving revision 1.8
retrieving revision 1.9
diff -C3 -r1.8 -r1.9
*** mod_log_config.c 1996/08/06 19:33:31 1.8
--- mod_log_config.c 1996/08/19 18:12:35 1.9
***************
*** 54,63 ****
/*
* This is module implements the TransferLog directive (same as the
! * common log module), and an additional directive, LogFormat.
*
! * The argument to LogFormat is a string, which can include literal
! * characters copied into the log files, and '%' directives as follows:
*
* %...b: bytes sent.
* %...h: remote host
--- 54,112 ----
/*
* 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 compatable
! * 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"
! *
! * Except: no RefererIgnore functionality
! * logs '-' if no Referer or User-Agent instead of nothing
! *
! * 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.
* %...h: remote host
***************
*** 117,122 ****
--- 166,201 ----
static mode_t xfer_mode = ( S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH );
#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 a pointer to
+ * the logs specified for the main server for virtual servers, so that
+ * if this vhost has now 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 in 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 {
+ array_header *default_format;
+ array_header *config_logs;
+ array_header *server_config_logs;
+ } multi_log_state;
+
+ /*
+ * config_log_state holds the status of a single log file. fname cannot
+ * be NULL. 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_fd is -1 before the log file is opened and set to a valid
+ * fd after it is opened.
+ */
+
typedef struct {
char *fname;
array_header *format;
***************
*** 414,448 ****
return cp ? cp : "-";
}
! int config_log_transaction(request_rec *r)
! {
! config_log_state *cls = get_module_config (r->server->module_config,
! &config_log_module);
!
! array_header *strsa= make_array(r->pool,
cls->format->nelts,sizeof(char*));
! log_format_item *items = (log_format_item *)cls->format->elts;
char *str, **strs, *s;
request_rec *orig;
int i;
int len = 0;
orig = r;
while (orig->prev) orig = orig->prev;
while (r->next) r = r->next;
! for (i = 0; i < cls->format->nelts; ++i)
! *((char**)push_array (strsa)) = process_item (r, orig, &items[i]);
strs = (char **)strsa->elts;
! for (i = 0; i < cls->format->nelts; ++i)
! len += strlen (strs[i]);
str = palloc (r->pool, len + 1);
! for (i = 0, s = str; i < cls->format->nelts; ++i) {
! strcpy (s, strs[i]);
! s += strlen (strs[i]);
}
write(cls->log_fd, str, strlen(str));
--- 493,530 ----
return cp ? cp : "-";
}
! int config_log_transaction(request_rec *r, config_log_state *cls,
! array_header *default_format) {
! array_header *strsa;
! log_format_item *items;
char *str, **strs, *s;
request_rec *orig;
int i;
int len = 0;
+ array_header *format;
+
+ format = cls->format ? cls->format : default_format;
+
+ strsa= make_array(r->pool, format->nelts,sizeof(char*));
+ 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)
! *((char**)push_array (strsa)) = process_item (r, orig, &items[i]);
strs = (char **)strsa->elts;
! for (i = 0; i < format->nelts; ++i)
! len += strlen (strs[i]);
str = palloc (r->pool, len + 1);
! for (i = 0, s = str; i < format->nelts; ++i) {
! strcpy (s, strs[i]);
! s += strlen (strs[i]);
}
write(cls->log_fd, str, strlen(str));
***************
*** 450,455 ****
--- 532,564 ----
return OK;
}
+ int multi_log_transaction(request_rec *r)
+ {
+ multi_log_state *mls = get_module_config (r->server->module_config,
+ &config_log_module);
+ config_log_state *clsarray;
+ int i;
+
+ 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);
+ }
+ }
+ 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];
+
+ config_log_transaction(r, cls, mls->default_format);
+ }
+ }
+
+ return OK;
+ }
+
/*****************************************************************
*
* Module glue...
***************
*** 457,496 ****
void *make_config_log_state (pool *p, server_rec *s)
{
! config_log_state *cls =
! (config_log_state *)palloc (p, sizeof (config_log_state));
! cls->fname = NULL;
! cls->format = NULL;
! cls->log_fd = -1;
! return (void *)cls;
}
! char *set_config_log (cmd_parms *parms, void *dummy, char *arg)
{
! config_log_state *cls = get_module_config (parms->server->module_config,
&config_log_module);
! cls->fname = arg;
! return NULL;
}
! char *log_format (cmd_parms *cmd, void *dummy, char *arg)
{
char *err_string = NULL;
! config_log_state *cls = get_module_config (cmd->server->module_config,
! &config_log_module);
!
! cls->format = parse_log_string (cmd->pool, arg, &err_string);
return err_string;
}
command_rec config_log_cmds[] = {
! { "TransferLog", set_config_log, NULL, RSRC_CONF, TAKE1,
"the filename of the access log" },
{ "LogFormat", log_format, NULL, RSRC_CONF, TAKE1,
! "a log format string (see docs)" },
{ NULL }
};
--- 566,639 ----
void *make_config_log_state (pool *p, server_rec *s)
{
! multi_log_state *mls =
! (multi_log_state *)palloc(p, sizeof (multi_log_state));
!
! mls->config_logs =
! make_array(p, 5, sizeof (config_log_state));
! mls->default_format = NULL;
! mls->server_config_logs = NULL;
!
! 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
! */
! void *merge_config_log_state (pool *p, void *basev, void *addv)
! {
! multi_log_state *base = (multi_log_state *)basev;
! multi_log_state *add = (multi_log_state *)addv;
! multi_log_state *new =
! (multi_log_state *)palloc (p, sizeof(multi_log_state));
!
! add->server_config_logs = base->config_logs;
!
! return add;
}
! char *log_format (cmd_parms *cmd, void *dummy, char *arg)
{
! char *err_string = NULL;
! multi_log_state *mls = get_module_config (cmd->server->module_config,
&config_log_module);
! mls->default_format = parse_log_string (cmd->pool, arg, &err_string);
! return err_string;
}
! char *add_custom_log(cmd_parms *cmd, void *dummy, char *fn, char *fmt)
{
char *err_string = NULL;
! multi_log_state *mls = get_module_config (cmd->server->module_config,
! &config_log_module);
! config_log_state *cls;
!
! cls = (config_log_state*)push_array(mls->config_logs);
! cls->fname = fn;
! if (!fmt)
! cls->format = NULL;
! else
! cls->format = parse_log_string (cmd->pool, fmt, &err_string);
! cls->log_fd = -1;
!
return err_string;
}
+ char *set_transfer_log(cmd_parms *cmd, void *dummy, char *fn)
+ {
+ return add_custom_log(cmd, dummy, fn, NULL);
+ }
+
command_rec config_log_cmds[] = {
! { "CustomLog", add_custom_log, NULL, RSRC_CONF, TAKE2,
! "a file name and a custom log format string" },
! { "TransferLog", set_transfer_log, NULL, RSRC_CONF, TAKE1,
"the filename of the access log" },
{ "LogFormat", log_format, NULL, RSRC_CONF, TAKE1,
! "a log format string (see docs)" },
{ NULL }
};
***************
*** 509,573 ****
}
config_log_state *open_config_log (server_rec *s, pool *p,
! config_log_state *defaults)
! {
! config_log_state *cls = get_module_config (s->module_config,
! &config_log_module);
!
if (cls->log_fd > 0) return cls; /* virtual config shared w/main server
*/
-
- if (cls->format == NULL) {
- char *dummy;
-
- if (defaults) cls->format = defaults->format;
- else cls->format = parse_log_string (p, DEFAULT_LOG_FORMAT, &dummy);
- }
- if (cls->fname == NULL) {
- if (defaults) {
- cls->log_fd = defaults->log_fd;
- return cls;
- }
- else cls->fname = DEFAULT_XFERLOG;
- }
-
if (*cls->fname == '|') {
! FILE *dummy;
!
! spawn_child(p, config_log_child, (void *)(cls->fname+1),
! kill_after_timeout, &dummy, NULL);
!
! if (dummy == NULL) {
! fprintf (stderr, "Couldn't fork child for TransferLog process\n");
! exit (1);
! }
! cls->log_fd = fileno (dummy);
}
else {
! char *fname = server_root_relative (p, cls->fname);
! if((cls->log_fd = popenf(p, fname, xfer_flags, xfer_mode)) < 0) {
! fprintf (stderr,
! "httpd: could not open transfer log file %s.\n", fname);
! perror("open");
! exit(1);
! }
}
return cls;
}
void init_config_log (server_rec *s, pool *p)
{
/* First, do "physical" server, which gets default log fd and format
* for the virtual servers, if they don't override...
*/
! config_log_state *default_conf = open_config_log (s, p, NULL);
/* Then, virtual servers */
! for (s = s->next; s; s = s->next) open_config_log (s, p, default_conf);
}
module config_log_module = {
--- 652,729 ----
}
config_log_state *open_config_log (server_rec *s, pool *p,
! config_log_state *cls,
! array_header *default_format) {
if (cls->log_fd > 0) return cls; /* virtual config shared w/main server
*/
if (*cls->fname == '|') {
! FILE *dummy;
!
! spawn_child(p, config_log_child, (void *)(cls->fname+1),
! kill_after_timeout, &dummy, NULL);
!
! if (dummy == NULL) {
! fprintf (stderr, "Couldn't fork child for TransferLog
process\n");
! exit (1);
! }
! cls->log_fd = fileno (dummy);
}
else {
! char *fname = server_root_relative (p, cls->fname);
! if((cls->log_fd = popenf(p, fname, xfer_flags, xfer_mode)) < 0) {
! fprintf (stderr,
! "httpd: could not open transfer log file %s.\n",
fname);
! perror("open");
! exit(1);
! }
}
return cls;
}
+ config_log_state *open_multi_logs (server_rec *s, pool *p)
+ {
+ int i;
+ multi_log_state *mls = get_module_config(s->module_config,
+ &config_log_module);
+ config_log_state *clsarray;
+ char *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];
+
+ cls = open_config_log(s, p, cls, mls->default_format);
+ }
+ }
+ 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];
+
+ cls = open_config_log(s, p, cls, mls->default_format);
+ }
+ }
+
+ return NULL;
+ }
+
void init_config_log (server_rec *s, pool *p)
{
/* First, do "physical" server, which gets default log fd and format
* for the virtual servers, if they don't override...
*/
! open_multi_logs (s, p);
/* Then, virtual servers */
! for (s = s->next; s; s = s->next) open_multi_logs (s, p);
}
module config_log_module = {
***************
*** 576,582 ****
NULL, /* create per-dir config */
NULL, /* merge per-dir config */
make_config_log_state, /* server config */
! NULL, /* merge server config */
config_log_cmds, /* command table */
NULL, /* handlers */
NULL, /* filename translation */
--- 732,738 ----
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 table */
NULL, /* handlers */
NULL, /* filename translation */
***************
*** 585,589 ****
NULL, /* check access */
NULL, /* type_checker */
NULL, /* fixups */
! config_log_transaction /* logger */
};
--- 741,745 ----
NULL, /* check access */
NULL, /* type_checker */
NULL, /* fixups */
! multi_log_transaction /* logger */
};