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