X-Git-Url: https://gerrit.automotivelinux.org/gerrit/gitweb?a=blobdiff_plain;f=src%2Fverbose.c;h=e0f951001d8e3619d94f1b013a0172749f4edd5d;hb=65353dce81a629e042800bb7b86fcd869a76727e;hp=2b0090737ea4ac6d6c56f3f6f19f2f37d7ba4940;hpb=305d98f7b6db1a3207cc877bd2cda819e3b90656;p=src%2Fapp-framework-binder.git diff --git a/src/verbose.c b/src/verbose.c index 2b009073..e0f95100 100644 --- a/src/verbose.c +++ b/src/verbose.c @@ -1,5 +1,5 @@ /* - Copyright (C) 2016, 2017 "IoT.bzh" + Copyright (C) 2015-2020 "IoT.bzh" author: José Bollo @@ -21,22 +21,57 @@ #include "verbose.h" -int verbosity = 1; +#define MASKOF(x) (1 << (x)) -#define LEVEL(x) ((x) < 0 ? 0 : (x) > 7 ? 7 : (x)) +#if !defined(DEFAULT_LOGLEVEL) +# define DEFAULT_LOGLEVEL Log_Level_Warning +#endif + +#if !defined(DEFAULT_LOGMASK) +# define DEFAULT_LOGMASK (MASKOF((DEFAULT_LOGLEVEL) + 1) - 1) +#endif + +#if !defined(MINIMAL_LOGLEVEL) +# define MINIMAL_LOGLEVEL Log_Level_Error +#endif + +#if !defined(MINIMAL_LOGMASK) +# define MINIMAL_LOGMASK (MASKOF((MINIMAL_LOGLEVEL) + 1) - 1) +#endif + +static const char *names[] = { + "emergency", + "alert", + "critical", + "error", + "warning", + "notice", + "info", + "debug" +}; + +static const char asort[] = { 1, 2, 7, 0, 3, 6, 5, 4 }; + +int logmask = DEFAULT_LOGMASK | MINIMAL_LOGMASK; + +void (*verbose_observer)(int loglevel, const char *file, int line, const char *function, const char *fmt, va_list args); + +#define CROP_LOGLEVEL(x) \ + ((x) < Log_Level_Emergency ? Log_Level_Emergency \ + : (x) > Log_Level_Debug ? Log_Level_Debug : (x)) #if defined(VERBOSE_WITH_SYSLOG) #include -void vverbose(int level, const char *file, int line, const char *function, const char *fmt, va_list args) +static void _vverbose_(int loglevel, const char *file, int line, const char *function, const char *fmt, va_list args) { char *p; if (file == NULL || vasprintf(&p, fmt, args) < 0) - vsyslog(level, fmt, args); + vsyslog(loglevel, fmt, args); else { - syslog(LEVEL(level), "%s [%s:%d, function]", p, file, line, function); + syslog(CROP_LOGLEVEL(loglevel), "%s [%s:%d, %s]", p, file, line, function?:"?"); free(p); } } @@ -56,15 +91,15 @@ static const char *appname; static int appauthority; -void vverbose(int level, const char *file, int line, const char *function, const char *fmt, va_list args) +static void _vverbose_(int loglevel, const char *file, int line, const char *function, const char *fmt, va_list args) { char lino[20]; if (file == NULL) { - sd_journal_printv(level, fmt, args); + sd_journal_printv(loglevel, fmt, args); } else { sprintf(lino, "%d", line); - sd_journal_printv_with_location(level, file, lino, function, fmt, args); + sd_journal_printv_with_location(loglevel, file, lino, function, fmt, args); } } @@ -78,6 +113,9 @@ void verbose_set_name(const char *name, int authority) #include #include +#include +#include +#include static const char *appname; @@ -94,18 +132,127 @@ static const char *prefixes[] = { "<7> DEBUG" }; -void vverbose(int level, const char *file, int line, const char *function, const char *fmt, va_list args) +static const char *prefixes_colorized[] = { + "<0> " COLOR_EMERGENCY "EMERGENCY" COLOR_DEFAULT, + "<1> " COLOR_ALERT "ALERT" COLOR_DEFAULT, + "<2> " COLOR_CRITICAL "CRITICAL" COLOR_DEFAULT, + "<3> " COLOR_ERROR "ERROR" COLOR_DEFAULT, + "<4> " COLOR_WARNING "WARNING" COLOR_DEFAULT, + "<5> " COLOR_NOTICE "NOTICE" COLOR_DEFAULT, + "<6> " COLOR_INFO "INFO" COLOR_DEFAULT, + "<7> " COLOR_DEBUG "DEBUG" COLOR_DEFAULT +}; + +static int colorize = 0; + +static int tty; + +static const char chars[] = { '\n', '?', ':', ' ', '[', ',', ']' }; + +static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + +static void _vverbose_(int loglevel, const char *file, int line, const char *function, const char *fmt, va_list args) { - int saverr = errno; - int tty = isatty(fileno(stderr)); - errno = saverr; + char buffer[4000]; + char lino[40]; + int saverr, n, rc; + struct iovec iov[20]; + + /* save errno */ + saverr = errno; + + /* check if tty (2) or not (1) */ + if (!tty) + tty = 1 + isatty(STDERR_FILENO); - fprintf(stderr, "%s: ", prefixes[LEVEL(level)] + (tty ? 4 : 0)); - vfprintf(stderr, fmt, args); - if (file != NULL && (!tty || verbosity > 2)) - fprintf(stderr, " [%s:%d,%s]\n", file, line, function); + /* prefix */ + if (colorize) + iov[0].iov_base = (void*)prefixes_colorized[CROP_LOGLEVEL(loglevel)] + (tty - 1 ? 4 : 0); else - fprintf(stderr, "\n"); + iov[0].iov_base = (void*)prefixes[CROP_LOGLEVEL(loglevel)] + (tty - 1 ? 4 : 0); + iov[0].iov_len = strlen(iov[0].iov_base); + + /* " " */ + iov[1].iov_base = (void*)&chars[2]; + iov[1].iov_len = 2; + + n = 2; + if (fmt) { + iov[n].iov_base = buffer; + errno = saverr; + rc = vsnprintf(buffer, sizeof buffer, fmt, args); + if (rc < 0) + rc = 0; + else if ((size_t)rc > sizeof buffer) { + /* if too long, ellipsis the end with ... */ + rc = (int)sizeof buffer; + buffer[rc - 1] = buffer[rc - 2] = buffer[rc - 3] = '.'; + } + iov[n++].iov_len = (size_t)rc; + } + if (file && (!fmt || tty == 1 || loglevel <= Log_Level_Warning)) { + + if (colorize) + { + iov[n].iov_base = (void*)COLOR_FILE; + iov[n++].iov_len = strlen(COLOR_FILE); + } + + /* "[" (!fmt) or " [" (fmt) */ + iov[n].iov_base = (void*)&chars[3 + !fmt]; + iov[n++].iov_len = 2 - !fmt; + /* file */ + iov[n].iov_base = (void*)file; + iov[n++].iov_len = strlen(file); + /* ":" */ + iov[n].iov_base = (void*)&chars[2]; + iov[n++].iov_len = 1; + if (line) { + /* line number */ + iov[n].iov_base = lino; + iov[n++].iov_len = snprintf(lino, sizeof lino, "%d", line); + } else { + /* "?" */ + iov[n].iov_base = (void*)&chars[1]; + iov[n++].iov_len = 1; + } + /* "," */ + iov[n].iov_base = (void*)&chars[5]; + iov[n++].iov_len = 1; + if (function) { + /* function name */ + iov[n].iov_base = (void*)function; + iov[n++].iov_len = strlen(function); + } else { + /* "?" */ + iov[n].iov_base = (void*)&chars[1]; + iov[n++].iov_len = 1; + } + iov[n].iov_base = (void*)&chars[6]; + iov[n++].iov_len = 1; + + if (colorize) + { + iov[n].iov_base = (void*)COLOR_DEFAULT; + iov[n++].iov_len = strlen(COLOR_DEFAULT); + } + } + if (n == 2) { + /* "?" */ + iov[n].iov_base = (void*)&chars[1]; + iov[n++].iov_len = 1; + } + /* "\n" */ + iov[n].iov_base = (void*)&chars[0]; + iov[n++].iov_len = 1; + + /* emit the message */ + pthread_mutex_lock(&mutex); + writev(STDERR_FILENO, iov, n); + pthread_mutex_unlock(&mutex); + + /* restore errno */ + errno = saverr; } void verbose_set_name(const char *name, int authority) @@ -116,12 +263,113 @@ void verbose_set_name(const char *name, int authority) #endif -void verbose(int level, const char *file, int line, const char *function, const char *fmt, ...) +void vverbose(int loglevel, const char *file, int line, const char *function, const char *fmt, va_list args) +{ + void (*observer)(int loglevel, const char *file, int line, const char *function, const char *fmt, va_list args) = verbose_observer; + + if (!observer) + _vverbose_(loglevel, file, line, function, fmt, args); + else { + va_list ap; + va_copy(ap, args); + _vverbose_(loglevel, file, line, function, fmt, args); + observer(loglevel, file, line, function, fmt, ap); + va_end(ap); + } +} + +void verbose(int loglevel, const char *file, int line, const char *function, const char *fmt, ...) { va_list ap; va_start(ap, fmt); - vverbose(level, file, line, function, fmt, ap); + vverbose(loglevel, file, line, function, fmt, ap); va_end(ap); } +void set_logmask(int lvl) +{ + logmask = lvl | MINIMAL_LOGMASK; +} + +void verbose_add(int level) +{ + set_logmask(logmask | MASKOF(level)); +} + +void verbose_sub(int level) +{ + set_logmask(logmask & ~MASKOF(level)); +} + +void verbose_clear() +{ + set_logmask(0); +} + +void verbose_dec() +{ + verbosity_set(verbosity_get() - 1); +} + +void verbose_inc() +{ + verbosity_set(verbosity_get() + 1); +} + +int verbosity_to_mask(int verbo) +{ + int x = verbo + Log_Level_Error; + int l = CROP_LOGLEVEL(x); + return (1 << (l + 1)) - 1; +} + +int verbosity_from_mask(int mask) +{ + int v = 0; + while (mask > verbosity_to_mask(v)) + v++; + return v; +} + +void verbosity_set(int verbo) +{ + set_logmask(verbosity_to_mask(verbo)); +} + +int verbosity_get() +{ + return verbosity_from_mask(logmask); +} + +int verbose_level_of_name(const char *name) +{ + int c, i, r, l = 0, u = sizeof names / sizeof * names; + while (l < u) { + i = (l + u) >> 1; + r = (int)asort[i]; + c = strcasecmp(names[r], name); + if (!c) + return r; + if (c < 0) + l = i + 1; + else + u = i; + } + return -1; +} + +const char *verbose_name_of_level(int level) +{ + return level == CROP_LOGLEVEL(level) ? names[level] : NULL; +} + +void verbose_colorize() +{ + colorize = 1; +} + +int verbose_is_colorized() +{ + return colorize; +}