lsquic_logger.c revision b93f59be
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 124#ifdef WIN32 125struct timezone 126{ 127 int tz_minuteswest; /* minutes W of Greenwich */ 128 int tz_dsttime; /* type of dst correction */ 129}; 130 131static int 132gettimeofday (struct timeval *tv, struct timezone *tz) 133{ 134 FILETIME ft; 135 unsigned __int64 tmpres = 0; 136 static int tzflag; 137 138 if (NULL != tv) 139 { 140 GetSystemTimeAsFileTime(&ft); 141 142 tmpres |= ft.dwHighDateTime; 143 tmpres <<= 32; 144 tmpres |= ft.dwLowDateTime; 145 146 /*converting file time to unix epoch */ 147 tmpres -= DELTA_EPOCH_IN_MICROSECS; 148 tmpres /= 10; /*convert into microseconds */ 149 tv->tv_sec = (long) (tmpres / 1000000UL); 150 tv->tv_usec = (long) (tmpres % 1000000UL); 151 } 152 153 if (NULL != tz) 154 { 155 if (!tzflag) 156 { 157 _tzset(); 158 tzflag++; 159 } 160 tz->tz_minuteswest = _timezone / 60; 161 tz->tz_dsttime = _daylight; 162 } 163 164 return 0; 165} 166 167 168#endif 169 170 171static void 172print_timestamp (void) 173{ 174 struct tm tm; 175 struct timeval tv; 176 gettimeofday(&tv, NULL); 177 localtime_r(&tv.tv_sec, &tm); 178 if (g_llts == LLTS_YYYYMMDD_HHMMSSUS) 179 lsquic_printf("%04d-%02d-%02d %02d:%02d:%02d.%06d ", 180 tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, 181 tm.tm_hour, tm.tm_min, tm.tm_sec, (int) (tv.tv_usec)); 182 else if (g_llts == LLTS_YYYYMMDD_HHMMSSMS) 183 lsquic_printf("%04d-%02d-%02d %02d:%02d:%02d.%03d ", 184 tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, 185 tm.tm_hour, tm.tm_min, tm.tm_sec, (int) (tv.tv_usec / 1000)); 186 else if (g_llts == LLTS_HHMMSSMS) 187 lsquic_printf("%02d:%02d:%02d.%03d ", tm.tm_hour, tm.tm_min, 188 tm.tm_sec, (int) (tv.tv_usec / 1000)); 189 else if (g_llts == LLTS_HHMMSSUS) 190 lsquic_printf("%02d:%02d:%02d.%06d ", tm.tm_hour, tm.tm_min, 191 tm.tm_sec, (int) tv.tv_usec); 192 else if (g_llts == LLTS_CHROMELIKE) 193 lsquic_printf("%02d%02d/%02d%02d%02d.%06d ", tm.tm_mon + 1, 194 tm.tm_mday,tm.tm_hour, tm.tm_min, tm.tm_sec, (int) tv.tv_usec); 195} 196 197 198void 199lsquic_logger_log3 (enum lsq_log_level log_level, 200 enum lsquic_logger_module module, 201 uint64_t conn_id, uint32_t stream_id, const char *fmt, ...) 202{ 203 const int saved_errno = errno; 204 205 if (g_llts != LLTS_NONE) 206 print_timestamp(); 207 208 lsquic_printf("[%s] [QUIC:%"PRIu64"-%"PRIu32"] %s: ", 209 lsq_loglevel2str[log_level], conn_id, stream_id, lsqlm_to_str[module]); 210 va_list ap; 211 va_start(ap, fmt); 212 logger_if->vprintf(logger_ctx, fmt, ap); 213 va_end(ap); 214 lsquic_printf("\n"); 215 errno = saved_errno; 216} 217 218 219void 220lsquic_logger_log2 (enum lsq_log_level log_level, 221 enum lsquic_logger_module module, 222 uint64_t conn_id, const char *fmt, ...) 223{ 224 const int saved_errno = errno; 225 226 if (g_llts != LLTS_NONE) 227 print_timestamp(); 228 229 lsquic_printf("[%s] [QUIC:%"PRIu64"] %s: ", 230 lsq_loglevel2str[log_level], conn_id, lsqlm_to_str[module]); 231 va_list ap; 232 va_start(ap, fmt); 233 logger_if->vprintf(logger_ctx, fmt, ap); 234 va_end(ap); 235 lsquic_printf("\n"); 236 errno = saved_errno; 237} 238 239 240void 241lsquic_logger_log1 (enum lsq_log_level log_level, 242 enum lsquic_logger_module module, 243 const char *fmt, ...) 244{ 245 const int saved_errno = errno; 246 247 if (g_llts != LLTS_NONE) 248 print_timestamp(); 249 250 lsquic_printf("[%s] %s: ", lsq_loglevel2str[log_level], 251 lsqlm_to_str[module]); 252 va_list ap; 253 va_start(ap, fmt); 254 logger_if->vprintf(logger_ctx, fmt, ap); 255 va_end(ap); 256 lsquic_printf("\n"); 257 errno = saved_errno; 258} 259 260 261void 262lsquic_logger_log0 (enum lsq_log_level log_level, const char *fmt, ...) 263{ 264 const int saved_errno = errno; 265 266 if (g_llts != LLTS_NONE) 267 print_timestamp(); 268 269 lsquic_printf("[%s] ", lsq_loglevel2str[log_level]); 270 va_list ap; 271 va_start(ap, fmt); 272 logger_if->vprintf(logger_ctx, fmt, ap); 273 va_end(ap); 274 lsquic_printf("\n"); 275 errno = saved_errno; 276} 277 278 279void 280lsquic_logger_init (const struct lsquic_logger_if *lif, void *lctx, 281 unsigned llts) 282{ 283 logger_if = lif; 284 logger_ctx = lctx; 285 if (llts < N_LLTS) 286 g_llts = llts; 287 LSQ_DEBUG("%s called", __func__); 288} 289 290 291enum lsquic_logger_module 292lsquic_str_to_logger_module (const char *str) 293{ 294 enum lsquic_logger_module i; 295 for (i = 0; i < sizeof(lsqlm_to_str) / sizeof(lsqlm_to_str[0]); ++i) 296 if (0 == strcasecmp(lsqlm_to_str[i], str)) 297 return i; 298 return -1; 299} 300 301 302enum lsq_log_level 303lsquic_str_to_log_level (const char *str) 304{ 305 if (0 == strcasecmp(str, "emerg")) 306 return LSQ_LOG_EMERG; 307 if (0 == strcasecmp(str, "alert")) 308 return LSQ_LOG_ALERT; 309 if (0 == strcasecmp(str, "crit")) 310 return LSQ_LOG_CRIT; 311 if (0 == strcasecmp(str, "error")) 312 return LSQ_LOG_ERROR; 313 if (0 == strcasecmp(str, "warn")) 314 return LSQ_LOG_WARN; 315 if (0 == strcasecmp(str, "notice")) 316 return LSQ_LOG_NOTICE; 317 if (0 == strcasecmp(str, "info")) 318 return LSQ_LOG_INFO; 319 if (0 == strcasecmp(str, "debug")) 320 return LSQ_LOG_DEBUG; 321 return -1; 322} 323 324 325void 326lsquic_log_to_fstream (FILE *file, unsigned llts) 327{ 328 lsquic_logger_init(&file_logger_if, file, llts); 329} 330 331 332int 333lsquic_logger_lopt (const char *optarg_orig) 334{ 335 char *const optarg = strdup(optarg_orig); 336 char *mod_str; 337 int i; 338 for (i = 0; (mod_str = strtok(i ? NULL : optarg, ",")); ++i) { 339 char *level_str = strchr(mod_str, '='); 340 if (!level_str) { 341 fprintf(stderr, "Invalid module specification `%s'\n", mod_str); 342 break; 343 } 344 *level_str = '\0'; 345 ++level_str; 346 enum lsquic_logger_module mod = lsquic_str_to_logger_module(mod_str); 347 if (-1 == (int) mod) { 348 fprintf(stderr, "`%s' is not a valid module name\n", mod_str); 349 break; 350 } 351 enum lsq_log_level level = lsquic_str_to_log_level(level_str); 352 if (-1 == (int) level) { 353 fprintf(stderr, "`%s' is not a valid level\n", level_str); 354 break; 355 } 356 lsq_log_levels[mod] = level; 357 LSQ_INFO("set %s to %s", mod_str, level_str); 358 } 359 free(optarg); 360 return mod_str == NULL ? 0 : -1; 361} 362 363 364int 365lsquic_set_log_level (const char *level_str) 366{ 367 enum lsq_log_level level; 368 unsigned i; 369 370 level = lsquic_str_to_log_level(level_str); 371 if ((int) level >= 0) 372 { 373 for (i = 0; i < sizeof(lsq_log_levels) / sizeof(lsq_log_levels[0]); ++i) 374 lsq_log_levels[i] = level; 375 return 0; 376 } 377 else 378 return -1; 379} 380 381 382