4 * DEBUG: section 46 Access Log
5 * AUTHOR: Duane Wessels
7 * SQUID Web Proxy Cache http://www.squid-cache.org/
8 * ----------------------------------------------------------
10 * Squid is the result of efforts by numerous individuals from
11 * the Internet community; see the CONTRIBUTORS file for full
12 * details. Many organizations have provided support for Squid's
13 * development; see the SPONSORS file for full details. Squid is
14 * Copyrighted (C) 2001 by the Regents of the University of
15 * California; see the COPYRIGHT file for full details. Squid
16 * incorporates software developed and/or copyrighted by other
17 * sources; see the CREDITS file for full details.
19 * This program is free software; you can redistribute it and/or modify
20 * it under the terms of the GNU General Public License as published by
21 * the Free Software Foundation; either version 2 of the License, or
22 * (at your option) any later version.
24 * This program is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 * GNU General Public License for more details.
29 * You should have received a copy of the GNU General Public License
30 * along with this program; if not, write to the Free Software
31 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
37 #include "AccessLogEntry.h"
39 // Store.h Required by configuration directives parsing/dumping only
42 #include "errorpage.h"
43 #include "err_detail_type.h"
44 #include "acl/Checklist.h"
45 #include "errorpage.h"
47 #include "eui/Eui48.h"
48 #include "eui/Eui64.h"
50 #include "hier_code.h"
51 #include "HttpReply.h"
52 #include "HttpRequest.h"
55 #include "mgr/Registration.h"
57 #include "SquidTime.h"
59 static void accessLogSquid(AccessLogEntry
* al
, Logfile
* logfile
);
60 static void accessLogCommon(AccessLogEntry
* al
, Logfile
* logfile
);
61 static void accessLogCustom(AccessLogEntry
* al
, customlog
* log
);
63 static Logfile
*headerslog
= NULL
;
66 #if MULTICAST_MISS_STREAM
67 static int mcast_miss_fd
= -1;
69 static struct sockaddr_in mcast_miss_to
;
70 static void mcast_encode(unsigned int *, size_t, const unsigned int *);
73 const char *log_tags
[] = {
77 "TCP_REFRESH_UNMODIFIED",
78 "TCP_REFRESH_FAIL", // same tag logged for LOG_TCP_REFRESH_FAIL_OLD and
79 "TCP_REFRESH_FAIL", // LOG_TCP_REFRESH_FAIL_ERR for backward-compatibility
80 "TCP_REFRESH_MODIFIED",
81 "TCP_CLIENT_REFRESH_MISS",
107 static hash_table
*via_table
= NULL
;
108 static hash_table
*forw_table
= NULL
;
109 static void fvdbInit();
110 static void fvdbDumpTable(StoreEntry
* e
, hash_table
* hash
);
111 static void fvdbCount(hash_table
* hash
, const char *key
);
112 static OBJH fvdbDumpVia
;
113 static OBJH fvdbDumpForw
;
114 static FREE fvdbFreeEntry
;
115 static void fvdbClear(void);
116 static void fvdbRegisterWithCacheManager();
119 int LogfileStatus
= LOG_DISABLE
;
122 bool alLogformatHasAdaptToken
= false;
126 bool alLogformatHasIcapToken
= false;
129 #define LOG_BUF_SZ (MAX_URL<<2)
131 static const char c2x
[] =
132 "000102030405060708090a0b0c0d0e0f"
133 "101112131415161718191a1b1c1d1e1f"
134 "202122232425262728292a2b2c2d2e2f"
135 "303132333435363738393a3b3c3d3e3f"
136 "404142434445464748494a4b4c4d4e4f"
137 "505152535455565758595a5b5c5d5e5f"
138 "606162636465666768696a6b6c6d6e6f"
139 "707172737475767778797a7b7c7d7e7f"
140 "808182838485868788898a8b8c8d8e8f"
141 "909192939495969798999a9b9c9d9e9f"
142 "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf"
143 "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf"
144 "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf"
145 "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf"
146 "e0e1e2e3e4e5e6e7e8e9eaebecedeeef"
147 "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff";
149 /* log_quote -- URL-style encoding on MIME headers. */
152 log_quote(const char *header
)
159 if (header
== NULL
) {
160 buf
= static_cast<char *>(xcalloc(1, 1));
165 buf
= static_cast<char *>(xcalloc(1, (strlen(header
) * 3) + 1));
168 * We escape: \x00-\x1F"#%;<>?{}|\\\\^~`\[\]\x7F-\xFF
169 * which is the default escape list for the CPAN Perl5 URI module
170 * modulo the inclusion of space (x40) to make the raw logs a bit
174 while ((c
= *(const unsigned char *) header
++) != '\0') {
178 *buf_cursor
++ = '\\';
180 } else if (c
== '\n') {
181 *buf_cursor
++ = '\\';
207 *buf_cursor
++ = c2x
[i
];
208 *buf_cursor
++ = c2x
[i
+ 1];
211 } else if (c
== '\\') {
212 *buf_cursor
++ = '\\';
213 *buf_cursor
++ = '\\';
217 *buf_cursor
++ = (char) c
;
226 username_quote(const char *header
)
227 /* copy of log_quote. Bugs there will be found here */
234 if (header
== NULL
) {
235 buf
= static_cast<char *>(xcalloc(1, 1));
240 buf
= static_cast<char *>(xcalloc(1, (strlen(header
) * 3) + 1));
243 * We escape: space \x00-\x1F and space (0x40) and \x7F-\xFF
244 * to prevent garbage in the logs. CR and LF are also there just in case.
247 while ((c
= *(const unsigned char *) header
++) != '\0') {
249 *buf_cursor
++ = '\\';
251 } else if (c
== '\n') {
252 *buf_cursor
++ = '\\';
260 *buf_cursor
++ = c2x
[i
];
261 *buf_cursor
++ = c2x
[i
+ 1];
263 *buf_cursor
++ = (char) c
;
272 accessLogFormatName(const char *name
)
280 return username_quote(name
);
284 log_quoted_string(const char *str
)
286 char *out
= (char *)xmalloc(strlen(str
) * 2 + 1);
290 int l
= strcspn(str
, "\"\\\r\n\t");
331 * Bytecodes for the configureable logformat stuff
334 LFT_NONE
, /* dummy */
337 LFT_CLIENT_IP_ADDRESS
,
344 /*LFT_SERVER_IP_ADDRESS, */
345 LFT_SERVER_IP_OR_PEER_NAME
,
346 /*LFT_SERVER_PORT, */
353 LFT_TIME_SECONDS_SINCE_EPOCH
,
357 LFT_TIME_TO_HANDLE_REQUEST
,
359 LFT_PEER_RESPONSE_TIME
,
360 LFT_TOTAL_SERVER_SIDE_RESPONSE_TIME
,
364 LFT_REQUEST_HEADER_ELEM
,
365 LFT_REQUEST_ALL_HEADERS
,
367 LFT_ADAPTED_REQUEST_HEADER
,
368 LFT_ADAPTED_REQUEST_HEADER_ELEM
,
369 LFT_ADAPTED_REQUEST_ALL_HEADERS
,
372 LFT_REPLY_HEADER_ELEM
,
373 LFT_REPLY_ALL_HEADERS
,
379 /*LFT_USER_SCHEME, */
382 LFT_HTTP_SENT_STATUS_CODE_OLD_30
,
383 LFT_HTTP_SENT_STATUS_CODE
,
384 LFT_HTTP_RECEIVED_STATUS_CODE
,
385 /*LFT_HTTP_STATUS, */
386 LFT_HTTP_BODY_BYTES_READ
,
390 LFT_SQUID_ERROR_DETAIL
,
398 /*LFT_REQUEST_QUERY, * // * this is not needed. see strip_query_terms */
401 LFT_REQUEST_SIZE_TOTAL
,
402 /*LFT_REQUEST_SIZE_LINE, */
403 LFT_REQUEST_SIZE_HEADERS
,
404 /*LFT_REQUEST_SIZE_BODY, */
405 /*LFT_REQUEST_SIZE_BODY_NO_TE, */
407 LFT_REPLY_SIZE_TOTAL
,
408 LFT_REPLY_HIGHOFFSET
,
409 LFT_REPLY_OBJECTSIZE
,
410 /*LFT_REPLY_SIZE_LINE, */
411 LFT_REPLY_SIZE_HEADERS
,
412 /*LFT_REPLY_SIZE_BODY, */
413 /*LFT_REPLY_SIZE_BODY_NO_TE, */
422 LTF_ADAPTATION_SUM_XACT_TIMES
,
423 LTF_ADAPTATION_ALL_XACT_TIMES
,
424 LFT_ADAPTATION_LAST_HEADER
,
425 LFT_ADAPTATION_LAST_HEADER_ELEM
,
426 LFT_ADAPTATION_LAST_ALL_HEADERS
,
435 LFT_ICAP_REQUEST_URI
,
436 LFT_ICAP_REQUEST_METHOD
,
439 LFT_ICAP_BODY_BYTES_READ
,
442 LFT_ICAP_REQ_HEADER_ELEM
,
443 LFT_ICAP_REQ_ALL_HEADERS
,
446 LFT_ICAP_REP_HEADER_ELEM
,
447 LFT_ICAP_REP_ALL_HEADERS
,
449 LFT_ICAP_TR_RESPONSE_TIME
,
452 LFT_ICAP_STATUS_CODE
,
455 LFT_PERCENT
/* special string cases for escaped chars */
466 /* FIXME: public class so we can pre-define its type. */
467 class logformat_token
470 logformat_bcode_t type
;
482 unsigned char precision
;
483 enum log_quote quote
;
485 unsigned int space
:1;
488 logformat_token
*next
; /* todo: move from linked list to array */
491 struct logformat_token_table_entry
{
493 logformat_bcode_t token_type
;
497 struct logformat_token_table_entry logformat_token_table
[] = {
499 {">a", LFT_CLIENT_IP_ADDRESS
},
500 {">p", LFT_CLIENT_PORT
},
501 {">A", LFT_CLIENT_FQDN
},
503 {">eui", LFT_CLIENT_EUI
},
506 /*{ "<a", LFT_SERVER_IP_ADDRESS }, */
507 /*{ "<p", LFT_SERVER_PORT }, */
508 {"<A", LFT_SERVER_IP_OR_PEER_NAME
},
510 /* {"oa", LFT_OUTGOING_IP}, */
511 /* {"ot", LFT_OUTGOING_TOS}, */
513 {"la", LFT_LOCAL_IP
},
514 {"lp", LFT_LOCAL_PORT
},
515 /*{ "lA", LFT_LOCAL_NAME }, */
516 {"<lp", LFT_PEER_LOCAL_PORT
},
518 {"ts", LFT_TIME_SECONDS_SINCE_EPOCH
},
519 {"tu", LFT_TIME_SUBSECOND
},
520 {"tl", LFT_TIME_LOCALTIME
},
521 {"tg", LFT_TIME_GMT
},
522 {"tr", LFT_TIME_TO_HANDLE_REQUEST
},
524 {"<pt", LFT_PEER_RESPONSE_TIME
},
525 {"<tt", LFT_TOTAL_SERVER_SIDE_RESPONSE_TIME
},
526 {"dt", LFT_DNS_WAIT_TIME
},
528 {">ha", LFT_ADAPTED_REQUEST_HEADER
},
529 {">ha", LFT_ADAPTED_REQUEST_ALL_HEADERS
},
530 {">h", LFT_REQUEST_HEADER
},
531 {">h", LFT_REQUEST_ALL_HEADERS
},
532 {"<h", LFT_REPLY_HEADER
},
533 {"<h", LFT_REPLY_ALL_HEADERS
},
535 {"un", LFT_USER_NAME
},
536 {"ul", LFT_USER_LOGIN
},
537 /*{ "ur", LFT_USER_REALM }, */
538 /*{ "us", LFT_USER_SCHEME }, */
539 {"ui", LFT_USER_IDENT
},
540 {"ue", LFT_USER_EXTERNAL
},
542 {"Hs", LFT_HTTP_SENT_STATUS_CODE_OLD_30
},
543 {">Hs", LFT_HTTP_SENT_STATUS_CODE
},
544 {"<Hs", LFT_HTTP_RECEIVED_STATUS_CODE
},
545 /*{ "Ht", LFT_HTTP_STATUS }, */
546 {"<bs", LFT_HTTP_BODY_BYTES_READ
},
548 {"Ss", LFT_SQUID_STATUS
},
549 { "err_code", LFT_SQUID_ERROR
},
550 { "err_detail", LFT_SQUID_ERROR_DETAIL
},
551 {"Sh", LFT_SQUID_HIERARCHY
},
553 {"mt", LFT_MIME_TYPE
},
555 {"rm", LFT_REQUEST_METHOD
},
556 {"ru", LFT_REQUEST_URI
}, /* doesn't include the query-string */
557 {"rp", LFT_REQUEST_URLPATH
}, /* doesn't include the host */
558 /* { "rq", LFT_REQUEST_QUERY }, * / / * the query-string, INCLUDING the leading ? */
559 {">v", LFT_REQUEST_VERSION
},
560 {"rv", LFT_REQUEST_VERSION
},
562 { ">st", LFT_REQUEST_SIZE_TOTAL
},
563 /*{ ">sl", LFT_REQUEST_SIZE_LINE }, * / / * the request line "GET ... " */
564 { ">sh", LFT_REQUEST_SIZE_HEADERS
},
565 /*{ ">sb", LFT_REQUEST_SIZE_BODY }, */
566 /*{ ">sB", LFT_REQUEST_SIZE_BODY_NO_TE }, */
568 {"<st", LFT_REPLY_SIZE_TOTAL
},
569 {"<sH", LFT_REPLY_HIGHOFFSET
},
570 {"<sS", LFT_REPLY_OBJECTSIZE
},
571 /*{ "<sl", LFT_REPLY_SIZE_LINE }, * / / * the reply line (protocol, code, text) */
572 { "<sh", LFT_REPLY_SIZE_HEADERS
},
573 /*{ "<sb", LFT_REPLY_SIZE_BODY }, */
574 /*{ "<sB", LFT_REPLY_SIZE_BODY_NO_TE }, */
577 {"st", LFT_IO_SIZE_TOTAL
},
579 {"sn", LFT_SEQUENCE_NUMBER
},
584 {"adapt::all_trs", LTF_ADAPTATION_ALL_XACT_TIMES
},
585 {"adapt::sum_trs", LTF_ADAPTATION_SUM_XACT_TIMES
},
586 {"adapt::<last_h", LFT_ADAPTATION_LAST_HEADER
},
590 {"icap::tt", LFT_ICAP_TOTAL_TIME
},
591 {"icap::<last_h", LFT_ADAPTATION_LAST_HEADER
}, // deprecated
593 {"icap::<A", LFT_ICAP_ADDR
},
594 {"icap::<service_name", LFT_ICAP_SERV_NAME
},
595 {"icap::ru", LFT_ICAP_REQUEST_URI
},
596 {"icap::rm", LFT_ICAP_REQUEST_METHOD
},
597 {"icap::>st", LFT_ICAP_BYTES_SENT
},
598 {"icap::<st", LFT_ICAP_BYTES_READ
},
599 {"icap::<bs", LFT_ICAP_BODY_BYTES_READ
},
601 {"icap::>h", LFT_ICAP_REQ_HEADER
},
602 {"icap::<h", LFT_ICAP_REP_HEADER
},
604 {"icap::tr", LFT_ICAP_TR_RESPONSE_TIME
},
605 {"icap::tio", LFT_ICAP_IO_TIME
},
606 {"icap::to", LFT_ICAP_OUTCOME
},
607 {"icap::Hs", LFT_ICAP_STATUS_CODE
},
610 {NULL
, LFT_NONE
} /* this must be last */
614 accessLogCustom(AccessLogEntry
* al
, customlog
* log
)
618 logformat_token
*fmt
;
626 logfile
= log
->logfile
;
628 for (fmt
= lf
->format
; fmt
!= NULL
; fmt
= fmt
->next
) { /* for each token */
629 const char *out
= NULL
;
644 out
= fmt
->data
.string
;
647 case LFT_CLIENT_IP_ADDRESS
:
648 if (al
->cache
.caddr
.IsNoAddr()) // e.g., ICAP OPTIONS lack client
651 out
= al
->cache
.caddr
.NtoA(tmp
,1024);
654 case LFT_CLIENT_FQDN
:
655 if (al
->cache
.caddr
.IsAnyAddr()) // e.g., ICAP OPTIONS lack client
658 out
= fqdncache_gethostbyaddr(al
->cache
.caddr
, FQDN_LOOKUP_IF_MISS
);
660 out
= al
->cache
.caddr
.NtoA(tmp
,1024);
665 case LFT_CLIENT_PORT
:
667 outint
= al
->request
->client_addr
.GetPort();
675 if (al
->cache
.caddr
.IsIPv4())
676 al
->request
->client_eui48
.encode(tmp
, 1024);
678 al
->request
->client_eui64
.encode(tmp
, 1024);
684 /* case LFT_SERVER_IP_ADDRESS: */
686 case LFT_SERVER_IP_OR_PEER_NAME
:
691 /* case LFT_SERVER_PORT: */
695 out
= al
->request
->my_addr
.NtoA(tmp
,1024);
702 outint
= al
->request
->my_addr
.GetPort();
708 case LFT_PEER_LOCAL_PORT
:
709 if (al
->hier
.peer_local_port
) {
710 outint
= al
->hier
.peer_local_port
;
716 case LFT_TIME_SECONDS_SINCE_EPOCH
:
717 // some platforms store time in 32-bit, some 64-bit...
718 outoff
= static_cast<int64_t>(current_time
.tv_sec
);
722 case LFT_TIME_SUBSECOND
:
723 outint
= current_time
.tv_usec
/ fmt
->divisor
;
728 case LFT_TIME_LOCALTIME
:
734 spec
= fmt
->data
.timespec
;
736 if (fmt
->type
== LFT_TIME_LOCALTIME
) {
738 spec
= "%d/%b/%Y:%H:%M:%S %z";
739 t
= localtime(&squid_curtime
);
742 spec
= "%d/%b/%Y:%H:%M:%S";
744 t
= gmtime(&squid_curtime
);
747 strftime(tmp
, sizeof(tmp
), spec
, t
);
754 case LFT_TIME_TO_HANDLE_REQUEST
:
755 outint
= al
->cache
.msec
;
759 case LFT_PEER_RESPONSE_TIME
:
760 if (al
->hier
.peer_response_time
< 0) {
763 outoff
= al
->hier
.peer_response_time
;
768 case LFT_TOTAL_SERVER_SIDE_RESPONSE_TIME
:
769 if (al
->hier
.total_response_time
< 0) {
772 outoff
= al
->hier
.total_response_time
;
777 case LFT_DNS_WAIT_TIME
:
778 if (al
->request
&& al
->request
->dnsWait
>= 0) {
779 outint
= al
->request
->dnsWait
;
784 case LFT_REQUEST_HEADER
:
787 sb
= al
->request
->header
.getByName(fmt
->data
.header
.header
);
789 out
= sb
.termedBuf();
795 case LFT_ADAPTED_REQUEST_HEADER
:
798 sb
= al
->adapted_request
->header
.getByName(fmt
->data
.header
.header
);
800 out
= sb
.termedBuf();
806 case LFT_REPLY_HEADER
:
808 sb
= al
->reply
->header
.getByName(fmt
->data
.header
.header
);
810 out
= sb
.termedBuf();
817 case LTF_ADAPTATION_SUM_XACT_TIMES
:
819 Adaptation::History::Pointer ah
= al
->request
->adaptHistory();
821 ah
->sumLogString(fmt
->data
.string
, sb
);
822 out
= sb
.termedBuf();
826 case LTF_ADAPTATION_ALL_XACT_TIMES
:
828 Adaptation::History::Pointer ah
= al
->request
->adaptHistory();
830 ah
->allLogString(fmt
->data
.string
, sb
);
831 out
= sb
.termedBuf();
835 case LFT_ADAPTATION_LAST_HEADER
:
837 const Adaptation::History::Pointer ah
= al
->request
->adaptHistory();
838 if (ah
!= NULL
) // XXX: add adapt::<all_h but use lastMeta here
839 sb
= ah
->allMeta
.getByName(fmt
->data
.header
.header
);
842 // XXX: here and elsewhere: move such code inside the if guard
843 out
= sb
.termedBuf();
849 case LFT_ADAPTATION_LAST_HEADER_ELEM
:
851 const Adaptation::History::Pointer ah
= al
->request
->adaptHistory();
852 if (ah
!= NULL
) // XXX: add adapt::<all_h but use lastMeta here
853 sb
= ah
->allMeta
.getByNameListMember(fmt
->data
.header
.header
, fmt
->data
.header
.element
, fmt
->data
.header
.separator
);
856 out
= sb
.termedBuf();
862 case LFT_ADAPTATION_LAST_ALL_HEADERS
:
863 out
= al
->headers
.adapt_last
;
873 out
= al
->icap
.hostAddr
.NtoA(tmp
,1024);
876 case LFT_ICAP_SERV_NAME
:
877 out
= al
->icap
.serviceName
.termedBuf();
880 case LFT_ICAP_REQUEST_URI
:
881 out
= al
->icap
.reqUri
.termedBuf();
884 case LFT_ICAP_REQUEST_METHOD
:
885 out
= Adaptation::Icap::ICAP::methodStr(al
->icap
.reqMethod
);
888 case LFT_ICAP_BYTES_SENT
:
889 outoff
= al
->icap
.bytesSent
;
893 case LFT_ICAP_BYTES_READ
:
894 outoff
= al
->icap
.bytesRead
;
898 case LFT_ICAP_BODY_BYTES_READ
:
899 if (al
->icap
.bodyBytesRead
>= 0) {
900 outoff
= al
->icap
.bodyBytesRead
;
903 // else if icap.bodyBytesRead < 0, we do not have any http data,
904 // so just print a "-" (204 responses etc)
907 case LFT_ICAP_REQ_HEADER
:
908 if (NULL
!= al
->icap
.request
) {
909 sb
= al
->icap
.request
->header
.getByName(fmt
->data
.header
.header
);
910 out
= sb
.termedBuf();
915 case LFT_ICAP_REQ_HEADER_ELEM
:
917 sb
= al
->icap
.request
->header
.getByNameListMember(fmt
->data
.header
.header
, fmt
->data
.header
.element
, fmt
->data
.header
.separator
);
919 out
= sb
.termedBuf();
925 case LFT_ICAP_REQ_ALL_HEADERS
:
926 if (al
->icap
.request
) {
927 HttpHeaderPos pos
= HttpHeaderInitPos
;
928 while (const HttpHeaderEntry
*e
= al
->icap
.request
->header
.getEntry(&pos
)) {
934 out
= sb
.termedBuf();
939 case LFT_ICAP_REP_HEADER
:
940 if (NULL
!= al
->icap
.reply
) {
941 sb
= al
->icap
.reply
->header
.getByName(fmt
->data
.header
.header
);
942 out
= sb
.termedBuf();
947 case LFT_ICAP_REP_HEADER_ELEM
:
948 if (NULL
!= al
->icap
.reply
)
949 sb
= al
->icap
.reply
->header
.getByNameListMember(fmt
->data
.header
.header
, fmt
->data
.header
.element
, fmt
->data
.header
.separator
);
951 out
= sb
.termedBuf();
957 case LFT_ICAP_REP_ALL_HEADERS
:
958 if (al
->icap
.reply
) {
959 HttpHeaderPos pos
= HttpHeaderInitPos
;
960 while (const HttpHeaderEntry
*e
= al
->icap
.reply
->header
.getEntry(&pos
)) {
966 out
= sb
.termedBuf();
971 case LFT_ICAP_TR_RESPONSE_TIME
:
972 outint
= al
->icap
.trTime
;
976 case LFT_ICAP_IO_TIME
:
977 outint
= al
->icap
.ioTime
;
981 case LFT_ICAP_STATUS_CODE
:
982 outint
= al
->icap
.resStatus
;
986 case LFT_ICAP_OUTCOME
:
987 out
= al
->icap
.outcome
;
990 case LFT_ICAP_TOTAL_TIME
:
991 outint
= al
->icap
.processingTime
;
995 case LFT_REQUEST_HEADER_ELEM
:
997 sb
= al
->request
->header
.getByNameListMember(fmt
->data
.header
.header
, fmt
->data
.header
.element
, fmt
->data
.header
.separator
);
999 out
= sb
.termedBuf();
1005 case LFT_ADAPTED_REQUEST_HEADER_ELEM
:
1006 if (al
->adapted_request
)
1007 sb
= al
->adapted_request
->header
.getByNameListMember(fmt
->data
.header
.header
, fmt
->data
.header
.element
, fmt
->data
.header
.separator
);
1009 out
= sb
.termedBuf();
1015 case LFT_REPLY_HEADER_ELEM
:
1017 sb
= al
->reply
->header
.getByNameListMember(fmt
->data
.header
.header
, fmt
->data
.header
.element
, fmt
->data
.header
.separator
);
1019 out
= sb
.termedBuf();
1025 case LFT_REQUEST_ALL_HEADERS
:
1026 out
= al
->headers
.request
;
1032 case LFT_ADAPTED_REQUEST_ALL_HEADERS
:
1033 out
= al
->headers
.adapted_request
;
1039 case LFT_REPLY_ALL_HEADERS
:
1040 out
= al
->headers
.reply
;
1047 out
= accessLogFormatName(al
->cache
.authuser
);
1050 out
= accessLogFormatName(al
->cache
.extuser
);
1055 out
= accessLogFormatName(al
->cache
.ssluser
);
1060 out
= accessLogFormatName(al
->cache
.rfc931
);
1066 case LFT_USER_LOGIN
:
1067 out
= accessLogFormatName(al
->cache
.authuser
);
1073 case LFT_USER_IDENT
:
1074 out
= accessLogFormatName(al
->cache
.rfc931
);
1080 case LFT_USER_EXTERNAL
:
1081 out
= accessLogFormatName(al
->cache
.extuser
);
1087 /* case LFT_USER_REALM: */
1088 /* case LFT_USER_SCHEME: */
1090 // the fmt->type can not be LFT_HTTP_SENT_STATUS_CODE_OLD_30
1091 // but compiler complains if ommited
1092 case LFT_HTTP_SENT_STATUS_CODE_OLD_30
:
1093 case LFT_HTTP_SENT_STATUS_CODE
:
1094 outint
= al
->http
.code
;
1100 case LFT_HTTP_RECEIVED_STATUS_CODE
:
1101 if (al
->hier
.peer_reply_status
== HTTP_STATUS_NONE
) {
1104 outint
= al
->hier
.peer_reply_status
;
1108 /* case LFT_HTTP_STATUS:
1109 * out = statusline->text;
1113 case LFT_HTTP_BODY_BYTES_READ
:
1114 if (al
->hier
.bodyBytesRead
>= 0) {
1115 outoff
= al
->hier
.bodyBytesRead
;
1118 // else if hier.bodyBytesRead < 0 we did not have any data exchange with
1119 // a peer server so just print a "-" (eg requests served from cache,
1120 // or internal error messages).
1123 case LFT_SQUID_STATUS
:
1124 if (al
->http
.timedout
|| al
->http
.aborted
) {
1125 snprintf(tmp
, sizeof(tmp
), "%s%s", log_tags
[al
->cache
.code
],
1126 al
->http
.statusSfx());
1129 out
= log_tags
[al
->cache
.code
];
1134 case LFT_SQUID_ERROR
:
1135 if (al
->request
&& al
->request
->errType
!= ERR_NONE
)
1136 out
= errorPageName(al
->request
->errType
);
1139 case LFT_SQUID_ERROR_DETAIL
:
1140 if (al
->request
&& al
->request
->errDetail
!= ERR_DETAIL_NONE
) {
1141 if (al
->request
->errDetail
> ERR_DETAIL_START
&&
1142 al
->request
->errDetail
< ERR_DETAIL_MAX
)
1143 out
= errorDetailName(al
->request
->errDetail
);
1145 if (al
->request
->errDetail
>= ERR_DETAIL_EXCEPTION_START
)
1146 snprintf(tmp
, sizeof(tmp
), "%s=0x%X",
1147 errorDetailName(al
->request
->errDetail
), (uint32_t) al
->request
->errDetail
);
1149 snprintf(tmp
, sizeof(tmp
), "%s=%d",
1150 errorDetailName(al
->request
->errDetail
), al
->request
->errDetail
);
1156 case LFT_SQUID_HIERARCHY
:
1157 if (al
->hier
.ping
.timedout
)
1158 mb
.append("TIMEOUT_", 8);
1160 out
= hier_code_str
[al
->hier
.code
];
1165 out
= al
->http
.content_type
;
1169 case LFT_REQUEST_METHOD
:
1170 out
= al
->_private
.method_str
;
1174 case LFT_REQUEST_URI
:
1179 case LFT_REQUEST_URLPATH
:
1181 out
= al
->request
->urlpath
.termedBuf();
1186 case LFT_REQUEST_VERSION
:
1187 snprintf(tmp
, sizeof(tmp
), "%d.%d", (int) al
->http
.version
.major
, (int) al
->http
.version
.minor
);
1191 case LFT_REQUEST_SIZE_TOTAL
:
1192 outoff
= al
->cache
.requestSize
;
1196 /*case LFT_REQUEST_SIZE_LINE: */
1197 case LFT_REQUEST_SIZE_HEADERS
:
1198 outoff
= al
->cache
.requestHeadersSize
;
1201 /*case LFT_REQUEST_SIZE_BODY: */
1202 /*case LFT_REQUEST_SIZE_BODY_NO_TE: */
1204 case LFT_REPLY_SIZE_TOTAL
:
1205 outoff
= al
->cache
.replySize
;
1209 case LFT_REPLY_HIGHOFFSET
:
1210 outoff
= al
->cache
.highOffset
;
1216 case LFT_REPLY_OBJECTSIZE
:
1217 outoff
= al
->cache
.objectSize
;
1223 /*case LFT_REPLY_SIZE_LINE: */
1224 case LFT_REPLY_SIZE_HEADERS
:
1225 outint
= al
->cache
.replyHeadersSize
;
1228 /*case LFT_REPLY_SIZE_BODY: */
1229 /*case LFT_REPLY_SIZE_BODY_NO_TE: */
1233 out
= al
->request
->tag
.termedBuf();
1239 case LFT_IO_SIZE_TOTAL
:
1240 outint
= al
->cache
.requestSize
+ al
->cache
.replySize
;
1246 out
= al
->request
->extacl_log
.termedBuf();
1252 case LFT_SEQUENCE_NUMBER
:
1253 outoff
= logfile
->sequence_number
;
1264 snprintf(tmp
, sizeof(tmp
), "%0*" PRId64
, fmt
->zero
? (int) fmt
->width
: 0, outoff
);
1268 snprintf(tmp
, sizeof(tmp
), "%0*ld", fmt
->zero
? (int) fmt
->width
: 0, outint
);
1273 if (quote
|| fmt
->quote
!= LOG_QUOTE_NONE
) {
1274 char *newout
= NULL
;
1277 switch (fmt
->quote
) {
1279 case LOG_QUOTE_NONE
:
1280 newout
= rfc1738_escape_unescaped(out
);
1283 case LOG_QUOTE_QUOTES
:
1284 newout
= log_quoted_string(out
);
1288 case LOG_QUOTE_BRAKETS
:
1289 newout
= log_quote(out
);
1294 newout
= rfc1738_escape(out
);
1313 mb
.Printf("%-*s", (int) fmt
->width
, out
);
1315 mb
.Printf("%*s", (int) fmt
->width
, out
);
1317 mb
.append(out
, strlen(out
));
1331 logfilePrintf(logfile
, "%s\n", mb
.buf
);
1334 /* parses a single token. Returns the token length in characters,
1335 * and fills in the lt item with the token information.
1336 * def is for sure null-terminated
1339 accessLogGetNewLogFormatToken(logformat_token
* lt
, char *def
, enum log_quote
*quote
)
1343 struct logformat_token_table_entry
*lte
;
1346 memset(lt
, 0, sizeof(*lt
));
1347 l
= strcspn(cur
, "%");
1351 /* it's a string for sure, until \0 or the next % */
1352 cp
= (char *)xmalloc(l
+ 1);
1353 xstrncpy(cp
, cur
, l
+ 1);
1354 lt
->type
= LFT_STRING
;
1355 lt
->data
.string
= cp
;
1362 if (*quote
== LOG_QUOTE_NONE
)
1363 *quote
= LOG_QUOTE_QUOTES
;
1364 else if (*quote
== LOG_QUOTE_QUOTES
)
1365 *quote
= LOG_QUOTE_NONE
;
1370 if (*quote
== LOG_QUOTE_NONE
)
1371 *quote
= LOG_QUOTE_BRAKETS
;
1376 if (*quote
== LOG_QUOTE_BRAKETS
)
1377 *quote
= LOG_QUOTE_NONE
;
1397 lt
->quote
= LOG_QUOTE_QUOTES
;
1402 lt
->quote
= LOG_QUOTE_RAW
;
1407 lt
->quote
= LOG_QUOTE_BRAKETS
;
1412 lt
->quote
= LOG_QUOTE_URL
;
1432 lt
->width
= strtol(cur
, &cur
, 10);
1435 lt
->precision
= strtol(cur
+ 1, &cur
, 10);
1440 l
= strcspn(cur
, "}");
1441 cp
= (char *)xmalloc(l
+ 1);
1442 xstrncpy(cp
, cur
, l
+ 1);
1443 lt
->data
.string
= cp
;
1450 // For upward compatibility, assume "http::" prefix as default prefix
1451 // for all log access formating codes, except those starting
1452 // from "icap::", "adapt::" and "%"
1453 if (strncmp(cur
,"http::", 6) == 0 &&
1454 strncmp(cur
+6, "icap::", 6) != 0 &&
1455 strncmp(cur
+6, "adapt::", 12) != 0 && *(cur
+6) != '%' ) {
1459 lt
->type
= LFT_NONE
;
1461 for (lte
= logformat_token_table
; lte
->config
!= NULL
; lte
++) {
1462 if (strncmp(lte
->config
, cur
, strlen(lte
->config
)) == 0) {
1463 lt
->type
= lte
->token_type
;
1464 cur
+= strlen(lte
->config
);
1469 if (lt
->type
== LFT_NONE
) {
1470 fatalf("Can't parse configuration token: '%s'\n",
1484 case LFT_ADAPTATION_LAST_HEADER
:
1488 case LFT_ICAP_REQ_HEADER
:
1490 case LFT_ICAP_REP_HEADER
:
1493 case LFT_ADAPTED_REQUEST_HEADER
:
1495 case LFT_REQUEST_HEADER
:
1497 case LFT_REPLY_HEADER
:
1499 if (lt
->data
.string
) {
1500 char *header
= lt
->data
.string
;
1501 char *cp
= strchr(header
, ':');
1506 if (*cp
== ',' || *cp
== ';' || *cp
== ':')
1507 lt
->data
.header
.separator
= *cp
++;
1509 lt
->data
.header
.separator
= ',';
1511 lt
->data
.header
.element
= cp
;
1514 case LFT_REQUEST_HEADER
:
1515 lt
->type
= LFT_REQUEST_HEADER_ELEM
;
1518 case LFT_ADAPTED_REQUEST_HEADER
:
1519 lt
->type
= LFT_ADAPTED_REQUEST_HEADER_ELEM
;
1522 case LFT_REPLY_HEADER
:
1523 lt
->type
= LFT_REPLY_HEADER_ELEM
;
1526 case LFT_ADAPTATION_LAST_HEADER
:
1527 lt
->type
= LFT_ADAPTATION_LAST_HEADER_ELEM
;
1531 case LFT_ICAP_REQ_HEADER
:
1532 lt
->type
= LFT_ICAP_REQ_HEADER_ELEM
;
1534 case LFT_ICAP_REP_HEADER
:
1535 lt
->type
= LFT_ICAP_REP_HEADER_ELEM
;
1543 lt
->data
.header
.header
= header
;
1546 case LFT_REQUEST_HEADER
:
1547 lt
->type
= LFT_REQUEST_ALL_HEADERS
;
1550 case LFT_ADAPTED_REQUEST_HEADER
:
1551 lt
->type
= LFT_ADAPTED_REQUEST_ALL_HEADERS
;
1554 case LFT_REPLY_HEADER
:
1555 lt
->type
= LFT_REPLY_ALL_HEADERS
;
1558 case LFT_ADAPTATION_LAST_HEADER
:
1559 lt
->type
= LFT_ADAPTATION_LAST_ALL_HEADERS
;
1563 case LFT_ICAP_REQ_HEADER
:
1564 lt
->type
= LFT_ICAP_REQ_ALL_HEADERS
;
1566 case LFT_ICAP_REP_HEADER
:
1567 lt
->type
= LFT_ICAP_REP_ALL_HEADERS
;
1573 Config
.onoff
.log_mime_hdrs
= 1;
1578 case LFT_CLIENT_FQDN
:
1579 Config
.onoff
.log_fqdn
= 1;
1582 case LFT_TIME_SUBSECOND
:
1585 if (lt
->precision
) {
1587 lt
->divisor
= 1000000;
1589 for (i
= lt
->precision
; i
> 1; i
--)
1598 case LFT_HTTP_SENT_STATUS_CODE_OLD_30
:
1599 debugs(46, 0, "WARNING: the \"Hs\" formating code is deprecated use the \">Hs\" instead");
1600 lt
->type
= LFT_HTTP_SENT_STATUS_CODE
;
1610 accessLogParseLogFormat(logformat_token
** fmt
, char *def
)
1613 logformat_token
*new_lt
, *last_lt
;
1614 enum log_quote quote
= LOG_QUOTE_NONE
;
1616 debugs(46, 2, "accessLogParseLogFormat: got definition '" << def
<< "'");
1618 /* very inefficent parser, but who cares, this needs to be simple */
1619 /* First off, let's tokenize, we'll optimize in a second pass.
1620 * A token can either be a %-prefixed sequence (usually a dynamic
1621 * token but it can be an escaped sequence), or a string. */
1623 eos
= def
+ strlen(def
);
1624 *fmt
= new_lt
= last_lt
= (logformat_token
*)xmalloc(sizeof(logformat_token
));
1625 cur
+= accessLogGetNewLogFormatToken(new_lt
, cur
, "e
);
1628 new_lt
= (logformat_token
*)xmalloc(sizeof(logformat_token
));
1629 last_lt
->next
= new_lt
;
1631 cur
+= accessLogGetNewLogFormatToken(new_lt
, cur
, "e
);
1638 accessLogDumpLogFormat(StoreEntry
* entry
, const char *name
, logformat
* definitions
)
1643 struct logformat_token_table_entry
*te
;
1644 debugs(46, 4, "accessLogDumpLogFormat called");
1646 for (format
= definitions
; format
; format
= format
->next
) {
1647 debugs(46, 3, "Dumping logformat definition for " << format
->name
);
1648 storeAppendPrintf(entry
, "logformat %s ", format
->name
);
1650 for (t
= format
->format
; t
; t
= t
->next
) {
1651 if (t
->type
== LFT_STRING
)
1652 storeAppendPrintf(entry
, "%s", t
->data
.string
);
1656 logformat_bcode_t type
= t
->type
;
1664 case LFT_ADAPTATION_LAST_HEADER_ELEM
:
1667 case LFT_ICAP_REQ_HEADER_ELEM
:
1668 case LFT_ICAP_REP_HEADER_ELEM
:
1670 case LFT_REQUEST_HEADER_ELEM
:
1671 case LFT_ADAPTED_REQUEST_HEADER_ELEM
:
1672 case LFT_REPLY_HEADER_ELEM
:
1674 if (t
->data
.header
.separator
!= ',')
1675 snprintf(argbuf
, sizeof(argbuf
), "%s:%c%s", t
->data
.header
.header
, t
->data
.header
.separator
, t
->data
.header
.element
);
1677 snprintf(argbuf
, sizeof(argbuf
), "%s:%s", t
->data
.header
.header
, t
->data
.header
.element
);
1682 case LFT_REQUEST_HEADER_ELEM
:
1683 type
= LFT_REQUEST_HEADER
;
1685 case LFT_ADAPTED_REQUEST_HEADER_ELEM
:
1686 type
= LFT_ADAPTED_REQUEST_HEADER
;
1688 case LFT_REPLY_HEADER_ELEM
:
1689 type
= LFT_REPLY_HEADER
;
1692 case LFT_ADAPTATION_LAST_HEADER_ELEM
:
1693 type
= LFT_ADAPTATION_LAST_HEADER
;
1697 case LFT_ICAP_REQ_HEADER_ELEM
:
1698 type
= LFT_ICAP_REQ_HEADER
;
1700 case LFT_ICAP_REP_HEADER_ELEM
:
1701 type
= LFT_ICAP_REP_HEADER
;
1710 case LFT_REQUEST_ALL_HEADERS
:
1711 case LFT_ADAPTED_REQUEST_ALL_HEADERS
:
1712 case LFT_REPLY_ALL_HEADERS
:
1715 case LFT_ADAPTATION_LAST_ALL_HEADERS
:
1718 case LFT_ICAP_REQ_ALL_HEADERS
:
1719 case LFT_ICAP_REP_ALL_HEADERS
:
1723 case LFT_REQUEST_ALL_HEADERS
:
1724 type
= LFT_REQUEST_HEADER
;
1726 case LFT_ADAPTED_REQUEST_ALL_HEADERS
:
1727 type
= LFT_ADAPTED_REQUEST_HEADER
;
1729 case LFT_REPLY_ALL_HEADERS
:
1730 type
= LFT_REPLY_HEADER
;
1733 case LFT_ADAPTATION_LAST_ALL_HEADERS
:
1734 type
= LFT_ADAPTATION_LAST_HEADER
;
1738 case LFT_ICAP_REQ_ALL_HEADERS
:
1739 type
= LFT_ICAP_REQ_HEADER
;
1741 case LFT_ICAP_REP_ALL_HEADERS
:
1742 type
= LFT_ICAP_REP_HEADER
;
1753 arg
= t
->data
.string
;
1758 entry
->append("%", 1);
1762 case LOG_QUOTE_QUOTES
:
1763 entry
->append("\"", 1);
1766 case LOG_QUOTE_BRAKETS
:
1767 entry
->append("[", 1);
1771 entry
->append("#", 1);
1775 entry
->append("'", 1);
1778 case LOG_QUOTE_NONE
:
1783 entry
->append("-", 1);
1786 entry
->append("0", 1);
1789 storeAppendPrintf(entry
, "%d", (int) t
->width
);
1792 storeAppendPrintf(entry
, ".%d", (int) t
->precision
);
1795 storeAppendPrintf(entry
, "{%s}", arg
);
1797 for (te
= logformat_token_table
; te
->config
!= NULL
; te
++) {
1798 if (te
->token_type
== type
) {
1799 storeAppendPrintf(entry
, "%s", te
->config
);
1805 entry
->append(" ", 1);
1807 assert(te
->config
!= NULL
);
1811 entry
->append("\n", 1);
1817 accessLogFreeLogFormat(logformat_token
** tokens
)
1820 logformat_token
*token
= *tokens
;
1821 *tokens
= token
->next
;
1822 safe_free(token
->data
.string
);
1828 accessLogSquid(AccessLogEntry
* al
, Logfile
* logfile
)
1830 const char *client
= NULL
;
1831 const char *user
= NULL
;
1832 char buf
[MAX_IPSTRLEN
];
1834 if (Config
.onoff
.log_fqdn
) {
1835 client
= fqdncache_gethostbyaddr(al
->cache
.caddr
, FQDN_LOOKUP_IF_MISS
);
1838 if (client
== NULL
) {
1839 client
= al
->cache
.caddr
.NtoA(buf
,MAX_IPSTRLEN
);
1842 user
= accessLogFormatName(al
->cache
.authuser
);
1845 user
= accessLogFormatName(al
->cache
.extuser
);
1850 user
= accessLogFormatName(al
->cache
.ssluser
);
1855 user
= accessLogFormatName(al
->cache
.rfc931
);
1860 if (!Config
.onoff
.log_mime_hdrs
) {
1861 logfilePrintf(logfile
, "%9ld.%03d %6d %s %s%s/%03d %"PRId64
" %s %s %s %s%s/%s %s\n",
1862 (long int) current_time
.tv_sec
,
1863 (int) current_time
.tv_usec
/ 1000,
1866 log_tags
[al
->cache
.code
],
1867 al
->http
.statusSfx(),
1869 al
->cache
.replySize
,
1870 al
->_private
.method_str
,
1872 user
? user
: dash_str
,
1873 al
->hier
.ping
.timedout
? "TIMEOUT_" : "",
1874 hier_code_str
[al
->hier
.code
],
1876 al
->http
.content_type
);
1878 char *ereq
= log_quote(al
->headers
.request
);
1879 char *erep
= log_quote(al
->headers
.reply
);
1880 logfilePrintf(logfile
, "%9ld.%03d %6d %s %s%s/%03d %"PRId64
" %s %s %s %s%s/%s %s [%s] [%s]\n",
1881 (long int) current_time
.tv_sec
,
1882 (int) current_time
.tv_usec
/ 1000,
1885 log_tags
[al
->cache
.code
],
1886 al
->http
.statusSfx(),
1888 al
->cache
.replySize
,
1889 al
->_private
.method_str
,
1891 user
? user
: dash_str
,
1892 al
->hier
.ping
.timedout
? "TIMEOUT_" : "",
1893 hier_code_str
[al
->hier
.code
],
1895 al
->http
.content_type
,
1905 accessLogCommon(AccessLogEntry
* al
, Logfile
* logfile
)
1907 const char *client
= NULL
;
1908 char *user1
= NULL
, *user2
= NULL
;
1909 char buf
[MAX_IPSTRLEN
];
1911 if (Config
.onoff
.log_fqdn
) {
1912 client
= fqdncache_gethostbyaddr(al
->cache
.caddr
, 0);
1915 if (client
== NULL
) {
1916 client
= al
->cache
.caddr
.NtoA(buf
,MAX_IPSTRLEN
);
1919 user1
= accessLogFormatName(al
->cache
.authuser
);
1921 user2
= accessLogFormatName(al
->cache
.rfc931
);
1923 logfilePrintf(logfile
, "%s %s %s [%s] \"%s %s HTTP/%d.%d\" %d %"PRId64
" %s%s:%s%s",
1925 user2
? user2
: dash_str
,
1926 user1
? user1
: dash_str
,
1927 mkhttpdlogtime(&squid_curtime
),
1928 al
->_private
.method_str
,
1930 al
->http
.version
.major
, al
->http
.version
.minor
,
1932 al
->cache
.replySize
,
1933 log_tags
[al
->cache
.code
],
1934 al
->http
.statusSfx(),
1935 hier_code_str
[al
->hier
.code
],
1936 (Config
.onoff
.log_mime_hdrs
?"":"\n"));
1942 if (Config
.onoff
.log_mime_hdrs
) {
1943 char *ereq
= log_quote(al
->headers
.request
);
1944 char *erep
= log_quote(al
->headers
.reply
);
1945 logfilePrintf(logfile
, " [%s] [%s]\n", ereq
, erep
);
1953 accessLogICAPSquid(AccessLogEntry
* al
, Logfile
* logfile
)
1955 const char *client
= NULL
;
1956 const char *user
= NULL
;
1957 char tmp
[MAX_IPSTRLEN
], clientbuf
[MAX_IPSTRLEN
];
1959 if (al
->cache
.caddr
.IsAnyAddr()) { // ICAP OPTIONS xactions lack client
1962 if (Config
.onoff
.log_fqdn
)
1963 client
= fqdncache_gethostbyaddr(al
->cache
.caddr
, FQDN_LOOKUP_IF_MISS
);
1965 client
= al
->cache
.caddr
.NtoA(clientbuf
, MAX_IPSTRLEN
);
1968 user
= accessLogFormatName(al
->cache
.authuser
);
1971 user
= accessLogFormatName(al
->cache
.extuser
);
1976 user
= accessLogFormatName(al
->cache
.ssluser
);
1981 user
= accessLogFormatName(al
->cache
.rfc931
);
1986 logfilePrintf(logfile
, "%9ld.%03d %6d %s -/%03d %"PRId64
" %s %s %s -/%s -\n",
1987 (long int) current_time
.tv_sec
,
1988 (int) current_time
.tv_usec
/ 1000,
1995 Adaptation::Icap::ICAP::methodStr(al
->icap
.reqMethod
),
1996 al
->icap
.reqUri
.termedBuf(),
1997 user
? user
: dash_str
,
1998 al
->icap
.hostAddr
.NtoA(tmp
, MAX_IPSTRLEN
));
2004 accessLogLogTo(customlog
* log
, AccessLogEntry
* al
, ACLChecklist
* checklist
)
2007 if (al
->url
== NULL
)
2010 if (!al
->http
.content_type
|| *al
->http
.content_type
== '\0')
2011 al
->http
.content_type
= dash_str
;
2014 al
->_private
.method_str
= icp_opcode_str
[al
->icp
.opcode
];
2015 else if (al
->htcp
.opcode
)
2016 al
->_private
.method_str
= al
->htcp
.opcode
;
2018 al
->_private
.method_str
= RequestMethodStr(al
->http
.method
);
2020 if (al
->hier
.host
[0] == '\0')
2021 xstrncpy(al
->hier
.host
, dash_str
, SQUIDHOSTNAMELEN
);
2023 for (; log
; log
= log
->next
) {
2024 if (checklist
&& log
->aclList
&& !checklist
->matchAclListFast(log
->aclList
))
2028 logfileLineStart(log
->logfile
);
2030 switch (log
->type
) {
2033 if (Config
.onoff
.common_log
)
2034 accessLogCommon(al
, log
->logfile
);
2036 accessLogSquid(al
, log
->logfile
);
2040 accessLogSquid(al
, log
->logfile
);
2044 accessLogCommon(al
, log
->logfile
);
2048 accessLogCustom(al
, log
);
2052 case CLF_ICAP_SQUID
:
2053 accessLogICAPSquid(al
, log
->logfile
);
2061 fatalf("Unknown log format %d\n", log
->type
);
2065 logfileLineEnd(log
->logfile
);
2068 // NP: WTF? if _any_ log line has no checklist ignore the following ones?
2075 accessLogLog(AccessLogEntry
* al
, ACLChecklist
* checklist
)
2077 if (LogfileStatus
!= LOG_ENABLE
)
2080 accessLogLogTo(Config
.Log
.accesslogs
, al
, checklist
);
2081 #if MULTICAST_MISS_STREAM
2083 if (al
->cache
.code
!= LOG_TCP_MISS
)
2085 else if (al
->http
.method
!= METHOD_GET
)
2087 else if (mcast_miss_fd
< 0)
2090 unsigned int ibuf
[365];
2092 xstrncpy((char *) ibuf
, al
->url
, 364 * sizeof(int));
2093 isize
= ((strlen(al
->url
) + 8) / 8) * 2;
2098 mcast_encode((unsigned int *) ibuf
, isize
,
2099 (const unsigned int *) Config
.mcast_miss
.encode_key
);
2101 comm_udp_sendto(mcast_miss_fd
,
2102 &mcast_miss_to
, sizeof(mcast_miss_to
),
2103 ibuf
, isize
* sizeof(int));
2110 accessLogRotate(void)
2118 for (log
= Config
.Log
.accesslogs
; log
; log
= log
->next
) {
2120 logfileRotate(log
->logfile
);
2126 logfileRotate(headerslog
);
2132 accessLogClose(void)
2136 for (log
= Config
.Log
.accesslogs
; log
; log
= log
->next
) {
2138 logfileClose(log
->logfile
);
2139 log
->logfile
= NULL
;
2145 logfileClose(headerslog
);
2152 HierarchyLogEntry::HierarchyLogEntry() :
2154 cd_lookup(LOOKUP_NONE
),
2157 peer_reply_status(HTTP_STATUS_NONE
),
2158 peer_response_time(-1),
2159 total_response_time(-1),
2163 memset(host
, '\0', SQUIDHOSTNAMELEN
);
2164 memset(cd_host
, '\0', SQUIDHOSTNAMELEN
);
2166 peer_select_start
.tv_sec
=0;
2167 peer_select_start
.tv_usec
=0;
2169 store_complete_stop
.tv_sec
=0;
2170 store_complete_stop
.tv_usec
=0;
2172 peer_http_request_sent
.tv_sec
= 0;
2173 peer_http_request_sent
.tv_usec
= 0;
2175 first_conn_start
.tv_sec
= 0;
2176 first_conn_start
.tv_usec
= 0;
2180 hierarchyNote(HierarchyLogEntry
* hl
,
2182 const char *cache_peer
)
2186 xstrncpy(hl
->host
, cache_peer
, SQUIDHOSTNAMELEN
);
2190 accessLogRegisterWithCacheManager(void)
2193 fvdbRegisterWithCacheManager();
2202 accessLogRegisterWithCacheManager();
2204 assert(sizeof(log_tags
) == (LOG_TYPE_MAX
+ 1) * sizeof(char *));
2207 alLogformatHasAdaptToken
= false;
2210 alLogformatHasIcapToken
= false;
2213 for (log
= Config
.Log
.accesslogs
; log
; log
= log
->next
) {
2214 if (log
->type
== CLF_NONE
)
2217 log
->logfile
= logfileOpen(log
->filename
, MAX_URL
<< 2, 1);
2219 LogfileStatus
= LOG_ENABLE
;
2222 for (logformat_token
* curr_token
= (log
->logFormat
?log
->logFormat
->format
:NULL
); curr_token
; curr_token
= curr_token
->next
) {
2223 if (curr_token
->type
== LTF_ADAPTATION_SUM_XACT_TIMES
||
2224 curr_token
->type
== LTF_ADAPTATION_ALL_XACT_TIMES
||
2225 curr_token
->type
== LFT_ADAPTATION_LAST_HEADER
||
2226 curr_token
->type
== LFT_ADAPTATION_LAST_HEADER_ELEM
||
2227 curr_token
->type
== LFT_ADAPTATION_LAST_ALL_HEADERS
) {
2228 alLogformatHasAdaptToken
= true;
2231 if (curr_token
->type
== LFT_ICAP_TOTAL_TIME
) {
2232 alLogformatHasIcapToken
= true;
2241 headerslog
= logfileOpen("/usr/local/squid/logs/headers.log", 512);
2243 assert(NULL
!= headerslog
);
2246 #if MULTICAST_MISS_STREAM
2248 if (Config
.mcast_miss
.addr
.s_addr
!= no_addr
.s_addr
) {
2249 memset(&mcast_miss_to
, '\0', sizeof(mcast_miss_to
));
2250 mcast_miss_to
.sin_family
= AF_INET
;
2251 mcast_miss_to
.sin_port
= htons(Config
.mcast_miss
.port
);
2252 mcast_miss_to
.sin_addr
.s_addr
= Config
.mcast_miss
.addr
.s_addr
;
2253 mcast_miss_fd
= comm_open(SOCK_DGRAM
,
2255 Config
.Addrs
.udp_incoming
,
2256 Config
.mcast_miss
.port
,
2258 "Multicast Miss Stream");
2260 if (mcast_miss_fd
< 0)
2261 fatal("Cannot open Multicast Miss Stream Socket");
2263 debugs(46, 1, "Multicast Miss Stream Socket opened on FD " << mcast_miss_fd
);
2265 mcastSetTtl(mcast_miss_fd
, Config
.mcast_miss
.ttl
);
2267 if (strlen(Config
.mcast_miss
.encode_key
) < 16)
2268 fatal("mcast_encode_key is too short, must be 16 characters");
2280 accessLogTime(time_t t
)
2284 static char buf
[128];
2285 static time_t last_t
= 0;
2289 strftime(buf
, 127, "%Y/%m/%d %H:%M:%S", tm
);
2302 via_table
= hash_create((HASHCMP
*) strcmp
, 977, hash4
);
2303 forw_table
= hash_create((HASHCMP
*) strcmp
, 977, hash4
);
2307 fvdbRegisterWithCacheManager(void)
2309 Mgr::RegisterAction("via_headers", "Via Request Headers", fvdbDumpVia
, 0, 1);
2310 Mgr::RegisterAction("forw_headers", "X-Forwarded-For Request Headers",
2311 fvdbDumpForw
, 0, 1);
2315 fvdbCount(hash_table
* hash
, const char *key
)
2322 fv
= (fvdb_entry
*)hash_lookup(hash
, key
);
2325 fv
= static_cast <fvdb_entry
*>(xcalloc(1, sizeof(fvdb_entry
)));
2326 fv
->hash
.key
= xstrdup(key
);
2327 hash_join(hash
, &fv
->hash
);
2334 fvdbCountVia(const char *key
)
2336 fvdbCount(via_table
, key
);
2340 fvdbCountForw(const char *key
)
2342 fvdbCount(forw_table
, key
);
2346 fvdbDumpTable(StoreEntry
* e
, hash_table
* hash
)
2356 while ((h
= hash_next(hash
))) {
2357 fv
= (fvdb_entry
*) h
;
2358 storeAppendPrintf(e
, "%9d %s\n", fv
->n
, hashKeyStr(&fv
->hash
));
2363 fvdbDumpVia(StoreEntry
* e
)
2365 fvdbDumpTable(e
, via_table
);
2369 fvdbDumpForw(StoreEntry
* e
)
2371 fvdbDumpTable(e
, forw_table
);
2376 fvdbFreeEntry(void *data
)
2378 fvdb_entry
*fv
= static_cast <fvdb_entry
*>(data
);
2379 xfree(fv
->hash
.key
);
2386 hashFreeItems(via_table
, fvdbFreeEntry
);
2387 hashFreeMemory(via_table
);
2388 via_table
= hash_create((HASHCMP
*) strcmp
, 977, hash4
);
2389 hashFreeItems(forw_table
, fvdbFreeEntry
);
2390 hashFreeMemory(forw_table
);
2391 forw_table
= hash_create((HASHCMP
*) strcmp
, 977, hash4
);
2396 #if MULTICAST_MISS_STREAM
2398 * From http://www.io.com/~paulhart/game/algorithms/tea.html
2400 * size of 'ibuf' must be a multiple of 2.
2401 * size of 'key' must be 4.
2402 * 'ibuf' is modified in place, encrypted data is written in
2403 * network byte order.
2406 mcast_encode(unsigned int *ibuf
, size_t isize
, const unsigned int *key
)
2411 const unsigned int delta
= 0x9e3779b9;
2412 unsigned int n
= 32;
2413 const unsigned int k0
= htonl(key
[0]);
2414 const unsigned int k1
= htonl(key
[1]);
2415 const unsigned int k2
= htonl(key
[2]);
2416 const unsigned int k3
= htonl(key
[3]);
2419 for (i
= 0; i
< isize
; i
+= 2) {
2421 z
= htonl(ibuf
[i
+ 1]);
2424 for (n
= 32; n
; n
--) {
2426 y
+= (z
<< 4) + (k0
^ z
) + (sum
^ (z
>> 5)) + k1
;
2427 z
+= (y
<< 4) + (k2
^ y
) + (sum
^ (y
>> 5)) + k3
;
2431 ibuf
[i
+ 1] = htonl(z
);
2439 headersLog(int cs
, int pq
, const HttpRequestMethod
& method
, void *data
)
2443 unsigned short magic
= 0;
2444 unsigned char M
= (unsigned char) m
;
2454 hmask
= rep
->header
.mask
;
2456 if (rep
->cache_control
)
2457 ccmask
= rep
->cache_control
->mask
;
2463 hmask
= req
->header
.mask
;
2465 if (req
->cache_control
)
2466 ccmask
= req
->cache_control
->mask
;
2477 magic
= htons(magic
);
2478 ccmask
= htonl(ccmask
);
2481 S
= (unsigned short) rep
->sline
.status
;
2483 S
= (unsigned short) HTTP_STATUS_NONE
;
2485 logfileWrite(headerslog
, &magic
, sizeof(magic
));
2486 logfileWrite(headerslog
, &M
, sizeof(M
));
2487 logfileWrite(headerslog
, &S
, sizeof(S
));
2488 logfileWrite(headerslog
, hmask
, sizeof(HttpHeaderMask
));
2489 logfileWrite(headerslog
, &ccmask
, sizeof(int));
2495 accessLogFreeMemory(AccessLogEntry
* aLogEntry
)
2497 safe_free(aLogEntry
->headers
.request
);
2500 safe_free(aLogEntry
->headers
.adapt_last
);
2503 safe_free(aLogEntry
->headers
.reply
);
2504 safe_free(aLogEntry
->cache
.authuser
);
2506 safe_free(aLogEntry
->headers
.adapted_request
);
2507 HTTPMSGUNLOCK(aLogEntry
->adapted_request
);
2509 HTTPMSGUNLOCK(aLogEntry
->reply
);
2510 HTTPMSGUNLOCK(aLogEntry
->request
);
2512 HTTPMSGUNLOCK(aLogEntry
->icap
.reply
);
2513 HTTPMSGUNLOCK(aLogEntry
->icap
.request
);
2518 logTypeIsATcpHit(log_type code
)
2520 /* this should be a bitmap for better optimization */
2522 if (code
== LOG_TCP_HIT
)
2525 if (code
== LOG_TCP_IMS_HIT
)
2528 if (code
== LOG_TCP_REFRESH_FAIL_OLD
)
2531 if (code
== LOG_TCP_REFRESH_UNMODIFIED
)
2534 if (code
== LOG_TCP_NEGATIVE_HIT
)
2537 if (code
== LOG_TCP_MEM_HIT
)
2540 if (code
== LOG_TCP_OFFLINE_HIT
)