eal: support dynamic log types
[dpdk.git] / lib / librte_eal / common / eal_common_log.c
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
5  *   All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33
34 #include <stdio.h>
35 #include <stdint.h>
36 #include <stdarg.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <errno.h>
40
41 #include <rte_eal.h>
42 #include <rte_log.h>
43 #include <rte_per_lcore.h>
44
45 #include "eal_private.h"
46
47 /* global log structure */
48 struct rte_logs rte_logs = {
49         .type = ~0,
50         .level = RTE_LOG_DEBUG,
51         .file = NULL,
52 };
53
54 /* Stream to use for logging if rte_logs.file is NULL */
55 static FILE *default_log_stream;
56
57 /**
58  * This global structure stores some informations about the message
59  * that is currently being processed by one lcore
60  */
61 struct log_cur_msg {
62         uint32_t loglevel; /**< log level - see rte_log.h */
63         uint32_t logtype;  /**< log type  - see rte_log.h */
64 };
65
66 struct rte_log_dynamic_type {
67         const char *name;
68         uint32_t loglevel;
69 };
70
71  /* per core log */
72 static RTE_DEFINE_PER_LCORE(struct log_cur_msg, log_cur_msg);
73
74 /* default logs */
75
76 /* Change the stream that will be used by logging system */
77 int
78 rte_openlog_stream(FILE *f)
79 {
80         rte_logs.file = f;
81         return 0;
82 }
83
84 /* Set global log level */
85 void
86 rte_set_log_level(uint32_t level)
87 {
88         rte_logs.level = (uint32_t)level;
89 }
90
91 /* Get global log level */
92 uint32_t
93 rte_get_log_level(void)
94 {
95         return rte_logs.level;
96 }
97
98 /* Set global log type */
99 void
100 rte_set_log_type(uint32_t type, int enable)
101 {
102         if (type < RTE_LOGTYPE_FIRST_EXT_ID) {
103                 if (enable)
104                         rte_logs.type |= type;
105                 else
106                         rte_logs.type &= ~type;
107         }
108
109         if (enable)
110                 rte_log_set_level(type, 0);
111         else
112                 rte_log_set_level(type, RTE_LOG_DEBUG);
113 }
114
115 /* Get global log type */
116 uint32_t
117 rte_get_log_type(void)
118 {
119         return rte_logs.type;
120 }
121
122 int
123 rte_log_set_level(uint32_t type, uint32_t level)
124 {
125         if (type >= rte_logs.dynamic_types_len)
126                 return -1;
127         if (level > RTE_LOG_DEBUG)
128                 return -1;
129
130         rte_logs.dynamic_types[type].loglevel = level;
131
132         return 0;
133 }
134
135 /* get the current loglevel for the message beeing processed */
136 int rte_log_cur_msg_loglevel(void)
137 {
138         return RTE_PER_LCORE(log_cur_msg).loglevel;
139 }
140
141 /* get the current logtype for the message beeing processed */
142 int rte_log_cur_msg_logtype(void)
143 {
144         return RTE_PER_LCORE(log_cur_msg).logtype;
145 }
146
147 static int
148 rte_log_lookup(const char *name)
149 {
150         size_t i;
151
152         for (i = 0; i < rte_logs.dynamic_types_len; i++) {
153                 if (rte_logs.dynamic_types[i].name == NULL)
154                         continue;
155                 if (strcmp(name, rte_logs.dynamic_types[i].name) == 0)
156                         return i;
157         }
158
159         return -1;
160 }
161
162 /* register an extended log type, assuming table is large enough, and id
163  * is not yet registered.
164  */
165 static int
166 __rte_log_register(const char *name, int id)
167 {
168         char *dup_name = strdup(name);
169
170         if (dup_name == NULL)
171                 return -ENOMEM;
172
173         rte_logs.dynamic_types[id].name = dup_name;
174         rte_logs.dynamic_types[id].loglevel = RTE_LOG_DEBUG;
175
176         return id;
177 }
178
179 /* register an extended log type */
180 int
181 rte_log_register(const char *name)
182 {
183         struct rte_log_dynamic_type *new_dynamic_types;
184         int id, ret;
185
186         id = rte_log_lookup(name);
187         if (id >= 0)
188                 return id;
189
190         new_dynamic_types = realloc(rte_logs.dynamic_types,
191                 sizeof(struct rte_log_dynamic_type) *
192                 (rte_logs.dynamic_types_len + 1));
193         if (new_dynamic_types == NULL)
194                 return -ENOMEM;
195         rte_logs.dynamic_types = new_dynamic_types;
196
197         ret = __rte_log_register(name, rte_logs.dynamic_types_len);
198         if (ret < 0)
199                 return ret;
200
201         rte_logs.dynamic_types_len++;
202
203         return ret;
204 }
205
206 RTE_INIT(rte_log_init);
207 static void
208 rte_log_init(void)
209 {
210         rte_logs.dynamic_types = calloc(RTE_LOGTYPE_FIRST_EXT_ID,
211                 sizeof(struct rte_log_dynamic_type));
212         if (rte_logs.dynamic_types == NULL)
213                 return;
214
215         /* register legacy log types, keep sync'd with RTE_LOGTYPE_* */
216         __rte_log_register("eal", 0);
217         __rte_log_register("malloc", 1);
218         __rte_log_register("ring", 2);
219         __rte_log_register("mempool", 3);
220         __rte_log_register("timer", 4);
221         __rte_log_register("pmd", 5);
222         __rte_log_register("hash", 6);
223         __rte_log_register("lpm", 7);
224         __rte_log_register("kni", 8);
225         __rte_log_register("acl", 9);
226         __rte_log_register("power", 10);
227         __rte_log_register("meter", 11);
228         __rte_log_register("sched", 12);
229         __rte_log_register("port", 13);
230         __rte_log_register("table", 14);
231         __rte_log_register("pipeline", 15);
232         __rte_log_register("mbuf", 16);
233         __rte_log_register("cryptodev", 17);
234         __rte_log_register("user1", 24);
235         __rte_log_register("user2", 25);
236         __rte_log_register("user3", 26);
237         __rte_log_register("user4", 27);
238         __rte_log_register("user5", 28);
239         __rte_log_register("user6", 29);
240         __rte_log_register("user7", 30);
241         __rte_log_register("user8", 31);
242
243         rte_logs.dynamic_types_len = RTE_LOGTYPE_FIRST_EXT_ID;
244 }
245
246 /*
247  * Generates a log message The message will be sent in the stream
248  * defined by the previous call to rte_openlog_stream().
249  */
250 int
251 rte_vlog(uint32_t level, uint32_t logtype, const char *format, va_list ap)
252 {
253         int ret;
254         FILE *f = rte_logs.file;
255         if (f == NULL) {
256                 f = default_log_stream;
257                 if (f == NULL) {
258                         /*
259                          * Grab the current value of stderr here, rather than
260                          * just initializing default_log_stream to stderr. This
261                          * ensures that we will always use the current value
262                          * of stderr, even if the application closes and
263                          * reopens it.
264                          */
265                         f = stderr;
266                 }
267         }
268
269         if (level > rte_logs.level)
270                 return 0;
271         if (logtype >= rte_logs.dynamic_types_len)
272                 return -1;
273         if (level > rte_logs.dynamic_types[logtype].loglevel)
274                 return 0;
275
276         /* save loglevel and logtype in a global per-lcore variable */
277         RTE_PER_LCORE(log_cur_msg).loglevel = level;
278         RTE_PER_LCORE(log_cur_msg).logtype = logtype;
279
280         ret = vfprintf(f, format, ap);
281         fflush(f);
282         return ret;
283 }
284
285 /*
286  * Generates a log message The message will be sent in the stream
287  * defined by the previous call to rte_openlog_stream().
288  * No need to check level here, done by rte_vlog().
289  */
290 int
291 rte_log(uint32_t level, uint32_t logtype, const char *format, ...)
292 {
293         va_list ap;
294         int ret;
295
296         va_start(ap, format);
297         ret = rte_vlog(level, logtype, format, ap);
298         va_end(ap);
299         return ret;
300 }
301
302 /*
303  * Called by environment-specific initialization functions.
304  */
305 void
306 eal_log_set_default(FILE *default_log)
307 {
308         default_log_stream = default_log;
309
310 #if RTE_LOG_DP_LEVEL >= RTE_LOG_DEBUG
311         RTE_LOG(NOTICE, EAL,
312                 "Debug dataplane logs available - lower performance\n");
313 #endif
314 }