Commit 9303f55e authored by Poul-Henning Kamp's avatar Poul-Henning Kamp

Move the varnishstat -f argument into varnishapi, it is broadly

applicable and can be implemented more efficiently this way.

The new syntax is an expansion of the old, which allows
"class.ident.name" or just "name" patterns to be specified.

A pattern which starts with '^' excludes the matching fields,
otherwise the pattern includes them.

If the first pattern is an exclude pattern, all fields start
out included, and vice versa.

Notice that "class" and "ident" fields always must have their
trailing '.' even if they are empty.

Each subcomponent can have a '*' suffix, which will ("glob") match
anything.

Multiple "-f" arguments can be given, they will be concatenated.

All patterns will be tested sequentially, and the last one that
matches determines the result.

Example:

	-f "SMA..sma_nreq,^SMA.ba*." -f "shm_*"

This will return:
	SMA.storage_0.sma_nreq
	shm_records
	shm_writes
	...

but not:
	SMA.storage_0.sma_nobj
	SMA.bar.sma_nreq
	sms_nreq
	...




git-svn-id: http://www.varnish-cache.org/svn/trunk/varnish-cache@4911 d4fa192b-c00b-0410-8231-f00ffab90ce4
parent 8a88e7a6
......@@ -49,62 +49,23 @@ SVNID("$Id$")
#include "varnishapi.h"
#include "varnishstat.h"
#define FIELD_EXCLUSION_CHARACTER '^'
int
show_field(const char* field, const char *fields)
{
const char* field_start;
const char* field_end;
int field_length;
int match_value = 1;
if (fields[0] == FIELD_EXCLUSION_CHARACTER) {
match_value = 0;
fields++;
}
field_start = strstr(fields, field);
if (field_start != NULL) {
field_length = strlen( field );
while (field_start != NULL) {
field_end = field_start + field_length;
if ((field_start == fields ||
*(field_start - 1) == ',') &&
(*field_end == ',' || *field_end == '\0'))
return (match_value);
field_start = strstr( field_end, field );
}
}
return (!match_value);
}
/*--------------------------------------------------------------------*/
struct xml_priv {
const char *fields;
};
static int
do_xml_cb(void *priv, const struct vsl_statpt * const pt)
{
uint64_t val;
struct xml_priv *xp;
xp = priv;
if (xp->fields != NULL && !show_field(pt->nm, xp->fields))
return (0);
(void)priv;
assert(!strcmp(pt->fmt, "uint64_t"));
val = *(const volatile uint64_t*)pt->ptr;
printf("\t<stat>\n");
if (strcmp(pt->type, ""))
printf("\t\t<type>%s</type>\n", pt->type);
if (strcmp(pt->class, ""))
printf("\t\t<type>%s</type>\n", pt->class);
if (strcmp(pt->ident, ""))
printf("\t\t<ident>%s</ident>\n", pt->ident);
printf("\t\t<name>%s</name>\n", pt->nm);
printf("\t\t<name>%s</name>\n", pt->name);
printf("\t\t<value>%ju</value>\n", val);
printf("\t\t<flag>%c</flag>\n", pt->flag);
printf("\t\t<description>%s</description>\n", pt->desc);
......@@ -113,19 +74,16 @@ do_xml_cb(void *priv, const struct vsl_statpt * const pt)
}
static void
do_xml(const struct VSL_data *vd, const char* fields)
do_xml(const struct VSL_data *vd)
{
char time_stamp[20];
time_t now;
struct xml_priv xp;
xp.fields = fields;
printf("<?xml version=\"1.0\"?>\n");
now = time(NULL);
(void)strftime(time_stamp, 20, "%Y-%m-%dT%H:%M:%S", localtime(&now));
printf("<varnishstat timestamp=\"%s\">\n", time_stamp);
(void)VSL_IterStat(vd, do_xml_cb, &xp);
(void)VSL_IterStat(vd, do_xml_cb, NULL);
printf("</varnishstat>\n");
}
......@@ -133,7 +91,6 @@ do_xml(const struct VSL_data *vd, const char* fields)
struct once_priv {
double up;
const char *fields;
int pad;
};
......@@ -145,16 +102,14 @@ do_once_cb(void *priv, const struct vsl_statpt * const pt)
int i;
op = priv;
if (op->fields != NULL && !show_field(pt->nm, op->fields))
return (0);
assert(!strcmp(pt->fmt, "uint64_t"));
val = *(const volatile uint64_t*)pt->ptr;
i = 0;
if (strcmp(pt->type, ""))
i += printf("%s.", pt->type);
if (strcmp(pt->class, ""))
i += printf("%s.", pt->class);
if (strcmp(pt->ident, ""))
i += printf("%s.", pt->ident);
i += printf("%s", pt->nm);
i += printf("%s", pt->name);
if (i > op->pad)
op->pad = i + 1;
printf("%*.*s", op->pad - i, op->pad - i, "");
......@@ -166,13 +121,12 @@ do_once_cb(void *priv, const struct vsl_statpt * const pt)
}
static void
do_once(const struct VSL_data *vd, const struct varnish_stats *VSL_stats, const char* fields)
do_once(const struct VSL_data *vd, const struct varnish_stats *VSL_stats)
{
struct once_priv op;
memset(&op, 0, sizeof op);
op.up = VSL_stats->uptime;
op.fields = fields;
op.pad = 18;
(void)VSL_IterStat(vd, do_once_cb, &op);
......@@ -180,6 +134,36 @@ do_once(const struct VSL_data *vd, const struct varnish_stats *VSL_stats, const
/*--------------------------------------------------------------------*/
static int
do_list_cb(void *priv, const struct vsl_statpt * const pt)
{
int i;
(void)priv;
i = 0;
if (strcmp(pt->class, ""))
i += fprintf(stderr, "%s.", pt->class);
if (strcmp(pt->ident, ""))
i += fprintf(stderr, "%s.", pt->ident);
i += fprintf(stderr, "%s", pt->name);
if (i < 30)
fprintf(stderr, "%*s", i - 30, "");
fprintf(stderr, " %s\n", pt->desc);
return (0);
}
static void
list_fields(const struct VSL_data *vd)
{
fprintf(stderr, "Varnishstat -f option fields:\n");
fprintf(stderr, "Field name Description\n");
fprintf(stderr, "---------- -----------\n");
(void)VSL_IterStat(vd, do_list_cb, NULL);
}
/*--------------------------------------------------------------------*/
static void
usage(void)
{
......@@ -204,66 +188,6 @@ usage(void)
exit(1);
}
static void
list_fields(void)
{
fprintf(stderr, "Varnishstat -f option fields:\n");
fprintf(stderr, "Field name Description\n");
fprintf(stderr, "---------- -----------\n");
#define MAC_STAT(n, t, l, f, d) \
do { \
fprintf(stderr, "%-20s %s\n", #n, d); \
} while (0);
#include "stat_field.h"
#undef MAC_STAT
}
static int
valid_fields(const char* fields)
{
int i, valid_field, field_length;
const char *all_fields[] = {
#define MAC_STAT(n, t, l, f, d) \
#n,
#include "stat_field.h"
#undef MAC_STAT
NULL };
const char *field_start, *field_end;
if (fields[0] == FIELD_EXCLUSION_CHARACTER)
fields++;
for (field_start = fields; ; field_start = field_end + 1) {
field_end = strchr(field_start, ',');
if (field_end != NULL)
field_length = field_end - field_start;
else
field_length = strlen(field_start);
valid_field = 0;
for (i = 0; all_fields[i] != NULL; i++) {
if (strncmp(field_start, all_fields[i], field_length)
== 0 && field_length == strlen( all_fields[i])) {
valid_field = 1;
break;
}
}
if (!valid_field) {
(void)fputs("The field '", stderr);
(void)fwrite(field_start, 1, field_length, stderr);
(void)fputs("' is not a valid field\n", stderr);
return (0);
}
if (field_end == NULL || *field_end == '\0')
break;
}
return (1);
}
int
main(int argc, char * const *argv)
{
......@@ -271,7 +195,6 @@ main(int argc, char * const *argv)
struct VSL_data *vd;
const struct varnish_stats *VSL_stats;
int delay = 1, once = 0, xml = 0;
const char *fields = NULL;
vd = VSL_New();
......@@ -281,10 +204,12 @@ main(int argc, char * const *argv)
once = 1;
break;
case 'f':
fields = optarg;
(void)VSL_Stat_Arg(vd, c, optarg);
break;
case 'l':
list_fields();
if (VSL_Open(vd))
exit(1);
list_fields(vd);
exit(0);
case 'V':
varnish_version("varnishstat");
......@@ -308,17 +233,12 @@ main(int argc, char * const *argv)
if ((VSL_stats = VSL_OpenStats(vd)) == NULL)
exit(1);
if (fields != NULL && !valid_fields(fields)) {
usage();
exit(1);
}
if (xml)
do_xml(vd, fields);
do_xml(vd);
else if (once)
do_once(vd, VSL_stats, fields);
do_once(vd, VSL_stats);
else
do_curses(vd, VSL_stats, delay, fields);
do_curses(vd, VSL_stats, delay);
exit(0);
}
......@@ -27,5 +27,4 @@
*
*/
int show_field(const char* field, const char *fields);
void do_curses(struct VSL_data *vd, const struct varnish_stats *VSL_stats, int delay, const char *fields);
void do_curses(struct VSL_data *vd, const struct varnish_stats *VSL_stats, int delay);
......@@ -65,21 +65,13 @@ struct pt {
static VTAILQ_HEAD(, pt) pthead = VTAILQ_HEAD_INITIALIZER(pthead);
struct curses_priv {
const char *fields;
};
static int
do_curses_cb(void *priv, const struct vsl_statpt * const sp)
{
struct curses_priv *cp;
struct pt *pt;
char buf[128];
cp = priv;
if (cp->fields != NULL && !show_field(sp->nm, cp->fields))
return (0);
(void)priv;
assert(!strcmp(sp->fmt, "uint64_t"));
pt = calloc(sizeof *pt, 1);
......@@ -91,15 +83,15 @@ do_curses_cb(void *priv, const struct vsl_statpt * const sp)
pt->type = sp->flag;
*buf = '\0';
if (strcmp(sp->type, "")) {
strcat(buf, sp->type);
if (strcmp(sp->class, "")) {
strcat(buf, sp->class);
strcat(buf, ".");
}
if (strcmp(sp->ident, "")) {
strcat(buf, sp->ident);
strcat(buf, ".");
}
strcat(buf, sp->nm);
strcat(buf, sp->name);
strcat(buf, " - ");
strcat(buf, sp->desc);
pt->name = strdup(buf);
......@@ -108,9 +100,8 @@ do_curses_cb(void *priv, const struct vsl_statpt * const sp)
}
static void
prep_pts(const struct VSL_data *vd, const char *fields)
prep_pts(const struct VSL_data *vd)
{
struct curses_priv cp;
struct pt *pt, *pt2;
VTAILQ_FOREACH_SAFE(pt, &pthead, next, pt2) {
......@@ -118,10 +109,8 @@ prep_pts(const struct VSL_data *vd, const char *fields)
free(pt->name);
free(pt);
}
cp.fields = fields;
(void)VSL_IterStat(vd, do_curses_cb, &cp);
(void)VSL_IterStat(vd, do_curses_cb, NULL);
}
static void
......@@ -135,7 +124,7 @@ myexp(double *acc, double val, unsigned *n, unsigned nmax)
void
do_curses(struct VSL_data *vd, const struct varnish_stats *VSL_stats,
int delay, const char *fields)
int delay)
{
intmax_t ju;
struct timeval tv;
......@@ -158,7 +147,7 @@ do_curses(struct VSL_data *vd, const struct varnish_stats *VSL_stats,
/*
* Initialization goes in outher loop
*/
prep_pts(vd, fields);
prep_pts(vd);
AC(erase());
AC(refresh());
......
......@@ -612,9 +612,9 @@ do_stat_cb(void *priv, const struct vsl_statpt * const pt)
const char *p = sp->target;
int i;
if (strcmp(pt->type, "")) {
i = strlen(pt->type);
if (memcmp(pt->type, p, i))
if (strcmp(pt->class, "")) {
i = strlen(pt->class);
if (memcmp(pt->class, p, i))
return (0);
p += i;
if (*p != '.')
......@@ -630,7 +630,7 @@ do_stat_cb(void *priv, const struct vsl_statpt * const pt)
return (0);
p++;
}
if (strcmp(pt->nm, p))
if (strcmp(pt->name, p))
return (0);
assert(!strcmp(pt->fmt, "uint64_t"));
......
......@@ -75,9 +75,9 @@ void vsl_itern(const struct VSL_data *vd, struct shmalloc **pp);
for((var) = vsl_iter0((vd)); (var) != NULL; vsl_itern((vd), &(var)))
struct vsl_statpt {
const char *type; /* stat struct type */
const char *class; /* stat struct type */
const char *ident; /* stat struct ident */
const char *nm; /* field name */
const char *name; /* field name */
const char *fmt; /* field format ("uint64_t") */
int flag; /* 'a' = counter, 'i' = gauge */
const char *desc; /* description */
......
......@@ -10,6 +10,7 @@ libvarnishapi_la_SOURCES = \
vsl.h \
\
../libvarnish/assert.c \
../libvarnish/argv.c \
../libvarnish/svn_version.c \
../libvarnish/version.c \
../libvarnish/vin.c \
......
......@@ -47,6 +47,7 @@ SVNID("$Id$")
#include "shmlog.h"
#include "vre.h"
#include "vbm.h"
#include "vqueue.h"
#include "miniobj.h"
#include "varnishapi.h"
......@@ -81,6 +82,8 @@ VSL_New(void)
vd->rbuf = malloc(vd->rbuflen);
assert(vd->rbuf != NULL);
VTAILQ_INIT(&vd->sf_list);
return (vd);
}
......@@ -89,6 +92,7 @@ VSL_New(void)
void
VSL_Delete(struct VSL_data *vd)
{
struct vsl_sf *sf;
VSL_Close(vd);
vbit_destroy(vd->vbm_client);
......@@ -98,6 +102,16 @@ VSL_Delete(struct VSL_data *vd)
free(vd->n_opt);
free(vd->rbuf);
free(vd->fname);
while(!VTAILQ_EMPTY(&vd->sf_list)) {
sf = VTAILQ_FIRST(&vd->sf_list);
VTAILQ_REMOVE(&vd->sf_list, sf, next);
free(sf->class);
free(sf->ident);
free(sf->name);
free(sf);
}
free(vd);
}
......
......@@ -33,6 +33,20 @@
#define SLEEP_USEC (50*1000)
#define TIMEOUT_USEC (5*1000*1000)
struct vsl_sf {
unsigned magic;
#define VSL_SF_MAGIC 0x558478dd
VTAILQ_ENTRY(vsl_sf) next;
int flags;
#define VSL_SF_EXCL (1 << 0)
#define VSL_SF_CL_WC (1 << 1)
#define VSL_SF_ID_WC (1 << 2)
#define VSL_SF_NM_WC (1 << 3)
char *class;
char *ident;
char *name;
};
struct VSL_data {
unsigned magic;
#define VSL_MAGIC 0x6e3bd69b
......@@ -45,6 +59,13 @@ struct VSL_data {
void *vsl_end;
unsigned alloc_seq;
/* Stuff relating the stats fields start here */
int sf_init;
VTAILQ_HEAD(, vsl_sf) sf_list;
/* Stuff relating the log records below here */
unsigned char *log_start;
unsigned char *log_end;
unsigned char *log_ptr;
......
......@@ -44,9 +44,11 @@ SVNID("$Id$")
#include <unistd.h>
#include "vas.h"
#include "argv.h"
#include "shmlog.h"
#include "vre.h"
#include "vbm.h"
#include "vqueue.h"
#include "miniobj.h"
#include "varnishapi.h"
......@@ -242,12 +244,93 @@ VSL_Log_Arg(struct VSL_data *vd, int arg, const char *opt)
/*--------------------------------------------------------------------*/
static int
vsl_sf_arg(struct VSL_data *vd, const char *opt)
{
struct vsl_sf *sf;
char **av, *q, *p;
int i;
CHECK_OBJ_NOTNULL(vd, VSL_MAGIC);
if (VTAILQ_EMPTY(&vd->sf_list)) {
if (*opt == '^')
vd->sf_init = 1;
}
av = ParseArgv(opt, ARGV_COMMA);
AN(av);
if (av[0] != NULL) {
fprintf(stderr, "Parse error: %s", av[0]);
exit (1);
}
for (i = 1; av[i] != NULL; i++) {
ALLOC_OBJ(sf, VSL_SF_MAGIC);
AN(sf);
VTAILQ_INSERT_TAIL(&vd->sf_list, sf, next);
p = av[i];
if (*p == '^') {
sf->flags |= VSL_SF_EXCL;
p++;
}
q = strchr(p, '.');
if (q != NULL) {
*q++ = '\0';
if (*p != '\0')
REPLACE(sf->class, p);
p = q;
if (*p != '\0') {
q = strchr(p, '.');
if (q != NULL) {
*q++ = '\0';
if (*p != '\0')
REPLACE(sf->ident, p);
p = q;
}
}
}
if (*p != '\0') {
REPLACE(sf->name, p);
}
/* Check for wildcards */
if (sf->class != NULL) {
q = strchr(sf->class, '*');
if (q != NULL && q[1] == '\0') {
*q = '\0';
sf->flags |= VSL_SF_CL_WC;
}
}
if (sf->ident != NULL) {
q = strchr(sf->ident, '*');
if (q != NULL && q[1] == '\0') {
*q = '\0';
sf->flags |= VSL_SF_ID_WC;
}
}
if (sf->name != NULL) {
q = strchr(sf->name, '*');
if (q != NULL && q[1] == '\0') {
*q = '\0';
sf->flags |= VSL_SF_NM_WC;
}
}
}
FreeArgv(av);
return (1);
}
/*--------------------------------------------------------------------*/
int
VSL_Stat_Arg(struct VSL_data *vd, int arg, const char *opt)
{
CHECK_OBJ_NOTNULL(vd, VSL_MAGIC);
switch (arg) {
case 'f': return (vsl_sf_arg(vd, opt));
case 'n': return (vsl_n_arg(vd, opt));
default:
return (0);
......
......@@ -44,6 +44,7 @@ SVNID("$Id$")
#include "shmlog.h"
#include "vre.h"
#include "vbm.h"
#include "vqueue.h"
#include "miniobj.h"
#include "varnishapi.h"
......
......@@ -39,6 +39,7 @@ SVNID("$Id$")
#include "vas.h"
#include "shmlog.h"
#include "vre.h"
#include "vqueue.h"
#include "miniobj.h"
#include "varnishapi.h"
......@@ -52,6 +53,7 @@ VSL_OpenStats(struct VSL_data *vd)
struct shmalloc *sha;
CHECK_OBJ_NOTNULL(vd, VSL_MAGIC);
if (VSL_Open(vd))
return (NULL);
sha = vsl_find_alloc(vd, VSL_CLASS_STAT, "", "");
......@@ -63,22 +65,63 @@ VSL_OpenStats(struct VSL_data *vd)
* -1 -> unknown stats encountered.
*/
static inline int
iter_test(const char *s1, const char *s2, int wc)
{
if (s1 == NULL)
return (0);
if (!wc)
return (strcmp(s1, s2));
for (; *s1 != '\0' && *s1 == *s2; s1++, s2++)
continue;
return (*s1 != '\0');
}
static int
iter_call(const struct VSL_data *vd, vsl_stat_f *func, void *priv,
const struct vsl_statpt *const sp)
{
struct vsl_sf *sf;
int good = vd->sf_init;
if (VTAILQ_EMPTY(&vd->sf_list))
return (func(priv, sp));
VTAILQ_FOREACH(sf, &vd->sf_list, next) {
if (iter_test(sf->class, sp->class, sf->flags & VSL_SF_CL_WC))
continue;
if (iter_test(sf->ident, sp->ident, sf->flags & VSL_SF_ID_WC))
continue;
if (iter_test(sf->name, sp->name, sf->flags & VSL_SF_NM_WC))
continue;
if (sf->flags & VSL_SF_EXCL)
good = 0;
else
good = 1;
}
if (!good)
return (0);
return (func(priv, sp));
}
static int
iter_main(struct shmalloc *sha, vsl_stat_f *func, void *priv)
iter_main(const struct VSL_data *vd, struct shmalloc *sha, vsl_stat_f *func,
void *priv)
{
struct varnish_stats *st = SHA_PTR(sha);
struct vsl_statpt sp;
int i;
sp.type = "";
sp.class = "";
sp.ident = "";
#define MAC_STAT(nn, tt, ll, ff, dd) \
sp.nm = #nn; \
sp.name = #nn; \
sp.fmt = #tt; \
sp.flag = ff; \
sp.desc = dd; \
sp.ptr = &st->nn; \
i = func(priv, &sp); \
i = iter_call(vd, func, priv, &sp); \
if (i) \
return(i);
#include "stat_field.h"
......@@ -87,21 +130,22 @@ iter_main(struct shmalloc *sha, vsl_stat_f *func, void *priv)
}
static int
iter_sma(struct shmalloc *sha, vsl_stat_f *func, void *priv)
iter_sma(const struct VSL_data *vd, struct shmalloc *sha, vsl_stat_f *func,
void *priv)
{
struct varnish_stats_sma *st = SHA_PTR(sha);
struct vsl_statpt sp;
int i;
sp.type = VSL_TYPE_STAT_SMA;
sp.class = VSL_TYPE_STAT_SMA;
sp.ident = sha->ident;
#define MAC_STAT_SMA(nn, tt, ll, ff, dd) \
sp.nm = #nn; \
sp.name = #nn; \
sp.fmt = #tt; \
sp.flag = ff; \
sp.desc = dd; \
sp.ptr = &st->nn; \
i = func(priv, &sp); \
i = iter_call(vd, func, priv, &sp); \
if (i) \
return(i);
#include "stat_field.h"
......@@ -121,9 +165,9 @@ VSL_IterStat(const struct VSL_data *vd, vsl_stat_f *func, void *priv)
if (strcmp(sha->class, VSL_CLASS_STAT))
continue;
if (!strcmp(sha->type, VSL_TYPE_STAT))
i = iter_main(sha, func, priv);
i = iter_main(vd, sha, func, priv);
else if (!strcmp(sha->type, VSL_TYPE_STAT_SMA))
i = iter_sma(sha, func, priv);
i = iter_sma(vd, sha, func, priv);
else
i = -1;
if (i != 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