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 174 if (level <= g_spdk_log_print_level) { 175 get_timestamp_prefix(timestamp, sizeof(timestamp)); 176 if (file) { 177 fprintf(stderr, "%s%s:%4d:%s: *%s*: %s", timestamp, file, line, func, spdk_level_names[level], buf); 178 } else { 179 fprintf(stderr, "%s%s", timestamp, buf); 180 } 181 } 182 183 if (level <= g_spdk_log_level) { 184 if (file) { 185 syslog(severity, "%s:%4d:%s: *%s*: %s", file, line, func, spdk_level_names[level], buf); 186 } else { 187 syslog(severity, "%s", buf); 188 } 189 } 190 191 free(ext_buf); 192 } 193 194 void 195 spdk_vflog(FILE *fp, const char *file, const int line, const char *func, 196 const char *format, va_list ap) 197 { 198 char buf[MAX_TMPBUF]; 199 char timestamp[64]; 200 201 vsnprintf(buf, sizeof(buf), format, ap); 202 203 get_timestamp_prefix(timestamp, sizeof(timestamp)); 204 205 if (file) { 206 fprintf(fp, "%s%s:%4d:%s: %s", timestamp, file, line, func, buf); 207 } else { 208 fprintf(fp, "%s%s", timestamp, buf); 209 } 210 211 fflush(fp); 212 } 213 214 void 215 spdk_flog(FILE *fp, const char *file, const int line, const char *func, 216 const char *format, ...) 217 { 218 va_list ap; 219 220 va_start(ap, format); 221 spdk_vflog(fp, file, line, func, format, ap); 222 va_end(ap); 223 } 224 225 static void 226 fdump(FILE *fp, const char *label, const uint8_t *buf, size_t len) 227 { 228 char tmpbuf[MAX_TMPBUF]; 229 char buf16[16 + 1]; 230 size_t total; 231 unsigned int idx; 232 233 fprintf(fp, "%s\n", label); 234 235 memset(buf16, 0, sizeof buf16); 236 total = 0; 237 for (idx = 0; idx < len; idx++) { 238 if (idx != 0 && idx % 16 == 0) { 239 snprintf(tmpbuf + total, sizeof tmpbuf - total, 240 " %s", buf16); 241 memset(buf16, 0, sizeof buf16); 242 fprintf(fp, "%s\n", tmpbuf); 243 total = 0; 244 } 245 if (idx % 16 == 0) { 246 total += snprintf(tmpbuf + total, sizeof tmpbuf - total, 247 "%08x ", idx); 248 } 249 if (idx % 8 == 0) { 250 total += snprintf(tmpbuf + total, sizeof tmpbuf - total, 251 "%s", " "); 252 } 253 total += snprintf(tmpbuf + total, sizeof tmpbuf - total, 254 "%2.2x ", buf[idx] & 0xff); 255 buf16[idx % 16] = isprint(buf[idx]) ? buf[idx] : '.'; 256 } 257 for (; idx % 16 != 0; idx++) { 258 if (idx == 8) { 259 total += snprintf(tmpbuf + total, sizeof tmpbuf - total, 260 " "); 261 } 262 263 total += snprintf(tmpbuf + total, sizeof tmpbuf - total, " "); 264 } 265 snprintf(tmpbuf + total, sizeof tmpbuf - total, " %s", buf16); 266 fprintf(fp, "%s\n", tmpbuf); 267 fflush(fp); 268 } 269 270 void 271 spdk_log_dump(FILE *fp, const char *label, const void *buf, size_t len) 272 { 273 fdump(fp, label, buf, len); 274 } 275