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