Commit 4cf923ae authored by Dag Erling Smørgrav's avatar Dag Erling Smørgrav

Rewrite to better handle both the curses case and the one-shot case.


git-svn-id: http://www.varnish-cache.org/svn/trunk/varnish-cache@1592 d4fa192b-c00b-0410-8231-f00ffab90ce4
parent 06071479
......@@ -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}
......@@ -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.
......@@ -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);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment