]> git.ipfire.org Git - thirdparty/squid.git/blame - src/stat.cc
fix commented in USE_ICMP
[thirdparty/squid.git] / src / stat.cc
CommitLineData
e5f6c5c2 1
30a4f2a8 2/*
f6c78bd2 3 * $Id: stat.cc,v 1.88 1996/10/15 18:06:25 wessels Exp $
30a4f2a8 4 *
5 * DEBUG: section 18 Cache Manager Statistics
6 * AUTHOR: Harvest Derived
7 *
8 * SQUID Internet Object Cache http://www.nlanr.net/Squid/
9 * --------------------------------------------------------
10 *
11 * Squid is the result of efforts by numerous individuals from the
12 * Internet community. Development is led by Duane Wessels of the
13 * National Laboratory for Applied Network Research and funded by
14 * the National Science Foundation.
15 *
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
20 *
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29 *
30 */
019dd986 31
32/*
30a4f2a8 33 * Copyright (c) 1994, 1995. All rights reserved.
34 *
35 * The Harvest software was developed by the Internet Research Task
36 * Force Research Group on Resource Discovery (IRTF-RD):
37 *
38 * Mic Bowman of Transarc Corporation.
39 * Peter Danzig of the University of Southern California.
40 * Darren R. Hardy of the University of Colorado at Boulder.
41 * Udi Manber of the University of Arizona.
42 * Michael F. Schwartz of the University of Colorado at Boulder.
43 * Duane Wessels of the University of Colorado at Boulder.
44 *
45 * This copyright notice applies to software in the Harvest
46 * ``src/'' directory only. Users should consult the individual
47 * copyright notices in the ``components/'' subdirectories for
48 * copyright information about other software bundled with the
49 * Harvest source code distribution.
50 *
51 * TERMS OF USE
52 *
53 * The Harvest software may be used and re-distributed without
54 * charge, provided that the software origin and research team are
55 * cited in any use of the system. Most commonly this is
56 * accomplished by including a link to the Harvest Home Page
57 * (http://harvest.cs.colorado.edu/) from the query page of any
58 * Broker you deploy, as well as in the query result pages. These
59 * links are generated automatically by the standard Broker
60 * software distribution.
61 *
62 * The Harvest software is provided ``as is'', without express or
63 * implied warranty, and with no support nor obligation to assist
64 * in its use, correction, modification or enhancement. We assume
65 * no liability with respect to the infringement of copyrights,
66 * trade secrets, or any patents, and are not responsible for
67 * consequential damages. Proper use of the Harvest software is
68 * entirely the responsibility of the user.
69 *
70 * DERIVATIVE WORKS
71 *
72 * Users may make derivative works from the Harvest software, subject
73 * to the following constraints:
74 *
75 * - You must include the above copyright notice and these
76 * accompanying paragraphs in all forms of derivative works,
77 * and any documentation and other materials related to such
78 * distribution and use acknowledge that the software was
79 * developed at the above institutions.
80 *
81 * - You must notify IRTF-RD regarding your distribution of
82 * the derivative work.
83 *
84 * - You must clearly notify users that your are distributing
85 * a modified version and not the original Harvest software.
86 *
87 * - Any derivative product is also subject to these copyright
88 * and use restrictions.
89 *
90 * Note that the Harvest software is NOT in the public domain. We
91 * retain copyright, as specified above.
92 *
93 * HISTORY OF FREE SOFTWARE STATUS
94 *
95 * Originally we required sites to license the software in cases
96 * where they were going to build commercial products/services
97 * around Harvest. In June 1995 we changed this policy. We now
98 * allow people to use the core Harvest software (the code found in
99 * the Harvest ``src/'' directory) for free. We made this change
100 * in the interest of encouraging the widest possible deployment of
101 * the technology. The Harvest software is really a reference
102 * implementation of a set of protocols and formats, some of which
103 * we intend to standardize. We encourage commercial
104 * re-implementations of code complying to this set of standards.
019dd986 105 */
ed43818f 106
234967c9 107
44a47c6e 108#include "squid.h"
090089c4 109
090089c4 110#define MAX_LINELEN (4096)
111#define max(a,b) ((a)>(b)? (a): (b))
112
113typedef struct _log_read_data_t {
114 StoreEntry *sentry;
115} log_read_data_t;
116
b8de7ebe 117typedef struct _squid_read_data_t {
090089c4 118 StoreEntry *sentry;
119 int fd;
b8de7ebe 120} squid_read_data_t;
090089c4 121
122/* GLOBALS */
123Meta_data meta_data;
86ee2017 124volatile unsigned long ntcpconn = 0;
125volatile unsigned long nudpconn = 0;
30a4f2a8 126struct _iostats IOStats;
30a4f2a8 127char *open_bracket = "{\n";
128char *close_bracket = "}\n";
a528eb87 129
67508012 130extern char *diskFileName _PARAMS((int));
131
132/* LOCALS */
133static char *stat_describe _PARAMS((StoreEntry * entry));
134static char *mem_describe _PARAMS((StoreEntry * entry));
135static char *ttl_describe _PARAMS((StoreEntry * entry));
136static char *flags_describe _PARAMS((StoreEntry * entry));
137static char *elapsed_time _PARAMS((StoreEntry * entry, int since, char *TTL));
138static void dummyhandler _PARAMS((cacheinfo *, StoreEntry *));
139static void info_get _PARAMS((cacheinfo *, StoreEntry *));
140static void logReadEndHandler _PARAMS((int, int, log_read_data_t *));
141static void log_clear _PARAMS((cacheinfo *, StoreEntry *));
142static void log_disable _PARAMS((cacheinfo *, StoreEntry *));
143static void log_enable _PARAMS((cacheinfo *, StoreEntry *));
144static void log_get_start _PARAMS((cacheinfo *, StoreEntry *));
145static void log_status_get _PARAMS((cacheinfo *, StoreEntry *));
146static void parameter_get _PARAMS((cacheinfo *, StoreEntry *));
147static void proto_count _PARAMS((cacheinfo *, protocol_t, log_type));
148static void proto_newobject _PARAMS((cacheinfo *, protocol_t, int, int));
149static void proto_purgeobject _PARAMS((cacheinfo *, protocol_t, int));
150static void proto_touchobject _PARAMS((cacheinfo *, protocol_t, int));
151static void server_list _PARAMS((cacheinfo *, StoreEntry *));
152static void squidReadEndHandler _PARAMS((int, int, squid_read_data_t *));
153static void squid_get_start _PARAMS((cacheinfo *, StoreEntry *));
154static void statFiledescriptors _PARAMS((StoreEntry *));
155static void stat_get _PARAMS((cacheinfo *, char *req, StoreEntry *));
156static void stat_io_get _PARAMS((StoreEntry *));
157static void stat_objects_get _PARAMS((cacheinfo *, StoreEntry *, int vm_or_not));
158static void stat_utilization_get _PARAMS((cacheinfo *, StoreEntry *, char *desc));
159static int cache_size_get _PARAMS((cacheinfo *));
160static int logReadHandler _PARAMS((int, char *, int, log_read_data_t *));
161static int squidReadHandler _PARAMS((int, char *, int, squid_read_data_t *));
162static int memoryAccounted _PARAMS((void));
20882fb1 163
164#ifdef UNUSED_CODE
67508012 165static int mallinfoTotal _PARAMS((void));
20882fb1 166#endif
167
168#ifdef XMALLOC_STATISTICS
67508012 169static void info_get_mallstat _PARAMS((int, int, StoreEntry *));
20882fb1 170#endif
30a4f2a8 171
090089c4 172/* process utilization information */
b8d8561b 173static void
174stat_utilization_get(cacheinfo * obj, StoreEntry * sentry, char *desc)
090089c4 175{
8213067d 176 protocol_t proto_id;
177 proto_stat *p = &obj->proto_stat_data[PROTO_MAX];
090089c4 178 proto_stat *q = NULL;
179 int secs = 0;
180
b8de7ebe 181 secs = (int) (squid_curtime - squid_starttime);
a528eb87 182 storeAppendPrintf(sentry, "{ %s\n", desc); /* } */
234967c9 183 strcpy(p->protoname, "TOTAL");
090089c4 184 p->object_count = 0;
185 p->kb.max = 0;
186 p->kb.min = 0;
187 p->kb.avg = 0;
188 p->kb.now = 0;
189 p->hit = 0;
190 p->miss = 0;
191 p->refcount = 0;
192 p->transferbyte = 0;
090089c4 193 /* find the total */
30a4f2a8 194 for (proto_id = PROTO_NONE; proto_id < PROTO_MAX; ++proto_id) {
090089c4 195 q = &obj->proto_stat_data[proto_id];
090089c4 196 p->object_count += q->object_count;
197 p->kb.max += q->kb.max;
198 p->kb.min += q->kb.min;
199 p->kb.avg += q->kb.avg;
200 p->kb.now += q->kb.now;
201 p->hit += q->hit;
202 p->miss += q->miss;
203 p->refcount += q->refcount;
204 p->transferbyte += q->transferbyte;
205 }
090089c4 206 /* dump it */
30a4f2a8 207 for (proto_id = PROTO_NONE; proto_id <= PROTO_MAX; ++proto_id) {
090089c4 208 p = &obj->proto_stat_data[proto_id];
209 if (p->hit != 0) {
210 p->hitratio =
211 (float) p->hit /
212 ((float) p->hit +
213 (float) p->miss);
214 }
30a4f2a8 215 storeAppendPrintf(sentry, "{%8.8s %d %d %d %d %4.2f %d %d %d}\n",
090089c4 216 p->protoname,
217 p->object_count,
218 p->kb.max,
219 p->kb.now,
220 p->kb.min,
221 p->hitratio,
222 (secs ? p->transferbyte / secs : 0),
223 p->refcount,
224 p->transferbyte);
090089c4 225 }
30a4f2a8 226 storeAppendPrintf(sentry, close_bracket);
227}
228
b8d8561b 229static void
230stat_io_get(StoreEntry * sentry)
30a4f2a8 231{
232 int i;
233
234 storeAppendPrintf(sentry, open_bracket);
235 storeAppendPrintf(sentry, "{HTTP I/O}\n");
236 storeAppendPrintf(sentry, "{number of reads: %d}\n", IOStats.Http.reads);
237 storeAppendPrintf(sentry, "{deferred reads: %d (%d%%)}\n",
238 IOStats.Http.reads_deferred,
239 percent(IOStats.Http.reads_deferred, IOStats.Http.reads));
240 storeAppendPrintf(sentry, "{Read Histogram:}\n");
241 for (i = 0; i < 16; i++) {
242 storeAppendPrintf(sentry, "{%5d-%5d: %9d %2d%%}\n",
243 i ? (1 << (i - 1)) + 1 : 1,
244 1 << i,
245 IOStats.Http.read_hist[i],
246 percent(IOStats.Http.read_hist[i], IOStats.Http.reads));
247 }
248
249 storeAppendPrintf(sentry, "{}\n");
250 storeAppendPrintf(sentry, "{FTP I/O}\n");
251 storeAppendPrintf(sentry, "{number of reads: %d}\n", IOStats.Ftp.reads);
252 storeAppendPrintf(sentry, "{deferred reads: %d (%d%%)}\n",
253 IOStats.Ftp.reads_deferred,
254 percent(IOStats.Ftp.reads_deferred, IOStats.Ftp.reads));
255 storeAppendPrintf(sentry, "{Read Histogram:}\n");
256 for (i = 0; i < 16; i++) {
257 storeAppendPrintf(sentry, "{%5d-%5d: %9d %2d%%}\n",
258 i ? (1 << (i - 1)) + 1 : 1,
259 1 << i,
260 IOStats.Ftp.read_hist[i],
261 percent(IOStats.Ftp.read_hist[i], IOStats.Ftp.reads));
262 }
263
56fa4cad 264 storeAppendPrintf(sentry, "{}\n");
265 storeAppendPrintf(sentry, "{Gopher I/O}\n");
266 storeAppendPrintf(sentry, "{number of reads: %d}\n", IOStats.Gopher.reads);
267 storeAppendPrintf(sentry, "{deferred reads: %d (%d%%)}\n",
268 IOStats.Gopher.reads_deferred,
269 percent(IOStats.Gopher.reads_deferred, IOStats.Gopher.reads));
270 storeAppendPrintf(sentry, "{Read Histogram:}\n");
271 for (i = 0; i < 16; i++) {
272 storeAppendPrintf(sentry, "{%5d-%5d: %9d %2d%%}\n",
273 i ? (1 << (i - 1)) + 1 : 1,
274 1 << i,
275 IOStats.Gopher.read_hist[i],
276 percent(IOStats.Gopher.read_hist[i], IOStats.Gopher.reads));
277 }
278
279 storeAppendPrintf(sentry, "{}\n");
280 storeAppendPrintf(sentry, "{WAIS I/O}\n");
281 storeAppendPrintf(sentry, "{number of reads: %d}\n", IOStats.Wais.reads);
282 storeAppendPrintf(sentry, "{deferred reads: %d (%d%%)}\n",
283 IOStats.Wais.reads_deferred,
284 percent(IOStats.Wais.reads_deferred, IOStats.Wais.reads));
285 storeAppendPrintf(sentry, "{Read Histogram:}\n");
286 for (i = 0; i < 16; i++) {
287 storeAppendPrintf(sentry, "{%5d-%5d: %9d %2d%%}\n",
288 i ? (1 << (i - 1)) + 1 : 1,
289 1 << i,
290 IOStats.Wais.read_hist[i],
291 percent(IOStats.Wais.read_hist[i], IOStats.Wais.reads));
292 }
293
30a4f2a8 294 storeAppendPrintf(sentry, close_bracket);
090089c4 295}
296
297
298/* return total bytes of all registered and known objects.
299 * may not reflect the retrieving object....
300 * something need to be done here to get more accurate cache size */
b8d8561b 301static int
302cache_size_get(cacheinfo * obj)
090089c4 303{
304 int size = 0;
8213067d 305 protocol_t proto_id;
090089c4 306 /* sum all size, exclude total */
30a4f2a8 307 for (proto_id = PROTO_NONE; proto_id < PROTO_MAX; proto_id++)
090089c4 308 size += obj->proto_stat_data[proto_id].kb.now;
8213067d 309 return size;
090089c4 310}
311
090089c4 312/* process objects list */
b8d8561b 313static void
314stat_objects_get(cacheinfo * obj, StoreEntry * sentry, int vm_or_not)
090089c4 315{
95d659f0 316 LOCAL_ARRAY(char, space, 40);
317 LOCAL_ARRAY(char, space2, 40);
090089c4 318 int npend = 0;
09610784 319 StoreEntry *entry = NULL;
090089c4 320 int N = 0;
321 int obj_size;
322
30a4f2a8 323 storeAppendPrintf(sentry, open_bracket);
090089c4 324
325 for (entry = storeGetFirst();
326 entry != NULL;
327 entry = storeGetNext()) {
328 if (vm_or_not && (entry->mem_status == NOT_IN_MEMORY) &&
329 (entry->swap_status == SWAP_OK))
330 continue;
331 if ((++N & 0xFF) == 0) {
316a3472 332 getCurrentTime();
019dd986 333 debug(18, 3, "stat_objects_get: Processed %d objects...\n", N);
090089c4 334 }
335 obj_size = entry->object_len;
336 npend = storePendingNClients(entry);
337 if (entry->mem_obj)
22e4fa85 338 obj_size = entry->mem_obj->e_current_len;
c30c5a73 339 storeAppendPrintf(sentry, "{ %s %d %s %s %s %s %d %d %s %s }\n",
090089c4 340 entry->url,
341 obj_size,
342 elapsed_time(entry, (int) entry->timestamp, space),
343 flags_describe(entry),
344 elapsed_time(entry, (int) entry->lastref, space2),
ed82beba 345 ttl_describe(entry),
090089c4 346 npend,
644642ab 347 (int) entry->refcount,
090089c4 348 mem_describe(entry),
349 stat_describe(entry));
090089c4 350 }
30a4f2a8 351 storeAppendPrintf(sentry, close_bracket);
090089c4 352}
353
354
355/* process a requested object into a manager format */
b8d8561b 356static void
357stat_get(cacheinfo * obj, char *req, StoreEntry * sentry)
090089c4 358{
359
30a4f2a8 360 if (strcmp(req, "objects") == 0) {
090089c4 361 stat_objects_get(obj, sentry, 0);
30a4f2a8 362 } else if (strcmp(req, "vm_objects") == 0) {
090089c4 363 stat_objects_get(obj, sentry, 1);
f88bb09c 364 } else if (strcmp(req, "ipcache") == 0) {
30a4f2a8 365 stat_ipcache_get(sentry);
f88bb09c 366 } else if (strcmp(req, "fqdncache") == 0) {
367 fqdnStats(sentry);
f83b7b2c 368 } else if (strcmp(req, "dns") == 0) {
369 dnsStats(sentry);
d2af9477 370 } else if (strcmp(req, "redirector") == 0) {
371 redirectStats(sentry);
30a4f2a8 372 } else if (strcmp(req, "utilization") == 0) {
a528eb87 373 stat_utilization_get(HTTPCacheInfo, sentry, "HTTP");
374 stat_utilization_get(ICPCacheInfo, sentry, "ICP");
30a4f2a8 375 } else if (strcmp(req, "io") == 0) {
376 stat_io_get(sentry);
377 } else if (strcmp(req, "reply_headers") == 0) {
378 httpReplyHeaderStats(sentry);
d51e52f5 379 } else if (strcmp(req, "filedescriptors") == 0) {
380 statFiledescriptors(sentry);
67508012 381 } else if (strcmp(req, "netdb") == 0) {
382 netdbDump(sentry);
090089c4 383 }
384}
385
386
387/* generate logfile status information */
b8d8561b 388static void
389log_status_get(cacheinfo * obj, StoreEntry * sentry)
090089c4 390{
090089c4 391 if (obj->logfile_status == LOG_ENABLE) {
c30c5a73 392 storeAppendPrintf(sentry, "{\"Logfile is Enabled. Filename: %s\"}\n",
090089c4 393 obj->logfilename);
394 } else {
c30c5a73 395 storeAppendPrintf(sentry, "{\"Logfile is Disabled.\"}\n");
090089c4 396 }
090089c4 397}
398
399
400
401/* log convert handler */
402/* call for each line in file, use fileWalk routine */
b8d8561b 403static int
404logReadHandler(int fd_unused, char *buf, int size_unused, log_read_data_t * data)
090089c4 405{
c30c5a73 406 storeAppendPrintf(data->sentry, "{%s}\n", buf);
a2cc6ac9 407 return 0;
090089c4 408}
409
410/* log convert end handler */
411/* call when a walk is completed or error. */
b8d8561b 412static void
413logReadEndHandler(int fd, int errflag_unused, log_read_data_t * data)
090089c4 414{
30a4f2a8 415 storeAppendPrintf(data->sentry, close_bracket);
090089c4 416 storeComplete(data->sentry);
417 safe_free(data);
557a6b70 418 file_close(fd);
090089c4 419}
420
421
422
423/* start converting logfile to processed format */
b8d8561b 424static void
425log_get_start(cacheinfo * obj, StoreEntry * sentry)
090089c4 426{
090089c4 427 log_read_data_t *data = NULL;
557a6b70 428 int fd;
090089c4 429
430 if (obj->logfile_status == LOG_DISABLE) {
431 /* Manufacture status when logging is disabled */
432 log_status_get(obj, sentry);
433 storeComplete(sentry);
434 return;
435 }
557a6b70 436 fd = file_open(obj->logfilename, NULL, O_RDONLY);
437 if (fd < 0) {
438 debug(18, 0, "Cannot open logfile: %s: %s\n",
439 obj->logfilename, xstrerror());
440 return;
441 }
30a4f2a8 442 data = xcalloc(1, sizeof(log_read_data_t));
090089c4 443 data->sentry = sentry;
c30c5a73 444 storeAppendPrintf(sentry, "{\n");
557a6b70 445 file_walk(fd,
446 (FILE_WALK_HD) logReadEndHandler,
447 (void *) data,
448 (FILE_WALK_LHD) logReadHandler,
449 (void *) data);
090089c4 450 return;
451}
452
453
b8de7ebe 454/* squid convert handler */
090089c4 455/* call for each line in file, use fileWalk routine */
b8d8561b 456static int
457squidReadHandler(int fd_unused, char *buf, int size_unused, squid_read_data_t * data)
090089c4 458{
c30c5a73 459 storeAppendPrintf(data->sentry, "{\"%s\"}\n", buf);
a2cc6ac9 460 return 0;
090089c4 461}
462
b8de7ebe 463/* squid convert end handler */
090089c4 464/* call when a walk is completed or error. */
b8d8561b 465static void
466squidReadEndHandler(int fd_unused, int errflag_unused, squid_read_data_t * data)
090089c4 467{
30a4f2a8 468 storeAppendPrintf(data->sentry, close_bracket);
090089c4 469 storeComplete(data->sentry);
470 file_close(data->fd);
471 safe_free(data);
472}
473
474
b8de7ebe 475/* start convert squid.conf file to processed format */
b8d8561b 476static void
477squid_get_start(cacheinfo * obj, StoreEntry * sentry)
090089c4 478{
b8de7ebe 479 squid_read_data_t *data;
090089c4 480
30a4f2a8 481 data = xcalloc(1, sizeof(squid_read_data_t));
090089c4 482 data->sentry = sentry;
00fac1f8 483 data->fd = file_open((char *) ConfigFile, NULL, O_RDONLY);
30a4f2a8 484 storeAppendPrintf(sentry, open_bracket);
b8de7ebe 485 file_walk(data->fd, (FILE_WALK_HD) squidReadEndHandler, (void *) data,
486 (FILE_WALK_LHD) squidReadHandler, (void *) data);
090089c4 487}
488
489
b8d8561b 490static void
491dummyhandler(cacheinfo * obj, StoreEntry * sentry)
090089c4 492{
c30c5a73 493 storeAppendPrintf(sentry, "{ \"Not_Implemented_yet.\"}\n");
090089c4 494}
495
b8d8561b 496static void
497server_list(cacheinfo * obj, StoreEntry * sentry)
090089c4 498{
090089c4 499 edge *e = NULL;
500 dom_list *d = NULL;
30a4f2a8 501 icp_opcode op;
090089c4 502
30a4f2a8 503 storeAppendPrintf(sentry, open_bracket);
090089c4 504
30a4f2a8 505 if (getFirstEdge() == NULL)
c30c5a73 506 storeAppendPrintf(sentry, "{There are no neighbors installed.}\n");
090089c4 507 for (e = getFirstEdge(); e; e = getNextEdge(e)) {
508 if (e->host == NULL)
6eb42cae 509 fatal_dump("Found an edge without a hostname!");
30a4f2a8 510 storeAppendPrintf(sentry, "\n{%-11.11s: %s/%d/%d}\n",
511 e->type == EDGE_PARENT ? "Parent" : "Sibling",
512 e->host,
513 e->http_port,
514 e->icp_port);
515 storeAppendPrintf(sentry, "{Status : %s}\n",
090089c4 516 e->neighbor_up ? "Up" : "Down");
30a4f2a8 517 storeAppendPrintf(sentry, "{AVG RTT : %d msec}\n", e->stats.rtt);
518 storeAppendPrintf(sentry, "{ACK DEFICIT: %8d}\n", e->stats.ack_deficit);
519 storeAppendPrintf(sentry, "{PINGS SENT : %8d}\n", e->stats.pings_sent);
520 storeAppendPrintf(sentry, "{PINGS ACKED: %8d %3d%%}\n",
521 e->stats.pings_acked,
522 percent(e->stats.pings_acked, e->stats.pings_sent));
523 storeAppendPrintf(sentry, "{Histogram of PINGS ACKED:}\n");
524 for (op = ICP_OP_INVALID; op < ICP_OP_END; op++) {
525 if (e->stats.counts[op] == 0)
526 continue;
527 storeAppendPrintf(sentry, "{%-10.10s : %8d %3d%%}\n",
528 IcpOpcodeStr[op],
529 e->stats.counts[op],
530 percent(e->stats.counts[op], e->stats.pings_acked));
531 }
532 storeAppendPrintf(sentry, "{FETCHES : %8d %3d%%}\n",
533 e->stats.fetches,
534 percent(e->stats.fetches, e->stats.pings_acked));
535
090089c4 536 if (e->last_fail_time) {
c30c5a73 537 storeAppendPrintf(sentry, "{Last failed connect() at: %s}\n",
090089c4 538 mkhttpdlogtime(&(e->last_fail_time)));
090089c4 539 }
c30c5a73 540 storeAppendPrintf(sentry, "{DOMAIN LIST: ");
090089c4 541 for (d = e->domains; d; d = d->next) {
542 if (d->do_ping)
c30c5a73 543 storeAppendPrintf(sentry, "%s ", d->domain);
090089c4 544 else
c30c5a73 545 storeAppendPrintf(sentry, "!%s ", d->domain);
090089c4 546 }
30a4f2a8 547 storeAppendPrintf(sentry, close_bracket); /* } */
090089c4 548 }
30a4f2a8 549 storeAppendPrintf(sentry, close_bracket);
090089c4 550}
551
30a4f2a8 552#if XMALLOC_STATISTICS
b8d8561b 553static void
554info_get_mallstat(int size, number, StoreEntry * sentry)
30a4f2a8 555{
30a4f2a8 556 if (number > 0)
557 storeAppendPrintf(sentry, "{\t%d = %d}\n", size, number);
558}
559#endif
090089c4 560
b8d8561b 561static char *
562host_port_fmt(char *host, u_short port)
d51e52f5 563{
95d659f0 564 LOCAL_ARRAY(char, buf, 32);
d2af9477 565 sprintf(buf, "%s.%d", host, (int) port);
566 return buf;
d51e52f5 567}
568
b8d8561b 569static void
570statFiledescriptors(StoreEntry * sentry)
d51e52f5 571{
572 int i;
573 int j;
574 char *s = NULL;
575 int lft;
576 int to;
577
578 storeAppendPrintf(sentry, open_bracket);
579 storeAppendPrintf(sentry, "{Active file descriptors:}\n");
580 storeAppendPrintf(sentry, "{%-4s %-6s %-4s %-4s %-21s %s}\n",
581 "File",
582 "Type",
583 "Lftm",
584 "Tout",
585 "Remote Address",
586 "Description");
587 storeAppendPrintf(sentry, "{---- ------ ---- ---- --------------------- ------------------------------}\n");
d51e52f5 588 for (i = 0; i < FD_SETSIZE; i++) {
589 if (!fdstat_isopen(i))
590 continue;
591 j = fdstatGetType(i);
592 storeAppendPrintf(sentry, "{%4d %-6s ",
d2af9477 593 i,
594 fdstatTypeStr[j]);
d51e52f5 595 switch (j) {
596 case FD_SOCKET:
597 if ((lft = comm_get_fd_lifetime(i)) < 0)
598 lft = 0;
599 to = comm_get_fd_timeout(i);
600 if (lft > 0)
601 lft = (lft - squid_curtime) / 60;
602 if (to > 0)
603 to = (to - squid_curtime) / 60;
3f155cbf 604 if (fd_table[i].timeout_handler == NULL)
605 to = 0;
d51e52f5 606 storeAppendPrintf(sentry, "%4d %4d %-21s %s}\n",
607 lft,
608 to,
609 host_port_fmt(fd_table[i].ipaddr, fd_table[i].remote_port),
610 fd_note(i, NULL));
611 break;
612 case FD_FILE:
613 storeAppendPrintf(sentry, "%31s %s}\n",
614 "",
615 (s = diskFileName(i)) ? s : "-");
616 break;
617 case FD_PIPE:
618 storeAppendPrintf(sentry, "%31s %s}\n", "", fd_note(i, NULL));
619 break;
620 case FD_LOG:
621 storeAppendPrintf(sentry, "%31s %s}\n", "", fd_note(i, NULL));
622 break;
623 case FD_UNKNOWN:
624 default:
625 storeAppendPrintf(sentry, "%31s %s}\n", "", fd_note(i, NULL));
626 break;
627 }
628 }
629 storeAppendPrintf(sentry, close_bracket);
630}
631
b8d8561b 632static int
0673c0ba 633memoryAccounted(void)
1a082686 634{
92a8c005 635 return (int)
636 meta_data.store_entries * sizeof(StoreEntry) +
637 meta_data.ipcache_count * sizeof(ipcache_entry) +
f88bb09c 638 meta_data.fqdncache_count * sizeof(fqdncache_entry) +
b15fe823 639 hash_links_allocated * sizeof(hash_link) +
92a8c005 640 sm_stats.total_pages_allocated * sm_stats.page_size +
641 disk_stats.total_pages_allocated * disk_stats.page_size +
642 request_pool.total_pages_allocated * request_pool.page_size +
643 mem_obj_pool.total_pages_allocated * mem_obj_pool.page_size +
644 meta_data.url_strings +
3e12e062 645 meta_data.netdb_addrs * sizeof(netdbEntry) +
646 meta_data.netdb_hosts * sizeof(struct _net_db_name) +
f6c78bd2 647 meta_data.client_info * client_info_sz +
f6610c4e 648 meta_data.misc;
1a082686 649}
650
20882fb1 651#ifdef UNUSED_CODE
b8d8561b 652static int
0673c0ba 653mallinfoTotal(void)
1a082686 654{
655 int total = 0;
656#if HAVE_MALLINFO
657 struct mallinfo mp;
658 mp = mallinfo();
659 total = mp.arena;
660#endif
661 return total;
662}
20882fb1 663#endif
090089c4 664
b8d8561b 665static void
666info_get(cacheinfo * obj, StoreEntry * sentry)
090089c4 667{
668 char *tod = NULL;
e5f6c5c2 669 float f;
4c05a8b1 670#if HAVE_MALLINFO
30a4f2a8 671 int t;
672#endif
090089c4 673
674#if defined(HAVE_GETRUSAGE) && defined(RUSAGE_SELF)
675 struct rusage rusage;
676#endif
677
50bc2565 678#if HAVE_MALLINFO
090089c4 679 struct mallinfo mp;
680#endif
681
30a4f2a8 682 storeAppendPrintf(sentry, open_bracket);
d51e52f5 683 storeAppendPrintf(sentry, "{Squid Object Cache: Version %s}\n",
684 version_string);
620da955 685 tod = mkrfc850(squid_starttime);
c30c5a73 686 storeAppendPrintf(sentry, "{Start Time:\t%s}\n", tod);
620da955 687 tod = mkrfc850(squid_curtime);
c30c5a73 688 storeAppendPrintf(sentry, "{Current Time:\t%s}\n", tod);
d51e52f5 689 storeAppendPrintf(sentry, "{Connection information for %s:}\n",
690 appname);
691 storeAppendPrintf(sentry, "{\tNumber of TCP connections:\t%lu}\n",
692 ntcpconn);
693 storeAppendPrintf(sentry, "{\tNumber of UDP connections:\t%lu}\n",
694 nudpconn);
090089c4 695
e5f6c5c2 696 f = (float) (squid_curtime - squid_starttime);
d2af9477 697 storeAppendPrintf(sentry, "{\tConnections per hour:\t%.1f}\n",
d51e52f5 698 f == 0.0 ? 0.0 : ((ntcpconn + nudpconn) / (f / 3600)));
090089c4 699
30a4f2a8 700 storeAppendPrintf(sentry, "{Cache information for %s:}\n",
701 appname);
702 storeAppendPrintf(sentry, "{\tStorage Swap size:\t%d MB}\n",
703 storeGetSwapSize() >> 10);
704 storeAppendPrintf(sentry, "{\tStorage Mem size:\t%d KB}\n",
e954773d 705 store_mem_size >> 10);
090089c4 706
30a4f2a8 707#if HAVE_GETRUSAGE && defined(RUSAGE_SELF)
c30c5a73 708 storeAppendPrintf(sentry, "{Resource usage for %s:}\n", appname);
090089c4 709 getrusage(RUSAGE_SELF, &rusage);
d51e52f5 710 storeAppendPrintf(sentry, "{\tCPU Time: %d seconds (%d user %d sys)}\n",
711 (int) rusage.ru_utime.tv_sec + (int) rusage.ru_stime.tv_sec,
712 (int) rusage.ru_utime.tv_sec,
713 (int) rusage.ru_stime.tv_sec);
714 storeAppendPrintf(sentry, "{\tCPU Usage: %d%%}\n",
715 percent(rusage.ru_utime.tv_sec + rusage.ru_stime.tv_sec,
716 squid_curtime - squid_starttime));
30a4f2a8 717 storeAppendPrintf(sentry, "{\tProcess Size: rss %ld KB}\n",
090089c4 718 rusage.ru_maxrss * getpagesize() >> 10);
30a4f2a8 719 storeAppendPrintf(sentry, "{\tPage faults with physical i/o: %ld}\n",
090089c4 720 rusage.ru_majflt);
090089c4 721#endif
722
50bc2565 723#if HAVE_MALLINFO
090089c4 724 mp = mallinfo();
d51e52f5 725 storeAppendPrintf(sentry, "{Memory usage for %s via mallinfo():}\n",
726 appname);
30a4f2a8 727 storeAppendPrintf(sentry, "{\tTotal space in arena: %6d KB}\n",
b560dd20 728 mp.arena >> 10);
30a4f2a8 729 storeAppendPrintf(sentry, "{\tOrdinary blocks: %6d KB %6d blks}\n",
730 mp.uordblks >> 10, mp.ordblks);
731 storeAppendPrintf(sentry, "{\tSmall blocks: %6d KB %6d blks}\n",
732 mp.usmblks >> 10, mp.smblks);
733 storeAppendPrintf(sentry, "{\tHolding blocks: %6d KB %6d blks}\n",
734 mp.hblkhd >> 10, mp.hblks);
735 storeAppendPrintf(sentry, "{\tFree Small blocks: %6d KB}\n",
736 mp.fsmblks >> 10);
737 storeAppendPrintf(sentry, "{\tFree Ordinary blocks: %6d KB}\n",
738 mp.fordblks >> 10);
739 t = mp.uordblks + mp.usmblks + mp.hblkhd;
740 storeAppendPrintf(sentry, "{\tTotal in use: %6d KB %d%%}\n",
741 t >> 10, percent(t, mp.arena));
742 t = mp.fsmblks + mp.fordblks;
743 storeAppendPrintf(sentry, "{\tTotal free: %6d KB %d%%}\n",
744 t >> 10, percent(t, mp.arena));
745#ifdef WE_DONT_USE_KEEP
746 storeAppendPrintf(sentry, "{\tKeep option: %6d KB}\n",
747 mp.keepcost >> 10);
748#endif
46c883ed 749#if HAVE_EXT_MALLINFO
c30c5a73 750 storeAppendPrintf(sentry, "{\tmax size of small blocks:\t%d}\n", mp.mxfast);
751 storeAppendPrintf(sentry, "{\tnumber of small blocks in a holding block:\t%d}\n",
090089c4 752 mp.nlblks);
c30c5a73 753 storeAppendPrintf(sentry, "{\tsmall block rounding factor:\t%d}\n", mp.grain);
754 storeAppendPrintf(sentry, "{\tspace (including overhead) allocated in ord. blks:\t%d}\n"
090089c4 755 ,mp.uordbytes);
c30c5a73 756 storeAppendPrintf(sentry, "{\tnumber of ordinary blocks allocated:\t%d}\n",
090089c4 757 mp.allocated);
c30c5a73 758 storeAppendPrintf(sentry, "{\tbytes used in maintaining the free tree:\t%d}\n",
090089c4 759 mp.treeoverhead);
46c883ed 760#endif /* HAVE_EXT_MALLINFO */
50bc2565 761#endif /* HAVE_MALLINFO */
090089c4 762
c30c5a73 763 storeAppendPrintf(sentry, "{File descriptor usage for %s:}\n", appname);
30a4f2a8 764 storeAppendPrintf(sentry, "{\tMax number of file desc available: %4d}\n",
765 FD_SETSIZE);
766 storeAppendPrintf(sentry, "{\tLargest file desc currently in use: %4d}\n",
090089c4 767 fdstat_biggest_fd());
30a4f2a8 768 storeAppendPrintf(sentry, "{\tAvailable number of file descriptors: %4d}\n",
090089c4 769 fdstat_are_n_free_fd(0));
30a4f2a8 770 storeAppendPrintf(sentry, "{\tReserved number of file descriptors: %4d}\n",
090089c4 771 RESERVED_FD);
090089c4 772
c30c5a73 773 storeAppendPrintf(sentry, "{Internal Data Structures:}\n");
c31201c6 774 storeAppendPrintf(sentry, "{\t%6d StoreEntries}\n",
775 meta_data.store_entries);
776 storeAppendPrintf(sentry, "{\t%6d StoreEntries with MemObjects}\n",
777 meta_data.mem_obj_count);
778 storeAppendPrintf(sentry, "{\t%6d StoreEntries with MemObject Data}\n",
779 meta_data.mem_data_count);
780 storeAppendPrintf(sentry, "{\t%6d Hot Object Cache Items}\n",
30a4f2a8 781 meta_data.hot_vm);
30a4f2a8 782
c31201c6 783 storeAppendPrintf(sentry, "{Accounted Memory Usage:}\n");
30a4f2a8 784 storeAppendPrintf(sentry, "{\t%-25.25s %7d x %4d bytes = %6d KB}\n",
785 "StoreEntry",
cff333e8 786 meta_data.store_entries,
787 (int) sizeof(StoreEntry),
0d5fc38a 788 (int) (meta_data.store_entries * sizeof(StoreEntry) >> 10));
cff333e8 789
a6f3a003 790 storeAppendPrintf(sentry, "{\t%-25.25s = %6d KB}\n",
791 "URL strings",
792 meta_data.url_strings >> 10);
793
30a4f2a8 794 storeAppendPrintf(sentry, "{\t%-25.25s %7d x %4d bytes = %6d KB}\n",
795 "IPCacheEntry",
cff333e8 796 meta_data.ipcache_count,
797 (int) sizeof(ipcache_entry),
0d5fc38a 798 (int) (meta_data.ipcache_count * sizeof(ipcache_entry) >> 10));
cff333e8 799
f88bb09c 800 storeAppendPrintf(sentry, "{\t%-25.25s %7d x %4d bytes = %6d KB}\n",
801 "FQDNCacheEntry",
802 meta_data.fqdncache_count,
803 (int) sizeof(fqdncache_entry),
804 (int) (meta_data.fqdncache_count * sizeof(fqdncache_entry) >> 10));
805
30a4f2a8 806 storeAppendPrintf(sentry, "{\t%-25.25s %7d x %4d bytes = %6d KB}\n",
807 "Hash link",
b15fe823 808 hash_links_allocated,
cff333e8 809 (int) sizeof(hash_link),
b15fe823 810 (int) (hash_links_allocated * sizeof(hash_link) >> 10));
cff333e8 811
30a4f2a8 812 storeAppendPrintf(sentry, "{\t%-25.25s %7d x %4d bytes = %6d KB (%6d free)}\n",
813 "Pool MemObject structures",
814 mem_obj_pool.total_pages_allocated,
815 mem_obj_pool.page_size,
816 mem_obj_pool.total_pages_allocated * mem_obj_pool.page_size >> 10,
817 (mem_obj_pool.total_pages_allocated - mem_obj_pool.n_pages_in_use) * mem_obj_pool.page_size >> 10);
818
819 storeAppendPrintf(sentry, "{\t%-25.25s %7d x %4d bytes = %6d KB (%6d free)}\n",
820 "Pool for Request structures",
821 request_pool.total_pages_allocated,
822 request_pool.page_size,
823 request_pool.total_pages_allocated * request_pool.page_size >> 10,
824 (request_pool.total_pages_allocated - request_pool.n_pages_in_use) * request_pool.page_size >> 10);
825
826 storeAppendPrintf(sentry, "{\t%-25.25s %7d x %4d bytes = %6d KB (%6d free)}\n",
827 "Pool for in-memory object data",
828 sm_stats.total_pages_allocated,
829 sm_stats.page_size,
830 sm_stats.total_pages_allocated * sm_stats.page_size >> 10,
831 (sm_stats.total_pages_allocated - sm_stats.n_pages_in_use) * sm_stats.page_size >> 10);
cff333e8 832
30a4f2a8 833 storeAppendPrintf(sentry, "{\t%-25.25s %7d x %4d bytes = %6d KB (%6d free)}\n",
834 "Pool for disk I/O",
835 disk_stats.total_pages_allocated,
836 disk_stats.page_size,
cff333e8 837 disk_stats.total_pages_allocated * disk_stats.page_size >> 10,
838 (disk_stats.total_pages_allocated - disk_stats.n_pages_in_use) * disk_stats.page_size >> 10);
cff333e8 839
82696127 840 storeAppendPrintf(sentry, "{\t%-25.25s %7d x %4d bytes = %6d KB}\n",
3e12e062 841 "NetDB Address Entries",
842 meta_data.netdb_addrs,
82696127 843 (int) sizeof(netdbEntry),
3e12e062 844 (int) (meta_data.netdb_addrs * sizeof(netdbEntry) >> 10));
845
846 storeAppendPrintf(sentry, "{\t%-25.25s %7d x %4d bytes = %6d KB}\n",
847 "NetDB Host Entries",
848 meta_data.netdb_hosts,
849 (int) sizeof(struct _net_db_name),
f6610c4e 850 (int) (meta_data.netdb_hosts * sizeof(struct _net_db_name) >> 10));
e97f40f4 851
5ecceaa4 852 storeAppendPrintf(sentry, "{\t%-25.25s %7d x %4d bytes = %6d KB}\n",
853 "ClientDB Entries",
854 meta_data.client_info,
855 client_info_sz,
856 (int) (meta_data.client_info * client_info_sz >> 10));
82696127 857
30a4f2a8 858 storeAppendPrintf(sentry, "{\t%-25.25s = %6d KB}\n",
859 "Miscellaneous",
860 meta_data.misc >> 10);
cff333e8 861
30a4f2a8 862 storeAppendPrintf(sentry, "{\t%-25.25s = %6d KB}\n",
863 "Total Accounted",
1a082686 864 memoryAccounted() >> 10);
30a4f2a8 865
866#if XMALLOC_STATISTICS
867 storeAppendPrintf(sentry, "{Memory allocation statistics}\n");
868 malloc_statistics(info_get_mallstat, sentry);
869#endif
090089c4 870
30a4f2a8 871 storeAppendPrintf(sentry, close_bracket);
090089c4 872}
873
b8d8561b 874static void
875parameter_get(cacheinfo * obj, StoreEntry * sentry)
090089c4 876{
30a4f2a8 877 storeAppendPrintf(sentry, open_bracket);
d51e52f5 878 storeAppendPrintf(sentry,
879 "{VM-Max %d \"# Maximum hot-vm cache (MB)\"}\n",
b6f794d6 880 Config.Mem.maxSize / (1 << 20));
d51e52f5 881 storeAppendPrintf(sentry,
882 "{VM-High %d \"# High water mark hot-vm cache (%%)\"}\n",
b6f794d6 883 Config.Mem.highWaterMark);
d51e52f5 884 storeAppendPrintf(sentry,
885 "{VM-Low %d \"# Low water-mark hot-vm cache (%%)\"}\n",
b6f794d6 886 Config.Mem.lowWaterMark);
d51e52f5 887 storeAppendPrintf(sentry,
888 "{Swap-Max %d \"# Maximum disk cache (MB)\"}\n",
b6f794d6 889 Config.Swap.maxSize / (1 << 10));
d51e52f5 890 storeAppendPrintf(sentry,
891 "{Swap-High %d \"# High Water mark disk cache (%%)\"}\n",
b6f794d6 892 Config.Swap.highWaterMark);
d51e52f5 893 storeAppendPrintf(sentry,
894 "{Swap-Low %d \"# Low water mark disk cache (%%)\"}\n",
b6f794d6 895 Config.Swap.lowWaterMark);
d51e52f5 896 storeAppendPrintf(sentry,
897 "{HTTP-Max %d\"# Maximum size HTTP objects (KB)\"}\n",
b6f794d6 898 Config.Http.maxObjSize / (1 << 10));
d51e52f5 899 storeAppendPrintf(sentry,
900 "{HTTP-TTL %d \"# Http object default TTL (hrs)\"}\n",
b6f794d6 901 Config.Http.defaultTtl / 3600);
d51e52f5 902 storeAppendPrintf(sentry,
903 "{Gopher-Max %d \"# Maximum size gopher objects (KB)\"}\n",
b6f794d6 904 Config.Gopher.maxObjSize / (1 << 10));
d51e52f5 905 storeAppendPrintf(sentry,
906 "{Gopher-TTL %d \"# TTL for gopher objects (hrs)\"}\n",
b6f794d6 907 Config.Gopher.defaultTtl / 3600);
d51e52f5 908 storeAppendPrintf(sentry,
909 "{FTP-Max %d \"# Maximum size FTP objects (KB)\"}\n",
b6f794d6 910 Config.Ftp.maxObjSize / (1 << 10));
d51e52f5 911 storeAppendPrintf(sentry,
912 "{FTP-TTL %d \"# TTL for FTP objects (hrs)\"}\n",
b6f794d6 913 Config.Ftp.defaultTtl / 3600);
d51e52f5 914 storeAppendPrintf(sentry,
915 "{Neg-TTL %d \"# TTL for negative cache (s)\"}\n",
b6f794d6 916 Config.negativeTtl);
d51e52f5 917 storeAppendPrintf(sentry,
918 "{ReadTimeout %d \"# Maximum idle connection (s)\"}\n",
b6f794d6 919 Config.readTimeout);
d51e52f5 920 storeAppendPrintf(sentry,
921 "{ClientLifetime %d \"# Lifetime for incoming HTTP requests\"}\n",
b6f794d6 922 Config.lifetimeDefault);
d51e52f5 923 storeAppendPrintf(sentry,
924 "{CleanRate %d \"# Rate for periodic object expiring\"}\n",
b6f794d6 925 Config.cleanRate);
090089c4 926 /* Cachemgr.cgi expects an integer in the second field of the string */
d51e52f5 927 storeAppendPrintf(sentry,
928 "{HttpAccelMode %d \"# Is operating as an HTTP accelerator\"}\n",
090089c4 929 httpd_accel_mode);
30a4f2a8 930 storeAppendPrintf(sentry, close_bracket);
090089c4 931}
932
2ba42578 933#if LOG_FULL_HEADERS
e43efe50 934static char c2x[] =
f6c78bd2 935"000102030405060708090a0b0c0d0e0f"
936"101112131415161718191a1b1c1d1e1f"
937"202122232425262728292a2b2c2d2e2f"
938"303132333435363738393a3b3c3d3e3f"
939"404142434445464748494a4b4c4d4e4f"
940"505152535455565758595a5b5c5d5e5f"
941"606162636465666768696a6b6c6d6e6f"
942"707172737475767778797a7b7c7d7e7f"
943"808182838485868788898a8b8c8d8e8f"
944"909192939495969798999a9b9c9d9e9f"
945"a0a1a2a3a4a5a6a7a8a9aaabacadaeaf"
946"b0b1b2b3b4b5b6b7b8b9babbbcbdbebf"
947"c0c1c2c3c4c5c6c7c8c9cacbcccdcecf"
948"d0d1d2d3d4d5d6d7d8d9dadbdcdddedf"
949"e0e1e2e3e4e5e6e7e8e9eaebecedeeef"
950"f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff";
e43efe50 951
952/* log_quote -- URL-style encoding on MIME headers. */
953
b8d8561b 954char *
955log_quote(char *header)
e43efe50 956{
957 int c, i;
958 char *buf, *buf_cursor;
e43efe50 959 if (header == NULL) {
960 buf = xcalloc(1, 1);
961 *buf = '\0';
962 return buf;
963 }
e43efe50 964 buf = xcalloc((strlen(header) * 3) + 1, 1);
965 buf_cursor = buf;
e43efe50 966 /*
967 * We escape: \x00-\x1F"#%;<>?{}|\\\\^~`\[\]\x7F-\xFF
968 * which is the default escape list for the CPAN Perl5 URI module
969 * modulo the inclusion of space (x40) to make the raw logs a bit
970 * more readable.
971 */
972 while ((c = *header++)) {
973 if (c <= 0x1F
e8a6899c 974 || c >= 0x7F
975 || c == '"'
976 || c == '#'
977 || c == '%'
978 || c == ';'
979 || c == '<'
980 || c == '>'
981 || c == '?'
982 || c == '{'
983 || c == '}'
984 || c == '|'
985 || c == '\\'
986 || c == '^'
987 || c == '~'
988 || c == '`'
989 || c == '['
990 || c == ']') {
e43efe50 991 *buf_cursor++ = '%';
e8a6899c 992 i = c * 2;
e43efe50 993 *buf_cursor++ = c2x[i];
e8a6899c 994 *buf_cursor++ = c2x[i + 1];
e43efe50 995 } else {
996 *buf_cursor++ = c;
997 }
998 }
e43efe50 999 *buf_cursor = '\0';
1000 return buf;
1001}
2ba42578 1002#endif /* LOG_FULL_HEADERS */
e43efe50 1003
1004
b8d8561b 1005static void
1006log_append(cacheinfo * obj,
1007 char *url,
1008 struct in_addr caddr,
1009 int size,
1010 char *action,
1011 char *method,
1012 int http_code,
1013 int msec,
1014 char *ident,
1015#if !LOG_FULL_HEADERS
1016 struct _hierarchyLogData *hierData
2ba42578 1017#else
b8d8561b 1018 struct _hierarchyLogData *hierData,
1019 char *request_hdr,
1020 char *reply_hdr
e8a6899c 1021#endif /* LOG_FULL_HEADERS */
b8d8561b 1022)
090089c4 1023{
2ba42578 1024#if LOG_FULL_HEADERS
e43efe50 1025 LOCAL_ARRAY(char, tmp, 10000); /* MAX_URL is 4096 */
2ba42578 1026#else
1027 LOCAL_ARRAY(char, tmp, 6000); /* MAX_URL is 4096 */
e43efe50 1028#endif /* LOG_FULL_HEADERS */
557a6b70 1029 int x;
00859e30 1030 char *client = NULL;
eaa77841 1031 hier_code hier_code = HIER_NONE;
e81957b7 1032 char *hier_host = dash_str;
eaa77841 1033 int hier_timeout = 0;
090089c4 1034
b6f794d6 1035 if (Config.Log.log_fqdn)
00859e30 1036 client = fqdncache_gethostbyaddr(caddr, 0);
b7f3c263 1037 if (client == NULL)
1038 client = inet_ntoa(caddr);
090089c4 1039
b7f3c263 1040 getCurrentTime();
090089c4 1041
316a3472 1042 if (!method)
e81957b7 1043 method = dash_str;
6eb42cae 1044 if (!url)
e81957b7 1045 url = dash_str;
a0c09e11 1046 if (!ident || ident[0] == '\0')
e81957b7 1047 ident = dash_str;
eaa77841 1048 if (hierData) {
1049 hier_code = hierData->code;
e81957b7 1050 hier_host = hierData->host ? hierData->host : dash_str;
eaa77841 1051 hier_timeout = hierData->timeout;
1052 }
090089c4 1053 if (obj->logfile_status == LOG_ENABLE) {
b6f794d6 1054 if (Config.commonLogFormat)
92f80c9c 1055 sprintf(tmp, "%s %s - [%s] \"%s %s\" %s %d\n",
b7f3c263 1056 client,
92f80c9c 1057 ident,
1058 mkhttpdlogtime(&squid_curtime),
1059 method,
1060 url,
1061 action,
1062 size);
090089c4 1063 else
eaa77841 1064 sprintf(tmp, "%9d.%03d %6d %s %s/%03d %d %s %s %s %s%s/%s\n",
316a3472 1065 (int) current_time.tv_sec,
fc07a0e4 1066 (int) current_time.tv_usec / 1000,
1067 msec,
b7f3c263 1068 client,
316a3472 1069 action,
fc07a0e4 1070 http_code,
316a3472 1071 size,
1072 method,
a0c09e11 1073 url,
9864ee44 1074 ident,
eaa77841 1075 hier_timeout ? "TIMEOUT_" : "",
1076 hier_strings[hier_code],
1077 hier_host);
2ba42578 1078#if LOG_FULL_HEADERS
e43efe50 1079 if (Config.logMimeHdrs) {
1080 int msize = strlen(tmp);
1081 char *ereq = log_quote(request_hdr);
1082 char *erep = log_quote(reply_hdr);
1083
1084 if (msize + strlen(ereq) + strlen(erep) + 7 <= sizeof(tmp))
e8a6899c 1085 sprintf(tmp + msize - 1, " [%s] [%s]\n", ereq, erep);
e43efe50 1086 else
1087 debug(18, 1, "log_append: Long headers not logged.\n");
1088 safe_free(ereq);
1089 safe_free(erep);
1090 }
e43efe50 1091#endif /* LOG_FULL_HEADERS */
557a6b70 1092 x = file_write(obj->logfile_fd,
9864ee44 1093 xstrdup(tmp),
557a6b70 1094 strlen(tmp),
1095 obj->logfile_access,
1096 NULL,
1097 NULL,
1098 xfree);
9864ee44 1099 if (x != DISK_OK)
019dd986 1100 debug(18, 1, "log_append: File write failed.\n");
090089c4 1101 }
1102}
1103
b8d8561b 1104static void
1105log_enable(cacheinfo * obj, StoreEntry * sentry)
090089c4 1106{
090089c4 1107 if (obj->logfile_status == LOG_DISABLE) {
1108 obj->logfile_status = LOG_ENABLE;
1109
1110 /* open the logfile */
557a6b70 1111 obj->logfile_fd = file_open(obj->logfilename, NULL, O_WRONLY | O_CREAT);
090089c4 1112 if (obj->logfile_fd == DISK_ERROR) {
019dd986 1113 debug(18, 0, "Cannot open logfile: %s\n", obj->logfilename);
090089c4 1114 obj->logfile_status = LOG_DISABLE;
1115 }
1116 obj->logfile_access = file_write_lock(obj->logfile_fd);
1117
1118 }
1119 /* at the moment, store one char to make a storage manager happy */
c30c5a73 1120 storeAppendPrintf(sentry, " ");
090089c4 1121}
1122
b8d8561b 1123static void
1124log_disable(cacheinfo * obj, StoreEntry * sentry)
090089c4 1125{
090089c4 1126 if (obj->logfile_status == LOG_ENABLE)
1127 file_close(obj->logfile_fd);
1128
1129 obj->logfile_status = LOG_DISABLE;
1130 /* at the moment, store one char to make a storage manager happy */
c30c5a73 1131 storeAppendPrintf(sentry, " ");
090089c4 1132}
1133
1134
1135
b8d8561b 1136static void
1137log_clear(cacheinfo * obj, StoreEntry * sentry)
090089c4 1138{
30a4f2a8 1139 /* what should be done here. Erase file ??? or move it to another name? At the moment, just erase it. bug here need to be fixed. what if there are still data in memory. Need flush here */
090089c4 1140 if (obj->logfile_status == LOG_ENABLE)
1141 file_close(obj->logfile_fd);
1142
1143 unlink(obj->logfilename);
1144
1145 /* reopen it anyway */
557a6b70 1146 obj->logfile_fd = file_open(obj->logfilename, NULL, O_WRONLY | O_CREAT);
090089c4 1147 if (obj->logfile_fd == DISK_ERROR) {
019dd986 1148 debug(18, 0, "Cannot open logfile: %s\n", obj->logfilename);
090089c4 1149 obj->logfile_status = LOG_DISABLE;
1150 }
1151 /* at the moment, store one char to make a storage manager happy */
c30c5a73 1152 storeAppendPrintf(sentry, " ");
090089c4 1153}
1154
1155
1156
b8d8561b 1157static void
1158proto_newobject(cacheinfo * obj, protocol_t proto_id, int size, int restart)
090089c4 1159{
1160 proto_stat *p = &obj->proto_stat_data[proto_id];
1161
1162 p->object_count++;
1163
1164 /* Account for 1KB granularity */
1165 p->kb.now += ((size + 1023) >> 10);
1166
1167 if (p->kb.now > p->kb.max)
1168 p->kb.max = p->kb.now;
1169 if (restart)
1170 p->kb.min = p->kb.now;
1171}
1172
1173
b8d8561b 1174static void
1175proto_purgeobject(cacheinfo * obj, protocol_t proto_id, int size)
090089c4 1176{
1177 proto_stat *p = &obj->proto_stat_data[proto_id];
1178
1179 p->object_count--;
1180
1181 /* Scale down to KB */
1182 p->kb.now -= ((size + 1023) >> 10);
1183
1184 if (p->kb.now < p->kb.min)
1185 p->kb.min = p->kb.now;
1186}
1187
1188/* update stat for each particular protocol when an object is fetched */
b8d8561b 1189static void
1190proto_touchobject(cacheinfo * obj, protocol_t proto_id, int size)
090089c4 1191{
1192 obj->proto_stat_data[proto_id].refcount++;
1193 obj->proto_stat_data[proto_id].transferbyte += (1023 + size) >> 10;
1194}
1195
b8d8561b 1196static void
1197proto_count(cacheinfo * obj, protocol_t proto_id, log_type type)
090089c4 1198{
a528eb87 1199 switch (type) {
1200 case LOG_TCP_HIT:
1201 case LOG_TCP_IMS_HIT:
1202 case LOG_TCP_EXPIRED_HIT:
1203 case LOG_UDP_HIT:
1204 case LOG_UDP_HIT_OBJ:
1205 obj->proto_stat_data[proto_id].hit++;
1206 break;
1207 default:
1208 obj->proto_stat_data[proto_id].miss++;
1209 break;
1210 }
090089c4 1211}
1212
090089c4 1213
b8d8561b 1214void
1215stat_init(cacheinfo ** object, char *logfilename)
090089c4 1216{
1217 cacheinfo *obj = NULL;
1218 int i;
1219
92a8c005 1220 debug(18, 5, "stat_init: Initializing...\n");
30a4f2a8 1221 obj = xcalloc(1, sizeof(cacheinfo));
090089c4 1222 obj->stat_get = stat_get;
1223 obj->info_get = info_get;
1224 obj->cache_size_get = cache_size_get;
090089c4 1225 obj->log_get_start = log_get_start;
1226 obj->log_status_get = log_status_get;
1227 obj->log_append = log_append;
1228 obj->log_clear = log_clear;
1229 obj->log_enable = log_enable;
1230 obj->log_disable = log_disable;
1231 obj->logfile_status = LOG_ENABLE;
b8de7ebe 1232 obj->squid_get_start = squid_get_start;
090089c4 1233 obj->parameter_get = parameter_get;
1234 obj->server_list = server_list;
a528eb87 1235 if (logfilename) {
1236 memset(obj->logfilename, '0', MAX_FILE_NAME_LEN);
1237 strncpy(obj->logfilename, logfilename, MAX_FILE_NAME_LEN - 1);
1238 obj->logfile_fd = file_open(obj->logfilename, NULL, O_WRONLY | O_CREAT);
1239 if (obj->logfile_fd == DISK_ERROR) {
1240 debug(18, 0, "%s: %s\n", obj->logfilename, xstrerror());
1241 fatal("Cannot open logfile.");
1242 }
1243 obj->logfile_access = file_write_lock(obj->logfile_fd);
090089c4 1244 }
92a6f4b1 1245 obj->proto_id = urlParseProtocol;
090089c4 1246 obj->proto_newobject = proto_newobject;
1247 obj->proto_purgeobject = proto_purgeobject;
1248 obj->proto_touchobject = proto_touchobject;
a528eb87 1249 obj->proto_count = proto_count;
090089c4 1250 obj->NotImplement = dummyhandler;
30a4f2a8 1251 for (i = PROTO_NONE; i <= PROTO_MAX; i++) {
090089c4 1252 switch (i) {
8213067d 1253 case PROTO_HTTP:
090089c4 1254 strcpy(obj->proto_stat_data[i].protoname, "HTTP");
1255 break;
8213067d 1256 case PROTO_GOPHER:
090089c4 1257 strcpy(obj->proto_stat_data[i].protoname, "GOPHER");
1258 break;
8213067d 1259 case PROTO_FTP:
090089c4 1260 strcpy(obj->proto_stat_data[i].protoname, "FTP");
1261 break;
234967c9 1262 case PROTO_WAIS:
1263 strcpy(obj->proto_stat_data[i].protoname, "WAIS");
1264 break;
8213067d 1265 case PROTO_CACHEOBJ:
1266 strcpy(obj->proto_stat_data[i].protoname, "CACHE_OBJ");
090089c4 1267 break;
8213067d 1268 case PROTO_MAX:
1269 strcpy(obj->proto_stat_data[i].protoname, "TOTAL");
090089c4 1270 break;
8213067d 1271 case PROTO_NONE:
090089c4 1272 default:
8213067d 1273 strcpy(obj->proto_stat_data[i].protoname, "OTHER");
090089c4 1274 break;
1275 }
090089c4 1276 obj->proto_stat_data[i].object_count = 0;
1277 obj->proto_stat_data[i].hit = 0;
1278 obj->proto_stat_data[i].miss = 0;
1279 obj->proto_stat_data[i].hitratio = 0.0;
1280 obj->proto_stat_data[i].transferrate = 0;
1281 obj->proto_stat_data[i].refcount = 0;
1282 obj->proto_stat_data[i].transferbyte = 0;
090089c4 1283 obj->proto_stat_data[i].kb.max = 0;
1284 obj->proto_stat_data[i].kb.min = 0;
1285 obj->proto_stat_data[i].kb.avg = 0;
1286 obj->proto_stat_data[i].kb.now = 0;
090089c4 1287 }
090089c4 1288 *object = obj;
1289}
1290
67508012 1291static char *
b8d8561b 1292stat_describe(StoreEntry * entry)
090089c4 1293{
95d659f0 1294 LOCAL_ARRAY(char, state, 256);
090089c4 1295
1296 state[0] = '\0';
e62d2dea 1297 sprintf(state, "%s/%s",
9dfb6c1c 1298 storeStatusStr[entry->store_status],
1299 pingStatusStr[entry->ping_status]);
090089c4 1300 return (state);
1301}
1302
67508012 1303static char *
b8d8561b 1304mem_describe(StoreEntry * entry)
090089c4 1305{
95d659f0 1306 LOCAL_ARRAY(char, where, 100);
090089c4 1307
1308 where[0] = '\0';
e62d2dea 1309 sprintf(where, "D%d/%s/%s",
9dfb6c1c 1310 entry->swap_file_number,
1311 swapStatusStr[entry->swap_status],
1312 memStatusStr[entry->mem_status]);
090089c4 1313 return (where);
1314}
1315
1316
67508012 1317static char *
b8d8561b 1318ttl_describe(StoreEntry * entry)
090089c4 1319{
1320 int hh, mm, ss;
95d659f0 1321 LOCAL_ARRAY(char, TTL, 60);
090089c4 1322 int ttl;
1323
1324 TTL[0] = '\0';
1325 strcpy(TTL, "UNKNOWN"); /* sometimes the TTL isn't set below */
b8de7ebe 1326 ttl = entry->expires - squid_curtime;
090089c4 1327 if (ttl < 0)
1328 strcpy(TTL, "EXPIRED");
1329 else {
1330
1331 hh = ttl / 3600;
1332 ttl -= hh * 3600;
1333 mm = ttl / 60;
1334 ttl -= mm * 60;
1335 ss = ttl;
1336
1337 sprintf(TTL, "% 6d:%02d:%02d", hh, mm, ss);
1338 }
1339 return (TTL);
1340}
1341
67508012 1342static char *
b8d8561b 1343elapsed_time(StoreEntry * entry, int since, char *TTL)
090089c4 1344{
1345 int hh, mm, ss, ttl;
1346
1347 TTL[0] = '\0';
1348 strcpy(TTL, "UNKNOWN"); /* sometimes TTL doesn't get set */
b8de7ebe 1349 ttl = squid_curtime - since;
090089c4 1350 if (since == 0) {
1351 strcpy(TTL, "NEVER");
1352 } else if (ttl < 0) {
1353 strcpy(TTL, "EXPIRED");
1354 } else {
1355 hh = ttl / 3600;
1356 ttl -= hh * 3600;
1357 mm = ttl / 60;
1358 ttl -= mm * 60;
1359 ss = ttl;
1360 sprintf(TTL, "% 6d:%02d:%02d", hh, mm, ss);
1361 }
1362 return (TTL);
1363}
1364
1365
67508012 1366static char *
b8d8561b 1367flags_describe(StoreEntry * entry)
090089c4 1368{
95d659f0 1369 LOCAL_ARRAY(char, FLAGS, 32);
090089c4 1370 char LOCK_CNT[32];
1371
1372 strcpy(FLAGS, "F:");
1373 if (BIT_TEST(entry->flag, KEY_CHANGE))
1374 strncat(FLAGS, "K", sizeof(FLAGS) - 1);
1c481e00 1375 if (BIT_TEST(entry->flag, ENTRY_CACHABLE))
090089c4 1376 strncat(FLAGS, "C", sizeof(FLAGS) - 1);
1377 if (BIT_TEST(entry->flag, REFRESH_REQUEST))
1378 strncat(FLAGS, "R", sizeof(FLAGS) - 1);
1379 if (BIT_TEST(entry->flag, RELEASE_REQUEST))
1380 strncat(FLAGS, "Z", sizeof(FLAGS) - 1);
1381 if (BIT_TEST(entry->flag, ABORT_MSG_PENDING))
1382 strncat(FLAGS, "A", sizeof(FLAGS) - 1);
1383 if (BIT_TEST(entry->flag, DELAY_SENDING))
1384 strncat(FLAGS, "D", sizeof(FLAGS) - 1);
1385 if (BIT_TEST(entry->flag, IP_LOOKUP_PENDING))
1386 strncat(FLAGS, "P", sizeof(FLAGS) - 1);
1387 if (entry->lock_count)
1388 strncat(FLAGS, "L", sizeof(FLAGS) - 1);
1389 if (entry->lock_count) {
1390 sprintf(LOCK_CNT, "%d", entry->lock_count);
1391 strncat(FLAGS, LOCK_CNT, sizeof(FLAGS) - 1);
1392 }
1393 return (FLAGS);
1394}
1395
b8d8561b 1396void
0673c0ba 1397stat_rotate_log(void)
090089c4 1398{
1399 int i;
95d659f0 1400 LOCAL_ARRAY(char, from, MAXPATHLEN);
1401 LOCAL_ARRAY(char, to, MAXPATHLEN);
090089c4 1402 char *fname = NULL;
1403
a528eb87 1404 if ((fname = HTTPCacheInfo->logfilename) == NULL)
090089c4 1405 return;
1406
019dd986 1407 debug(18, 1, "stat_rotate_log: Rotating\n");
090089c4 1408
1409 /* Rotate numbers 0 through N up one */
b6f794d6 1410 for (i = Config.Log.rotateNumber; i > 1;) {
090089c4 1411 i--;
1412 sprintf(from, "%s.%d", fname, i - 1);
1413 sprintf(to, "%s.%d", fname, i);
1414 rename(from, to);
1415 }
1416 /* Rotate the current log to .0 */
b6f794d6 1417 if (Config.Log.rotateNumber > 0) {
090089c4 1418 sprintf(to, "%s.%d", fname, 0);
1419 rename(fname, to);
1420 }
1421 /* Close and reopen the log. It may have been renamed "manually"
1422 * before HUP'ing us. */
a528eb87 1423 file_close(HTTPCacheInfo->logfile_fd);
1424 HTTPCacheInfo->logfile_fd = file_open(fname, NULL, O_WRONLY | O_CREAT);
1425 if (HTTPCacheInfo->logfile_fd == DISK_ERROR) {
30a4f2a8 1426 debug(18, 0, "stat_rotate_log: Cannot open logfile: %s\n", fname);
a528eb87 1427 HTTPCacheInfo->logfile_status = LOG_DISABLE;
6eb42cae 1428 fatal("Cannot open logfile.");
090089c4 1429 }
a528eb87 1430 HTTPCacheInfo->logfile_access = file_write_lock(HTTPCacheInfo->logfile_fd);
090089c4 1431}
457bedbd 1432
b8d8561b 1433void
0673c0ba 1434statCloseLog(void)
457bedbd 1435{
a528eb87 1436 file_close(HTTPCacheInfo->logfile_fd);
457bedbd 1437}