source: bin/varnishtop/varnishtop.c @ 8aa1d8

Revision 8aa1d8, 7.1 KB checked in by Poul-Henning Kamp <phk@…>, 3 years ago (diff)

Eliminate nested <*.h> includes from include/*

Sort #includes according to rules which are for me to know and you
to guess.

  • Property mode set to 100644
Line 
1/*-
2 * Copyright (c) 2006 Verdens Gang AS
3 * Copyright (c) 2006-2011 Varnish Software 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 * Log tailer for Varnish
31 */
32
33#include "config.h"
34
35#include <ctype.h>
36#include <curses.h>
37#include <errno.h>
38#include <limits.h>
39#include <pthread.h>
40#include <signal.h>
41#include <stdio.h>
42#include <stdlib.h>
43#include <string.h>
44#include <unistd.h>
45
46#include "vapi/vsl.h"
47#include "vapi/vsm.h"
48#include "vas.h"
49#include "vcs.h"
50#include "vqueue.h"
51#include "vsb.h"
52
53#if 0
54#define AC(x) assert((x) != ERR)
55#else
56#define AC(x) x
57#endif
58
59struct top {
60        uint8_t                 tag;
61        char                    *rec_data;
62        int                     clen;
63        unsigned                hash;
64        VTAILQ_ENTRY(top)       list;
65        double                  count;
66};
67
68static VTAILQ_HEAD(tophead, top) top_head = VTAILQ_HEAD_INITIALIZER(top_head);
69
70static unsigned ntop;
71
72/*--------------------------------------------------------------------*/
73
74static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
75
76static int f_flag = 0;
77
78static unsigned maxfieldlen = 0;
79
80static void
81accumulate(uint32_t * const p)
82{
83        struct top *tp, *tp2;
84        const char *q;
85        unsigned int u, l;
86        uint8_t t;
87        int i;
88
89        // fprintf(stderr, "%p %08x %08x\n", p, p[0], p[1]);
90
91        u = 0;
92        q = VSL_DATA(p);
93        l = VSL_LEN(p);
94        t = VSL_TAG(p);
95        for (i = 0; i < l; i++, q++) {
96                if (f_flag && (*q == ':' || isspace(*q))) {
97                        l = q - VSL_DATA(p);
98                        break;
99                }
100                u += *q;
101        }
102
103        VTAILQ_FOREACH(tp, &top_head, list) {
104                if (tp->hash != u)
105                        continue;
106                if (tp->tag != t)
107                        continue;
108                if (tp->clen != l)
109                        continue;
110                if (memcmp(VSL_DATA(p), tp->rec_data, l))
111                        continue;
112                tp->count += 1.0;
113                break;
114        }
115        if (tp == NULL) {
116                ntop++;
117                tp = calloc(sizeof *tp, 1);
118                assert(tp != NULL);
119                tp->rec_data = calloc(l + 1, 1);
120                assert(tp->rec_data != NULL);
121                tp->hash = u;
122                tp->count = 1.0;
123                tp->clen = l;
124                tp->tag = t;
125                memcpy(tp->rec_data, VSL_DATA(p), l);
126                tp->rec_data[l] = '\0';
127                VTAILQ_INSERT_TAIL(&top_head, tp, list);
128        }
129        while (1) {
130                tp2 = VTAILQ_PREV(tp, tophead, list);
131                if (tp2 == NULL || tp2->count >= tp->count)
132                        break;
133                VTAILQ_REMOVE(&top_head, tp2, list);
134                VTAILQ_INSERT_AFTER(&top_head, tp, tp2, list);
135        }
136        while (1) {
137                tp2 = VTAILQ_NEXT(tp, list);
138                if (tp2 == NULL || tp2->count <= tp->count)
139                        break;
140                VTAILQ_REMOVE(&top_head, tp2, list);
141                VTAILQ_INSERT_BEFORE(tp, tp2, list);
142        }
143}
144
145static void
146update(const struct VSM_data *vd, int period)
147{
148        struct top *tp, *tp2;
149        int l, len;
150        double t = 0;
151        static time_t last = 0;
152        static unsigned n;
153        time_t now;
154
155        now = time(NULL);
156        if (now == last)
157                return;
158        last = now;
159
160        l = 1;
161        if (n < period)
162                n++;
163        AC(erase());
164        AC(mvprintw(0, 0, "%*s", COLS - 1, VSM_Name(vd)));
165        AC(mvprintw(0, 0, "list length %u", ntop));
166        VTAILQ_FOREACH_SAFE(tp, &top_head, list, tp2) {
167                if (++l < LINES) {
168                        len = tp->clen;
169                        if (len > COLS - 20)
170                                len = COLS - 20;
171                        AC(mvprintw(l, 0, "%9.2f %-*.*s %*.*s\n",
172                            tp->count, maxfieldlen, maxfieldlen,
173                            VSL_tags[tp->tag],
174                            len, len, tp->rec_data));
175                        t = tp->count;
176                }
177                tp->count += (1.0/3.0 - tp->count) / (double)n;
178                if (tp->count * 10 < t || l > LINES * 10) {
179                        VTAILQ_REMOVE(&top_head, tp, list);
180                        free(tp->rec_data);
181                        free(tp);
182                        ntop--;
183                }
184        }
185        AC(refresh());
186}
187
188static void *
189accumulate_thread(void *arg)
190{
191        struct VSM_data *vd = arg;
192        uint32_t *p;
193        int i;
194
195        for (;;) {
196
197                i = VSL_NextLog(vd, &p, NULL);
198                if (i < 0)
199                        break;
200                if (i == 0) {
201                        AZ(usleep(50000));
202                        continue;
203                }
204
205                AZ(pthread_mutex_lock(&mtx));
206                accumulate(p);
207                AZ(pthread_mutex_unlock(&mtx));
208        }
209        return (arg);
210}
211
212static void
213do_curses(struct VSM_data *vd, int period)
214{
215        pthread_t thr;
216        int i;
217
218        for (i = 0; i < 256; i++) {
219                if (VSL_tags[i] == NULL)
220                        continue;
221                if (maxfieldlen < strlen(VSL_tags[i]))
222                        maxfieldlen = strlen(VSL_tags[i]);
223        }
224
225        if (pthread_create(&thr, NULL, accumulate_thread, vd) != 0) {
226                fprintf(stderr, "pthread_create(): %s\n", strerror(errno));
227                exit(1);
228        }
229
230        (void)initscr();
231        AC(raw());
232        AC(noecho());
233        AC(nonl());
234        AC(intrflush(stdscr, FALSE));
235        (void)curs_set(0);
236        AC(erase());
237        for (;;) {
238                AZ(pthread_mutex_lock(&mtx));
239                update(vd, period);
240                AZ(pthread_mutex_unlock(&mtx));
241
242                timeout(1000);
243                switch (getch()) {
244                case ERR:
245                        break;
246#ifdef KEY_RESIZE
247                case KEY_RESIZE:
248                        AC(erase());
249                        break;
250#endif
251                case '\014': /* Ctrl-L */
252                case '\024': /* Ctrl-T */
253                        AC(redrawwin(stdscr));
254                        AC(refresh());
255                        break;
256                case '\003': /* Ctrl-C */
257                        AZ(raise(SIGINT));
258                        break;
259                case '\032': /* Ctrl-Z */
260                        AC(endwin());
261                        AZ(raise(SIGTSTP));
262                        break;
263                case '\021': /* Ctrl-Q */
264                case 'Q':
265                case 'q':
266                        AC(endwin());
267                        return;
268                default:
269                        AC(beep());
270                        break;
271                }
272        }
273}
274
275static void
276dump(void)
277{
278        struct top *tp, *tp2;
279
280        VTAILQ_FOREACH_SAFE(tp, &top_head, list, tp2) {
281                if (tp->count <= 1.0)
282                        break;
283                printf("%9.2f %s %*.*s\n",
284                    tp->count, VSL_tags[tp->tag],
285                    tp->clen, tp->clen, tp->rec_data);
286        }
287}
288
289static void
290do_once(struct VSM_data *vd)
291{
292        uint32_t *p;
293
294        while (VSL_NextLog(vd, &p, NULL) > 0)
295                accumulate(p);
296        dump();
297}
298
299static void
300usage(void)
301{
302        fprintf(stderr,
303            "usage: varnishtop %s [-1fV] [-n varnish_name]\n", VSL_USAGE);
304        exit(1);
305}
306
307int
308main(int argc, char **argv)
309{
310        struct VSM_data *vd;
311        int o, once = 0;
312        float period = 60; /* seconds */
313
314        vd = VSM_New();
315        VSL_Setup(vd);
316
317        while ((o = getopt(argc, argv, VSL_ARGS "1fVp:")) != -1) {
318                switch (o) {
319                case '1':
320                        AN(VSL_Arg(vd, 'd', NULL));
321                        once = 1;
322                        break;
323                case 'f':
324                        f_flag = 1;
325                        break;
326                case 'p':
327                        errno = 0;
328                        period = strtol(optarg, NULL, 0);
329                        if (errno != 0)  {
330                                fprintf(stderr, "Syntax error, %s is not a number", optarg);
331                                exit(1);
332                        }
333                        break;
334                case 'V':
335                        VCS_Message("varnishtop");
336                        exit(0);
337                case 'm':
338                        fprintf(stderr, "-m is not supported\n");
339                        exit(1);
340                default:
341                        if (VSL_Arg(vd, o, optarg) > 0)
342                                break;
343                        usage();
344                }
345        }
346
347        if (VSL_Open(vd, 1))
348                exit (1);
349
350        if (once) {
351                VSL_NonBlocking(vd, 1);
352                do_once(vd);
353        } else {
354                do_curses(vd, period);
355        }
356        exit(0);
357}
Note: See TracBrowser for help on using the repository browser.