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 :
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 : void
27 5 : spdk_log_set_level(enum spdk_log_level level)
28 : {
29 5 : assert(level >= SPDK_LOG_DISABLED);
30 5 : assert(level <= SPDK_LOG_DEBUG);
31 5 : g_spdk_log_level = level;
32 5 : }
33 :
34 : enum spdk_log_level
35 5 : spdk_log_get_level(void) {
36 5 : return g_spdk_log_level;
37 : }
38 :
39 : void
40 5 : spdk_log_set_print_level(enum spdk_log_level level)
41 : {
42 5 : assert(level >= SPDK_LOG_DISABLED);
43 5 : assert(level <= SPDK_LOG_DEBUG);
44 5 : g_spdk_log_print_level = level;
45 5 : }
46 :
47 : enum spdk_log_level
48 5 : spdk_log_get_print_level(void) {
49 5 : return g_spdk_log_print_level;
50 : }
51 :
52 : void
53 2 : spdk_log_open(logfunc *logf)
54 : {
55 2 : if (logf) {
56 1 : g_log = logf;
57 : } else {
58 1 : openlog("spdk", LOG_PID, LOG_LOCAL7);
59 : }
60 2 : }
61 :
62 : void
63 1 : spdk_log_close(void)
64 : {
65 1 : if (!g_log) {
66 1 : closelog();
67 : }
68 1 : }
69 :
70 : void
71 0 : spdk_log_enable_timestamps(bool value)
72 : {
73 0 : g_log_timestamps = value;
74 0 : }
75 :
76 : static void
77 1277 : get_timestamp_prefix(char *buf, int buf_size)
78 : {
79 : struct tm *info;
80 1277 : char date[24];
81 1277 : struct timespec ts;
82 : long usec;
83 :
84 1277 : if (!g_log_timestamps) {
85 0 : buf[0] = '\0';
86 0 : return;
87 : }
88 :
89 1277 : clock_gettime(CLOCK_REALTIME, &ts);
90 1277 : info = localtime(&ts.tv_sec);
91 1277 : usec = ts.tv_nsec / 1000;
92 1277 : if (info == NULL) {
93 0 : snprintf(buf, buf_size, "[%s.%06ld] ", "unknown date", usec);
94 0 : return;
95 : }
96 :
97 1277 : strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", info);
98 1277 : snprintf(buf, buf_size, "[%s.%06ld] ", date, usec);
99 : }
100 :
101 : void
102 2505 : spdk_log(enum spdk_log_level level, const char *file, const int line, const char *func,
103 : const char *format, ...)
104 : {
105 2505 : va_list ap;
106 :
107 2505 : va_start(ap, format);
108 2505 : spdk_vlog(level, file, line, func, format, ap);
109 2505 : va_end(ap);
110 2505 : }
111 :
112 : int
113 1277 : spdk_log_to_syslog_level(enum spdk_log_level level)
114 : {
115 1277 : switch (level) {
116 1 : case SPDK_LOG_DEBUG:
117 : case SPDK_LOG_INFO:
118 1 : return LOG_INFO;
119 0 : case SPDK_LOG_NOTICE:
120 0 : return LOG_NOTICE;
121 1 : case SPDK_LOG_WARN:
122 1 : return LOG_WARNING;
123 1275 : case SPDK_LOG_ERROR:
124 1275 : return LOG_ERR;
125 0 : case SPDK_LOG_DISABLED:
126 0 : return -1;
127 0 : default:
128 0 : break;
129 : }
130 :
131 0 : return LOG_INFO;
132 : }
133 :
134 : void
135 2505 : spdk_vlog(enum spdk_log_level level, const char *file, const int line, const char *func,
136 : const char *format, va_list ap)
137 : {
138 2505 : int severity = LOG_INFO;
139 2505 : char *buf, _buf[MAX_TMPBUF], *ext_buf = NULL;
140 2505 : char timestamp[64];
141 2505 : va_list ap_copy;
142 : int rc;
143 :
144 2505 : if (g_log) {
145 5 : g_log(level, file, line, func, format, ap);
146 5 : return;
147 : }
148 :
149 2500 : if (level > g_spdk_log_print_level && level > g_spdk_log_level) {
150 1223 : return;
151 : }
152 :
153 1277 : severity = spdk_log_to_syslog_level(level);
154 1277 : if (severity < 0) {
155 0 : return;
156 : }
157 :
158 1277 : buf = _buf;
159 :
160 1277 : va_copy(ap_copy, ap);
161 1277 : rc = vsnprintf(_buf, sizeof(_buf), format, ap);
162 1277 : if (rc > MAX_TMPBUF) {
163 : /* The output including the terminating was more than MAX_TMPBUF bytes.
164 : * Try allocating memory large enough to hold the output.
165 : */
166 1 : rc = vasprintf(&ext_buf, format, ap_copy);
167 1 : if (rc < 0) {
168 : /* Failed to allocate memory. Allow output to be truncated. */
169 : } else {
170 1 : buf = ext_buf;
171 : }
172 : }
173 1277 : va_end(ap_copy);
174 :
175 1277 : if (level <= g_spdk_log_print_level) {
176 1277 : get_timestamp_prefix(timestamp, sizeof(timestamp));
177 1277 : if (file) {
178 1277 : fprintf(stderr, "%s%s:%4d:%s: *%s*: %s", timestamp, file, line, func, spdk_level_names[level], buf);
179 : } else {
180 0 : fprintf(stderr, "%s%s", timestamp, buf);
181 : }
182 : }
183 :
184 1277 : if (level <= g_spdk_log_level) {
185 1277 : if (file) {
186 1277 : syslog(severity, "%s:%4d:%s: *%s*: %s", file, line, func, spdk_level_names[level], buf);
187 : } else {
188 0 : syslog(severity, "%s", buf);
189 : }
190 : }
191 :
192 1277 : free(ext_buf);
193 : }
194 :
195 : void
196 0 : spdk_vflog(FILE *fp, const char *file, const int line, const char *func,
197 : const char *format, va_list ap)
198 : {
199 0 : char buf[MAX_TMPBUF];
200 0 : char timestamp[64];
201 :
202 0 : vsnprintf(buf, sizeof(buf), format, ap);
203 :
204 0 : get_timestamp_prefix(timestamp, sizeof(timestamp));
205 :
206 0 : if (file) {
207 0 : fprintf(fp, "%s%s:%4d:%s: %s", timestamp, file, line, func, buf);
208 : } else {
209 0 : fprintf(fp, "%s%s", timestamp, buf);
210 : }
211 :
212 0 : fflush(fp);
213 0 : }
214 :
215 : void
216 0 : spdk_flog(FILE *fp, const char *file, const int line, const char *func,
217 : const char *format, ...)
218 : {
219 0 : va_list ap;
220 :
221 0 : va_start(ap, format);
222 0 : spdk_vflog(fp, file, line, func, format, ap);
223 0 : va_end(ap);
224 0 : }
225 :
226 : static void
227 3 : fdump(FILE *fp, const char *label, const uint8_t *buf, size_t len)
228 : {
229 3 : char tmpbuf[MAX_TMPBUF];
230 3 : char buf16[16 + 1];
231 : size_t total;
232 : unsigned int idx;
233 :
234 3 : fprintf(fp, "%s\n", label);
235 :
236 3 : memset(buf16, 0, sizeof buf16);
237 3 : total = 0;
238 43 : for (idx = 0; idx < len; idx++) {
239 40 : if (idx != 0 && idx % 16 == 0) {
240 1 : snprintf(tmpbuf + total, sizeof tmpbuf - total,
241 : " %s", buf16);
242 1 : memset(buf16, 0, sizeof buf16);
243 1 : fprintf(fp, "%s\n", tmpbuf);
244 1 : total = 0;
245 : }
246 40 : if (idx % 16 == 0) {
247 4 : total += snprintf(tmpbuf + total, sizeof tmpbuf - total,
248 : "%08x ", idx);
249 : }
250 40 : if (idx % 8 == 0) {
251 6 : total += snprintf(tmpbuf + total, sizeof tmpbuf - total,
252 : "%s", " ");
253 : }
254 40 : total += snprintf(tmpbuf + total, sizeof tmpbuf - total,
255 40 : "%2.2x ", buf[idx] & 0xff);
256 40 : buf16[idx % 16] = isprint(buf[idx]) ? buf[idx] : '.';
257 : }
258 27 : for (; idx % 16 != 0; idx++) {
259 24 : if (idx == 8) {
260 1 : total += snprintf(tmpbuf + total, sizeof tmpbuf - total,
261 : " ");
262 : }
263 :
264 24 : total += snprintf(tmpbuf + total, sizeof tmpbuf - total, " ");
265 : }
266 3 : snprintf(tmpbuf + total, sizeof tmpbuf - total, " %s", buf16);
267 3 : fprintf(fp, "%s\n", tmpbuf);
268 3 : fflush(fp);
269 3 : }
270 :
271 : void
272 3 : spdk_log_dump(FILE *fp, const char *label, const void *buf, size_t len)
273 : {
274 3 : fdump(fp, label, buf, len);
275 3 : }
|