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