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