├── .gitignore
├── .travis.yml
├── CHANGES.rst
├── COPYING
├── LICENSE
├── Makefile.am
├── README.rst
├── autogen.sh
├── configure.ac
├── example.vcl
├── m4
└── PLACEHOLDER
├── readmeAsWell.rst
├── src
├── HTML
│ ├── vmod_html.c
│ └── vmod_html.h
├── Makefile.am
├── tests
│ ├── test01.vtc
│ ├── test03.vtc
│ └── test04.vtc
├── vmod_rtstatus.c
├── vmod_rtstatus.h
├── vmod_rtstatus.vcc
└── vmod_rtstatus_cache.c
└── varnishstatus.png
/.gitignore:
--------------------------------------------------------------------------------
1 | Makefile
2 | Makefile.in
3 | .deps/
4 | .libs/
5 | *.o
6 | *.lo
7 | *.la
8 | *~
9 | *.[1-9]
10 |
11 | /aclocal.m4
12 | /autom4te.cache/
13 | /compile
14 | /config.guess
15 | /config.h
16 | /config.h.in
17 | /config.log
18 | /config.status
19 | /config.sub
20 | /configure
21 | /depcomp
22 | /install-sh
23 | /libtool
24 | /ltmain.sh
25 | /missing
26 | /stamp-h1
27 | /m4/
28 |
29 | /src/vcc_if.c
30 | /src/vcc_if.h
31 |
32 | /src/vmod_rtstatus*rst
33 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: c
2 |
3 | before_install:
4 | - sudo apt-get update -q
5 | - sudo apt-get install -qq apt-transport-https python-docutils
6 | - curl -L https://packagecloud.io/varnishcache/varnish40/gpgkey | sudo apt-key add -
7 | - echo "deb https://packagecloud.io/varnishcache/varnish40/ubuntu/ precise main" | sudo tee /etc/apt/sources.list.d/varnish-cache.list
8 | - sudo apt-get -q update
9 | - sudo apt-get install varnish varnish-dev
10 |
11 | before_script:
12 | - ./autogen.sh
13 | - ./configure --prefix=/usr
14 | - make -j4
15 |
16 | script:
17 | - make check -j4
18 |
19 | compiler:
20 | - clang
21 | - gcc
22 |
--------------------------------------------------------------------------------
/CHANGES.rst:
--------------------------------------------------------------------------------
1 | libvmod-rtstatus 1.1.1 (unreleased)
2 | -----------------------------------
3 |
4 | * Version change in configure.ac.
5 | * Debian folder and spec file deleted.
6 |
7 | libvmod-example 1.1.0 (2015-12-09)
8 | ----------------------------------
9 |
10 | Bugs fixed
11 | ----------
12 |
13 | - 8_ - Workspace saturation after increasing number of backends.
14 |
15 | .. _8: https://github.com/varnish/libvmod-rtstatus/issues/8
16 |
17 |
18 |
--------------------------------------------------------------------------------
/COPYING:
--------------------------------------------------------------------------------
1 | Copyright (c) 2014 Varnish Software AS
2 | ...
3 | See LICENSE for details.
4 |
5 | You're free to use and distribute this under terms in the
6 | LICENSE. Please add your relevant copyright statements.
7 |
8 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Redistribution and use in source and binary forms, with or without
2 | modification, are permitted provided that the following conditions
3 | are met:
4 | 1. Redistributions of source code must retain the above copyright
5 | notice, this list of conditions and the following disclaimer.
6 | 2. Redistributions in binary form must reproduce the above copyright
7 | notice, this list of conditions and the following disclaimer in the
8 | documentation and/or other materials provided with the distribution.
9 |
10 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
11 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
12 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13 | ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
14 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
15 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
16 | OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
17 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
18 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
19 | OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
20 | SUCH DAMAGE.
21 |
--------------------------------------------------------------------------------
/Makefile.am:
--------------------------------------------------------------------------------
1 | ACLOCAL_AMFLAGS = -I m4 -I ${LIBVARNISHAPI_DATAROOTDIR}/aclocal
2 |
3 | SUBDIRS = src
4 |
5 | DISTCHECK_CONFIGURE_FLAGS = \
6 | VMOD_DIR='$${libdir}/varnish/vmods'
7 |
8 |
9 | EXTRA_DIST = CHANGES.rst README.rst LICENSE
10 |
11 | doc_DATA = CHANGES.rst README.rst LICENSE
12 |
13 | dist_man_MANS = vmod_rtstatus.3
14 | MAINTAINERCLEANFILES = $(dist_man_MANS)
15 |
16 | vmod_rtstatus.3: README.rst
17 |
18 | %.1 %.2 %.3 %.4 %.5 %.6 %.7 %.8 %.9:
19 | if HAVE_RST2MAN
20 | ${RST2MAN} $< $@
21 | else
22 | @echo "========================================"
23 | @echo "You need rst2man installed to make dist"
24 | @echo "========================================"
25 | @false
26 | endif
27 |
28 |
--------------------------------------------------------------------------------
/README.rst:
--------------------------------------------------------------------------------
1 |
2 | =============
3 | vmod_rtstatus
4 | =============
5 |
6 | .. image:: https://travis-ci.org/varnish/libvmod-rtstatus.svg?branch=4.0
7 | :target: https://travis-ci.org/varnish/libvmod-rtstatus
8 |
9 | -------------------------------
10 | Varnish Real-Time Status Module
11 | -------------------------------
12 |
13 | :Author: Arianna Aondio
14 | :Date: 2015-12-09
15 | :Version: 1.1.1
16 |
17 | SYNOPSIS
18 | ========
19 |
20 | import rtstatus;
21 |
22 | DESCRIPTION
23 | ===========
24 |
25 | A vmod that lets you query your Varnish server for a JSON object containing
26 | counters.
27 |
28 | Visiting the URL ``/rtstatus.json`` on the Varnish server will produce an
29 | application/json response of the following format::
30 |
31 | {
32 | "Uptime" : 0+00:09:38,
33 | "hitrate": 0.00,
34 | "load": 1,
35 | "varnish_version" : "varnish-4.0.1 revision c6f20e4",
36 | "server_id": "arianna-ThinkPad-X230",
37 | "client_id": "127.0.0.1",
38 | "backend": [{"director_name" : "simple" , "name":"default", "value": "healthy"},
39 | {"director_name" : "simple" , "name":"server1", "value": "healthy"},
40 | {"director_name" : "simple" , "name":"server2", "value": "healthy"}],
41 | "MAIN.uptime": {"type": "MAIN", "descr": "Child process uptime", "value": 578},
42 | "VBE.server1(192.168.0.10,,8081).vcls": {"type": "VBE", "ident": "server1(192.168.0.10,,8081)", "descr": "VCL references", "value": 1},
43 | "VBE.server1(192.168.0.10,,8081).happy": {"type": "VBE", "ident": "server1(192.168.0.10,,8081)", "descr": "Happy health probes", "value": 0},
44 | "VBE.server1(192.168.0.10,,8081).bereq_hdrbytes": {"type": "VBE", "ident": "server1(192.168.0.10,,8081)", "descr": "Request header bytes", "value": 0},
45 | }
46 |
47 | Visiting the URL ``/rtstatus`` on the Varnish server will produce an
48 | application/javascript response of the following format:
49 |
50 | .. image:: varnishstatus.png
51 | :alt: RTstatus frontend
52 |
53 | FUNCTIONS
54 | =========
55 |
56 | rtstatus
57 | --------
58 |
59 | Prototype::
60 |
61 | rtstatus(REAL delta)
62 | *delta* is the interval of seconds used for hitrate and load calculations.
63 | It has to be > 0 and < 60 seconds.
64 |
65 | Return value
66 | STRING
67 |
68 | html()
69 | ------
70 |
71 | Prototype::
72 |
73 | html( )
74 |
75 | Return value
76 | STRING
77 |
78 | INSTALLATION
79 | ============
80 | The source tree is based on autotools to configure the building, and
81 | does also have the necessary bits in place to do functional unit tests
82 | using the varnishtest tool.
83 |
84 | Make targets:
85 |
86 | * make - builds the vmod
87 | * make install - installs your vmod in `VMODDIR`
88 | * make check - runs the unit tests in ``src/tests/*.vtc``
89 |
90 | In your VCL you could then use this vmod along the following lines::
91 |
92 | vcl 4.0;
93 | import std;
94 | import rtstatus;
95 |
96 | sub vcl_recv {
97 | if (req.url ~ "/rtstatus.json") {
98 | return(synth(700, "OK")); }
99 | if (req.url ~ "/rtstatus") {
100 | return(synth(800, "OK"));
101 | }
102 | }
103 | sub vcl_synth {
104 | if (resp.status == 700){
105 | set resp.status = 200;
106 | set resp.http.Content-Type = "application/json; charset=utf-8";
107 | synthetic(rtstatus.rtstatus(5));
108 | return (deliver);
109 | }
110 | if (resp.status == 800) {
111 | set resp.status = 200;
112 | set resp.http.Content-Type = "text/html; charset=utf-8";
113 | synthetic(rtstatus.html());
114 | return (deliver);
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/autogen.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | warn() {
4 | echo "WARNING: $@" 1>&2
5 | }
6 |
7 | case `uname -s` in
8 | Darwin)
9 | LIBTOOLIZE=glibtoolize
10 | ;;
11 | FreeBSD)
12 | LIBTOOLIZE=libtoolize
13 | ;;
14 | Linux)
15 | LIBTOOLIZE=libtoolize
16 | ;;
17 | SunOS)
18 | LIBTOOLIZE=libtoolize
19 | ;;
20 | *)
21 | warn "unrecognized platform:" `uname -s`
22 | LIBTOOLIZE=libtoolize
23 | esac
24 |
25 | automake_version=`automake --version | tr ' ' '\n' | egrep '^[0-9]\.[0-9a-z.-]+'`
26 | if [ -z "$automake_version" ] ; then
27 | warn "unable to determine automake version"
28 | else
29 | case $automake_version in
30 | 0.*|1.[0-8]|1.[0-8][.-]*)
31 | warn "automake ($automake_version) detected; 1.9 or newer recommended"
32 | ;;
33 | *)
34 | ;;
35 | esac
36 | fi
37 |
38 | # check for varnishapi.m4 in custom paths
39 | dataroot=$(pkg-config --variable=datarootdir varnishapi 2>/dev/null)
40 | if [ -z "$dataroot" ] ; then
41 | cat >&2 <<'EOF'
42 | Package varnishapi was not found in the pkg-config search path.
43 | Perhaps you should add the directory containing `varnishapi.pc'
44 | to the PKG_CONFIG_PATH environment variable
45 | EOF
46 | exit 1
47 | fi
48 |
49 | set -ex
50 |
51 | aclocal -I m4 -I ${dataroot}/aclocal
52 | $LIBTOOLIZE --copy --force
53 | autoheader
54 | automake --add-missing --copy --foreign
55 | autoconf
56 |
--------------------------------------------------------------------------------
/configure.ac:
--------------------------------------------------------------------------------
1 | AC_PREREQ(2.59)
2 | AC_COPYRIGHT([Copyright (c) 2015 Varnish Software AS])
3 | AC_INIT([libvmod-rtstatus], [1.1.1])
4 | AC_CONFIG_MACRO_DIR([m4])
5 | AC_CONFIG_SRCDIR(src/vmod_rtstatus.vcc)
6 | AC_CONFIG_HEADERS(config.h)
7 |
8 | AC_CANONICAL_SYSTEM
9 | AC_LANG(C)
10 |
11 | AM_INIT_AUTOMAKE([foreign])
12 |
13 | AC_GNU_SOURCE
14 | AC_PROG_CC
15 | AC_PROG_CC_STDC
16 | if test "x$ac_cv_prog_cc_c99" = xno; then
17 | AC_MSG_ERROR([Could not find a C99 compatible compiler])
18 | fi
19 | AC_PROG_CPP
20 |
21 | AC_PROG_INSTALL
22 | AC_PROG_LIBTOOL
23 | AC_PROG_MAKE_SET
24 |
25 | # Check for rst utilities
26 | AC_CHECK_PROGS(RST2MAN, [rst2man rst2man.py], "no")
27 | if test "x$RST2MAN" = "xno"; then
28 | AC_MSG_WARN([rst2man not found - not building man pages])
29 | fi
30 | AM_CONDITIONAL(HAVE_RST2MAN, [test "x$RST2MAN" != "xno"])
31 |
32 | # Checks for header files.
33 | AC_HEADER_STDC
34 | AC_CHECK_HEADERS([sys/stdlib.h])
35 |
36 | # backwards compat with older pkg-config
37 | # - pull in AC_DEFUN from pkg.m4
38 | m4_ifndef([PKG_CHECK_VAR], [
39 | # PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE,
40 | # [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
41 | # -------------------------------------------
42 | # Retrieves the value of the pkg-config variable for the given module.
43 | AC_DEFUN([PKG_CHECK_VAR],
44 | [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
45 | AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl
46 |
47 | _PKG_CONFIG([$1], [variable="][$3]["], [$2])
48 | AS_VAR_COPY([$1], [pkg_cv_][$1])
49 |
50 | AS_VAR_IF([$1], [""], [$5], [$4])dnl
51 | ])# PKG_CHECK_VAR
52 | ])
53 |
54 | PKG_CHECK_MODULES([libvarnishapi], [varnishapi])
55 | PKG_CHECK_VAR([LIBVARNISHAPI_DATAROOTDIR], [varnishapi], [datarootdir])
56 | PKG_CHECK_VAR([LIBVARNISHAPI_BINDIR], [varnishapi], [bindir])
57 | PKG_CHECK_VAR([LIBVARNISHAPI_SBINDIR], [varnishapi], [sbindir])
58 | AC_SUBST([LIBVARNISHAPI_DATAROOTDIR])
59 |
60 | # Varnish include files tree
61 | VARNISH_VMOD_INCLUDES
62 | VARNISH_VMOD_DIR
63 | VARNISH_VMODTOOL
64 |
65 | AC_PATH_PROG([VARNISHTEST], [varnishtest], [],
66 | [$LIBVARNISHAPI_BINDIR:$LIBVARNISHAPI_SBINDIR:$PATH])
67 | AC_PATH_PROG([VARNISHD], [varnishd], [],
68 | [$LIBVARNISHAPI_SBINDIR:$LIBVARNISHAPI_BINDIR:$PATH])
69 |
70 | AC_CONFIG_FILES([
71 | Makefile
72 | src/Makefile
73 | ])
74 | AC_OUTPUT
75 |
--------------------------------------------------------------------------------
/example.vcl:
--------------------------------------------------------------------------------
1 | vcl 4.0;
2 | import std;
3 | import directors;
4 | import rtstatus;
5 |
6 | backend default {
7 | .host = "127.0.0.1";
8 | .port = "8080";
9 | }
10 | backend server1 {
11 | .host = "127.0.0.1";
12 | .port ="8081";
13 | }
14 | backend server2 {
15 | .host = "127.0.0.1";
16 | .port = "8082";
17 | }
18 |
19 | sub vcl_init {
20 | new bar = directors.round_robin();
21 | bar.add_backend(server1);
22 | bar.add_backend(server2);
23 | bar.add_backend(default);
24 | }
25 |
26 | sub vcl_recv {
27 | if (req.url ~ "/rtstatus.json") {
28 | return(synth(700, "OK"));
29 | }
30 | if (req.url ~ "/rtstatus") {
31 | return(synth(800, "OK"));
32 | }
33 | }
34 |
35 | sub vcl_synth {
36 | if (resp.status == 700) {
37 | set resp.status = 200;
38 | set resp.http.Content-Type = "application/json; charset=utf-8";
39 | synthetic(rtstatus.rtstatus());
40 | return (deliver);
41 | }
42 | if (resp.status == 800) {
43 | set resp.status = 200;
44 | set resp.http.Content-Type = "text/html; charset=utf-8";
45 | synthetic(rtstatus.html());
46 | return (deliver);
47 | }
48 | }
49 |
50 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/m4/PLACEHOLDER:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/varnish/libvmod-rtstatus/3c945939f3a72e01c30d58f3ec44442618827d8c/m4/PLACEHOLDER
--------------------------------------------------------------------------------
/readmeAsWell.rst:
--------------------------------------------------------------------------------
1 | Before reading this, please read the official README.
2 | This file is meant for a better understanding of the VMOD.
3 |
4 | The VMOD has two functions:
5 |
6 | rtstatus(REAL delta): this is the important one, it generates a JSON object containing a lot of varnish-counters.They are mostly raw, so you can use them as you prefer.
7 | The parameter *delta* is requested because is used for calculating hitrate and request load, the idea behind this is something like "I'd really like to know how my hitrate and my load have been doing in the last 13 seconds". *delta* has to be greater than 0 and smaller than 60 seconds; please remember the VMOD is called rtstatus where rt stands for real-time, values greater than one minutes just don't make sense for this vmod.
8 | I suggest to set delta to 5 or 10 seconds.
9 |
10 | html(): this function has been written for presenting the counters in a nice way. It is a c wrapper around some HTML/css and javascript. Basically I just wrote everything into a big string and then I used this string to feed the vmod function.
11 | Please feel free customize your frontend and if your idea is good, feel free to suggest it :)
12 |
--------------------------------------------------------------------------------
/src/HTML/vmod_html.c:
--------------------------------------------------------------------------------
1 | #include "cache/cache.h"
2 | #include "vmod_rtstatus.h"
3 | #include "vmod_html.h"
4 |
5 | VCL_STRING
6 | vmod_html(const struct vrt_ctx *ctx)
7 | {
8 | struct iter_priv iter = { 0 };
9 | iter.vsb = VSB_new(NULL, ctx->ws->f, WS_Reserve(ctx->ws, 0), VSB_AUTOEXTEND);
10 | VSB_cat(iter.vsb, html);
11 | VSB_finish(iter.vsb);
12 | if (VSB_error(iter.vsb)) {
13 | VSLb(ctx->vsl, SLT_VCL_Error, "VSB error");
14 | WS_Release(ctx->ws, VSB_len(iter.vsb) + 1);
15 | return "{}";
16 | }
17 | WS_Release(ctx->ws, VSB_len(iter.vsb) + 1);
18 | return (iter.vsb->s_buf);
19 | }
20 |
21 |
--------------------------------------------------------------------------------
/src/HTML/vmod_html.h:
--------------------------------------------------------------------------------
1 | char *html =
2 | "\n"
3 | "\n"
4 | "
\n"
5 | " \n"
6 | " \n"
7 | " \n"
8 | " \n"
9 | " \n"
10 | " \n"
11 | " Varnish Status\n"
12 | " \n"
13 | " \n"
14 | " \n"
15 | " \n"
16 | " \n"
17 | " \n"
18 | " \n"
22 | " \n"
23 | " \n"
24 | " \n"
34 | "\n"
35 | "\n"
36 | "
VARNISH STATUS
\n"
37 | "
\n"
38 | "\n"
43 | "
\n"
44 | "
\n"
45 | "\n"
46 | "
\n"
47 | " \n"
48 | " \n"
49 | " Backends | \n"
50 | " Num | \n"
51 | " Req | \n"
52 | " Conn | \n"
53 | " Unhealthy | \n"
54 | " Busy | \n"
55 | " Fail | \n"
56 | " Reuse | \n"
57 | " Toolate | \n"
58 | " Recycle | \n"
59 | " Retry | \n"
60 | "
\n"
61 | " \n"
62 | " \n"
63 | "
\n"
64 | "
\n"
65 | "\n"
66 | "\n"
67 | "
\n"
68 | "
\n"
69 | "\n"
70 | "
\n"
71 | " \n"
72 | " \n"
73 | " Backend name | \n"
74 | " Health | \n"
75 | " Req KB/s | \n"
76 | " Requests | \n"
77 | " Resp KB/s | \n"
78 | " Responses | \n"
79 | " Pipe hdr | \n"
80 | " Pipe out | \n"
81 | " Pipe in | \n"
82 | "
\n"
83 | " \n"
84 | " \n"
85 | "
\n"
86 | "
Show detailed counters\n"
87 | "
\n"
88 | "
\n"
89 | "
\n"
90 | " Description | Name | Value |
\n"
91 | " \n"
92 | "
\n"
93 | "
\n"
94 | "
\n"
95 | "
\n"
96 | "
\n"
97 | "\n"
102 | "\n"
203 | "\n"
204 | "\n"
205 | ;
206 |
--------------------------------------------------------------------------------
/src/Makefile.am:
--------------------------------------------------------------------------------
1 | AM_CPPFLAGS = @VMOD_INCLUDES@ -Wall -Werror
2 |
3 | vmoddir = @VMOD_DIR@
4 | vmod_LTLIBRARIES = libvmod_rtstatus.la
5 |
6 | libvmod_rtstatus_la_LDFLAGS = -module -export-dynamic -avoid-version -shared $(VARNISHAPI_LIBS)
7 | libvmod_rtstatus_la_LIBADD = -lvarnishapi
8 |
9 | libvmod_rtstatus_la_SOURCES = \
10 | vmod_rtstatus.h \
11 | vmod_rtstatus.c \
12 | vmod_rtstatus_cache.c \
13 | HTML/vmod_html.h \
14 | HTML/vmod_html.c
15 |
16 | nodist_libvmod_rtstatus_la_SOURCES = \
17 | vcc_if.c \
18 | vcc_if.h
19 |
20 | vmod_rtstatus.lo: vcc_if.c vcc_if.h
21 |
22 | vcc_if.c: vcc_if.h
23 |
24 | vcc_if.h: @VMODTOOL@ $(top_srcdir)/src/vmod_rtstatus.vcc
25 | @VMODTOOL@ $(top_srcdir)/src/vmod_rtstatus.vcc
26 |
27 | VMOD_TESTS = $(top_srcdir)/src/tests/*.vtc
28 | .PHONY: $(VMOD_TESTS)
29 |
30 | $(top_srcdir)/src/tests/*.vtc:
31 | @VARNISHTEST@ -Dvarnishd=@VARNISHD@ -Dvmod_topbuild=$(abs_top_builddir) $@
32 |
33 |
34 | check: $(VMOD_TESTS)
35 |
36 | EXTRA_DIST = \
37 | vmod_rtstatus.vcc\
38 | $(VMOD_TESTS)
39 |
40 | CLEANFILES = \
41 | $(builddir)/vcc_if.c \
42 | $(builddir)/vcc_if.h \
43 | $(builddir)/vmod_rtstatus.rst \
44 | $(builddir)/vmod_rtstatus.man.rst
45 |
--------------------------------------------------------------------------------
/src/tests/test01.vtc:
--------------------------------------------------------------------------------
1 | varnishtest "Test rtstatus vmod"
2 | server s1 {
3 | rxreq
4 | txresp -body "012345\n"
5 | accept
6 | rxreq
7 | txresp -body "012345\n"
8 | accept
9 | rxreq
10 | txresp -body "012345\n"
11 | accept
12 | rxreq
13 | txresp -body "012345\n"
14 | accept
15 | rxreq
16 | txresp -body "012345\n"
17 | accept
18 | rxreq
19 | txresp -body "012345\n"
20 | } -start
21 |
22 | varnish v1 -vcl+backend {
23 | sub vcl_hit {
24 | return (restart);
25 | }
26 |
27 | sub vcl_synth {
28 | if (req.restarts == 2) {
29 | set resp.status = 200;
30 | set resp.reason = "restart=2";
31 | } elsif (req.restarts > 2) {
32 | set resp.status = 501;
33 | set resp.reason = "restart>2";
34 | } elsif (req.restarts < 2) {
35 | set resp.status = 500;
36 | set resp.reason = "restart<2";
37 | }
38 | }
39 | } -start
40 |
41 | varnish v1 -cliok "param.set max_restarts 2"
42 |
43 | client c1 {
44 | txreq -url "/"
45 | rxresp
46 | expect resp.status == 200
47 | } -run
48 |
49 | varnish v1 -cliok "param.set max_restarts 3"
50 |
51 | client c1 {
52 | txreq -url "/"
53 | rxresp
54 | expect resp.status == 501
55 | } -run
56 |
57 | varnish v1 -cliok "param.set max_restarts 1"
58 |
59 | client c1 {
60 | txreq -url "/"
61 | rxresp
62 | expect resp.status == 500
63 | } -run
64 |
--------------------------------------------------------------------------------
/src/tests/test03.vtc:
--------------------------------------------------------------------------------
1 | varnishtest "Test rtstatus not proper url"
2 |
3 | server s1 {
4 | rxreq
5 | txresp
6 | } -start
7 |
8 | varnish v1 -vcl+backend {
9 | import rtstatus from "${vmod_topbuild}/src/.libs/libvmod_rtstatus.so";
10 |
11 | sub vcl_recv {
12 | if (req.url !~ "/rtstatus") {
13 | return(synth(503, "KO"));
14 | }
15 | }
16 | } -start
17 |
18 | client c1 {
19 | txreq -url "/rtstati"
20 | rxresp
21 | expect resp.status == 503
22 | } -run
23 |
24 |
25 |
--------------------------------------------------------------------------------
/src/tests/test04.vtc:
--------------------------------------------------------------------------------
1 | varnishtest "Test rtstatus multiple varnish istances"
2 |
3 | server s1 {
4 | rxreq
5 | txresp
6 | } -start
7 |
8 | varnish v1 -vcl+backend {
9 | import rtstatus from "${vmod_topbuild}/src/.libs/libvmod_rtstatus.so";
10 |
11 | sub vcl_recv {
12 | if (req.url ~ "/rtstatus") {
13 | return(synth(200, "OK"));
14 | }
15 | }
16 | sub vcl_synth {
17 | if (resp.status == 200) {
18 | synthetic(rtstatus.rtstatus(1));
19 | return(deliver);
20 | }
21 | }
22 | } -start
23 |
24 | varnish v2 -vcl+backend {
25 | import rtstatus from "${vmod_topbuild}/src/.libs/libvmod_rtstatus.so";
26 |
27 | sub vcl_recv {
28 | if (req.url !~ "/rtstatus") {
29 | return(synth(503, "KO"));
30 | }
31 | }
32 | sub vcl_synth {
33 | if (resp.status == 503) {
34 | set resp.http.Header = "KO";
35 | return(deliver);
36 | }
37 | }
38 |
39 | } -start
40 |
41 | client c1 {
42 | txreq -url "/rtstatus"
43 | rxresp
44 | expect resp.status == 200
45 | } -start
46 |
47 | client c1 -connect ${v2_sock} {
48 | txreq -url "/rtstati"
49 | rxresp
50 | expect resp.status == 503
51 | expect resp.http.Header == "KO"
52 | } -run
53 |
54 |
--------------------------------------------------------------------------------
/src/vmod_rtstatus.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 |
7 | #include "vapi/vsc.h"
8 | #include "vmod_rtstatus.h"
9 |
10 | uint64_t beresp_hdr, beresp_body;
11 | uint64_t bereq_hdr, bereq_body;
12 | static struct hitrate hitrate;
13 | static struct load load;
14 | int n_be, cont;
15 |
16 | double
17 | VTIM_mono(void)
18 | {
19 | #ifdef HAVE_GETHRTIME
20 | return (gethrtime() * 1e-9);
21 | #elif HAVE_CLOCK_GETTIME
22 | struct timespec ts;
23 |
24 | clock_gettime(CLOCK_MONOTONIC, &ts);
25 | return (ts.tv_sec + 1e-9 * ts.tv_nsec);
26 | #else
27 | struct timeval tv;
28 |
29 | gettimeofday(&tv, NULL);
30 | return (tv.tv_sec + 1e-6 * tv.tv_usec);
31 | #endif
32 | }
33 |
34 | int
35 | init_function(struct vmod_priv *priv, const struct VCL_conf *conf)
36 | {
37 | memset(&hitrate, 0, sizeof(struct hitrate));
38 | memset(&load, 0, sizeof(struct load));
39 | beresp_hdr = beresp_body = 0;
40 | bereq_hdr = bereq_body = 0;
41 | n_be = 0;
42 | cont = 0;
43 | return (0);
44 | }
45 |
46 | static void
47 | update_counter(struct counter *counter, double val)
48 | {
49 | if (counter->n < counter->nmax)
50 | counter->n++;
51 | counter->acc += (val - counter->acc) / (double)counter->n;
52 | }
53 |
54 | void
55 | rate(struct iter_priv *iter, struct VSM_data *vd)
56 | {
57 | double hr, mr, ratio, tv, dt, reqload;
58 | struct VSC_C_main *VSC_C_main;
59 | uint64_t hit, miss;
60 | time_t up;
61 | int req;
62 |
63 | VSC_C_main = VSC_Main(vd, NULL);
64 | if (VSC_C_main == NULL)
65 | return;
66 |
67 | tv = VTIM_mono();
68 | dt = tv - hitrate.tm;
69 | hitrate.tm = tv;
70 |
71 | hit = VSC_C_main->cache_hit;
72 | miss = VSC_C_main->cache_miss;
73 | hr = (hit - hitrate.hit) / dt;
74 | mr = (miss - hitrate.miss) / dt;
75 | hitrate.hit = hit;
76 | hitrate.miss = miss;
77 |
78 | if (hr + mr != 0)
79 | ratio = hr / (hr + mr);
80 | else
81 | ratio = 0;
82 |
83 | up = VSC_C_main->uptime;
84 | req = VSC_C_main->client_req;
85 | reqload = ((req - load.req) / dt);
86 | load.req = req;
87 |
88 | update_counter(&hitrate.hr, ratio);
89 | update_counter(&load.rl, reqload);
90 |
91 | VSB_printf(iter->vsb, "\t\"uptime\" : \"%d+%02d:%02d:%02d\",\n",
92 | (int)up / 86400, (int)(up % 86400) / 3600,
93 | (int)(up % 3600) / 60, (int)up % 60);
94 | VSB_printf(iter->vsb, "\t\"uptime_sec\": \"%.2f\",\n", (double)up);
95 | VSB_printf(iter->vsb, "\t\"hitrate\": \"%.2f\",\n", hitrate.hr.acc * 100);
96 | VSB_printf(iter->vsb, "\t\"load\": \"%.2f\",\n", load.rl.acc);
97 | VSB_printf(iter->vsb, "\t\"delta\": \"%.2f\",\n", iter->delta);
98 | }
99 |
100 | int
101 | json_status(void *priv, const struct VSC_point *const pt)
102 | {
103 | struct iter_priv *iter = priv;
104 | const struct VSC_section *sec;
105 | uint64_t val;
106 |
107 | if (pt == NULL)
108 | return (0);
109 |
110 | val = *(const volatile uint64_t *)pt->ptr;
111 | sec = pt->section;
112 |
113 | if (iter->jp)
114 | iter->jp = 0;
115 | else
116 | VSB_cat(iter->vsb, ",\n");
117 | VSB_cat(iter->vsb, "\t\"");
118 | if (strcmp(sec->fantom->type, "")) {
119 | VSB_cat(iter->vsb, sec->fantom->type);
120 | VSB_cat(iter->vsb, ".");
121 | }
122 | if (strcmp(sec->fantom->ident, "")) {
123 | VSB_cat(iter->vsb, sec->fantom->ident);
124 | VSB_cat(iter->vsb, ".");
125 | }
126 | VSB_cat(iter->vsb, pt->desc->name);
127 | VSB_cat(iter->vsb, "\": {");
128 | if (strcmp(sec->fantom->type, "")) {
129 | VSB_cat(iter->vsb, "\"type\": \"");
130 | VSB_cat(iter->vsb, sec->fantom->type);
131 | VSB_cat(iter->vsb, "\", ");
132 | }
133 | if (strcmp(sec->fantom->ident, "")) {
134 | VSB_cat(iter->vsb, "\"ident\": \"");
135 | VSB_cat(iter->vsb, sec->fantom->ident);
136 | VSB_cat(iter->vsb, "\", ");
137 | }
138 | VSB_cat(iter->vsb, "\"descr\": \"");
139 | VSB_cat(iter->vsb, pt->desc->sdesc);
140 | VSB_cat(iter->vsb, "\", ");
141 | VSB_printf(iter->vsb,"\"value\": %" PRIu64 "}", val);
142 | if (iter->jp)
143 | VSB_cat(iter->vsb, "\n");
144 | return(0);
145 | }
146 |
147 | int
148 | creepy_math(void *priv, const struct VSC_point *const pt)
149 | {
150 | struct iter_priv *iter = priv;
151 | const struct VSC_section *sec;
152 | uint64_t val;
153 |
154 | if (pt == NULL)
155 | return (0);
156 |
157 | val = *(const volatile uint64_t *)pt->ptr;
158 | sec = pt->section;
159 | if(!strcmp(sec->fantom->type,"MAIN")){
160 | if(!strcmp(pt->desc->name, "n_backend")){
161 | n_be = (int)val;
162 | }
163 | }
164 | if (!strcmp(sec->fantom->type, "VBE")) {
165 | if(!strcmp(pt->desc->name, "bereq_hdrbytes"))
166 | bereq_hdr = val;
167 | if(!strcmp(pt->desc->name, "bereq_bodybytes")) {
168 | bereq_body = val;
169 | VSB_cat(iter->vsb, "{\"ident\":\"");
170 | VSB_cat(iter->vsb, pt->section->fantom->ident);
171 | VSB_printf(iter->vsb,"\", \"bereq_tot\": %" PRIu64 ",",
172 | bereq_body + bereq_hdr);
173 | }
174 |
175 | if(!strcmp(pt->desc->name, "beresp_hdrbytes"))
176 | beresp_hdr = val;
177 | if(!strcmp(pt->desc->name, "beresp_bodybytes")) {
178 | beresp_body = val;
179 | VSB_printf(iter->vsb,"\"beresp_tot\": %" PRIu64 "}",
180 | beresp_body + beresp_hdr);
181 | if(cont < (n_be -1)) {
182 | VSB_cat(iter->vsb, ",\n\t\t");
183 | cont++;
184 | }
185 | }
186 | }
187 | return(0);
188 | }
189 |
190 | int
191 | run_subroutine(struct iter_priv *iter, struct VSM_data *vd)
192 | {
193 | hitrate.hr.nmax = iter->delta;
194 | load.rl.nmax = iter->delta;
195 | VSB_cat(iter->vsb, "{\n");
196 | rate(iter, vd);
197 | general_info(iter);
198 | backend(iter);
199 | VSB_cat(iter->vsb, "\t\"be_bytes\": [");
200 | (void)VSC_Iter(vd, NULL, creepy_math, iter);
201 | VSB_cat(iter->vsb, "],\n");
202 | cont = 0;
203 | (void)VSC_Iter(vd, NULL, json_status, iter);
204 | VSB_cat(iter->vsb, "\n}\n");
205 | return(0);
206 | }
207 |
208 |
--------------------------------------------------------------------------------
/src/vmod_rtstatus.h:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 |
5 | #include "vsb.h"
6 | #include "vrt.h"
7 | #include "vrt_obj.h"
8 | #include "vapi/vsm.h"
9 |
10 | struct iter_priv{
11 | const struct vrt_ctx *cpy_ctx;
12 | struct vsb *vsb;
13 | int jp;
14 | double delta;
15 | };
16 | struct counter {
17 | unsigned n, nmax;
18 | double acc;
19 | };
20 |
21 | struct hitrate {
22 | double tm;
23 | uint64_t hit, miss;
24 | struct counter hr; /* hr stands for hitrate */
25 | };
26 | struct load {
27 | uint64_t req;
28 | struct counter rl; /* rl stands for reqload */
29 | };
30 |
31 |
32 | void WS_Release(struct ws *ws, unsigned bytes);
33 | unsigned WS_Reserve(struct ws *ws, unsigned bytes);
34 | int run_subroutine(struct iter_priv *iter, struct VSM_data *vd);
35 | int general_info(struct iter_priv *iter);
36 | int backend(struct iter_priv *iter);
37 |
--------------------------------------------------------------------------------
/src/vmod_rtstatus.vcc:
--------------------------------------------------------------------------------
1 | $Module rtstatus 3 rtstatus VMOD
2 | $Init init_function
3 | $Function STRING rtstatus(REAL delta)
4 | $Function STRING html()
5 |
--------------------------------------------------------------------------------
/src/vmod_rtstatus_cache.c:
--------------------------------------------------------------------------------
1 | #include "cache/cache.h"
2 | #include "vapi/vsm.h"
3 | #include "vcl.h"
4 | #include "cache/cache_backend.h"
5 | #include "vmod_rtstatus.h"
6 |
7 | int
8 | backend(struct iter_priv *iter)
9 | {
10 | const struct vrt_ctx *ctx = iter->cpy_ctx;
11 | int i;
12 |
13 | VSB_cat(iter->vsb, "\t\"backend\": [");
14 | for (i = 1; i < iter->cpy_ctx->vcl->ndirector; ++i) {
15 | CHECK_OBJ_NOTNULL(ctx->vcl->director[i], DIRECTOR_MAGIC);
16 | if (strcmp("simple", ctx->vcl->director[i]->name) == 0) {
17 | char buf[1024];
18 | int j, healthy;
19 | healthy = VDI_Healthy(ctx->vcl->director[i]);
20 | j = snprintf(buf, sizeof buf, "{\"director_name\" :"
21 | " \"%s\" , \"name\":\"%s\", \"value\": \"%s\"}",
22 | ctx->vcl->director[i]->name,
23 | ctx->vcl->director[i]->vcl_name,
24 | healthy ? "healthy" : "sick");
25 | assert(j >= 0);
26 | VSB_cat(iter->vsb, buf);
27 | if (i < (ctx->vcl->ndirector - 1)) {
28 | VSB_cat(iter->vsb, ",\n\t\t");
29 | }
30 | }
31 | }
32 | VSB_cat(iter->vsb, "],\n");
33 | return(0);
34 | }
35 |
36 | int
37 | general_info(struct iter_priv *iter)
38 | {
39 | static char vrt_hostname[255] = "";
40 | VSB_cat(iter->vsb, "\t\"varnish_version\" : \"");
41 | VSB_cat(iter->vsb, VCS_version);
42 | VSB_cat(iter->vsb, "\",\n");
43 | gethostname(vrt_hostname, sizeof(vrt_hostname));
44 | VSB_cat(iter->vsb, "\t\"server_id\": \"");
45 | VSB_cat(iter->vsb, vrt_hostname);
46 | VSB_cat(iter->vsb, "\",\n");
47 | return(0);
48 | }
49 |
50 | VCL_STRING
51 | vmod_rtstatus(const struct vrt_ctx *ctx, VCL_REAL delta)
52 | {
53 | struct iter_priv iter = { 0 };
54 | struct VSM_data *vd;
55 |
56 | if (delta < 1 || delta > 60) {
57 | VSLb(ctx->vsl, SLT_VCL_Error, "Delta has to be between"
58 | "1 and 60 seconds");
59 | return "{}";
60 |
61 | }
62 | vd = VSM_New();
63 | if (VSM_Open(vd)) {
64 | VSLb(ctx->vsl, SLT_VCL_Error, "Can't open VSM");
65 | VSM_Delete(vd);
66 | return "{}";
67 | }
68 | iter.vsb = ctx->req->synth_body;
69 | iter.cpy_ctx = ctx;
70 | iter.jp = 1;
71 | iter.delta = delta;
72 | run_subroutine(&iter, vd);
73 | VSM_Delete(vd);
74 | return "";
75 |
76 | }
77 |
--------------------------------------------------------------------------------
/varnishstatus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/varnish/libvmod-rtstatus/3c945939f3a72e01c30d58f3ec44442618827d8c/varnishstatus.png
--------------------------------------------------------------------------------