xref: /spdk/lib/log/log.c (revision 45f7571a08ed25a4d3f9453f4a4ee245835feeb8)
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright (c) Intel Corporation.
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 "spdk/stdinc.h"
35 
36 #include "spdk_internal/log.h"
37 
38 static TAILQ_HEAD(, spdk_trace_flag) g_trace_flags = TAILQ_HEAD_INITIALIZER(g_trace_flags);
39 
40 int spdk_g_log_facility = LOG_DAEMON;
41 static enum spdk_log_level g_spdk_log_level = SPDK_LOG_NOTICE;
42 static enum spdk_log_level g_spdk_log_print_level = SPDK_LOG_NOTICE;
43 
44 SPDK_LOG_REGISTER_TRACE_FLAG("debug", SPDK_TRACE_DEBUG)
45 
46 #define MAX_TMPBUF 1024
47 
48 struct syslog_code {
49 	const char *c_name;
50 	int c_val;
51 };
52 
53 static const struct syslog_code facilitynames[] = {
54 	{ "auth",	LOG_AUTH,	},
55 	{ "authpriv",	LOG_AUTHPRIV,	},
56 	{ "cron",	LOG_CRON,	},
57 	{ "daemon",	LOG_DAEMON,	},
58 	{ "ftp",	LOG_FTP,	},
59 	{ "kern",	LOG_KERN,	},
60 	{ "lpr",	LOG_LPR,	},
61 	{ "mail",	LOG_MAIL,	},
62 	{ "news",	LOG_NEWS,	},
63 	{ "syslog",	LOG_SYSLOG,	},
64 	{ "user",	LOG_USER,	},
65 	{ "uucp",	LOG_UUCP,	},
66 	{ "local0",	LOG_LOCAL0,	},
67 	{ "local1",	LOG_LOCAL1,	},
68 	{ "local2",	LOG_LOCAL2,	},
69 	{ "local3",	LOG_LOCAL3,	},
70 	{ "local4",	LOG_LOCAL4,	},
71 	{ "local5",	LOG_LOCAL5,	},
72 	{ "local6",	LOG_LOCAL6,	},
73 	{ "local7",	LOG_LOCAL7,	},
74 #ifdef __FreeBSD__
75 	{ "console",	LOG_CONSOLE,	},
76 	{ "ntp",	LOG_NTP,	},
77 	{ "security",	LOG_SECURITY,	},
78 #endif
79 	{ NULL,		-1,		}
80 };
81 
82 static const char *const spdk_level_names[] = {
83 	[SPDK_LOG_ERROR]	= "ERROR",
84 	[SPDK_LOG_WARN]		= "WARNING",
85 	[SPDK_LOG_NOTICE]	= "NOTICE",
86 	[SPDK_LOG_INFO]		= "INFO",
87 	[SPDK_LOG_DEBUG]	= "DEBUG",
88 };
89 
90 void
91 spdk_log_open(void)
92 {
93 	if (spdk_g_log_facility != 0) {
94 		openlog("spdk", LOG_PID, spdk_g_log_facility);
95 	} else {
96 		openlog("spdk", LOG_PID, LOG_DAEMON);
97 	}
98 }
99 
100 void
101 spdk_log_close(void)
102 {
103 	closelog();
104 }
105 
106 void
107 spdk_log_set_level(enum spdk_log_level level)
108 {
109 	g_spdk_log_level = level;
110 }
111 
112 enum spdk_log_level
113 spdk_log_get_level(void) {
114 	return g_spdk_log_level;
115 }
116 
117 void
118 spdk_log_set_print_level(enum spdk_log_level level)
119 {
120 	g_spdk_log_print_level = level;
121 }
122 
123 enum spdk_log_level
124 spdk_log_get_print_level(void) {
125 	return g_spdk_log_print_level;
126 }
127 
128 int
129 spdk_set_log_facility(const char *facility)
130 {
131 	int i;
132 
133 	for (i = 0; facilitynames[i].c_name != NULL; i++) {
134 		if (strcasecmp(facilitynames[i].c_name, facility) == 0) {
135 			spdk_g_log_facility = facilitynames[i].c_val;
136 			return 0;
137 		}
138 	}
139 
140 	spdk_g_log_facility = LOG_DAEMON;
141 	return -1;
142 }
143 
144 const char *
145 spdk_get_log_facility(void)
146 {
147 	const char *def_name = NULL;
148 	int i;
149 
150 	for (i = 0; facilitynames[i].c_name != NULL; i++) {
151 		if (facilitynames[i].c_val == spdk_g_log_facility) {
152 			return facilitynames[i].c_name;
153 		} else if (facilitynames[i].c_val == LOG_DAEMON) {
154 			def_name = facilitynames[i].c_name;
155 		}
156 	}
157 
158 	return def_name;
159 }
160 
161 void
162 spdk_log(enum spdk_log_level level, const char *file, const int line, const char *func,
163 	 const char *format, ...)
164 {
165 	int severity = LOG_INFO;
166 	char buf[MAX_TMPBUF];
167 	va_list ap;
168 
169 	switch (level) {
170 	case SPDK_LOG_ERROR:
171 		severity = LOG_ERR;
172 		break;
173 	case SPDK_LOG_WARN:
174 		severity = LOG_WARNING;
175 		break;
176 	case SPDK_LOG_NOTICE:
177 		severity = LOG_NOTICE;
178 		break;
179 	case SPDK_LOG_INFO:
180 	case SPDK_LOG_DEBUG:
181 		severity = LOG_INFO;
182 		break;
183 	}
184 
185 	va_start(ap, format);
186 
187 	vsnprintf(buf, sizeof(buf), format, ap);
188 
189 	if (level <= g_spdk_log_print_level) {
190 		fprintf(stderr, "%s:%4d:%s: *%s*: %s", file, line, func, spdk_level_names[level], buf);
191 	}
192 
193 	if (level <= g_spdk_log_level) {
194 		syslog(severity, "%s:%4d:%s: *%s*: %s", file, line, func, spdk_level_names[level], buf);
195 	}
196 
197 	va_end(ap);
198 }
199 
200 static void
201 fdump(FILE *fp, const char *label, const uint8_t *buf, size_t len)
202 {
203 	char tmpbuf[MAX_TMPBUF];
204 	char buf16[16 + 1];
205 	size_t total;
206 	unsigned int idx;
207 
208 	fprintf(fp, "%s\n", label);
209 
210 	memset(buf16, 0, sizeof buf16);
211 	total = 0;
212 	for (idx = 0; idx < len; idx++) {
213 		if (idx != 0 && idx % 16 == 0) {
214 			snprintf(tmpbuf + total, sizeof tmpbuf - total,
215 				 " %s", buf16);
216 			fprintf(fp, "%s\n", tmpbuf);
217 			total = 0;
218 		}
219 		if (idx % 16 == 0) {
220 			total += snprintf(tmpbuf + total, sizeof tmpbuf - total,
221 					  "%08x ", idx);
222 		}
223 		if (idx % 8 == 0) {
224 			total += snprintf(tmpbuf + total, sizeof tmpbuf - total,
225 					  "%s", " ");
226 		}
227 		total += snprintf(tmpbuf + total, sizeof tmpbuf - total,
228 				  "%2.2x ", buf[idx] & 0xff);
229 		buf16[idx % 16] = isprint(buf[idx]) ? buf[idx] : '.';
230 	}
231 	for (; idx % 16 != 0; idx++) {
232 		total += snprintf(tmpbuf + total, sizeof tmpbuf - total, "   ");
233 		buf16[idx % 16] = ' ';
234 	}
235 	snprintf(tmpbuf + total, sizeof tmpbuf - total, "  %s", buf16);
236 	fprintf(fp, "%s\n", tmpbuf);
237 	fflush(fp);
238 }
239 
240 void
241 spdk_trace_dump(const char *label, const uint8_t *buf, size_t len)
242 {
243 	fdump(stderr, label, buf, len);
244 }
245 
246 static struct spdk_trace_flag *
247 get_trace_flag(const char *name)
248 {
249 	struct spdk_trace_flag *flag;
250 
251 	TAILQ_FOREACH(flag, &g_trace_flags, tailq) {
252 		if (strcasecmp(name, flag->name) == 0) {
253 			return flag;
254 		}
255 	}
256 
257 	return NULL;
258 }
259 
260 void
261 spdk_log_register_trace_flag(const char *name, struct spdk_trace_flag *flag)
262 {
263 	struct spdk_trace_flag *iter;
264 
265 	if (name == NULL || flag == NULL) {
266 		SPDK_ERRLOG("missing spdk_trace_flag parameters\n");
267 		abort();
268 	}
269 
270 	if (get_trace_flag(name)) {
271 		SPDK_ERRLOG("duplicate spdk_trace_flag '%s'\n", name);
272 		abort();
273 	}
274 
275 	TAILQ_FOREACH(iter, &g_trace_flags, tailq) {
276 		if (strcasecmp(iter->name, flag->name) > 0) {
277 			TAILQ_INSERT_BEFORE(iter, flag, tailq);
278 			return;
279 		}
280 	}
281 
282 	TAILQ_INSERT_TAIL(&g_trace_flags, flag, tailq);
283 }
284 
285 bool
286 spdk_log_get_trace_flag(const char *name)
287 {
288 	struct spdk_trace_flag *flag = get_trace_flag(name);
289 
290 	if (flag && flag->enabled) {
291 		return true;
292 	}
293 
294 	return false;
295 }
296 
297 static int
298 set_trace_flag(const char *name, bool value)
299 {
300 	struct spdk_trace_flag *flag;
301 
302 	if (strcasecmp(name, "all") == 0) {
303 		TAILQ_FOREACH(flag, &g_trace_flags, tailq) {
304 			flag->enabled = value;
305 		}
306 		return 0;
307 	}
308 
309 	flag = get_trace_flag(name);
310 	if (flag == NULL) {
311 		return -1;
312 	}
313 
314 	flag->enabled = value;
315 
316 	return 0;
317 }
318 
319 int
320 spdk_log_set_trace_flag(const char *name)
321 {
322 	return set_trace_flag(name, true);
323 }
324 
325 int
326 spdk_log_clear_trace_flag(const char *name)
327 {
328 	return set_trace_flag(name, false);
329 }
330 
331 struct spdk_trace_flag *
332 spdk_log_get_first_trace_flag(void)
333 {
334 	return TAILQ_FIRST(&g_trace_flags);
335 }
336 
337 struct spdk_trace_flag *
338 spdk_log_get_next_trace_flag(struct spdk_trace_flag *flag)
339 {
340 	return TAILQ_NEXT(flag, tailq);
341 }
342 
343 void
344 spdk_tracelog_usage(FILE *f, const char *trace_arg)
345 {
346 #ifdef DEBUG
347 	struct spdk_trace_flag *flag;
348 
349 	fprintf(f, " %s flag    enable trace flag (all", trace_arg);
350 
351 	TAILQ_FOREACH(flag, &g_trace_flags, tailq) {
352 		fprintf(f, ", %s", flag->name);
353 	}
354 
355 	fprintf(f, ")\n");
356 #else
357 	fprintf(f, " %s flag    enable trace flag (not supported - must rebuild with CONFIG_DEBUG=y)\n",
358 		trace_arg);
359 #endif
360 }
361