xref: /dpdk/lib/log/log.c (revision 62ae1149f2bdaed3482abb08f2e255f1ac4746e7)
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