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