diff -Naur apache_1.3.6+01-02/htdocs/manual/mod/mod_log_config.html apache_1.3.6+01-03/htdocs/manual/mod/mod_log_config.html --- apache_1.3.6+01-02/htdocs/manual/mod/mod_log_config.html Mon Mar 22 16:17:41 1999 +++ apache_1.3.6+01-03/htdocs/manual/mod/mod_log_config.html Thu Jul 15 13:11:41 1999 @@ -172,9 +172,10 @@

Note that the common log format is defined by the string "%h %l -%u %t \"%r\" %s %b", which can be used as the basis for +%u %t \"%r\" %>s %b", which can be used as the basis for extending for format if desired (e.g., to add extra fields at the end). -NCSA's extended/combined log format would be "%h %l %u %t \"%r\" %s %b \"%{Referer}i\" \"%{User-agent}i\"". +NCSA's extended/combined log format would be "%h %l %u %t \"%r\" +%>s %b \"%{Referer}i\" \"%{User-agent}i\"".

@@ -205,6 +206,33 @@ See the examples below.

+

Performance Issues

+ +When Apache is compiled with USE_QUICK_LOG defined, logging +in Common Log Format (CLF) is extra fast. This module recognizes and +accelerates two variants of CLF: + + + +Numeric CLF is the same as using standard CLF with HostNameLookups off: +both log IP addresses rather than host names. Logging IP addresses is +much faster than logging host names. + +

Buffering log entries also increases performance, but at the cost of +delaying writing those entries to disk. Compile Apache with +BUFFERED_LOGS defined to buffer log entries. The standard +amount buffered is PIPE_BUF bytes (a POSIX defined +constant). For an even faster web server you can increase the buffering +by defining LOG_BUFSIZE to be the number of bytes you want +buffered. Beware though: increase LOG_BUFSIZE beyond +PIPE_BUF only if you know you're not using piped logs and +your system can write more than PIPE_BUF bytes atomically +to disk at once +

Security Considerations

See the security tips @@ -363,7 +391,7 @@ HREF="directive-dict.html#Default" REL="Help" >Default: LogFormat "%h %l %u %t \"%r\" -%s %b"
+%>s %b"
+#ifdef NO_WRITEV +struct iovec { + void *iov_base; + size_t iov_len; +}; +#else +#include +#endif + #ifdef __cplusplus extern "C" { #endif diff -Naur apache_1.3.6+01-02/src/include/httpd.h apache_1.3.6+01-03/src/include/httpd.h --- apache_1.3.6+01-02/src/include/httpd.h Wed Jul 14 15:47:23 1999 +++ apache_1.3.6+01-03/src/include/httpd.h Thu Jul 15 10:25:51 1999 @@ -66,6 +66,12 @@ * httpd.h: header for simple (ha! not anymore) http daemon */ +/* Mike Abbott - mja@sgi.com */ +#ifdef SPEED_DAEMON /* that's me, a real speed demon */ +# define BUFFERED_LOGS /* buffer log messages */ +# define USE_QUICK_LOG /* fast path through logging code */ +#endif + /* Headers in which EVERYONE has an interest... */ #include "ap_types.h" @@ -652,6 +658,7 @@ */ char *the_request; /* First line of request, so we can log it */ + int the_request_len; /* strlen(the_request) */ int assbackwards; /* HTTP/0.9, "simple" request */ int proxyreq; /* A proxy request (calculated during * post_read_request or translate_name) */ @@ -805,7 +812,8 @@ struct sockaddr_in local_addr; /* local address */ struct sockaddr_in remote_addr; /* remote address */ - char *remote_ip; /* Client's IP address */ + char remote_ip[16]; /* Client's IP address */ + int remote_ip_len; /* strlen(remote_ip) */ char *remote_host; /* Client's DNS name, if known. * NULL if DNS hasn't been checked, * "" if it has and no address was found. @@ -983,6 +991,7 @@ API_EXPORT(char *) ap_escape_quotes (pool *p, const char *instring); +API_EXPORT(char *) ap_inet_ntoa(struct in_addr, char * /* 16 bytes */, int *); API_EXPORT(int) ap_oversized_file(off_t); /* Common structure for reading of config files / passwd files etc. */ diff -Naur apache_1.3.6+01-02/src/main/buff.c apache_1.3.6+01-03/src/main/buff.c --- apache_1.3.6+01-02/src/main/buff.c Thu Jul 8 13:34:58 1999 +++ apache_1.3.6+01-03/src/main/buff.c Thu Jul 15 14:05:15 1999 @@ -63,10 +63,6 @@ #include #include #include -#ifndef NO_WRITEV -#include -#include -#endif #ifdef HAVE_BSTRING_H #include /* for IRIX, FD_SET calls bzero() */ diff -Naur apache_1.3.6+01-02/src/main/http_main.c apache_1.3.6+01-03/src/main/http_main.c --- apache_1.3.6+01-02/src/main/http_main.c Thu Jul 8 13:34:58 1999 +++ apache_1.3.6+01-03/src/main/http_main.c Thu Jul 15 12:25:03 1999 @@ -2986,8 +2986,8 @@ conn->client = inout; conn->remote_addr = *remaddr; - conn->remote_ip = ap_pstrdup(conn->pool, - inet_ntoa(conn->remote_addr.sin_addr)); + ap_inet_ntoa(conn->remote_addr.sin_addr, conn->remote_ip, + &conn->remote_ip_len); return conn; } @@ -3024,10 +3024,12 @@ int one = 1; char addr[512]; - if (server->sin_addr.s_addr != (ap_uint32) htonl(INADDR_ANY)) + if (server->sin_addr.s_addr != htonl(INADDR_ANY)) { + char nbuf[16]; ap_snprintf(addr, sizeof(addr), "address %s port %d", - inet_ntoa(server->sin_addr), ntohs(server->sin_port)); - else + ap_inet_ntoa(server->sin_addr, nbuf, NULL), + ntohs(server->sin_port)); + } else ap_snprintf(addr, sizeof(addr), "port %d", ntohs(server->sin_port)); /* note that because we're about to slack we don't use psocket */ @@ -3420,6 +3422,7 @@ #endif #ifdef BUFFERED_LOGS printf(" -D BUFFERED_LOGS\n"); + printf(" -D LOG_BUFSIZE=%d\n", LOG_BUFSIZE); #ifdef PIPE_BUF printf(" -D PIPE_BUF=%ld\n",(long)PIPE_BUF); #endif diff -Naur apache_1.3.6+01-02/src/main/http_protocol.c apache_1.3.6+01-03/src/main/http_protocol.c --- apache_1.3.6+01-02/src/main/http_protocol.c Wed Jul 14 17:19:12 1999 +++ apache_1.3.6+01-03/src/main/http_protocol.c Thu Jul 15 10:29:50 1999 @@ -840,6 +840,7 @@ r->request_time = time(NULL); r->the_request = r->rqbuf; + r->the_request_len = (int) (cp + 9 - r->rqbuf); r->method = "GET"; r->method_number = M_GET; ap_assert(!r->assbackwards); @@ -916,6 +917,7 @@ r->request_time = time(NULL); r->the_request = ap_pstrndup(r->pool, l, len); + r->the_request_len = len; r->method = ap_getword_white(r->pool, &ll); uri = ap_getword_white(r->pool, &ll); @@ -1314,6 +1316,7 @@ void ap_set_sub_req_protocol(request_rec *rnew, const request_rec *r) { rnew->the_request = r->the_request; /* Keep original request-line */ + rnew->the_request_len = r->the_request_len; rnew->assbackwards = 1; /* Don't send headers from this. */ rnew->no_local_copy = 1; /* Don't try to send USE_LOCAL_COPY for a diff -Naur apache_1.3.6+01-02/src/main/http_request.c apache_1.3.6+01-03/src/main/http_request.c --- apache_1.3.6+01-02/src/main/http_request.c Thu Jul 8 12:28:26 1999 +++ apache_1.3.6+01-03/src/main/http_request.c Thu Jul 15 10:30:03 1999 @@ -1289,6 +1289,7 @@ /* Inherit the rest of the protocol info... */ new->the_request = r->the_request; + new->the_request_len = r->the_request_len; new->allowed = r->allowed; diff -Naur apache_1.3.6+01-02/src/main/http_vhost.c apache_1.3.6+01-03/src/main/http_vhost.c --- apache_1.3.6+01-02/src/main/http_vhost.c Thu Jul 8 12:28:36 1999 +++ apache_1.3.6+01-03/src/main/http_vhost.c Thu Jul 15 10:30:09 1999 @@ -607,11 +607,12 @@ else { /* again, what can we do? They didn't specify a ServerName, and their DNS isn't working. -djg */ + char nbuf[16]; ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, main_s, "Failed to resolve server name " "for %s (check DNS) -- or specify an explicit " "ServerName", - inet_ntoa(s->addrs->host_addr)); + ap_inet_ntoa(s->addrs->host_addr, nbuf, NULL)); s->server_hostname = ap_pstrdup(p, "bogus_host_without_reverse_dns"); } diff -Naur apache_1.3.6+01-02/src/main/util.c apache_1.3.6+01-03/src/main/util.c --- apache_1.3.6+01-02/src/main/util.c Thu Jul 8 12:31:15 1999 +++ apache_1.3.6+01-03/src/main/util.c Thu Jul 15 10:30:25 1999 @@ -2189,6 +2189,50 @@ return outstring; } +/* + * Fast implementation of inet_ntoa(). buf should be 16 bytes. Returns + * buf and, if rlen is non-null, sets *rlen to strlen(buf). + */ +API_EXPORT(char *) +ap_inet_ntoa(struct in_addr in, char *buf, int *rlen) +{ + int i; + char *bp; + + /* + * This implementation is fast because it avoids sprintf(), + * division/modulo, and global static array lookups. + */ + + bp = buf; + for (i = 0; i < 4; i++) { + unsigned int o, n; + + o = ((unsigned char *) &in)[i]; + n = o; + if (n >= 200) { + *bp++ = '2'; + n -= 200; + } else if (n >= 100) { + *bp++ = '1'; + n -= 100; + } + if (o >= 10) { + int i; + for (i = 0; n >= 10; i++) + n -= 10; + *bp++ = i + '0'; + } + *bp++ = n + '0'; + *bp++ = '.'; + } + *--bp = 0; + if (rlen) + *rlen = (int) (bp - buf); + + return buf; +} + /* Return nonzero if the given file size is too large to serve. */ API_EXPORT(int) ap_oversized_file(off_t size) diff -Naur apache_1.3.6+01-02/src/modules/standard/mod_log_config.c apache_1.3.6+01-03/src/modules/standard/mod_log_config.c --- apache_1.3.6+01-02/src/modules/standard/mod_log_config.c Thu Jul 15 12:50:23 1999 +++ apache_1.3.6+01-03/src/modules/standard/mod_log_config.c Thu Jul 15 13:41:12 1999 @@ -166,8 +166,12 @@ * * --- rst */ -#define DEFAULT_LOG_FORMAT "%h %l %u %t \"%r\" %>s %b" +static const char common_log_format[] = "%h %l %u %t \"%r\" %>s %b"; +#define QUICK_CLF_MARKER ((array_header *) (ap_ptr) 0x1) +static const char quick_log_format[] = "%a %l %u %t \"%r\" %>s %b"; +#define QUICK_QLF_MARKER ((array_header *) (ap_ptr) 0x2) + #include "httpd.h" #include "http_config.h" #include "http_core.h" /* For REMOTE_NAME */ @@ -184,6 +188,12 @@ static mode_t xfer_mode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); #endif +/* + * Increasing LOG_BUFSIZE beyond PIPE_BUF is good for performance but do + * so only if you know you're not using piped logs and your system can + * write more than PIPE_BUF bytes atomically to disk at once + */ +#ifndef LOG_BUFSIZE /* 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 @@ -198,6 +208,7 @@ #else #define LOG_BUFSIZE (512) #endif +#endif /* * multi_log_state is our per-(virtual)-server configuration. We store @@ -248,39 +259,25 @@ * Note that many of these could have ap_sprintfs replaced with static buffers. */ -typedef const char *(*item_key_func) (request_rec *, char *); +typedef const char *(*item_key_func) (request_rec *, char *, size_t *); typedef struct { item_key_func func; char *arg; + size_t arglen; int condition_sense; int want_orig; array_header *conditions; } log_format_item; -static char *format_integer(pool *p, int i) -{ - return ap_psprintf(p, "%d", i); -} - -static char *pfmt(pool *p, int i) -{ - if (i <= 0) { - return "-"; - } - else { - return format_integer(p, i); - } -} - /*ARGSUSED*/ -static const char *constant_item(request_rec *dummy, char *stuff) +static const char *constant_item(request_rec *dummy, char *stuff, size_t *rlen) { return stuff; } /*ARGSUSED1*/ -static const char *log_remote_host(request_rec *r, char *a) +static const char *log_remote_host(request_rec *r, char *a, size_t *rlen) { return ap_get_remote_host(r->connection, r->per_dir_config, REMOTE_NAME); @@ -287,82 +284,112 @@ } /*ARGSUSED1*/ -static const char *log_remote_address(request_rec *r, char *a) +static const char *log_remote_address(request_rec *r, char *a, size_t *rlen) { + *rlen = r->connection->remote_ip_len; return r->connection->remote_ip; } /*ARGSUSED1*/ -static const char *log_remote_logname(request_rec *r, char *a) +static const char *log_remote_logname(request_rec *r, char *a, size_t *rlen) { return ap_get_remote_logname(r); } -/*ARGSUSED1*/ -static const char *log_remote_user(request_rec *r, char *a) +/*ARGSUSED*/ +static const char *log_remote_user(request_rec *r, char *a, size_t *rlen) { char *rvalue = r->connection->user; - if (rvalue == NULL) { - rvalue = "-"; - } - else if (strlen(rvalue) == 0) { - rvalue = "\"\""; + if (rvalue && *rvalue == 0) { + rvalue = "\"\""; + *rlen = 2; } + return rvalue; } /*ARGSUSED1*/ -static const char *log_request_line(request_rec *r, char *a) +static const char *log_request_line(request_rec *r, char *a, size_t *rlen) { - /* 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 (r->parsed_uri.password) ? ap_pstrcat(r->pool, r->method, " ", - ap_unparse_uri_components(r->pool, &r->parsed_uri, 0), - r->assbackwards ? NULL : " ", r->protocol, NULL) - : r->the_request; + /* 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) + */ + + if (r->parsed_uri.password == NULL) { + *rlen = r->the_request_len; + return r->the_request; + } + + return ap_pstrcat(r->pool, r->method, " ", + ap_unparse_uri_components(r->pool, &r->parsed_uri, 0), + r->assbackwards ? NULL : " ", r->protocol, NULL); } /*ARGSUSED1*/ -static const char *log_request_file(request_rec *r, char *a) +static const char *log_request_file(request_rec *r, char *a, size_t *rlen) { return r->filename; } /*ARGSUSED1*/ -static const char *log_request_uri(request_rec *r, char *a) +static const char *log_request_uri(request_rec *r, char *a, size_t *rlen) { return r->uri; } -/*ARGSUSED1*/ -static const char *log_status(request_rec *r, char *a) +/*ARGSUSED*/ +static const char *log_status(request_rec *r, char *a, size_t *rlen) { - return pfmt(r->pool, r->status); + /* Cache the last converted status. */ + static struct { + int status; + char str[16]; + size_t len; + } last; + + if (r->status > 0) { + if (r->status != last.status) { + last.status = r->status; + last.len = sprintf(last.str, "%d", last.status); + } + + *rlen = last.len; + return last.str; + } + + return NULL; } /*ARGSUSED1*/ -static const char *log_bytes_sent(request_rec *r, char *a) +static const char *log_bytes_sent(request_rec *r, char *a, size_t *rlen) { - if (!r->sent_bodyct) { - return "-"; - } + const char *cp; + const char *length; + + if (!r->sent_bodyct) + cp = NULL; + else if ((length = ap_table_get(r->headers_out, "Content-Length")) != NULL) + cp = length; else { ap_int32 bs; ap_bgetopt(r->connection->client, BO_BYTECT, &bs); - return ap_psprintf(r->pool, "%ld", (long) bs); + cp = ap_psprintf(r->pool, "%ld", (long) bs); } + + return cp; } -static const char *log_header_in(request_rec *r, char *a) +/*ARGSUSED2*/ +static const char *log_header_in(request_rec *r, char *a, size_t *rlen) { return ap_table_get(r->headers_in, a); } -static const char *log_header_out(request_rec *r, char *a) +/*ARGSUSED2*/ +static const char *log_header_out(request_rec *r, char *a, size_t *rlen) { const char *cp = ap_table_get(r->headers_out, a); if (!strcasecmp(a, "Content-type") && r->content_type) { @@ -374,16 +401,20 @@ return ap_table_get(r->err_headers_out, a); } -static const char *log_note(request_rec *r, char *a) +/*ARGSUSED2*/ +static const char *log_note(request_rec *r, char *a, size_t *rlen) { return ap_table_get(r->notes, a); } -static const char *log_env_var(request_rec *r, char *a) + +/*ARGSUSED2*/ +static const char *log_env_var(request_rec *r, char *a, size_t *rlen) { return ap_table_get(r->subprocess_env, a); } -static const char *log_request_time(request_rec *r, char *a) +/*ARGSUSED2*/ +static const char *log_request_time(request_rec *r, char *a, size_t *rlen) { int timz; struct tm *t; @@ -412,7 +443,7 @@ } /*ARGSUSED1*/ -static const char *log_request_duration(request_rec *r, char *a) +static const char *log_request_duration(request_rec *r, char *a, size_t *rlen) { return ap_psprintf(r->pool, "%ld", (long) (time(NULL) - r->request_time)); } @@ -421,13 +452,13 @@ * parsers don't need to duplicate all the vhost parsing crud. */ /*ARGSUSED1*/ -static const char *log_virtual_host(request_rec *r, char *a) +static const char *log_virtual_host(request_rec *r, char *a, size_t *rlen) { return r->server->server_hostname; } /*ARGSUSED1*/ -static const char *log_server_port(request_rec *r, char *a) +static const char *log_server_port(request_rec *r, char *a, size_t *rlen) { return ap_psprintf(r->pool, "%u", r->server->port ? r->server->port : ap_default_port(r)); @@ -437,13 +468,13 @@ * the dynamic mass virtual hosting trick works better. */ /*ARGSUSED1*/ -static const char *log_server_name(request_rec *r, char *a) +static const char *log_server_name(request_rec *r, char *a, size_t *rlen) { return ap_get_server_name(r); } /*ARGSUSED1*/ -static const char *log_child_pid(request_rec *r, char *a) +static const char *log_child_pid(request_rec *r, char *a, size_t *rlen) { return ap_psprintf(r->pool, "%ld", (long) getpid()); } @@ -586,6 +617,7 @@ } } *d = '\0'; + it->arglen = d - it->arg; *sa = s; return NULL; @@ -604,6 +636,7 @@ it->conditions = NULL; it->want_orig = -1; it->arg = ""; /* For safety's sake... */ + it->arglen = 0; while (*s) { int i; @@ -678,9 +711,17 @@ static array_header *parse_log_string(pool *p, const char *s, const char **err) { - array_header *a = ap_make_array(p, 30, sizeof(log_format_item)); + array_header *a; char *res; +#ifdef USE_QUICK_LOG + if (s == common_log_format || !strcmp(s, common_log_format)) + return QUICK_CLF_MARKER; + else if (s == quick_log_format || !strcmp(s, quick_log_format)) + return QUICK_QLF_MARKER; +#endif + + a = ap_make_array(p, 30, sizeof(log_format_item)); while (*s) { if ((res = parse_log_item(p, (log_format_item *) ap_push_array(a), &s))) { *err = res; @@ -699,9 +740,10 @@ */ static const char *process_item(request_rec *r, request_rec *orig, - log_format_item *item) + log_format_item *item, size_t *rlen) { const char *cp; + static const char dash[2] = "-"; /* First, see if we need to process this thing at all... */ @@ -719,14 +761,20 @@ if ((item->condition_sense && in_list) || (!item->condition_sense && !in_list)) { - return "-"; + *rlen = 1; + return dash; } } /* We do. Do it... */ - cp = (*item->func) (item->want_orig ? orig : r, item->arg); - return cp ? cp : "-"; + *rlen = item->arglen; + cp = (*item->func) (item->want_orig ? orig : r, item->arg, rlen); + if (cp) + return cp; + + *rlen = 1; + return dash; } #ifdef BUFFERED_LOGS @@ -739,18 +787,162 @@ } #endif +static void +log_vec(request_rec *r, config_log_state *cls, struct iovec *iovec, + int iovcnt, size_t len) +{ + int i; + char *s; + +#ifdef BUFFERED_LOGS + if (len + cls->outcnt > LOG_BUFSIZE) + flush_log(cls); + if (len < LOG_BUFSIZE) { + for (i = 0, s = &cls->outbuf[cls->outcnt]; i < iovcnt; i++) { + memcpy(s, iovec[i].iov_base, iovec[i].iov_len); + s += iovec[i].iov_len; + } + cls->outcnt += len; + } else { +#endif + char *str = ap_palloc(r->pool, len); + for (i = 0, s = str; i < iovcnt; i++) { + memcpy(s, iovec[i].iov_base, iovec[i].iov_len); + s += iovec[i].iov_len; + } + write(cls->log_fd, str, len); +#ifdef BUFFERED_LOGS + } +#endif +} + +#ifdef USE_QUICK_LOG +static int quick_log(request_rec *r, request_rec *orig, config_log_state *cls, + const array_header *format) +{ + struct iovec iovec[14]; + static const char sqsdn[6] = " \" -\n"; + + /* + * format is either: + * QUICK_CLF_MARKER for "%h %l %u %t \"%r\" %>s %b\n" + * or + * QUICK_QLF_MARKER for "%a %l %u %t \"%r\" %>s %b\n" + */ + + /* "%h" or "%a" */ + iovec[0].iov_len = 0; + iovec[0].iov_base = (format == QUICK_QLF_MARKER) ? + (void *) log_remote_address(r, NULL, &iovec[0].iov_len) : + (void *) log_remote_host(r, NULL, &iovec[0].iov_len); + if (iovec[0].iov_base) { + if (iovec[0].iov_len == 0) + iovec[0].iov_len = strlen(iovec[0].iov_base); + } else { + iovec[0].iov_base = (void *) &sqsdn[3]; + iovec[0].iov_len = 1; + } + + /* " " */ + iovec[1].iov_base = (void *) sqsdn; + iovec[1].iov_len = 1; + + /* "%l" */ + iovec[2].iov_len = 0; + iovec[2].iov_base = (void *) log_remote_logname(r, NULL, &iovec[2].iov_len); + if (iovec[2].iov_base == NULL) { + iovec[2].iov_base = (void *) &sqsdn[3]; + iovec[2].iov_len = 1; + } else if (iovec[2].iov_len == 0) + iovec[2].iov_len = strlen(iovec[2].iov_base); + + /* " " */ + iovec[3].iov_base = (void *) sqsdn; + iovec[3].iov_len = 1; + + /* "%u" */ + iovec[4].iov_len = 0; + iovec[4].iov_base = (void *) log_remote_user(r, NULL, &iovec[4].iov_len); + if (iovec[4].iov_base == NULL) { + iovec[4].iov_base = (void *) &sqsdn[3]; + iovec[4].iov_len = 1; + } else if (iovec[4].iov_len == 0) + iovec[4].iov_len = strlen(iovec[4].iov_base); + + /* " " */ + iovec[5].iov_base = (void *) sqsdn; + iovec[5].iov_len = 1; + + /* "%t" */ + iovec[6].iov_len = 0; + iovec[6].iov_base = (void *) log_request_time(r, NULL, &iovec[6].iov_len); + if (iovec[6].iov_len == 0) + iovec[6].iov_len = strlen(iovec[6].iov_base); + + /* " \"" */ + iovec[7].iov_base = (void *) sqsdn; + iovec[7].iov_len = 2; + + /* "%r" */ + iovec[8].iov_len = 0; + iovec[8].iov_base = (void *) log_request_line(orig, NULL, &iovec[8].iov_len); + if (iovec[8].iov_len == 0) + iovec[8].iov_len = strlen(iovec[8].iov_base); + + /* "\" " */ + iovec[9].iov_base = (void *) &sqsdn[1]; + iovec[9].iov_len = 2; + + /* "%>s" */ + iovec[10].iov_len = 0; + iovec[10].iov_base = (void *) log_status(r, NULL, &iovec[10].iov_len); + if (iovec[10].iov_base) { + if (iovec[10].iov_len == 0) + iovec[10].iov_len = strlen(iovec[10].iov_base); + } else { + iovec[10].iov_base = (void *) &sqsdn[3]; + iovec[10].iov_len = 1; + } + + /* " " */ + iovec[11].iov_base = (void *) sqsdn; + iovec[11].iov_len = 1; + + /* "%b" */ + iovec[12].iov_len = 0; + iovec[12].iov_base = (void *) log_bytes_sent(r, NULL, &iovec[12].iov_len); + if (iovec[12].iov_base) { + if (iovec[12].iov_len == 0) + iovec[12].iov_len = strlen(iovec[12].iov_base); + } else { + iovec[12].iov_base = (void *) &sqsdn[3]; + iovec[12].iov_len = 1; + } + + /* "\n" */ + iovec[13].iov_base = (void *) &sqsdn[4]; + iovec[13].iov_len = 1; + + log_vec(r, cls, iovec, 14, + iovec[0].iov_len + iovec[1].iov_len + iovec[2].iov_len + + iovec[3].iov_len + iovec[4].iov_len + iovec[5].iov_len + + iovec[6].iov_len + iovec[7].iov_len + iovec[8].iov_len + + iovec[9].iov_len + iovec[10].iov_len + iovec[11].iov_len + + iovec[12].iov_len + iovec[13].iov_len); + + return OK; +} +#endif + static int config_log_transaction(request_rec *r, config_log_state *cls, array_header *default_format) { log_format_item *items; - char *str, *s; - const char **strs; - int *strl; request_rec *orig; - int i; - int len = 0; + int i, len; array_header *format; char *envar; + struct iovec local_iovec[20], *iovec; if (cls->fname == NULL) { return DECLINED; @@ -774,12 +966,6 @@ } } - format = cls->format ? cls->format : default_format; - - strs = ap_palloc(r->pool, sizeof(char *) * (format->nelts)); - strl = ap_palloc(r->pool, sizeof(int) * (format->nelts)); - items = (log_format_item *) format->elts; - orig = r; while (orig->prev) { orig = orig->prev; @@ -788,43 +974,30 @@ r = r->next; } - for (i = 0; i < format->nelts; ++i) { - strs[i] = process_item(r, orig, &items[i]); - } + format = cls->format ? cls->format : default_format; - for (i = 0; i < format->nelts; ++i) { - len += strl[i] = ap_strlen(strs[i]); - } +#ifdef USE_QUICK_LOG + if (format == QUICK_CLF_MARKER || format == QUICK_QLF_MARKER) + return quick_log(r, orig, cls, format); +#endif -#ifdef BUFFERED_LOGS - if (len + cls->outcnt > LOG_BUFSIZE) { - flush_log(cls); - } - if (len >= LOG_BUFSIZE) { - str = ap_palloc(r->pool, len + 1); - for (i = 0, s = str; i < format->nelts; ++i) { - memcpy(s, strs[i], strl[i]); - s += strl[i]; - } - write(cls->log_fd, str, len); - } - else { - for (i = 0, s = &cls->outbuf[cls->outcnt]; i < format->nelts; ++i) { - memcpy(s, strs[i], strl[i]); - s += strl[i]; - } - cls->outcnt += len; - } -#else - str = ap_palloc(r->pool, len + 1); + len = 0; + if (format->nelts <= sizeof local_iovec / sizeof local_iovec[0]) + iovec = local_iovec; + else + iovec = ap_palloc(r->pool, sizeof *iovec * format->nelts); + items = (log_format_item *) format->elts; - for (i = 0, s = str; i < format->nelts; ++i) { - memcpy(s, strs[i], strl[i]); - s += strl[i]; + for (i = 0; i < format->nelts; ++i) { + iovec[i].iov_len = 0; + iovec[i].iov_base = (void *) process_item(r, orig, &items[i], + &iovec[i].iov_len); + if (iovec[i].iov_len == 0) + iovec[i].iov_len = strlen(iovec[i].iov_base); + len += iovec[i].iov_len; } - write(cls->log_fd, str, len); -#endif + log_vec(r, cls, iovec, format->nelts, len); return OK; } @@ -875,7 +1048,7 @@ mls->default_format = NULL; mls->server_config_logs = NULL; mls->formats = ap_make_table(p, 4); - ap_table_setn(mls->formats, "CLF", DEFAULT_LOG_FORMAT); + ap_table_setn(mls->formats, "CLF", common_log_format); return mls; } @@ -1043,7 +1216,7 @@ } if (!mls->default_format) { - mls->default_format = parse_log_string(p, DEFAULT_LOG_FORMAT, &dummy); + mls->default_format = parse_log_string(p, common_log_format, &dummy); } if (mls->config_logs->nelts) {