varnish-cache/bin/varnishtest/vtc_log.c
0
/*-
1
 * Copyright (c) 2008-2011 Varnish Software AS
2
 * All rights reserved.
3
 *
4
 * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
5
 *
6
 * SPDX-License-Identifier: BSD-2-Clause
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 * 1. Redistributions of source code must retain the above copyright
12
 *    notice, this list of conditions and the following disclaimer.
13
 * 2. Redistributions in binary form must reproduce the above copyright
14
 *    notice, this list of conditions and the following disclaimer in the
15
 *    documentation and/or other materials provided with the distribution.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
21
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27
 * SUCH DAMAGE.
28
 */
29
30
#include "config.h"
31
32
#include <math.h>
33
#include <stdarg.h>
34
#include <stdio.h>
35
#include <stdlib.h>
36
#include <string.h>
37
38
#include "vtc.h"
39
#include "vtc_log.h"
40
41
#include "vtim.h"
42
43
static pthread_mutex_t  vtclog_mtx;
44
static char             *vtclog_buf;
45
static unsigned         vtclog_left;
46
47
static pthread_key_t log_key;
48
static double t0;
49
50
void
51 11189
vtc_log_set_cmd(struct vtclog *vl, const struct cmds *cmds)
52
{
53 11189
        AN(cmds);
54 11189
        vl->cmds = cmds;
55 11189
}
56
57
/**********************************************************************/
58
59
#define GET_VL(vl)                                      \
60
        do {                                            \
61
                CHECK_OBJ_NOTNULL(vl, VTCLOG_MAGIC);    \
62
                PTOK(pthread_mutex_lock(&vl->mtx));     \
63
                vl->act = 1;                            \
64
                VSB_clear(vl->vsb);                     \
65
        } while(0)
66
67
#define REL_VL(vl)                                      \
68
        do {                                            \
69
                AZ(VSB_finish(vl->vsb));                \
70
                vtc_log_emit(vl);                       \
71
                VSB_clear(vl->vsb);                     \
72
                vl->act = 0;                            \
73
                PTOK(pthread_mutex_unlock(&vl->mtx));   \
74
        } while(0)
75
76
77
struct vtclog *
78 15662
vtc_logopen(const char *fmt, ...)
79
{
80
        struct vtclog *vl;
81
        va_list ap;
82
        char buf[BUFSIZ];
83
84 15662
        va_start(ap, fmt);
85 15662
        vbprintf(buf, fmt, ap);
86 15662
        va_end(ap);
87
88 15662
        ALLOC_OBJ(vl, VTCLOG_MAGIC);
89 15658
        AN(vl);
90 15658
        REPLACE(vl->id, buf);
91 15658
        vl->vsb = VSB_new_auto();
92 15658
        PTOK(pthread_mutex_init(&vl->mtx, NULL));
93 15658
        PTOK(pthread_setspecific(log_key, vl));
94 15658
        return (vl);
95
}
96
97
void
98 13644
vtc_logclose(void *arg)
99
{
100
        struct vtclog *vl;
101
102 13644
        CAST_OBJ_NOTNULL(vl, arg, VTCLOG_MAGIC);
103 13644
        if (pthread_getspecific(log_key) == vl)
104 7829
                PTOK(pthread_setspecific(log_key, NULL));
105 13644
        VSB_destroy(&vl->vsb);
106 13644
        PTOK(pthread_mutex_destroy(&vl->mtx));
107 13644
        REPLACE(vl->id, NULL);
108 13644
        FREE_OBJ(vl);
109 13644
}
110
111
static void v_noreturn_
112 4
vtc_logfail(void)
113
{
114
115 4
        vtc_error = 2;
116 4
        if (!pthread_equal(pthread_self(), vtc_thread))
117 0
                pthread_exit(NULL);
118
        else
119 4
                exit(fail_out());
120
121
        WRONG("unreachable"); /*lint !e827 Help Coverity Scan see noreturn. */
122
}
123
124
static const char * const lead[] = {
125
        "----",
126
        "*   ",
127
        "**  ",
128
        "*** ",
129
        "****"
130
};
131
132
#define NLEAD (sizeof(lead)/sizeof(lead[0]))
133
134
static void
135 897374
vtc_leadinv(const struct vtclog *vl, int lvl, const char *fmt, va_list ap)
136
{
137
138 897374
        assert(lvl < (int)NLEAD);
139 897374
        assert(lvl >= 0);
140 1794748
        VSB_printf(vl->vsb, "%s %-5s ",
141 897374
            lead[lvl < 0 ? 1: lvl], vl->id);
142 897374
        if (fmt != NULL)
143 897436
                (void)VSB_vprintf(vl->vsb, fmt, ap);
144 897498
}
145
146
static void
147 1340
vtc_leadin(const struct vtclog *vl, int lvl, const char *fmt, ...)
148
{
149
        va_list ap;
150
151 1340
        va_start(ap, fmt);
152 1340
        vtc_leadinv(vl, lvl, fmt, ap);
153 1340
        va_end(ap);
154 1340
}
155
156
static void
157 1137479
vtc_log_emit(const struct vtclog *vl)
158
{
159
        unsigned l;
160
        int i;
161
        int t_this;
162
        static int t_last = -1;
163
164 1137479
        l = VSB_len(vl->vsb);
165 1137479
        if (l == 0)
166 17030
                return;
167 1120449
        t_this = (int)round((VTIM_mono() - t0) * 1000);
168 1120449
        PTOK(pthread_mutex_lock(&vtclog_mtx));
169 1120449
        if (t_last != t_this) {
170 82687
                assert(vtclog_left > 25);
171 165374
                i = snprintf(vtclog_buf, vtclog_left,
172 82687
                    "**** dT    %d.%03d\n", t_this / 1000, t_this % 1000);
173 82687
                t_last = t_this;
174 82687
                vtclog_buf += i;
175 82687
                vtclog_left -= i;
176 82687
        }
177 1120449
        assert(vtclog_left > l);
178 1120449
        memcpy(vtclog_buf, VSB_data(vl->vsb), l);
179 1120449
        vtclog_buf += l;
180 1120449
        *vtclog_buf = '\0';
181 1120449
        vtclog_left -= l;
182 1120449
        PTOK(pthread_mutex_unlock(&vtclog_mtx));
183 1137479
}
184
185
void
186 4
vtc_fatal(struct vtclog *vl, const char *fmt, ...)
187
{
188
189 4
        GET_VL(vl);
190
        va_list ap;
191 4
        va_start(ap, fmt);
192 4
        vtc_leadinv(vl, 0, fmt, ap);
193 4
        VSB_putc(vl->vsb, '\n');
194 4
        va_end(ap);
195 4
        REL_VL(vl);
196
197 4
        vtc_logfail();
198
}
199
200
void
201 900252
vtc_log(struct vtclog *vl, int lvl, const char *fmt, ...)
202
{
203
204 900252
        GET_VL(vl);
205
        va_list ap;
206 900252
        va_start(ap, fmt);
207 900252
        if (lvl >= 0) {
208 896056
                vtc_leadinv(vl, lvl, fmt, ap);
209 896056
                VSB_putc(vl->vsb, '\n');
210 896056
        }
211 900252
        va_end(ap);
212 900252
        REL_VL(vl);
213
214 900252
        if (lvl == 0)
215 0
                vtc_logfail();
216 900252
}
217
218
/**********************************************************************
219
 * Dump a string
220
 */
221
222
#define MAX_DUMP 8192
223
224
void
225 236375
vtc_dump(struct vtclog *vl, int lvl, const char *pfx, const char *str, int len)
226
{
227
        char buf[64];
228 236375
        int quote = VSB_QUOTE_UNSAFE | VSB_QUOTE_ESCHEX;
229
230 236375
        AN(pfx);
231 236375
        GET_VL(vl);
232 236375
        if (str == NULL)
233 2
                vtc_leadin(vl, lvl, "%s(null)\n", pfx);
234
        else {
235 236373
                bprintf(buf, "%s %-5s %s|",
236
                    lead[lvl < 0 ? 1: lvl], vl->id, pfx);
237 236373
                if (len < 0)
238 191133
                        len = strlen(str);
239 45240
                else if (str[0] == 0x1f && (uint8_t)str[1] == 0x8b)
240 508
                        quote = VSB_QUOTE_HEX; // Dump gzip data in HEX
241 472746
                VSB_quote_pfx(vl->vsb, buf, str,
242 236373
                    len > MAX_DUMP ? MAX_DUMP : len, quote);
243 236373
                if (quote == VSB_QUOTE_HEX)
244 508
                        VSB_putc(vl->vsb, '\n');
245 236373
                if (len > MAX_DUMP)
246 936
                        VSB_printf(vl->vsb, "%s [...] (%d)\n",
247 468
                            buf, len - MAX_DUMP);
248
        }
249 236375
        REL_VL(vl);
250 236375
        if (lvl == 0)
251 0
                vtc_logfail();
252 236375
}
253
254
/**********************************************************************
255
 * Hexdump
256
 */
257
258
void
259 782
vtc_hexdump(struct vtclog *vl, int lvl, const char *pfx,
260
    const void *ptr, unsigned len)
261
{
262 782
        int nl = 1;
263
        unsigned l;
264 782
        const uint8_t *ss = ptr;
265
266 782
        AN(pfx);
267 782
        GET_VL(vl);
268 782
        if (ss == NULL)
269 0
                vtc_leadin(vl, lvl, "%s(null)\n", pfx);
270
        else {
271 13864
                for (l = 0; l < len; l++, ss++) {
272 13086
                        if (l > 512) {
273 4
                                VSB_cat(vl->vsb, "...");
274 4
                                break;
275
                        }
276 13082
                        if (nl) {
277 1338
                                vtc_leadin(vl, lvl, "%s| ", pfx);
278 1338
                                nl = 0;
279 1338
                        }
280 13082
                        VSB_printf(vl->vsb, " %02x", *ss);
281 13082
                        if ((l & 0xf) == 0xf) {
282 656
                                VSB_cat(vl->vsb, "\n");
283 656
                                nl = 1;
284 656
                        }
285 13082
                }
286
        }
287 782
        if (!nl)
288 682
                VSB_cat(vl->vsb, "\n");
289 782
        REL_VL(vl);
290 782
        if (lvl == 0)
291 0
                vtc_logfail();
292 782
}
293
294
/**********************************************************************/
295
296
static void v_noreturn_
297 0
vtc_log_VAS_Fail(const char *func, const char *file, int line,
298
    const char *cond, enum vas_e why)
299
{
300
        struct vtclog *vl;
301 0
        int e = errno;
302
303 0
        (void)why;
304 0
        vl = pthread_getspecific(log_key);
305 0
        if (vl == NULL || vl->act) {
306 0
                fprintf(stderr,
307
                    "Assert error in %s(), %s line %d:\n"
308
                    "  Condition(%s) not true. (errno=%d %s)\n",
309 0
                    func, file, line, cond, e, strerror(e));
310 0
        } else
311 0
                vtc_fatal(vl, "Assert error in %s(), %s line %d:"
312
                    "  Condition(%s) not true."
313 0
                    "  Errno=%d %s", func, file, line, cond, e, strerror(e));
314 0
        abort();
315
}
316
317
/**********************************************************************/
318
319
void
320 2014
vtc_loginit(char *buf, unsigned buflen)
321
{
322
323 2014
        VAS_Fail_Func = vtc_log_VAS_Fail;
324 2014
        t0 = VTIM_mono();
325 2014
        vtclog_buf = buf;
326 2014
        vtclog_left = buflen;
327 2014
        PTOK(pthread_mutex_init(&vtclog_mtx, NULL));
328 2014
        PTOK(pthread_key_create(&log_key, NULL));
329 2014
}