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