From 3e7e6746c042b874a37d7b06e0d5c84e8a816dec Mon Sep 17 00:00:00 2001 From: des Date: Thu, 28 Jun 2007 13:34:44 +0000 Subject: [PATCH] Rewrite to better handle both the curses case and the one-shot case. git-svn-id: svn+ssh://projects.linpro.no/svn/varnish/trunk@1592 d4fa192b-c00b-0410-8231-f00ffab90ce4 --- varnish-cache/bin/varnishtop/Makefile.am | 2 +- varnish-cache/bin/varnishtop/varnishtop.1 | 28 ++- varnish-cache/bin/varnishtop/varnishtop.c | 267 +++++++++++++++------- 3 files changed, 210 insertions(+), 87 deletions(-) diff --git a/varnish-cache/bin/varnishtop/Makefile.am b/varnish-cache/bin/varnishtop/Makefile.am index 1bfa6d4f..6c058ac1 100644 --- a/varnish-cache/bin/varnishtop/Makefile.am +++ b/varnish-cache/bin/varnishtop/Makefile.am @@ -14,4 +14,4 @@ varnishtop_LDADD = \ $(top_builddir)/lib/libvarnish/libvarnish.la \ $(top_builddir)/lib/libcompat/libcompat.a \ $(top_builddir)/lib/libvarnishapi/libvarnishapi.la \ - ${CURSES_LIBS} + ${CURSES_LIBS} ${PTHREAD_LIBS} diff --git a/varnish-cache/bin/varnishtop/varnishtop.1 b/varnish-cache/bin/varnishtop/varnishtop.1 index 6c3d685f..040f637d 100644 --- a/varnish-cache/bin/varnishtop/varnishtop.1 +++ b/varnish-cache/bin/varnishtop/varnishtop.1 @@ -28,7 +28,7 @@ .\" .\" $Id$ .\" -.Dd June 15, 2007 +.Dd June 28, 2007 .Dt VARNISHTOP 1 .Os .Sh NAME @@ -71,6 +71,8 @@ The following options are available: .It Fl 1 Instead of presenting of a continuously updated display, print the statistics once and exit. +Implies +.Fl d . .It Fl b Include log entries which result from communication with a backend server. @@ -98,7 +100,7 @@ Normally, .Nm will only process entries which are written to the log after it starts. -.Op Fl f +.It Fl f Sort and group only on the first field of each log entry. This is useful when displaying e.g. .Dv stataddr @@ -135,6 +137,18 @@ Exclude log entries which match the specified regular expression. .It Fl x Ar tag Exclude log entries with the specified tag. .El +.Sh EXAMPLES +The following example displays a continuously updated list of the most +frequently requested URLs: +.Bd -literal +varnishtop -i RxURL +.Ed +.Pp +The following example displays a continuously updated list of the most +commonly used user agents: +.Bd -literal +varnishtop -i RxHeader -C -I \\^User-Agent +.Ed .Sh SEE ALSO .Xr varnishd 1 , .Xr varnishhist 1 , @@ -144,12 +158,10 @@ Exclude log entries with the specified tag. .Sh HISTORY The .Nm -utility was developed by +utility was originally developed by .An Poul-Henning Kamp Aq phk@phk.freebsd.dk -in cooperation with Verdens Gang AS and Linpro AS. +in cooperation with Verdens Gang AS and Linpro AS, and later +substantially rewritten by +.An Dag-Erling Sm\(/orgrav Aq des@linpro.no . This manual page was written by .An Dag-Erling Sm\(/orgrav Aq des@linpro.no . -.Sh BUGS -The -.Fl 1 -option currently does not work very well. diff --git a/varnish-cache/bin/varnishtop/varnishtop.c b/varnish-cache/bin/varnishtop/varnishtop.c index 462139ef..ddf6a73a 100644 --- a/varnish-cache/bin/varnishtop/varnishtop.c +++ b/varnish-cache/bin/varnishtop/varnishtop.c @@ -4,6 +4,7 @@ * All rights reserved. * * Author: Poul-Henning Kamp + * Author: Dag-Erling Smørgrav * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -34,6 +35,8 @@ #include #include #include +#include +#include #include #include #include @@ -61,20 +64,72 @@ static unsigned ntop; /*--------------------------------------------------------------------*/ +static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER; + +static int f_flag = 0; + static void -usage(void) +accumulate(const unsigned char *p) { - fprintf(stderr, "usage: varnishtop %s [-1V] [-n varnish_name]\n", VSL_USAGE); - exit(1); + struct top *tp, *tp2; + const unsigned char *q; + unsigned int u; + int i; + + // fprintf(stderr, "%*.*s\n", p[1], p[1], p + 4); + + u = 0; + q = p + 4; + for (i = 0; i < p[1]; i++, q++) { + if (f_flag && (*q == ':' || isspace(*q))) + break; + u += *q; + } + + TAILQ_FOREACH(tp, &top_head, list) { + if (tp->hash != u) + continue; + if (tp->rec[0] != p[0]) + continue; + if (tp->clen != q - p) + continue; + if (memcmp(p + 4, tp->rec + 4, q - (p + 4))) + continue; + tp->count += 1.0; + break; + } + if (tp == NULL) { + ntop++; + tp = calloc(sizeof *tp, 1); + assert(tp != NULL); + tp->hash = u; + tp->count = 1.0; + tp->clen = q - p; + TAILQ_INSERT_TAIL(&top_head, tp, list); + } + memcpy(tp->rec, p, 4 + p[1]); + while (1) { + tp2 = TAILQ_PREV(tp, tophead, list); + if (tp2 == NULL || tp2->count >= tp->count) + break; + TAILQ_REMOVE(&top_head, tp2, list); + TAILQ_INSERT_AFTER(&top_head, tp, tp2, list); + } + while (1) { + tp2 = TAILQ_NEXT(tp, list); + if (tp2 == NULL || tp2->count <= tp->count) + break; + TAILQ_REMOVE(&top_head, tp2, list); + TAILQ_INSERT_BEFORE(tp, tp2, list); + } } static void -upd(void) +update(void) { struct top *tp, *tp2; int l; double t = 0; - unsigned u = 0; static time_t last; time_t now; @@ -84,12 +139,17 @@ upd(void) last = now; erase(); - l = 0; - mvprintw(0, 0, "list length %u\n", ntop); + l = 1; + mvprintw(0, 0, "%*s", COLS - 1, VSL_Name()); + mvprintw(0, 0, "list length %u", ntop); TAILQ_FOREACH_SAFE(tp, &top_head, list, tp2) { if (++l < LINES) { - printw("%10.2f %*.*s\n", - tp->count, tp->rec[1], tp->rec[1], tp->rec + 4); + int len = tp->rec[1]; + if (len > COLS - 20) + len = COLS - 20; + mvprintw(l, 0, "%9.2f %-9.9s %*.*s\n", + tp->count, VSL_tags[tp->rec[0]], + len, len, tp->rec + 4); t = tp->count; } tp->count *= .999; @@ -97,35 +157,139 @@ upd(void) TAILQ_REMOVE(&top_head, tp, list); free(tp); ntop--; - u++; } } - mvprintw(0, 40, "cleaned %u\n", u); refresh(); } +static void * +accumulate_thread(void *arg) +{ + struct VSL_data *vd = arg; + + for (;;) { + unsigned char *p; + int i; + + i = VSL_NextLog(vd, &p); + if (i < 0) + break; + if (i == 0) { + usleep(50000); + continue; + } + + pthread_mutex_lock(&mtx); + accumulate(p); + pthread_mutex_unlock(&mtx); + } + return (arg); +} + +static void +do_curses(struct VSL_data *vd) +{ + pthread_t thr; + int ch; + + if (pthread_create(&thr, NULL, accumulate_thread, vd) != 0) { + fprintf(stderr, "pthread_create(): %s\n", strerror(errno)); + exit(1); + } + + initscr(); + raw(); + noecho(); + nonl(); + intrflush(stdscr, false); + curs_set(0); + erase(); + for (;;) { + pthread_mutex_lock(&mtx); + update(); + pthread_mutex_unlock(&mtx); + + timeout(1000); + switch ((ch = getch())) { + case ERR: + break; + case KEY_RESIZE: + erase(); + break; + case '\014': /* Ctrl-L */ + case '\024': /* Ctrl-T */ + redrawwin(stdscr); + refresh(); + break; + case '\003': /* Ctrl-C */ + raise(SIGINT); + break; + case '\032': /* Ctrl-Z */ + endwin(); + raise(SIGTSTP); + break; + case '\021': /* Ctrl-Q */ + case 'Q': + case 'q': + endwin(); + return; + default: + beep(); + break; + } + } +} + +static void +dump(void) +{ + struct top *tp, *tp2; + int len; + + TAILQ_FOREACH_SAFE(tp, &top_head, list, tp2) { + if (tp->count <= 1.0) + break; + len = tp->rec[1]; + printf("%9.2f %*.*s\n", tp->count, len, len, tp->rec + 4); + } +} + +static void +do_once(struct VSL_data *vd) +{ + unsigned char *p; + + while (VSL_NextLog(vd, &p) > 0) + accumulate(p); + dump(); +} + +static void +usage(void) +{ + fprintf(stderr, "usage: varnishtop %s [-1fV] [-n varnish_name]\n", VSL_USAGE); + exit(1); +} + int main(int argc, char **argv) { - int i, c; - unsigned char *p, *q; struct VSL_data *vd; - unsigned u, v; - struct top *tp, *tp2; - int f_flag = 0; const char *n_arg = NULL; + int i, o, once = 0; vd = VSL_New(); - while ((c = getopt(argc, argv, VSL_ARGS "1fn:V")) != -1) { - i = VSL_Arg(vd, c, optarg); + while ((o = getopt(argc, argv, VSL_ARGS "1fn:V")) != -1) { + i = VSL_Arg(vd, o, optarg); if (i < 0) exit (1); if (i > 0) continue; - switch (c) { + switch (o) { case '1': - VSL_NonBlocking(vd, 1); + VSL_Arg(vd, 'd', NULL); + once = 1; break; case 'n': n_arg = optarg; @@ -144,64 +308,11 @@ main(int argc, char **argv) if (VSL_OpenLog(vd, n_arg)) exit (1); - initscr(); - v = 0; - while (1) { - i = VSL_NextLog(vd, &p); - if (i < 0) - break; - if (i == 0) { - upd(); - usleep(50000); - continue; - } - if (++v > 100) { - upd(); - v = 0; - } - u = 0; - q = p + 4; - for (i = 0; i < p[1]; i++, q++) { - if (f_flag && (*q == ':' || isspace(*q))) - break; - u += *q; - } - TAILQ_FOREACH(tp, &top_head, list) { - if (tp->hash != u) - continue; - if (tp->rec[0] != p[0]) - continue; - if (tp->clen != q - p) - continue; - if (memcmp(p + 4, tp->rec + 4, q - (p + 4))) - continue; - tp->count += 1.0; - break; - } - if (tp == NULL) { - ntop++; - tp = calloc(sizeof *tp, 1); - assert(tp != NULL); - tp->hash = u; - tp->count = 1.0; - tp->clen = q - p; - TAILQ_INSERT_TAIL(&top_head, tp, list); - } - memcpy(tp->rec, p, 4 + p[1]); - while (1) { - tp2 = TAILQ_PREV(tp, tophead, list); - if (tp2 == NULL || tp2->count >= tp->count) - break; - TAILQ_REMOVE(&top_head, tp2, list); - TAILQ_INSERT_AFTER(&top_head, tp, tp2, list); - } - while (1) { - tp2 = TAILQ_NEXT(tp, list); - if (tp2 == NULL || tp2->count <= tp->count) - break; - TAILQ_REMOVE(&top_head, tp2, list); - TAILQ_INSERT_BEFORE(tp, tp2, list); - } + if (once) { + VSL_NonBlocking(vd, 1); + do_once(vd); + } else { + do_curses(vd); } exit(0); } -- 2.39.5