lsquic_logger.c revision 55cd0b38
1229fce07SDmitri Tikhonov/* Copyright (c) 2017 - 2019 LiteSpeed Technologies Inc.  See LICENSE. */
250aadb33SDmitri Tikhonov/*
350aadb33SDmitri Tikhonov * LSQUIC Logger implementation.
450aadb33SDmitri Tikhonov */
550aadb33SDmitri Tikhonov
6560db45bSDmitri Tikhonov#include <assert.h>
750aadb33SDmitri Tikhonov#include <errno.h>
850aadb33SDmitri Tikhonov#include <inttypes.h>
950aadb33SDmitri Tikhonov#include <stdarg.h>
1050aadb33SDmitri Tikhonov#include <stdio.h>
1150aadb33SDmitri Tikhonov#include <stdlib.h>
1250aadb33SDmitri Tikhonov#include <string.h>
13461e84d8SAmol Deshpande#ifndef WIN32
1450aadb33SDmitri Tikhonov#include <sys/time.h>
15461e84d8SAmol Deshpande#endif
1650aadb33SDmitri Tikhonov#include <time.h>
1750aadb33SDmitri Tikhonov
1850aadb33SDmitri Tikhonov#define LSQUIC_LOGGER_MODULE LSQLM_LOGGER /* Quis custodiet ipsos custodes? */
1950aadb33SDmitri Tikhonov#include "lsquic_logger.h"
203229dd11SDmitri Tikhonov#include "lsquic_byteswap.h"
2150aadb33SDmitri Tikhonov#include "lsquic.h"
2250aadb33SDmitri Tikhonov
233229dd11SDmitri Tikhonov/* The switch to big-endian format in GQUIC also resulted in Chrome swapping
243229dd11SDmitri Tikhonov * the CID in its log.  We do the same thing in our log messages so that the
253229dd11SDmitri Tikhonov * CIDs are easy to match.  The exception is Q035, which is the last little-
263229dd11SDmitri Tikhonov * endian GQUIC version this library supports.
273229dd11SDmitri Tikhonov */
283229dd11SDmitri Tikhonov#if __BYTE_ORDER == __LITTLE_ENDIAN
293229dd11SDmitri Tikhonov#define DISP_CID(cid) bswap_64(cid)
303229dd11SDmitri Tikhonov#else
313229dd11SDmitri Tikhonov#define DISP_CID(cid) (cid)
323229dd11SDmitri Tikhonov#endif
333229dd11SDmitri Tikhonov
3450aadb33SDmitri Tikhonovstatic enum lsquic_logger_timestamp_style g_llts = LLTS_NONE;
3550aadb33SDmitri Tikhonov
3650aadb33SDmitri Tikhonovstatic int
3750aadb33SDmitri Tikhonovnull_vprintf (void *ctx, const char *fmt, va_list ap)
3850aadb33SDmitri Tikhonov{
3950aadb33SDmitri Tikhonov    return 0;
4050aadb33SDmitri Tikhonov}
4150aadb33SDmitri Tikhonov
4250aadb33SDmitri Tikhonov
4350aadb33SDmitri Tikhonovstatic int
4450aadb33SDmitri Tikhonovfile_vprintf (void *ctx, const char *fmt, va_list ap)
4550aadb33SDmitri Tikhonov{
4650aadb33SDmitri Tikhonov    return vfprintf((FILE *) ctx, fmt, ap);
4750aadb33SDmitri Tikhonov}
4850aadb33SDmitri Tikhonov
4950aadb33SDmitri Tikhonov
5050aadb33SDmitri Tikhonovstatic const struct lsquic_logger_if file_logger_if = {
5150aadb33SDmitri Tikhonov    .vprintf    = file_vprintf,
5250aadb33SDmitri Tikhonov};
5350aadb33SDmitri Tikhonov
5450aadb33SDmitri Tikhonovstatic const struct lsquic_logger_if null_logger_if = {
5550aadb33SDmitri Tikhonov    .vprintf    = null_vprintf,
5650aadb33SDmitri Tikhonov};
5750aadb33SDmitri Tikhonov
5850aadb33SDmitri Tikhonovstatic void *logger_ctx = NULL;
5950aadb33SDmitri Tikhonovstatic const struct lsquic_logger_if *logger_if = &null_logger_if;
6050aadb33SDmitri Tikhonov
6150aadb33SDmitri Tikhonovenum lsq_log_level lsq_log_levels[N_LSQUIC_LOGGER_MODULES] = {
6250aadb33SDmitri Tikhonov    [LSQLM_NOMODULE]    = LSQ_LOG_WARN,
6350aadb33SDmitri Tikhonov    [LSQLM_LOGGER]      = LSQ_LOG_WARN,
6450aadb33SDmitri Tikhonov    [LSQLM_EVENT]       = LSQ_LOG_WARN,
6550aadb33SDmitri Tikhonov    [LSQLM_ENGINE]      = LSQ_LOG_WARN,
6650aadb33SDmitri Tikhonov    [LSQLM_CONN]        = LSQ_LOG_WARN,
6750aadb33SDmitri Tikhonov    [LSQLM_RECHIST]     = LSQ_LOG_WARN,
6850aadb33SDmitri Tikhonov    [LSQLM_STREAM]      = LSQ_LOG_WARN,
6950aadb33SDmitri Tikhonov    [LSQLM_PARSE]       = LSQ_LOG_WARN,
7050aadb33SDmitri Tikhonov    [LSQLM_CFCW]        = LSQ_LOG_WARN,
7150aadb33SDmitri Tikhonov    [LSQLM_SFCW]        = LSQ_LOG_WARN,
7250aadb33SDmitri Tikhonov    [LSQLM_SENDCTL]     = LSQ_LOG_WARN,
7350aadb33SDmitri Tikhonov    [LSQLM_ALARMSET]    = LSQ_LOG_WARN,
7450aadb33SDmitri Tikhonov    [LSQLM_CRYPTO]      = LSQ_LOG_WARN,
7550aadb33SDmitri Tikhonov    [LSQLM_HANDSHAKE]   = LSQ_LOG_WARN,
7650aadb33SDmitri Tikhonov    [LSQLM_HSK_ADAPTER] = LSQ_LOG_WARN,
7750aadb33SDmitri Tikhonov    [LSQLM_CUBIC]       = LSQ_LOG_WARN,
7850aadb33SDmitri Tikhonov    [LSQLM_HEADERS]     = LSQ_LOG_WARN,
7950aadb33SDmitri Tikhonov    [LSQLM_FRAME_READER]= LSQ_LOG_WARN,
8050aadb33SDmitri Tikhonov    [LSQLM_FRAME_WRITER]= LSQ_LOG_WARN,
8150aadb33SDmitri Tikhonov    [LSQLM_CONN_HASH]   = LSQ_LOG_WARN,
8250aadb33SDmitri Tikhonov    [LSQLM_ENG_HIST]    = LSQ_LOG_WARN,
8350aadb33SDmitri Tikhonov    [LSQLM_SPI]         = LSQ_LOG_WARN,
8450aadb33SDmitri Tikhonov    [LSQLM_DI]          = LSQ_LOG_WARN,
8550aadb33SDmitri Tikhonov    [LSQLM_PACER]       = LSQ_LOG_WARN,
86e8bd737dSDmitri Tikhonov    [LSQLM_MIN_HEAP]    = LSQ_LOG_WARN,
873b55e6aeSDmitri Tikhonov    [LSQLM_HTTP1X]      = LSQ_LOG_WARN,
8855cd0b38SDmitri Tikhonov    [LSQLM_QLOG]        = LSQ_LOG_WARN,
8950aadb33SDmitri Tikhonov};
9050aadb33SDmitri Tikhonov
9150aadb33SDmitri Tikhonovconst char *const lsqlm_to_str[N_LSQUIC_LOGGER_MODULES] = {
9250aadb33SDmitri Tikhonov    [LSQLM_NOMODULE]    = "",
9350aadb33SDmitri Tikhonov    [LSQLM_LOGGER]      = "logger",
9450aadb33SDmitri Tikhonov    [LSQLM_EVENT]       = "event",
9550aadb33SDmitri Tikhonov    [LSQLM_ENGINE]      = "engine",
9650aadb33SDmitri Tikhonov    [LSQLM_CONN]        = "conn",
9750aadb33SDmitri Tikhonov    [LSQLM_RECHIST]     = "rechist",
9850aadb33SDmitri Tikhonov    [LSQLM_STREAM]      = "stream",
9950aadb33SDmitri Tikhonov    [LSQLM_PARSE]       = "parse",
10050aadb33SDmitri Tikhonov    [LSQLM_CFCW]        = "cfcw",
10150aadb33SDmitri Tikhonov    [LSQLM_SFCW]        = "sfcw",
10250aadb33SDmitri Tikhonov    [LSQLM_SENDCTL]     = "sendctl",
10350aadb33SDmitri Tikhonov    [LSQLM_ALARMSET]    = "alarmset",
10450aadb33SDmitri Tikhonov    [LSQLM_CRYPTO]      = "crypto",
10550aadb33SDmitri Tikhonov    [LSQLM_HANDSHAKE]   = "handshake",
10650aadb33SDmitri Tikhonov    [LSQLM_HSK_ADAPTER] = "hsk-adapter",
10750aadb33SDmitri Tikhonov    [LSQLM_CUBIC]       = "cubic",
10850aadb33SDmitri Tikhonov    [LSQLM_HEADERS]     = "headers",
10950aadb33SDmitri Tikhonov    [LSQLM_FRAME_READER]= "frame-reader",
11050aadb33SDmitri Tikhonov    [LSQLM_FRAME_WRITER]= "frame-writer",
11150aadb33SDmitri Tikhonov    [LSQLM_CONN_HASH]   = "conn-hash",
11250aadb33SDmitri Tikhonov    [LSQLM_ENG_HIST]    = "eng-hist",
11350aadb33SDmitri Tikhonov    [LSQLM_SPI]         = "spi",
11450aadb33SDmitri Tikhonov    [LSQLM_DI]          = "di",
11550aadb33SDmitri Tikhonov    [LSQLM_PACER]       = "pacer",
116e8bd737dSDmitri Tikhonov    [LSQLM_MIN_HEAP]    = "min-heap",
1173b55e6aeSDmitri Tikhonov    [LSQLM_HTTP1X]      = "http1x",
11855cd0b38SDmitri Tikhonov    [LSQLM_QLOG]        = "qlog",
11950aadb33SDmitri Tikhonov};
12050aadb33SDmitri Tikhonov
12150aadb33SDmitri Tikhonovconst char *const lsq_loglevel2str[N_LSQUIC_LOG_LEVELS] = {
12250aadb33SDmitri Tikhonov    [LSQ_LOG_ALERT]   =  "ALERT",
12350aadb33SDmitri Tikhonov    [LSQ_LOG_CRIT]    =  "CRIT",
12450aadb33SDmitri Tikhonov    [LSQ_LOG_DEBUG]   =  "DEBUG",
12550aadb33SDmitri Tikhonov    [LSQ_LOG_EMERG]   =  "EMERG",
12650aadb33SDmitri Tikhonov    [LSQ_LOG_ERROR]   =  "ERROR",
12750aadb33SDmitri Tikhonov    [LSQ_LOG_INFO]    =  "INFO",
12850aadb33SDmitri Tikhonov    [LSQ_LOG_NOTICE]  =  "NOTICE",
12950aadb33SDmitri Tikhonov    [LSQ_LOG_WARN]    =  "WARN",
13050aadb33SDmitri Tikhonov};
13150aadb33SDmitri Tikhonov
13250aadb33SDmitri Tikhonov
13350aadb33SDmitri Tikhonovstatic void
13450aadb33SDmitri Tikhonovlsquic_printf (const char *fmt, ...)
13550aadb33SDmitri Tikhonov{
13650aadb33SDmitri Tikhonov    va_list ap;
13750aadb33SDmitri Tikhonov    va_start(ap, fmt);
13850aadb33SDmitri Tikhonov    logger_if->vprintf(logger_ctx, fmt, ap);
13950aadb33SDmitri Tikhonov    va_end(ap);
14050aadb33SDmitri Tikhonov}
14150aadb33SDmitri Tikhonov
14250aadb33SDmitri Tikhonov
143b93f59beSBob Perper#ifdef WIN32
144560db45bSDmitri Tikhonov#define DELTA_EPOCH_IN_TICKS  116444736000000000Ui64
145b93f59beSBob Perperstruct timezone
146b93f59beSBob Perper{
147ab5c8df2SBob Perper    time_t tz_minuteswest;         /* minutes W of Greenwich */
148ab5c8df2SBob Perper    time_t tz_dsttime;             /* type of dst correction */
149b93f59beSBob Perper};
150b93f59beSBob Perper
151b93f59beSBob Perperstatic int
152b93f59beSBob Perpergettimeofday (struct timeval *tv, struct timezone *tz)
153b93f59beSBob Perper{
154b93f59beSBob Perper    FILETIME ft;
155560db45bSDmitri Tikhonov    uint64_t tmpres;
156b93f59beSBob Perper    static int tzflag;
157b93f59beSBob Perper
158b93f59beSBob Perper    if (NULL != tv)
159b93f59beSBob Perper    {
160b93f59beSBob Perper        GetSystemTimeAsFileTime(&ft);
161b93f59beSBob Perper
162560db45bSDmitri Tikhonov        tmpres = ((uint64_t) ft.dwHighDateTime << 32)
163560db45bSDmitri Tikhonov               | (ft.dwLowDateTime);
164b93f59beSBob Perper
165560db45bSDmitri Tikhonov        tmpres -= DELTA_EPOCH_IN_TICKS;
166560db45bSDmitri Tikhonov        tv->tv_sec = tmpres / 10000000;
167560db45bSDmitri Tikhonov        tv->tv_usec = tmpres % 1000000;
168b93f59beSBob Perper    }
169b93f59beSBob Perper
170b93f59beSBob Perper    if (NULL != tz)
171b93f59beSBob Perper    {
172b93f59beSBob Perper        if (!tzflag)
173b93f59beSBob Perper        {
174b93f59beSBob Perper            _tzset();
175b93f59beSBob Perper            tzflag++;
176b93f59beSBob Perper        }
177b93f59beSBob Perper        tz->tz_minuteswest = _timezone / 60;
178b93f59beSBob Perper        tz->tz_dsttime = _daylight;
179b93f59beSBob Perper    }
180b93f59beSBob Perper
181b93f59beSBob Perper    return 0;
182b93f59beSBob Perper}
183b93f59beSBob Perper
184b93f59beSBob Perper
185b93f59beSBob Perper#endif
186b93f59beSBob Perper
187b93f59beSBob Perper
18850aadb33SDmitri Tikhonovstatic void
18950aadb33SDmitri Tikhonovprint_timestamp (void)
19050aadb33SDmitri Tikhonov{
19150aadb33SDmitri Tikhonov    struct tm tm;
19250aadb33SDmitri Tikhonov    struct timeval tv;
19350aadb33SDmitri Tikhonov    gettimeofday(&tv, NULL);
194ab5c8df2SBob Perper#ifdef WIN32
195ab5c8df2SBob Perper    {
1967b1586ddSDmitri Tikhonov        time_t t = tv.tv_sec;
197560db45bSDmitri Tikhonov#ifndef NDEBUG
1987b1586ddSDmitri Tikhonov        errno_t e =
199560db45bSDmitri Tikhonov#endif
2007b1586ddSDmitri Tikhonov	localtime_s(&tm, &t);
201560db45bSDmitri Tikhonov	assert(!e);
202ab5c8df2SBob Perper    }
203ab5c8df2SBob Perper#else
20450aadb33SDmitri Tikhonov    localtime_r(&tv.tv_sec, &tm);
205ab5c8df2SBob Perper#endif
206bfc7bfd8SDmitri Tikhonov    if (g_llts == LLTS_YYYYMMDD_HHMMSSUS)
207bfc7bfd8SDmitri Tikhonov        lsquic_printf("%04d-%02d-%02d %02d:%02d:%02d.%06d ",
208bfc7bfd8SDmitri Tikhonov            tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
209bfc7bfd8SDmitri Tikhonov            tm.tm_hour, tm.tm_min, tm.tm_sec, (int) (tv.tv_usec));
210bfc7bfd8SDmitri Tikhonov    else if (g_llts == LLTS_YYYYMMDD_HHMMSSMS)
21150aadb33SDmitri Tikhonov        lsquic_printf("%04d-%02d-%02d %02d:%02d:%02d.%03d ",
21250aadb33SDmitri Tikhonov            tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
21350aadb33SDmitri Tikhonov            tm.tm_hour, tm.tm_min, tm.tm_sec, (int) (tv.tv_usec / 1000));
21450aadb33SDmitri Tikhonov    else if (g_llts == LLTS_HHMMSSMS)
21550aadb33SDmitri Tikhonov        lsquic_printf("%02d:%02d:%02d.%03d ", tm.tm_hour, tm.tm_min,
21650aadb33SDmitri Tikhonov                                    tm.tm_sec, (int) (tv.tv_usec / 1000));
21750aadb33SDmitri Tikhonov    else if (g_llts == LLTS_HHMMSSUS)
21850aadb33SDmitri Tikhonov        lsquic_printf("%02d:%02d:%02d.%06d ", tm.tm_hour, tm.tm_min,
21950aadb33SDmitri Tikhonov                                    tm.tm_sec, (int) tv.tv_usec);
22050aadb33SDmitri Tikhonov    else if (g_llts == LLTS_CHROMELIKE)
22150aadb33SDmitri Tikhonov        lsquic_printf("%02d%02d/%02d%02d%02d.%06d ", tm.tm_mon + 1,
22250aadb33SDmitri Tikhonov            tm.tm_mday,tm.tm_hour, tm.tm_min, tm.tm_sec, (int) tv.tv_usec);
22350aadb33SDmitri Tikhonov}
22450aadb33SDmitri Tikhonov
22550aadb33SDmitri Tikhonov
22650aadb33SDmitri Tikhonovvoid
22750aadb33SDmitri Tikhonovlsquic_logger_log3 (enum lsq_log_level log_level,
22850aadb33SDmitri Tikhonov                    enum lsquic_logger_module module,
22950aadb33SDmitri Tikhonov                    uint64_t conn_id, uint32_t stream_id, const char *fmt, ...)
23050aadb33SDmitri Tikhonov{
23150aadb33SDmitri Tikhonov    const int saved_errno = errno;
23250aadb33SDmitri Tikhonov
23350aadb33SDmitri Tikhonov    if (g_llts != LLTS_NONE)
23450aadb33SDmitri Tikhonov        print_timestamp();
23550aadb33SDmitri Tikhonov
23650aadb33SDmitri Tikhonov    lsquic_printf("[%s] [QUIC:%"PRIu64"-%"PRIu32"] %s: ",
2373229dd11SDmitri Tikhonov        lsq_loglevel2str[log_level], DISP_CID(conn_id), stream_id,
2383229dd11SDmitri Tikhonov        lsqlm_to_str[module]);
23950aadb33SDmitri Tikhonov    va_list ap;
24050aadb33SDmitri Tikhonov    va_start(ap, fmt);
24150aadb33SDmitri Tikhonov    logger_if->vprintf(logger_ctx, fmt, ap);
24250aadb33SDmitri Tikhonov    va_end(ap);
24350aadb33SDmitri Tikhonov    lsquic_printf("\n");
24450aadb33SDmitri Tikhonov    errno = saved_errno;
24550aadb33SDmitri Tikhonov}
24650aadb33SDmitri Tikhonov
24750aadb33SDmitri Tikhonov
24850aadb33SDmitri Tikhonovvoid
24950aadb33SDmitri Tikhonovlsquic_logger_log2 (enum lsq_log_level log_level,
25050aadb33SDmitri Tikhonov                    enum lsquic_logger_module module,
25150aadb33SDmitri Tikhonov                    uint64_t conn_id, const char *fmt, ...)
25250aadb33SDmitri Tikhonov{
25350aadb33SDmitri Tikhonov    const int saved_errno = errno;
25450aadb33SDmitri Tikhonov
25550aadb33SDmitri Tikhonov    if (g_llts != LLTS_NONE)
25650aadb33SDmitri Tikhonov        print_timestamp();
25750aadb33SDmitri Tikhonov
25850aadb33SDmitri Tikhonov    lsquic_printf("[%s] [QUIC:%"PRIu64"] %s: ",
2593229dd11SDmitri Tikhonov        lsq_loglevel2str[log_level], DISP_CID(conn_id), lsqlm_to_str[module]);
26050aadb33SDmitri Tikhonov    va_list ap;
26150aadb33SDmitri Tikhonov    va_start(ap, fmt);
26250aadb33SDmitri Tikhonov    logger_if->vprintf(logger_ctx, fmt, ap);
26350aadb33SDmitri Tikhonov    va_end(ap);
26450aadb33SDmitri Tikhonov    lsquic_printf("\n");
26550aadb33SDmitri Tikhonov    errno = saved_errno;
26650aadb33SDmitri Tikhonov}
26750aadb33SDmitri Tikhonov
26850aadb33SDmitri Tikhonov
26950aadb33SDmitri Tikhonovvoid
27050aadb33SDmitri Tikhonovlsquic_logger_log1 (enum lsq_log_level log_level,
27150aadb33SDmitri Tikhonov                    enum lsquic_logger_module module,
27250aadb33SDmitri Tikhonov                    const char *fmt, ...)
27350aadb33SDmitri Tikhonov{
27450aadb33SDmitri Tikhonov    const int saved_errno = errno;
27550aadb33SDmitri Tikhonov
27650aadb33SDmitri Tikhonov    if (g_llts != LLTS_NONE)
27750aadb33SDmitri Tikhonov        print_timestamp();
27850aadb33SDmitri Tikhonov
27950aadb33SDmitri Tikhonov    lsquic_printf("[%s] %s: ", lsq_loglevel2str[log_level],
28050aadb33SDmitri Tikhonov                                                lsqlm_to_str[module]);
28150aadb33SDmitri Tikhonov    va_list ap;
28250aadb33SDmitri Tikhonov    va_start(ap, fmt);
28350aadb33SDmitri Tikhonov    logger_if->vprintf(logger_ctx, fmt, ap);
28450aadb33SDmitri Tikhonov    va_end(ap);
28550aadb33SDmitri Tikhonov    lsquic_printf("\n");
28650aadb33SDmitri Tikhonov    errno = saved_errno;
28750aadb33SDmitri Tikhonov}
28850aadb33SDmitri Tikhonov
28950aadb33SDmitri Tikhonov
29050aadb33SDmitri Tikhonovvoid
29150aadb33SDmitri Tikhonovlsquic_logger_log0 (enum lsq_log_level log_level, const char *fmt, ...)
29250aadb33SDmitri Tikhonov{
29350aadb33SDmitri Tikhonov    const int saved_errno = errno;
29450aadb33SDmitri Tikhonov
29550aadb33SDmitri Tikhonov    if (g_llts != LLTS_NONE)
29650aadb33SDmitri Tikhonov        print_timestamp();
29750aadb33SDmitri Tikhonov
29850aadb33SDmitri Tikhonov    lsquic_printf("[%s] ", lsq_loglevel2str[log_level]);
29950aadb33SDmitri Tikhonov    va_list ap;
30050aadb33SDmitri Tikhonov    va_start(ap, fmt);
30150aadb33SDmitri Tikhonov    logger_if->vprintf(logger_ctx, fmt, ap);
30250aadb33SDmitri Tikhonov    va_end(ap);
30350aadb33SDmitri Tikhonov    lsquic_printf("\n");
30450aadb33SDmitri Tikhonov    errno = saved_errno;
30550aadb33SDmitri Tikhonov}
30650aadb33SDmitri Tikhonov
30750aadb33SDmitri Tikhonov
30850aadb33SDmitri Tikhonovvoid
30950aadb33SDmitri Tikhonovlsquic_logger_init (const struct lsquic_logger_if *lif, void *lctx,
31050aadb33SDmitri Tikhonov                    unsigned llts)
31150aadb33SDmitri Tikhonov{
31250aadb33SDmitri Tikhonov    logger_if  = lif;
31350aadb33SDmitri Tikhonov    logger_ctx = lctx;
31450aadb33SDmitri Tikhonov    if (llts < N_LLTS)
31550aadb33SDmitri Tikhonov        g_llts = llts;
31650aadb33SDmitri Tikhonov    LSQ_DEBUG("%s called", __func__);
31750aadb33SDmitri Tikhonov}
31850aadb33SDmitri Tikhonov
31950aadb33SDmitri Tikhonov
32050aadb33SDmitri Tikhonovenum lsquic_logger_module
32150aadb33SDmitri Tikhonovlsquic_str_to_logger_module (const char *str)
32250aadb33SDmitri Tikhonov{
32350aadb33SDmitri Tikhonov    enum lsquic_logger_module i;
32450aadb33SDmitri Tikhonov    for (i = 0; i < sizeof(lsqlm_to_str) / sizeof(lsqlm_to_str[0]); ++i)
32550aadb33SDmitri Tikhonov        if (0 == strcasecmp(lsqlm_to_str[i], str))
32650aadb33SDmitri Tikhonov            return i;
32750aadb33SDmitri Tikhonov    return -1;
32850aadb33SDmitri Tikhonov}
32950aadb33SDmitri Tikhonov
33050aadb33SDmitri Tikhonov
33150aadb33SDmitri Tikhonovenum lsq_log_level
33250aadb33SDmitri Tikhonovlsquic_str_to_log_level (const char *str)
33350aadb33SDmitri Tikhonov{
33450aadb33SDmitri Tikhonov    if (0 == strcasecmp(str, "emerg"))
33550aadb33SDmitri Tikhonov        return LSQ_LOG_EMERG;
33650aadb33SDmitri Tikhonov    if (0 == strcasecmp(str, "alert"))
33750aadb33SDmitri Tikhonov        return LSQ_LOG_ALERT;
33850aadb33SDmitri Tikhonov    if (0 == strcasecmp(str, "crit"))
33950aadb33SDmitri Tikhonov        return LSQ_LOG_CRIT;
34050aadb33SDmitri Tikhonov    if (0 == strcasecmp(str, "error"))
34150aadb33SDmitri Tikhonov        return LSQ_LOG_ERROR;
34250aadb33SDmitri Tikhonov    if (0 == strcasecmp(str, "warn"))
34350aadb33SDmitri Tikhonov        return LSQ_LOG_WARN;
34450aadb33SDmitri Tikhonov    if (0 == strcasecmp(str, "notice"))
34550aadb33SDmitri Tikhonov        return LSQ_LOG_NOTICE;
34650aadb33SDmitri Tikhonov    if (0 == strcasecmp(str, "info"))
34750aadb33SDmitri Tikhonov        return LSQ_LOG_INFO;
34850aadb33SDmitri Tikhonov    if (0 == strcasecmp(str, "debug"))
34950aadb33SDmitri Tikhonov        return LSQ_LOG_DEBUG;
35050aadb33SDmitri Tikhonov    return -1;
35150aadb33SDmitri Tikhonov}
35250aadb33SDmitri Tikhonov
35350aadb33SDmitri Tikhonov
35450aadb33SDmitri Tikhonovvoid
35550aadb33SDmitri Tikhonovlsquic_log_to_fstream (FILE *file, unsigned llts)
35650aadb33SDmitri Tikhonov{
35750aadb33SDmitri Tikhonov    lsquic_logger_init(&file_logger_if, file, llts);
35850aadb33SDmitri Tikhonov}
35950aadb33SDmitri Tikhonov
36050aadb33SDmitri Tikhonov
36150aadb33SDmitri Tikhonovint
36250aadb33SDmitri Tikhonovlsquic_logger_lopt (const char *optarg_orig)
36350aadb33SDmitri Tikhonov{
36450aadb33SDmitri Tikhonov    char *const optarg = strdup(optarg_orig);
36550aadb33SDmitri Tikhonov    char *mod_str;
36650aadb33SDmitri Tikhonov    int i;
36750aadb33SDmitri Tikhonov    for (i = 0; (mod_str = strtok(i ? NULL : optarg, ",")); ++i) {
36850aadb33SDmitri Tikhonov        char *level_str = strchr(mod_str, '=');
36950aadb33SDmitri Tikhonov        if (!level_str) {
37050aadb33SDmitri Tikhonov            fprintf(stderr, "Invalid module specification `%s'\n", mod_str);
37150aadb33SDmitri Tikhonov            break;
37250aadb33SDmitri Tikhonov        }
37350aadb33SDmitri Tikhonov        *level_str = '\0';
37450aadb33SDmitri Tikhonov        ++level_str;
37550aadb33SDmitri Tikhonov        enum lsquic_logger_module mod = lsquic_str_to_logger_module(mod_str);
37650aadb33SDmitri Tikhonov        if (-1 == (int) mod) {
37750aadb33SDmitri Tikhonov            fprintf(stderr, "`%s' is not a valid module name\n", mod_str);
37850aadb33SDmitri Tikhonov            break;
37950aadb33SDmitri Tikhonov        }
38050aadb33SDmitri Tikhonov        enum lsq_log_level level = lsquic_str_to_log_level(level_str);
38150aadb33SDmitri Tikhonov        if (-1 == (int) level) {
38250aadb33SDmitri Tikhonov            fprintf(stderr, "`%s' is not a valid level\n", level_str);
38350aadb33SDmitri Tikhonov            break;
38450aadb33SDmitri Tikhonov        }
38550aadb33SDmitri Tikhonov        lsq_log_levels[mod] = level;
38650aadb33SDmitri Tikhonov        LSQ_INFO("set %s to %s", mod_str, level_str);
38750aadb33SDmitri Tikhonov    }
38850aadb33SDmitri Tikhonov    free(optarg);
38950aadb33SDmitri Tikhonov    return mod_str == NULL ? 0 : -1;
39050aadb33SDmitri Tikhonov}
39150aadb33SDmitri Tikhonov
39250aadb33SDmitri Tikhonov
39350aadb33SDmitri Tikhonovint
39450aadb33SDmitri Tikhonovlsquic_set_log_level (const char *level_str)
39550aadb33SDmitri Tikhonov{
39650aadb33SDmitri Tikhonov    enum lsq_log_level level;
39750aadb33SDmitri Tikhonov    unsigned i;
39850aadb33SDmitri Tikhonov
39950aadb33SDmitri Tikhonov    level = lsquic_str_to_log_level(level_str);
40050aadb33SDmitri Tikhonov    if ((int) level >= 0)
40150aadb33SDmitri Tikhonov    {
40250aadb33SDmitri Tikhonov        for (i = 0; i < sizeof(lsq_log_levels) / sizeof(lsq_log_levels[0]); ++i)
40350aadb33SDmitri Tikhonov            lsq_log_levels[i] = level;
40450aadb33SDmitri Tikhonov        return 0;
40550aadb33SDmitri Tikhonov    }
40650aadb33SDmitri Tikhonov    else
40750aadb33SDmitri Tikhonov        return -1;
40850aadb33SDmitri Tikhonov}
409