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 */ };