2 * DEBUG: section 46 Access Log
3 * AUTHOR: Duane Wessels
5 * SQUID Web Proxy Cache http://www.squid-cache.org/
6 * ----------------------------------------------------------
8 * Squid is the result of efforts by numerous individuals from
9 * the Internet community; see the CONTRIBUTORS file for full
10 * details. Many organizations have provided support for Squid's
11 * development; see the SPONSORS file for full details. Squid is
12 * Copyrighted (C) 2001 by the Regents of the University of
13 * California; see the COPYRIGHT file for full details. Squid
14 * incorporates software developed and/or copyrighted by other
15 * sources; see the CREDITS file for full details.
17 * This program is free software; you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by
19 * the Free Software Foundation; either version 2 of the License, or
20 * (at your option) any later version.
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
27 * You should have received a copy of the GNU General Public License
28 * along with this program; if not, write to the Free Software
29 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
34 #include "AccessLogEntry.h"
35 #include "acl/Checklist.h"
36 #include "CachePeer.h"
37 #include "err_detail_type.h"
38 #include "errorpage.h"
39 #include "errorpage.h"
40 #include "format/Token.h"
42 #include "hier_code.h"
43 #include "HttpReply.h"
44 #include "HttpRequest.h"
45 #include "log/access_log.h"
46 #include "log/Config.h"
48 #include "log/Formats.h"
50 #include "mgr/Registration.h"
52 #include "SquidConfig.h"
53 #include "SquidTime.h"
57 #include "eui/Eui48.h"
58 #include "eui/Eui64.h"
62 static Logfile
*headerslog
= NULL
;
65 #if MULTICAST_MISS_STREAM
66 static int mcast_miss_fd
= -1;
68 static struct sockaddr_in mcast_miss_to
;
69 static void mcast_encode(unsigned int *, size_t, const unsigned int *);
78 static hash_table
*via_table
= NULL
;
79 static hash_table
*forw_table
= NULL
;
80 static void fvdbInit();
81 static void fvdbDumpTable(StoreEntry
* e
, hash_table
* hash
);
82 static void fvdbCount(hash_table
* hash
, const char *key
);
83 static OBJH fvdbDumpVia
;
84 static OBJH fvdbDumpForw
;
85 static FREE fvdbFreeEntry
;
86 static void fvdbClear(void);
87 static void fvdbRegisterWithCacheManager();
90 int LogfileStatus
= LOG_DISABLE
;
93 accessLogLogTo(CustomLog
* log
, AccessLogEntry::Pointer
&al
, ACLChecklist
* checklist
)
99 if (!al
->http
.content_type
|| *al
->http
.content_type
== '\0')
100 al
->http
.content_type
= dash_str
;
103 al
->_private
.method_str
= icp_opcode_str
[al
->icp
.opcode
];
104 else if (al
->htcp
.opcode
)
105 al
->_private
.method_str
= al
->htcp
.opcode
;
107 al
->_private
.method_str
= RequestMethodStr(al
->http
.method
);
109 if (al
->hier
.host
[0] == '\0')
110 xstrncpy(al
->hier
.host
, dash_str
, SQUIDHOSTNAMELEN
);
112 for (; log
; log
= log
->next
) {
113 if (log
->aclList
&& checklist
&& checklist
->fastCheck(log
->aclList
) != ACCESS_ALLOWED
)
117 logfileLineStart(log
->logfile
);
121 case Log::Format::CLF_SQUID
:
122 Log::Format::SquidNative(al
, log
->logfile
);
125 case Log::Format::CLF_COMBINED
:
126 Log::Format::HttpdCombined(al
, log
->logfile
);
129 case Log::Format::CLF_COMMON
:
130 Log::Format::HttpdCommon(al
, log
->logfile
);
133 case Log::Format::CLF_REFERER
:
134 Log::Format::SquidReferer(al
, log
->logfile
);
137 case Log::Format::CLF_USERAGENT
:
138 Log::Format::SquidUserAgent(al
, log
->logfile
);
141 case Log::Format::CLF_CUSTOM
:
142 Log::Format::SquidCustom(al
, log
);
146 case Log::Format::CLF_ICAP_SQUID
:
147 Log::Format::SquidIcap(al
, log
->logfile
);
151 case Log::Format::CLF_NONE
:
155 fatalf("Unknown log format %d\n", log
->type
);
159 logfileLineEnd(log
->logfile
);
162 // NP: WTF? if _any_ log line has no checklist ignore the following ones?
169 accessLogLog(AccessLogEntry::Pointer
&al
, ACLChecklist
* checklist
)
171 if (LogfileStatus
!= LOG_ENABLE
)
174 accessLogLogTo(Config
.Log
.accesslogs
, al
, checklist
);
175 #if MULTICAST_MISS_STREAM
177 if (al
->cache
.code
!= LOG_TCP_MISS
)
179 else if (al
->http
.method
!= METHOD_GET
)
181 else if (mcast_miss_fd
< 0)
184 unsigned int ibuf
[365];
186 xstrncpy((char *) ibuf
, al
->url
, 364 * sizeof(int));
187 isize
= ((strlen(al
->url
) + 8) / 8) * 2;
192 mcast_encode((unsigned int *) ibuf
, isize
,
193 (const unsigned int *) Config
.mcast_miss
.encode_key
);
195 comm_udp_sendto(mcast_miss_fd
,
196 &mcast_miss_to
, sizeof(mcast_miss_to
),
197 ibuf
, isize
* sizeof(int));
204 accessLogRotate(void)
212 for (log
= Config
.Log
.accesslogs
; log
; log
= log
->next
) {
214 logfileRotate(log
->logfile
);
220 logfileRotate(headerslog
);
230 for (log
= Config
.Log
.accesslogs
; log
; log
= log
->next
) {
232 logfileClose(log
->logfile
);
239 logfileClose(headerslog
);
246 HierarchyLogEntry::HierarchyLogEntry() :
248 cd_lookup(LOOKUP_NONE
),
251 peer_reply_status(HTTP_STATUS_NONE
),
252 peer_response_time(-1),
253 total_response_time(-1),
257 memset(host
, '\0', SQUIDHOSTNAMELEN
);
258 memset(cd_host
, '\0', SQUIDHOSTNAMELEN
);
260 peer_select_start
.tv_sec
=0;
261 peer_select_start
.tv_usec
=0;
263 store_complete_stop
.tv_sec
=0;
264 store_complete_stop
.tv_usec
=0;
266 peer_http_request_sent
.tv_sec
= 0;
267 peer_http_request_sent
.tv_usec
= 0;
269 first_conn_start
.tv_sec
= 0;
270 first_conn_start
.tv_usec
= 0;
274 HierarchyLogEntry::note(const Comm::ConnectionPointer
&server
, const char *requestedHost
)
277 if (tcpServer
== NULL
) {
279 xstrncpy(host
, requestedHost
, sizeof(host
));
281 code
= tcpServer
->peerType
;
283 if (tcpServer
->getPeer()) {
284 // went to peer, log peer host name
285 xstrncpy(host
, tcpServer
->getPeer()->name
, sizeof(host
));
287 xstrncpy(host
, requestedHost
, sizeof(host
));
293 accessLogRegisterWithCacheManager(void)
296 fvdbRegisterWithCacheManager();
305 accessLogRegisterWithCacheManager();
308 Log::TheConfig
.hasAdaptToken
= false;
311 Log::TheConfig
.hasIcapToken
= false;
314 for (log
= Config
.Log
.accesslogs
; log
; log
= log
->next
) {
315 if (log
->type
== Log::Format::CLF_NONE
)
318 log
->logfile
= logfileOpen(log
->filename
, MAX_URL
<< 2, 1);
320 LogfileStatus
= LOG_ENABLE
;
323 for (Format::Token
* curr_token
= (log
->logFormat
?log
->logFormat
->format
:NULL
); curr_token
; curr_token
= curr_token
->next
) {
324 if (curr_token
->type
== Format::LFT_ADAPTATION_SUM_XACT_TIMES
||
325 curr_token
->type
== Format::LFT_ADAPTATION_ALL_XACT_TIMES
||
326 curr_token
->type
== Format::LFT_ADAPTATION_LAST_HEADER
||
327 curr_token
->type
== Format::LFT_ADAPTATION_LAST_HEADER_ELEM
||
328 curr_token
->type
== Format::LFT_ADAPTATION_LAST_ALL_HEADERS
) {
329 Log::TheConfig
.hasAdaptToken
= true;
332 if (curr_token
->type
== Format::LFT_ICAP_TOTAL_TIME
) {
333 Log::TheConfig
.hasIcapToken
= true;
342 headerslog
= logfileOpen("/usr/local/squid/logs/headers.log", 512);
344 assert(NULL
!= headerslog
);
347 #if MULTICAST_MISS_STREAM
349 if (Config
.mcast_miss
.addr
.s_addr
!= no_addr
.s_addr
) {
350 memset(&mcast_miss_to
, '\0', sizeof(mcast_miss_to
));
351 mcast_miss_to
.sin_family
= AF_INET
;
352 mcast_miss_to
.sin_port
= htons(Config
.mcast_miss
.port
);
353 mcast_miss_to
.sin_addr
.s_addr
= Config
.mcast_miss
.addr
.s_addr
;
354 mcast_miss_fd
= comm_open(SOCK_DGRAM
,
356 Config
.Addrs
.udp_incoming
,
357 Config
.mcast_miss
.port
,
359 "Multicast Miss Stream");
361 if (mcast_miss_fd
< 0)
362 fatal("Cannot open Multicast Miss Stream Socket");
364 debugs(46, DBG_IMPORTANT
, "Multicast Miss Stream Socket opened on FD " << mcast_miss_fd
);
366 mcastSetTtl(mcast_miss_fd
, Config
.mcast_miss
.ttl
);
368 if (strlen(Config
.mcast_miss
.encode_key
) < 16)
369 fatal("mcast_encode_key is too short, must be 16 characters");
385 via_table
= hash_create((HASHCMP
*) strcmp
, 977, hash4
);
386 forw_table
= hash_create((HASHCMP
*) strcmp
, 977, hash4
);
390 fvdbRegisterWithCacheManager(void)
392 Mgr::RegisterAction("via_headers", "Via Request Headers", fvdbDumpVia
, 0, 1);
393 Mgr::RegisterAction("forw_headers", "X-Forwarded-For Request Headers",
398 fvdbCount(hash_table
* hash
, const char *key
)
405 fv
= (fvdb_entry
*)hash_lookup(hash
, key
);
408 fv
= static_cast <fvdb_entry
*>(xcalloc(1, sizeof(fvdb_entry
)));
409 fv
->hash
.key
= xstrdup(key
);
410 hash_join(hash
, &fv
->hash
);
417 fvdbCountVia(const char *key
)
419 fvdbCount(via_table
, key
);
423 fvdbCountForw(const char *key
)
425 fvdbCount(forw_table
, key
);
429 fvdbDumpTable(StoreEntry
* e
, hash_table
* hash
)
439 while ((h
= hash_next(hash
))) {
440 fv
= (fvdb_entry
*) h
;
441 storeAppendPrintf(e
, "%9d %s\n", fv
->n
, hashKeyStr(&fv
->hash
));
446 fvdbDumpVia(StoreEntry
* e
)
448 fvdbDumpTable(e
, via_table
);
452 fvdbDumpForw(StoreEntry
* e
)
454 fvdbDumpTable(e
, forw_table
);
459 fvdbFreeEntry(void *data
)
461 fvdb_entry
*fv
= static_cast <fvdb_entry
*>(data
);
469 hashFreeItems(via_table
, fvdbFreeEntry
);
470 hashFreeMemory(via_table
);
471 via_table
= hash_create((HASHCMP
*) strcmp
, 977, hash4
);
472 hashFreeItems(forw_table
, fvdbFreeEntry
);
473 hashFreeMemory(forw_table
);
474 forw_table
= hash_create((HASHCMP
*) strcmp
, 977, hash4
);
479 #if MULTICAST_MISS_STREAM
481 * From http://www.io.com/~paulhart/game/algorithms/tea.html
483 * size of 'ibuf' must be a multiple of 2.
484 * size of 'key' must be 4.
485 * 'ibuf' is modified in place, encrypted data is written in
486 * network byte order.
489 mcast_encode(unsigned int *ibuf
, size_t isize
, const unsigned int *key
)
494 const unsigned int delta
= 0x9e3779b9;
496 const unsigned int k0
= htonl(key
[0]);
497 const unsigned int k1
= htonl(key
[1]);
498 const unsigned int k2
= htonl(key
[2]);
499 const unsigned int k3
= htonl(key
[3]);
502 for (i
= 0; i
< isize
; i
+= 2) {
504 z
= htonl(ibuf
[i
+ 1]);
507 for (n
= 32; n
; --n
) {
509 y
+= (z
<< 4) + (k0
^ z
) + (sum
^ (z
>> 5)) + k1
;
510 z
+= (y
<< 4) + (k2
^ y
) + (sum
^ (y
>> 5)) + k3
;
514 ibuf
[i
+ 1] = htonl(z
);
522 headersLog(int cs
, int pq
, const HttpRequestMethod
& method
, void *data
)
526 unsigned short magic
= 0;
527 unsigned char M
= (unsigned char) m
;
537 hmask
= rep
->header
.mask
;
539 if (rep
->cache_control
)
540 ccmask
= rep
->cache_control
->mask
;
546 hmask
= req
->header
.mask
;
548 if (req
->cache_control
)
549 ccmask
= req
->cache_control
->mask
;
560 magic
= htons(magic
);
561 ccmask
= htonl(ccmask
);
564 S
= (unsigned short) rep
->sline
.status
;
566 S
= (unsigned short) HTTP_STATUS_NONE
;
568 logfileWrite(headerslog
, &magic
, sizeof(magic
));
569 logfileWrite(headerslog
, &M
, sizeof(M
));
570 logfileWrite(headerslog
, &S
, sizeof(S
));
571 logfileWrite(headerslog
, hmask
, sizeof(HttpHeaderMask
));
572 logfileWrite(headerslog
, &ccmask
, sizeof(int));
578 logTypeIsATcpHit(log_type code
)
580 /* this should be a bitmap for better optimization */
582 if (code
== LOG_TCP_HIT
)
585 if (code
== LOG_TCP_IMS_HIT
)
588 if (code
== LOG_TCP_REFRESH_FAIL_OLD
)
591 if (code
== LOG_TCP_REFRESH_UNMODIFIED
)
594 if (code
== LOG_TCP_NEGATIVE_HIT
)
597 if (code
== LOG_TCP_MEM_HIT
)
600 if (code
== LOG_TCP_OFFLINE_HIT
)