diff --git a/include/villas/log.h b/include/villas/log.h index f88870329..66b2de1bf 100644 --- a/include/villas/log.h +++ b/include/villas/log.h @@ -56,6 +56,24 @@ enum log_facilities { LOG_ALL = ~0xFF }; +struct log { + struct timespec epoch; /**< A global clock used to prefix the log messages. */ + + /** Debug level used by the debug() macro. + * It defaults to V (defined by the Makefile) and can be + * overwritten by the 'debug' setting in the configuration file. */ + int level; + + /** Debug facilities used by the debug() macro. */ + int facilities; +}; + +/** Initialize log object */ +int log_init(struct log *l); + +/** Destroy log object */ +int log_destroy(struct log *l); + /** Change log indention for current thread. * * The argument level can be negative! @@ -69,23 +87,30 @@ int log_indent(int levels); */ void log_outdent(int *); -/** Set the verbosity level of debug messages. +/** Set logging facilities based on expression. * - * @param lvl The new debug level. - * @param fac The new mask for debug facilities. + * Currently we support two types of expressions: + * 1. A comma seperated list of logging facilities + * 2. A comma seperated list of logging facilities which is prefixes with an exclamation mark '!' + * + * The first case enables only faciltities which are in the list. + * The second case enables all faciltities with exception of those which are in the list. + * + * @param expression The expression + * @return The new facilties mask (see enum log_faciltities) */ -void log_setlevel(int lvl, int fac); +int log_set_facility_expression(struct log *l, const char *expression); -/** Reset the wallclock of debug messages. */ -void log_init(); +/** Parse logging configuration. */ +int log_parse(struct log *l, config_setting_t *cfg); /** Logs variadic messages to stdout. * * @param lvl The log level * @param fmt The format string (printf alike) */ -void log_print(const char *lvl, const char *fmt, ...) - __attribute__ ((format(printf, 2, 3))); +void log_print(struct log *l, const char *lvl, const char *fmt, ...) + __attribute__ ((format(printf, 3, 4))); /** Logs variadic messages to stdout. * @@ -93,7 +118,7 @@ void log_print(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(const char *lvl, const char *fmt, va_list va); +void log_vprint(struct log *l, const char *lvl, const char *fmt, va_list va); /** Printf alike debug message with level. */ void debug(long lvl, const char *fmt, ...) diff --git a/lib/log.c b/lib/log.c index 36979eb71..47ac93479 100644 --- a/lib/log.c +++ b/lib/log.c @@ -23,16 +23,27 @@ #include "OpalPrint.h" #endif -/** Debug level used by the debug() macro. - * It defaults to V (defined by the Makefile) and can be - * overwritten by the 'debug' setting in the configuration file. */ -static unsigned level = V; +static struct log *log; -/** Debug facilities used by the debug() macro. */ -static unsigned facilities = ~0; - -/** A global clock used to prefix the log messages. */ -static struct timespec epoch; +/** List of debug facilities as strings */ +static const char *facilities_strs[] = { + "pool", /* LOG_POOL */ + "queue", /* LOG_QUEUE */ + "config", /* LOG_CONFIG */ + "hook", /* LOG_HOOK */ + "path", /* LOG_PATH */ + "mem", /* LOG_MEM */ + "web", /* LOG_WEB */ + "api", /* LOG_API */ + + /* Node-types */ + "socket", /* LOG_SOCKET */ + "file", /* LOG_FILE */ + "fpga", /* LOG_FPGA */ + "ngsi", /* LOG_NGSI */ + "websocket", /* LOG_WEBSOCKET */ + "opal" /* LOG_OPAL */ +}; #ifdef __GNUC__ /** The current log indention level (per thread!). */ @@ -51,34 +62,78 @@ void log_outdent(int *old) } #endif -void log_setlevel(int lvl, int fac) +int log_set_facility_expression(struct log *l, const char *expression) { - level = lvl; - debug(10, "Switched to debug level %u", level); + char *copy, *facility_str; + + enum { + NORMAL, + NEGATE + } mode; + + if (strlen(expression) <= 0) + return -1; + + if (expression[0] == '!') { + mode = NEGATE; + l->facilities = ~0xFF; + } + else { + mode = NORMAL; + l->facilities = 0; + } + + copy = strdup(expression); + facility_str = strtok(copy, ","); + + while (facility_str != NULL) { + for (int i = 0; i < ARRAY_LEN(facilities_strs); i++) { + if (strcmp(facilities_strs[i], facility_str)) { + switch (mode) { + case NORMAL: l->facilities |= (1 << (i+8)); + case NEGATE: l->facilities &= ~(1 << (i+8)); + } + } + } + + facility_str = strtok(NULL, ","); + } + + free(copy); + + return l->facilities; } -void log_init() +int log_init(struct log *l) { - epoch = time_now(); - debug(10, "Debug clock resetted"); + l->epoch = time_now(); + l->level = V; + l->facilities = LOG_ALL; + + debug(LOG_LOG | 10, "Log sub-system intialized"); + + /* Register this log instance globally */ + log = l; + + return 0; } -void log_print(const char *lvl, const char *fmt, ...) +void log_print(struct log *l, const char *lvl, const char *fmt, ...) { va_list ap; va_start(ap, fmt); - log_vprint(lvl, fmt, ap); + log_vprint(l, lvl, fmt, ap); va_end(ap); } -void log_vprint(const char *lvl, const char *fmt, va_list ap) +void log_vprint(struct log *l, const char *lvl, const char *fmt, va_list ap) { struct timespec ts = time_now(); char *buf = alloc(512); /* Timestamp */ - strcatf(&buf, "%10.3f ", time_delta(&epoch, &ts)); + strcatf(&buf, "%10.3f ", time_delta(&l->epoch, &ts)); /* Severity */ strcatf(&buf, "%5s ", lvl); @@ -102,12 +157,24 @@ void log_vprint(const char *lvl, const char *fmt, va_list ap) free(buf); } +int log_parse(struct log *l, config_setting_t *cfg) +{ + const char *facilities; + + config_setting_lookup_int(cfg, "level", &l->level); + + if (config_setting_lookup_string(cfg, "facilties", &facilities)) + log_set_facility_expression(l, facilities); + + return 0; +} + void line() { char buf[LOG_WIDTH]; memset(buf, 0x71, sizeof(buf)); - log_print("", "\b" ACS("%.*s"), LOG_WIDTH, buf); + log_print(log, "", "\b" ACS("%.*s"), LOG_WIDTH, buf); } void debug(long class, const char *fmt, ...) @@ -117,9 +184,9 @@ void debug(long class, const char *fmt, ...) int lvl = class & 0xFF; int fac = class & ~0xFF; - if (((fac == 0) || (fac & facilities)) && (lvl <= level)) { + if (((fac == 0) || (fac & log->facilities)) && (lvl <= log->level)) { va_start(ap, fmt); - log_vprint(LOG_LVL_DEBUG, fmt, ap); + log_vprint(log, LOG_LVL_DEBUG, fmt, ap); va_end(ap); } } @@ -129,7 +196,7 @@ void info(const char *fmt, ...) va_list ap; va_start(ap, fmt); - log_vprint(LOG_LVL_INFO, fmt, ap); + log_vprint(log, LOG_LVL_INFO, fmt, ap); va_end(ap); } @@ -138,7 +205,7 @@ void warn(const char *fmt, ...) va_list ap; va_start(ap, fmt); - log_vprint(LOG_LVL_WARN, fmt, ap); + log_vprint(log, LOG_LVL_WARN, fmt, ap); va_end(ap); } @@ -147,7 +214,7 @@ void stats(const char *fmt, ...) va_list ap; va_start(ap, fmt); - log_vprint(LOG_LVL_STATS, fmt, ap); + log_vprint(log, LOG_LVL_STATS, fmt, ap); va_end(ap); } @@ -156,7 +223,7 @@ void error(const char *fmt, ...) va_list ap; va_start(ap, fmt); - log_vprint(LOG_LVL_ERROR, fmt, ap); + log_vprint(log, LOG_LVL_ERROR, fmt, ap); va_end(ap); die(); @@ -171,7 +238,7 @@ void serror(const char *fmt, ...) vstrcatf(&buf, fmt, ap); va_end(ap); - log_print(LOG_LVL_ERROR, "%s: %m (%u)", buf, errno); + log_print(log, LOG_LVL_ERROR, "%s: %m (%u)", buf, errno); free(buf); die(); @@ -186,7 +253,7 @@ void cerror(config_setting_t *cfg, const char *fmt, ...) vstrcatf(&buf, fmt, ap); va_end(ap); - log_print(LOG_LVL_ERROR, "%s in %s:%u", buf, + log_print(log, LOG_LVL_ERROR, "%s in %s:%u", buf, config_setting_source_file(cfg) ? config_setting_source_file(cfg) : "(stdio)",