lsquic_logger.c revision bfc7bfd8
1/* Copyright (c) 2017 LiteSpeed Technologies Inc.  See LICENSE. */
2/*
3 * LSQUIC Logger implementation.
4 */
5
6#include <errno.h>
7#include <inttypes.h>
8#include <stdarg.h>
9#include <stdio.h>
10#include <stdlib.h>
11#include <string.h>
12#include <sys/time.h>
13#include <time.h>
14
15#define LSQUIC_LOGGER_MODULE LSQLM_LOGGER /* Quis custodiet ipsos custodes? */
16#include "lsquic_logger.h"
17#include "lsquic.h"
18
19static enum lsquic_logger_timestamp_style g_llts = LLTS_NONE;
20
21static int
22null_vprintf (void *ctx, const char *fmt, va_list ap)
23{
24    return 0;
25}
26
27
28static int
29file_vprintf (void *ctx, const char *fmt, va_list ap)
30{
31    return vfprintf((FILE *) ctx, fmt, ap);
32}
33
34
35static const struct lsquic_logger_if file_logger_if = {
36    .vprintf    = file_vprintf,
37};
38
39static const struct lsquic_logger_if null_logger_if = {
40    .vprintf    = null_vprintf,
41};
42
43static void *logger_ctx = NULL;
44static const struct lsquic_logger_if *logger_if = &null_logger_if;
45
46enum lsq_log_level lsq_log_levels[N_LSQUIC_LOGGER_MODULES] = {
47    [LSQLM_NOMODULE]    = LSQ_LOG_WARN,
48    [LSQLM_LOGGER]      = LSQ_LOG_WARN,
49    [LSQLM_EVENT]       = LSQ_LOG_WARN,
50    [LSQLM_ENGINE]      = LSQ_LOG_WARN,
51    [LSQLM_CONN]        = LSQ_LOG_WARN,
52    [LSQLM_RECHIST]     = LSQ_LOG_WARN,
53    [LSQLM_STREAM]      = LSQ_LOG_WARN,
54    [LSQLM_PARSE]       = LSQ_LOG_WARN,
55    [LSQLM_CFCW]        = LSQ_LOG_WARN,
56    [LSQLM_SFCW]        = LSQ_LOG_WARN,
57    [LSQLM_SENDCTL]     = LSQ_LOG_WARN,
58    [LSQLM_ALARMSET]    = LSQ_LOG_WARN,
59    [LSQLM_CRYPTO]      = LSQ_LOG_WARN,
60    [LSQLM_HANDSHAKE]   = LSQ_LOG_WARN,
61    [LSQLM_HSK_ADAPTER] = LSQ_LOG_WARN,
62    [LSQLM_CUBIC]       = LSQ_LOG_WARN,
63    [LSQLM_HEADERS]     = LSQ_LOG_WARN,
64    [LSQLM_FRAME_READER]= LSQ_LOG_WARN,
65    [LSQLM_FRAME_WRITER]= LSQ_LOG_WARN,
66    [LSQLM_CONN_HASH]   = LSQ_LOG_WARN,
67    [LSQLM_ENG_HIST]    = LSQ_LOG_WARN,
68    [LSQLM_SPI]         = LSQ_LOG_WARN,
69    [LSQLM_DI]          = LSQ_LOG_WARN,
70    [LSQLM_PACER]       = LSQ_LOG_WARN,
71};
72
73const char *const lsqlm_to_str[N_LSQUIC_LOGGER_MODULES] = {
74    [LSQLM_NOMODULE]    = "",
75    [LSQLM_LOGGER]      = "logger",
76    [LSQLM_EVENT]       = "event",
77    [LSQLM_ENGINE]      = "engine",
78    [LSQLM_CONN]        = "conn",
79    [LSQLM_RECHIST]     = "rechist",
80    [LSQLM_STREAM]      = "stream",
81    [LSQLM_PARSE]       = "parse",
82    [LSQLM_CFCW]        = "cfcw",
83    [LSQLM_SFCW]        = "sfcw",
84    [LSQLM_SENDCTL]     = "sendctl",
85    [LSQLM_ALARMSET]    = "alarmset",
86    [LSQLM_CRYPTO]      = "crypto",
87    [LSQLM_HANDSHAKE]   = "handshake",
88    [LSQLM_HSK_ADAPTER] = "hsk-adapter",
89    [LSQLM_CUBIC]       = "cubic",
90    [LSQLM_HEADERS]     = "headers",
91    [LSQLM_FRAME_READER]= "frame-reader",
92    [LSQLM_FRAME_WRITER]= "frame-writer",
93    [LSQLM_CONN_HASH]   = "conn-hash",
94    [LSQLM_ENG_HIST]    = "eng-hist",
95    [LSQLM_SPI]         = "spi",
96    [LSQLM_DI]          = "di",
97    [LSQLM_PACER]       = "pacer",
98};
99
100const char *const lsq_loglevel2str[N_LSQUIC_LOG_LEVELS] = {
101    [LSQ_LOG_ALERT]   =  "ALERT",
102    [LSQ_LOG_CRIT]    =  "CRIT",
103    [LSQ_LOG_DEBUG]   =  "DEBUG",
104    [LSQ_LOG_EMERG]   =  "EMERG",
105    [LSQ_LOG_ERROR]   =  "ERROR",
106    [LSQ_LOG_INFO]    =  "INFO",
107    [LSQ_LOG_NOTICE]  =  "NOTICE",
108    [LSQ_LOG_WARN]    =  "WARN",
109};
110
111
112static void
113lsquic_printf (const char *fmt, ...)
114{
115    va_list ap;
116    va_start(ap, fmt);
117    logger_if->vprintf(logger_ctx, fmt, ap);
118    va_end(ap);
119}
120
121
122static void
123print_timestamp (void)
124{
125    struct tm tm;
126    struct timeval tv;
127    gettimeofday(&tv, NULL);
128    localtime_r(&tv.tv_sec, &tm);
129    if (g_llts == LLTS_YYYYMMDD_HHMMSSUS)
130        lsquic_printf("%04d-%02d-%02d %02d:%02d:%02d.%06d ",
131            tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
132            tm.tm_hour, tm.tm_min, tm.tm_sec, (int) (tv.tv_usec));
133    else if (g_llts == LLTS_YYYYMMDD_HHMMSSMS)
134        lsquic_printf("%04d-%02d-%02d %02d:%02d:%02d.%03d ",
135            tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
136            tm.tm_hour, tm.tm_min, tm.tm_sec, (int) (tv.tv_usec / 1000));
137    else if (g_llts == LLTS_HHMMSSMS)
138        lsquic_printf("%02d:%02d:%02d.%03d ", tm.tm_hour, tm.tm_min,
139                                    tm.tm_sec, (int) (tv.tv_usec / 1000));
140    else if (g_llts == LLTS_HHMMSSUS)
141        lsquic_printf("%02d:%02d:%02d.%06d ", tm.tm_hour, tm.tm_min,
142                                    tm.tm_sec, (int) tv.tv_usec);
143    else if (g_llts == LLTS_CHROMELIKE)
144        lsquic_printf("%02d%02d/%02d%02d%02d.%06d ", tm.tm_mon + 1,
145            tm.tm_mday,tm.tm_hour, tm.tm_min, tm.tm_sec, (int) tv.tv_usec);
146}
147
148
149void
150lsquic_logger_log3 (enum lsq_log_level log_level,
151                    enum lsquic_logger_module module,
152                    uint64_t conn_id, uint32_t stream_id, const char *fmt, ...)
153{
154    const int saved_errno = errno;
155
156    if (g_llts != LLTS_NONE)
157        print_timestamp();
158
159    lsquic_printf("[%s] [QUIC:%"PRIu64"-%"PRIu32"] %s: ",
160        lsq_loglevel2str[log_level], conn_id, stream_id, lsqlm_to_str[module]);
161    va_list ap;
162    va_start(ap, fmt);
163    logger_if->vprintf(logger_ctx, fmt, ap);
164    va_end(ap);
165    lsquic_printf("\n");
166    errno = saved_errno;
167}
168
169
170void
171lsquic_logger_log2 (enum lsq_log_level log_level,
172                    enum lsquic_logger_module module,
173                    uint64_t conn_id, const char *fmt, ...)
174{
175    const int saved_errno = errno;
176
177    if (g_llts != LLTS_NONE)
178        print_timestamp();
179
180    lsquic_printf("[%s] [QUIC:%"PRIu64"] %s: ",
181        lsq_loglevel2str[log_level], conn_id, lsqlm_to_str[module]);
182    va_list ap;
183    va_start(ap, fmt);
184    logger_if->vprintf(logger_ctx, fmt, ap);
185    va_end(ap);
186    lsquic_printf("\n");
187    errno = saved_errno;
188}
189
190
191void
192lsquic_logger_log1 (enum lsq_log_level log_level,
193                    enum lsquic_logger_module module,
194                    const char *fmt, ...)
195{
196    const int saved_errno = errno;
197
198    if (g_llts != LLTS_NONE)
199        print_timestamp();
200
201    lsquic_printf("[%s] %s: ", lsq_loglevel2str[log_level],
202                                                lsqlm_to_str[module]);
203    va_list ap;
204    va_start(ap, fmt);
205    logger_if->vprintf(logger_ctx, fmt, ap);
206    va_end(ap);
207    lsquic_printf("\n");
208    errno = saved_errno;
209}
210
211
212void
213lsquic_logger_log0 (enum lsq_log_level log_level, const char *fmt, ...)
214{
215    const int saved_errno = errno;
216
217    if (g_llts != LLTS_NONE)
218        print_timestamp();
219
220    lsquic_printf("[%s] ", lsq_loglevel2str[log_level]);
221    va_list ap;
222    va_start(ap, fmt);
223    logger_if->vprintf(logger_ctx, fmt, ap);
224    va_end(ap);
225    lsquic_printf("\n");
226    errno = saved_errno;
227}
228
229
230void
231lsquic_logger_init (const struct lsquic_logger_if *lif, void *lctx,
232                    unsigned llts)
233{
234    logger_if  = lif;
235    logger_ctx = lctx;
236    if (llts < N_LLTS)
237        g_llts = llts;
238    LSQ_DEBUG("%s called", __func__);
239}
240
241
242enum lsquic_logger_module
243lsquic_str_to_logger_module (const char *str)
244{
245    enum lsquic_logger_module i;
246    for (i = 0; i < sizeof(lsqlm_to_str) / sizeof(lsqlm_to_str[0]); ++i)
247        if (0 == strcasecmp(lsqlm_to_str[i], str))
248            return i;
249    return -1;
250}
251
252
253enum lsq_log_level
254lsquic_str_to_log_level (const char *str)
255{
256    if (0 == strcasecmp(str, "emerg"))
257        return LSQ_LOG_EMERG;
258    if (0 == strcasecmp(str, "alert"))
259        return LSQ_LOG_ALERT;
260    if (0 == strcasecmp(str, "crit"))
261        return LSQ_LOG_CRIT;
262    if (0 == strcasecmp(str, "error"))
263        return LSQ_LOG_ERROR;
264    if (0 == strcasecmp(str, "warn"))
265        return LSQ_LOG_WARN;
266    if (0 == strcasecmp(str, "notice"))
267        return LSQ_LOG_NOTICE;
268    if (0 == strcasecmp(str, "info"))
269        return LSQ_LOG_INFO;
270    if (0 == strcasecmp(str, "debug"))
271        return LSQ_LOG_DEBUG;
272    return -1;
273}
274
275
276void
277lsquic_log_to_fstream (FILE *file, unsigned llts)
278{
279    lsquic_logger_init(&file_logger_if, file, llts);
280}
281
282
283int
284lsquic_logger_lopt (const char *optarg_orig)
285{
286    char *const optarg = strdup(optarg_orig);
287    char *mod_str;
288    int i;
289    for (i = 0; (mod_str = strtok(i ? NULL : optarg, ",")); ++i) {
290        char *level_str = strchr(mod_str, '=');
291        if (!level_str) {
292            fprintf(stderr, "Invalid module specification `%s'\n", mod_str);
293            break;
294        }
295        *level_str = '\0';
296        ++level_str;
297        enum lsquic_logger_module mod = lsquic_str_to_logger_module(mod_str);
298        if (-1 == (int) mod) {
299            fprintf(stderr, "`%s' is not a valid module name\n", mod_str);
300            break;
301        }
302        enum lsq_log_level level = lsquic_str_to_log_level(level_str);
303        if (-1 == (int) level) {
304            fprintf(stderr, "`%s' is not a valid level\n", level_str);
305            break;
306        }
307        lsq_log_levels[mod] = level;
308        LSQ_INFO("set %s to %s", mod_str, level_str);
309    }
310    free(optarg);
311    return mod_str == NULL ? 0 : -1;
312}
313
314
315int
316lsquic_set_log_level (const char *level_str)
317{
318    enum lsq_log_level level;
319    unsigned i;
320
321    level = lsquic_str_to_log_level(level_str);
322    if ((int) level >= 0)
323    {
324        for (i = 0; i < sizeof(lsq_log_levels) / sizeof(lsq_log_levels[0]); ++i)
325            lsq_log_levels[i] = level;
326        return 0;
327    }
328    else
329        return -1;
330}
331
332
333