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