// SPDX-License-Identifier: LGPL-2.1-or-later /* * This file is part of libnvme. * Copyright (C) 2021 SUSE LLC * * Authors: Hannes Reinecke * * This file implements basic logging functionality. */ #include #include #include #include #include #include #include #include #include #define LOG_FUNCNAME 1 #include "private.h" #include "log.h" #include "cleanup.h" #ifndef LOG_CLOCK #define LOG_CLOCK CLOCK_MONOTONIC #endif static nvme_root_t root; void __attribute__((format(printf, 4, 5))) __nvme_msg(nvme_root_t r, int lvl, const char *func, const char *format, ...) { FILE *fp = stderr; va_list ap; char pidbuf[16]; char timebuf[32]; static const char *const formats[] = { "%s%s%s", "%s%s%s: ", "%s<%s>%s ", "%s<%s> %s: ", "[%s] %s%s ", "[%s]%s %s: ", "[%s] <%s>%s ", "[%s] <%s> %s: ", }; _cleanup_free_ char *header = NULL; _cleanup_free_ char *message = NULL; int idx = 0; if (!r) r = root; if (r) fp = r->fp; if (r && lvl > r->log_level) return; if (!r && lvl > DEFAULT_LOGLEVEL) return; if (r && r->log_timestamp) { struct timespec now; clock_gettime(LOG_CLOCK, &now); snprintf(timebuf, sizeof(timebuf), "%6ld.%06ld", (long)now.tv_sec, now.tv_nsec / 1000); idx |= 1 << 2; } else *timebuf = '\0'; if (r && r->log_pid) { snprintf(pidbuf, sizeof(pidbuf), "%ld", (long)getpid()); idx |= 1 << 1; } else *pidbuf = '\0'; if (func) idx |= 1 << 0; if (asprintf(&header, formats[idx], timebuf, pidbuf, func ? func : "") == -1) header = NULL; va_start(ap, format); if (vasprintf(&message, format, ap) == -1) message = NULL; va_end(ap); fprintf(fp, "%s%s", header ? header : "", message ? message : ""); } void nvme_init_logging(nvme_root_t r, int lvl, bool log_pid, bool log_tstamp) { r->log_level = lvl; r->log_pid = log_pid; r->log_timestamp = log_tstamp; } int nvme_get_logging_level(nvme_root_t r, bool *log_pid, bool *log_tstamp) { if (!r) r = root; if (!r) return DEFAULT_LOGLEVEL; if (log_pid) *log_pid = r->log_pid; if (log_tstamp) *log_tstamp = r->log_timestamp; return r->log_level; } void nvme_set_root(nvme_root_t r) { root = r; } void nvme_set_debug(bool debug) { root->log_level = debug ? LOG_DEBUG : DEFAULT_LOGLEVEL; } bool nvme_get_debug(void) { return root->log_level == LOG_DEBUG; }