Branch data Line data Source code
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 : 0 : rte_openlog_stream(FILE *f)
78 : : {
79 : 0 : rte_logs.file = f;
80 : 0 : return 0;
81 : : }
82 : :
83 : : FILE *
84 : 589579 : rte_log_get_stream(void)
85 : : {
86 : 589579 : FILE *f = rte_logs.file;
87 : :
88 [ + # ]: 589579 : 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 [ + + ]: 589580 : return default_log_stream != NULL ? default_log_stream : stderr;
97 : : }
98 : : return f;
99 : : }
100 : :
101 : : /* Set global log level */
102 : : void
103 : 247 : rte_log_set_global_level(uint32_t level)
104 : : {
105 : 247 : rte_logs.level = (uint32_t)level;
106 : 247 : }
107 : :
108 : : /* Get global log level */
109 : : uint32_t
110 : 588437 : rte_log_get_global_level(void)
111 : : {
112 : 588437 : return rte_logs.level;
113 : : }
114 : :
115 : : int
116 : 587448 : rte_log_get_level(uint32_t type)
117 : : {
118 [ + - ]: 587448 : if (type >= rte_logs.dynamic_types_len)
119 : : return -1;
120 : :
121 : 587448 : return rte_logs.dynamic_types[type].loglevel;
122 : : }
123 : :
124 : : bool
125 : 587437 : rte_log_can_log(uint32_t logtype, uint32_t level)
126 : : {
127 : : int log_level;
128 : :
129 [ + + ]: 587437 : if (level > rte_log_get_global_level())
130 : : return false;
131 : :
132 : 587430 : log_level = rte_log_get_level(logtype);
133 [ + - ]: 587430 : if (log_level < 0)
134 : : return false;
135 : :
136 [ + + ]: 587430 : if (level > (uint32_t)log_level)
137 : 584219 : return false;
138 : :
139 : : return true;
140 : : }
141 : :
142 : : static void
143 : 52613 : logtype_set_level(uint32_t type, uint32_t level)
144 : : {
145 : 52613 : uint32_t current = rte_logs.dynamic_types[type].loglevel;
146 : :
147 [ + - ]: 52613 : if (current != level) {
148 : 52613 : rte_logs.dynamic_types[type].loglevel = level;
149 [ + - ]: 105226 : 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 : 52613 : }
156 : :
157 : : int
158 : 8 : rte_log_set_level(uint32_t type, uint32_t level)
159 : : {
160 [ + - ]: 8 : if (type >= rte_logs.dynamic_types_len)
161 : : return -1;
162 [ + - ]: 8 : if (level > RTE_LOG_MAX)
163 : : return -1;
164 : :
165 : 8 : logtype_set_level(type, level);
166 : :
167 : 8 : return 0;
168 : : }
169 : :
170 : : /* set log level by regular expression */
171 : : int
172 : 2 : rte_log_set_level_regexp(const char *regex, uint32_t level)
173 : : {
174 : : regex_t r;
175 : : size_t i;
176 : :
177 [ + - ]: 2 : if (level > RTE_LOG_MAX)
178 : : return -1;
179 : :
180 [ + - ]: 2 : if (regcomp(&r, regex, 0) != 0)
181 : : return -1;
182 : :
183 [ + + ]: 494 : for (i = 0; i < rte_logs.dynamic_types_len; i++) {
184 [ + + ]: 492 : if (rte_logs.dynamic_types[i].name == NULL)
185 : 46 : continue;
186 [ + + ]: 446 : if (regexec(&r, rte_logs.dynamic_types[i].name, 0,
187 : : NULL, 0) == 0)
188 : 2 : logtype_set_level(i, level);
189 : : }
190 : :
191 : 2 : regfree(&r);
192 : :
193 : 2 : 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 : 0 : log_save_level(uint32_t priority, const char *regex, const char *pattern)
202 : : {
203 : : struct rte_eal_opt_loglevel *opt_ll = NULL;
204 : :
205 : 0 : opt_ll = malloc(sizeof(*opt_ll));
206 [ # # ]: 0 : if (opt_ll == NULL)
207 : 0 : goto fail;
208 : :
209 : 0 : opt_ll->level = priority;
210 : :
211 [ # # ]: 0 : if (regex) {
212 : 0 : opt_ll->pattern = NULL;
213 [ # # ]: 0 : if (regcomp(&opt_ll->re_match, regex, 0) != 0)
214 : 0 : goto fail;
215 [ # # ]: 0 : } else if (pattern) {
216 : 0 : opt_ll->pattern = strdup(pattern);
217 [ # # ]: 0 : if (opt_ll->pattern == NULL)
218 : 0 : goto fail;
219 : : } else
220 : 0 : goto fail;
221 : :
222 [ # # ]: 0 : TAILQ_INSERT_HEAD(&opt_loglevel_list, opt_ll, next);
223 : 0 : return 0;
224 : 0 : fail:
225 : 0 : free(opt_ll);
226 : 0 : return -1;
227 : : }
228 : :
229 : : int
230 : 0 : eal_log_save_regexp(const char *regex, uint32_t level)
231 : : {
232 : 0 : return log_save_level(level, regex, NULL);
233 : : }
234 : :
235 : : /* set log level based on globbing pattern */
236 : : int
237 : 2 : rte_log_set_level_pattern(const char *pattern, uint32_t level)
238 : : {
239 : : size_t i;
240 : :
241 [ + - ]: 2 : if (level > RTE_LOG_MAX)
242 : : return -1;
243 : :
244 [ + + ]: 494 : for (i = 0; i < rte_logs.dynamic_types_len; i++) {
245 [ + + ]: 492 : if (rte_logs.dynamic_types[i].name == NULL)
246 : 46 : continue;
247 : :
248 [ + + ]: 446 : if (fnmatch(pattern, rte_logs.dynamic_types[i].name, 0) == 0)
249 : 3 : logtype_set_level(i, level);
250 : : }
251 : :
252 : : return 0;
253 : : }
254 : :
255 : : int
256 : 0 : eal_log_save_pattern(const char *pattern, uint32_t level)
257 : : {
258 : 0 : return log_save_level(level, NULL, pattern);
259 : : }
260 : :
261 : : /* get the current loglevel for the message being processed */
262 : 2058 : int rte_log_cur_msg_loglevel(void)
263 : : {
264 : 2058 : return RTE_PER_LCORE(log_cur_msg).loglevel;
265 : : }
266 : :
267 : : /* get the current logtype for the message being processed */
268 : 0 : int rte_log_cur_msg_logtype(void)
269 : : {
270 : 0 : return RTE_PER_LCORE(log_cur_msg).logtype;
271 : : }
272 : :
273 : : static int
274 : 53790 : log_lookup(const char *name)
275 : : {
276 : : size_t i;
277 : :
278 [ + + ]: 7322561 : for (i = 0; i < rte_logs.dynamic_types_len; i++) {
279 [ + + ]: 7272103 : if (rte_logs.dynamic_types[i].name == NULL)
280 : 1237170 : continue;
281 [ + + ]: 6034933 : if (strcmp(name, rte_logs.dynamic_types[i].name) == 0)
282 : 3332 : return i;
283 : : }
284 : :
285 : : return -1;
286 : : }
287 : :
288 : : static int
289 : 53790 : log_register(const char *name, uint32_t level)
290 : : {
291 : : struct rte_log_dynamic_type *new_dynamic_types;
292 : : int id;
293 : :
294 : 53790 : id = log_lookup(name);
295 [ + + ]: 53790 : if (id >= 0)
296 : : return id;
297 : :
298 : 50458 : new_dynamic_types = realloc(rte_logs.dynamic_types,
299 : : sizeof(struct rte_log_dynamic_type) *
300 : 50458 : (rte_logs.dynamic_types_len + 1));
301 [ + - ]: 50458 : if (new_dynamic_types == NULL)
302 : : return -ENOMEM;
303 : 50458 : rte_logs.dynamic_types = new_dynamic_types;
304 : :
305 : 50458 : id = rte_logs.dynamic_types_len;
306 : 50458 : memset(&rte_logs.dynamic_types[id], 0,
307 : : sizeof(rte_logs.dynamic_types[id]));
308 : 50458 : rte_logs.dynamic_types[id].name = strdup(name);
309 [ + - ]: 50458 : if (rte_logs.dynamic_types[id].name == NULL)
310 : : return -ENOMEM;
311 : 50458 : logtype_set_level(id, level);
312 : :
313 : 50458 : rte_logs.dynamic_types_len++;
314 : :
315 : 50458 : return id;
316 : : }
317 : :
318 : : /* register an extended log type */
319 : : int
320 : 2 : rte_log_register(const char *name)
321 : : {
322 : 2 : 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 : 53788 : 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 [ - + ]: 53788 : TAILQ_FOREACH(opt_ll, &opt_loglevel_list, next) {
333 [ # # ]: 0 : if (opt_ll->level > RTE_LOG_MAX)
334 : 0 : continue;
335 : :
336 [ # # ]: 0 : if (opt_ll->pattern) {
337 [ # # ]: 0 : if (fnmatch(opt_ll->pattern, name, 0) == 0)
338 : 0 : level = opt_ll->level;
339 : : } else {
340 [ # # ]: 0 : if (regexec(&opt_ll->re_match, name, 0, NULL, 0) == 0)
341 : 0 : level = opt_ll->level;
342 : : }
343 : : }
344 : :
345 : 53788 : 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 : 238 : RTE_INIT_PRIO(log_init, LOG)
368 : : {
369 : : uint32_t i;
370 : :
371 : 238 : rte_log_set_global_level(RTE_LOG_DEBUG);
372 : :
373 : 238 : rte_logs.dynamic_types = calloc(RTE_LOGTYPE_FIRST_EXT_ID,
374 : : sizeof(struct rte_log_dynamic_type));
375 [ + - ]: 238 : if (rte_logs.dynamic_types == NULL)
376 : : return;
377 : :
378 : : /* register legacy log types */
379 [ + + ]: 2380 : for (i = 0; i < RTE_DIM(logtype_strings); i++) {
380 : 4284 : rte_logs.dynamic_types[logtype_strings[i].log_id].name =
381 : 2142 : strdup(logtype_strings[i].logtype);
382 : 2142 : logtype_set_level(logtype_strings[i].log_id, RTE_LOG_INFO);
383 : : }
384 : :
385 : 238 : rte_logs.dynamic_types_len = RTE_LOGTYPE_FIRST_EXT_ID;
386 : : }
387 : :
388 : : const char *
389 : 105226 : eal_log_level2str(uint32_t level)
390 : : {
391 [ + - - + : 105226 : switch (level) {
+ + + + -
+ ]
392 : : case 0: return "disabled";
393 : 6 : case RTE_LOG_EMERG: return "emergency";
394 : 0 : case RTE_LOG_ALERT: return "alert";
395 : 0 : case RTE_LOG_CRIT: return "critical";
396 : 955 : case RTE_LOG_ERR: return "error";
397 : 952 : case RTE_LOG_WARNING: return "warning";
398 : 32844 : case RTE_LOG_NOTICE: return "notice";
399 : 17621 : case RTE_LOG_INFO: return "info";
400 : 248 : case RTE_LOG_DEBUG: return "debug";
401 : 0 : default: return "unknown";
402 : : }
403 : : }
404 : :
405 : : static int
406 : 0 : 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 [ # # # # ]: 0 : if (type_a->name == NULL && type_b->name == NULL)
412 : : return 0;
413 [ # # ]: 0 : if (type_a->name == NULL)
414 : : return -1;
415 [ # # ]: 0 : if (type_b->name == NULL)
416 : : return 1;
417 : 0 : return strcmp(type_a->name, type_b->name);
418 : : }
419 : :
420 : : /* Dump name of each logtype, one per line. */
421 : : void
422 : 0 : 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 : 0 : const size_t type_count = rte_logs.dynamic_types_len;
427 : 0 : const size_t total_size = type_size * type_count;
428 : : size_t type;
429 : :
430 : 0 : sorted_types = malloc(total_size);
431 [ # # ]: 0 : if (sorted_types == NULL) {
432 : : /* no sorting - unlikely */
433 : 0 : sorted_types = rte_logs.dynamic_types;
434 : : } else {
435 : 0 : memcpy(sorted_types, rte_logs.dynamic_types, total_size);
436 : 0 : qsort(sorted_types, type_count, type_size, log_type_compare);
437 : : }
438 : :
439 [ # # ]: 0 : for (type = 0; type < type_count; ++type) {
440 [ # # ]: 0 : if (sorted_types[type].name == NULL)
441 : 0 : continue;
442 : : fprintf(out, "%s%s\n", prefix, sorted_types[type].name);
443 : : }
444 : :
445 [ # # ]: 0 : if (sorted_types != rte_logs.dynamic_types)
446 : 0 : free(sorted_types);
447 : 0 : }
448 : :
449 : : /* dump global level and registered log types */
450 : : void
451 : 0 : rte_log_dump(FILE *f)
452 : : {
453 : : size_t i;
454 : :
455 : 0 : fprintf(f, "global log level is %s\n",
456 : : eal_log_level2str(rte_log_get_global_level()));
457 : :
458 [ # # ]: 0 : for (i = 0; i < rte_logs.dynamic_types_len; i++) {
459 [ # # ]: 0 : if (rte_logs.dynamic_types[i].name == NULL)
460 : 0 : continue;
461 : 0 : fprintf(f, "id %zu: %s, level is %s\n",
462 : 0 : i, rte_logs.dynamic_types[i].name,
463 : : eal_log_level2str(rte_logs.dynamic_types[i].loglevel));
464 : : }
465 : 0 : }
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 : 589579 : rte_vlog(uint32_t level, uint32_t logtype, const char *format, va_list ap)
473 : : {
474 : 589579 : FILE *f = rte_log_get_stream();
475 : : int ret;
476 : :
477 [ + + ]: 589580 : if (logtype >= rte_logs.dynamic_types_len)
478 : : return -1;
479 [ + + ]: 587438 : if (!rte_log_can_log(logtype, level))
480 : : return 0;
481 : :
482 : : /* save loglevel and logtype in a global per-lcore variable */
483 : 3211 : RTE_PER_LCORE(log_cur_msg).loglevel = level;
484 : 3211 : RTE_PER_LCORE(log_cur_msg).logtype = logtype;
485 : :
486 : : ret = vfprintf(f, format, ap);
487 : 3213 : fflush(f);
488 : 3213 : 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 : 589574 : rte_log(uint32_t level, uint32_t logtype, const char *format, ...)
498 : : {
499 : : va_list ap;
500 : : int ret;
501 : :
502 : 589574 : va_start(ap, format);
503 : 589574 : ret = rte_vlog(level, logtype, format, ap);
504 : 589575 : va_end(ap);
505 : 589575 : return ret;
506 : : }
507 : :
508 : : /*
509 : : * Called by environment-specific initialization functions.
510 : : */
511 : : void
512 : 170 : eal_log_set_default(FILE *default_log)
513 : : {
514 : 170 : 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 : 170 : }
521 : :
522 : : /*
523 : : * Called by eal_cleanup
524 : : */
525 : : void
526 : 238 : rte_eal_log_cleanup(void)
527 : : {
528 [ + + ]: 238 : if (default_log_stream) {
529 : 170 : fclose(default_log_stream);
530 : 170 : default_log_stream = NULL;
531 : : }
532 : 238 : }
|