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