1488570ebSJim Harris /* SPDX-License-Identifier: BSD-3-Clause 2a6dbe372Spaul luse * Copyright (C) 2016 Intel Corporation. 3aaa533adSDaniel Verkamp * All rights reserved. 4aaa533adSDaniel Verkamp */ 5aaa533adSDaniel Verkamp 6b961d9ccSBen Walker #include "spdk/stdinc.h" 7*0ce363beSVasilii Ivanov #include "spdk/util.h" 8aaa533adSDaniel Verkamp 94e8e97c8STomasz Zawadzki #include "spdk/log.h" 10aaa533adSDaniel Verkamp 11cca697b0SBen Walker static const char *const spdk_level_names[] = { 12cca697b0SBen Walker [SPDK_LOG_ERROR] = "ERROR", 13cca697b0SBen Walker [SPDK_LOG_WARN] = "WARNING", 14cca697b0SBen Walker [SPDK_LOG_NOTICE] = "NOTICE", 15cca697b0SBen Walker [SPDK_LOG_INFO] = "INFO", 16cca697b0SBen Walker [SPDK_LOG_DEBUG] = "DEBUG", 17cca697b0SBen Walker }; 18cca697b0SBen Walker 1985c146efSEd Rodriguez #define MAX_TMPBUF 1024 2085c146efSEd Rodriguez 21*0ce363beSVasilii Ivanov static struct spdk_log_opts g_log_opts = { 22*0ce363beSVasilii Ivanov .log = NULL, 23*0ce363beSVasilii Ivanov .open = NULL, 24*0ce363beSVasilii Ivanov .close = NULL, 25*0ce363beSVasilii Ivanov .user_ctx = NULL, 26*0ce363beSVasilii Ivanov }; 27d267d0e8SVitaliy Mysak static bool g_log_timestamps = true; 2846523f33Spaul luse 298e9bf181Swanghailiangx enum spdk_log_level g_spdk_log_level; 308e9bf181Swanghailiangx enum spdk_log_level g_spdk_log_print_level; 318e9bf181Swanghailiangx 328e9bf181Swanghailiangx void 338e9bf181Swanghailiangx spdk_log_set_level(enum spdk_log_level level) 348e9bf181Swanghailiangx { 358e9bf181Swanghailiangx assert(level >= SPDK_LOG_DISABLED); 368e9bf181Swanghailiangx assert(level <= SPDK_LOG_DEBUG); 378e9bf181Swanghailiangx g_spdk_log_level = level; 388e9bf181Swanghailiangx } 398e9bf181Swanghailiangx 408e9bf181Swanghailiangx enum spdk_log_level 418e9bf181Swanghailiangx spdk_log_get_level(void) { 428e9bf181Swanghailiangx return g_spdk_log_level; 438e9bf181Swanghailiangx } 448e9bf181Swanghailiangx 458e9bf181Swanghailiangx void 468e9bf181Swanghailiangx spdk_log_set_print_level(enum spdk_log_level level) 478e9bf181Swanghailiangx { 488e9bf181Swanghailiangx assert(level >= SPDK_LOG_DISABLED); 498e9bf181Swanghailiangx assert(level <= SPDK_LOG_DEBUG); 508e9bf181Swanghailiangx g_spdk_log_print_level = level; 518e9bf181Swanghailiangx } 528e9bf181Swanghailiangx 538e9bf181Swanghailiangx enum spdk_log_level 548e9bf181Swanghailiangx spdk_log_get_print_level(void) { 558e9bf181Swanghailiangx return g_spdk_log_print_level; 568e9bf181Swanghailiangx } 577b5d9b06STomasz Zawadzki 58*0ce363beSVasilii Ivanov static void 59*0ce363beSVasilii Ivanov log_open(void *ctx) 60235a8e37SBen Walker { 61ad474e95SBen Walker openlog("spdk", LOG_PID, LOG_LOCAL7); 62235a8e37SBen Walker } 63*0ce363beSVasilii Ivanov 64*0ce363beSVasilii Ivanov static void 65*0ce363beSVasilii Ivanov log_close(void *ctx) 66*0ce363beSVasilii Ivanov { 67*0ce363beSVasilii Ivanov closelog(); 68*0ce363beSVasilii Ivanov } 69*0ce363beSVasilii Ivanov 70*0ce363beSVasilii Ivanov void 71*0ce363beSVasilii Ivanov spdk_log_open(spdk_log_cb *log) 72*0ce363beSVasilii Ivanov { 73*0ce363beSVasilii Ivanov if (log) { 74*0ce363beSVasilii Ivanov struct spdk_log_opts opts = {.log = log}; 75*0ce363beSVasilii Ivanov opts.size = SPDK_SIZEOF(&opts, log); 76*0ce363beSVasilii Ivanov spdk_log_open_ext(&opts); 77*0ce363beSVasilii Ivanov } else { 78*0ce363beSVasilii Ivanov spdk_log_open_ext(NULL); 79*0ce363beSVasilii Ivanov } 80*0ce363beSVasilii Ivanov } 81*0ce363beSVasilii Ivanov 82*0ce363beSVasilii Ivanov void 83*0ce363beSVasilii Ivanov spdk_log_open_ext(struct spdk_log_opts *opts) 84*0ce363beSVasilii Ivanov { 85*0ce363beSVasilii Ivanov if (!opts) { 86*0ce363beSVasilii Ivanov g_log_opts.open = log_open; 87*0ce363beSVasilii Ivanov g_log_opts.close = log_close; 88*0ce363beSVasilii Ivanov goto out; 89*0ce363beSVasilii Ivanov } 90*0ce363beSVasilii Ivanov 91*0ce363beSVasilii Ivanov g_log_opts.log = SPDK_GET_FIELD(opts, log, NULL); 92*0ce363beSVasilii Ivanov g_log_opts.open = SPDK_GET_FIELD(opts, open, NULL); 93*0ce363beSVasilii Ivanov g_log_opts.close = SPDK_GET_FIELD(opts, close, NULL); 94*0ce363beSVasilii Ivanov g_log_opts.user_ctx = SPDK_GET_FIELD(opts, user_ctx, NULL); 95*0ce363beSVasilii Ivanov 96*0ce363beSVasilii Ivanov out: 97*0ce363beSVasilii Ivanov if (g_log_opts.open) { 98*0ce363beSVasilii Ivanov g_log_opts.open(g_log_opts.user_ctx); 99*0ce363beSVasilii Ivanov } 10046523f33Spaul luse } 101235a8e37SBen Walker 102235a8e37SBen Walker void 103235a8e37SBen Walker spdk_log_close(void) 104235a8e37SBen Walker { 105*0ce363beSVasilii Ivanov if (g_log_opts.close) { 106*0ce363beSVasilii Ivanov g_log_opts.close(g_log_opts.user_ctx); 107235a8e37SBen Walker } 108*0ce363beSVasilii Ivanov memset(&g_log_opts, 0, sizeof(g_log_opts)); 10946523f33Spaul luse } 110235a8e37SBen Walker 111d267d0e8SVitaliy Mysak void 112d267d0e8SVitaliy Mysak spdk_log_enable_timestamps(bool value) 113d267d0e8SVitaliy Mysak { 114d267d0e8SVitaliy Mysak g_log_timestamps = value; 115d267d0e8SVitaliy Mysak } 116d267d0e8SVitaliy Mysak 117419cd369SVitaliy Mysak static void 118419cd369SVitaliy Mysak get_timestamp_prefix(char *buf, int buf_size) 119419cd369SVitaliy Mysak { 120419cd369SVitaliy Mysak struct tm *info; 121419cd369SVitaliy Mysak char date[24]; 122419cd369SVitaliy Mysak struct timespec ts; 123419cd369SVitaliy Mysak long usec; 124419cd369SVitaliy Mysak 125d267d0e8SVitaliy Mysak if (!g_log_timestamps) { 126d267d0e8SVitaliy Mysak buf[0] = '\0'; 127d267d0e8SVitaliy Mysak return; 128d267d0e8SVitaliy Mysak } 129d267d0e8SVitaliy Mysak 130419cd369SVitaliy Mysak clock_gettime(CLOCK_REALTIME, &ts); 131419cd369SVitaliy Mysak info = localtime(&ts.tv_sec); 132419cd369SVitaliy Mysak usec = ts.tv_nsec / 1000; 1338e65bfc7SSeth Howell if (info == NULL) { 1348e65bfc7SSeth Howell snprintf(buf, buf_size, "[%s.%06ld] ", "unknown date", usec); 1358e65bfc7SSeth Howell return; 1368e65bfc7SSeth Howell } 137419cd369SVitaliy Mysak 138419cd369SVitaliy Mysak strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", info); 139419cd369SVitaliy Mysak snprintf(buf, buf_size, "[%s.%06ld] ", date, usec); 140419cd369SVitaliy Mysak } 141419cd369SVitaliy Mysak 142235a8e37SBen Walker void 143cca697b0SBen Walker spdk_log(enum spdk_log_level level, const char *file, const int line, const char *func, 144aaa533adSDaniel Verkamp const char *format, ...) 145aaa533adSDaniel Verkamp { 146cbe9ea52SVitaliy Mysak va_list ap; 147cbe9ea52SVitaliy Mysak 148cbe9ea52SVitaliy Mysak va_start(ap, format); 149cbe9ea52SVitaliy Mysak spdk_vlog(level, file, line, func, format, ap); 150cbe9ea52SVitaliy Mysak va_end(ap); 151cbe9ea52SVitaliy Mysak } 152cbe9ea52SVitaliy Mysak 15301936d2eSChangpeng Liu int 15401936d2eSChangpeng Liu spdk_log_to_syslog_level(enum spdk_log_level level) 15501936d2eSChangpeng Liu { 15601936d2eSChangpeng Liu switch (level) { 15701936d2eSChangpeng Liu case SPDK_LOG_DEBUG: 15801936d2eSChangpeng Liu case SPDK_LOG_INFO: 15901936d2eSChangpeng Liu return LOG_INFO; 16001936d2eSChangpeng Liu case SPDK_LOG_NOTICE: 16101936d2eSChangpeng Liu return LOG_NOTICE; 16201936d2eSChangpeng Liu case SPDK_LOG_WARN: 16301936d2eSChangpeng Liu return LOG_WARNING; 16401936d2eSChangpeng Liu case SPDK_LOG_ERROR: 16501936d2eSChangpeng Liu return LOG_ERR; 16601936d2eSChangpeng Liu case SPDK_LOG_DISABLED: 16701936d2eSChangpeng Liu return -1; 16801936d2eSChangpeng Liu default: 16901936d2eSChangpeng Liu break; 17001936d2eSChangpeng Liu } 17101936d2eSChangpeng Liu 17201936d2eSChangpeng Liu return LOG_INFO; 17301936d2eSChangpeng Liu } 17401936d2eSChangpeng Liu 175cbe9ea52SVitaliy Mysak void 176cbe9ea52SVitaliy Mysak spdk_vlog(enum spdk_log_level level, const char *file, const int line, const char *func, 177cbe9ea52SVitaliy Mysak const char *format, va_list ap) 178cbe9ea52SVitaliy Mysak { 179cca697b0SBen Walker int severity = LOG_INFO; 180f387b7feSShuhei Matsumoto char *buf, _buf[MAX_TMPBUF], *ext_buf = NULL; 181a2606d4bSMaciej Szwed char timestamp[64]; 182a93a149cSJim Harris va_list ap_copy; 183f387b7feSShuhei Matsumoto int rc; 184aaa533adSDaniel Verkamp 185*0ce363beSVasilii Ivanov if (g_log_opts.log) { 186*0ce363beSVasilii Ivanov g_log_opts.log(level, file, line, func, format, ap); 187a50246fbSx00267701 return; 188a50246fbSx00267701 } 189a50246fbSx00267701 190a50246fbSx00267701 if (level > g_spdk_log_print_level && level > g_spdk_log_level) { 191a50246fbSx00267701 return; 192a50246fbSx00267701 } 193a50246fbSx00267701 19401936d2eSChangpeng Liu severity = spdk_log_to_syslog_level(level); 19501936d2eSChangpeng Liu if (severity < 0) { 196ae2b2f64SPawel Wodkowski return; 197aaa533adSDaniel Verkamp } 198aaa533adSDaniel Verkamp 199f387b7feSShuhei Matsumoto buf = _buf; 200f387b7feSShuhei Matsumoto 201a93a149cSJim Harris va_copy(ap_copy, ap); 202f387b7feSShuhei Matsumoto rc = vsnprintf(_buf, sizeof(_buf), format, ap); 203f387b7feSShuhei Matsumoto if (rc > MAX_TMPBUF) { 204f387b7feSShuhei Matsumoto /* The output including the terminating was more than MAX_TMPBUF bytes. 205f387b7feSShuhei Matsumoto * Try allocating memory large enough to hold the output. 206f387b7feSShuhei Matsumoto */ 207a93a149cSJim Harris rc = vasprintf(&ext_buf, format, ap_copy); 208f387b7feSShuhei Matsumoto if (rc < 0) { 209f387b7feSShuhei Matsumoto /* Failed to allocate memory. Allow output to be truncated. */ 210f387b7feSShuhei Matsumoto } else { 211f387b7feSShuhei Matsumoto buf = ext_buf; 212f387b7feSShuhei Matsumoto } 213f387b7feSShuhei Matsumoto } 214d5e293deSMarcin Spiewak va_end(ap_copy); 215cca697b0SBen Walker 21665918cb8SBen Walker if (level <= g_spdk_log_print_level) { 217419cd369SVitaliy Mysak get_timestamp_prefix(timestamp, sizeof(timestamp)); 218caa9d4c8SVitaliy Mysak if (file) { 219419cd369SVitaliy Mysak fprintf(stderr, "%s%s:%4d:%s: *%s*: %s", timestamp, file, line, func, spdk_level_names[level], buf); 220caa9d4c8SVitaliy Mysak } else { 221419cd369SVitaliy Mysak fprintf(stderr, "%s%s", timestamp, buf); 222caa9d4c8SVitaliy Mysak } 223aaa533adSDaniel Verkamp } 22465918cb8SBen Walker 22565918cb8SBen Walker if (level <= g_spdk_log_level) { 226caa9d4c8SVitaliy Mysak if (file) { 22765918cb8SBen Walker syslog(severity, "%s:%4d:%s: *%s*: %s", file, line, func, spdk_level_names[level], buf); 228caa9d4c8SVitaliy Mysak } else { 229caa9d4c8SVitaliy Mysak syslog(severity, "%s", buf); 230caa9d4c8SVitaliy Mysak } 231aaa533adSDaniel Verkamp } 232f387b7feSShuhei Matsumoto 233f387b7feSShuhei Matsumoto free(ext_buf); 234aaa533adSDaniel Verkamp } 235aaa533adSDaniel Verkamp 2364f651a5cSShuhei Matsumoto void 2374f651a5cSShuhei Matsumoto spdk_vflog(FILE *fp, const char *file, const int line, const char *func, 2384f651a5cSShuhei Matsumoto const char *format, va_list ap) 2394f651a5cSShuhei Matsumoto { 2404f651a5cSShuhei Matsumoto char buf[MAX_TMPBUF]; 2414f651a5cSShuhei Matsumoto char timestamp[64]; 2424f651a5cSShuhei Matsumoto 2434f651a5cSShuhei Matsumoto vsnprintf(buf, sizeof(buf), format, ap); 2444f651a5cSShuhei Matsumoto 2454f651a5cSShuhei Matsumoto get_timestamp_prefix(timestamp, sizeof(timestamp)); 2464f651a5cSShuhei Matsumoto 2474f651a5cSShuhei Matsumoto if (file) { 2484f651a5cSShuhei Matsumoto fprintf(fp, "%s%s:%4d:%s: %s", timestamp, file, line, func, buf); 2494f651a5cSShuhei Matsumoto } else { 2504f651a5cSShuhei Matsumoto fprintf(fp, "%s%s", timestamp, buf); 2514f651a5cSShuhei Matsumoto } 2524f651a5cSShuhei Matsumoto 2534f651a5cSShuhei Matsumoto fflush(fp); 2544f651a5cSShuhei Matsumoto } 2554f651a5cSShuhei Matsumoto 2564f651a5cSShuhei Matsumoto void 2574f651a5cSShuhei Matsumoto spdk_flog(FILE *fp, const char *file, const int line, const char *func, 2584f651a5cSShuhei Matsumoto const char *format, ...) 2594f651a5cSShuhei Matsumoto { 2604f651a5cSShuhei Matsumoto va_list ap; 2614f651a5cSShuhei Matsumoto 2624f651a5cSShuhei Matsumoto va_start(ap, format); 2634f651a5cSShuhei Matsumoto spdk_vflog(fp, file, line, func, format, ap); 2644f651a5cSShuhei Matsumoto va_end(ap); 2654f651a5cSShuhei Matsumoto } 2664f651a5cSShuhei Matsumoto 267aaa533adSDaniel Verkamp static void 268aaa533adSDaniel Verkamp fdump(FILE *fp, const char *label, const uint8_t *buf, size_t len) 269aaa533adSDaniel Verkamp { 270aaa533adSDaniel Verkamp char tmpbuf[MAX_TMPBUF]; 27125749728SKrzysztof Jakimiak char buf16[16 + 1]; 272aaa533adSDaniel Verkamp size_t total; 27325749728SKrzysztof Jakimiak unsigned int idx; 274aaa533adSDaniel Verkamp 275aaa533adSDaniel Verkamp fprintf(fp, "%s\n", label); 276aaa533adSDaniel Verkamp 27725749728SKrzysztof Jakimiak memset(buf16, 0, sizeof buf16); 278aaa533adSDaniel Verkamp total = 0; 279aaa533adSDaniel Verkamp for (idx = 0; idx < len; idx++) { 28025749728SKrzysztof Jakimiak if (idx != 0 && idx % 16 == 0) { 281aaa533adSDaniel Verkamp snprintf(tmpbuf + total, sizeof tmpbuf - total, 28225749728SKrzysztof Jakimiak " %s", buf16); 283a2dbaf7eSRichael Zhuang memset(buf16, 0, sizeof buf16); 284aaa533adSDaniel Verkamp fprintf(fp, "%s\n", tmpbuf); 285aaa533adSDaniel Verkamp total = 0; 286aaa533adSDaniel Verkamp } 28725749728SKrzysztof Jakimiak if (idx % 16 == 0) { 28825749728SKrzysztof Jakimiak total += snprintf(tmpbuf + total, sizeof tmpbuf - total, 28925749728SKrzysztof Jakimiak "%08x ", idx); 29025749728SKrzysztof Jakimiak } 29125749728SKrzysztof Jakimiak if (idx % 8 == 0) { 29225749728SKrzysztof Jakimiak total += snprintf(tmpbuf + total, sizeof tmpbuf - total, 29325749728SKrzysztof Jakimiak "%s", " "); 29425749728SKrzysztof Jakimiak } 295aaa533adSDaniel Verkamp total += snprintf(tmpbuf + total, sizeof tmpbuf - total, 296aaa533adSDaniel Verkamp "%2.2x ", buf[idx] & 0xff); 29725749728SKrzysztof Jakimiak buf16[idx % 16] = isprint(buf[idx]) ? buf[idx] : '.'; 298aaa533adSDaniel Verkamp } 29925749728SKrzysztof Jakimiak for (; idx % 16 != 0; idx++) { 3001db6c18eSDarek Stojaczyk if (idx == 8) { 3011db6c18eSDarek Stojaczyk total += snprintf(tmpbuf + total, sizeof tmpbuf - total, 3021db6c18eSDarek Stojaczyk " "); 3031db6c18eSDarek Stojaczyk } 3041db6c18eSDarek Stojaczyk 305aaa533adSDaniel Verkamp total += snprintf(tmpbuf + total, sizeof tmpbuf - total, " "); 306aaa533adSDaniel Verkamp } 30725749728SKrzysztof Jakimiak snprintf(tmpbuf + total, sizeof tmpbuf - total, " %s", buf16); 308aaa533adSDaniel Verkamp fprintf(fp, "%s\n", tmpbuf); 309aaa533adSDaniel Verkamp fflush(fp); 310aaa533adSDaniel Verkamp } 311aaa533adSDaniel Verkamp 312aaa533adSDaniel Verkamp void 313b4b7d5d3SJim Harris spdk_log_dump(FILE *fp, const char *label, const void *buf, size_t len) 314aaa533adSDaniel Verkamp { 3159b99f2c0SPaul Luse fdump(fp, label, buf, len); 316aaa533adSDaniel Verkamp } 317