2017-03-30 23:54:57 +08:00
|
|
|
/*
|
2019-02-03 17:28:01 +08:00
|
|
|
* Copyright 2017-2019 Leonid Yuriev <leo@yuriev.ru>
|
2017-03-30 23:54:57 +08:00
|
|
|
* and other libmdbx authors: please see AUTHORS file.
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted only as authorized by the OpenLDAP
|
|
|
|
* Public License.
|
|
|
|
*
|
|
|
|
* A copy of this license is available in the file LICENSE in the
|
|
|
|
* top-level directory of the distribution or, alternatively, at
|
|
|
|
* <http://www.OpenLDAP.org/license.html>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "test.h"
|
|
|
|
|
2017-04-11 17:55:16 +08:00
|
|
|
static void fflushall() { fflush(nullptr); }
|
|
|
|
|
2017-03-30 23:54:57 +08:00
|
|
|
void failure(const char *fmt, ...) {
|
|
|
|
va_list ap;
|
|
|
|
va_start(ap, fmt);
|
2017-05-17 20:46:44 +08:00
|
|
|
fflushall();
|
2017-04-11 17:55:16 +08:00
|
|
|
logging::output(logging::failure, fmt, ap);
|
2017-03-30 23:54:57 +08:00
|
|
|
va_end(ap);
|
2017-04-11 17:55:16 +08:00
|
|
|
fflushall();
|
2017-03-30 23:54:57 +08:00
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *test_strerror(int errnum) {
|
|
|
|
static __thread char buf[1024];
|
|
|
|
return mdbx_strerror_r(errnum, buf, sizeof(buf));
|
|
|
|
}
|
|
|
|
|
|
|
|
void __noreturn failure_perror(const char *what, int errnum) {
|
|
|
|
failure("%s failed: %s (%d)\n", what, test_strerror(errnum), errnum);
|
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
2018-09-04 19:44:35 +08:00
|
|
|
static void mdbx_logger(int type, const char *function, int line,
|
|
|
|
const char *msg, va_list args) {
|
|
|
|
logging::loglevel level = logging::info;
|
|
|
|
if (type & MDBX_DBG_EXTRA)
|
|
|
|
level = logging::extra;
|
|
|
|
if (type & MDBX_DBG_TRACE)
|
|
|
|
level = logging::trace;
|
|
|
|
if (type & MDBX_DBG_PRINT)
|
|
|
|
level = logging::verbose;
|
|
|
|
|
|
|
|
if (!function)
|
|
|
|
function = "unknown";
|
|
|
|
if (type & MDBX_DBG_ASSERT) {
|
|
|
|
log_error("mdbx: assertion failure: %s, %d", function, line);
|
|
|
|
level = logging::failure;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (logging::output(
|
|
|
|
level,
|
|
|
|
strncmp(function, "mdbx_", 5) == 0 ? "%s: " : "mdbx: %s: ", function))
|
2018-09-14 20:13:05 +08:00
|
|
|
logging::feed_ap(msg, args);
|
2018-09-04 19:44:35 +08:00
|
|
|
if (type & MDBX_DBG_ASSERT)
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
|
2017-04-11 17:55:16 +08:00
|
|
|
namespace logging {
|
2017-03-30 23:54:57 +08:00
|
|
|
|
|
|
|
static std::string prefix;
|
2017-04-11 17:55:16 +08:00
|
|
|
static std::string suffix;
|
2017-03-30 23:54:57 +08:00
|
|
|
static loglevel level;
|
2017-04-11 17:55:16 +08:00
|
|
|
static FILE *last;
|
2017-03-30 23:54:57 +08:00
|
|
|
|
2018-09-04 19:44:35 +08:00
|
|
|
void setlevel(loglevel _level) {
|
2017-03-30 23:54:57 +08:00
|
|
|
level = (_level > error) ? failure : _level;
|
2018-09-04 19:44:35 +08:00
|
|
|
int mdbx_dbg_opts = MDBX_DBG_ASSERT | MDBX_DBG_JITTER | MDBX_DBG_DUMP;
|
|
|
|
if (level <= trace)
|
|
|
|
mdbx_dbg_opts |= MDBX_DBG_TRACE;
|
|
|
|
if (level <= verbose)
|
|
|
|
mdbx_dbg_opts |= MDBX_DBG_PRINT;
|
|
|
|
int rc = mdbx_setup_debug(mdbx_dbg_opts, mdbx_logger);
|
|
|
|
log_trace("set mdbx debug-opts: 0x%02x", rc);
|
|
|
|
}
|
|
|
|
|
|
|
|
void setup(loglevel _level, const std::string &_prefix) {
|
|
|
|
setlevel(_level);
|
2017-03-30 23:54:57 +08:00
|
|
|
prefix = _prefix;
|
|
|
|
}
|
|
|
|
|
|
|
|
void setup(const std::string &_prefix) { prefix = _prefix; }
|
|
|
|
|
2017-07-02 14:07:57 +08:00
|
|
|
const char *level2str(const loglevel alevel) {
|
|
|
|
switch (alevel) {
|
2017-03-30 23:54:57 +08:00
|
|
|
default:
|
|
|
|
return "invalid/unknown";
|
2017-04-21 23:34:43 +08:00
|
|
|
case extra:
|
|
|
|
return "extra";
|
2017-03-30 23:54:57 +08:00
|
|
|
case trace:
|
|
|
|
return "trace";
|
2017-04-21 23:34:43 +08:00
|
|
|
case verbose:
|
|
|
|
return "verbose";
|
2017-03-30 23:54:57 +08:00
|
|
|
case info:
|
|
|
|
return "info";
|
|
|
|
case notice:
|
|
|
|
return "notice";
|
|
|
|
case warning:
|
|
|
|
return "warning";
|
|
|
|
case error:
|
|
|
|
return "error";
|
|
|
|
case failure:
|
|
|
|
return "failure";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-17 20:46:44 +08:00
|
|
|
bool output(const loglevel priority, const char *format, ...) {
|
2017-04-21 23:34:43 +08:00
|
|
|
if (priority < level)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
va_list ap;
|
|
|
|
va_start(ap, format);
|
|
|
|
output(priority, format, ap);
|
|
|
|
va_end(ap);
|
|
|
|
return true;
|
2017-03-30 23:54:57 +08:00
|
|
|
}
|
|
|
|
|
2017-05-17 20:46:44 +08:00
|
|
|
bool output(const logging::loglevel priority, const char *format, va_list ap) {
|
2017-04-11 17:55:16 +08:00
|
|
|
if (last) {
|
2017-04-21 23:34:43 +08:00
|
|
|
putc('\n', last);
|
2017-04-25 20:00:36 +08:00
|
|
|
fflush(last);
|
2017-04-21 23:34:43 +08:00
|
|
|
last = nullptr;
|
|
|
|
}
|
2017-04-11 17:55:16 +08:00
|
|
|
|
2017-04-21 23:34:43 +08:00
|
|
|
if (priority < level)
|
|
|
|
return false;
|
|
|
|
|
2017-04-25 20:00:36 +08:00
|
|
|
chrono::time now = chrono::now_realtime();
|
|
|
|
struct tm tm;
|
|
|
|
#ifdef _MSC_VER
|
|
|
|
int rc = _localtime32_s(&tm, (const __time32_t *)&now.utc);
|
|
|
|
#else
|
2017-06-06 03:46:15 +08:00
|
|
|
time_t time = now.utc;
|
2017-05-24 06:42:10 +08:00
|
|
|
int rc = localtime_r(&time, &tm) ? MDBX_SUCCESS : errno;
|
2017-04-25 20:00:36 +08:00
|
|
|
#endif
|
2017-05-24 06:42:10 +08:00
|
|
|
if (rc != MDBX_SUCCESS)
|
2017-04-25 20:00:36 +08:00
|
|
|
failure_perror("localtime_r()", rc);
|
|
|
|
|
2017-04-27 21:22:57 +08:00
|
|
|
last = stdout;
|
2017-04-25 20:00:36 +08:00
|
|
|
fprintf(last,
|
|
|
|
"[ %02d%02d%02d-%02d:%02d:%02d.%06d_%05u %-10s %.4s ] %s" /* TODO */,
|
2017-04-27 21:22:57 +08:00
|
|
|
tm.tm_year - 100, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min,
|
2017-04-25 20:00:36 +08:00
|
|
|
tm.tm_sec, chrono::fractional2us(now.fractional), osal_getpid(),
|
|
|
|
prefix.c_str(), level2str(priority), suffix.c_str());
|
2017-05-17 20:46:44 +08:00
|
|
|
|
|
|
|
va_list ones;
|
2017-05-18 19:14:59 +08:00
|
|
|
memset(&ones, 0, sizeof(ones)) /* zap MSVC and other stupid compilers */;
|
2017-05-17 20:46:44 +08:00
|
|
|
if (priority >= error)
|
|
|
|
va_copy(ones, ap);
|
2017-04-21 23:34:43 +08:00
|
|
|
vfprintf(last, format, ap);
|
|
|
|
|
|
|
|
size_t len = strlen(format);
|
|
|
|
char end = len ? format[len - 1] : '\0';
|
2017-04-27 21:22:57 +08:00
|
|
|
|
2017-04-21 23:34:43 +08:00
|
|
|
switch (end) {
|
|
|
|
default:
|
|
|
|
putc('\n', last);
|
2017-07-04 18:07:08 +08:00
|
|
|
// fall through
|
2017-04-21 23:34:43 +08:00
|
|
|
case '\n':
|
2017-04-25 20:00:36 +08:00
|
|
|
fflush(last);
|
|
|
|
last = nullptr;
|
2017-07-04 18:07:08 +08:00
|
|
|
// fall through
|
2017-04-21 23:34:43 +08:00
|
|
|
case ' ':
|
|
|
|
case '_':
|
|
|
|
case ':':
|
|
|
|
case '|':
|
|
|
|
case ',':
|
|
|
|
case '\t':
|
|
|
|
case '\b':
|
|
|
|
case '\r':
|
|
|
|
case '\0':
|
|
|
|
break;
|
2017-04-11 17:55:16 +08:00
|
|
|
}
|
2017-04-27 21:22:57 +08:00
|
|
|
|
2017-05-17 20:46:44 +08:00
|
|
|
if (priority >= error) {
|
|
|
|
if (last != stderr) {
|
|
|
|
fprintf(stderr, "[ %05u %-10s %.4s ] %s", osal_getpid(), prefix.c_str(),
|
|
|
|
level2str(priority), suffix.c_str());
|
|
|
|
vfprintf(stderr, format, ones);
|
|
|
|
if (end != '\n')
|
|
|
|
putc('\n', stderr);
|
|
|
|
fflush(stderr);
|
|
|
|
}
|
|
|
|
va_end(ones);
|
2017-04-27 21:22:57 +08:00
|
|
|
}
|
|
|
|
|
2017-04-21 23:34:43 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-09-14 20:13:05 +08:00
|
|
|
bool feed_ap(const char *format, va_list ap) {
|
2017-04-21 23:34:43 +08:00
|
|
|
if (!last)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
vfprintf(last, format, ap);
|
|
|
|
size_t len = strlen(format);
|
2017-04-25 20:00:36 +08:00
|
|
|
if (len && format[len - 1] == '\n') {
|
|
|
|
fflush(last);
|
2017-04-21 23:34:43 +08:00
|
|
|
last = nullptr;
|
2017-04-25 20:00:36 +08:00
|
|
|
}
|
2017-04-21 23:34:43 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool feed(const char *format, ...) {
|
|
|
|
if (!last)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
va_list ap;
|
|
|
|
va_start(ap, format);
|
2018-09-14 20:13:05 +08:00
|
|
|
feed_ap(format, ap);
|
2017-04-21 23:34:43 +08:00
|
|
|
va_end(ap);
|
|
|
|
return true;
|
2017-04-11 17:55:16 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
local_suffix::local_suffix(const char *c_str)
|
|
|
|
: trim_pos(suffix.size()), indent(0) {
|
|
|
|
suffix.append(c_str);
|
|
|
|
}
|
|
|
|
|
|
|
|
local_suffix::local_suffix(const std::string &str)
|
|
|
|
: trim_pos(suffix.size()), indent(0) {
|
|
|
|
suffix.append(str);
|
|
|
|
}
|
|
|
|
|
|
|
|
void local_suffix::push() {
|
|
|
|
indent += 1;
|
|
|
|
suffix.push_back('\t');
|
|
|
|
}
|
|
|
|
|
|
|
|
void local_suffix::pop() {
|
|
|
|
assert(indent > 0);
|
|
|
|
if (indent > 0) {
|
|
|
|
indent -= 1;
|
|
|
|
suffix.pop_back();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
local_suffix::~local_suffix() { suffix.erase(trim_pos); }
|
|
|
|
|
2018-06-19 02:29:12 +08:00
|
|
|
} // namespace logging
|
2017-03-30 23:54:57 +08:00
|
|
|
|
2017-05-17 23:49:19 +08:00
|
|
|
void log_extra(const char *msg, ...) {
|
|
|
|
if (logging::extra >= logging::level) {
|
|
|
|
va_list ap;
|
|
|
|
va_start(ap, msg);
|
|
|
|
logging::output(logging::extra, msg, ap);
|
|
|
|
va_end(ap);
|
|
|
|
} else
|
|
|
|
logging::last = nullptr;
|
|
|
|
}
|
|
|
|
|
2017-03-30 23:54:57 +08:00
|
|
|
void log_trace(const char *msg, ...) {
|
2017-04-11 17:55:16 +08:00
|
|
|
if (logging::trace >= logging::level) {
|
2017-03-30 23:54:57 +08:00
|
|
|
va_list ap;
|
|
|
|
va_start(ap, msg);
|
2017-04-11 17:55:16 +08:00
|
|
|
logging::output(logging::trace, msg, ap);
|
2017-03-30 23:54:57 +08:00
|
|
|
va_end(ap);
|
2017-04-11 17:55:16 +08:00
|
|
|
} else
|
|
|
|
logging::last = nullptr;
|
2017-03-30 23:54:57 +08:00
|
|
|
}
|
|
|
|
|
2017-04-21 23:34:43 +08:00
|
|
|
void log_verbose(const char *msg, ...) {
|
|
|
|
if (logging::verbose >= logging::level) {
|
|
|
|
va_list ap;
|
|
|
|
va_start(ap, msg);
|
|
|
|
logging::output(logging::verbose, msg, ap);
|
|
|
|
va_end(ap);
|
|
|
|
} else
|
|
|
|
logging::last = nullptr;
|
|
|
|
}
|
|
|
|
|
2017-03-30 23:54:57 +08:00
|
|
|
void log_info(const char *msg, ...) {
|
2017-04-11 17:55:16 +08:00
|
|
|
if (logging::info >= logging::level) {
|
2017-03-30 23:54:57 +08:00
|
|
|
va_list ap;
|
|
|
|
va_start(ap, msg);
|
2017-04-11 17:55:16 +08:00
|
|
|
logging::output(logging::info, msg, ap);
|
2017-03-30 23:54:57 +08:00
|
|
|
va_end(ap);
|
2017-04-11 17:55:16 +08:00
|
|
|
} else
|
|
|
|
logging::last = nullptr;
|
2017-03-30 23:54:57 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void log_notice(const char *msg, ...) {
|
2017-04-11 17:55:16 +08:00
|
|
|
if (logging::notice >= logging::level) {
|
2017-03-30 23:54:57 +08:00
|
|
|
va_list ap;
|
|
|
|
va_start(ap, msg);
|
2017-04-11 17:55:16 +08:00
|
|
|
logging::output(logging::notice, msg, ap);
|
2017-03-30 23:54:57 +08:00
|
|
|
va_end(ap);
|
2017-04-11 17:55:16 +08:00
|
|
|
} else
|
|
|
|
logging::last = nullptr;
|
2017-03-30 23:54:57 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void log_warning(const char *msg, ...) {
|
2017-04-11 17:55:16 +08:00
|
|
|
if (logging::warning >= logging::level) {
|
2017-03-30 23:54:57 +08:00
|
|
|
va_list ap;
|
|
|
|
va_start(ap, msg);
|
2017-04-11 17:55:16 +08:00
|
|
|
logging::output(logging::warning, msg, ap);
|
2017-03-30 23:54:57 +08:00
|
|
|
va_end(ap);
|
2017-04-11 17:55:16 +08:00
|
|
|
} else
|
|
|
|
logging::last = nullptr;
|
2017-03-30 23:54:57 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void log_error(const char *msg, ...) {
|
2017-04-11 17:55:16 +08:00
|
|
|
if (logging::error >= logging::level) {
|
2017-03-30 23:54:57 +08:00
|
|
|
va_list ap;
|
|
|
|
va_start(ap, msg);
|
2017-04-11 17:55:16 +08:00
|
|
|
logging::output(logging::error, msg, ap);
|
2017-03-30 23:54:57 +08:00
|
|
|
va_end(ap);
|
2017-04-11 17:55:16 +08:00
|
|
|
} else
|
|
|
|
logging::last = nullptr;
|
2017-03-30 23:54:57 +08:00
|
|
|
}
|
|
|
|
|
2017-05-17 20:46:44 +08:00
|
|
|
void log_trouble(const char *where, const char *what, int errnum) {
|
2017-03-30 23:54:57 +08:00
|
|
|
log_error("%s: %s %s", where, what, test_strerror(errnum));
|
|
|
|
}
|
2017-05-17 20:46:44 +08:00
|
|
|
|
|
|
|
bool log_enabled(const logging::loglevel priority) {
|
|
|
|
return (priority >= logging::level);
|
|
|
|
}
|
2018-03-19 21:51:10 +08:00
|
|
|
|
|
|
|
void log_flush(void) { fflushall(); }
|