source: bin/varnishtop/varnishtop.c @ 22edaa

Revision 22edaa, 6.5 KB checked in by Dag Erling Smørgrav <des@…>, 5 years ago (diff)

Revert r3072, which was a no-op.
Add "config.h" where it's missing.

git-svn-id:  http://www.varnish-cache.org/svn/trunk/varnish-cache@3336 d4fa192b-c00b-0410-8231-f00ffab90ce4

  • Property mode set to 100644
Line 
1/*-
2 * Copyright (c) 2006 Verdens Gang AS
3 * Copyright (c) 2006-2008 Linpro AS
4 * All rights reserved.
5 *
6 * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
7 * Author: Dag-Erling Smørgrav <des@des.no>
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 *
30 * $Id$
31 *
32 * Log tailer for Varnish
33 */
34
35#include "config.h"
36
37#include <ctype.h>
38#include <curses.h>
39#include <errno.h>
40#include <pthread.h>
41#include <signal.h>
42#include <stdio.h>
43#include <stdlib.h>
44#include <string.h>
45#include <unistd.h>
46#include <limits.h>
47
48#include "vqueue.h"
49
50#include "vsb.h"
51
52#include "libvarnish.h"
53#include "shmlog.h"
54#include "varnishapi.h"
55
56struct top {
57        unsigned char           rec[4 + 255];
58        unsigned                clen;
59        unsigned                hash;
60        VTAILQ_ENTRY(top)       list;
61        double                  count;
62};
63
64static VTAILQ_HEAD(tophead, top) top_head = VTAILQ_HEAD_INITIALIZER(top_head);
65
66static unsigned ntop;
67
68/*--------------------------------------------------------------------*/
69
70static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
71
72static int f_flag = 0;
73
74static unsigned maxfieldlen = 0;
75
76static void
77accumulate(const unsigned char *p)
78{
79        struct top *tp, *tp2;
80        const unsigned char *q;
81        unsigned int u, l;
82        int i;
83
84        // fprintf(stderr, "%*.*s\n", p[1], p[1], p + 4);
85
86        u = 0;
87        q = p + SHMLOG_DATA;
88        l = SHMLOG_LEN(p);
89        for (i = 0; i < l; i++, q++) {
90                if (f_flag && (*q == ':' || isspace(*q)))
91                        break;
92                u += *q;
93        }
94
95        VTAILQ_FOREACH(tp, &top_head, list) {
96                if (tp->hash != u)
97                        continue;
98                if (tp->rec[SHMLOG_TAG] != p[SHMLOG_TAG])
99                        continue;
100                if (tp->clen != q - p)
101                        continue;
102                if (memcmp(p + SHMLOG_DATA, tp->rec + SHMLOG_DATA,
103                    q - (p + SHMLOG_DATA)))
104                        continue;
105                tp->count += 1.0;
106                break;
107        }
108        if (tp == NULL) {
109                ntop++;
110                tp = calloc(sizeof *tp, 1);
111                assert(tp != NULL);
112                tp->hash = u;
113                tp->count = 1.0;
114                tp->clen = q - p;
115                VTAILQ_INSERT_TAIL(&top_head, tp, list);
116        }
117        memcpy(tp->rec, p, SHMLOG_DATA + l);
118        while (1) {
119                tp2 = VTAILQ_PREV(tp, tophead, list);
120                if (tp2 == NULL || tp2->count >= tp->count)
121                        break;
122                VTAILQ_REMOVE(&top_head, tp2, list);
123                VTAILQ_INSERT_AFTER(&top_head, tp, tp2, list);
124        }
125        while (1) {
126                tp2 = VTAILQ_NEXT(tp, list);
127                if (tp2 == NULL || tp2->count <= tp->count)
128                        break;
129                VTAILQ_REMOVE(&top_head, tp2, list);
130                VTAILQ_INSERT_BEFORE(tp, tp2, list);
131        }
132}
133
134static void
135update(void)
136{
137        struct top *tp, *tp2;
138        int l, len;
139        double t = 0;
140        static time_t last;
141        time_t now;
142
143        now = time(NULL);
144        if (now == last)
145                return;
146        last = now;
147
148        erase();
149        l = 1;
150        mvprintw(0, 0, "%*s", COLS - 1, VSL_Name());
151        mvprintw(0, 0, "list length %u", ntop);
152        VTAILQ_FOREACH_SAFE(tp, &top_head, list, tp2) {
153                if (++l < LINES) {
154                        len = SHMLOG_LEN(tp->rec);
155                        if (len > COLS - 20)
156                                len = COLS - 20;
157                        mvprintw(l, 0, "%9.2f %-*.*s %*.*s\n",
158                            tp->count, maxfieldlen, maxfieldlen,
159                            VSL_tags[tp->rec[SHMLOG_TAG]],
160                            len, len, tp->rec + SHMLOG_DATA);
161                        t = tp->count;
162                }
163                tp->count *= .999;
164                if (tp->count * 10 < t || l > LINES * 10) {
165                        VTAILQ_REMOVE(&top_head, tp, list);
166                        free(tp);
167                        ntop--;
168                }
169        }
170        refresh();
171}
172
173static void *
174accumulate_thread(void *arg)
175{
176        struct VSL_data *vd = arg;
177
178        for (;;) {
179                unsigned char *p;
180                int i;
181
182                i = VSL_NextLog(vd, &p);
183                if (i < 0)
184                        break;
185                if (i == 0) {
186                        usleep(50000);
187                        continue;
188                }
189
190                pthread_mutex_lock(&mtx);
191                accumulate(p);
192                pthread_mutex_unlock(&mtx);
193        }
194        return (arg);
195}
196
197static void
198do_curses(struct VSL_data *vd)
199{
200        pthread_t thr;
201        int ch;
202        int i;
203
204        for (i = 0; i < 256; i++) {
205                if (VSL_tags[i] == NULL)
206                        continue;
207                if (maxfieldlen < strlen(VSL_tags[i]))
208                        maxfieldlen = strlen(VSL_tags[i]);
209        }
210
211        if (pthread_create(&thr, NULL, accumulate_thread, vd) != 0) {
212                fprintf(stderr, "pthread_create(): %s\n", strerror(errno));
213                exit(1);
214        }
215
216        initscr();
217        raw();
218        noecho();
219        nonl();
220        intrflush(stdscr, FALSE);
221        curs_set(0);
222        erase();
223        for (;;) {
224                pthread_mutex_lock(&mtx);
225                update();
226                pthread_mutex_unlock(&mtx);
227
228                timeout(1000);
229                switch ((ch = getch())) {
230                case ERR:
231                        break;
232#ifdef KEY_RESIZE
233                case KEY_RESIZE:
234                        erase();
235                        break;
236#endif
237                case '\014': /* Ctrl-L */
238                case '\024': /* Ctrl-T */
239                        redrawwin(stdscr);
240                        refresh();
241                        break;
242                case '\003': /* Ctrl-C */
243                        raise(SIGINT);
244                        break;
245                case '\032': /* Ctrl-Z */
246                        endwin();
247                        raise(SIGTSTP);
248                        break;
249                case '\021': /* Ctrl-Q */
250                case 'Q':
251                case 'q':
252                        endwin();
253                        return;
254                default:
255                        beep();
256                        break;
257                }
258        }
259}
260
261static void
262dump(void)
263{
264        struct top *tp, *tp2;
265        int len;
266
267        VTAILQ_FOREACH_SAFE(tp, &top_head, list, tp2) {
268                if (tp->count <= 1.0)
269                        break;
270                len = tp->rec[1];
271                printf("%9.2f %*.*s\n", tp->count, len, len, tp->rec + 4);
272        }
273}
274
275static void
276do_once(struct VSL_data *vd)
277{
278        unsigned char *p;
279
280        while (VSL_NextLog(vd, &p) > 0)
281                accumulate(p);
282        dump();
283}
284
285static void
286usage(void)
287{
288        fprintf(stderr,
289            "usage: varnishtop %s [-1fV] [-n varnish_name]\n", VSL_USAGE);
290        exit(1);
291}
292
293int
294main(int argc, char **argv)
295{
296        struct VSL_data *vd;
297        const char *n_arg = NULL;
298        int o, once = 0;
299
300        vd = VSL_New();
301
302        while ((o = getopt(argc, argv, VSL_ARGS "1fn:V")) != -1) {
303                switch (o) {
304                case '1':
305                        VSL_Arg(vd, 'd', NULL);
306                        once = 1;
307                        break;
308                case 'n':
309                        n_arg = optarg;
310                        break;
311                case 'f':
312                        f_flag = 1;
313                        break;
314                case 'V':
315                        varnish_version("varnishtop");
316                        exit(0);
317                default:
318                        if (VSL_Arg(vd, o, optarg) > 0)
319                                break;
320                        usage();
321                }
322        }
323
324        if (VSL_OpenLog(vd, n_arg))
325                exit (1);
326
327        if (once) {
328                VSL_NonBlocking(vd, 1);
329                do_once(vd);
330        } else {
331                do_curses(vd);
332        }
333        exit(0);
334}
Note: See TracBrowser for help on using the repository browser.