[master] 4a0eee1 Beginnings of new varnishncsa
Martin Blix Grydeland
martin at varnish-cache.org
Tue Nov 19 17:37:57 CET 2013
commit 4a0eee12f23c65f3ff275e81ef630e8611a91ecd
Author: Martin Blix Grydeland <martin at varnish-software.com>
Date: Fri Nov 1 18:35:02 2013 +0100
Beginnings of new varnishncsa
diff --git a/bin/Makefile.am b/bin/Makefile.am
index 0700f27..124cb98 100644
--- a/bin/Makefile.am
+++ b/bin/Makefile.am
@@ -3,7 +3,7 @@
# Disabling building of the tools while api is in flux
#SUBDIRS = varnishadm varnishd varnishlog varnishncsa varnishreplay varnishtest
-SUBDIRS = varnishadm varnishd varnishlog varnishtest
+SUBDIRS = varnishadm varnishd varnishlog varnishtest varnishncsa
if VARNISH_CURSES
#SUBDIRS += varnishhist varnishstat varnishtop
diff --git a/bin/varnishncsa/Makefile.am b/bin/varnishncsa/Makefile.am
index 7db8e89..9912d4c 100644
--- a/bin/varnishncsa/Makefile.am
+++ b/bin/varnishncsa/Makefile.am
@@ -8,18 +8,22 @@ dist_man_MANS = varnishncsa.1
varnishncsa_SOURCES = \
varnishncsa.c \
- base64.c \
+ varnishncsa_options.h \
+ varnishncsa_options.c \
base64.h \
- $(top_builddir)/lib/libvarnish/vas.c \
- $(top_builddir)/lib/libvarnish/flopen.c \
- $(top_builddir)/lib/libvarnish/version.c \
- $(top_builddir)/lib/libvarnish/vsb.c \
- $(top_builddir)/lib/libvarnish/vpf.c
+ base64.c \
+ $(top_srcdir)/lib/libvarnishtools/vut.c \
+ $(top_srcdir)/lib/libvarnish/vas.c \
+ $(top_srcdir)/lib/libvarnish/flopen.c \
+ $(top_srcdir)/lib/libvarnish/version.c \
+ $(top_srcdir)/lib/libvarnish/vpf.c \
+ $(top_srcdir)/lib/libvarnish/vtim.c \
+ $(top_srcdir)/lib/libvarnish/vsb.c
varnishncsa_LDADD = \
$(top_builddir)/lib/libvarnishcompat/libvarnishcompat.la \
$(top_builddir)/lib/libvarnishapi/libvarnishapi.la \
- ${RT_LIBS} ${LIBM} ${PTHREAD_LIBS}
+ ${RT_LIBS} ${LIBM}
varnishncsa.1: $(top_srcdir)/doc/sphinx/reference/varnishncsa.rst
if HAVE_RST2MAN
diff --git a/bin/varnishncsa/varnishncsa.c b/bin/varnishncsa/varnishncsa.c
index 4674974..43412fc 100644
--- a/bin/varnishncsa/varnishncsa.c
+++ b/bin/varnishncsa/varnishncsa.c
@@ -6,6 +6,7 @@
* Author: Anders Berg <andersb at vgnett.no>
* Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
* Author: Tollef Fog Heen <tfheen at varnish-software.com>
+ * Author: Martin Blix Grydeland <mbgrydeland at varnish-software.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -54,957 +55,860 @@
* %q Query string
* %H Protocol version
*
- * TODO: - Maybe rotate/compress log
*/
#include "config.h"
-#include <ctype.h>
-#include <errno.h>
-#include <signal.h>
-#include <stdint.h>
-#include <stdio.h>
#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
#include <string.h>
-#include <strings.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <ctype.h>
#include <time.h>
-#include <unistd.h>
#include "base64.h"
-#include "vapi/vsl.h"
#include "vapi/vsm.h"
+#include "vapi/vsl.h"
+#include "vapi/voptget.h"
#include "vas.h"
#include "vcs.h"
-#include "vpf.h"
-#include "vqueue.h"
#include "vsb.h"
+#include "vut.h"
+#include "vqueue.h"
+#include "miniobj.h"
+
+#define TIME_FMT "[%d/%b/%Y:%T %z]"
+#define FORMAT "%h %l %u %t \"%r\" %s %b \"%{Referer}i\" \"%{User-agent}i\""
+static const char progname[] = "varnishncsa2";
+
+struct format;
+struct fragment;
+
+enum e_frag {
+ F_H, /* %H Proto */
+ F_U, /* %U URL path */
+ F_q, /* %q Query string */
+ F_b, /* %b Bytes */
+ F_h, /* %h Host name / IP Address */
+ F_m, /* %m Method */
+ F_s, /* %s Status */
+ F_tstart, /* Time start */
+ F_tend, /* Time end */
+ F_ttfb, /* %{Varnish:time_firstbyte}x */
+ F_host, /* Host header */
+ F_auth, /* Authorization header */
+ F__MAX,
+};
-#include "compat/daemon.h"
+struct fragment {
+ unsigned gen;
+ const char *b, *e;
+};
+
+typedef int format_f(const struct format *format);
-static volatile sig_atomic_t reopen;
+struct format {
+ unsigned magic;
+#define FORMAT_MAGIC 0xC3119CDA
-struct hdr {
- char *key;
- char *value;
- VTAILQ_ENTRY(hdr) list;
+ VTAILQ_ENTRY(format) list;
+ format_f *func;
+ struct fragment *frag;
+ char *string;
+ const char *const *strptr;
+ char time_type;
+ char *time_fmt;
};
-static struct logline {
- char *df_H; /* %H, Protocol version */
- char *df_U; /* %U, URL path */
- char *df_q; /* %q, query string */
- char *df_b; /* %b, Bytes */
- char *df_h; /* %h (host name / IP adress)*/
- char *df_m; /* %m, Request method*/
- char *df_s; /* %s, Status */
- struct tm df_t; /* %t, Date and time, received */
- char *df_u; /* %u, Remote user */
- char *df_ttfb; /* Time to first byte */
- double df_D; /* %D, time taken to serve the request,
- in microseconds, also used for %T */
- const char *df_hitmiss; /* Whether this is a hit or miss */
- const char *df_handling; /* How the request was handled
- (hit/miss/pass/pipe) */
- int active; /* Is log line in an active trans */
- int complete; /* Is log line complete */
- uint64_t bitmap; /* Bitmap for regex matches */
- VTAILQ_HEAD(, hdr) req_headers; /* Request headers */
- VTAILQ_HEAD(, hdr) resp_headers; /* Response headers */
- VTAILQ_HEAD(, hdr) vcl_log; /* VLC_Log entries */
-} **ll;
-
-static struct VSM_data *vd;
-
-static size_t nll;
-
-static int m_flag = 0;
-
-static const char *c_format;
-static const char *b_format;
+struct watch {
+ unsigned magic;
+#define WATCH_MAGIC 0xA7D4005C
-static int
-isprefix(const char *str, const char *prefix, const char *end,
- const char **next)
-{
-
- while (str < end && *str && *prefix &&
- tolower((int)*str) == tolower((int)*prefix))
- ++str, ++prefix;
- if (*str && *str != ' ')
- return (0);
- if (next) {
- while (str < end && *str && *str == ' ')
- ++str;
- *next = str;
- }
- return (1);
-}
+ VTAILQ_ENTRY(watch) list;
+ char *key;
+ unsigned keylen;
+ struct fragment frag;
+};
+VTAILQ_HEAD(watch_head, watch);
+
+struct ctx {
+ /* Options */
+ int a_opt;
+ char *w_arg;
+
+ FILE *fo;
+ struct vsb *vsb;
+ unsigned gen;
+ VTAILQ_HEAD(,format) format;
+
+ /* State */
+ struct watch_head watch_vcl_log;
+ struct watch_head watch_reqhdr;
+ struct watch_head watch_resphdr;
+ struct fragment frag[F__MAX];
+ const char *hitmiss;
+ const char *handling;
+} CTX;
-/*
- * Returns a copy of the first consecutive sequence of non-space
- * characters in the string in dst. dst will be free'd first if non-NULL.
- */
static void
-trimfield(char **dst, const char *str, const char *end)
+usage(int status)
{
- size_t len;
-
- /* free if already set */
- if (*dst != NULL) {
- free(*dst);
- *dst = NULL;
- }
-
- /* skip leading space */
- while (str < end && *str && *str == ' ')
- ++str;
+ const char **opt;
- /* seek to end of field */
- for (len = 0; &str[len] < end && str[len]; ++len)
- if (str[len] == ' ')
- break;
-
- /* copy and return */
- *dst = malloc(len + 1);
- assert(*dst != NULL);
- memcpy(*dst, str, len);
- (*dst)[len] = '\0';
+ fprintf(stderr, "Usage: %s <options>\n\n", progname);
+ fprintf(stderr, "Options:\n");
+ for (opt = vopt_usage; *opt != NULL; opt += 2)
+ fprintf(stderr, " %-25s %s\n", *opt, *(opt + 1));
+ exit(status);
}
-/*
- * Returns a copy of the entire string with leading and trailing spaces
- * trimmed in dst. dst will be free'd first if non-NULL.
- */
static void
-trimline(char **dst, const char *str, const char *end)
+openout(int append)
{
- size_t len;
-
- /* free if already set */
- if (*dst != NULL) {
- free(*dst);
- *dst = NULL;
- }
- /* skip leading space */
- while (str < end && *str && *str == ' ')
- ++str;
-
- /* seek to end of string */
- for (len = 0; &str[len] < end && str[len]; ++len)
- /* nothing */ ;
-
- /* trim trailing space */
- while (len && str[len - 1] == ' ')
- --len;
-
- /* copy and return */
- *dst = malloc(len + 1);
- assert(*dst != NULL);
- memcpy(*dst, str, len);
- (*dst)[len] = '\0';
+ AN(CTX.w_arg);
+ CTX.fo = fopen(CTX.w_arg, append ? "a" : "w");
+ if (CTX.fo == NULL)
+ VUT_Error(1, "Can't open output file (%s)", strerror(errno));
}
-static char *
-req_header(struct logline *l, const char *name)
+static int __match_proto__(VUT_cb_f)
+rotateout(void)
{
- struct hdr *h;
- VTAILQ_FOREACH(h, &l->req_headers, list) {
- if (strcasecmp(h->key, name) == 0) {
- return (h->value);
- }
- }
- return (NULL);
-}
-static char *
-resp_header(struct logline *l, const char *name)
-{
- struct hdr *h;
- VTAILQ_FOREACH(h, &l->resp_headers, list) {
- if (strcasecmp(h->key, name) == 0) {
- return (h->value);
- }
- }
- return (NULL);
+ AN(CTX.w_arg);
+ AN(CTX.fo);
+ fclose(CTX.fo);
+ openout(0);
+ AN(CTX.fo);
+ return (0);
}
-static char *
-vcl_log(struct logline *l, const char *name)
+static int __match_proto__(VUT_cb_f)
+flushout(void)
{
- struct hdr *h;
- VTAILQ_FOREACH(h, &l->vcl_log, list) {
- if (strcasecmp(h->key, name) == 0) {
- return (h->value);
- }
- }
- return (NULL);
+
+ AN(CTX.fo);
+ if (fflush(CTX.fo))
+ return (-5);
+ return (0);
}
-static void
-clean_logline(struct logline *lp)
+static inline int
+vsb_fcat(struct vsb *vsb, const struct fragment *f, const char *dflt)
{
- struct hdr *h, *h2;
-#define freez(x) do { if (x) free(x); x = NULL; } while (0);
- freez(lp->df_H);
- freez(lp->df_U);
- freez(lp->df_q);
- freez(lp->df_b);
- freez(lp->df_h);
- freez(lp->df_m);
- freez(lp->df_s);
- freez(lp->df_u);
- freez(lp->df_ttfb);
- VTAILQ_FOREACH_SAFE(h, &lp->req_headers, list, h2) {
- VTAILQ_REMOVE(&lp->req_headers, h, list);
- freez(h->key);
- freez(h->value);
- freez(h);
- }
- VTAILQ_FOREACH_SAFE(h, &lp->resp_headers, list, h2) {
- VTAILQ_REMOVE(&lp->resp_headers, h, list);
- freez(h->key);
- freez(h->value);
- freez(h);
- }
- VTAILQ_FOREACH_SAFE(h, &lp->vcl_log, list, h2) {
- VTAILQ_REMOVE(&lp->vcl_log, h, list);
- freez(h->key);
- freez(h->value);
- freez(h);
+
+ if (f->gen == CTX.gen) {
+ assert(f->b <= f->e);
+ return (VSB_bcat(vsb, f->b, f->e - f->b));
}
-#undef freez
- memset(lp, 0, sizeof *lp);
+ if (dflt)
+ return (VSB_cat(vsb, dflt));
+ return (-1);
}
-static int
-collect_backend(struct logline *lp, enum VSL_tag_e tag, unsigned spec,
- const char *ptr, unsigned len)
+static int __match_proto__(format_f)
+format_string(const struct format *format)
{
- const char *end, *next, *split;
- struct hdr *h;
- size_t l;
-
- assert(spec & VSL_S_BACKEND);
- end = ptr + len;
-
- switch (tag) {
- case SLT_BackendOpen:
- if (lp->active || lp->df_h != NULL) {
- /* New start for active line,
- clean it and start from scratch */
- clean_logline(lp);
- }
- lp->active = 1;
- if (isprefix(ptr, "default", end, &next))
- trimfield(&lp->df_h, next, end);
- else
- trimfield(&lp->df_h, ptr, end);
- break;
-
- case SLT_BereqMethod:
- if (!lp->active)
- break;
- if (lp->df_m != NULL) {
- clean_logline(lp);
- break;
- }
- trimline(&lp->df_m, ptr, end);
- break;
- case SLT_BereqURL: {
- char *qs;
+ CHECK_OBJ_NOTNULL(format, FORMAT_MAGIC);
+ AN(format->string);
+ AZ(VSB_cat(CTX.vsb, format->string));
+ return (1);
+}
- if (!lp->active)
- break;
- if (lp->df_U != NULL || lp->df_q != NULL) {
- clean_logline(lp);
- break;
- }
- qs = memchr(ptr, '?', len);
- if (qs) {
- trimline(&lp->df_U, ptr, qs);
- trimline(&lp->df_q, qs, end);
- } else {
- trimline(&lp->df_U, ptr, end);
- }
- break;
- }
+static int __match_proto__(format_f)
+format_strptr(const struct format *format)
+{
- case SLT_BereqProtocol:
- if (!lp->active)
- break;
- if (lp->df_H != NULL) {
- clean_logline(lp);
- break;
- }
- trimline(&lp->df_H, ptr, end);
- break;
+ CHECK_OBJ_NOTNULL(format, FORMAT_MAGIC);
+ AN(format->strptr);
+ AN(*format->strptr);
+ AZ(VSB_cat(CTX.vsb, *format->strptr));
+ return (1);
+}
- case SLT_BerespStatus:
- if (!lp->active)
- break;
- if (lp->df_s != NULL) {
- clean_logline(lp);
- break;
- }
- trimline(&lp->df_s, ptr, end);
- break;
+static int __match_proto__(format_f)
+format_fragment(const struct format *format)
+{
- case SLT_BereqHeader:
- case SLT_BerespHeader:
- if (!lp->active)
- break;
- split = memchr(ptr, ':', len);
- if (split == NULL)
- break;
- if (tag == SLT_BerespHeader) {
- if (isprefix(ptr, "content-length:", end, &next))
- trimline(&lp->df_b, next, end);
- else if (isprefix(ptr, "date:", end, &next) &&
- strptime(next, "%a, %d %b %Y %T", &lp->df_t) == NULL) {
- clean_logline(lp);
- }
- } else {
- if (isprefix(ptr, "authorization:", end, &next) &&
- isprefix(next, "basic", end, &next)) {
- trimline(&lp->df_u, next, end);
- }
- }
- h = calloc(1, sizeof(struct hdr));
- AN(h);
- AN(split);
- l = strlen(split);
- trimline(&h->key, ptr, split-1);
- trimline(&h->value, split+1, split+l-1);
- if (tag == SLT_BereqHeader)
- VTAILQ_INSERT_HEAD(&lp->req_headers, h, list);
- else
- VTAILQ_INSERT_HEAD(&lp->resp_headers, h, list);
-
- case SLT_BackendReuse:
- case SLT_BackendClose:
- if (!lp->active)
- break;
- /* got it all */
- lp->complete = 1;
- break;
+ CHECK_OBJ_NOTNULL(format, FORMAT_MAGIC);
+ AN(format->frag);
- default:
- break;
+ if (format->frag->gen != CTX.gen) {
+ if (format->string == NULL)
+ return (-1);
+ AZ(VSB_cat(CTX.vsb, format->string));
+ return (0);
}
+ AZ(vsb_fcat(CTX.vsb, format->frag, NULL));
return (1);
}
-static int
-collect_client(struct logline *lp, enum VSL_tag_e tag, unsigned spec,
- const char *ptr, unsigned len)
+static int __match_proto__(format_f)
+format_time(const struct format *format)
{
- const char *end, *next, *split;
+ double t_start, t_end;
+ char *p;
+ char buf[64];
time_t t;
+ struct tm tm;
+
+ CHECK_OBJ_NOTNULL(format, FORMAT_MAGIC);
+ if (CTX.frag[F_tstart].gen != CTX.gen ||
+ CTX.frag[F_tend].gen != CTX.gen) {
+ if (format->string == NULL)
+ return (-1);
+ AZ(VSB_cat(CTX.vsb, format->string));
+ return (0);
+ }
- assert(spec & VSL_S_CLIENT);
- end = ptr + len;
+ t_start = strtod(CTX.frag[F_tstart].b, &p);
+ if (p != CTX.frag[F_tstart].e)
+ return (-1);
+ t_end = strtod(CTX.frag[F_tend].b, &p);
+ if (p != CTX.frag[F_tend].e)
+ return (-1);
- switch (tag) {
- case SLT_ReqStart:
- if (lp->active || lp->df_h != NULL) {
- /* New start for active line,
- clean it and start from scratch */
- clean_logline(lp);
- }
- lp->active = 1;
- trimfield(&lp->df_h, ptr, end);
+ switch (format->time_type) {
+ case 'D':
+ AZ(VSB_printf(CTX.vsb, "%f", t_end - t_start));
break;
-
- case SLT_ReqMethod:
- if (!lp->active)
- break;
- if (lp->df_m != NULL) {
- clean_logline(lp);
- break;
- }
- trimline(&lp->df_m, ptr, end);
+ case 't':
+ AN(format->time_fmt);
+ t = t_start;
+ localtime_r(&t, &tm);
+ strftime(buf, sizeof buf, format->time_fmt, &tm);
+ AZ(VSB_cat(CTX.vsb, buf));
break;
-
- case SLT_ReqURL: {
- char *qs;
-
- if (!lp->active)
- break;
- if (lp->df_U != NULL || lp->df_q != NULL) {
- clean_logline(lp);
- break;
- }
- qs = memchr(ptr, '?', len);
- if (qs) {
- trimline(&lp->df_U, ptr, qs);
- trimline(&lp->df_q, qs, end);
- } else {
- trimline(&lp->df_U, ptr, end);
- }
+ case 'T':
+ AZ(VSB_printf(CTX.vsb, "%d", (int)(t_end - t_start)));
break;
+ default:
+ WRONG("Time format specifier");
}
- case SLT_ReqProtocol:
- if (!lp->active)
- break;
- if (lp->df_H != NULL) {
- clean_logline(lp);
- break;
- }
- trimline(&lp->df_H, ptr, end);
- break;
-
- case SLT_ObjStatus:
- if (!lp->active)
- break;
- if (lp->df_s != NULL)
- clean_logline(lp);
- else
- trimline(&lp->df_s, ptr, end);
- break;
-
- case SLT_ObjHeader:
- case SLT_ReqHeader:
- if (!lp->active)
- break;
- split = memchr(ptr, ':', len);
- if (split == NULL)
- break;
- if (tag == SLT_ReqHeader &&
- isprefix(ptr, "authorization:", end, &next) &&
- isprefix(next, "basic", end, &next)) {
- trimline(&lp->df_u, next, end);
- } else {
- struct hdr *h;
- h = calloc(1, sizeof(struct hdr));
- AN(h);
- AN(split);
- trimline(&h->key, ptr, split);
- trimline(&h->value, split+1, end);
- if (tag == SLT_ReqHeader)
- VTAILQ_INSERT_HEAD(&lp->req_headers, h, list);
- else
- VTAILQ_INSERT_HEAD(&lp->resp_headers, h, list);
- }
- break;
-
- case SLT_VCL_Log:
- if(!lp->active)
- break;
-
- split = memchr(ptr, ':', len);
- if (split == NULL)
- break;
+ return (1);
+}
- struct hdr *h;
- h = calloc(1, sizeof(struct hdr));
- AN(h);
- AN(split);
+static int __match_proto__(format_f)
+format_requestline(const struct format *format)
+{
- trimline(&h->key, ptr, split);
- trimline(&h->value, split+1, end);
+ (void)format;
+ AZ(vsb_fcat(CTX.vsb, &CTX.frag[F_m], "-"));
+ AZ(VSB_putc(CTX.vsb, ' '));
+ if (CTX.frag[F_host].gen == CTX.gen) {
+ if (strncmp(CTX.frag[F_host].b, "http://", 7))
+ AZ(VSB_cat(CTX.vsb, "http://"));
+ AZ(vsb_fcat(CTX.vsb, &CTX.frag[F_host], NULL));
+ } else
+ AZ(VSB_cat(CTX.vsb, "http://localhost"));
+ AZ(vsb_fcat(CTX.vsb, &CTX.frag[F_U], "-"));
+ AZ(vsb_fcat(CTX.vsb, &CTX.frag[F_q], ""));
+ AZ(VSB_putc(CTX.vsb, ' '));
+ AZ(vsb_fcat(CTX.vsb, &CTX.frag[F_H], "HTTP/1.0"));
+ return (1);
+}
- VTAILQ_INSERT_HEAD(&lp->vcl_log, h, list);
- break;
+static int __match_proto__(format_f)
+format_auth(const struct format *format)
+{
+ char buf[128];
+ char *q;
+
+ if (CTX.frag[F_auth].gen != CTX.gen ||
+ VB64_decode(buf, sizeof buf, CTX.frag[F_auth].b,
+ CTX.frag[F_auth].e)) {
+ if (format->string == NULL)
+ return (-1);
+ AZ(VSB_cat(CTX.vsb, format->string));
+ return (0);
+ }
+ q = strchr(buf, ':');
+ if (q != NULL)
+ *q = '\0';
+ AZ(VSB_cat(CTX.vsb, buf));
+ return (1);
+}
- case SLT_VCL_call:
- if(!lp->active)
- break;
- if (strncmp(ptr, "hit", len) == 0) {
- lp->df_hitmiss = "hit";
- lp->df_handling = "hit";
- } else if (strncmp(ptr, "miss", len) == 0) {
- lp->df_hitmiss = "miss";
- lp->df_handling = "miss";
- } else if (strncmp(ptr, "pass", len) == 0) {
- lp->df_hitmiss = "miss";
- lp->df_handling = "pass";
- } else if (strncmp(ptr, "error", len) == 0) {
- /* Arguably, error isn't a hit or a miss, but
- miss is less wrong */
- lp->df_hitmiss = "miss";
- lp->df_handling = "error";
- } else if (strncmp(ptr, "pipe", len) == 0) {
- /* Just skip piped requests, since we can't
- * print their status code */
- clean_logline(lp);
- break;
- }
- break;
+static int
+print(void)
+{
+ const struct format *f;
+ int i, r = 1;
+
+ VSB_clear(CTX.vsb);
+ VTAILQ_FOREACH(f, &CTX.format, list) {
+ i = (f->func)(f);
+ if (r > i)
+ r = i;
+ }
+ AZ(VSB_putc(CTX.vsb, '\n'));
+ AZ(VSB_finish(CTX.vsb));
+ if (r >= 0) {
+ i = fwrite(VSB_data(CTX.vsb), 1, VSB_len(CTX.vsb), CTX.fo);
+ if (i != VSB_len(CTX.vsb))
+ return (-5);
+ }
+ return (0);
+}
- case SLT_Length:
- if (!lp->active)
- break;
- if (lp->df_b != NULL) {
- clean_logline(lp);
- break;
- }
- trimline(&lp->df_b, ptr, end);
- break;
+static void
+addf_string(const char *str)
+{
+ struct format *f;
+
+ AN(str);
+ ALLOC_OBJ(f, FORMAT_MAGIC);
+ AN(f);
+ f->func = &format_string;
+ f->string = strdup(str);
+ AN(f->string);
+ VTAILQ_INSERT_TAIL(&CTX.format, f, list);
+}
- case SLT_SessClose:
- if (!lp->active)
- break;
- if (strncmp(ptr, "TX_PIPE", len) == 0 ||
- strncmp(ptr, "TX_ERROR", len) == 0) {
- clean_logline(lp);
- break;
- }
- break;
+static void
+addf_strptr(const char *const *strptr)
+{
+ struct format *f;
+
+ AN(strptr);
+ ALLOC_OBJ(f, FORMAT_MAGIC);
+ AN(f);
+ f->func = &format_strptr;
+ f->strptr = strptr;
+ VTAILQ_INSERT_TAIL(&CTX.format, f, list);
+}
- case SLT_ReqEnd:
- {
- char ttfb[64];
- double t_start, t_end;
- if (!lp->active)
- break;
- if (lp->df_ttfb != NULL ||
- sscanf(ptr, "%*u %lf %lf %*u.%*u %s", &t_start, &t_end, ttfb)
- != 3) {
- clean_logline(lp);
- break;
- }
- if (lp->df_ttfb != NULL)
- free(lp->df_ttfb);
- lp->df_ttfb = strdup(ttfb);
- lp->df_D = t_end - t_start;
- t = t_start;
- localtime_r(&t, &lp->df_t);
- /* got it all */
- lp->complete = 1;
- break;
+static void
+addf_fragment(struct fragment *frag, const char *str)
+{
+ struct format *f;
+
+ AN(frag);
+ ALLOC_OBJ(f, FORMAT_MAGIC);
+ AN(f);
+ f->func = &format_fragment;
+ f->frag = frag;
+ if (str != NULL) {
+ f->string = strdup(str);
+ AN(f->string);
}
+ VTAILQ_INSERT_TAIL(&CTX.format, f, list);
+}
- default:
- break;
+static void
+addf_time(char type, const char *fmt, const char *str)
+{
+ struct format *f;
+
+ ALLOC_OBJ(f, FORMAT_MAGIC);
+ AN(f);
+ f->func = &format_time;
+ f->time_type = type;
+ if (fmt != NULL) {
+ f->time_fmt = strdup(fmt);
+ AN(f->time_fmt);
}
+ if (str != NULL) {
+ f->string = strdup(str);
+ AN(f->string);
+ }
+ VTAILQ_INSERT_TAIL(&CTX.format, f, list);
+}
- return (1);
+static void
+addf_requestline(void)
+{
+ struct format *f;
+
+ ALLOC_OBJ(f, FORMAT_MAGIC);
+ AN(f);
+ f->func = &format_requestline;
+ VTAILQ_INSERT_TAIL(&CTX.format, f, list);
}
-static int
-h_ncsa(void *priv, enum VSL_tag_e tag, unsigned fd,
- unsigned len, unsigned spec, const char *ptr, uint64_t bitmap)
+static void
+addf_vcl_log(const char *key, const char *str)
{
- struct logline *lp;
- FILE *fo = priv;
- char *q, tbuf[64];
- const char *p;
- struct vsb *os;
- const char *format;
-
- /* XXX: Ignore fd's outside 65536 */
- if (fd >= 65536)
- return (reopen);
-
- if (fd >= nll) {
- struct logline **newll = ll;
- size_t newnll = nll;
-
- while (fd >= newnll)
- newnll += newnll + 1;
- newll = realloc(newll, newnll * sizeof *newll);
- assert(newll != NULL);
- memset(newll + nll, 0, (newnll - nll) * sizeof *newll);
- ll = newll;
- nll = newnll;
- }
- if (ll[fd] == NULL) {
- ll[fd] = calloc(sizeof *ll[fd], 1);
- assert(ll[fd] != NULL);
- }
- lp = ll[fd];
- if (spec & VSL_S_BACKEND) {
- collect_backend(lp, tag, spec, ptr, len);
- format = b_format;
- } else if (spec & VSL_S_CLIENT) {
- collect_client(lp, tag, spec, ptr, len);
- format = c_format;
- } else {
- /* huh? */
- return (reopen);
+ struct watch *w;
+ struct format *f;
+
+ AN(key);
+ ALLOC_OBJ(w, WATCH_MAGIC);
+ AN(w);
+ w->key = strdup(key);
+ AN(w->key);
+ w->keylen = strlen(w->key);
+ VTAILQ_INSERT_TAIL(&CTX.watch_vcl_log, w, list);
+
+ ALLOC_OBJ(f, FORMAT_MAGIC);
+ AN(f);
+ f->func = &format_fragment;
+ f->frag = &w->frag;
+ if (str != NULL) {
+ f->string = strdup(str);
+ AN(f->string);
}
+ VTAILQ_INSERT_TAIL(&CTX.format, f, list);
+}
- lp->bitmap |= bitmap;
-
- if (!lp->complete)
- return (reopen);
+static void
+addf_hdr(struct watch_head *head, const char *key, const char *str)
+{
+ struct watch *w;
+ struct format *f;
+
+ AN(head);
+ AN(key);
+ ALLOC_OBJ(w, WATCH_MAGIC);
+ AN(w);
+ w->key = strdup(key);
+ AN(w->key);
+ w->keylen = strlen(w->key);
+ VTAILQ_INSERT_TAIL(head, w, list);
+
+ ALLOC_OBJ(f, FORMAT_MAGIC);
+ AN(f);
+ f->func = &format_fragment;
+ f->frag = &w->frag;
+ if (str != NULL) {
+ f->string = strdup(str);
+ AN(f->string);
+ }
+ VTAILQ_INSERT_TAIL(&CTX.format, f, list);
+}
- if (m_flag && !VSL_Matched(vd, lp->bitmap))
- /* -o is in effect matching rule failed. Don't display */
- return (reopen);
+static void
+addf_auth(const char *str)
+{
+ struct format *f;
-#if 0
- /* non-optional fields */
- if (!lp->df_m || !lp->df_U || !lp->df_H || !lp->df_s) {
- clean_logline(lp);
- return (reopen);
+ ALLOC_OBJ(f, FORMAT_MAGIC);
+ f->func = &format_auth;
+ if (str != NULL) {
+ f->string = strdup(str);
+ AN(f->string);
}
-#endif
+ VTAILQ_INSERT_TAIL(&CTX.format, f, list);
+}
- /* We have a complete data set - log a line */
+static void
+parse_format(const char *format)
+{
+ const char *p, *q;
+ struct vsb *vsb;
+ char buf[256];
- fo = priv;
- os = VSB_new_auto();
+ vsb = VSB_new_auto();
+ AN(vsb);
for (p = format; *p != '\0'; p++) {
- /* allow the most essential escape sequences in format. */
+ /* Allow the most essential escape sequences in format */
if (*p == '\\') {
p++;
- if (*p == 't') VSB_putc(os, '\t');
- if (*p == 'n') VSB_putc(os, '\n');
+ if (*p == 't')
+ AZ(VSB_putc(vsb, '\t'));
+ else if (*p == 'n')
+ AZ(VSB_putc(vsb, '\n'));
+ else if (*p != '\0')
+ AZ(VSB_putc(vsb, *p));
continue;
}
if (*p != '%') {
- VSB_putc(os, *p);
+ AZ(VSB_putc(vsb, *p));
continue;
}
- p++;
- switch (*p) {
- case 'b':
- /* %b */
- VSB_cat(os, lp->df_b ? lp->df_b : "-");
- break;
+ if (VSB_len(vsb) > 0) {
+ AZ(VSB_finish(vsb));
+ addf_string(VSB_data(vsb));
+ VSB_clear(vsb);
+ }
- case 'D':
- /* %D */
- VSB_printf(os, "%f", lp->df_D);
+ p++;
+ switch (*p) {
+ case 'b': /* Bytes */
+ addf_fragment(&CTX.frag[F_b], "-");
break;
-
- case 'H':
- VSB_cat(os, lp->df_H ? lp->df_H : "HTTP/1.0");
+ case 'D': /* Float request time */
+ addf_time(*p, NULL, NULL);
break;
-
- case 'h':
- if (!lp->df_h && spec & VSL_S_BACKEND)
- VSB_cat(os, "127.0.0.1");
- else
- VSB_cat(os, lp->df_h ? lp->df_h : "-");
+ case 'h': /* Client host name / IP Address */
+ addf_fragment(&CTX.frag[F_h], "-");
break;
- case 'l':
- VSB_putc(os, '-');
+ case 'H': /* Protocol */
+ addf_fragment(&CTX.frag[F_H], "HTTP/1.0");
break;
-
- case 'm':
- VSB_cat(os, lp->df_m ? lp->df_m : "-");
+ case 'l': /* Client user ID (identd) always '-' */
+ AZ(VSB_putc(vsb, '-'));
break;
-
- case 'q':
- VSB_cat(os, lp->df_q ? lp->df_q : "");
+ case 'm': /* Method */
+ addf_fragment(&CTX.frag[F_m], "-");
break;
-
- case 'r':
- /*
- * Fake "%r". This would be a lot easier if Varnish
- * normalized the request URL.
- */
- VSB_cat(os, lp->df_m ? lp->df_m : "-");
- VSB_putc(os, ' ');
- if (req_header(lp, "Host")) {
- if (strncmp(req_header(lp, "Host"),
- "http://", 7) != 0)
- VSB_cat(os, "http://");
- VSB_cat(os, req_header(lp, "Host"));
- } else {
- VSB_cat(os, "http://localhost");
- }
- VSB_cat(os, lp->df_U ? lp->df_U : "-");
- VSB_cat(os, lp->df_q ? lp->df_q : "");
- VSB_putc(os, ' ');
- VSB_cat(os, lp->df_H ? lp->df_H : "HTTP/1.0");
+ case 'q': /* Query string */
+ addf_fragment(&CTX.frag[F_q], "");
break;
-
- case 's':
- /* %s */
- VSB_cat(os, lp->df_s ? lp->df_s : "");
+ case 'r': /* Request line */
+ addf_requestline();
break;
-
- case 't':
- /* %t */
- strftime(tbuf, sizeof tbuf,
- "[%d/%b/%Y:%T %z]", &lp->df_t);
- VSB_cat(os, tbuf);
+ case 's': /* Status code */
+ addf_fragment(&CTX.frag[F_s], "");
break;
-
- case 'T':
- /* %T */
- VSB_printf(os, "%d", (int)lp->df_D);
+ case 't': /* strftime */
+ addf_time(*p, TIME_FMT, NULL);
break;
-
- case 'U':
- VSB_cat(os, lp->df_U ? lp->df_U : "-");
+ case 'T': /* Int request time */
+ addf_time(*p, NULL, NULL);
break;
-
case 'u':
- /* %u: decode authorization string */
- if (lp->df_u != NULL) {
- char *rubuf;
- size_t rulen;
-
- VB64_init();
- rulen = ((strlen(lp->df_u) + 3) * 4) / 3;
- rubuf = malloc(rulen);
- assert(rubuf != NULL);
- VB64_decode(rubuf, rulen, lp->df_u);
- q = strchr(rubuf, ':');
- if (q != NULL)
- *q = '\0';
- VSB_cat(os, rubuf);
- free(rubuf);
- } else {
- VSB_putc(os, '-');
- }
+ addf_auth("-");
break;
-
- case '{': {
- const char *h, *tmp;
- char fname[100], type;
- tmp = p;
- type = 0;
- while (*tmp != '\0' && *tmp != '}')
- tmp++;
- if (*tmp == '}') {
- tmp++;
- type = *tmp;
- memcpy(fname, p+1, tmp-p-2);
- fname[tmp-p-2] = 0;
- }
-
- switch (type) {
+ case 'U': /* URL */
+ addf_fragment(&CTX.frag[F_U], "-");
+ break;
+ case '{':
+ p++;
+ q = p;
+ while (*q && *q != '}')
+ q++;
+ if (!*q)
+ VUT_Error(1, "Unmatched bracket at: %s", p - 2);
+ assert(q - p < sizeof buf - 1);
+ strncpy(buf, p, q - p);
+ buf[q - p] = '\0';
+ q++;
+ switch (*q) {
case 'i':
- h = req_header(lp, fname);
- VSB_cat(os, h ? h : "-");
- p = tmp;
+ strcat(buf, ":");
+ addf_hdr(&CTX.watch_reqhdr, buf, "-");
break;
case 'o':
- h = resp_header(lp, fname);
- VSB_cat(os, h ? h : "-");
- p = tmp;
+ strcat(buf, ":");
+ addf_hdr(&CTX.watch_resphdr, buf, "-");
break;
case 't':
- strftime(tbuf, sizeof tbuf, fname, &lp->df_t);
- VSB_cat(os, tbuf);
- p = tmp;
+ addf_time(*q, buf, NULL);
break;
case 'x':
- if (!strcmp(fname, "Varnish:time_firstbyte")) {
- VSB_cat(os, lp->df_ttfb);
- p = tmp;
+ if (!strcmp(buf, "Varnish:time_firstbyte")) {
+ addf_fragment(&CTX.frag[F_ttfb], "");
break;
- } else if (!strcmp(fname, "Varnish:hitmiss")) {
- VSB_cat(os, (lp->df_hitmiss ?
- lp->df_hitmiss : "-"));
- p = tmp;
+ }
+ if (!strcmp(buf, "Varnish:hitmiss")) {
+ addf_strptr(&CTX.hitmiss);
break;
- } else if (!strcmp(fname, "Varnish:handling")) {
- VSB_cat(os, (lp->df_handling ?
- lp->df_handling : "-"));
- p = tmp;
+ }
+ if (!strcmp(buf, "Varnish:handling")) {
+ addf_strptr(&CTX.handling);
break;
- } else if (!strncmp(fname, "VCL_Log:", 8)) {
- // support pulling entries logged
- // with std.log() into output.
- // Format: %{VCL_Log:keyname}x
- // Logging: std.log("keyname:value")
- h = vcl_log(lp, fname+8);
- VSB_cat(os, h ? h : "-");
- p = tmp;
+ }
+ if (!strncmp(buf, "VCL_Log:", 8)) {
+ addf_vcl_log(buf + 8, "");
break;
}
/* FALLTHROUGH */
default:
- fprintf(stderr,
- "Unknown format starting at: %s\n", --p);
- exit(1);
+ VUT_Error(1, "Unknown format specifier at: %s",
+ p - 2);
}
+ p = q;
break;
- }
- /* Fall through if we haven't handled something */
- /* FALLTHROUGH*/
default:
- fprintf(stderr,
- "Unknown format starting at: %s\n", --p);
- exit(1);
+ VUT_Error(1, "Unknown format specifier at: %s", p - 1);
}
}
- VSB_putc(os, '\n');
- /* flush the stream */
- VSB_finish(os);
- fprintf(fo, "%s", VSB_data(os));
- fflush(fo);
+ if (VSB_len(vsb) > 0) {
+ /* Add any remaining static */
+ AZ(VSB_finish(vsb));
+ addf_string(VSB_data(vsb));
+ VSB_clear(vsb);
+ }
- /* clean up */
- clean_logline(lp);
- VSB_delete(os);
- return (reopen);
+ VSB_delete(vsb);
}
-/*--------------------------------------------------------------------*/
-
-static void
-sighup(int sig)
+static int
+isprefix(const char *str, const char *prefix, const char *end,
+ const char **next)
{
- (void)sig;
- reopen = 1;
+ while (str < end && *str && *prefix &&
+ tolower((int)*str) == tolower((int)*prefix))
+ ++str, ++prefix;
+ if (*str && *str != ' ')
+ return (0);
+ if (next) {
+ while (str < end && *str && *str == ' ')
+ ++str;
+ *next = str;
+ }
+ return (1);
}
-static FILE *
-open_log(const char *ofn, int append)
+static void
+frag_fields(const char *b, const char *e, ...)
{
- FILE *of;
-
- if ((of = fopen(ofn, append ? "a" : "w")) == NULL) {
- perror(ofn);
- exit(1);
+ va_list ap;
+ const char *p, *q;
+ int n, field;
+ struct fragment *frag;
+
+ AN(b);
+ AN(e);
+ va_start(ap, e);
+
+ field = va_arg(ap, int);
+ frag = va_arg(ap, struct fragment *);
+ for (n = 1, q = b; q < e; n++) {
+ assert(field > 0);
+ AN(frag);
+
+ p = q;
+ /* Skip WS */
+ while (p < e && isspace(*p))
+ p++;
+ q = p;
+ /* Skip non-WS */
+ while (q < e && !isspace(*q))
+ q++;
+
+ if (field == n) {
+ frag->gen = CTX.gen;
+ frag->b = p;
+ frag->e = q;
+ field = va_arg(ap, int);
+ if (field == 0)
+ break;
+ frag = va_arg(ap, struct fragment *);
+ }
}
- return (of);
+ va_end(ap);
}
-/*--------------------------------------------------------------------*/
+static void
+frag_line(const char *b, const char *e, struct fragment *f)
+{
+
+ /* Skip leading space */
+ while (b < e && isspace(*b))
+ ++b;
+
+ /* Skip trailing space */
+ while (e > b && isspace(*(e - 1)))
+ --e;
+
+ f->gen = CTX.gen;
+ f->b = b;
+ f->e = e;
+}
static void
-usage(void)
+process_hdr(const struct watch_head *head, const char *b, const char *e)
{
+ struct watch *w;
- fprintf(stderr,
- "usage: varnishncsa %s [-afDV] [-n varnish_name] "
- "[-P file] [-w file] [-F format] \n", VSL_USAGE);
- exit(1);
+ VTAILQ_FOREACH(w, head, list) {
+ if (strncasecmp(b, w->key, w->keylen))
+ continue;
+ frag_line(b + w->keylen, e, &w->frag);
+ }
}
-int
-main(int argc, char *argv[])
+static int __match_proto__(VSLQ_dispatch_f)
+dispatch_f(struct VSL_data *vsl, struct VSL_transaction * const pt[],
+ void *priv)
{
- int c;
- int a_flag = 0, D_flag = 0, format_flag = 0, b_flag = 0;
- const char *P_arg = NULL;
- const char *w_arg = NULL;
- struct vpf_fh *pfh = NULL;
- FILE *of;
- c_format = "%h %l %u %t \"%r\" %s %b \"%{Referer}i\" \"%{User-agent}i\"";
- b_format = "%h %l %u %t \"%r\" %s %b \"%{Referer}i\" \"%{User-agent}i\"";
-
- vd = VSM_New();
-
- while ((c = getopt(argc, argv, VSL_ARGS "aDP:Vw:fF:B:C:")) != -1) {
- switch (c) {
- case 'a':
- a_flag = 1;
- break;
- case 'f':
- case 'F':
- if (format_flag) {
- fprintf(stderr,
- "-f, -F, -B or -C can not be combined\n");
- exit(1);
- }
- format_flag = 1;
- switch (c) {
- case 'f':
- b_format = c_format =
- "%{X-Forwarded-For}i %l %u %t \"%r\""
- " %s %b \"%{Referer}i\" \"%{User-agent}i\"";
+ struct VSL_transaction *t;
+ unsigned tag;
+ const char *b, *e, *p;
+ struct watch *w;
+ int i;
+
+ (void)vsl;
+ (void)priv;
+
+ for (t = pt[0]; t != NULL; t = *++pt) {
+ CTX.gen++;
+ if (t->type != VSL_t_req)
+ continue;
+ CTX.hitmiss = "-";
+ CTX.handling = "-";
+ while ((1 == VSL_Next(t->c))) {
+ tag = VSL_TAG(t->c->rec.ptr);
+ b = VSL_CDATA(t->c->rec.ptr);
+ e = b + VSL_LEN(t->c->rec.ptr);
+
+ switch (tag) {
+ case SLT_ReqStart:
+ frag_fields(b, e, 1, &CTX.frag[F_h], 0, NULL);
+ break;
+ case SLT_ReqMethod:
+ frag_line(b, e, &CTX.frag[F_m]);
+ break;
+ case SLT_ReqURL:
+ p = memchr(b, '?', e - b);
+ if (p == NULL)
+ p = e;
+ frag_line(b, e, &CTX.frag[F_U]);
+ frag_line(b, e, &CTX.frag[F_q]);
+ break;
+ case SLT_ReqProtocol:
+ frag_line(b, e, &CTX.frag[F_H]);
+ break;
+ case SLT_RespStatus:
+ frag_line(b, e, &CTX.frag[F_s]);
+ break;
+ case SLT_Length:
+ frag_line(b, e, &CTX.frag[F_b]);
break;
- case 'F':
- b_format = c_format = optarg;
+ case SLT_ReqEnd:
+ frag_fields(b, e, 1, &CTX.frag[F_tstart],
+ 2, &CTX.frag[F_tend], 3, &CTX.frag[F_ttfb],
+ 0, NULL);
break;
- case 'B':
- b_format = optarg;
+ case SLT_ReqHeader:
+ if (isprefix(b, e, "Host:", &p))
+ frag_line(p, e, &CTX.frag[F_host]);
+ else if (isprefix(b, "Authorization:", e, &p) &&
+ isprefix(p, "basic", e, &p))
+ frag_line(p, e, &CTX.frag[F_auth]);
break;
- case 'C':
- c_format = optarg;
+ case SLT_VCL_call:
+ if (!strcasecmp(b, "recv")) {
+ CTX.hitmiss = "-";
+ CTX.handling = "-";
+ } else if (!strcasecmp(b, "hit")) {
+ CTX.hitmiss = "hit";
+ CTX.handling = "hit";
+ } else if (!strcasecmp(b, "miss")) {
+ CTX.hitmiss = "miss";
+ CTX.handling = "miss";
+ } else if (!strcasecmp(b, "pass")) {
+ CTX.hitmiss = "miss";
+ CTX.handling = "pass";
+ } else if (!strcasecmp(b, "error")) {
+ /* Arguably, error isn't a hit or
+ a miss, but miss is less
+ wrong */
+ CTX.hitmiss = "miss";
+ CTX.handling = "error";
+ } else if (!strcasecmp(b, "pipe")) {
+ CTX.hitmiss = "miss";
+ CTX.handling = "pipe";
+ }
+ break;
+ default:
break;
}
+
+ if (tag == SLT_VCL_Log) {
+ VTAILQ_FOREACH(w, &CTX.watch_vcl_log, list) {
+ CHECK_OBJ_NOTNULL(w, WATCH_MAGIC);
+ if (strncmp(b, w->key, w->keylen))
+ continue;
+ p = b + w->keylen;
+ if (*p != ':')
+ continue;
+ p++;
+ if (p > e)
+ continue;
+ frag_line(p, e, &w->frag);
+ }
+ }
+ if (tag == SLT_ReqHeader)
+ process_hdr(&CTX.watch_reqhdr, b, e);
+ if (tag == SLT_RespHeader)
+ process_hdr(&CTX.watch_resphdr, b, e);
+ }
+ i = print();
+ if (i)
+ return (i);
+ }
+
+ return (0);
+}
+
+int
+main(int argc, char * const *argv)
+{
+ char opt;
+ char *format = NULL;
+
+ memset(&CTX, 0, sizeof CTX);
+ VTAILQ_INIT(&CTX.format);
+ VTAILQ_INIT(&CTX.watch_vcl_log);
+ VTAILQ_INIT(&CTX.watch_reqhdr);
+ VTAILQ_INIT(&CTX.watch_resphdr);
+ CTX.vsb = VSB_new_auto();
+ AN(CTX.vsb);
+ VB64_init();
+ VUT_Init(progname);
+
+ while ((opt = getopt(argc, argv, vopt_optstring)) != -1) {
+ switch (opt) {
+ case 'a':
+ /* Append to file */
+ CTX.a_opt = 1;
break;
- case 'D':
- D_flag = 1;
- break;
- case 'P':
- P_arg = optarg;
+ case 'F':
+ /* Format string */
+ if (format != NULL)
+ free(format);
+ format = strdup(optarg);
+ AN(format);
break;
- case 'V':
- VCS_Message("varnishncsa");
- exit(0);
+ case 'h':
+ /* Usage help */
+ usage(0);
case 'w':
- w_arg = optarg;
- break;
- case 'b':
- b_flag = 1;
- if (VSL_Arg(vd, c, optarg) > 0)
- break;
- usage();
- break;
- case 'i':
- fprintf(stderr, "-i is not valid for varnishncsa\n");
- exit(1);
- break;
- case 'I':
- fprintf(stderr, "-I is not valid for varnishncsa\n");
- exit(1);
+ /* Write to file */
+ REPLACE(CTX.w_arg, optarg);
break;
- case 'c':
- /* XXX: Silently ignored: it's required anyway */
- break;
- case 'm':
- m_flag = 1;
- /* FALLTHOUGH */
default:
- if (VSL_Arg(vd, c, optarg) > 0)
- break;
- usage();
+ if (!VUT_Arg(opt, optarg))
+ usage(1);
}
}
- if (! b_flag)
- VSL_Arg(vd, 'c', optarg);
-
- if (VSM_Open(vd)) {
- fprintf(stderr, "%s\n", VSM_Error(vd));
- return (-1);
- }
-
- if (P_arg && (pfh = VPF_Open(P_arg, 0644, NULL)) == NULL) {
- perror(P_arg);
- exit(1);
- }
-
- if (D_flag && varnish_daemon(0, 0) == -1) {
- perror("daemon()");
- if (pfh != NULL)
- VPF_Remove(pfh);
- exit(1);
- }
-
- if (pfh != NULL)
- VPF_Write(pfh);
-
- if (w_arg) {
- of = open_log(w_arg, a_flag);
- signal(SIGHUP, sighup);
- } else {
- w_arg = "stdout";
- of = stdout;
- }
-
- while (VSL_Dispatch(vd, h_ncsa, of) >= 0) {
- if (fflush(of) != 0) {
- perror(w_arg);
- exit(1);
- }
- if (reopen && of != stdout) {
- fclose(of);
- of = open_log(w_arg, a_flag);
- reopen = 0;
- }
- }
+ if (optind != argc)
+ usage(1);
+
+ /* Check for valid grouping mode */
+ assert(VUT.g_arg < VSL_g__MAX);
+ if (VUT.g_arg != VSL_g_vxid && VUT.g_arg != VSL_g_request)
+ VUT_Error(1, "Invalid grouping mode: %s",
+ VSLQ_grouping[VUT.g_arg]);
+
+ /* Prepare output format */
+ if (format == NULL)
+ format = strdup(FORMAT);
+ parse_format(format);
+ free(format);
+ format = NULL;
+
+ /* Setup output */
+ VUT.dispatch_f = &dispatch_f;
+ VUT.dispatch_priv = NULL;
+ if (CTX.w_arg) {
+ openout(CTX.a_opt);
+ AN(CTX.fo);
+ VUT.sighup_f = &rotateout;
+ } else
+ CTX.fo = stdout;
+ VUT.idle_f = &flushout;
+
+ VUT_Setup();
+ VUT_Main();
+ VUT_Fini();
exit(0);
}
diff --git a/bin/varnishncsa/varnishncsa_options.c b/bin/varnishncsa/varnishncsa_options.c
new file mode 100644
index 0000000..91fb2e0
--- /dev/null
+++ b/bin/varnishncsa/varnishncsa_options.c
@@ -0,0 +1,34 @@
+/*-
+ * Copyright (c) 2013 Varnish Software AS
+ * All rights reserved.
+ *
+ * Author: Martin Blix Grydeland <martin at varnish-software.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Option definitions for varnishlog
+ */
+
+#include <stdlib.h>
+#define VOPT_DEFINITION
+#define VOPT_INC "varnishncsa_options.h"
+#include "vapi/voptget.h"
diff --git a/bin/varnishncsa/varnishncsa_options.h b/bin/varnishncsa/varnishncsa_options.h
new file mode 100644
index 0000000..346b7fc
--- /dev/null
+++ b/bin/varnishncsa/varnishncsa_options.h
@@ -0,0 +1,69 @@
+/*-
+ * Copyright (c) 2013 Varnish Software AS
+ * All rights reserved.
+ *
+ * Author: Martin Blix Grydeland <martin at varnish-software.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "vapi/vapi_options.h"
+#include "vut_options.h"
+
+#define NCSA_OPT_a \
+ VOPT("a", "[-a]", "Append to file", \
+ "When writing output to a file, append to it rather than" \
+ " overwrite it." \
+ )
+
+#define NCSA_OPT_F \
+ VOPT("F:", "[-F format]", "Set output format", \
+ "Set the output log format string." \
+ )
+
+#define NCSA_OPT_g \
+ VOPT("g:", "[-g <request|vxid>]", "Grouping mode", \
+ "The grouping of the log records. The default is to group" \
+ " by vxid." \
+ )
+
+#define NCSA_OPT_w \
+ VOPT("w:", "[-w filename]", "Output filename", \
+ "Redirect output to file. The file will be overwritten" \
+ " unless the -a option was specified. If the application" \
+ " receives a SIGHUP the file will be reopened allowing" \
+ " the old one to be rotated away." \
+ )
+
+NCSA_OPT_a
+VSL_OPT_C
+VUT_OPT_d
+VUT_OPT_D
+NCSA_OPT_F
+NCSA_OPT_g
+VUT_OPT_h
+VUT_OPT_n
+VUT_OPT_N
+VUT_OPT_P
+VUT_OPT_q
+VUT_OPT_V
+NCSA_OPT_w
diff --git a/configure.ac b/configure.ac
index 42a427c..905d131 100644
--- a/configure.ac
+++ b/configure.ac
@@ -543,6 +543,7 @@ AC_CONFIG_FILES([
bin/varnishlog/Makefile
bin/varnishstat/Makefile
bin/varnishtest/Makefile
+ bin/varnishncsa/Makefile
doc/Makefile
doc/sphinx/Makefile
doc/sphinx/conf.py
More information about the varnish-commit
mailing list