xref: /spdk/lib/log/log.c (revision 0ce363bebe8ca422f8a9e2bd103dc1eaee71fb2e)
1488570ebSJim Harris /*   SPDX-License-Identifier: BSD-3-Clause
2a6dbe372Spaul luse  *   Copyright (C) 2016 Intel Corporation.
3aaa533adSDaniel Verkamp  *   All rights reserved.
4aaa533adSDaniel Verkamp  */
5aaa533adSDaniel Verkamp 
6b961d9ccSBen Walker #include "spdk/stdinc.h"
7*0ce363beSVasilii Ivanov #include "spdk/util.h"
8aaa533adSDaniel Verkamp 
94e8e97c8STomasz Zawadzki #include "spdk/log.h"
10aaa533adSDaniel Verkamp 
11cca697b0SBen Walker static const char *const spdk_level_names[] = {
12cca697b0SBen Walker 	[SPDK_LOG_ERROR]	= "ERROR",
13cca697b0SBen Walker 	[SPDK_LOG_WARN]		= "WARNING",
14cca697b0SBen Walker 	[SPDK_LOG_NOTICE]	= "NOTICE",
15cca697b0SBen Walker 	[SPDK_LOG_INFO]		= "INFO",
16cca697b0SBen Walker 	[SPDK_LOG_DEBUG]	= "DEBUG",
17cca697b0SBen Walker };
18cca697b0SBen Walker 
1985c146efSEd Rodriguez #define MAX_TMPBUF 1024
2085c146efSEd Rodriguez 
21*0ce363beSVasilii Ivanov static struct spdk_log_opts g_log_opts = {
22*0ce363beSVasilii Ivanov 	.log = NULL,
23*0ce363beSVasilii Ivanov 	.open = NULL,
24*0ce363beSVasilii Ivanov 	.close = NULL,
25*0ce363beSVasilii Ivanov 	.user_ctx = NULL,
26*0ce363beSVasilii Ivanov };
27d267d0e8SVitaliy Mysak static bool g_log_timestamps = true;
2846523f33Spaul luse 
298e9bf181Swanghailiangx enum spdk_log_level g_spdk_log_level;
308e9bf181Swanghailiangx enum spdk_log_level g_spdk_log_print_level;
318e9bf181Swanghailiangx 
328e9bf181Swanghailiangx void
338e9bf181Swanghailiangx spdk_log_set_level(enum spdk_log_level level)
348e9bf181Swanghailiangx {
358e9bf181Swanghailiangx 	assert(level >= SPDK_LOG_DISABLED);
368e9bf181Swanghailiangx 	assert(level <= SPDK_LOG_DEBUG);
378e9bf181Swanghailiangx 	g_spdk_log_level = level;
388e9bf181Swanghailiangx }
398e9bf181Swanghailiangx 
408e9bf181Swanghailiangx enum spdk_log_level
418e9bf181Swanghailiangx spdk_log_get_level(void) {
428e9bf181Swanghailiangx 	return g_spdk_log_level;
438e9bf181Swanghailiangx }
448e9bf181Swanghailiangx 
458e9bf181Swanghailiangx void
468e9bf181Swanghailiangx spdk_log_set_print_level(enum spdk_log_level level)
478e9bf181Swanghailiangx {
488e9bf181Swanghailiangx 	assert(level >= SPDK_LOG_DISABLED);
498e9bf181Swanghailiangx 	assert(level <= SPDK_LOG_DEBUG);
508e9bf181Swanghailiangx 	g_spdk_log_print_level = level;
518e9bf181Swanghailiangx }
528e9bf181Swanghailiangx 
538e9bf181Swanghailiangx enum spdk_log_level
548e9bf181Swanghailiangx spdk_log_get_print_level(void) {
558e9bf181Swanghailiangx 	return g_spdk_log_print_level;
568e9bf181Swanghailiangx }
577b5d9b06STomasz Zawadzki 
58*0ce363beSVasilii Ivanov static void
59*0ce363beSVasilii Ivanov log_open(void *ctx)
60235a8e37SBen Walker {
61ad474e95SBen Walker 	openlog("spdk", LOG_PID, LOG_LOCAL7);
62235a8e37SBen Walker }
63*0ce363beSVasilii Ivanov 
64*0ce363beSVasilii Ivanov static void
65*0ce363beSVasilii Ivanov log_close(void *ctx)
66*0ce363beSVasilii Ivanov {
67*0ce363beSVasilii Ivanov 	closelog();
68*0ce363beSVasilii Ivanov }
69*0ce363beSVasilii Ivanov 
70*0ce363beSVasilii Ivanov void
71*0ce363beSVasilii Ivanov spdk_log_open(spdk_log_cb *log)
72*0ce363beSVasilii Ivanov {
73*0ce363beSVasilii Ivanov 	if (log) {
74*0ce363beSVasilii Ivanov 		struct spdk_log_opts opts = {.log = log};
75*0ce363beSVasilii Ivanov 		opts.size = SPDK_SIZEOF(&opts, log);
76*0ce363beSVasilii Ivanov 		spdk_log_open_ext(&opts);
77*0ce363beSVasilii Ivanov 	} else {
78*0ce363beSVasilii Ivanov 		spdk_log_open_ext(NULL);
79*0ce363beSVasilii Ivanov 	}
80*0ce363beSVasilii Ivanov }
81*0ce363beSVasilii Ivanov 
82*0ce363beSVasilii Ivanov void
83*0ce363beSVasilii Ivanov spdk_log_open_ext(struct spdk_log_opts *opts)
84*0ce363beSVasilii Ivanov {
85*0ce363beSVasilii Ivanov 	if (!opts) {
86*0ce363beSVasilii Ivanov 		g_log_opts.open = log_open;
87*0ce363beSVasilii Ivanov 		g_log_opts.close = log_close;
88*0ce363beSVasilii Ivanov 		goto out;
89*0ce363beSVasilii Ivanov 	}
90*0ce363beSVasilii Ivanov 
91*0ce363beSVasilii Ivanov 	g_log_opts.log = SPDK_GET_FIELD(opts, log, NULL);
92*0ce363beSVasilii Ivanov 	g_log_opts.open = SPDK_GET_FIELD(opts, open, NULL);
93*0ce363beSVasilii Ivanov 	g_log_opts.close = SPDK_GET_FIELD(opts, close, NULL);
94*0ce363beSVasilii Ivanov 	g_log_opts.user_ctx = SPDK_GET_FIELD(opts, user_ctx, NULL);
95*0ce363beSVasilii Ivanov 
96*0ce363beSVasilii Ivanov out:
97*0ce363beSVasilii Ivanov 	if (g_log_opts.open) {
98*0ce363beSVasilii Ivanov 		g_log_opts.open(g_log_opts.user_ctx);
99*0ce363beSVasilii Ivanov 	}
10046523f33Spaul luse }
101235a8e37SBen Walker 
102235a8e37SBen Walker void
103235a8e37SBen Walker spdk_log_close(void)
104235a8e37SBen Walker {
105*0ce363beSVasilii Ivanov 	if (g_log_opts.close) {
106*0ce363beSVasilii Ivanov 		g_log_opts.close(g_log_opts.user_ctx);
107235a8e37SBen Walker 	}
108*0ce363beSVasilii Ivanov 	memset(&g_log_opts, 0, sizeof(g_log_opts));
10946523f33Spaul luse }
110235a8e37SBen Walker 
111d267d0e8SVitaliy Mysak void
112d267d0e8SVitaliy Mysak spdk_log_enable_timestamps(bool value)
113d267d0e8SVitaliy Mysak {
114d267d0e8SVitaliy Mysak 	g_log_timestamps = value;
115d267d0e8SVitaliy Mysak }
116d267d0e8SVitaliy Mysak 
117419cd369SVitaliy Mysak static void
118419cd369SVitaliy Mysak get_timestamp_prefix(char *buf, int buf_size)
119419cd369SVitaliy Mysak {
120419cd369SVitaliy Mysak 	struct tm *info;
121419cd369SVitaliy Mysak 	char date[24];
122419cd369SVitaliy Mysak 	struct timespec ts;
123419cd369SVitaliy Mysak 	long usec;
124419cd369SVitaliy Mysak 
125d267d0e8SVitaliy Mysak 	if (!g_log_timestamps) {
126d267d0e8SVitaliy Mysak 		buf[0] = '\0';
127d267d0e8SVitaliy Mysak 		return;
128d267d0e8SVitaliy Mysak 	}
129d267d0e8SVitaliy Mysak 
130419cd369SVitaliy Mysak 	clock_gettime(CLOCK_REALTIME, &ts);
131419cd369SVitaliy Mysak 	info = localtime(&ts.tv_sec);
132419cd369SVitaliy Mysak 	usec = ts.tv_nsec / 1000;
1338e65bfc7SSeth Howell 	if (info == NULL) {
1348e65bfc7SSeth Howell 		snprintf(buf, buf_size, "[%s.%06ld] ", "unknown date", usec);
1358e65bfc7SSeth Howell 		return;
1368e65bfc7SSeth Howell 	}
137419cd369SVitaliy Mysak 
138419cd369SVitaliy Mysak 	strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", info);
139419cd369SVitaliy Mysak 	snprintf(buf, buf_size, "[%s.%06ld] ", date, usec);
140419cd369SVitaliy Mysak }
141419cd369SVitaliy Mysak 
142235a8e37SBen Walker void
143cca697b0SBen Walker spdk_log(enum spdk_log_level level, const char *file, const int line, const char *func,
144aaa533adSDaniel Verkamp 	 const char *format, ...)
145aaa533adSDaniel Verkamp {
146cbe9ea52SVitaliy Mysak 	va_list ap;
147cbe9ea52SVitaliy Mysak 
148cbe9ea52SVitaliy Mysak 	va_start(ap, format);
149cbe9ea52SVitaliy Mysak 	spdk_vlog(level, file, line, func, format, ap);
150cbe9ea52SVitaliy Mysak 	va_end(ap);
151cbe9ea52SVitaliy Mysak }
152cbe9ea52SVitaliy Mysak 
15301936d2eSChangpeng Liu int
15401936d2eSChangpeng Liu spdk_log_to_syslog_level(enum spdk_log_level level)
15501936d2eSChangpeng Liu {
15601936d2eSChangpeng Liu 	switch (level) {
15701936d2eSChangpeng Liu 	case SPDK_LOG_DEBUG:
15801936d2eSChangpeng Liu 	case SPDK_LOG_INFO:
15901936d2eSChangpeng Liu 		return LOG_INFO;
16001936d2eSChangpeng Liu 	case SPDK_LOG_NOTICE:
16101936d2eSChangpeng Liu 		return LOG_NOTICE;
16201936d2eSChangpeng Liu 	case SPDK_LOG_WARN:
16301936d2eSChangpeng Liu 		return LOG_WARNING;
16401936d2eSChangpeng Liu 	case SPDK_LOG_ERROR:
16501936d2eSChangpeng Liu 		return LOG_ERR;
16601936d2eSChangpeng Liu 	case SPDK_LOG_DISABLED:
16701936d2eSChangpeng Liu 		return -1;
16801936d2eSChangpeng Liu 	default:
16901936d2eSChangpeng Liu 		break;
17001936d2eSChangpeng Liu 	}
17101936d2eSChangpeng Liu 
17201936d2eSChangpeng Liu 	return LOG_INFO;
17301936d2eSChangpeng Liu }
17401936d2eSChangpeng Liu 
175cbe9ea52SVitaliy Mysak void
176cbe9ea52SVitaliy Mysak spdk_vlog(enum spdk_log_level level, const char *file, const int line, const char *func,
177cbe9ea52SVitaliy Mysak 	  const char *format, va_list ap)
178cbe9ea52SVitaliy Mysak {
179cca697b0SBen Walker 	int severity = LOG_INFO;
180f387b7feSShuhei Matsumoto 	char *buf, _buf[MAX_TMPBUF], *ext_buf = NULL;
181a2606d4bSMaciej Szwed 	char timestamp[64];
182a93a149cSJim Harris 	va_list ap_copy;
183f387b7feSShuhei Matsumoto 	int rc;
184aaa533adSDaniel Verkamp 
185*0ce363beSVasilii Ivanov 	if (g_log_opts.log) {
186*0ce363beSVasilii Ivanov 		g_log_opts.log(level, file, line, func, format, ap);
187a50246fbSx00267701 		return;
188a50246fbSx00267701 	}
189a50246fbSx00267701 
190a50246fbSx00267701 	if (level > g_spdk_log_print_level && level > g_spdk_log_level) {
191a50246fbSx00267701 		return;
192a50246fbSx00267701 	}
193a50246fbSx00267701 
19401936d2eSChangpeng Liu 	severity = spdk_log_to_syslog_level(level);
19501936d2eSChangpeng Liu 	if (severity < 0) {
196ae2b2f64SPawel Wodkowski 		return;
197aaa533adSDaniel Verkamp 	}
198aaa533adSDaniel Verkamp 
199f387b7feSShuhei Matsumoto 	buf = _buf;
200f387b7feSShuhei Matsumoto 
201a93a149cSJim Harris 	va_copy(ap_copy, ap);
202f387b7feSShuhei Matsumoto 	rc = vsnprintf(_buf, sizeof(_buf), format, ap);
203f387b7feSShuhei Matsumoto 	if (rc > MAX_TMPBUF) {
204f387b7feSShuhei Matsumoto 		/* The output including the terminating was more than MAX_TMPBUF bytes.
205f387b7feSShuhei Matsumoto 		 * Try allocating memory large enough to hold the output.
206f387b7feSShuhei Matsumoto 		 */
207a93a149cSJim Harris 		rc = vasprintf(&ext_buf, format, ap_copy);
208f387b7feSShuhei Matsumoto 		if (rc < 0) {
209f387b7feSShuhei Matsumoto 			/* Failed to allocate memory. Allow output to be truncated. */
210f387b7feSShuhei Matsumoto 		} else {
211f387b7feSShuhei Matsumoto 			buf = ext_buf;
212f387b7feSShuhei Matsumoto 		}
213f387b7feSShuhei Matsumoto 	}
214d5e293deSMarcin Spiewak 	va_end(ap_copy);
215cca697b0SBen Walker 
21665918cb8SBen Walker 	if (level <= g_spdk_log_print_level) {
217419cd369SVitaliy Mysak 		get_timestamp_prefix(timestamp, sizeof(timestamp));
218caa9d4c8SVitaliy Mysak 		if (file) {
219419cd369SVitaliy Mysak 			fprintf(stderr, "%s%s:%4d:%s: *%s*: %s", timestamp, file, line, func, spdk_level_names[level], buf);
220caa9d4c8SVitaliy Mysak 		} else {
221419cd369SVitaliy Mysak 			fprintf(stderr, "%s%s", timestamp, buf);
222caa9d4c8SVitaliy Mysak 		}
223aaa533adSDaniel Verkamp 	}
22465918cb8SBen Walker 
22565918cb8SBen Walker 	if (level <= g_spdk_log_level) {
226caa9d4c8SVitaliy Mysak 		if (file) {
22765918cb8SBen Walker 			syslog(severity, "%s:%4d:%s: *%s*: %s", file, line, func, spdk_level_names[level], buf);
228caa9d4c8SVitaliy Mysak 		} else {
229caa9d4c8SVitaliy Mysak 			syslog(severity, "%s", buf);
230caa9d4c8SVitaliy Mysak 		}
231aaa533adSDaniel Verkamp 	}
232f387b7feSShuhei Matsumoto 
233f387b7feSShuhei Matsumoto 	free(ext_buf);
234aaa533adSDaniel Verkamp }
235aaa533adSDaniel Verkamp 
2364f651a5cSShuhei Matsumoto void
2374f651a5cSShuhei Matsumoto spdk_vflog(FILE *fp, const char *file, const int line, const char *func,
2384f651a5cSShuhei Matsumoto 	   const char *format, va_list ap)
2394f651a5cSShuhei Matsumoto {
2404f651a5cSShuhei Matsumoto 	char buf[MAX_TMPBUF];
2414f651a5cSShuhei Matsumoto 	char timestamp[64];
2424f651a5cSShuhei Matsumoto 
2434f651a5cSShuhei Matsumoto 	vsnprintf(buf, sizeof(buf), format, ap);
2444f651a5cSShuhei Matsumoto 
2454f651a5cSShuhei Matsumoto 	get_timestamp_prefix(timestamp, sizeof(timestamp));
2464f651a5cSShuhei Matsumoto 
2474f651a5cSShuhei Matsumoto 	if (file) {
2484f651a5cSShuhei Matsumoto 		fprintf(fp, "%s%s:%4d:%s: %s", timestamp, file, line, func, buf);
2494f651a5cSShuhei Matsumoto 	} else {
2504f651a5cSShuhei Matsumoto 		fprintf(fp, "%s%s", timestamp, buf);
2514f651a5cSShuhei Matsumoto 	}
2524f651a5cSShuhei Matsumoto 
2534f651a5cSShuhei Matsumoto 	fflush(fp);
2544f651a5cSShuhei Matsumoto }
2554f651a5cSShuhei Matsumoto 
2564f651a5cSShuhei Matsumoto void
2574f651a5cSShuhei Matsumoto spdk_flog(FILE *fp, const char *file, const int line, const char *func,
2584f651a5cSShuhei Matsumoto 	  const char *format, ...)
2594f651a5cSShuhei Matsumoto {
2604f651a5cSShuhei Matsumoto 	va_list ap;
2614f651a5cSShuhei Matsumoto 
2624f651a5cSShuhei Matsumoto 	va_start(ap, format);
2634f651a5cSShuhei Matsumoto 	spdk_vflog(fp, file, line, func, format, ap);
2644f651a5cSShuhei Matsumoto 	va_end(ap);
2654f651a5cSShuhei Matsumoto }
2664f651a5cSShuhei Matsumoto 
267aaa533adSDaniel Verkamp static void
268aaa533adSDaniel Verkamp fdump(FILE *fp, const char *label, const uint8_t *buf, size_t len)
269aaa533adSDaniel Verkamp {
270aaa533adSDaniel Verkamp 	char tmpbuf[MAX_TMPBUF];
27125749728SKrzysztof Jakimiak 	char buf16[16 + 1];
272aaa533adSDaniel Verkamp 	size_t total;
27325749728SKrzysztof Jakimiak 	unsigned int idx;
274aaa533adSDaniel Verkamp 
275aaa533adSDaniel Verkamp 	fprintf(fp, "%s\n", label);
276aaa533adSDaniel Verkamp 
27725749728SKrzysztof Jakimiak 	memset(buf16, 0, sizeof buf16);
278aaa533adSDaniel Verkamp 	total = 0;
279aaa533adSDaniel Verkamp 	for (idx = 0; idx < len; idx++) {
28025749728SKrzysztof Jakimiak 		if (idx != 0 && idx % 16 == 0) {
281aaa533adSDaniel Verkamp 			snprintf(tmpbuf + total, sizeof tmpbuf - total,
28225749728SKrzysztof Jakimiak 				 " %s", buf16);
283a2dbaf7eSRichael Zhuang 			memset(buf16, 0, sizeof buf16);
284aaa533adSDaniel Verkamp 			fprintf(fp, "%s\n", tmpbuf);
285aaa533adSDaniel Verkamp 			total = 0;
286aaa533adSDaniel Verkamp 		}
28725749728SKrzysztof Jakimiak 		if (idx % 16 == 0) {
28825749728SKrzysztof Jakimiak 			total += snprintf(tmpbuf + total, sizeof tmpbuf - total,
28925749728SKrzysztof Jakimiak 					  "%08x ", idx);
29025749728SKrzysztof Jakimiak 		}
29125749728SKrzysztof Jakimiak 		if (idx % 8 == 0) {
29225749728SKrzysztof Jakimiak 			total += snprintf(tmpbuf + total, sizeof tmpbuf - total,
29325749728SKrzysztof Jakimiak 					  "%s", " ");
29425749728SKrzysztof Jakimiak 		}
295aaa533adSDaniel Verkamp 		total += snprintf(tmpbuf + total, sizeof tmpbuf - total,
296aaa533adSDaniel Verkamp 				  "%2.2x ", buf[idx] & 0xff);
29725749728SKrzysztof Jakimiak 		buf16[idx % 16] = isprint(buf[idx]) ? buf[idx] : '.';
298aaa533adSDaniel Verkamp 	}
29925749728SKrzysztof Jakimiak 	for (; idx % 16 != 0; idx++) {
3001db6c18eSDarek Stojaczyk 		if (idx == 8) {
3011db6c18eSDarek Stojaczyk 			total += snprintf(tmpbuf + total, sizeof tmpbuf - total,
3021db6c18eSDarek Stojaczyk 					  " ");
3031db6c18eSDarek Stojaczyk 		}
3041db6c18eSDarek Stojaczyk 
305aaa533adSDaniel Verkamp 		total += snprintf(tmpbuf + total, sizeof tmpbuf - total, "   ");
306aaa533adSDaniel Verkamp 	}
30725749728SKrzysztof Jakimiak 	snprintf(tmpbuf + total, sizeof tmpbuf - total, "  %s", buf16);
308aaa533adSDaniel Verkamp 	fprintf(fp, "%s\n", tmpbuf);
309aaa533adSDaniel Verkamp 	fflush(fp);
310aaa533adSDaniel Verkamp }
311aaa533adSDaniel Verkamp 
312aaa533adSDaniel Verkamp void
313b4b7d5d3SJim Harris spdk_log_dump(FILE *fp, const char *label, const void *buf, size_t len)
314aaa533adSDaniel Verkamp {
3159b99f2c0SPaul Luse 	fdump(fp, label, buf, len);
316aaa533adSDaniel Verkamp }
317