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 1253 : get_timestamp_prefix(char *buf, int buf_size)
78 : {
79 : struct tm *info;
80 1253 : char date[24];
81 1253 : struct timespec ts;
82 : long usec;
83 :
84 1253 : if (!g_log_timestamps) {
85 0 : buf[0] = '\0';
86 0 : return;
87 : }
88 :
89 1253 : clock_gettime(CLOCK_REALTIME, &ts);
90 1253 : info = localtime(&ts.tv_sec);
91 1253 : usec = ts.tv_nsec / 1000;
92 1253 : if (info == NULL) {
93 0 : snprintf(buf, buf_size, "[%s.%06ld] ", "unknown date", usec);
94 0 : return;
95 : }
96 :
97 1253 : strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", info);
98 1253 : snprintf(buf, buf_size, "[%s.%06ld] ", date, usec);
99 : }
100 :
101 : void
102 2477 : spdk_log(enum spdk_log_level level, const char *file, const int line, const char *func,
103 : const char *format, ...)
104 : {
105 2477 : va_list ap;
106 :
107 2477 : va_start(ap, format);
108 2477 : spdk_vlog(level, file, line, func, format, ap);
109 2477 : va_end(ap);
110 2477 : }
111 :
112 : int
113 1253 : spdk_log_to_syslog_level(enum spdk_log_level level)
114 : {
115 1253 : 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 1251 : case SPDK_LOG_ERROR:
124 1251 : 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 2477 : 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 2477 : int severity = LOG_INFO;
139 2477 : char *buf, _buf[MAX_TMPBUF], *ext_buf = NULL;
140 2477 : char timestamp[64];
141 : int rc;
142 :
143 2477 : if (g_log) {
144 5 : g_log(level, file, line, func, format, ap);
145 5 : return;
146 : }
147 :
148 2472 : if (level > g_spdk_log_print_level && level > g_spdk_log_level) {
149 1219 : return;
150 : }
151 :
152 1253 : severity = spdk_log_to_syslog_level(level);
153 1253 : if (severity < 0) {
154 0 : return;
155 : }
156 :
157 1253 : buf = _buf;
158 :
159 1253 : rc = vsnprintf(_buf, sizeof(_buf), format, ap);
160 1253 : if (rc > MAX_TMPBUF) {
161 : /* The output including the terminating was more than MAX_TMPBUF bytes.
162 : * Try allocating memory large enough to hold the output.
163 : */
164 1 : rc = vasprintf(&ext_buf, format, ap);
165 1 : if (rc < 0) {
166 : /* Failed to allocate memory. Allow output to be truncated. */
167 : } else {
168 1 : buf = ext_buf;
169 : }
170 : }
171 :
172 1253 : if (level <= g_spdk_log_print_level) {
173 1253 : get_timestamp_prefix(timestamp, sizeof(timestamp));
174 1253 : if (file) {
175 1253 : fprintf(stderr, "%s%s:%4d:%s: *%s*: %s", timestamp, file, line, func, spdk_level_names[level], buf);
176 : } else {
177 0 : fprintf(stderr, "%s%s", timestamp, buf);
178 : }
179 : }
180 :
181 1253 : if (level <= g_spdk_log_level) {
182 1253 : if (file) {
183 1253 : syslog(severity, "%s:%4d:%s: *%s*: %s", file, line, func, spdk_level_names[level], buf);
184 : } else {
185 0 : syslog(severity, "%s", buf);
186 : }
187 : }
188 :
189 1253 : free(ext_buf);
190 : }
191 :
192 : void
193 0 : spdk_vflog(FILE *fp, const char *file, const int line, const char *func,
194 : const char *format, va_list ap)
195 : {
196 0 : char buf[MAX_TMPBUF];
197 0 : char timestamp[64];
198 :
199 0 : vsnprintf(buf, sizeof(buf), format, ap);
200 :
201 0 : get_timestamp_prefix(timestamp, sizeof(timestamp));
202 :
203 0 : if (file) {
204 0 : fprintf(fp, "%s%s:%4d:%s: %s", timestamp, file, line, func, buf);
205 : } else {
206 0 : fprintf(fp, "%s%s", timestamp, buf);
207 : }
208 :
209 0 : fflush(fp);
210 0 : }
211 :
212 : void
213 0 : spdk_flog(FILE *fp, const char *file, const int line, const char *func,
214 : const char *format, ...)
215 : {
216 0 : va_list ap;
217 :
218 0 : va_start(ap, format);
219 0 : spdk_vflog(fp, file, line, func, format, ap);
220 0 : va_end(ap);
221 0 : }
222 :
223 : static void
224 3 : fdump(FILE *fp, const char *label, const uint8_t *buf, size_t len)
225 : {
226 3 : char tmpbuf[MAX_TMPBUF];
227 3 : char buf16[16 + 1];
228 : size_t total;
229 : unsigned int idx;
230 :
231 3 : fprintf(fp, "%s\n", label);
232 :
233 3 : memset(buf16, 0, sizeof buf16);
234 3 : total = 0;
235 43 : for (idx = 0; idx < len; idx++) {
236 40 : if (idx != 0 && idx % 16 == 0) {
237 1 : snprintf(tmpbuf + total, sizeof tmpbuf - total,
238 : " %s", buf16);
239 1 : memset(buf16, 0, sizeof buf16);
240 1 : fprintf(fp, "%s\n", tmpbuf);
241 1 : total = 0;
242 : }
243 40 : if (idx % 16 == 0) {
244 4 : total += snprintf(tmpbuf + total, sizeof tmpbuf - total,
245 : "%08x ", idx);
246 : }
247 40 : if (idx % 8 == 0) {
248 6 : total += snprintf(tmpbuf + total, sizeof tmpbuf - total,
249 : "%s", " ");
250 : }
251 40 : total += snprintf(tmpbuf + total, sizeof tmpbuf - total,
252 40 : "%2.2x ", buf[idx] & 0xff);
253 40 : buf16[idx % 16] = isprint(buf[idx]) ? buf[idx] : '.';
254 : }
255 27 : for (; idx % 16 != 0; idx++) {
256 24 : if (idx == 8) {
257 1 : total += snprintf(tmpbuf + total, sizeof tmpbuf - total,
258 : " ");
259 : }
260 :
261 24 : total += snprintf(tmpbuf + total, sizeof tmpbuf - total, " ");
262 : }
263 3 : snprintf(tmpbuf + total, sizeof tmpbuf - total, " %s", buf16);
264 3 : fprintf(fp, "%s\n", tmpbuf);
265 3 : fflush(fp);
266 3 : }
267 :
268 : void
269 3 : spdk_log_dump(FILE *fp, const char *label, const void *buf, size_t len)
270 : {
271 3 : fdump(fp, label, buf, len);
272 3 : }
|