source: bin/varnishhist/varnishhist.c @ babc31

Revision babc31, 6.7 KB checked in by Tollef Fog Heen <tfheen@…>, 5 years ago (diff)

Portability fixes from pkgsrc/NetBSD

Apply portability patches from pkgsrc, thanks to michael for
forwarding those.

Fixes #471

git-svn-id:  http://www.varnish-cache.org/svn/trunk/varnish-cache@3964 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 <sys/types.h>
38#include <curses.h>
39#include <errno.h>
40#include <limits.h>
41#include <math.h>
42#include <pthread.h>
43#include <regex.h>
44#include <signal.h>
45#include <stdio.h>
46#include <stdlib.h>
47#include <string.h>
48#include <unistd.h>
49
50#include "libvarnish.h"
51#include "shmlog.h"
52#include "varnishapi.h"
53
54#define HIST_N 2000 /* how far back we remember */
55#define HIST_LOW -6 /* low end of log range */
56#define HIST_HIGH 3 /* high end of log range */
57#define HIST_RANGE (HIST_HIGH - HIST_LOW)
58#define HIST_RES 100 /* bucket resolution */
59#define HIST_BUCKETS (HIST_RANGE * HIST_RES)
60
61static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
62
63static int delay = 1;
64static unsigned rr_hist[HIST_N];
65static unsigned nhist;
66static unsigned next_hist;
67static unsigned bucket_miss[HIST_BUCKETS];
68static unsigned bucket_hit[HIST_BUCKETS];
69static unsigned char hh[FD_SETSIZE];
70
71static double log_ten;
72
73static int scales[] = {
74        1,
75        2,
76        3,
77        4,
78        5,
79        10,
80        15,
81        20,
82        25,
83        50,
84        100,
85        250,
86        500,
87        1000,
88        2500,
89        5000,
90        10000,
91        25000,
92        50000,
93        100000,
94        INT_MAX
95};
96
97static void
98update(void)
99{
100        int w = COLS / HIST_RANGE;
101        int n = w * HIST_RANGE;
102        unsigned bm[n], bh[n];
103        unsigned max;
104        int i, j, scale;
105
106        erase();
107
108        /* Draw horizontal axis */
109        w = COLS / HIST_RANGE;
110        n = w * HIST_RANGE;
111        for (i = 0; i < n; ++i)
112                mvaddch(LINES - 2, i, '-');
113        for (i = 0, j = HIST_LOW; i < HIST_RANGE; ++i, ++j) {
114                mvaddch(LINES - 2, w * i, '+');
115                mvprintw(LINES - 1, w * i, "|1e%d", j);
116        }
117
118        mvprintw(0, 0, "%*s", COLS - 1, VSL_Name());
119
120        /* count our flock */
121        for (i = 0; i < n; ++i)
122                bm[i] = bh[i] = 0;
123        for (i = 0, max = 1; i < HIST_BUCKETS; ++i) {
124                j = i * n / HIST_BUCKETS;
125                bm[j] += bucket_miss[i];
126                bh[j] += bucket_hit[i];
127                if (bm[j] + bh[j] > max)
128                        max = bm[j] + bh[j];
129        }
130
131        /* scale */
132        for (i = 0; max / scales[i] > LINES - 3; ++i)
133                /* nothing */ ;
134        scale = scales[i];
135
136        mvprintw(0, 0, "1:%d, n = %d", scale, nhist);
137
138        /* show them */
139        for (i = 0; i < n; ++i) {
140                for (j = 0; j < bm[i] / scale; ++j)
141                        mvaddch(LINES - 3 - j, i, '#');
142                for (; j < (bm[i] + bh[i]) / scale; ++j)
143                        mvaddch(LINES - 3 - j, i, '|');
144        }
145
146        refresh();
147}
148
149static int
150h_hist(void *priv, enum shmlogtag tag, unsigned fd, unsigned len,
151    unsigned spec, const char *ptr)
152{
153        double b;
154        int i, j;
155
156        (void)priv;
157        (void)len;
158        (void)spec;
159
160        if (fd >= FD_SETSIZE)
161                /* oops */
162                return (0);
163
164        if (tag == SLT_Hit) {
165                hh[fd] = 1;
166                return (0);
167        }
168        if (tag != SLT_ReqEnd)
169                return (0);
170
171        /* determine processing time */
172#if 1
173        i = sscanf(ptr, "%*d %*f %*f %*f %lf", &b);
174#else
175        i = sscanf(ptr, "%*d %*f %*f %lf", &b);
176#endif
177        assert(i == 1);
178
179        /* select bucket */
180        i = HIST_RES * (log(b) / log_ten);
181        if (i < HIST_LOW * HIST_RES)
182                i = HIST_LOW * HIST_RES;
183        if (i >= HIST_HIGH * HIST_RES)
184                i = HIST_HIGH * HIST_RES - 1;
185        i -= HIST_LOW * HIST_RES;
186        assert(i >= 0);
187        assert(i < HIST_BUCKETS);
188
189        pthread_mutex_lock(&mtx);
190
191        /* phase out old data */
192        if (nhist == HIST_N) {
193                j = rr_hist[next_hist];
194                if (j < 0)  {
195                        assert(bucket_miss[-j] > 0);
196                        bucket_miss[-j]--;
197                } else {
198                        assert(bucket_hit[j] > 0);
199                        bucket_hit[j]--;
200                }
201        } else {
202                ++nhist;
203        }
204
205        /* phase in new data */
206        if (hh[fd] || i == 0) {
207                bucket_hit[i]++;
208                rr_hist[next_hist] = i;
209        } else {
210                bucket_miss[i]++;
211                rr_hist[next_hist] = -i;
212        }
213        if (++next_hist == HIST_N) {
214                next_hist = 0;
215        }
216        hh[fd] = 0;
217
218        pthread_mutex_unlock(&mtx);
219
220        return (0);
221}
222
223static void *
224accumulate_thread(void *arg)
225{
226        struct VSL_data *vd = arg;
227        int i;
228
229        for (;;) {
230                i = VSL_Dispatch(vd, h_hist, NULL);
231                if (i < 0)
232                        break;
233                if (i == 0)
234                        usleep(50000);
235        }
236        return (arg);
237}
238
239static void
240do_curses(struct VSL_data *vd)
241{
242        pthread_t thr;
243        int ch;
244
245        if (pthread_create(&thr, NULL, accumulate_thread, vd) != 0) {
246                fprintf(stderr, "pthread_create(): %s\n", strerror(errno));
247                exit(1);
248        }
249
250        initscr();
251        raw();
252        noecho();
253        nonl();
254        intrflush(stdscr, FALSE);
255        curs_set(0);
256        erase();
257        for (;;) {
258                pthread_mutex_lock(&mtx);
259                update();
260                pthread_mutex_unlock(&mtx);
261
262                timeout(delay * 1000);
263                switch ((ch = getch())) {
264                case ERR:
265                        break;
266#ifdef KEY_RESIZE
267                case KEY_RESIZE:
268                        erase();
269                        break;
270#endif
271                case '\014': /* Ctrl-L */
272                case '\024': /* Ctrl-T */
273                        redrawwin(stdscr);
274                        refresh();
275                        break;
276                case '\003': /* Ctrl-C */
277                        raise(SIGINT);
278                        break;
279                case '\032': /* Ctrl-Z */
280                        endwin();
281                        raise(SIGTSTP);
282                        break;
283                case '\021': /* Ctrl-Q */
284                case 'Q':
285                case 'q':
286                        endwin();
287                        return;
288                case '0':
289                case '1':
290                case '2':
291                case '3':
292                case '4':
293                case '5':
294                case '6':
295                case '7':
296                case '8':
297                case '9':
298                        delay = 1 << (ch - '0');
299                        break;
300                default:
301                        beep();
302                        break;
303                }
304        }
305}
306
307/*--------------------------------------------------------------------*/
308
309static void
310usage(void)
311{
312        fprintf(stderr, "usage: varnishhist "
313            "%s [-n varnish_name] [-V] [-w delay]\n", VSL_USAGE);
314        exit(1);
315}
316
317int
318main(int argc, char **argv)
319{
320        int o;
321        struct VSL_data *vd;
322        const char *n_arg = NULL;
323
324        vd = VSL_New();
325
326        while ((o = getopt(argc, argv, VSL_ARGS "n:Vw:")) != -1) {
327                switch (o) {
328                case 'n':
329                        n_arg = optarg;
330                        break;
331                case 'V':
332                        varnish_version("varnishhist");
333                        exit(0);
334                case 'w':
335                        delay = atoi(optarg);
336                        break;
337                default:
338                        if (VSL_Arg(vd, o, optarg) > 0)
339                                break;
340                        usage();
341                }
342        }
343
344        if (VSL_OpenLog(vd, n_arg))
345                exit(1);
346
347        log_ten = log(10.0);
348
349        do_curses(vd);
350        exit(0);
351}
Note: See TracBrowser for help on using the repository browser.