diff --git a/common/include/villas/log.h b/common/include/villas/log.h index 334bd1c36..96bdac568 100644 --- a/common/include/villas/log.h +++ b/common/include/villas/log.h @@ -36,11 +36,15 @@ extern "C" { #include /* The log level which is passed as first argument to print() */ -#define LOG_LVL_DEBUG CLR_GRY("Debug") -#define LOG_LVL_INFO CLR_WHT("Info ") -#define LOG_LVL_WARN CLR_YEL("Warn ") -#define LOG_LVL_ERROR CLR_RED("Error") -#define LOG_LVL_STATS CLR_MAG("Stats") +enum log_level { + LOG_LVL_DEBUG, + LOG_LVL_INFO, + LOG_LVL_WARN, + LOG_LVL_ERROR, + LOG_LVL_STATS, +}; + +typedef void (*log_cb_t)(struct log *l, enum log_level lvl, const char *fmt, va_list va); /** Debug facilities. * @@ -84,6 +88,8 @@ enum log_facilities { struct log { enum state state; + const char *name; + struct timespec epoch; /**< A global clock used to prefix the log messages. */ struct winsize window; /**< Size of the terminal window. */ @@ -99,15 +105,18 @@ struct log { int syslog; /**< Whether or not to log to syslogd. */ bool tty; /**< Is the log file a tty? */ + log_cb_t callback; + FILE *file; /**< Send all log output to this file / stdout / stderr. */ }; /** The global log instance. */ -struct log *global_log; -struct log default_log; +extern struct log *global_log; /** Initialize log object */ -int log_init(struct log *l, int level, long faciltities); +int log_init(struct log *l, const char *name, int level, long faciltities); + +void log_set_callback(struct log *l, log_cb_t cb); int log_open(struct log *l); @@ -135,7 +144,7 @@ int log_set_facility_expression(struct log *l, const char *expression); * @param lvl The log level * @param fmt The format string (printf alike) */ -void log_print(struct log *l, const char *lvl, const char *fmt, ...) +void log_print(struct log *l, enum log_level lvl, const char *fmt, ...) __attribute__ ((format(printf, 3, 4))); /** Logs variadic messages to stdout. @@ -144,7 +153,7 @@ void log_print(struct log *l, const char *lvl, const char *fmt, ...) * @param fmt The format string (printf alike) * @param va The variadic argument list (see stdarg.h) */ -void log_vprint(struct log *l, const char *lvl, const char *fmt, va_list va); +void log_vprint(struct log *l, enum log_level lvl, const char *fmt, va_list va); /** Printf alike debug message with level. */ void debug(long lvl, const char *fmt, ...) diff --git a/common/lib/log.c b/common/lib/log.c index d35d101e1..54a6e0b04 100644 --- a/common/lib/log.c +++ b/common/lib/log.c @@ -43,23 +43,33 @@ #endif struct log *global_log; +struct log default_log; /* We register a default log instance */ __attribute__((constructor)) void register_default_log() { int ret; - static struct log default_log; - ret = log_init(&default_log, V, LOG_ALL); + ret = log_init(&default_log, "default", V, LOG_ALL); if (ret) error("Failed to initalize log"); ret = log_open(&default_log); if (ret) error("Failed to start log"); + + global_log = &default_log; } +static const char *level_strs[] = { + CLR_GRY("Debug"), /* LOG_LVL_DEBUG */ + CLR_WHT("Info "), /* LOG_LVL_INFO */ + CLR_YEL("Warn "), /* LOG_LVL_WARN */ + CLR_RED("Error"), /* LOG_LVL_ERROR */ + CLR_MAG("Stats") /* LOG_LVL_STATS */ +}; + /** List of debug facilities as strings */ static const char *facilities_strs[] = { "pool", /* LOG_POOL */ @@ -106,18 +116,20 @@ static void log_resize(int signal, siginfo_t *sinfo, void *ctx) debug(LOG_LOG | 15, "New terminal size: %dx%x", global_log->window.ws_row, global_log->window.ws_col); } -int log_init(struct log *l, int level, long facilitites) +int log_init(struct log *l, const char *name, int level, long facilitites) { int ret; /* Register this log instance globally */ global_log = l; + l->name = name; l->level = level; l->syslog = 0; l->facilities = facilitites; l->file = stderr; l->path = NULL; + l->callback = NULL; l->epoch = time_now(); l->prefix = getenv("VILLAS_LOG_PREFIX"); @@ -159,6 +171,11 @@ int log_init(struct log *l, int level, long facilitites) return 0; } +void log_set_callback(struct log *l, log_cb_t cb) +{ + l->callback = cb; +} + int log_open(struct log *l) { if (l->path) { @@ -263,7 +280,7 @@ found: if (negate) return l->facilities; } -void log_print(struct log *l, const char *lvl, const char *fmt, ...) +void log_print(struct log *l, enum log_level lvl, const char *fmt, ...) { va_list ap; @@ -272,11 +289,16 @@ void log_print(struct log *l, const char *lvl, const char *fmt, ...) va_end(ap); } -void log_vprint(struct log *l, const char *lvl, const char *fmt, va_list ap) +void log_vprint(struct log *l, enum log_level lvl, const char *fmt, va_list ap) { struct timespec ts = time_now(); static __thread char buf[1024]; + if (l->callback) { + l->callback(l, lvl, fmt, ap); + return; + } + int off = 0; int len = sizeof(buf); @@ -285,7 +307,7 @@ void log_vprint(struct log *l, const char *lvl, const char *fmt, va_list ap) off += snprintf(buf + off, len - off, "%s", l->prefix); /* Timestamp & Severity */ - off += snprintf(buf + off, len - off, "%10.3f %-5s ", time_delta(&l->epoch, &ts), lvl); + off += snprintf(buf + off, len - off, "%10.3f %-5s ", time_delta(&l->epoch, &ts), level_strs[lvl]); /* Format String */ off += vsnprintf(buf + off, len - off, fmt, ap); diff --git a/common/lib/log_config.c b/common/lib/log_config.c index ead230296..ab97dac4e 100644 --- a/common/lib/log_config.c +++ b/common/lib/log_config.c @@ -84,14 +84,12 @@ void jerror(json_error_t *err, const char *fmt, ...) va_list ap; char *buf = NULL; - struct log *l = global_log ? global_log : &default_log; - va_start(ap, fmt); vstrcatf(&buf, fmt, ap); va_end(ap); - log_print(l, LOG_LVL_ERROR, "%s:", buf); - log_print(l, LOG_LVL_ERROR, " %s in %s:%d:%d", err->text, err->source, err->line, err->column); + log_print(global_log, LOG_LVL_ERROR, "%s:", buf); + log_print(global_log, LOG_LVL_ERROR, " %s in %s:%d:%d", err->text, err->source, err->line, err->column); free(buf); diff --git a/common/lib/table.c b/common/lib/table.c index f9b65c036..88a55b6f3 100644 --- a/common/lib/table.c +++ b/common/lib/table.c @@ -62,10 +62,8 @@ static int table_resize(struct table *t, int width) void table_header(struct table *t) { - struct log *l = global_log ? global_log : &default_log; - - if (t->width != l->width) - table_resize(t, l->width); + if (t->width != global_log->width) + table_resize(t, global_log->width); char *line0 = strf("\b"); char *line1 = strf("\b\b" BOX_UD); @@ -121,10 +119,8 @@ void table_header(struct table *t) void table_row(struct table *t, ...) { - struct log *l = global_log ? global_log : &default_log; - - if (t->width != l->width) { - table_resize(t, l->width); + if (t->width != global_log->width) { + table_resize(t, global_log->width); table_header(t); } @@ -156,10 +152,8 @@ void table_row(struct table *t, ...) void table_footer(struct table *t) { - struct log *l = global_log ? global_log : &default_log; - - if (t->width != l->width) - table_resize(t, l->width); + if (t->width != global_log->width) + table_resize(t, global_log->width); char *line = strf("\b"); diff --git a/common/tests/advio.c b/common/tests/advio.c deleted file mode 100644 index 15947c76d..000000000 --- a/common/tests/advio.c +++ /dev/null @@ -1,255 +0,0 @@ -/** Unit tests for advio - * - * @author Steffen Vogel - * @copyright 2017-2018, Institute for Automation of Complex Power Systems, EONERC - * @license GNU General Public License (version 3) - * - * VILLAScommon - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *********************************************************************************/ - -#include - -#include -#include - -#include -#include - -/** This URI points to a Sciebo share which contains some test files. - * The Sciebo share is read/write accessible via WebDAV. */ -#define BASE_URI "https://1Nrd46fZX8HbggT:badpass@rwth-aachen.sciebo.de/public.php/webdav/node/tests" - -Test(advio, islocal) -{ - int ret; - - ret = aislocal("/var/log/villas/dta.dat"); - cr_assert_eq(ret, 1); - - ret = aislocal("http://www.google.de"); - cr_assert_eq(ret, 0); - - ret = aislocal("torrent://www.google.de"); - cr_assert_eq(ret, -1); -} - -Test(advio, local) -{ - AFILE *af; - int ret; - char *buf = NULL; - size_t buflen = 0; - - /* We open this file and check the first line */ - af = afopen(__FILE__, "r"); - cr_assert(af, "Failed to open local file"); - - ret = getline(&buf, &buflen, af->file); - cr_assert_gt(ret, 1); - cr_assert_str_eq(buf, "/** Unit tests for advio\n"); -} - -Test(advio, download) -{ - AFILE *af; - int ret; - size_t len; - char buffer[64]; - char expect[64] = "ook4iekohC2Teegoghu6ayoo1OThooregheebaet8Zod1angah0che7quai4ID7A"; - - af = afopen(BASE_URI "/download" , "r"); - cr_assert(af, "Failed to download file"); - - len = afread(buffer, 1, sizeof(buffer), af); - cr_assert_gt(len, 0, "len=%zu, feof=%u", len, afeof(af)); - - cr_assert_arr_eq(buffer, expect, sizeof(expect)); - - ret = afclose(af); - cr_assert_eq(ret, 0, "Failed to close file"); -} - -Test(advio, download_large) -{ - AFILE *af; - int ret; - - af = afopen(BASE_URI "/download-large" , "r"); - cr_assert(af, "Failed to download file"); - - char line[4096]; - - char *f; - - f = afgets(line, 4096, af); - cr_assert_not_null(f); - - /* Check first line */ - cr_assert_str_eq(line, "# VILLASnode signal params: type=mixed, values=4, rate=1000.000000, limit=100000, amplitude=1.000000, freq=1.000000\n"); - - while(afgets(line, 4096, af)); - - /* Check last line */ - cr_assert_str_eq(line, "1497710478.862332239(99999) 0.752074 -0.006283 1.000000 0.996000\n"); - - ret = afclose(af); - cr_assert_eq(ret, 0, "Failed to close file"); -} - -Test(advio, resume) -{ - int ret; - char *retp; - AFILE *af1, *af2; - char *fn, dir[] = "/tmp/temp.XXXXXX"; - char line1[32]; - char *line2 = NULL; - size_t linelen = 0; - - retp = mkdtemp(dir); - cr_assert_not_null(retp); - - ret = asprintf(&fn, "%s/file", dir); - cr_assert_gt(ret, 0); - - af1 = afopen(fn, "w+"); - cr_assert_not_null(af1); - - /* We flush once the empty file in order to upload an empty file. */ - aupload(af1, 0); - - af2 = afopen(fn, "r"); - cr_assert_not_null(af2); - - for (int i = 0; i < 100; i++) { - snprintf(line1, sizeof(line1), "This is line %d\n", i); - - afputs(line1, af1); - aupload(af1, 1); - - adownload(af2, 1); - - ret = agetline(&line2, &linelen, af2); - cr_assert_gt(ret, 0); - - cr_assert_str_eq(line1, line2); - } - - ret = afclose(af1); - cr_assert_eq(ret, 0); - - ret = afclose(af2); - cr_assert_eq(ret, 0); - - ret = unlink(fn); - cr_assert_eq(ret, 0); - - ret = rmdir(dir); - cr_assert_eq(ret, 0); - - free(line2); -} - -Test(advio, upload) -{ - AFILE *af; - int ret; - size_t len; - - char upload[64]; - char buffer[64]; - - /* Get some random data to upload */ - len = read_random(upload, sizeof(upload)); - cr_assert_eq(len, sizeof(upload)); - - /* Open file for writing */ - af = afopen(BASE_URI "/upload", "w+"); - cr_assert(af, "Failed to download file"); - - len = afwrite(upload, 1, sizeof(upload), af); - cr_assert_eq(len, sizeof(upload)); - - ret = afclose(af); - cr_assert_eq(ret, 0, "Failed to close/upload file"); - - /* Open for reading and comparison */ - af = afopen(BASE_URI "/upload", "r"); - cr_assert(af, "Failed to download file"); - - len = afread(buffer, 1, sizeof(upload), af); - cr_assert_eq(len, sizeof(upload)); - - cr_assert_arr_eq(buffer, upload, len); - - ret = afclose(af); - cr_assert(ret == 0, "Failed to close file"); -} - -Test(advio, append) -{ - AFILE *af; - int ret; - size_t len; - - char append1[64] = "xa5gieTohlei9iu1uVaePae6Iboh3eeheeme5iejue5sheshae4uzisha9Faesei"; - char append2[64] = "bitheeRae7igee2miepahJaefoGad1Ooxeif0Mooch4eojoumueYahn4ohc9poo2"; - char expect[128] = "xa5gieTohlei9iu1uVaePae6Iboh3eeheeme5iejue5sheshae4uzisha9FaeseibitheeRae7igee2miepahJaefoGad1Ooxeif0Mooch4eojoumueYahn4ohc9poo2"; - char buffer[128]; - - /* Open file for writing first chunk */ - af = afopen(BASE_URI "/append", "w+"); - cr_assert(af, "Failed to download file"); - - /* The append file might already exist and be not empty from a previous run. */ - ret = ftruncate(afileno(af), 0); - cr_assert_eq(ret, 0); - - char c; - fseek(af->file, 0, SEEK_SET); - if (af->file) { - while ((c = getc(af->file)) != EOF) - putchar(c); - } - - len = afwrite(append1, 1, sizeof(append1), af); - cr_assert_eq(len, sizeof(append1)); - - ret = afclose(af); - cr_assert_eq(ret, 0, "Failed to close/upload file"); - - /* Open file for writing second chunk */ - af = afopen(BASE_URI "/append", "a"); - cr_assert(af, "Failed to download file"); - - len = afwrite(append2, 1, sizeof(append2), af); - cr_assert_eq(len, sizeof(append2)); - - ret = afclose(af); - cr_assert_eq(ret, 0, "Failed to close/upload file"); - - /* Open for reading and comparison */ - af = afopen(BASE_URI "/append", "r"); - cr_assert(af, "Failed to download file"); - - len = afread(buffer, 1, sizeof(buffer), af); - cr_assert_eq(len, sizeof(buffer)); - - ret = afclose(af); - cr_assert(ret == 0, "Failed to close file"); - - cr_assert_arr_eq(buffer, expect, sizeof(expect)); -} diff --git a/common/tests/bitset.c b/common/tests/bitset.c deleted file mode 100644 index 41c6abd8e..000000000 --- a/common/tests/bitset.c +++ /dev/null @@ -1,130 +0,0 @@ -/** Unit tests for advio - * - * @author Steffen Vogel - * @copyright 2017-2018, Institute for Automation of Complex Power Systems, EONERC - * @license GNU General Public License (version 3) - * - * VILLAScommon - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *********************************************************************************/ - -#include - -#include -#include - -#define LEN 1027 - -Test(bitset, simple) -{ - int ret; - struct bitset bs; - - int bits[] = { 23, 223, 25, 111, 252, 86, 222, 454, LEN-1 }; - - ret = bitset_init(&bs, LEN); - cr_assert_eq(ret, 0); - - for (int i = 0; i < ARRAY_LEN(bits); i++) { - bitset_set(&bs, bits[i]); - cr_assert_eq(ret, 0); - } - - for (int i = 0; i < ARRAY_LEN(bits); i++) { - ret = bitset_test(&bs, bits[i]); - cr_assert_eq(ret, 1, "Failed at bit %d", i); - } - - for (int i = 0; i < ARRAY_LEN(bits); i++) { - ret = bitset_clear(&bs, bits[i]); - cr_assert_eq(ret, 0, "Failed at bit %d", i); - } - - for (int i = 0; i < LEN; i++) { - ret = bitset_test(&bs, i); - cr_assert_eq(ret, 0); - } - - ret = bitset_destroy(&bs); - cr_assert_eq(ret, 0); -} - -Test(bitset, outofbounds) -{ - int ret; - struct bitset bs; - - ret = bitset_init(&bs, LEN); - cr_assert_eq(ret, 0); - - ret = bitset_set(&bs, LEN+1); - cr_assert_eq(ret, -1); - - ret = bitset_test(&bs, LEN+1); - cr_assert_eq(ret, -1); - - ret = bitset_destroy(&bs); - cr_assert_eq(ret, 0); -} - -Test(bitset, cmp) -{ - int ret; - struct bitset bs1, bs2; - - ret = bitset_init(&bs1, LEN); - cr_assert_eq(ret, 0); - - ret = bitset_init(&bs2, LEN); - cr_assert_eq(ret, 0); - - ret = bitset_set(&bs1, 525); - cr_assert_eq(ret, 0); - - ret = bitset_set(&bs2, 525); - cr_assert_eq(ret, 0); - - ret = bitset_cmp(&bs1, &bs2); - cr_assert_eq(ret, 0); - - ret = bitset_clear(&bs2, 525); - cr_assert_eq(ret, 0); - - ret = bitset_cmp(&bs1, &bs2); - cr_assert_neq(ret, 0); - - ret = bitset_destroy(&bs1); - cr_assert_eq(ret, 0); - - ret = bitset_destroy(&bs2); - cr_assert_eq(ret, 0); -} - -Test(bitset, all) -{ - int ret; - struct bitset bs; - - ret = bitset_init(&bs, LEN); - cr_assert_eq(ret, 0); - - for (int i = 0; i < LEN; i++) { - bitset_test(&bs, i); - cr_assert_eq(ret, 0); - } - - ret = bitset_destroy(&bs); - cr_assert_eq(ret, 0); -}