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