mirror of
https://git.FreeBSD.org/ports.git
synced 2024-12-18 03:46:03 +00:00
2b17f205b0
<http://www.squid-cache.org/Versions/v2/2.5/bugs/> to fix an "assertion failed: HttpReply.c:105: rep" error (squid bug #1606). - Update the customlog patchset accordingly. - Bump PORTREVISION. PR: ports/97066 Submitted by: maintainer
1598 lines
40 KiB
Diff
1598 lines
40 KiB
Diff
! This patch is sourced from http://devel.squid-cache.org/customlog/
|
|
! Modified diff paths to apply cleanly
|
|
|
|
Index: src/access_log.c
|
|
diff -u src/access_log.c:1.15.6.8 src/access_log.c:1.15.6.3.2.15
|
|
--- src/access_log.c:1.15.6.8 Tue Mar 29 18:17:46 2005
|
|
+++ src/access_log.c Mon May 15 03:58:22 2006
|
|
@@ -36,9 +36,6 @@
|
|
|
|
#include "squid.h"
|
|
|
|
-static void accessLogSquid(AccessLogEntry * al);
|
|
-static void accessLogCommon(AccessLogEntry * al);
|
|
-static Logfile *logfile = NULL;
|
|
#if HEADERS_LOG
|
|
static Logfile *headerslog = NULL;
|
|
#endif
|
|
@@ -234,8 +231,768 @@
|
|
return username_quote(name);
|
|
}
|
|
|
|
+static char *
|
|
+log_quoted_string(const char *str)
|
|
+{
|
|
+ char *out = xmalloc(strlen(str) * 2 + 1);
|
|
+ char *p = out;
|
|
+ while (*str) {
|
|
+ int l = strcspn(str, "\"\\\r\n\t");
|
|
+ memcpy(p, str, l);
|
|
+ str += l;
|
|
+ p += l;
|
|
+ switch (*str) {
|
|
+ case '\0':
|
|
+ break;
|
|
+ case '\r':
|
|
+ *p++ = '\\';
|
|
+ *p++ = 'r';
|
|
+ str++;
|
|
+ break;
|
|
+ case '\n':
|
|
+ *p++ = '\\';
|
|
+ *p++ = 'n';
|
|
+ str++;
|
|
+ break;
|
|
+ case '\t':
|
|
+ *p++ = '\\';
|
|
+ *p++ = 't';
|
|
+ str++;
|
|
+ break;
|
|
+ default:
|
|
+ *p++ = '\\';
|
|
+ *p++ = *str;
|
|
+ str++;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ *p++ = '\0';
|
|
+ return out;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * Bytecodes for the configureable logformat stuff
|
|
+ */
|
|
+typedef enum {
|
|
+ LFT_NONE, /* dummy */
|
|
+ LFT_STRING,
|
|
+
|
|
+ LFT_CLIENT_IP_ADDRESS,
|
|
+ LFT_CLIENT_FQDN,
|
|
+/*LFT_CLIENT_PORT, */
|
|
+
|
|
+/*LFT_SERVER_IP_ADDRESS, */
|
|
+ LFT_SERVER_IP_OR_PEER_NAME,
|
|
+/*LFT_SERVER_PORT, */
|
|
+
|
|
+ LFT_LOCAL_IP,
|
|
+ LFT_LOCAL_PORT,
|
|
+/*LFT_LOCAL_NAME, */
|
|
+
|
|
+ LFT_TIME_SECONDS_SINCE_EPOCH,
|
|
+ LFT_TIME_SUBSECOND,
|
|
+ LFT_TIME_LOCALTIME,
|
|
+ LFT_TIME_GMT,
|
|
+ LFT_TIME_TO_HANDLE_REQUEST,
|
|
+
|
|
+ LFT_REQUEST_HEADER,
|
|
+ LFT_REQUEST_HEADER_ELEM,
|
|
+ LFT_REQUEST_ALL_HEADERS,
|
|
+
|
|
+ LFT_REPLY_HEADER,
|
|
+ LFT_REPLY_HEADER_ELEM,
|
|
+ LFT_REPLY_ALL_HEADERS,
|
|
+
|
|
+ LFT_USER_NAME,
|
|
+ LFT_USER_LOGIN,
|
|
+ LFT_USER_IDENT,
|
|
+/*LFT_USER_REALM, */
|
|
+/*LFT_USER_SCHEME, */
|
|
+
|
|
+ LFT_HTTP_CODE,
|
|
+/*LFT_HTTP_STATUS, */
|
|
+
|
|
+ LFT_SQUID_STATUS,
|
|
+/*LFT_SQUID_ERROR, */
|
|
+ LFT_SQUID_HIERARCHY,
|
|
+
|
|
+ LFT_MIME_TYPE,
|
|
+
|
|
+ LFT_REQUEST_METHOD,
|
|
+ LFT_REQUEST_URI,
|
|
+/*LFT_REQUEST_QUERY, * // * this is not needed. see strip_query_terms */
|
|
+ LFT_REQUEST_VERSION,
|
|
+
|
|
+/*LFT_REQUEST_SIZE_TOTAL, */
|
|
+/*LFT_REQUEST_SIZE_LINE, */
|
|
+/*LFT_REQUEST_SIZE_HEADERS, */
|
|
+/*LFT_REQUEST_SIZE_BODY, */
|
|
+/*LFT_REQUEST_SIZE_BODY_NO_TE, */
|
|
+
|
|
+ LFT_REPLY_SIZE_TOTAL,
|
|
+/*LFT_REPLY_SIZE_LINE, */
|
|
+/*LFT_REPLY_SIZE_HEADERS, */
|
|
+/*LFT_REPLY_SIZE_BODY, */
|
|
+/*LFT_REPLY_SIZE_BODY_NO_TE, */
|
|
+
|
|
+#ifdef HAVE_EXTACL_LOG
|
|
+ LFT_EXT_LOG,
|
|
+#endif
|
|
+
|
|
+ LFT_PERCENT /* special string cases for escaped chars */
|
|
+} logformat_bcode_t;
|
|
+
|
|
+enum log_quote {
|
|
+ LOG_QUOTE_NONE = 0,
|
|
+ LOG_QUOTE_QUOTES,
|
|
+ LOG_QUOTE_BRAKETS,
|
|
+ LOG_QUOTE_URL,
|
|
+ LOG_QUOTE_RAW
|
|
+};
|
|
+struct _logformat_token {
|
|
+ logformat_bcode_t type;
|
|
+ union {
|
|
+ char *string;
|
|
+ struct {
|
|
+ char *header;
|
|
+ char *element;
|
|
+ char separator;
|
|
+ } header;
|
|
+ char *timespec;
|
|
+ } data;
|
|
+ unsigned char width;
|
|
+ unsigned char precision;
|
|
+ enum log_quote quote:3;
|
|
+ unsigned int left:1;
|
|
+ unsigned int space:1;
|
|
+ unsigned int zero:1;
|
|
+ int divisor;
|
|
+ logformat_token *next; /* todo: move from linked list to array */
|
|
+};
|
|
+
|
|
+struct logformat_token_table_entry {
|
|
+ const char *config;
|
|
+ logformat_bcode_t token_type;
|
|
+ int options;
|
|
+};
|
|
+
|
|
+struct logformat_token_table_entry logformat_token_table[] =
|
|
+{
|
|
+
|
|
+ {">a", LFT_CLIENT_IP_ADDRESS},
|
|
+/*{ ">p", LFT_CLIENT_PORT}, */
|
|
+ {">A", LFT_CLIENT_FQDN},
|
|
+
|
|
+/*{ "<a", LFT_SERVER_IP_ADDRESS }, */
|
|
+/*{ "<p", LFT_SERVER_PORT }, */
|
|
+ {"<A", LFT_SERVER_IP_OR_PEER_NAME},
|
|
+
|
|
+ {"la", LFT_LOCAL_IP},
|
|
+ {"lp", LFT_LOCAL_PORT},
|
|
+/*{ "lA", LFT_LOCAL_NAME }, */
|
|
+
|
|
+ {"ts", LFT_TIME_SECONDS_SINCE_EPOCH},
|
|
+ {"tu", LFT_TIME_SUBSECOND},
|
|
+ {"tl", LFT_TIME_LOCALTIME},
|
|
+ {"tg", LFT_TIME_GMT},
|
|
+ {"tr", LFT_TIME_TO_HANDLE_REQUEST},
|
|
+
|
|
+ {">h", LFT_REQUEST_HEADER},
|
|
+ {"<h", LFT_REPLY_HEADER},
|
|
+
|
|
+ {"un", LFT_USER_NAME},
|
|
+ {"ul", LFT_USER_LOGIN},
|
|
+/*{ "ur", LFT_USER_REALM }, */
|
|
+/*{ "us", LFT_USER_SCHEME }, */
|
|
+ {"ui", LFT_USER_IDENT},
|
|
+
|
|
+ {"Hs", LFT_HTTP_CODE},
|
|
+/*{ "Ht", LFT_HTTP_STATUS }, */
|
|
+
|
|
+ {"Ss", LFT_SQUID_STATUS},
|
|
+/*{ "Se", LFT_SQUID_ERROR }, */
|
|
+ {"Sh", LFT_SQUID_HIERARCHY},
|
|
+
|
|
+ {"mt", LFT_MIME_TYPE},
|
|
+
|
|
+ {"rm", LFT_REQUEST_METHOD},
|
|
+ {"ru", LFT_REQUEST_URI}, /* doesn't include the query-string */
|
|
+/* { "rq", LFT_REQUEST_QUERY }, * / / * the query-string, INCLUDING the leading ? */
|
|
+ {">v", LFT_REQUEST_VERSION},
|
|
+ {"rv", LFT_REQUEST_VERSION},
|
|
+
|
|
+/*{ ">st", LFT_REQUEST_SIZE_TOTAL }, */
|
|
+/*{ ">sl", LFT_REQUEST_SIZE_LINE }, * / / * the request line "GET ... " */
|
|
+/*{ ">sh", LFT_REQUEST_SIZE_HEADERS }, */
|
|
+/*{ ">sb", LFT_REQUEST_SIZE_BODY }, */
|
|
+/*{ ">sB", LFT_REQUEST_SIZE_BODY_NO_TE }, */
|
|
+
|
|
+ {"<st", LFT_REPLY_SIZE_TOTAL},
|
|
+/*{ "<sl", LFT_REPLY_SIZE_LINE }, * / / * the reply line (protocol, code, text) */
|
|
+/*{ "<sh", LFT_REPLY_SIZE_HEADERS }, */
|
|
+/*{ "<sb", LFT_REPLY_SIZE_BODY }, */
|
|
+/*{ "<sB", LFT_REPLY_SIZE_BODY_NO_TE }, */
|
|
+
|
|
+#ifdef HAVE_EXTACL_LOG
|
|
+ {"ea", LFT_EXT_LOG},
|
|
+#endif
|
|
+
|
|
+ {"%", LFT_PERCENT},
|
|
+
|
|
+ {NULL, LFT_NONE} /* this must be last */
|
|
+};
|
|
+
|
|
+static void
|
|
+accessLogCustom(AccessLogEntry * al, customlog * log)
|
|
+{
|
|
+ logformat *lf;
|
|
+ Logfile *logfile;
|
|
+ logformat_token *fmt;
|
|
+ static MemBuf mb = MemBufNULL;
|
|
+ char tmp[1024];
|
|
+ String sb = StringNull;
|
|
+
|
|
+ memBufReset(&mb);
|
|
+
|
|
+ lf = log->logFormat;
|
|
+ logfile = log->logfile;
|
|
+ for (fmt = lf->format; fmt != NULL; fmt = fmt->next) { /* for each token */
|
|
+ const char *out = NULL;
|
|
+ int quote = 0;
|
|
+ long int outint = 0;
|
|
+ int doint = 0;
|
|
+ int dofree = 0;
|
|
+ switch (fmt->type) {
|
|
+ case LFT_NONE:
|
|
+ out = "";
|
|
+ break;
|
|
+ case LFT_STRING:
|
|
+ out = fmt->data.string;
|
|
+ break;
|
|
+ case LFT_CLIENT_IP_ADDRESS:
|
|
+ out = inet_ntoa(al->cache.caddr);
|
|
+ break;
|
|
+
|
|
+ case LFT_CLIENT_FQDN:
|
|
+ out = fqdncache_gethostbyaddr(al->cache.caddr, FQDN_LOOKUP_IF_MISS);
|
|
+ if (!out)
|
|
+ out = inet_ntoa(al->cache.caddr);
|
|
+ break;
|
|
+
|
|
+ /* case LFT_CLIENT_PORT: */
|
|
+
|
|
+ /* case LFT_SERVER_IP_ADDRESS: */
|
|
+
|
|
+ case LFT_SERVER_IP_OR_PEER_NAME:
|
|
+ out = al->hier.host;
|
|
+ break;
|
|
+
|
|
+ /* case LFT_SERVER_PORT: */
|
|
+
|
|
+ case LFT_LOCAL_IP:
|
|
+ if (al->request)
|
|
+ out = inet_ntoa(al->request->my_addr);
|
|
+ break;
|
|
+
|
|
+ case LFT_LOCAL_PORT:
|
|
+ if (al->request) {
|
|
+ outint = al->request->my_port;
|
|
+ doint = 1;
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ case LFT_TIME_SECONDS_SINCE_EPOCH:
|
|
+ outint = current_time.tv_sec;
|
|
+ doint = 1;
|
|
+ break;
|
|
+
|
|
+ case LFT_TIME_SUBSECOND:
|
|
+ outint = current_time.tv_usec / fmt->divisor;
|
|
+ doint = 1;
|
|
+ break;
|
|
+
|
|
+
|
|
+ case LFT_TIME_LOCALTIME:
|
|
+ case LFT_TIME_GMT:
|
|
+ {
|
|
+ const char *spec;
|
|
+ struct tm *t;
|
|
+ spec = fmt->data.timespec;
|
|
+ if (!spec)
|
|
+ spec = "%d/%b/%Y:%H:%M:%S %z";
|
|
+ if (fmt->type == LFT_TIME_LOCALTIME)
|
|
+ t = localtime(&squid_curtime);
|
|
+ else
|
|
+ t = gmtime(&squid_curtime);
|
|
+ strftime(tmp, sizeof(tmp), spec, t);
|
|
+ out = tmp;
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ case LFT_TIME_TO_HANDLE_REQUEST:
|
|
+ outint = al->cache.msec;
|
|
+ doint = 1;
|
|
+ break;
|
|
+
|
|
+ case LFT_REQUEST_HEADER:
|
|
+ if (al->request)
|
|
+ sb = httpHeaderGetByName(&al->request->header, fmt->data.header.header);
|
|
+ out = strBuf(sb);
|
|
+ quote = 1;
|
|
+ break;
|
|
+
|
|
+ case LFT_REPLY_HEADER:
|
|
+ if (al->reply)
|
|
+ sb = httpHeaderGetByName(&al->reply->header, fmt->data.header.header);
|
|
+ out = strBuf(sb);
|
|
+ quote = 1;
|
|
+ break;
|
|
+
|
|
+ case LFT_REQUEST_HEADER_ELEM:
|
|
+ if (al->request)
|
|
+ sb = httpHeaderGetByNameListMember(&al->request->header, fmt->data.header.header, fmt->data.header.element, fmt->data.header.separator);
|
|
+ out = strBuf(sb);
|
|
+ quote = 1;
|
|
+ break;
|
|
+
|
|
+ case LFT_REPLY_HEADER_ELEM:
|
|
+ if (al->reply)
|
|
+ sb = httpHeaderGetByNameListMember(&al->reply->header, fmt->data.header.header, fmt->data.header.element, fmt->data.header.separator);
|
|
+ out = strBuf(sb);
|
|
+ quote = 1;
|
|
+ break;
|
|
+
|
|
+ case LFT_REQUEST_ALL_HEADERS:
|
|
+ out = al->headers.request;
|
|
+ quote = 1;
|
|
+ break;
|
|
+
|
|
+ case LFT_REPLY_ALL_HEADERS:
|
|
+ out = al->headers.reply;
|
|
+ quote = 1;
|
|
+ break;
|
|
+
|
|
+ case LFT_USER_NAME:
|
|
+ out = accessLogFormatName(al->cache.authuser ?
|
|
+ al->cache.authuser : al->cache.rfc931);
|
|
+ dofree = 1;
|
|
+ break;
|
|
+
|
|
+ case LFT_USER_LOGIN:
|
|
+ out = accessLogFormatName(al->cache.authuser);
|
|
+ dofree = 1;
|
|
+ break;
|
|
+
|
|
+ case LFT_USER_IDENT:
|
|
+ out = accessLogFormatName(al->cache.rfc931);
|
|
+ dofree = 1;
|
|
+ break;
|
|
+
|
|
+ /* case LFT_USER_REALM: */
|
|
+ /* case LFT_USER_SCHEME: */
|
|
+
|
|
+ case LFT_HTTP_CODE:
|
|
+ outint = al->http.code;
|
|
+ doint = 1;
|
|
+ break;
|
|
+
|
|
+ /* case LFT_HTTP_STATUS:
|
|
+ * out = statusline->text;
|
|
+ * quote = 1;
|
|
+ * break;
|
|
+ */
|
|
+
|
|
+ case LFT_SQUID_STATUS:
|
|
+ out = log_tags[al->cache.code];
|
|
+ break;
|
|
+
|
|
+ /* case LFT_SQUID_ERROR: */
|
|
+
|
|
+ case LFT_SQUID_HIERARCHY:
|
|
+ if (al->hier.ping.timedout)
|
|
+ memBufAppend(&mb, "TIMEOUT_", 8);
|
|
+ out = hier_strings[al->hier.code];
|
|
+ break;
|
|
+
|
|
+ case LFT_MIME_TYPE:
|
|
+ out = al->http.content_type;
|
|
+ break;
|
|
+
|
|
+ case LFT_REQUEST_METHOD:
|
|
+ out = al->private.method_str;
|
|
+ break;
|
|
+
|
|
+ case LFT_REQUEST_URI:
|
|
+ out = al->url;
|
|
+ break;
|
|
+
|
|
+ case LFT_REQUEST_VERSION:
|
|
+ snprintf(tmp, sizeof(tmp), "%d.%d", (int) al->http.version.major, (int) al->http.version.minor);
|
|
+ out = tmp;
|
|
+ break;
|
|
+
|
|
+ /*case LFT_REQUEST_SIZE_TOTAL: */
|
|
+ /*case LFT_REQUEST_SIZE_LINE: */
|
|
+ /*case LFT_REQUEST_SIZE_HEADERS: */
|
|
+ /*case LFT_REQUEST_SIZE_BODY: */
|
|
+ /*case LFT_REQUEST_SIZE_BODY_NO_TE: */
|
|
+
|
|
+ case LFT_REPLY_SIZE_TOTAL:
|
|
+ outint = al->cache.size;
|
|
+ doint = 1;
|
|
+ break;
|
|
+
|
|
+ /*case LFT_REPLY_SIZE_LINE: */
|
|
+ /*case LFT_REPLY_SIZE_HEADERS: */
|
|
+ /*case LFT_REPLY_SIZE_BODY: */
|
|
+ /*case LFT_REPLY_SIZE_BODY_NO_TE: */
|
|
+
|
|
+#ifdef HAVE_EXTACL_LOG
|
|
+ case LFT_EXT_LOG:
|
|
+ if (al->request)
|
|
+ out = strBuf(al->request->extacl_log);
|
|
+
|
|
+ quote = 1;
|
|
+ break;
|
|
+#endif
|
|
+
|
|
+ case LFT_PERCENT:
|
|
+ out = "%";
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ if (doint) {
|
|
+ snprintf(tmp, sizeof(tmp), "%0*ld", fmt->zero ? (int) fmt->width : 0, outint);
|
|
+ out = tmp;
|
|
+ }
|
|
+ if (out && *out) {
|
|
+ if (quote || fmt->quote != LOG_QUOTE_NONE) {
|
|
+ char *newout = NULL;
|
|
+ int newfree = 0;
|
|
+ switch (fmt->quote) {
|
|
+ case LOG_QUOTE_NONE:
|
|
+ newout = rfc1738_escape_unescaped(out);
|
|
+ break;
|
|
+ case LOG_QUOTE_QUOTES:
|
|
+ newout = log_quoted_string(out);
|
|
+ newfree = 1;
|
|
+ break;
|
|
+ case LOG_QUOTE_BRAKETS:
|
|
+ newout = log_quote(out);
|
|
+ newfree = 1;
|
|
+ break;
|
|
+ case LOG_QUOTE_URL:
|
|
+ newout = rfc1738_escape(out);
|
|
+ break;
|
|
+ case LOG_QUOTE_RAW:
|
|
+ break;
|
|
+ }
|
|
+ if (newout) {
|
|
+ if (dofree)
|
|
+ safe_free(out);
|
|
+ out = newout;
|
|
+ dofree = newfree;
|
|
+ }
|
|
+ }
|
|
+ if (fmt->width) {
|
|
+ if (fmt->left)
|
|
+ memBufPrintf(&mb, "%-*s", (int) fmt->width, out);
|
|
+ else
|
|
+ memBufPrintf(&mb, "%*s", (int) fmt->width, out);
|
|
+ } else
|
|
+ memBufAppend(&mb, out, strlen(out));
|
|
+ } else {
|
|
+ memBufAppend(&mb, "-", 1);
|
|
+ }
|
|
+ if (fmt->space)
|
|
+ memBufAppend(&mb, " ", 1);
|
|
+ stringClean(&sb);
|
|
+ if (dofree)
|
|
+ safe_free(out);
|
|
+ }
|
|
+ logfilePrintf(logfile, "%s\n", mb.buf);
|
|
+}
|
|
+
|
|
+/* parses a single token. Returns the token length in characters,
|
|
+ * and fills in the lt item with the token information.
|
|
+ * def is for sure null-terminated
|
|
+ */
|
|
+static int
|
|
+accessLogGetNewLogFormatToken(logformat_token * lt, char *def, enum log_quote *quote)
|
|
+{
|
|
+ char *cur = def;
|
|
+ struct logformat_token_table_entry *lte;
|
|
+ int l;
|
|
+
|
|
+ memset(lt, 0, sizeof(*lt));
|
|
+ l = strcspn(cur, "%");
|
|
+ if (l > 0) {
|
|
+ char *cp;
|
|
+ /* it's a string for sure, until \0 or the next % */
|
|
+ cp = xmalloc(l + 1);
|
|
+ xstrncpy(cp, cur, l + 1);
|
|
+ lt->type = LFT_STRING;
|
|
+ lt->data.string = cp;
|
|
+ while (l > 0) {
|
|
+ switch (*cur) {
|
|
+ case '"':
|
|
+ if (*quote == LOG_QUOTE_NONE)
|
|
+ *quote = LOG_QUOTE_QUOTES;
|
|
+ else if (*quote == LOG_QUOTE_QUOTES)
|
|
+ *quote = LOG_QUOTE_NONE;
|
|
+ break;
|
|
+ case '[':
|
|
+ if (*quote == LOG_QUOTE_NONE)
|
|
+ *quote = LOG_QUOTE_BRAKETS;
|
|
+ break;
|
|
+ case ']':
|
|
+ if (*quote == LOG_QUOTE_BRAKETS)
|
|
+ *quote = LOG_QUOTE_NONE;
|
|
+ break;
|
|
+ }
|
|
+ cur++;
|
|
+ l--;
|
|
+ }
|
|
+ goto done;
|
|
+ }
|
|
+ if (!*cur)
|
|
+ goto done;
|
|
+ cur++;
|
|
+ switch (*cur) {
|
|
+ case '"':
|
|
+ lt->quote = LOG_QUOTE_QUOTES;
|
|
+ cur++;
|
|
+ break;
|
|
+ case '\'':
|
|
+ lt->quote = LOG_QUOTE_RAW;
|
|
+ cur++;
|
|
+ break;
|
|
+ case '[':
|
|
+ lt->quote = LOG_QUOTE_BRAKETS;
|
|
+ cur++;
|
|
+ break;
|
|
+ case '#':
|
|
+ lt->quote = LOG_QUOTE_URL;
|
|
+ cur++;
|
|
+ break;
|
|
+ default:
|
|
+ lt->quote = *quote;
|
|
+ break;
|
|
+ }
|
|
+ if (*cur == '-') {
|
|
+ lt->left = 1;
|
|
+ cur++;
|
|
+ }
|
|
+ if (*cur == '0') {
|
|
+ lt->zero = 1;
|
|
+ cur++;
|
|
+ }
|
|
+ if (isdigit(*cur))
|
|
+ lt->width = strtol(cur, &cur, 10);
|
|
+ if (*cur == '.')
|
|
+ lt->precision = strtol(cur + 1, &cur, 10);
|
|
+ if (*cur == '{') {
|
|
+ char *cp;
|
|
+ cur++;
|
|
+ l = strcspn(cur, "}");
|
|
+ cp = xmalloc(l + 1);
|
|
+ xstrncpy(cp, cur, l + 1);
|
|
+ lt->data.string = cp;
|
|
+ cur += l;
|
|
+ if (*cur == '}')
|
|
+ cur++;
|
|
+ }
|
|
+ lt->type = LFT_NONE;
|
|
+ for (lte = logformat_token_table; lte->config != NULL; lte++) {
|
|
+ if (strncmp(lte->config, cur, strlen(lte->config)) == 0) {
|
|
+ lt->type = lte->token_type;
|
|
+ cur += strlen(lte->config);
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ if (lt->type == LFT_NONE) {
|
|
+ fatalf("Can't parse configuration token: '%s'\n",
|
|
+ def);
|
|
+ }
|
|
+ if (*cur == ' ') {
|
|
+ lt->space = 1;
|
|
+ cur++;
|
|
+ }
|
|
+ done:
|
|
+ switch (lt->type) {
|
|
+ case LFT_REQUEST_HEADER:
|
|
+ case LFT_REPLY_HEADER:
|
|
+ if (lt->data.string) {
|
|
+ char *header = lt->data.string;
|
|
+ char *cp = strchr(header, ':');
|
|
+ if (cp) {
|
|
+ *cp++ = '\0';
|
|
+ if (*cp == ',' || *cp == ';' || *cp == ':')
|
|
+ lt->data.header.separator = *cp++;
|
|
+ else
|
|
+ lt->data.header.separator = ',';
|
|
+ lt->data.header.element = cp;
|
|
+ lt->type = (lt->type == LFT_REQUEST_HEADER) ?
|
|
+ LFT_REQUEST_HEADER_ELEM :
|
|
+ LFT_REPLY_HEADER_ELEM;
|
|
+ }
|
|
+ lt->data.header.header = header;
|
|
+ } else {
|
|
+ lt->type = (lt->type == LFT_REQUEST_HEADER) ?
|
|
+ LFT_REQUEST_ALL_HEADERS :
|
|
+ LFT_REPLY_ALL_HEADERS;
|
|
+ Config.onoff.log_mime_hdrs = 1;
|
|
+ }
|
|
+ break;
|
|
+ case LFT_CLIENT_FQDN:
|
|
+ Config.onoff.log_fqdn = 1;
|
|
+ break;
|
|
+ case LFT_TIME_SUBSECOND:
|
|
+ lt->divisor = 1000;
|
|
+ if (lt->precision) {
|
|
+ int i;
|
|
+ lt->divisor = 1000000;
|
|
+ for (i = lt->precision; i > 1; i--)
|
|
+ lt->divisor /= 10;
|
|
+ if (!lt->divisor)
|
|
+ lt->divisor = 0;
|
|
+ }
|
|
+ break;
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+ return (cur - def);
|
|
+}
|
|
+
|
|
+int
|
|
+accessLogParseLogFormat(logformat_token ** fmt, char *def)
|
|
+{
|
|
+ char *cur, *eos;
|
|
+ logformat_token *new_lt, *last_lt;
|
|
+ enum log_quote quote = LOG_QUOTE_NONE;
|
|
+
|
|
+ debug(46, 1) ("accessLogParseLogFormat: got definition '%s'\n", def);
|
|
+
|
|
+ /* very inefficent parser, but who cares, this needs to be simple */
|
|
+ /* First off, let's tokenize, we'll optimize in a second pass.
|
|
+ * A token can either be a %-prefixed sequence (usually a dynamic
|
|
+ * token but it can be an escaped sequence), or a string. */
|
|
+ cur = def;
|
|
+ eos = def + strlen(def);
|
|
+ *fmt = new_lt = last_lt = xmalloc(sizeof(logformat_token));
|
|
+ cur += accessLogGetNewLogFormatToken(new_lt, cur, "e);
|
|
+ while (cur < eos) {
|
|
+ new_lt = xmalloc(sizeof(logformat_token));
|
|
+ last_lt->next = new_lt;
|
|
+ last_lt = new_lt;
|
|
+ cur += accessLogGetNewLogFormatToken(new_lt, cur, "e);
|
|
+ }
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+void
|
|
+accessLogDumpLogFormat(StoreEntry * entry, const char *name, logformat * definitions)
|
|
+{
|
|
+ logformat_token *t;
|
|
+ logformat *format;
|
|
+ struct logformat_token_table_entry *te;
|
|
+ debug(46, 0) ("accessLogDumpLogFormat called\n");
|
|
+
|
|
+ for (format = definitions; format; format = format->next) {
|
|
+ debug(46, 0) ("Dumping logformat definition for %s\n", format->name);
|
|
+ storeAppendPrintf(entry, "logformat %s ", format->name);
|
|
+ for (t = format->format; t; t = t->next) {
|
|
+ if (t->type == LFT_STRING)
|
|
+ storeAppendPrintf(entry, "%s", t->data.string);
|
|
+ else {
|
|
+ char argbuf[256];
|
|
+ char *arg = NULL;
|
|
+ logformat_bcode_t type = t->type;
|
|
+
|
|
+ switch (type) {
|
|
+ /* special cases */
|
|
+ case LFT_STRING:
|
|
+ break;
|
|
+ case LFT_REQUEST_HEADER_ELEM:
|
|
+ case LFT_REPLY_HEADER_ELEM:
|
|
+ if (t->data.header.separator != ',')
|
|
+ snprintf(argbuf, sizeof(argbuf), "%s:%c%s", t->data.header.header, t->data.header.separator, t->data.header.element);
|
|
+ else
|
|
+ snprintf(argbuf, sizeof(argbuf), "%s:%s", t->data.header.header, t->data.header.element);
|
|
+
|
|
+ arg = argbuf;
|
|
+ type = (type == LFT_REQUEST_HEADER_ELEM) ?
|
|
+ LFT_REQUEST_HEADER :
|
|
+ LFT_REPLY_HEADER;
|
|
+ break;
|
|
+
|
|
+ case LFT_REQUEST_ALL_HEADERS:
|
|
+ case LFT_REPLY_ALL_HEADERS:
|
|
+ type = (type == LFT_REQUEST_ALL_HEADERS) ?
|
|
+ LFT_REQUEST_HEADER :
|
|
+ LFT_REPLY_HEADER;
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ if (t->data.string)
|
|
+ arg = t->data.string;
|
|
+ break;
|
|
+ }
|
|
+ storeAppend(entry, "%", 1);
|
|
+ switch (t->quote) {
|
|
+ case LOG_QUOTE_QUOTES:
|
|
+ storeAppend(entry, "\"", 1);
|
|
+ break;
|
|
+ case LOG_QUOTE_BRAKETS:
|
|
+ storeAppend(entry, "[", 1);
|
|
+ break;
|
|
+ case LOG_QUOTE_URL:
|
|
+ storeAppend(entry, "#", 1);
|
|
+ break;
|
|
+ case LOG_QUOTE_RAW:
|
|
+ storeAppend(entry, "'", 1);
|
|
+ break;
|
|
+ case LOG_QUOTE_NONE:
|
|
+ break;
|
|
+ }
|
|
+ if (t->left)
|
|
+ storeAppend(entry, "-", 1);
|
|
+ if (t->zero)
|
|
+ storeAppend(entry, "0", 1);
|
|
+ if (t->width)
|
|
+ storeAppendPrintf(entry, "%d", (int) t->width);
|
|
+ if (t->precision)
|
|
+ storeAppendPrintf(entry, ".%d", (int) t->precision);
|
|
+ if (arg)
|
|
+ storeAppendPrintf(entry, "{%s}", arg);
|
|
+ for (te = logformat_token_table; te->config != NULL; te++) {
|
|
+ if (te->token_type == t->type) {
|
|
+ storeAppendPrintf(entry, "%s", te->config);
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ if (t->space)
|
|
+ storeAppend(entry, " ", 1);
|
|
+ assert(te->config != NULL);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ storeAppend(entry, "\n", 1);
|
|
+}
|
|
+
|
|
+void
|
|
+accessLogFreeLogFormat(logformat_token ** tokens)
|
|
+{
|
|
+ while (*tokens) {
|
|
+ logformat_token *token = *tokens;
|
|
+ *tokens = token->next;
|
|
+ safe_free(token->data.string);
|
|
+ xfree(token);
|
|
+ }
|
|
+}
|
|
+
|
|
static void
|
|
-accessLogSquid(AccessLogEntry * al)
|
|
+accessLogSquid(AccessLogEntry * al, Logfile * logfile)
|
|
{
|
|
const char *client = NULL;
|
|
char *user = NULL;
|
|
@@ -261,10 +1018,19 @@
|
|
al->hier.host,
|
|
al->http.content_type);
|
|
safe_free(user);
|
|
+ if (Config.onoff.log_mime_hdrs) {
|
|
+ char *ereq = log_quote(al->headers.request);
|
|
+ char *erep = log_quote(al->headers.reply);
|
|
+ logfilePrintf(logfile, " [%s] [%s]\n", ereq, erep);
|
|
+ safe_free(ereq);
|
|
+ safe_free(erep);
|
|
+ } else {
|
|
+ logfilePrintf(logfile, "\n");
|
|
+ }
|
|
}
|
|
|
|
static void
|
|
-accessLogCommon(AccessLogEntry * al)
|
|
+accessLogCommon(AccessLogEntry * al, Logfile * logfile)
|
|
{
|
|
const char *client = NULL;
|
|
char *user1 = NULL, *user2 = NULL;
|
|
@@ -288,11 +1054,21 @@
|
|
hier_strings[al->hier.code]);
|
|
safe_free(user1);
|
|
safe_free(user2);
|
|
+ if (Config.onoff.log_mime_hdrs) {
|
|
+ char *ereq = log_quote(al->headers.request);
|
|
+ char *erep = log_quote(al->headers.reply);
|
|
+ logfilePrintf(logfile, " [%s] [%s]\n", ereq, erep);
|
|
+ safe_free(ereq);
|
|
+ safe_free(erep);
|
|
+ } else {
|
|
+ logfilePrintf(logfile, "\n");
|
|
+ }
|
|
}
|
|
|
|
void
|
|
-accessLogLog(AccessLogEntry * al)
|
|
+accessLogLog(AccessLogEntry * al, aclCheck_t * checklist)
|
|
{
|
|
+ customlog *log;
|
|
if (LogfileStatus != LOG_ENABLE)
|
|
return;
|
|
if (al->url == NULL)
|
|
@@ -306,20 +1082,38 @@
|
|
if (al->hier.host[0] == '\0')
|
|
xstrncpy(al->hier.host, dash_str, SQUIDHOSTNAMELEN);
|
|
|
|
- if (Config.onoff.common_log)
|
|
- accessLogCommon(al);
|
|
- else
|
|
- accessLogSquid(al);
|
|
- if (Config.onoff.log_mime_hdrs) {
|
|
- char *ereq = log_quote(al->headers.request);
|
|
- char *erep = log_quote(al->headers.reply);
|
|
- logfilePrintf(logfile, " [%s] [%s]\n", ereq, erep);
|
|
- safe_free(ereq);
|
|
- safe_free(erep);
|
|
- } else {
|
|
- logfilePrintf(logfile, "\n");
|
|
+ for (log = Config.Log.accesslogs; log; log = log->next) {
|
|
+ if (checklist && log->aclList && aclMatchAclList(log->aclList, checklist) != 1)
|
|
+ continue;
|
|
+ switch (log->type) {
|
|
+ case CLF_AUTO:
|
|
+ if (Config.onoff.common_log)
|
|
+ accessLogCommon(al, log->logfile);
|
|
+ else
|
|
+ accessLogSquid(al, log->logfile);
|
|
+ break;
|
|
+ case CLF_SQUID:
|
|
+ accessLogSquid(al, log->logfile);
|
|
+ break;
|
|
+ case CLF_COMMON:
|
|
+ accessLogCommon(al, log->logfile);
|
|
+ break;
|
|
+ case CLF_CUSTOM:
|
|
+ accessLogCustom(al, log);
|
|
+ break;
|
|
+ case CLF_NONE:
|
|
+ goto last;
|
|
+ default:
|
|
+ fatalf("Unknown log format %d\n", log->type);
|
|
+ break;
|
|
+ }
|
|
+ logfileFlush(log->logfile);
|
|
+ if (!checklist)
|
|
+ break;
|
|
}
|
|
- logfileFlush(logfile);
|
|
+ last:
|
|
+ (void) 0; /* NULL statement for label */
|
|
+
|
|
#if MULTICAST_MISS_STREAM
|
|
if (al->cache.code != LOG_TCP_MISS)
|
|
(void) 0;
|
|
@@ -346,12 +1140,15 @@
|
|
void
|
|
accessLogRotate(void)
|
|
{
|
|
+ customlog *log;
|
|
#if FORW_VIA_DB
|
|
fvdbClear();
|
|
#endif
|
|
- if (NULL == logfile)
|
|
- return;
|
|
- logfileRotate(logfile);
|
|
+ for (log = Config.Log.accesslogs; log; log = log->next) {
|
|
+ if (log->logfile) {
|
|
+ logfileRotate(log->logfile);
|
|
+ }
|
|
+ }
|
|
#if HEADERS_LOG
|
|
logfileRotate(headerslog);
|
|
#endif
|
|
@@ -360,10 +1157,13 @@
|
|
void
|
|
accessLogClose(void)
|
|
{
|
|
- if (NULL == logfile)
|
|
- return;
|
|
- logfileClose(logfile);
|
|
- logfile = NULL;
|
|
+ customlog *log;
|
|
+ for (log = Config.Log.accesslogs; log; log = log->next) {
|
|
+ if (log->logfile) {
|
|
+ logfileClose(log->logfile);
|
|
+ log->logfile = NULL;
|
|
+ }
|
|
+ }
|
|
#if HEADERS_LOG
|
|
logfileClose(headerslog);
|
|
headerslog = NULL;
|
|
@@ -383,11 +1183,14 @@
|
|
void
|
|
accessLogInit(void)
|
|
{
|
|
+ customlog *log;
|
|
assert(sizeof(log_tags) == (LOG_TYPE_MAX + 1) * sizeof(char *));
|
|
- if (strcasecmp(Config.Log.access, "none") == 0)
|
|
- return;
|
|
- logfile = logfileOpen(Config.Log.access, MAX_URL << 1, 1);
|
|
- LogfileStatus = LOG_ENABLE;
|
|
+ for (log = Config.Log.accesslogs; log; log = log->next) {
|
|
+ if (log->type == CLF_NONE)
|
|
+ continue;
|
|
+ log->logfile = logfileOpen(log->filename, MAX_URL << 1, 1);
|
|
+ LogfileStatus = LOG_ENABLE;
|
|
+ }
|
|
#if HEADERS_LOG
|
|
headerslog = logfileOpen("/usr/local/squid/logs/headers.log", MAX_URL << 1, 0);
|
|
assert(NULL != headerslog);
|
|
Index: src/cache_cf.c
|
|
diff -u src/cache_cf.c:1.38.6.29 src/cache_cf.c:1.38.6.11.4.10
|
|
--- src/cache_cf.c:1.38.6.29 Wed Oct 26 19:13:24 2005
|
|
+++ src/cache_cf.c Fri Mar 3 18:27:50 2006
|
|
@@ -60,6 +60,14 @@
|
|
static void dump_cachedir_option_readonly(StoreEntry * e, const char *option, SwapDir * sd);
|
|
static void parse_cachedir_option_maxsize(SwapDir * sd, const char *option, const char *value, int reconfiguring);
|
|
static void dump_cachedir_option_maxsize(StoreEntry * e, const char *option, SwapDir * sd);
|
|
+static void parse_logformat(logformat ** logformat_definitions);
|
|
+static void parse_access_log(customlog ** customlog_definitions);
|
|
+static void dump_logformat(StoreEntry * entry, const char *name, logformat * definitions);
|
|
+static void dump_access_log(StoreEntry * entry, const char *name, customlog * definitions);
|
|
+static void free_logformat(logformat ** definitions);
|
|
+static void free_access_log(customlog ** definitions);
|
|
+
|
|
+
|
|
static struct cache_dir_option common_cachedir_options[] =
|
|
{
|
|
{"read-only", parse_cachedir_option_readonly, dump_cachedir_option_readonly},
|
|
@@ -2625,3 +2633,144 @@
|
|
return t;
|
|
}
|
|
}
|
|
+
|
|
+static void
|
|
+parse_logformat(logformat ** logformat_definitions)
|
|
+{
|
|
+ logformat *nlf;
|
|
+ char *name, *def;
|
|
+
|
|
+ if ((name = strtok(NULL, w_space)) == NULL)
|
|
+ self_destruct();
|
|
+ if ((def = strtok(NULL, "\r\n")) == NULL)
|
|
+ self_destruct();
|
|
+
|
|
+ debug(3, 1) ("Logformat for '%s' is '%s'\n", name, def);
|
|
+
|
|
+ nlf = xcalloc(1, sizeof(logformat));
|
|
+ nlf->name = xstrdup(name);
|
|
+ if (!accessLogParseLogFormat(&nlf->format, def))
|
|
+ self_destruct();
|
|
+ nlf->next = *logformat_definitions;
|
|
+ *logformat_definitions = nlf;
|
|
+}
|
|
+
|
|
+static void
|
|
+parse_access_log(customlog ** logs)
|
|
+{
|
|
+ const char *filename, *logdef_name;
|
|
+ customlog *cl;
|
|
+ logformat *lf;
|
|
+
|
|
+ cl = xcalloc(1, sizeof(*cl));
|
|
+
|
|
+ if ((filename = strtok(NULL, w_space)) == NULL)
|
|
+ self_destruct();
|
|
+
|
|
+ if (strcmp(filename, "none") == 0) {
|
|
+ cl->type = CLF_NONE;
|
|
+ goto done;
|
|
+ }
|
|
+ if ((logdef_name = strtok(NULL, w_space)) == NULL)
|
|
+ logdef_name = "auto";
|
|
+
|
|
+ debug(3, 9) ("Log definition name '%s' file '%s'\n", logdef_name, filename);
|
|
+
|
|
+ cl->filename = xstrdup(filename);
|
|
+
|
|
+ /* look for the definition pointer corresponding to this name */
|
|
+ lf = Config.Log.logformats;
|
|
+ while (lf != NULL) {
|
|
+ debug(3, 9) ("Comparing against '%s'\n", lf->name);
|
|
+ if (strcmp(lf->name, logdef_name) == 0)
|
|
+ break;
|
|
+ lf = lf->next;
|
|
+ }
|
|
+ if (lf != NULL) {
|
|
+ cl->type = CLF_CUSTOM;
|
|
+ cl->logFormat = lf;
|
|
+ } else if (strcmp(logdef_name, "auto") == 0) {
|
|
+ cl->type = CLF_AUTO;
|
|
+ } else if (strcmp(logdef_name, "squid") == 0) {
|
|
+ cl->type = CLF_SQUID;
|
|
+ } else if (strcmp(logdef_name, "common") == 0) {
|
|
+ cl->type = CLF_COMMON;
|
|
+ } else {
|
|
+ debug(3, 0) ("Log format '%s' is not defined\n", logdef_name);
|
|
+ self_destruct();
|
|
+ }
|
|
+
|
|
+ done:
|
|
+ aclParseAclList(&cl->aclList);
|
|
+
|
|
+ while (*logs)
|
|
+ logs = &(*logs)->next;
|
|
+ *logs = cl;
|
|
+}
|
|
+
|
|
+static void
|
|
+dump_logformat(StoreEntry * entry, const char *name, logformat * definitions)
|
|
+{
|
|
+ accessLogDumpLogFormat(entry, name, definitions);
|
|
+}
|
|
+
|
|
+static void
|
|
+dump_access_log(StoreEntry * entry, const char *name, customlog * logs)
|
|
+{
|
|
+ customlog *log;
|
|
+ for (log = logs; log; log = log->next) {
|
|
+ storeAppendPrintf(entry, "%s ", name);
|
|
+ switch (log->type) {
|
|
+ case CLF_CUSTOM:
|
|
+ storeAppendPrintf(entry, "%s %s", log->filename, log->logFormat->name);
|
|
+ break;
|
|
+ case CLF_NONE:
|
|
+ storeAppendPrintf(entry, "none");
|
|
+ break;
|
|
+ case CLF_SQUID:
|
|
+ storeAppendPrintf(entry, "%s squid", log->filename);
|
|
+ break;
|
|
+ case CLF_COMMON:
|
|
+ storeAppendPrintf(entry, "%s squid", log->filename);
|
|
+ break;
|
|
+ case CLF_AUTO:
|
|
+ if (log->aclList)
|
|
+ storeAppendPrintf(entry, "%s auto", log->filename);
|
|
+ else
|
|
+ storeAppendPrintf(entry, "%s", log->filename);
|
|
+ break;
|
|
+ case CLF_UNKNOWN:
|
|
+ break;
|
|
+ }
|
|
+ if (log->aclList)
|
|
+ dump_acl_list(entry, log->aclList);
|
|
+ storeAppendPrintf(entry, "\n");
|
|
+ }
|
|
+}
|
|
+
|
|
+static void
|
|
+free_logformat(logformat ** definitions)
|
|
+{
|
|
+ while (*definitions) {
|
|
+ logformat *format = *definitions;
|
|
+ *definitions = format->next;
|
|
+ accessLogFreeLogFormat(&format->format);
|
|
+ xfree(format);
|
|
+ }
|
|
+}
|
|
+
|
|
+static void
|
|
+free_access_log(customlog ** definitions)
|
|
+{
|
|
+ while (*definitions) {
|
|
+ customlog *log = *definitions;
|
|
+ *definitions = log->next;
|
|
+
|
|
+ log->logFormat = NULL;
|
|
+ log->type = CLF_UNKNOWN;
|
|
+ if (log->aclList)
|
|
+ aclDestroyAclList(&log->aclList);
|
|
+ safe_free(log->filename);
|
|
+ xfree(log);
|
|
+ }
|
|
+}
|
|
Index: src/cf.data.pre
|
|
diff -u src/cf.data.pre:1.49.2.86 src/cf.data.pre:1.49.2.40.2.18
|
|
--- src/cf.data.pre:1.49.2.86 Sat Feb 25 19:13:57 2006
|
|
+++ src/cf.data.pre Fri Mar 3 18:27:50 2006
|
|
@@ -834,16 +834,97 @@
|
|
(hard coded at 1 MB).
|
|
DOC_END
|
|
|
|
-
|
|
-NAME: cache_access_log
|
|
-TYPE: string
|
|
-DEFAULT: @DEFAULT_ACCESS_LOG@
|
|
-LOC: Config.Log.access
|
|
+NAME: logformat
|
|
+TYPE: logformat
|
|
+LOC: Config.Log.logformats
|
|
+DEFAULT: none
|
|
DOC_START
|
|
- Logs the client request activity. Contains an entry for
|
|
- every HTTP and ICP queries received. To disable, enter "none".
|
|
-DOC_END
|
|
+ Usage:
|
|
+
|
|
+ logformat <name> <format specification>
|
|
+
|
|
+ Defines an access log format.
|
|
+
|
|
+ The <format specification> is a string with embedded % format codes
|
|
+
|
|
+ % format codes all follow the same basic structure where all but
|
|
+ the formatcode is optional. Output strings are automatically escaped
|
|
+ as required according to their context and the output format
|
|
+ modifiers are usually not needed, but can be specified if an explicit
|
|
+ output format is desired.
|
|
+
|
|
+ % ["|[|'|#] [-] [[0]width] [{argument}] formatcode
|
|
+
|
|
+ " output in quoted string format
|
|
+ [ output in squid text log format as used by log_mime_hdrs
|
|
+ # output in URL quoted format
|
|
+ ' output as-is
|
|
+
|
|
+ - left aligned
|
|
+ width field width. If starting with 0 then the
|
|
+ output is zero padded
|
|
+ {arg} argument such as header name etc
|
|
+
|
|
+ Format codes:
|
|
+
|
|
+ >a Client source IP address
|
|
+ >A Client FQDN
|
|
+ <A Server IP address or peer name
|
|
+ la Local IP address (http_port)
|
|
+ lp Local port number (http_port)
|
|
+ ts Seconds since epoch
|
|
+ tu subsecond time (milliseconds)
|
|
+ tl Local time. Optional strftime format argument
|
|
+ default %d/%b/%Y:%H:%M:%S %z
|
|
+ tg GMT time. Optional strftime format argument
|
|
+ default %d/%b/%Y:%H:%M:%S %z
|
|
+ tr Response time (milliseconds)
|
|
+ >h Request header. Optional header name argument
|
|
+ on the format header[:[separator]element]
|
|
+ <h Reply header. Optional header name argument
|
|
+ as for >h
|
|
+ un User name
|
|
+ ul User login
|
|
+ ui User ident
|
|
+ Hs HTTP status code
|
|
+ Ss Squid request status (TCP_MISS etc)
|
|
+ Sh Squid hierarchy status (DEFAULT_PARENT etc)
|
|
+ mt MIME content type
|
|
+ rm Request method (GET/POST etc)
|
|
+ ru Request URL
|
|
+ rv Request protocol version
|
|
+ ea Log string returned by external acl
|
|
+ <st Reply size including HTTP headers
|
|
+ % a literal % character
|
|
+
|
|
+logformat squid %ts.%03tu %6tr %>a %Ss/%03Hs %<st %rm %ru %un %Sh/%<A %mt
|
|
+logformat squidmime %ts.%03tu %6tr %>a %Ss/%03Hs %<st %rm %ru %un %Sh/%<A %mt [%>h] [%<h]
|
|
+logformat common %>a %ui %un [%tl] "%rm %ru HTTP/%rv" %Hs %<st %Ss:%Sh
|
|
+logformat combined %>a %ui %un [%tl] "%rm %ru HTTP/%rv" %Hs %<st "%{Referer}>h" "%{User-Agent}>h" %Ss:%Sh
|
|
+DOC_END
|
|
+
|
|
+NAME: access_log cache_access_log
|
|
+TYPE: access_log
|
|
+LOC: Config.Log.accesslogs
|
|
+DEFAULT: none
|
|
+DOC_START
|
|
+ These files log client request activities. Has a line every HTTP or
|
|
+ ICP request. The format is:
|
|
+ access_log <filepath> [<logformat name> [acl acl ...]]
|
|
+
|
|
+ Will log to the specified file using the specified format (which
|
|
+ must be defined in a logformat directive) those entries which match
|
|
+ ALL the acl's specified (which must be defined in acl clauses).
|
|
+ If no acl is specified, all requests will be logged to this file.
|
|
+
|
|
+ To disable logging of a request use the filepath "none", in which case
|
|
+ a logformat name should not be specified.
|
|
|
|
+ To log the request via syslog specify a filepath of "syslog"
|
|
+NOCOMMENT_START
|
|
+access_log @DEFAULT_ACCESS_LOG@ squid
|
|
+NOCOMMENT_END
|
|
+DOC_END
|
|
|
|
NAME: cache_log
|
|
TYPE: string
|
|
@@ -2440,6 +2521,17 @@
|
|
no limit imposed.
|
|
DOC_END
|
|
|
|
+NAME: log_access
|
|
+TYPE: acl_access
|
|
+LOC: Config.accessList.log
|
|
+DEFAULT: none
|
|
+COMMENT: allow|deny acl acl...
|
|
+DOC_START
|
|
+ This options allows you to control which requests gets logged
|
|
+ to access.log (see cache_access_log directive). Requests denied
|
|
+ for logging will also not be accounted for in performance counters.
|
|
+DOC_END
|
|
+
|
|
COMMENT_START
|
|
ADMINISTRATIVE PARAMETERS
|
|
-----------------------------------------------------------------------------
|
|
Index: src/client_side.c
|
|
diff -u src/client_side.c:1.47.2.76 src/client_side.c:1.47.2.31.2.15
|
|
--- src/client_side.c:1.47.2.76 Fri Mar 10 19:16:31 2006
|
|
+++ src/client_side.c Mon Apr 24 08:22:33 2006
|
|
@@ -871,14 +871,18 @@
|
|
http->al.cache.code = http->log_type;
|
|
http->al.cache.msec = tvSubMsec(http->start, current_time);
|
|
if (request) {
|
|
- Packer p;
|
|
- MemBuf mb;
|
|
- memBufDefInit(&mb);
|
|
- packerToMemInit(&p, &mb);
|
|
- httpHeaderPackInto(&request->header, &p);
|
|
+ if (Config.onoff.log_mime_hdrs) {
|
|
+ Packer p;
|
|
+ MemBuf mb;
|
|
+ memBufDefInit(&mb);
|
|
+ packerToMemInit(&p, &mb);
|
|
+ httpHeaderPackInto(&request->header, &p);
|
|
+ http->al.headers.request = xstrdup(mb.buf);
|
|
+ packerClean(&p);
|
|
+ memBufClean(&mb);
|
|
+ }
|
|
http->al.http.method = request->method;
|
|
http->al.http.version = request->http_ver;
|
|
- http->al.headers.request = xstrdup(mb.buf);
|
|
http->al.hier = request->hier;
|
|
if (request->auth_user_request) {
|
|
if (authenticateUserRequestUsername(request->auth_user_request))
|
|
@@ -888,12 +892,17 @@
|
|
}
|
|
if (conn->rfc931[0])
|
|
http->al.cache.rfc931 = conn->rfc931;
|
|
- packerClean(&p);
|
|
- memBufClean(&mb);
|
|
}
|
|
- accessLogLog(&http->al);
|
|
- clientUpdateCounters(http);
|
|
- clientdbUpdate(conn->peer.sin_addr, http->log_type, PROTO_HTTP, http->out.size);
|
|
+ http->al.request = request;
|
|
+ if (!http->acl_checklist)
|
|
+ http->acl_checklist = clientAclChecklistCreate(Config.accessList.http, http);
|
|
+ http->acl_checklist->reply = http->reply;
|
|
+ if (!Config.accessList.log || aclCheckFast(Config.accessList.log, http->acl_checklist)) {
|
|
+ http->al.reply = http->reply;
|
|
+ accessLogLog(&http->al, http->acl_checklist);
|
|
+ clientUpdateCounters(http);
|
|
+ clientdbUpdate(conn->peer.sin_addr, http->log_type, PROTO_HTTP, http->out.size);
|
|
+ }
|
|
}
|
|
if (http->acl_checklist)
|
|
aclChecklistFree(http->acl_checklist);
|
|
@@ -904,6 +913,7 @@
|
|
safe_free(http->al.headers.request);
|
|
safe_free(http->al.headers.reply);
|
|
safe_free(http->al.cache.authuser);
|
|
+ http->al.request = NULL;
|
|
safe_free(http->redirect.location);
|
|
stringClean(&http->range_iter.boundary);
|
|
if ((e = http->entry)) {
|
|
Index: src/icp_v2.c
|
|
diff -u src/icp_v2.c:1.5 src/icp_v2.c:1.5.60.1
|
|
--- src/icp_v2.c:1.5 Fri May 4 06:39:12 2001
|
|
+++ src/icp_v2.c Sat Jun 21 05:45:26 2003
|
|
@@ -63,7 +63,7 @@
|
|
al.cache.size = len;
|
|
al.cache.code = logcode;
|
|
al.cache.msec = delay;
|
|
- accessLogLog(&al);
|
|
+ accessLogLog(&al, NULL);
|
|
}
|
|
|
|
void
|
|
Index: src/logfile.c
|
|
diff -u src/logfile.c:1.5.38.3 src/logfile.c:1.5.38.3.4.4
|
|
--- src/logfile.c:1.5.38.3 Mon Jan 20 19:15:11 2003
|
|
+++ src/logfile.c Sun May 21 16:56:52 2006
|
|
@@ -36,36 +36,127 @@
|
|
|
|
static void logfileWriteWrapper(Logfile * lf, const void *buf, size_t len);
|
|
|
|
+#if HAVE_SYSLOG
|
|
+typedef struct {
|
|
+ const char *name;
|
|
+ int value;
|
|
+}syslog_symbol_t;
|
|
+
|
|
+static int
|
|
+syslog_ntoa(const char *s)
|
|
+{
|
|
+#define syslog_symbol(a) #a, a
|
|
+ static syslog_symbol_t symbols[] =
|
|
+ {
|
|
+#ifdef LOG_AUTHPRIV
|
|
+ {syslog_symbol(LOG_AUTHPRIV)},
|
|
+#endif
|
|
+#ifdef LOG_DAEMON
|
|
+ {syslog_symbol(LOG_DAEMON)},
|
|
+#endif
|
|
+#ifdef LOG_LOCAL0
|
|
+ {syslog_symbol(LOG_LOCAL0)},
|
|
+#endif
|
|
+#ifdef LOG_LOCAL1
|
|
+ {syslog_symbol(LOG_LOCAL1)},
|
|
+#endif
|
|
+#ifdef LOG_LOCAL2
|
|
+ {syslog_symbol(LOG_LOCAL2)},
|
|
+#endif
|
|
+#ifdef LOG_LOCAL3
|
|
+ {syslog_symbol(LOG_LOCAL3)},
|
|
+#endif
|
|
+#ifdef LOG_LOCAL4
|
|
+ {syslog_symbol(LOG_LOCAL4)},
|
|
+#endif
|
|
+#ifdef LOG_LOCAL5
|
|
+ {syslog_symbol(LOG_LOCAL5)},
|
|
+#endif
|
|
+#ifdef LOG_LOCAL6
|
|
+ {syslog_symbol(LOG_LOCAL6)},
|
|
+#endif
|
|
+#ifdef LOG_LOCAL7
|
|
+ {syslog_symbol(LOG_LOCAL7)},
|
|
+#endif
|
|
+#ifdef LOG_USER
|
|
+ {syslog_symbol(LOG_USER)},
|
|
+#endif
|
|
+#ifdef LOG_ERR
|
|
+ {syslog_symbol(LOG_ERR)},
|
|
+#endif
|
|
+#ifdef LOG_WARNING
|
|
+ {syslog_symbol(LOG_WARNING)},
|
|
+#endif
|
|
+#ifdef LOG_NOTICE
|
|
+ {syslog_symbol(LOG_NOTICE)},
|
|
+#endif
|
|
+#ifdef LOG_INFO
|
|
+ {syslog_symbol(LOG_INFO)},
|
|
+#endif
|
|
+#ifdef LOG_DEBUG
|
|
+ {syslog_symbol(LOG_DEBUG)},
|
|
+#endif
|
|
+ {NULL, 0}
|
|
+ };
|
|
+ syslog_symbol_t *p;
|
|
+
|
|
+ for (p = symbols; p->name != NULL; ++p)
|
|
+ if (!strcmp(s, p->name) || !strcmp(s, p->name + 4))
|
|
+ return p->value;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+#define PRIORITY_MASK (LOG_ERR | LOG_WARNING | LOG_NOTICE | LOG_INFO | LOG_DEBUG)
|
|
+#endif /* HAVE_SYSLOG */
|
|
+
|
|
Logfile *
|
|
logfileOpen(const char *path, size_t bufsz, int fatal_flag)
|
|
{
|
|
- int fd;
|
|
- Logfile *lf;
|
|
- fd = file_open(path, O_WRONLY | O_CREAT | O_TEXT);
|
|
- if (DISK_ERROR == fd) {
|
|
- if (ENOENT == errno && fatal_flag) {
|
|
- fatalf("Cannot open '%s' because\n"
|
|
- "\tthe parent directory does not exist.\n"
|
|
- "\tPlease create the directory.\n", path);
|
|
- } else if (EACCES == errno && fatal_flag) {
|
|
- fatalf("Cannot open '%s' for writing.\n"
|
|
- "\tThe parent directory must be writeable by the\n"
|
|
- "\tuser '%s', which is the cache_effective_user\n"
|
|
- "\tset in squid.conf.", path, Config.effectiveUser);
|
|
- } else {
|
|
- debug(50, 1) ("logfileOpen: %s: %s\n", path, xstrerror());
|
|
- return NULL;
|
|
+ Logfile *lf = xcalloc(1, sizeof(*lf));
|
|
+ xstrncpy(lf->path, path, MAXPATHLEN);
|
|
+#if HAVE_SYSLOG
|
|
+ if (strcmp(path, "syslog") == 0 || strncmp(path, "syslog:", 7) == 0) {
|
|
+ lf->flags.syslog = 1;
|
|
+ lf->fd = -1;
|
|
+ if (path[6] != '\0') {
|
|
+ const char *priority = path + 7;
|
|
+ char *facility = strchr(priority, '|');
|
|
+ if (facility) {
|
|
+ *facility++ = '\0';
|
|
+ lf->syslog_priority |= syslog_ntoa(facility);
|
|
+ }
|
|
+ lf->syslog_priority |= syslog_ntoa(priority);
|
|
+ }
|
|
+ if ((lf->syslog_priority & PRIORITY_MASK) == 0)
|
|
+ lf->syslog_priority |= LOG_INFO;
|
|
+ } else
|
|
+#endif
|
|
+ {
|
|
+ int fd = file_open(path, O_WRONLY | O_CREAT | O_TEXT);
|
|
+ if (DISK_ERROR == fd) {
|
|
+ if (ENOENT == errno && fatal_flag) {
|
|
+ fatalf("Cannot open '%s' because\n"
|
|
+ "\tthe parent directory does not exist.\n"
|
|
+ "\tPlease create the directory.\n", path);
|
|
+ } else if (EACCES == errno && fatal_flag) {
|
|
+ fatalf("Cannot open '%s' for writing.\n"
|
|
+ "\tThe parent directory must be writeable by the\n"
|
|
+ "\tuser '%s', which is the cache_effective_user\n"
|
|
+ "\tset in squid.conf.", path, Config.effectiveUser);
|
|
+ } else {
|
|
+ debug(50, 1) ("logfileOpen: %s: %s\n", path, xstrerror());
|
|
+ safe_free(lf);
|
|
+ return NULL;
|
|
+ }
|
|
+ }
|
|
+ lf->fd = fd;
|
|
+ if (bufsz > 0) {
|
|
+ lf->buf = xmalloc(bufsz);
|
|
+ lf->bufsz = bufsz;
|
|
}
|
|
}
|
|
- lf = xcalloc(1, sizeof(*lf));
|
|
- lf->fd = fd;
|
|
if (fatal_flag)
|
|
lf->flags.fatal = 1;
|
|
- xstrncpy(lf->path, path, MAXPATHLEN);
|
|
- if (bufsz > 0) {
|
|
- lf->buf = xmalloc(bufsz);
|
|
- lf->bufsz = bufsz;
|
|
- }
|
|
return lf;
|
|
}
|
|
|
|
@@ -73,7 +164,8 @@
|
|
logfileClose(Logfile * lf)
|
|
{
|
|
logfileFlush(lf);
|
|
- file_close(lf->fd);
|
|
+ if (lf->fd >= 0)
|
|
+ file_close(lf->fd);
|
|
if (lf->buf)
|
|
xfree(lf->buf);
|
|
xfree(lf);
|
|
@@ -89,6 +181,8 @@
|
|
char from[MAXPATHLEN];
|
|
char to[MAXPATHLEN];
|
|
assert(lf->path);
|
|
+ if (lf->flags.syslog)
|
|
+ return;
|
|
#ifdef S_ISREG
|
|
if (stat(lf->path, &sb) == 0)
|
|
if (S_ISREG(sb.st_mode) == 0)
|
|
@@ -120,6 +214,12 @@
|
|
void
|
|
logfileWrite(Logfile * lf, void *buf, size_t len)
|
|
{
|
|
+#if HAVE_SYSLOG
|
|
+ if (lf->flags.syslog) {
|
|
+ syslog(lf->syslog_priority, "%s", (char *) buf);
|
|
+ return;
|
|
+ }
|
|
+#endif
|
|
if (0 == lf->bufsz) {
|
|
/* buffering disabled */
|
|
logfileWriteWrapper(lf, buf, len);
|
|
Index: src/protos.h
|
|
diff -u src/protos.h:1.41.6.34 src/protos.h:1.41.6.14.2.10
|
|
--- src/protos.h:1.41.6.34 Sat Feb 25 19:13:57 2006
|
|
+++ src/protos.h Fri Mar 3 18:27:52 2006
|
|
@@ -34,11 +34,14 @@
|
|
#ifndef SQUID_PROTOS_H
|
|
#define SQUID_PROTOS_H
|
|
|
|
-extern void accessLogLog(AccessLogEntry *);
|
|
+extern void accessLogLog(AccessLogEntry *, aclCheck_t * checklist);
|
|
extern void accessLogRotate(void);
|
|
extern void accessLogClose(void);
|
|
extern void accessLogInit(void);
|
|
extern const char *accessLogTime(time_t);
|
|
+extern int accessLogParseLogFormat(logformat_token ** fmt, char *def);
|
|
+extern void accessLogDumpLogFormat(StoreEntry * entry, const char *name, logformat * definitions);
|
|
+extern void accessLogFreeLogFormat(logformat_token ** fmt);
|
|
extern void hierarchyNote(HierarchyLogEntry *, hier_code, const char *);
|
|
#if FORW_VIA_DB
|
|
extern void fvdbCountVia(const char *key);
|
|
Index: src/structs.h
|
|
diff -u src/structs.h:1.48.2.46 src/structs.h:1.48.2.11.2.14
|
|
--- src/structs.h:1.48.2.46 Fri Mar 10 19:16:31 2006
|
|
+++ src/structs.h Mon Apr 24 08:22:34 2006
|
|
@@ -465,7 +465,6 @@
|
|
char *as_whois_server;
|
|
struct {
|
|
char *log;
|
|
- char *access;
|
|
char *store;
|
|
char *swap;
|
|
#if USE_USERAGENT_LOG
|
|
@@ -477,6 +476,8 @@
|
|
#if WIP_FWD_LOG
|
|
char *forward;
|
|
#endif
|
|
+ logformat *logformats;
|
|
+ customlog *accesslogs;
|
|
int rotateNumber;
|
|
} Log;
|
|
char *adminEmail;
|
|
@@ -623,6 +624,7 @@
|
|
acl_access *AlwaysDirect;
|
|
acl_access *ASlists;
|
|
acl_access *noCache;
|
|
+ acl_access *log;
|
|
#if SQUID_SNMP
|
|
acl_access *snmp;
|
|
#endif
|
|
@@ -1061,6 +1063,8 @@
|
|
const char *method_str;
|
|
} private;
|
|
HierarchyLogEntry hier;
|
|
+ HttpReply *reply;
|
|
+ request_t *request;
|
|
};
|
|
|
|
struct _clientHttpRequest {
|
|
@@ -2210,8 +2214,32 @@
|
|
size_t bufsz;
|
|
ssize_t offset;
|
|
struct {
|
|
- unsigned int fatal:1;
|
|
+ unsigned int fatal;
|
|
+ unsigned int syslog;
|
|
} flags;
|
|
+ int syslog_priority;
|
|
+};
|
|
+
|
|
+struct _logformat {
|
|
+ char *name;
|
|
+ logformat_token *format;
|
|
+ logformat *next;
|
|
+};
|
|
+
|
|
+struct _customlog {
|
|
+ char *filename;
|
|
+ acl_list *aclList;
|
|
+ logformat *logFormat;
|
|
+ Logfile *logfile;
|
|
+ customlog *next;
|
|
+ enum {
|
|
+ CLF_UNKNOWN,
|
|
+ CLF_AUTO,
|
|
+ CLF_CUSTOM,
|
|
+ CLF_SQUID,
|
|
+ CLF_COMMON,
|
|
+ CLF_NONE
|
|
+ } type;
|
|
};
|
|
|
|
struct cache_dir_option {
|
|
Index: src/typedefs.h
|
|
diff -u src/typedefs.h:1.25.6.8 src/typedefs.h:1.25.6.2.2.6
|
|
--- src/typedefs.h:1.25.6.8 Sat Mar 26 18:16:17 2005
|
|
+++ src/typedefs.h Thu May 26 21:34:16 2005
|
|
@@ -209,6 +209,9 @@
|
|
typedef struct _storerepl_entry storerepl_entry_t;
|
|
typedef struct _diskd_queue diskd_queue;
|
|
typedef struct _Logfile Logfile;
|
|
+typedef struct _logformat_token logformat_token;
|
|
+typedef struct _logformat logformat;
|
|
+typedef struct _customlog customlog;
|
|
typedef struct _RemovalPolicy RemovalPolicy;
|
|
typedef struct _RemovalPolicyWalker RemovalPolicyWalker;
|
|
typedef struct _RemovalPurgeWalker RemovalPurgeWalker;
|