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