test: refine logging.

This commit is contained in:
Leo Yuriev 2017-04-11 12:55:16 +03:00
parent 270b367a4f
commit 2a80ad67fb
7 changed files with 187 additions and 95 deletions

View File

@ -231,94 +231,98 @@ const struct option_verb table_bits[] = {
{"data.dups", MDB_DUPSORT}, {"data.dups", MDB_DUPSORT},
{nullptr, 0}}; {nullptr, 0}};
static void dump_verbs(FILE *out, const char *caption, size_t bits, static void dump_verbs(const char *caption, size_t bits,
const struct option_verb *verbs) { const struct option_verb *verbs) {
fprintf(out, "%s: (%" PRIu64 ")", caption, (uint64_t)bits); log_info("%s: 0x%" PRIx64 " = ", caption, (uint64_t)bits);
const char *comma = "";
while (verbs->mask && bits) { while (verbs->mask && bits) {
if ((bits & verbs->mask) == verbs->mask) { if ((bits & verbs->mask) == verbs->mask) {
fprintf(out, ", %s", verbs->verb); logging::feed("%s%s", comma, verbs->verb);
bits -= verbs->mask; bits -= verbs->mask;
comma = ", ";
} }
++verbs; ++verbs;
} }
fprintf(out, "\n"); logging::feed("\n");
} }
static void dump_duration(FILE *out, const char *caption, unsigned duration) { static void dump_duration(const char *caption, unsigned duration) {
fprintf(out, "%s: ", caption); log_info("%s: ", caption);
if (duration) { if (duration) {
if (duration > 24 * 3600) if (duration > 24 * 3600)
fprintf(out, "%u_", duration / (24 * 3600)); logging::feed("%u_", duration / (24 * 3600));
if (duration > 3600) if (duration > 3600)
fprintf(out, "%02u:", (duration % (24 * 3600)) / 3600); logging::feed("%02u:", (duration % (24 * 3600)) / 3600);
fprintf(out, "%02u:%02u", (duration % 3600) / 60, duration % 60); logging::feed("%02u:%02u", (duration % 3600) / 60, duration % 60);
} else } else {
fprintf(out, "INFINITE"); logging::feed("INFINITE");
fprintf(out, "\n"); }
logging::feed("\n");
} }
void dump(FILE *out) { void dump(const char *title) {
logging::local_suffix indent(title);
for (auto i = global::actors.begin(); i != global::actors.end(); ++i) { for (auto i = global::actors.begin(); i != global::actors.end(); ++i) {
fprintf(out, "testcase %s\n", testcase2str(i->testcase)); log_info("#%u, testcase %s, id/table %u\n", i->order,
if (i->id) testcase2str(i->testcase), i->id);
fprintf(out, "\tid/table %u\n", i->id); indent.push();
if (i->params.loglevel) { if (i->params.loglevel) {
fprintf(out, "\tlog: level %u, %s\n", i->params.loglevel, log_info("log: level %u, %s\n", i->params.loglevel,
i->params.pathname_log.empty() ? "console" i->params.pathname_log.empty() ? "console"
: i->params.pathname_log.c_str()); : i->params.pathname_log.c_str());
} }
fprintf(out, "\tdatabase: %s, size %" PRIu64 "\n", log_info("database: %s, size %" PRIu64 "\n", i->params.pathname_db.c_str(),
i->params.pathname_db.c_str(), i->params.size); i->params.size);
dump_verbs(out, "\tmode", i->params.mode_flags, mode_bits); dump_verbs("mode", i->params.mode_flags, mode_bits);
dump_verbs(out, "\ttable", i->params.table_flags, table_bits); dump_verbs("table", i->params.table_flags, table_bits);
fprintf(out, "\tseed %u\n", i->params.seed); log_info("seed %u\n", i->params.seed);
if (i->params.test_nrecords) if (i->params.test_nrecords)
fprintf(out, "\trecords %u\n", i->params.test_nrecords); log_info("records %u\n", i->params.test_nrecords);
else else
dump_duration(out, "\tduration", i->params.test_duration); dump_duration("duration", i->params.test_duration);
if (i->params.nrepeat) if (i->params.nrepeat)
fprintf(out, "\trepeat %u\n", i->params.nrepeat); log_info("repeat %u\n", i->params.nrepeat);
else else
fprintf(out, "\trepeat ETERNALLY\n"); log_info("repeat ETERNALLY\n");
fprintf(out, "\tthreads %u\n", i->params.nthreads); log_info("threads %u\n", i->params.nthreads);
fprintf(out, "\tkey: minlen %u, maxlen %u\n", i->params.keylen_min, log_info("key: minlen %u, maxlen %u\n", i->params.keylen_min,
i->params.keylen_max); i->params.keylen_max);
fprintf(out, "\tdata: minlen %u, maxlen %u\n", i->params.datalen_min, log_info("data: minlen %u, maxlen %u\n", i->params.datalen_min,
i->params.datalen_max); i->params.datalen_max);
fprintf(out, "\tbatch: read %u, write %u\n", i->params.batch_read, log_info("batch: read %u, write %u\n", i->params.batch_read,
i->params.batch_write); i->params.batch_write);
if (i->params.waitfor_nops) if (i->params.waitfor_nops)
fprintf(out, "\twait: actor %u for %u ops\n", i->wait4id, log_info("wait: actor %u for %u ops\n", i->wait4id,
i->params.waitfor_nops); i->params.waitfor_nops);
else if (i->params.delaystart) else if (i->params.delaystart)
dump_duration(out, "\tdelay", i->params.delaystart); dump_duration("delay", i->params.delaystart);
else else
fprintf(out, "\tno-delay\n"); log_info("no-delay\n");
fprintf(out, "\tlimits: readers %u, tables %u\n", i->params.max_readers, log_info("limits: readers %u, tables %u\n", i->params.max_readers,
i->params.max_tables); i->params.max_tables);
fprintf(out, "\tdrop table: %s\n", i->params.drop_table ? "Yes" : "No"); log_info("drop table: %s\n", i->params.drop_table ? "Yes" : "No");
indent.pop();
fprintf(out, "\t#---\n");
} }
dump_duration(out, "timeout", global::config::timeout); dump_duration("timeout", global::config::timeout);
fprintf(out, "cleanup: before %s, after %s\n", log_info("cleanup: before %s, after %s\n",
global::config::dont_cleanup_before ? "No" : "Yes", global::config::dont_cleanup_before ? "No" : "Yes",
global::config::dont_cleanup_after ? "No" : "Yes"); global::config::dont_cleanup_after ? "No" : "Yes");
} }
} /* namespace config */ } /* namespace config */

View File

@ -108,7 +108,7 @@ struct actor_config_pod {
extern const struct option_verb mode_bits[]; extern const struct option_verb mode_bits[];
extern const struct option_verb table_bits[]; extern const struct option_verb table_bits[];
void dump(FILE *out); void dump(const char *title = "config-dump: ");
} /* namespace config */ } /* namespace config */

View File

@ -14,13 +14,15 @@
#include "test.h" #include "test.h"
static void fflushall() { fflush(nullptr); }
void failure(const char *fmt, ...) { void failure(const char *fmt, ...) {
va_list ap; va_list ap;
fflush(NULL); fflush(NULL);
va_start(ap, fmt); va_start(ap, fmt);
loggging::output(loggging::failure, fmt, ap); logging::output(logging::failure, fmt, ap);
va_end(ap); va_end(ap);
fflush(NULL); fflushall();
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@ -35,10 +37,12 @@ void __noreturn failure_perror(const char *what, int errnum) {
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
namespace loggging { namespace logging {
static std::string prefix; static std::string prefix;
static std::string suffix;
static loglevel level; static loglevel level;
static FILE *last;
void setup(loglevel _level, const std::string &_prefix) { void setup(loglevel _level, const std::string &_prefix) {
level = (_level > error) ? failure : _level; level = (_level > error) ? failure : _level;
@ -68,61 +72,123 @@ const char *level2str(const loglevel level) {
void output(loglevel priority, const char *format, va_list ap) { void output(loglevel priority, const char *format, va_list ap) {
if (priority >= level) { if (priority >= level) {
FILE *out = (priority >= error) ? stderr : stdout; last = (priority >= error) ? stderr : stdout;
fprintf(out, "[ %u %-10s %6s ] " /* TODO */, osal_getpid(), prefix.c_str(), fprintf(last, "[ %u %-10s %6s ] %s" /* TODO */, osal_getpid(),
level2str(priority)); prefix.c_str(), level2str(priority), suffix.c_str());
vfprintf(out, format, ap); vfprintf(last, format, ap);
size_t len = strlen(format); size_t len = strlen(format);
if (len && format[len - 1] != '\n') char end = len ? format[len - 1] : '\0';
putc('\n', out); switch (end) {
default:
putc('\n', last);
case '\n':
if (priority > info)
fflushall();
break;
case ' ':
case '_':
case ':':
case '|':
case ',':
case '\t':
case '\b':
case '\r':
case '\0':
return;
}
}
last = nullptr;
}
void feed(const char *format, ...) {
if (last) {
va_list ap;
va_start(ap, format);
vfprintf(last, format, ap);
va_end(ap);
size_t len = strlen(format);
if (len && format[len - 1] == '\n')
last = nullptr;
} }
} }
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); }
} /* namespace log */ } /* namespace log */
void log_trace(const char *msg, ...) { void log_trace(const char *msg, ...) {
if (loggging::trace >= loggging::level) { if (logging::trace >= logging::level) {
va_list ap; va_list ap;
va_start(ap, msg); va_start(ap, msg);
loggging::output(loggging::trace, msg, ap); logging::output(logging::trace, msg, ap);
va_end(ap); va_end(ap);
} } else
logging::last = nullptr;
} }
void log_info(const char *msg, ...) { void log_info(const char *msg, ...) {
if (loggging::info >= loggging::level) { if (logging::info >= logging::level) {
va_list ap; va_list ap;
va_start(ap, msg); va_start(ap, msg);
loggging::output(loggging::info, msg, ap); logging::output(logging::info, msg, ap);
va_end(ap); va_end(ap);
} } else
logging::last = nullptr;
} }
void log_notice(const char *msg, ...) { void log_notice(const char *msg, ...) {
if (loggging::notice >= loggging::level) { if (logging::notice >= logging::level) {
va_list ap; va_list ap;
va_start(ap, msg); va_start(ap, msg);
loggging::output(loggging::notice, msg, ap); logging::output(logging::notice, msg, ap);
va_end(ap); va_end(ap);
} } else
logging::last = nullptr;
} }
void log_warning(const char *msg, ...) { void log_warning(const char *msg, ...) {
if (loggging::warning >= loggging::level) { if (logging::warning >= logging::level) {
va_list ap; va_list ap;
va_start(ap, msg); va_start(ap, msg);
loggging::output(loggging::warning, msg, ap); logging::output(logging::warning, msg, ap);
va_end(ap); va_end(ap);
} } else
logging::last = nullptr;
} }
void log_error(const char *msg, ...) { void log_error(const char *msg, ...) {
if (loggging::error >= loggging::level) { if (logging::error >= logging::level) {
va_list ap; va_list ap;
va_start(ap, msg); va_start(ap, msg);
loggging::output(loggging::error, msg, ap); logging::output(logging::error, msg, ap);
va_end(ap); va_end(ap);
} } else
logging::last = nullptr;
} }
void log_touble(const char *where, const char *what, int errnum) { void log_touble(const char *where, const char *what, int errnum) {

View File

@ -18,16 +18,19 @@
void __noreturn usage(void); void __noreturn usage(void);
void __noreturn
#ifdef __GNUC__ #ifdef __GNUC__
__attribute__((format(printf, 1, 2))) #define __printf_args(format_index, first_arg) \
__attribute__((format(printf, format_index, first_arg)))
#else
#define __printf_args(format_index, first_arg)
#endif #endif
failure(const char *fmt, ...);
void __noreturn __printf_args(1, 2) failure(const char *fmt, ...);
void __noreturn failure_perror(const char *what, int errnum); void __noreturn failure_perror(const char *what, int errnum);
const char *test_strerror(int errnum); const char *test_strerror(int errnum);
namespace loggging { namespace logging {
enum loglevel { enum loglevel {
trace, trace,
@ -43,14 +46,32 @@ void setup(loglevel level, const std::string &prefix);
void setup(const std::string &prefix); void setup(const std::string &prefix);
void output(loglevel priority, const char *format, va_list ap); void output(loglevel priority, const char *format, va_list ap);
void __printf_args(1, 2) feed(const char *format, ...);
class local_suffix {
protected:
size_t trim_pos;
int indent;
public:
local_suffix(const local_suffix &) = delete;
local_suffix(const local_suffix &&) = delete;
const local_suffix &operator=(const local_suffix &) = delete;
local_suffix(const char *c_str);
local_suffix(const std::string &str);
void push();
void pop();
~local_suffix();
};
} /* namespace log */ } /* namespace log */
void log_trace(const char *msg, ...); void __printf_args(1, 2) log_trace(const char *msg, ...);
void log_info(const char *msg, ...); void __printf_args(1, 2) log_info(const char *msg, ...);
void log_notice(const char *msg, ...); void __printf_args(1, 2) log_notice(const char *msg, ...);
void log_warning(const char *msg, ...); void __printf_args(1, 2) log_warning(const char *msg, ...);
void log_error(const char *msg, ...); void __printf_args(1, 2) log_error(const char *msg, ...);
void log_touble(const char *where, const char *what, int errnum); void log_touble(const char *where, const char *what, int errnum);

View File

@ -26,9 +26,9 @@ void actor_params::set_defaults(void) {
pathname_log = ""; pathname_log = "";
loglevel = loglevel =
#ifdef NDEBUG #ifdef NDEBUG
loggging::notice; logging::notice;
#else #else
loggging::trace; logging::trace;
#endif #endif
pathname_db = pathname_db =
@ -118,7 +118,7 @@ int main(int argc, char *const argv[]) {
actor_params params; actor_params params;
params.set_defaults(); params.set_defaults();
global::config::dump_config = true; global::config::dump_config = true;
loggging::setup((loggging::loglevel)params.loglevel, "main"); logging::setup((logging::loglevel)params.loglevel, "main");
unsigned lastid = 0; unsigned lastid = 0;
if (argc == 2 && strncmp(argv[1], "--case=", 7) == 0) { if (argc == 2 && strncmp(argv[1], "--case=", 7) == 0) {
@ -228,11 +228,11 @@ int main(int argc, char *const argv[]) {
} }
if (global::config::dump_config) if (global::config::dump_config)
config::dump(stdout); config::dump();
bool failed = false; bool failed = false;
if (global::actors.size()) { if (global::actors.size()) {
loggging::setup("overlord"); logging::setup("overlord");
if (!global::config::dont_cleanup_before) if (!global::config::dont_cleanup_before)
cleanup(); cleanup();

View File

@ -53,13 +53,13 @@ const char *status2str(actor_status status) {
static void mdbx_debug_logger(int type, const char *function, int line, static void mdbx_debug_logger(int type, const char *function, int line,
const char *msg, va_list args) { const char *msg, va_list args) {
loggging::loglevel level = loggging::trace; logging::loglevel level = logging::trace;
if (type & MDBX_DBG_PRINT) if (type & MDBX_DBG_PRINT)
level = loggging::info; level = logging::info;
if (type & MDBX_DBG_ASSERT) { if (type & MDBX_DBG_ASSERT) {
log_error("libmdbx assertion failure: %s, %d", log_error("libmdbx assertion failure: %s, %d",
function ? function : "unknown", line); function ? function : "unknown", line);
level = loggging::failure; level = logging::failure;
} }
output(level, msg, args); output(level, msg, args);
@ -122,7 +122,8 @@ bool testcase::wait4start() {
log_trace(">> wait4start(%u)", config.wait4id); log_trace(">> wait4start(%u)", config.wait4id);
int rc = osal_waitfor(config.wait4id); int rc = osal_waitfor(config.wait4id);
if (rc) { if (rc) {
log_trace("<< wait4start(%u), failed %s", test_strerror(rc)); log_trace("<< wait4start(%u), failed %s", config.wait4id,
test_strerror(rc));
return false; return false;
} }
return true; return true;
@ -167,8 +168,8 @@ bool testcase::teardown() {
bool test_execute(const actor_config &config) { bool test_execute(const actor_config &config) {
const mdbx_pid_t pid = osal_getpid(); const mdbx_pid_t pid = osal_getpid();
loggging::setup((loggging::loglevel)config.params.loglevel, logging::setup((logging::loglevel)config.params.loglevel,
format("child_%u.%u", config.order, config.id)); format("child_%u.%u", config.order, config.id));
log_trace(">> wait4barrier"); log_trace(">> wait4barrier");
osal_wait4barrier(); osal_wait4barrier();

View File

@ -90,8 +90,8 @@ protected:
public: public:
testcase(const actor_config &config, const mdbx_pid_t pid) testcase(const actor_config &config, const mdbx_pid_t pid)
: config(config), pid(pid) { : config(config), pid(pid) {
loggging::setup(format("%s_%u.%u", testcase2str(config.testcase), logging::setup(format("%s_%u.%u", testcase2str(config.testcase),
config.order, config.id)); config.order, config.id));
} }
virtual bool setup(); virtual bool setup();