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