From 7d3851046e0dda9b24ebe2eb59f3a725bec1d14a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sun, 15 Aug 2021 11:41:12 +0200 Subject: [PATCH 1/3] log: pull in log.{c,h} from foot --- log.c | 237 ++++++++++++++++++++++++++++------------------ log.h | 68 +++++++++---- main.c | 4 +- modules/network.c | 2 +- modules/script.c | 2 +- particle.c | 2 +- 6 files changed, 197 insertions(+), 118 deletions(-) diff --git a/log.c b/log.c index c5d9093..52595bc 100644 --- a/log.c +++ b/log.c @@ -1,41 +1,55 @@ #include "log.h" -#include -#include -#include -#include -#include #include -#include -#include - +#include +#include +#include +#include +#include +#include #include +#include +#include + +#include "debug.h" + +#define ALEN(v) (sizeof(v) / sizeof((v)[0])) +#define UNUSED __attribute__((unused)) static bool colorize = false; static bool do_syslog = true; +static enum log_class log_level = LOG_CLASS_NONE; + +static const struct { + const char name[8]; + const char log_prefix[7]; + uint8_t color; + int syslog_equivalent; +} log_level_map[] = { + [LOG_CLASS_NONE] = {"none", "none", 5, -1}, + [LOG_CLASS_ERROR] = {"error", " err", 31, LOG_ERR}, + [LOG_CLASS_WARNING] = {"warning", "warn", 33, LOG_WARNING}, + [LOG_CLASS_INFO] = {"info", "info", 97, LOG_INFO}, + [LOG_CLASS_DEBUG] = {"debug", " dbg", 36, LOG_DEBUG}, +}; void log_init(enum log_colorize _colorize, bool _do_syslog, - enum log_facility syslog_facility, enum log_class syslog_level) + enum log_facility syslog_facility, enum log_class _log_level) { static const int facility_map[] = { [LOG_FACILITY_USER] = LOG_USER, [LOG_FACILITY_DAEMON] = LOG_DAEMON, }; - static const int level_map[] = { - [LOG_CLASS_ERROR] = LOG_ERR, - [LOG_CLASS_WARNING] = LOG_WARNING, - [LOG_CLASS_INFO] = LOG_INFO, - [LOG_CLASS_DEBUG] = LOG_DEBUG, - }; - colorize = _colorize == LOG_COLORIZE_NEVER ? false : _colorize == LOG_COLORIZE_ALWAYS ? true : isatty(STDERR_FILENO); do_syslog = _do_syslog; + log_level = _log_level; - if (do_syslog) { + int slvl = log_level_map[_log_level].syslog_equivalent; + if (do_syslog && slvl != -1) { openlog(NULL, /*LOG_PID*/0, facility_map[syslog_facility]); - setlogmask(LOG_UPTO(level_map[syslog_level])); + setlogmask(LOG_UPTO(slvl)); } } @@ -50,117 +64,156 @@ static void _log(enum log_class log_class, const char *module, const char *file, int lineno, const char *fmt, int sys_errno, va_list va) { - const char *class = "abcd"; - int class_clr = 0; - switch (log_class) { - case LOG_CLASS_ERROR: class = " err"; class_clr = 31; break; - case LOG_CLASS_WARNING: class = "warn"; class_clr = 33; break; - case LOG_CLASS_INFO: class = "info"; class_clr = 97; break; - case LOG_CLASS_DEBUG: class = " dbg"; class_clr = 36; break; - } + assert(log_class > LOG_CLASS_NONE); + assert(log_class < ALEN(log_level_map)); + + if (log_class > log_level) + return; + + const char *prefix = log_level_map[log_class].log_prefix; + unsigned int class_clr = log_level_map[log_class].color; char clr[16]; - snprintf(clr, sizeof(clr), "\e[%dm", class_clr); - fprintf(stderr, "%s%s%s: ", colorize ? clr : "", class, colorize ? "\e[0m" : ""); + snprintf(clr, sizeof(clr), "\033[%um", class_clr); + fprintf(stderr, "%s%s%s: ", colorize ? clr : "", prefix, colorize ? "\033[0m" : ""); if (colorize) - fprintf(stderr, "\e[2m"); + fputs("\033[2m", stderr); fprintf(stderr, "%s:%d: ", file, lineno); if (colorize) - fprintf(stderr, "\e[0m"); + fputs("\033[0m", stderr); vfprintf(stderr, fmt, va); if (sys_errno != 0) fprintf(stderr, ": %s", strerror(sys_errno)); - fprintf(stderr, "\n"); + fputc('\n', stderr); } static void _sys_log(enum log_class log_class, const char *module, - const char *file __attribute__((unused)), - int lineno __attribute__((unused)), + const char UNUSED *file, int UNUSED lineno, const char *fmt, int sys_errno, va_list va) { + assert(log_class > LOG_CLASS_NONE); + assert(log_class < ALEN(log_level_map)); + if (!do_syslog) return; /* Map our log level to syslog's level */ - int level = -1; - switch (log_class) { - case LOG_CLASS_ERROR: level = LOG_ERR; break; - case LOG_CLASS_WARNING: level = LOG_WARNING; break; - case LOG_CLASS_INFO: level = LOG_INFO; break; - case LOG_CLASS_DEBUG: level = LOG_DEBUG; break; - } + int level = log_level_map[log_class].syslog_equivalent; - assert(level != -1); + char msg[4096]; + int n = vsnprintf(msg, sizeof(msg), fmt, va); + assert(n >= 0); - const char *sys_err = sys_errno != 0 ? strerror(sys_errno) : NULL; + if (sys_errno != 0 && (size_t)n < sizeof(msg)) + snprintf(msg + n, sizeof(msg) - n, ": %s", strerror(sys_errno)); + syslog(level, "%s: %s", module, msg); +} + +void +log_msg_va(enum log_class log_class, const char *module, + const char *file, int lineno, const char *fmt, va_list va) +{ va_list va2; va_copy(va2, va); - - /* Calculate required size of buffer holding the entire log message */ - int required_len = 0; - required_len += strlen(module) + 2; /* "%s: " */ - required_len += vsnprintf(NULL, 0, fmt, va2); va_end(va2); - - if (sys_errno != 0) - required_len += strlen(sys_err) + 2; /* ": %s" */ - - /* Format the msg */ - char *msg = malloc(required_len + 1); - int idx = 0; - - idx += snprintf(&msg[idx], required_len + 1 - idx, "%s: ", module); - idx += vsnprintf(&msg[idx], required_len + 1 - idx, fmt, va); - - if (sys_errno != 0) { - snprintf( - &msg[idx], required_len + 1 - idx, ": %s", strerror(sys_errno)); - } - - syslog(level, "%s", msg); - free(msg); + _log(log_class, module, file, lineno, fmt, 0, va); + _sys_log(log_class, module, file, lineno, fmt, 0, va2); + va_end(va2); } void log_msg(enum log_class log_class, const char *module, const char *file, int lineno, const char *fmt, ...) { - va_list ap1, ap2; - va_start(ap1, fmt); - va_copy(ap2, ap1); - _log(log_class, module, file, lineno, fmt, 0, ap1); - _sys_log(log_class, module, file, lineno, fmt, 0, ap2); - va_end(ap1); - va_end(ap2); + va_list va; + va_start(va, fmt); + log_msg_va(log_class, module, file, lineno, fmt, va); + va_end(va); } -void log_errno(enum log_class log_class, const char *module, - const char *file, int lineno, - const char *fmt, ...) +void +log_errno_va(enum log_class log_class, const char *module, + const char *file, int lineno, + const char *fmt, va_list va) { - va_list ap1, ap2; - va_start(ap1, fmt); - va_copy(ap2, ap1); - _log(log_class, module, file, lineno, fmt, errno, ap1); - _sys_log(log_class, module, file, lineno, fmt, errno, ap2); - va_end(ap1); - va_end(ap2); + log_errno_provided_va(log_class, module, file, lineno, errno, fmt, va); } -void log_errno_provided(enum log_class log_class, const char *module, - const char *file, int lineno, int _errno, - const char *fmt, ...) +void +log_errno(enum log_class log_class, const char *module, + const char *file, int lineno, + const char *fmt, ...) { - va_list ap1, ap2; - va_start(ap1, fmt); - va_copy(ap2, ap1); - _log(log_class, module, file, lineno, fmt, _errno, ap1); - _sys_log(log_class, module, file, lineno, fmt, _errno, ap2); - va_end(ap1); - va_end(ap2); + va_list va; + va_start(va, fmt); + log_errno_va(log_class, module, file, lineno, fmt, va); + va_end(va); +} + +void +log_errno_provided_va(enum log_class log_class, const char *module, + const char *file, int lineno, int errno_copy, + const char *fmt, va_list va) +{ + va_list va2; + va_copy(va2, va); + _log(log_class, module, file, lineno, fmt, errno_copy, va); + _sys_log(log_class, module, file, lineno, fmt, errno_copy, va2); + va_end(va2); +} + +void +log_errno_provided(enum log_class log_class, const char *module, + const char *file, int lineno, int errno_copy, + const char *fmt, ...) +{ + va_list va; + va_start(va, fmt); + log_errno_provided_va(log_class, module, file, lineno, errno_copy, fmt, va); + va_end(va); +} + +static size_t +map_len(void) +{ + size_t len = ALEN(log_level_map); +#ifndef _DEBUG + /* Exclude "debug" entry for non-debug builds */ + len--; +#endif + return len; +} + +int +log_level_from_string(const char *str) +{ + if (str[0] == '\0') + return -1; + + for (int i = 0, n = map_len(); i < n; i++) + if (strcmp(str, log_level_map[i].name) == 0) + return i; + + return -1; +} + +const char * +log_level_string_hint(void) +{ + static char buf[64]; + if (buf[0] != '\0') + return buf; + + for (size_t i = 0, pos = 0, n = map_len(); i < n; i++) { + const char *entry = log_level_map[i].name; + const char *delim = (i + 1 < n) ? ", " : ""; + pos += snprintf(buf + pos, sizeof(buf) - pos, "'%s'%s", entry, delim); + } + + return buf; } diff --git a/log.h b/log.h index dfddd76..94fd178 100644 --- a/log.h +++ b/log.h @@ -1,42 +1,68 @@ #pragma once #include +#include enum log_colorize { LOG_COLORIZE_NEVER, LOG_COLORIZE_ALWAYS, LOG_COLORIZE_AUTO }; enum log_facility { LOG_FACILITY_USER, LOG_FACILITY_DAEMON }; -enum log_class { LOG_CLASS_ERROR, LOG_CLASS_WARNING, LOG_CLASS_INFO, LOG_CLASS_DEBUG }; + +enum log_class { + LOG_CLASS_NONE, + LOG_CLASS_ERROR, + LOG_CLASS_WARNING, + LOG_CLASS_INFO, + LOG_CLASS_DEBUG +}; void log_init(enum log_colorize colorize, bool do_syslog, - enum log_facility syslog_facility, enum log_class syslog_level); + enum log_facility syslog_facility, enum log_class log_level); void log_deinit(void); -void log_msg(enum log_class log_class, const char *module, - const char *file, int lineno, - const char *fmt, ...) __attribute__((format (printf, 5, 6))); +void log_msg( + enum log_class log_class, const char *module, + const char *file, int lineno, + const char *fmt, ...) __attribute__((format (printf, 5, 6))); -void log_errno(enum log_class log_class, const char *module, - const char *file, int lineno, - const char *fmt, ...) __attribute__((format (printf, 5, 6))); +void log_errno( + enum log_class log_class, const char *module, + const char *file, int lineno, + const char *fmt, ...) __attribute__((format (printf, 5, 6))); void log_errno_provided( enum log_class log_class, const char *module, const char *file, int lineno, int _errno, const char *fmt, ...) __attribute__((format (printf, 6, 7))); -#define LOG_ERR(fmt, ...) \ - log_msg(LOG_CLASS_ERROR, LOG_MODULE, __FILE__, __LINE__, fmt, ## __VA_ARGS__) -#define LOG_ERRNO(fmt, ...) \ - log_errno(LOG_CLASS_ERROR, LOG_MODULE, __FILE__, __LINE__, fmt, ## __VA_ARGS__) -#define LOG_ERRNO_P(fmt, _errno, ...) \ +void log_msg_va( + enum log_class log_class, const char *module, + const char *file, int lineno, const char *fmt, va_list va) __attribute__((format (printf, 5, 0))); +void log_errno_va( + enum log_class log_class, const char *module, + const char *file, int lineno, + const char *fmt, va_list va) __attribute__((format (printf, 5, 0))); +void log_errno_provided_va( + enum log_class log_class, const char *module, + const char *file, int lineno, int _errno, + const char *fmt, va_list va) __attribute__((format (printf, 6, 0))); + + +int log_level_from_string(const char *str); +const char *log_level_string_hint(void); + +#define LOG_ERR(...) \ + log_msg(LOG_CLASS_ERROR, LOG_MODULE, __FILE__, __LINE__, __VA_ARGS__) +#define LOG_ERRNO(...) \ + log_errno(LOG_CLASS_ERROR, LOG_MODULE, __FILE__, __LINE__, __VA_ARGS__) +#define LOG_ERRNO_P(_errno, ...) \ log_errno_provided(LOG_CLASS_ERROR, LOG_MODULE, __FILE__, __LINE__, \ - _errno, fmt, ## __VA_ARGS__) -#define LOG_WARN(fmt, ...) \ - log_msg(LOG_CLASS_WARNING, LOG_MODULE, __FILE__, __LINE__, fmt, ## __VA_ARGS__) -#define LOG_INFO(fmt, ...) \ - log_msg(LOG_CLASS_INFO, LOG_MODULE, __FILE__, __LINE__, fmt, ## __VA_ARGS__) + _errno, __VA_ARGS__) +#define LOG_WARN(...) \ + log_msg(LOG_CLASS_WARNING, LOG_MODULE, __FILE__, __LINE__, __VA_ARGS__) +#define LOG_INFO(...) \ + log_msg(LOG_CLASS_INFO, LOG_MODULE, __FILE__, __LINE__, __VA_ARGS__) #if defined(LOG_ENABLE_DBG) && LOG_ENABLE_DBG - #define LOG_DBG(fmt, ...) \ - log_msg(LOG_CLASS_DEBUG, LOG_MODULE, __FILE__, __LINE__, fmt, ## __VA_ARGS__) + #define LOG_DBG(...) \ + log_msg(LOG_CLASS_DEBUG, LOG_MODULE, __FILE__, __LINE__, __VA_ARGS__) #else - #define LOG_DBG(fmt, ...) + #define LOG_DBG(...) #endif diff --git a/main.c b/main.c index cab5f9e..48a94f6 100644 --- a/main.c +++ b/main.c @@ -275,7 +275,7 @@ main(int argc, char *const *argv) log_init(log_colorize, log_syslog, LOG_FACILITY_DAEMON, LOG_CLASS_INFO); - _Static_assert(LOG_CLASS_ERROR + 1 == FCFT_LOG_CLASS_ERROR, + _Static_assert((int)LOG_CLASS_ERROR == (int)FCFT_LOG_CLASS_ERROR, "fcft log level enum offset"); _Static_assert((int)LOG_COLORIZE_ALWAYS == (int)FCFT_LOG_COLORIZE_ALWAYS, "fcft colorize enum mismatch"); @@ -367,7 +367,7 @@ done: int res; int r = thrd_join(bar_thread, &res); if (r != 0) - LOG_ERRNO_P("failed to join bar thread", r); + LOG_ERRNO_P(r, "failed to join bar thread"); bar->destroy(bar); close(abort_fd); diff --git a/modules/network.c b/modules/network.c index c6b32af..b9277d7 100644 --- a/modules/network.c +++ b/modules/network.c @@ -451,7 +451,7 @@ parse_reply(struct module *mod, const struct nlmsghdr *hdr, size_t len) case NLMSG_ERROR:{ const struct nlmsgerr *err = NLMSG_DATA(hdr); - LOG_ERRNO_P("netlink", err->error); + LOG_ERRNO_P(err->error, "netlink"); return false; } diff --git a/modules/script.c b/modules/script.c index 189f4b6..f323635 100644 --- a/modules/script.c +++ b/modules/script.c @@ -495,7 +495,7 @@ execute_script(struct module *mod) } if (r > 0) { - LOG_ERRNO_P("%s: failed to start", _errno, m->path); + LOG_ERRNO_P(_errno, "%s: failed to start", m->path); close(comm_pipe[0]); waitpid(pid, NULL, 0); return -1; diff --git a/particle.c b/particle.c index a1e2b2c..468bd28 100644 --- a/particle.c +++ b/particle.c @@ -203,7 +203,7 @@ exposable_default_on_mouse(struct exposable *exposable, struct bar *bar, if (WIFEXITED(wstatus)) { if (WEXITSTATUS(wstatus) != 0) - LOG_ERRNO_P("%s: failed to execute", WEXITSTATUS(wstatus), exposable->on_click[btn]); + LOG_ERRNO_P(WEXITSTATUS(wstatus), "%s: failed to execute", exposable->on_click[btn]); } else LOG_ERR("%s: did not exit normally", exposable->on_click[btn]); From be10465a3bc9fc4cdde67ff73ffe6bb4f8e4d575 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sun, 15 Aug 2021 11:43:49 +0200 Subject: [PATCH 2/3] main: add -d,--log-level=info|warning|error|none Closes #84 --- CHANGELOG.md | 2 ++ completions/zsh/_yambar | 1 + doc/yambar.1.scd | 4 ++++ main.c | 37 +++++++++++++++++++++++++++---------- 4 files changed, 34 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e82a0f8..8316b08 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,8 @@ four borders to the same value (https://codeberg.org/dnkl/yambar/issues/77). * river: `per-output: false|true`. +* `-d,--log-level=info|warning|error|none` command line option + (https://codeberg.org/dnkl/yambar/issues/84). ### Changed diff --git a/completions/zsh/_yambar b/completions/zsh/_yambar index aa8172f..65b3100 100644 --- a/completions/zsh/_yambar +++ b/completions/zsh/_yambar @@ -8,5 +8,6 @@ _arguments \ '(-c --config)'{-c,--config}'[alternative configuration file]:filename:_files' \ '(-C --validate)'{-C,--validate}'[verify configuration then quit]' \ '(-p --print-pid)'{-p,--print-pid}'[print PID to this file or FD when up and running]:pidfile:_files' \ + '(-d --log-level)'{-d,--log-level}'[log level (info)]:loglevel:(info warning error none)' \ '(-l --log-colorize)'{-l,--log-colorize}'[enable or disable colorization of log output on stderr]:logcolor:(never always auto)' \ '(-s --log-no-syslog)'{-s,--log-no-syslog}'[disable syslog logging]' diff --git a/doc/yambar.1.scd b/doc/yambar.1.scd index f2526a2..a34f13c 100644 --- a/doc/yambar.1.scd +++ b/doc/yambar.1.scd @@ -27,6 +27,10 @@ yambar - modular status panel for X11 and Wayland (or FD) is closed immediately after writing the PID. When a _FILE_ as been specified, the file is unlinked exit. +*-d*,*--log-level*={*info*,*warning*,*error*,*none*} + Log level, used both for log output on stderr as well as + syslog. Default: _info_. + *-l*,*--log-colorize*=[{*never*,*always*,*auto*}] Enables or disables colorization of log output on stderr. diff --git a/main.c b/main.c index 48a94f6..e92e2e5 100644 --- a/main.c +++ b/main.c @@ -127,13 +127,14 @@ print_usage(const char *prog_name) printf("Usage: %s [OPTION]...\n", prog_name); printf("\n"); printf("Options:\n"); - printf(" -b,--backend={xcb,wayland,auto} backend to use (default: auto)\n" - " -c,--config=FILE alternative configuration file\n" - " -C,--validate verify configuration then quit\n" - " -p,--print-pid=FILE|FD print PID to file or FD\n" - " -l,--log-colorize=[never|always|auto] enable/disable colorization of log output on stderr\n" - " -s,--log-no-syslog disable syslog logging\n" - " -v,--version show the version number and quit\n"); + printf(" -b,--backend={xcb,wayland,auto} backend to use (default: auto)\n" + " -c,--config=FILE alternative configuration file\n" + " -C,--validate verify configuration then quit\n" + " -p,--print-pid=FILE|FD print PID to file or FD\n" + " -d,--log-level={info|warning|error|none} log level (info)\n" + " -l,--log-colorize=[never|always|auto] enable/disable colorization of log output on stderr\n" + " -s,--log-no-syslog disable syslog logging\n" + " -v,--version show the version number and quit\n"); } static bool @@ -181,6 +182,7 @@ main(int argc, char *const *argv) {"config", required_argument, 0, 'c'}, {"validate", no_argument, 0, 'C'}, {"print-pid", required_argument, 0, 'p'}, + {"log-level", required_argument, 0, 'd'}, {"log-colorize", optional_argument, 0, 'l'}, {"log-no-syslog", no_argument, 0, 's'}, {"version", no_argument, 0, 'v'}, @@ -195,11 +197,12 @@ main(int argc, char *const *argv) char *config_path = NULL; enum bar_backend backend = BAR_BACKEND_AUTO; + enum log_class log_level = LOG_CLASS_INFO; enum log_colorize log_colorize = LOG_COLORIZE_AUTO; bool log_syslog = true; while (true) { - int c = getopt_long(argc, argv, ":b:c:Cp:l::svh", longopts, NULL); + int c = getopt_long(argc, argv, ":b:c:Cp:d:l::svh", longopts, NULL); if (c == -1) break; @@ -238,6 +241,20 @@ main(int argc, char *const *argv) pid_file = optarg; break; + case 'd': { + int lvl = log_level_from_string(optarg); + if (lvl < 0) { + fprintf( + stderr, + "-d,--log-level: %s: argument must be one of %s\n", + optarg, + log_level_string_hint()); + return EXIT_FAILURE; + } + log_level = lvl; + break; + } + case 'l': if (optarg == NULL || strcmp(optarg, "auto") == 0) log_colorize = LOG_COLORIZE_AUTO; @@ -273,14 +290,14 @@ main(int argc, char *const *argv) } } - log_init(log_colorize, log_syslog, LOG_FACILITY_DAEMON, LOG_CLASS_INFO); + log_init(log_colorize, log_syslog, LOG_FACILITY_DAEMON, log_level); _Static_assert((int)LOG_CLASS_ERROR == (int)FCFT_LOG_CLASS_ERROR, "fcft log level enum offset"); _Static_assert((int)LOG_COLORIZE_ALWAYS == (int)FCFT_LOG_COLORIZE_ALWAYS, "fcft colorize enum mismatch"); fcft_log_init( - (enum fcft_log_colorize)log_colorize, log_syslog, FCFT_LOG_CLASS_INFO); + (enum fcft_log_colorize)log_colorize, log_syslog, (enum fcft_log_class)log_level); const struct sigaction sa = {.sa_handler = &signal_handler}; sigaction(SIGINT, &sa, NULL); From 495a4c8fb161801f256987a27fee7c3513d37a41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sun, 15 Aug 2021 16:34:46 +0200 Subject: [PATCH 3/3] =?UTF-8?q?log:=20remove=20unused=20include=20?= =?UTF-8?q?=E2=80=9Cdebug.h=E2=80=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- log.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/log.c b/log.c index 52595bc..c1adcd0 100644 --- a/log.c +++ b/log.c @@ -11,8 +11,6 @@ #include #include -#include "debug.h" - #define ALEN(v) (sizeof(v) / sizeof((v)[0])) #define UNUSED __attribute__((unused))