1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2010-2014 Intel Corporation 3 */ 4 5 #include <stdio.h> 6 #include <stdint.h> 7 #include <stdarg.h> 8 #include <stdlib.h> 9 #include <string.h> 10 #include <errno.h> 11 #include <regex.h> 12 #include <fnmatch.h> 13 #include <sys/queue.h> 14 15 #include <rte_log.h> 16 #include <rte_per_lcore.h> 17 18 #include "log_internal.h" 19 20 #ifdef RTE_EXEC_ENV_WINDOWS 21 #define strdup _strdup 22 #endif 23 24 struct rte_log_dynamic_type { 25 const char *name; 26 uint32_t loglevel; 27 }; 28 29 /** The rte_log structure. */ 30 static struct rte_logs { 31 uint32_t type; /**< Bitfield with enabled logs. */ 32 uint32_t level; /**< Log level. */ 33 FILE *file; /**< Output file set by rte_openlog_stream, or NULL. */ 34 size_t dynamic_types_len; 35 struct rte_log_dynamic_type *dynamic_types; 36 } rte_logs = { 37 .type = UINT32_MAX, 38 .level = RTE_LOG_DEBUG, 39 }; 40 41 struct rte_eal_opt_loglevel { 42 /** Next list entry */ 43 TAILQ_ENTRY(rte_eal_opt_loglevel) next; 44 /** Compiled regular expression obtained from the option */ 45 regex_t re_match; 46 /** Globbing pattern option */ 47 char *pattern; 48 /** Log level value obtained from the option */ 49 uint32_t level; 50 }; 51 52 TAILQ_HEAD(rte_eal_opt_loglevel_list, rte_eal_opt_loglevel); 53 54 /** List of valid EAL log level options */ 55 static struct rte_eal_opt_loglevel_list opt_loglevel_list = 56 TAILQ_HEAD_INITIALIZER(opt_loglevel_list); 57 58 /* Stream to use for logging if rte_logs.file is NULL */ 59 static FILE *default_log_stream; 60 61 /** 62 * This global structure stores some information about the message 63 * that is currently being processed by one lcore 64 */ 65 struct log_cur_msg { 66 uint32_t loglevel; /**< log level - see rte_log.h */ 67 uint32_t logtype; /**< log type - see rte_log.h */ 68 }; 69 70 /* per core log */ 71 static RTE_DEFINE_PER_LCORE(struct log_cur_msg, log_cur_msg); 72 73 /* default logs */ 74 75 /* Change the stream that will be used by logging system */ 76 int 77 rte_openlog_stream(FILE *f) 78 { 79 rte_logs.file = f; 80 return 0; 81 } 82 83 FILE * 84 rte_log_get_stream(void) 85 { 86 FILE *f = rte_logs.file; 87 88 if (f == NULL) { 89 /* 90 * Grab the current value of stderr here, rather than 91 * just initializing default_log_stream to stderr. This 92 * ensures that we will always use the current value 93 * of stderr, even if the application closes and 94 * reopens it. 95 */ 96 return default_log_stream != NULL ? default_log_stream : stderr; 97 } 98 return f; 99 } 100 101 /* Set global log level */ 102 void 103 rte_log_set_global_level(uint32_t level) 104 { 105 rte_logs.level = (uint32_t)level; 106 } 107 108 /* Get global log level */ 109 uint32_t 110 rte_log_get_global_level(void) 111 { 112 return rte_logs.level; 113 } 114 115 int 116 rte_log_get_level(uint32_t type) 117 { 118 if (type >= rte_logs.dynamic_types_len) 119 return -1; 120 121 return rte_logs.dynamic_types[type].loglevel; 122 } 123 124 bool 125 rte_log_can_log(uint32_t logtype, uint32_t level) 126 { 127 int log_level; 128 129 if (level > rte_log_get_global_level()) 130 return false; 131 132 log_level = rte_log_get_level(logtype); 133 if (log_level < 0) 134 return false; 135 136 if (level > (uint32_t)log_level) 137 return false; 138 139 return true; 140 } 141 142 static void 143 logtype_set_level(uint32_t type, uint32_t level) 144 { 145 uint32_t current = rte_logs.dynamic_types[type].loglevel; 146 147 if (current != level) { 148 rte_logs.dynamic_types[type].loglevel = level; 149 RTE_LOG(DEBUG, EAL, "%s log level changed from %s to %s\n", 150 rte_logs.dynamic_types[type].name == NULL ? 151 "" : rte_logs.dynamic_types[type].name, 152 eal_log_level2str(current), 153 eal_log_level2str(level)); 154 } 155 } 156 157 int 158 rte_log_set_level(uint32_t type, uint32_t level) 159 { 160 if (type >= rte_logs.dynamic_types_len) 161 return -1; 162 if (level > RTE_LOG_MAX) 163 return -1; 164 165 logtype_set_level(type, level); 166 167 return 0; 168 } 169 170 /* set log level by regular expression */ 171 int 172 rte_log_set_level_regexp(const char *regex, uint32_t level) 173 { 174 regex_t r; 175 size_t i; 176 177 if (level > RTE_LOG_MAX) 178 return -1; 179 180 if (regcomp(&r, regex, 0) != 0) 181 return -1; 182 183 for (i = 0; i < rte_logs.dynamic_types_len; i++) { 184 if (rte_logs.dynamic_types[i].name == NULL) 185 continue; 186 if (regexec(&r, rte_logs.dynamic_types[i].name, 0, 187 NULL, 0) == 0) 188 logtype_set_level(i, level); 189 } 190 191 regfree(&r); 192 193 return 0; 194 } 195 196 /* 197 * Save the type string and the loglevel for later dynamic 198 * logtypes which may register later. 199 */ 200 static int 201 log_save_level(uint32_t priority, const char *regex, const char *pattern) 202 { 203 struct rte_eal_opt_loglevel *opt_ll = NULL; 204 205 opt_ll = malloc(sizeof(*opt_ll)); 206 if (opt_ll == NULL) 207 goto fail; 208 209 opt_ll->level = priority; 210 211 if (regex) { 212 opt_ll->pattern = NULL; 213 if (regcomp(&opt_ll->re_match, regex, 0) != 0) 214 goto fail; 215 } else if (pattern) { 216 opt_ll->pattern = strdup(pattern); 217 if (opt_ll->pattern == NULL) 218 goto fail; 219 } else 220 goto fail; 221 222 TAILQ_INSERT_HEAD(&opt_loglevel_list, opt_ll, next); 223 return 0; 224 fail: 225 free(opt_ll); 226 return -1; 227 } 228 229 int 230 eal_log_save_regexp(const char *regex, uint32_t level) 231 { 232 return log_save_level(level, regex, NULL); 233 } 234 235 /* set log level based on globbing pattern */ 236 int 237 rte_log_set_level_pattern(const char *pattern, uint32_t level) 238 { 239 size_t i; 240 241 if (level > RTE_LOG_MAX) 242 return -1; 243 244 for (i = 0; i < rte_logs.dynamic_types_len; i++) { 245 if (rte_logs.dynamic_types[i].name == NULL) 246 continue; 247 248 if (fnmatch(pattern, rte_logs.dynamic_types[i].name, 0) == 0) 249 logtype_set_level(i, level); 250 } 251 252 return 0; 253 } 254 255 int 256 eal_log_save_pattern(const char *pattern, uint32_t level) 257 { 258 return log_save_level(level, NULL, pattern); 259 } 260 261 /* get the current loglevel for the message being processed */ 262 int rte_log_cur_msg_loglevel(void) 263 { 264 return RTE_PER_LCORE(log_cur_msg).loglevel; 265 } 266 267 /* get the current logtype for the message being processed */ 268 int rte_log_cur_msg_logtype(void) 269 { 270 return RTE_PER_LCORE(log_cur_msg).logtype; 271 } 272 273 static int 274 log_lookup(const char *name) 275 { 276 size_t i; 277 278 for (i = 0; i < rte_logs.dynamic_types_len; i++) { 279 if (rte_logs.dynamic_types[i].name == NULL) 280 continue; 281 if (strcmp(name, rte_logs.dynamic_types[i].name) == 0) 282 return i; 283 } 284 285 return -1; 286 } 287 288 static int 289 log_register(const char *name, uint32_t level) 290 { 291 struct rte_log_dynamic_type *new_dynamic_types; 292 int id; 293 294 id = log_lookup(name); 295 if (id >= 0) 296 return id; 297 298 new_dynamic_types = realloc(rte_logs.dynamic_types, 299 sizeof(struct rte_log_dynamic_type) * 300 (rte_logs.dynamic_types_len + 1)); 301 if (new_dynamic_types == NULL) 302 return -ENOMEM; 303 rte_logs.dynamic_types = new_dynamic_types; 304 305 id = rte_logs.dynamic_types_len; 306 memset(&rte_logs.dynamic_types[id], 0, 307 sizeof(rte_logs.dynamic_types[id])); 308 rte_logs.dynamic_types[id].name = strdup(name); 309 if (rte_logs.dynamic_types[id].name == NULL) 310 return -ENOMEM; 311 logtype_set_level(id, level); 312 313 rte_logs.dynamic_types_len++; 314 315 return id; 316 } 317 318 /* register an extended log type */ 319 int 320 rte_log_register(const char *name) 321 { 322 return log_register(name, RTE_LOG_INFO); 323 } 324 325 /* Register an extended log type and try to pick its level from EAL options */ 326 int 327 rte_log_register_type_and_pick_level(const char *name, uint32_t level_def) 328 { 329 struct rte_eal_opt_loglevel *opt_ll; 330 uint32_t level = level_def; 331 332 TAILQ_FOREACH(opt_ll, &opt_loglevel_list, next) { 333 if (opt_ll->level > RTE_LOG_MAX) 334 continue; 335 336 if (opt_ll->pattern) { 337 if (fnmatch(opt_ll->pattern, name, 0) == 0) 338 level = opt_ll->level; 339 } else { 340 if (regexec(&opt_ll->re_match, name, 0, NULL, 0) == 0) 341 level = opt_ll->level; 342 } 343 } 344 345 return log_register(name, level); 346 } 347 348 struct logtype { 349 uint32_t log_id; 350 const char *logtype; 351 }; 352 353 static const struct logtype logtype_strings[] = { 354 {RTE_LOGTYPE_EAL, "lib.eal"}, 355 356 {RTE_LOGTYPE_USER1, "user1"}, 357 {RTE_LOGTYPE_USER2, "user2"}, 358 {RTE_LOGTYPE_USER3, "user3"}, 359 {RTE_LOGTYPE_USER4, "user4"}, 360 {RTE_LOGTYPE_USER5, "user5"}, 361 {RTE_LOGTYPE_USER6, "user6"}, 362 {RTE_LOGTYPE_USER7, "user7"}, 363 {RTE_LOGTYPE_USER8, "user8"} 364 }; 365 366 /* Logging should be first initializer (before drivers and bus) */ 367 RTE_INIT_PRIO(log_init, LOG) 368 { 369 uint32_t i; 370 371 rte_log_set_global_level(RTE_LOG_DEBUG); 372 373 rte_logs.dynamic_types = calloc(RTE_LOGTYPE_FIRST_EXT_ID, 374 sizeof(struct rte_log_dynamic_type)); 375 if (rte_logs.dynamic_types == NULL) 376 return; 377 378 /* register legacy log types */ 379 for (i = 0; i < RTE_DIM(logtype_strings); i++) { 380 rte_logs.dynamic_types[logtype_strings[i].log_id].name = 381 strdup(logtype_strings[i].logtype); 382 logtype_set_level(logtype_strings[i].log_id, RTE_LOG_INFO); 383 } 384 385 rte_logs.dynamic_types_len = RTE_LOGTYPE_FIRST_EXT_ID; 386 } 387 388 const char * 389 eal_log_level2str(uint32_t level) 390 { 391 switch (level) { 392 case 0: return "disabled"; 393 case RTE_LOG_EMERG: return "emergency"; 394 case RTE_LOG_ALERT: return "alert"; 395 case RTE_LOG_CRIT: return "critical"; 396 case RTE_LOG_ERR: return "error"; 397 case RTE_LOG_WARNING: return "warning"; 398 case RTE_LOG_NOTICE: return "notice"; 399 case RTE_LOG_INFO: return "info"; 400 case RTE_LOG_DEBUG: return "debug"; 401 default: return "unknown"; 402 } 403 } 404 405 static int 406 log_type_compare(const void *a, const void *b) 407 { 408 const struct rte_log_dynamic_type *type_a = a; 409 const struct rte_log_dynamic_type *type_b = b; 410 411 if (type_a->name == NULL && type_b->name == NULL) 412 return 0; 413 if (type_a->name == NULL) 414 return -1; 415 if (type_b->name == NULL) 416 return 1; 417 return strcmp(type_a->name, type_b->name); 418 } 419 420 /* Dump name of each logtype, one per line. */ 421 void 422 rte_log_list_types(FILE *out, const char *prefix) 423 { 424 struct rte_log_dynamic_type *sorted_types; 425 const size_t type_size = sizeof(rte_logs.dynamic_types[0]); 426 const size_t type_count = rte_logs.dynamic_types_len; 427 const size_t total_size = type_size * type_count; 428 size_t type; 429 430 sorted_types = malloc(total_size); 431 if (sorted_types == NULL) { 432 /* no sorting - unlikely */ 433 sorted_types = rte_logs.dynamic_types; 434 } else { 435 memcpy(sorted_types, rte_logs.dynamic_types, total_size); 436 qsort(sorted_types, type_count, type_size, log_type_compare); 437 } 438 439 for (type = 0; type < type_count; ++type) { 440 if (sorted_types[type].name == NULL) 441 continue; 442 fprintf(out, "%s%s\n", prefix, sorted_types[type].name); 443 } 444 445 if (sorted_types != rte_logs.dynamic_types) 446 free(sorted_types); 447 } 448 449 /* dump global level and registered log types */ 450 void 451 rte_log_dump(FILE *f) 452 { 453 size_t i; 454 455 fprintf(f, "global log level is %s\n", 456 eal_log_level2str(rte_log_get_global_level())); 457 458 for (i = 0; i < rte_logs.dynamic_types_len; i++) { 459 if (rte_logs.dynamic_types[i].name == NULL) 460 continue; 461 fprintf(f, "id %zu: %s, level is %s\n", 462 i, rte_logs.dynamic_types[i].name, 463 eal_log_level2str(rte_logs.dynamic_types[i].loglevel)); 464 } 465 } 466 467 /* 468 * Generates a log message The message will be sent in the stream 469 * defined by the previous call to rte_openlog_stream(). 470 */ 471 int 472 rte_vlog(uint32_t level, uint32_t logtype, const char *format, va_list ap) 473 { 474 FILE *f = rte_log_get_stream(); 475 int ret; 476 477 if (logtype >= rte_logs.dynamic_types_len) 478 return -1; 479 if (!rte_log_can_log(logtype, level)) 480 return 0; 481 482 /* save loglevel and logtype in a global per-lcore variable */ 483 RTE_PER_LCORE(log_cur_msg).loglevel = level; 484 RTE_PER_LCORE(log_cur_msg).logtype = logtype; 485 486 ret = vfprintf(f, format, ap); 487 fflush(f); 488 return ret; 489 } 490 491 /* 492 * Generates a log message The message will be sent in the stream 493 * defined by the previous call to rte_openlog_stream(). 494 * No need to check level here, done by rte_vlog(). 495 */ 496 int 497 rte_log(uint32_t level, uint32_t logtype, const char *format, ...) 498 { 499 va_list ap; 500 int ret; 501 502 va_start(ap, format); 503 ret = rte_vlog(level, logtype, format, ap); 504 va_end(ap); 505 return ret; 506 } 507 508 /* 509 * Called by environment-specific initialization functions. 510 */ 511 void 512 eal_log_set_default(FILE *default_log) 513 { 514 default_log_stream = default_log; 515 516 #if RTE_LOG_DP_LEVEL >= RTE_LOG_DEBUG 517 RTE_LOG(NOTICE, EAL, 518 "Debug dataplane logs available - lower performance\n"); 519 #endif 520 } 521 522 /* 523 * Called by eal_cleanup 524 */ 525 void 526 rte_eal_log_cleanup(void) 527 { 528 if (default_log_stream) { 529 fclose(default_log_stream); 530 default_log_stream = NULL; 531 } 532 } 533