diff --git a/server/include/log.h b/server/include/log.h index ecde7b582..6175f48a0 100644 --- a/server/include/log.h +++ b/server/include/log.h @@ -5,34 +5,44 @@ * @file */ - #ifndef _LOG_H_ +#ifndef _LOG_H_ #define _LOG_H_ +#include + #ifdef __GNUC__ #define INDENT int __attribute__ ((__cleanup__(log_outdent), unused)) _old_indent = log_indent(1); #else #define INDENT ; #endif -/** Global 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 config file. - */ -extern int _debug; - /** The log level which is passed as first argument to print() */ -enum log_level { - DEBUG, - INFO, - WARN, - ERROR -}; +#define DEBUG GRY("Debug") +#define INFO "" +#define WARN YEL("Warn") +#define ERROR RED("Error") + +/** Change log indention for current thread. + * + * The argument level can be negative! + */ int log_indent(int levels); +/** A helper function the restore the previous log indention level. + * + * This function is usually called by a __cleanup__ handler (GCC C Extension). + * See INDENT macro. + */ void log_outdent(int *); -/** Reset the wallclock of debugging outputs */ +/** Set the verbosity level of debug messages. + * + * @param lvl The new debug level. + */ +void log_setlevel(int lvl); + +/** Reset the wallclock of debug messages. */ void log_reset(); /** Logs variadic messages to stdout. @@ -40,38 +50,40 @@ void log_reset(); * @param lvl The log level * @param fmt The format string (printf alike) */ -void log_print(enum log_level lvl, const char *fmt, ...) +void log_print(const char *lvl, const char *fmt, ...) __attribute__ ((format(printf, 2, 3))); +/** Logs variadic messages to stdout. + * + * @param lvl The log level + * @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); + /** Printf alike debug message with level. */ -#define debug(lvl, msg, ...) do if (lvl <= _debug) log_print(DEBUG, msg, ##__VA_ARGS__); while (0) +void debug(int lvl, const char *fmt, ...) + __attribute__ ((format(printf, 2, 3))); /** Printf alike info message. */ -#define info(msg, ...) do log_print(INFO, msg, ##__VA_ARGS__); while (0) +void info(const char *fmt, ...) + __attribute__ ((format(printf, 1, 2))); /** Printf alike warning message. */ -#define warn(msg, ...) do log_print(WARN, msg, ##__VA_ARGS__); while (0) - +void warn(const char *fmt, ...) + __attribute__ ((format(printf, 1, 2))); + /** Print error and exit. */ -#define error(msg, ...) do { \ - log_print(ERROR, msg, ##__VA_ARGS__); \ - die(); \ - } while (0) +void error(const char *fmt, ...) + __attribute__ ((format(printf, 1, 2))); /** Print error and strerror(errno). */ -#define serror(msg, ...) do { \ - log_print(ERROR, msg ": %s", ##__VA_ARGS__, strerror(errno)); \ - die(); \ - } while (0) +void serror(const char *fmt, ...) + __attribute__ ((format(printf, 1, 2))); /** Print configuration error and exit. */ -#define cerror(c, msg, ...) do { \ - log_print(ERROR, msg " in %s:%u", ##__VA_ARGS__, \ - (config_setting_source_file(c)) ? \ - config_setting_source_file(c) : "(stdio)", \ - config_setting_source_line(c)); \ - die(); \ - } while (0) +void cerror(config_setting_t *cfg, const char *fmt, ...) + __attribute__ ((format(printf, 2, 3))); #endif /* _LOG_H_ */ diff --git a/server/include/utils.h b/server/include/utils.h index fce60c599..ed7b0c3dd 100644 --- a/server/include/utils.h +++ b/server/include/utils.h @@ -24,39 +24,25 @@ #endif /* Some color escape codes for pretty log messages */ -#ifndef ENABLE_OPAL_ASYNC - #define GRY(str) "\e[30m" str "\e[0m" /**< Print str in gray */ - #define RED(str) "\e[31m" str "\e[0m" /**< Print str in red */ - #define GRN(str) "\e[32m" str "\e[0m" /**< Print str in green */ - #define YEL(str) "\e[33m" str "\e[0m" /**< Print str in yellow */ - #define BLU(str) "\e[34m" str "\e[0m" /**< Print str in blue */ - #define MAG(str) "\e[35m" str "\e[0m" /**< Print str in magenta */ - #define CYN(str) "\e[36m" str "\e[0m" /**< Print str in cyan */ - #define WHT(str) "\e[37m" str "\e[0m" /**< Print str in white */ - #define BLD(str) "\e[1m" str "\e[0m" /**< Print str in bold */ +#define GRY(str) "\e[30m" str "\e[0m" /**< Print str in gray */ +#define RED(str) "\e[31m" str "\e[0m" /**< Print str in red */ +#define GRN(str) "\e[32m" str "\e[0m" /**< Print str in green */ +#define YEL(str) "\e[33m" str "\e[0m" /**< Print str in yellow */ +#define BLU(str) "\e[34m" str "\e[0m" /**< Print str in blue */ +#define MAG(str) "\e[35m" str "\e[0m" /**< Print str in magenta */ +#define CYN(str) "\e[36m" str "\e[0m" /**< Print str in cyan */ +#define WHT(str) "\e[37m" str "\e[0m" /**< Print str in white */ +#define BLD(str) "\e[1m" str "\e[0m" /**< Print str in bold */ - #define GFX(chr) "\e(0" chr "\e(B" - #define UP(n) "\e[" ## n ## "A" - #define DOWN(n) "\e[" ## n ## "B" - #define RIGHT(n) "\e[" ## n ## "C" - #define LEFT(n) "\e[" ## n ## "D" -#else - #define GRY(str) str - #define RED(str) str - #define GRN(str) str - #define YEL(str) str - #define BLU(str) str - #define MAG(str) str - #define CYN(str) str - #define WHT(str) str - #define BLD(str) str - - #define GFX(chr) " " - #define UP(n) "" - #define DOWN(n) "" - #define RIGHT(n) "" - #define LEFT(n) "" -#endif +/* Alternate character set */ +#define ACS(chr) "\e(0" chr "\e(B" +#define ACS_VERTICAL ACS("\x78") +#define ACS_VERTRIGHT ACS("\x74s") +s +/* UTF-8 Line drawing characters */ +#define UTF8_BOX "\xE2\x96\x88" +#define UTF8_VERTICAL "\xE2\x94\x82" +#define UTF8_VERTRIGHT "\xE2\x94\x9C" /* CPP stringification */ #define XSTR(x) STR(x) diff --git a/server/src/cfg.c b/server/src/cfg.c index ae37cea6f..ef666a061 100644 --- a/server/src/cfg.c +++ b/server/src/cfg.c @@ -83,8 +83,6 @@ int config_parse_global(config_setting_t *cfg, struct settings *set) config_setting_lookup_int(cfg, "debug", &set->debug); config_setting_lookup_float(cfg, "stats", &set->stats); - _debug = set->debug; - set->cfg = cfg; return 0; diff --git a/server/src/log.c b/server/src/log.c index 61a30abee..9a27f7a09 100644 --- a/server/src/log.c +++ b/server/src/log.c @@ -4,20 +4,25 @@ * @copyright 2015, Institute for Automation of Complex Power Systems, EONERC */ - #include +#include #include #include "log.h" #include "utils.h" -int _debug = V; +/** 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 int level = V; +/** A global clock used to prefix the log messages. */ static struct timespec epoch; #ifdef __GNUC__ +/** The current log indention level (per thread!). */ static __thread int indent = 0; -/** Get thread-specific pointer to indent level */ int log_indent(int levels) { int old = indent; @@ -31,41 +36,47 @@ void log_outdent(int *old) } #endif +void log_setlevel(int lvl) +{ + level = lvl; + debug(10, "Switched to debug level %u", level); +} + void log_reset() { clock_gettime(CLOCK_REALTIME, &epoch); + debug(10, "Debug clock resetted"); } -void log_print(enum log_level lvl, const char *fmt, ...) +void log_print(const char *lvl, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + log_vprint(lvl, fmt, ap); + va_end(ap); +} + +void log_vprint(const char *lvl, const char *fmt, va_list ap) { struct timespec ts; char buf[512] = ""; - va_list ap; - /* Timestamp */ clock_gettime(CLOCK_REALTIME, &ts); - strap(buf, sizeof(buf), "%8.3f ", timespec_delta(&epoch, &ts)); + strap(buf, sizeof(buf), "%10.3f ", timespec_delta(&epoch, &ts)); /* Severity */ - switch (lvl) { - case DEBUG: strap(buf, sizeof(buf), BLD("%-5s "), GRY("Debug")); break; - case INFO: strap(buf, sizeof(buf), BLD("%-5s "), " " ); break; - case WARN: strap(buf, sizeof(buf), BLD("%-5s "), YEL(" Warn")); break; - case ERROR: strap(buf, sizeof(buf), BLD("%-5s "), RED("Error")); break; - } - + strap(buf, sizeof(buf), BLD("%-5s "), lvl); + /* Indention */ #ifdef __GNUC__ for (int i = 0; i < indent; i++) - strap(buf, sizeof(buf), GFX("\x78") " "); - strap(buf, sizeof(buf), GFX("\x74") " "); + strap(buf, sizeof(buf), ACS_VERTICAL " "); + strap(buf, sizeof(buf), ACS_VERTRIGHT " "); #endif /* Format String */ - va_start(ap, fmt); vstrap(buf, sizeof(buf), fmt, ap); - va_end(ap); /* Output */ #ifdef ENABLE_OPAL_ASYNC @@ -73,3 +84,79 @@ void log_print(enum log_level lvl, const char *fmt, ...) #endif fprintf(stderr, "\r%s\n", buf); } + +/** Printf alike debug message with level. */ +void debug(int lvl, const char *fmt, ...) +{ + va_list ap; + + if (lvl <= level) { + va_start(ap, fmt); + log_vprint(DEBUG, fmt, ap); + va_end(ap); + } +} + +/** Printf alike info message. */ +void info(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + log_vprint(INFO, fmt, ap); + va_end(ap); +} + +/** Printf alike warning message. */ +void warn(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + log_vprint(WARN, fmt, ap); + va_end(ap); +} + +/** Print error and exit. */ +void error(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + log_vprint(ERROR, fmt, ap); + va_end(ap); + + die(); +} + +/** Print error and strerror(errno). */ +void serror(const char *fmt, ...) +{ + va_list ap; + char buf[1024]; + + va_start(ap, fmt); + vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + + log_print(ERROR, "%s: %s", buf, strerror(errno)); + die(); +} + +/** Print configuration error and exit. */ +void cerror(config_setting_t *cfg, const char *fmt, ...) +{ + va_list ap; + char buf[1024]; + + va_start(ap, fmt); + vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + + log_print(ERROR, "%s in %s:%u", buf, + config_setting_source_file(cfg) + ? config_setting_source_file(cfg) + : "(stdio)", + config_setting_source_line(cfg)); + die(); +} \ No newline at end of file diff --git a/server/src/server.c b/server/src/server.c index 96b1d89be..da35207e9 100644 --- a/server/src/server.c +++ b/server/src/server.c @@ -130,8 +130,9 @@ int main(int argc, char *argv[]) char *configfile = (argc == 2) ? argv[1] : "opal-shmem.conf"; - info("This is Simulator2Simulator Server (S2SS) %s (built on %s, %s, debug=%d)", - BLD(YEL(VERSION)), BLD(MAG(__DATE__)), BLD(MAG(__TIME__)), _debug); + log_reset(); + info("This is Simulator2Simulator Server (S2SS) %s (built on %s, %s)", + BLD(YEL(VERSION)), BLD(MAG(__DATE__)), BLD(MAG(__TIME__))); /* Check priviledges */ if (getuid() != 0)