]> err.no Git - varnish/commitdiff
Rewrite to better handle both the curses case and the one-shot case.
authordes <des@d4fa192b-c00b-0410-8231-f00ffab90ce4>
Thu, 28 Jun 2007 13:34:44 +0000 (13:34 +0000)
committerdes <des@d4fa192b-c00b-0410-8231-f00ffab90ce4>
Thu, 28 Jun 2007 13:34:44 +0000 (13:34 +0000)
git-svn-id: svn+ssh://projects.linpro.no/svn/varnish/trunk@1592 d4fa192b-c00b-0410-8231-f00ffab90ce4

varnish-cache/bin/varnishtop/Makefile.am
varnish-cache/bin/varnishtop/varnishtop.1
varnish-cache/bin/varnishtop/varnishtop.c

index 1bfa6d4fe0ba11298ac7e6ff10e17929318bea65..6c058ac143c7844fc7aa84db53ba68ab8258cf2e 100644 (file)
@@ -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}
index 6c3d685fb4a6f1a80a575b71b9305e107a0eabba..040f637ddb67a46a321d08f2f10f983a19f64457 100644 (file)
@@ -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.
index 462139ef8a95bd504cf47e023b59a4e04dfc7344..ddf6a73a3973f5a14f2ab68703828b488b28dd40 100644 (file)
@@ -4,6 +4,7 @@
  * All rights reserved.
  *
  * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
+ * Author: Dag-Erling Smørgrav <des@linpro.no>
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -34,6 +35,8 @@
 #include <ctype.h>
 #include <curses.h>
 #include <errno.h>
+#include <pthread.h>
+#include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -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);
 }