xref: /spdk/lib/log/log.c (revision 307b8c112ffd90a26d53dd15fad67bd9038ef526)
1 /*   SPDX-License-Identifier: BSD-3-Clause
2  *   Copyright (c) Intel Corporation.
3  *   All rights reserved.
4  */
5 
6 #include "spdk/stdinc.h"
7 
8 #include "spdk/log.h"
9 
10 static const char *const spdk_level_names[] = {
11 	[SPDK_LOG_ERROR]	= "ERROR",
12 	[SPDK_LOG_WARN]		= "WARNING",
13 	[SPDK_LOG_NOTICE]	= "NOTICE",
14 	[SPDK_LOG_INFO]		= "INFO",
15 	[SPDK_LOG_DEBUG]	= "DEBUG",
16 };
17 
18 #define MAX_TMPBUF 1024
19 
20 static logfunc *g_log = NULL;
21 static bool g_log_timestamps = true;
22 
23 enum spdk_log_level g_spdk_log_level;
24 enum spdk_log_level g_spdk_log_print_level;
25 
26 SPDK_LOG_REGISTER_COMPONENT(log)
27 
28 void
29 spdk_log_set_level(enum spdk_log_level level)
30 {
31 	assert(level >= SPDK_LOG_DISABLED);
32 	assert(level <= SPDK_LOG_DEBUG);
33 	g_spdk_log_level = level;
34 }
35 
36 enum spdk_log_level
37 spdk_log_get_level(void) {
38 	return g_spdk_log_level;
39 }
40 
41 void
42 spdk_log_set_print_level(enum spdk_log_level level)
43 {
44 	assert(level >= SPDK_LOG_DISABLED);
45 	assert(level <= SPDK_LOG_DEBUG);
46 	g_spdk_log_print_level = level;
47 }
48 
49 enum spdk_log_level
50 spdk_log_get_print_level(void) {
51 	return g_spdk_log_print_level;
52 }
53 
54 void
55 spdk_log_open(logfunc *logf)
56 {
57 	if (logf) {
58 		g_log = logf;
59 	} else {
60 		openlog("spdk", LOG_PID, LOG_LOCAL7);
61 	}
62 }
63 
64 void
65 spdk_log_close(void)
66 {
67 	if (!g_log) {
68 		closelog();
69 	}
70 }
71 
72 void
73 spdk_log_enable_timestamps(bool value)
74 {
75 	g_log_timestamps = value;
76 }
77 
78 static void
79 get_timestamp_prefix(char *buf, int buf_size)
80 {
81 	struct tm *info;
82 	char date[24];
83 	struct timespec ts;
84 	long usec;
85 
86 	if (!g_log_timestamps) {
87 		buf[0] = '\0';
88 		return;
89 	}
90 
91 	clock_gettime(CLOCK_REALTIME, &ts);
92 	info = localtime(&ts.tv_sec);
93 	usec = ts.tv_nsec / 1000;
94 	if (info == NULL) {
95 		snprintf(buf, buf_size, "[%s.%06ld] ", "unknown date", usec);
96 		return;
97 	}
98 
99 	strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", info);
100 	snprintf(buf, buf_size, "[%s.%06ld] ", date, usec);
101 }
102 
103 void
104 spdk_log(enum spdk_log_level level, const char *file, const int line, const char *func,
105 	 const char *format, ...)
106 {
107 	va_list ap;
108 
109 	va_start(ap, format);
110 	spdk_vlog(level, file, line, func, format, ap);
111 	va_end(ap);
112 }
113 
114 int
115 spdk_log_to_syslog_level(enum spdk_log_level level)
116 {
117 	switch (level) {
118 	case SPDK_LOG_DEBUG:
119 	case SPDK_LOG_INFO:
120 		return LOG_INFO;
121 	case SPDK_LOG_NOTICE:
122 		return LOG_NOTICE;
123 	case SPDK_LOG_WARN:
124 		return LOG_WARNING;
125 	case SPDK_LOG_ERROR:
126 		return LOG_ERR;
127 	case SPDK_LOG_DISABLED:
128 		return -1;
129 	default:
130 		break;
131 	}
132 
133 	return LOG_INFO;
134 }
135 
136 void
137 spdk_vlog(enum spdk_log_level level, const char *file, const int line, const char *func,
138 	  const char *format, va_list ap)
139 {
140 	int severity = LOG_INFO;
141 	char buf[MAX_TMPBUF];
142 	char timestamp[64];
143 
144 	if (g_log) {
145 		g_log(level, file, line, func, format, ap);
146 		return;
147 	}
148 
149 	if (level > g_spdk_log_print_level && level > g_spdk_log_level) {
150 		return;
151 	}
152 
153 	severity = spdk_log_to_syslog_level(level);
154 	if (severity < 0) {
155 		return;
156 	}
157 
158 	vsnprintf(buf, sizeof(buf), format, ap);
159 
160 	if (level <= g_spdk_log_print_level) {
161 		get_timestamp_prefix(timestamp, sizeof(timestamp));
162 		if (file) {
163 			fprintf(stderr, "%s%s:%4d:%s: *%s*: %s", timestamp, file, line, func, spdk_level_names[level], buf);
164 		} else {
165 			fprintf(stderr, "%s%s", timestamp, buf);
166 		}
167 	}
168 
169 	if (level <= g_spdk_log_level) {
170 		if (file) {
171 			syslog(severity, "%s:%4d:%s: *%s*: %s", file, line, func, spdk_level_names[level], buf);
172 		} else {
173 			syslog(severity, "%s", buf);
174 		}
175 	}
176 }
177 
178 static void
179 fdump(FILE *fp, const char *label, const uint8_t *buf, size_t len)
180 {
181 	char tmpbuf[MAX_TMPBUF];
182 	char buf16[16 + 1];
183 	size_t total;
184 	unsigned int idx;
185 
186 	fprintf(fp, "%s\n", label);
187 
188 	memset(buf16, 0, sizeof buf16);
189 	total = 0;
190 	for (idx = 0; idx < len; idx++) {
191 		if (idx != 0 && idx % 16 == 0) {
192 			snprintf(tmpbuf + total, sizeof tmpbuf - total,
193 				 " %s", buf16);
194 			memset(buf16, 0, sizeof buf16);
195 			fprintf(fp, "%s\n", tmpbuf);
196 			total = 0;
197 		}
198 		if (idx % 16 == 0) {
199 			total += snprintf(tmpbuf + total, sizeof tmpbuf - total,
200 					  "%08x ", idx);
201 		}
202 		if (idx % 8 == 0) {
203 			total += snprintf(tmpbuf + total, sizeof tmpbuf - total,
204 					  "%s", " ");
205 		}
206 		total += snprintf(tmpbuf + total, sizeof tmpbuf - total,
207 				  "%2.2x ", buf[idx] & 0xff);
208 		buf16[idx % 16] = isprint(buf[idx]) ? buf[idx] : '.';
209 	}
210 	for (; idx % 16 != 0; idx++) {
211 		if (idx == 8) {
212 			total += snprintf(tmpbuf + total, sizeof tmpbuf - total,
213 					  " ");
214 		}
215 
216 		total += snprintf(tmpbuf + total, sizeof tmpbuf - total, "   ");
217 	}
218 	snprintf(tmpbuf + total, sizeof tmpbuf - total, "  %s", buf16);
219 	fprintf(fp, "%s\n", tmpbuf);
220 	fflush(fp);
221 }
222 
223 void
224 spdk_log_dump(FILE *fp, const char *label, const void *buf, size_t len)
225 {
226 	fdump(fp, label, buf, len);
227 }
228