Line data Source code
1 : /* SPDX-License-Identifier: BSD-3-Clause
2 : * Copyright (C) 2016 Intel Corporation.
3 : * All rights reserved.
4 : */
5 :
6 : #include "spdk/stdinc.h"
7 : #include "spdk/util.h"
8 :
9 : #include "spdk/log.h"
10 :
11 : static const char *const spdk_level_names[] = {
12 : [SPDK_LOG_ERROR] = "ERROR",
13 : [SPDK_LOG_WARN] = "WARNING",
14 : [SPDK_LOG_NOTICE] = "NOTICE",
15 : [SPDK_LOG_INFO] = "INFO",
16 : [SPDK_LOG_DEBUG] = "DEBUG",
17 : };
18 :
19 : #define MAX_TMPBUF 1024
20 :
21 : static struct spdk_log_opts g_log_opts = {
22 : .log = NULL,
23 : .open = NULL,
24 : .close = NULL,
25 : .user_ctx = NULL,
26 : };
27 : static bool g_log_timestamps = true;
28 :
29 : enum spdk_log_level g_spdk_log_level;
30 : enum spdk_log_level g_spdk_log_print_level;
31 :
32 : void
33 5 : spdk_log_set_level(enum spdk_log_level level)
34 : {
35 5 : assert(level >= SPDK_LOG_DISABLED);
36 5 : assert(level <= SPDK_LOG_DEBUG);
37 5 : g_spdk_log_level = level;
38 5 : }
39 :
40 : enum spdk_log_level
41 5 : spdk_log_get_level(void) {
42 5 : return g_spdk_log_level;
43 : }
44 :
45 : void
46 5 : spdk_log_set_print_level(enum spdk_log_level level)
47 : {
48 5 : assert(level >= SPDK_LOG_DISABLED);
49 5 : assert(level <= SPDK_LOG_DEBUG);
50 5 : g_spdk_log_print_level = level;
51 5 : }
52 :
53 : enum spdk_log_level
54 5 : spdk_log_get_print_level(void) {
55 5 : return g_spdk_log_print_level;
56 : }
57 :
58 : static void
59 1 : log_open(void *ctx)
60 : {
61 1 : openlog("spdk", LOG_PID, LOG_LOCAL7);
62 1 : }
63 :
64 : static void
65 1 : log_close(void *ctx)
66 : {
67 1 : closelog();
68 1 : }
69 :
70 : void
71 2 : spdk_log_open(spdk_log_cb *log)
72 : {
73 2 : if (log) {
74 1 : struct spdk_log_opts opts = {.log = log};
75 1 : opts.size = SPDK_SIZEOF(&opts, log);
76 1 : spdk_log_open_ext(&opts);
77 : } else {
78 1 : spdk_log_open_ext(NULL);
79 : }
80 2 : }
81 :
82 : void
83 3 : spdk_log_open_ext(struct spdk_log_opts *opts)
84 : {
85 3 : if (!opts) {
86 1 : g_log_opts.open = log_open;
87 1 : g_log_opts.close = log_close;
88 1 : goto out;
89 : }
90 :
91 2 : g_log_opts.log = SPDK_GET_FIELD(opts, log, NULL);
92 2 : g_log_opts.open = SPDK_GET_FIELD(opts, open, NULL);
93 2 : g_log_opts.close = SPDK_GET_FIELD(opts, close, NULL);
94 2 : g_log_opts.user_ctx = SPDK_GET_FIELD(opts, user_ctx, NULL);
95 :
96 3 : out:
97 3 : if (g_log_opts.open) {
98 2 : g_log_opts.open(g_log_opts.user_ctx);
99 : }
100 3 : }
101 :
102 : void
103 3 : spdk_log_close(void)
104 : {
105 3 : if (g_log_opts.close) {
106 2 : g_log_opts.close(g_log_opts.user_ctx);
107 : }
108 3 : memset(&g_log_opts, 0, sizeof(g_log_opts));
109 3 : }
110 :
111 : void
112 0 : spdk_log_enable_timestamps(bool value)
113 : {
114 0 : g_log_timestamps = value;
115 0 : }
116 :
117 : static void
118 1336 : get_timestamp_prefix(char *buf, int buf_size)
119 : {
120 : struct tm *info;
121 1336 : char date[24];
122 1336 : struct timespec ts;
123 : long usec;
124 :
125 1336 : if (!g_log_timestamps) {
126 0 : buf[0] = '\0';
127 0 : return;
128 : }
129 :
130 1336 : clock_gettime(CLOCK_REALTIME, &ts);
131 1336 : info = localtime(&ts.tv_sec);
132 1336 : usec = ts.tv_nsec / 1000;
133 1336 : if (info == NULL) {
134 0 : snprintf(buf, buf_size, "[%s.%06ld] ", "unknown date", usec);
135 0 : return;
136 : }
137 :
138 1336 : strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", info);
139 1336 : snprintf(buf, buf_size, "[%s.%06ld] ", date, usec);
140 : }
141 :
142 : void
143 2589 : spdk_log(enum spdk_log_level level, const char *file, const int line, const char *func,
144 : const char *format, ...)
145 : {
146 2589 : va_list ap;
147 :
148 2589 : va_start(ap, format);
149 2589 : spdk_vlog(level, file, line, func, format, ap);
150 2589 : va_end(ap);
151 2589 : }
152 :
153 : int
154 1336 : spdk_log_to_syslog_level(enum spdk_log_level level)
155 : {
156 1336 : switch (level) {
157 1 : case SPDK_LOG_DEBUG:
158 : case SPDK_LOG_INFO:
159 1 : return LOG_INFO;
160 0 : case SPDK_LOG_NOTICE:
161 0 : return LOG_NOTICE;
162 1 : case SPDK_LOG_WARN:
163 1 : return LOG_WARNING;
164 1334 : case SPDK_LOG_ERROR:
165 1334 : return LOG_ERR;
166 0 : case SPDK_LOG_DISABLED:
167 0 : return -1;
168 0 : default:
169 0 : break;
170 : }
171 :
172 0 : return LOG_INFO;
173 : }
174 :
175 : void
176 2589 : spdk_vlog(enum spdk_log_level level, const char *file, const int line, const char *func,
177 : const char *format, va_list ap)
178 : {
179 2589 : int severity = LOG_INFO;
180 2589 : char *buf, _buf[MAX_TMPBUF], *ext_buf = NULL;
181 2589 : char timestamp[64];
182 2589 : va_list ap_copy;
183 : int rc;
184 :
185 2589 : if (g_log_opts.log) {
186 6 : g_log_opts.log(level, file, line, func, format, ap);
187 6 : return;
188 : }
189 :
190 2583 : if (level > g_spdk_log_print_level && level > g_spdk_log_level) {
191 1247 : return;
192 : }
193 :
194 1336 : severity = spdk_log_to_syslog_level(level);
195 1336 : if (severity < 0) {
196 0 : return;
197 : }
198 :
199 1336 : buf = _buf;
200 :
201 1336 : va_copy(ap_copy, ap);
202 1336 : rc = vsnprintf(_buf, sizeof(_buf), format, ap);
203 1336 : if (rc > MAX_TMPBUF) {
204 : /* The output including the terminating was more than MAX_TMPBUF bytes.
205 : * Try allocating memory large enough to hold the output.
206 : */
207 1 : rc = vasprintf(&ext_buf, format, ap_copy);
208 1 : if (rc < 0) {
209 : /* Failed to allocate memory. Allow output to be truncated. */
210 : } else {
211 1 : buf = ext_buf;
212 : }
213 : }
214 1336 : va_end(ap_copy);
215 :
216 1336 : if (level <= g_spdk_log_print_level) {
217 1336 : get_timestamp_prefix(timestamp, sizeof(timestamp));
218 1336 : if (file) {
219 1336 : fprintf(stderr, "%s%s:%4d:%s: *%s*: %s", timestamp, file, line, func, spdk_level_names[level], buf);
220 : } else {
221 0 : fprintf(stderr, "%s%s", timestamp, buf);
222 : }
223 : }
224 :
225 1336 : if (level <= g_spdk_log_level) {
226 1336 : if (file) {
227 1336 : syslog(severity, "%s:%4d:%s: *%s*: %s", file, line, func, spdk_level_names[level], buf);
228 : } else {
229 0 : syslog(severity, "%s", buf);
230 : }
231 : }
232 :
233 1336 : free(ext_buf);
234 : }
235 :
236 : void
237 0 : spdk_vflog(FILE *fp, const char *file, const int line, const char *func,
238 : const char *format, va_list ap)
239 : {
240 0 : char buf[MAX_TMPBUF];
241 0 : char timestamp[64];
242 :
243 0 : vsnprintf(buf, sizeof(buf), format, ap);
244 :
245 0 : get_timestamp_prefix(timestamp, sizeof(timestamp));
246 :
247 0 : if (file) {
248 0 : fprintf(fp, "%s%s:%4d:%s: %s", timestamp, file, line, func, buf);
249 : } else {
250 0 : fprintf(fp, "%s%s", timestamp, buf);
251 : }
252 :
253 0 : fflush(fp);
254 0 : }
255 :
256 : void
257 0 : spdk_flog(FILE *fp, const char *file, const int line, const char *func,
258 : const char *format, ...)
259 : {
260 0 : va_list ap;
261 :
262 0 : va_start(ap, format);
263 0 : spdk_vflog(fp, file, line, func, format, ap);
264 0 : va_end(ap);
265 0 : }
266 :
267 : static void
268 3 : fdump(FILE *fp, const char *label, const uint8_t *buf, size_t len)
269 : {
270 3 : char tmpbuf[MAX_TMPBUF];
271 3 : char buf16[16 + 1];
272 : size_t total;
273 : unsigned int idx;
274 :
275 3 : fprintf(fp, "%s\n", label);
276 :
277 3 : memset(buf16, 0, sizeof buf16);
278 3 : total = 0;
279 43 : for (idx = 0; idx < len; idx++) {
280 40 : if (idx != 0 && idx % 16 == 0) {
281 1 : snprintf(tmpbuf + total, sizeof tmpbuf - total,
282 : " %s", buf16);
283 1 : memset(buf16, 0, sizeof buf16);
284 1 : fprintf(fp, "%s\n", tmpbuf);
285 1 : total = 0;
286 : }
287 40 : if (idx % 16 == 0) {
288 4 : total += snprintf(tmpbuf + total, sizeof tmpbuf - total,
289 : "%08x ", idx);
290 : }
291 40 : if (idx % 8 == 0) {
292 6 : total += snprintf(tmpbuf + total, sizeof tmpbuf - total,
293 : "%s", " ");
294 : }
295 80 : total += snprintf(tmpbuf + total, sizeof tmpbuf - total,
296 40 : "%2.2x ", buf[idx] & 0xff);
297 40 : buf16[idx % 16] = isprint(buf[idx]) ? buf[idx] : '.';
298 : }
299 27 : for (; idx % 16 != 0; idx++) {
300 24 : if (idx == 8) {
301 1 : total += snprintf(tmpbuf + total, sizeof tmpbuf - total,
302 : " ");
303 : }
304 :
305 24 : total += snprintf(tmpbuf + total, sizeof tmpbuf - total, " ");
306 : }
307 3 : snprintf(tmpbuf + total, sizeof tmpbuf - total, " %s", buf16);
308 3 : fprintf(fp, "%s\n", tmpbuf);
309 3 : fflush(fp);
310 3 : }
311 :
312 : void
313 3 : spdk_log_dump(FILE *fp, const char *label, const void *buf, size_t len)
314 : {
315 3 : fdump(fp, label, buf, len);
316 3 : }
|