varnish-cache/bin/varnishstat/varnishstat.c
0
/*-
1
 * Copyright (c) 2006 Verdens Gang AS
2
 * Copyright (c) 2006-2015 Varnish Software AS
3
 * All rights reserved.
4
 *
5
 * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
6
 * Author: Dag-Erling Smørgrav <des@des.no>
7
 *
8
 * SPDX-License-Identifier: BSD-2-Clause
9
 *
10
 * Redistribution and use in source and binary forms, with or without
11
 * modification, are permitted provided that the following conditions
12
 * are met:
13
 * 1. Redistributions of source code must retain the above copyright
14
 *    notice, this list of conditions and the following disclaimer.
15
 * 2. Redistributions in binary form must reproduce the above copyright
16
 *    notice, this list of conditions and the following disclaimer in the
17
 *    documentation and/or other materials provided with the distribution.
18
 *
19
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
23
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29
 * SUCH DAMAGE.
30
 *
31
 * Statistics output program
32
 */
33
34
#include "config.h"
35
36
#include <stdarg.h>
37
#include <stdio.h>
38
#include <stdlib.h>
39
#include <signal.h>
40
#include <string.h>
41
#include <time.h>
42
#include <unistd.h>
43
#include <math.h>
44
45
#define VOPT_DEFINITION
46
#define VOPT_INC "varnishstat_options.h"
47
48
#include "vapi/voptget.h"
49
#include "vapi/vsl.h"
50
#include "vdef.h"
51
#include "vut.h"
52
53
#include "varnishstat.h"
54
55
static struct VUT *vut;
56
int has_f = 0;
57
58
/*--------------------------------------------------------------------*/
59
60
static int v_matchproto_(VSC_iter_f)
61 3040
do_xml_cb(void *priv, const struct VSC_point * const pt)
62
{
63
        uint64_t val;
64
65 3040
        (void)priv;
66 3040
        if (pt == NULL)
67 0
                return (0);
68 3040
        AZ(strcmp(pt->ctype, "uint64_t"));
69 3040
        val = VSC_Value(pt);
70
71 3040
        printf("\t<stat>\n");
72 3040
        printf("\t\t<name>%s</name>\n", pt->name);
73 3040
        printf("\t\t<value>%ju</value>\n", (uintmax_t)val);
74 3040
        printf("\t\t<flag>%c</flag>\n", pt->semantics);
75 3040
        printf("\t\t<format>%c</format>\n", pt->format);
76 3040
        printf("\t\t<description>%s</description>\n", pt->sdesc);
77 3040
        printf("\t</stat>\n");
78 3040
        return (0);
79 3040
}
80
81
static void
82 8
do_xml(struct vsm *vsm, struct vsc *vsc)
83
{
84
        char time_stamp[20];
85
        time_t now;
86
87 8
        printf("<?xml version=\"1.0\"?>\n");
88 8
        now = time(NULL);
89 8
        (void)strftime(time_stamp, 20, "%Y-%m-%dT%H:%M:%S", localtime(&now));
90 8
        printf("<varnishstat timestamp=\"%s\">\n", time_stamp);
91 8
        (void)VSC_Iter(vsc, vsm, do_xml_cb, NULL);
92 8
        printf("</varnishstat>\n");
93 8
}
94
95
96
/*--------------------------------------------------------------------*/
97
98
static int v_matchproto_(VSC_iter_f)
99 12160
do_json_cb(void *priv, const struct VSC_point * const pt)
100
{
101
        const char **sep;
102
        uintmax_t val;
103
104 12160
        if (pt == NULL)
105 0
                return (0);
106
107 12160
        AZ(strcmp(pt->ctype, "uint64_t"));
108 12160
        val = (uintmax_t)VSC_Value(pt);
109
110 12160
        sep = priv;
111
112 12160
        printf(
113
            "%s"
114
            "    \"%s\": {\n"
115
            "      \"description\": \"%s\",\n"
116
            "      \"flag\": \"%c\",\n"
117
            "      \"format\": \"%c\",\n"
118
            "      \"value\": %ju\n"
119
            "    }",
120 12160
            *sep, pt->name, pt->sdesc, pt->semantics, pt->format, val);
121
122 12160
        *sep = ",\n";
123 12160
        return (0);
124 12160
}
125
126
static void
127 32
do_json(struct vsm *vsm, struct vsc *vsc)
128
{
129
        const char *sep;
130
        char time_stamp[20];
131
        time_t now;
132
133 32
        sep = "";
134 32
        now = time(NULL);
135
136 32
        (void)strftime(time_stamp, 20, "%Y-%m-%dT%H:%M:%S", localtime(&now));
137 32
        printf(
138
            "{\n"
139
            "  \"version\": 1,\n"
140
            "  \"timestamp\": \"%s\",\n"
141 32
            "  \"counters\": {\n", time_stamp);
142 32
        (void)VSC_Iter(vsc, vsm, do_json_cb, &sep);
143 32
        printf(
144
            "\n"
145
            "  }\n"
146
            "}\n");
147 32
}
148
149
150
/*--------------------------------------------------------------------*/
151
152
struct once_priv {
153
        double  up;
154
        int pad;
155
};
156
157
static int v_matchproto_(VSC_iter_f)
158 80
do_once_cb_first(void *priv, const struct VSC_point * const pt)
159
{
160
        struct once_priv *op;
161
        uint64_t val;
162
163 80
        if (pt == NULL)
164 0
                return (0);
165 80
        op = priv;
166 80
        AZ(strcmp(pt->ctype, "uint64_t"));
167 80
        if (strcmp(pt->name, "MAIN.uptime"))
168 0
                return (0);
169 80
        val = VSC_Value(pt);
170 80
        op->up = (double)val;
171 80
        return (1);
172 80
}
173
174
static int v_matchproto_(VSC_iter_f)
175 30040
do_once_cb(void *priv, const struct VSC_point * const pt)
176
{
177
        struct once_priv *op;
178
        uint64_t val;
179
        int i;
180
181 30040
        if (pt == NULL)
182 0
                return (0);
183 30040
        op = priv;
184 30040
        AZ(strcmp(pt->ctype, "uint64_t"));
185 30040
        val = VSC_Value(pt);
186 30040
        i = 0;
187 30040
        i += printf("%s", pt->name);
188 30040
        if (i >= op->pad)
189 192
                op->pad = i + 1;
190 30040
        printf("%*.*s", op->pad - i, op->pad - i, "");
191 30040
        if (pt->semantics == 'c')
192 26632
                printf("%12ju %12.2f %s\n",
193 26632
                    (uintmax_t)val, op->up ? val / op->up : 0,
194 26632
                    pt->sdesc);
195
        else
196 3408
                printf("%12ju %12s %s\n",
197 3408
                    (uintmax_t)val, ".  ", pt->sdesc);
198 30040
        return (0);
199 30040
}
200
201
static void
202 80
do_once(struct vsm *vsm, struct vsc *vsc)
203
{
204 80
        struct vsc *vsconce = VSC_New();
205
        struct once_priv op;
206
207 80
        AN(vsconce);
208 80
        AN(VSC_Arg(vsconce, 'f', "MAIN.uptime"));
209
210 80
        memset(&op, 0, sizeof op);
211 80
        op.pad = 18;
212
213 80
        (void)VSC_Iter(vsconce, vsm, do_once_cb_first, &op);
214 80
        VSC_Destroy(&vsconce, vsm);
215 80
        (void)VSC_Iter(vsc, vsm, do_once_cb, &op);
216 80
}
217
218
/*--------------------------------------------------------------------*/
219
220
static int v_matchproto_(VSC_iter_f)
221 3040
do_list_cb(void *priv, const struct VSC_point * const pt)
222
{
223
        int i;
224
225 3040
        (void)priv;
226
227 3040
        if (pt == NULL)
228 0
                return (0);
229
230 3040
        i = 0;
231 3040
        i += printf("%s", pt->name);
232 3040
        if (i < 30)
233 3016
                printf("%*s", i - 30, "");
234 3040
        printf(" %s\n", pt->sdesc);
235 3040
        return (0);
236 3040
}
237
238
static void
239 8
list_fields(struct vsm *vsm, struct vsc *vsc)
240
{
241 8
        printf("Varnishstat -f option fields:\n");
242 8
        printf("Field name                     Description\n");
243 8
        printf("----------                     -----------\n");
244
245 8
        (void)VSC_Iter(vsc, vsm, do_list_cb, NULL);
246 8
}
247
248
/*--------------------------------------------------------------------*/
249
250
static void v_noreturn_
251 16
usage(int status)
252
{
253
        const char **opt;
254
255 16
        fprintf(stderr, "Usage: %s <options>\n\n", vut->progname);
256 16
        fprintf(stderr, "Options:\n");
257 224
        for (opt = vopt_spec.vopt_usage; *opt != NULL; opt +=2)
258 208
                fprintf(stderr, " %-25s %s\n", *opt, *(opt + 1));
259 16
        exit(status);
260
}
261
262
static int
263 8
key_bindings(void)
264
{
265
266
#define BINDING_KEY(chr, name, next)    \
267
        printf("<%s>" next, name);
268
#define BINDING(name, desc)             \
269
        printf("\n%s\n\n", desc);
270
#include "varnishstat_bindings.h"
271
        return (0);
272
}
273
274
int
275 248
main(int argc, char * const *argv)
276
{
277
        struct vsm *vd;
278 248
        int once = 0, xml = 0, json = 0, f_list = 0, curses = 0;
279
        signed char opt;
280
        int i;
281
        struct vsc *vsc;
282
283 248
        if (argc == 2 && !strcmp(argv[1], "--bindings"))
284 8
                exit(key_bindings());
285
286 240
        vut = VUT_InitProg(argc, argv, &vopt_spec);
287 240
        AN(vut);
288 240
        vd = VSM_New();
289 240
        AN(vd);
290 240
        vsc = VSC_New();
291 240
        AN(vsc);
292
293 720
        while ((opt = getopt(argc, argv, vopt_spec.vopt_optstring)) != -1) {
294 512
                switch (opt) {
295
                case '1':
296 80
                        once = 1;
297 80
                        break;
298
                case 'c':
299 0
                        curses = 1;
300 0
                        break;
301
                case 'h':
302
                        /* Usage help */
303 8
                        usage(0);
304
                        break;
305
                case 'l':
306 8
                        f_list = 1;
307 8
                        break;
308
                case 'x':
309 8
                        xml = 1;
310 8
                        break;
311
                case 'j':
312 32
                        json = 1;
313 32
                        break;
314
                case 'I':
315
                case 'X':
316
                case 'f':
317 152
                        AN(VSC_Arg(vsc, opt, optarg));
318 152
                        has_f = 1;
319 152
                        break;
320
                case 'r':
321 0
                        AN(VSC_Arg(vsc, opt, optarg));
322 0
                        break;
323
                case 'V':
324 0
                        AN(VUT_Arg(vut, opt, optarg));
325 0
                        break;
326
                default:
327 224
                        i = VSM_Arg(vd, opt, optarg);
328 224
                        if (i < 0)
329 24
                                VUT_Error(vut, 1, "%s", VSM_Error(vd));
330 200
                        if (!i)
331 0
                                usage(1);
332 200
                }
333
        }
334
335 208
        if (optind != argc)
336 8
                usage(1);
337
338 200
        if (!(curses || xml || json || once || f_list)) {
339 72
                curses = isatty(STDOUT_FILENO);
340 72
                once = !curses;
341 72
        }
342
343 200
        if (VSM_Attach(vd, STDERR_FILENO))
344 16
                VUT_Error(vut, 1, "%s", VSM_Error(vd));
345
346 184
        if (curses) {
347 56
                if (has_f) {
348 16
                        AN(VSC_Arg(vsc, 'R', "MGT.uptime"));
349 16
                        AN(VSC_Arg(vsc, 'R', "MAIN.uptime"));
350 16
                        AN(VSC_Arg(vsc, 'R', "MAIN.cache_hit"));
351 16
                        AN(VSC_Arg(vsc, 'R', "MAIN.cache_miss"));
352 16
                }
353 56
                do_curses(vd, vsc);
354 56
        }
355 128
        else if (xml)
356 8
                do_xml(vd, vsc);
357 120
        else if (json)
358 32
                do_json(vd, vsc);
359 88
        else if (once)
360 80
                do_once(vd, vsc);
361 8
        else if (f_list)
362 8
                list_fields(vd, vsc);
363
        else
364 0
                WRONG("undefined varnishstat mode");
365
366 184
        exit(0);
367
}