From aab6f6c71877a42561da5aa4a222dd18181ea78f Mon Sep 17 00:00:00 2001 From: Christian Meffert Date: Sat, 22 Feb 2025 13:52:05 +0000 Subject: [PATCH] [logger] Support logging with logfmt format --- src/conffile.c | 1 + src/logger.c | 54 ++++++++++++++++++++++++++++++++++++++++++++------ src/logger.h | 2 +- src/main.c | 48 ++++++++++++++++++++++++-------------------- 4 files changed, 77 insertions(+), 28 deletions(-) diff --git a/src/conffile.c b/src/conffile.c index 9f0d8e48..0476803f 100644 --- a/src/conffile.c +++ b/src/conffile.c @@ -49,6 +49,7 @@ static cfg_opt_t sec_general[] = CFG_STR("db_backup_path", NULL, CFGF_NONE), CFG_STR("logfile", STATEDIR "/log/" PACKAGE ".log", CFGF_NONE), CFG_INT_CB("loglevel", E_LOG, CFGF_NONE, &cb_loglevel), + CFG_STR("logformat", "default", CFGF_NONE), CFG_STR("admin_password", NULL, CFGF_NONE), CFG_INT("websocket_port", 3688, CFGF_NONE), CFG_STR("websocket_interface", NULL, CFGF_NONE), diff --git a/src/logger.c b/src/logger.c index 43dc0ba2..ba312011 100644 --- a/src/logger.c +++ b/src/logger.c @@ -60,7 +60,13 @@ static char *logfilename; static FILE *logfile; static char *labels[] = { "config", "daap", "db", "httpd", "http", "main", "mdns", "misc", "rsp", "scan", "xcode", "event", "remote", "dacp", "ffmpeg", "artwork", "player", "raop", "laudio", "dmap", "dbperf", "spotify", "scrobble", "cache", "mpd", "stream", "cast", "fifo", "lib", "web", "airplay", "rcp" }; static char *severities[] = { "FATAL", "LOG", "WARN", "INFO", "DEBUG", "SPAM" }; +static char *format_labels[] = { "default", "logfmt" }; +enum format { + L_FMT_DEFAULT = 0, + L_FMT_LOGFMT = 1, +}; +static enum format format = L_FMT_DEFAULT; static int set_logdomains(char *domains) @@ -94,6 +100,23 @@ set_logdomains(char *domains) return 0; } +static int +format_code_get(const char *label) +{ + int i; + + if (!label) + return 0; + + for (i = 0; i < ARRAY_SIZE(format_labels); i++) + { + if (strcmp(label, format_labels[i]) == 0) + return i; + } + + return 0; +} + static int repeat_count(const char *fmt) { @@ -139,16 +162,34 @@ logger_write_with_label(int severity, int domain, const char *content) char thread_nametid[32]; time_t t; struct tm timebuf; + char logfmt_msg[1024]; int ret; thread_getnametid(thread_nametid, sizeof(thread_nametid)); - t = time(NULL); - ret = strftime(stamp, sizeof(stamp), "%Y-%m-%d %H:%M:%S", localtime_r(&t, &timebuf)); - if (ret == 0) - stamp[0] = '\0'; - logger_write("[%s] [%5s] [%16s] %8s: %s", stamp, severities[severity], thread_nametid, labels[domain], content); + if (format == L_FMT_LOGFMT) + { + ret = strftime(stamp, sizeof(stamp), "%Y-%m-%dT%H:%M:%S%z", localtime_r(&t, &timebuf)); + if (ret == 0) + stamp[0] = '\0'; + + strncpy(logfmt_msg, content, sizeof(logfmt_msg)); + logfmt_msg[sizeof(logfmt_msg) - 1] = '\0'; + safe_snreplace(logfmt_msg, sizeof(logfmt_msg), "\n", " "); + safe_snreplace(logfmt_msg, sizeof(logfmt_msg), "\"", "\\\""); + + logger_write("time=%s level=%s thread=\"%s\" component=%s msg=\"%s\"\n", stamp, severities[severity], thread_nametid, + labels[domain], logfmt_msg); + } + else + { + ret = strftime(stamp, sizeof(stamp), "%Y-%m-%d %H:%M:%S", localtime_r(&t, &timebuf)); + if (ret == 0) + stamp[0] = '\0'; + + logger_write("[%s] [%5s] [%16s] %8s: %s", stamp, severities[severity], thread_nametid, labels[domain], content); + } } static void @@ -408,7 +449,7 @@ logger_detach(void) } int -logger_init(char *file, char *domains, int severity) +logger_init(char *file, char *domains, int severity, char *logformat) { int ret; @@ -421,6 +462,7 @@ logger_init(char *file, char *domains, int severity) console = 1; threshold = severity; + format = format_code_get(logformat); if (domains) { diff --git a/src/logger.h b/src/logger.h index d7099b02..30e19c5a 100644 --- a/src/logger.h +++ b/src/logger.h @@ -84,7 +84,7 @@ void logger_detach(void); int -logger_init(char *file, char *domains, int severity); +logger_init(char *file, char *domains, int severity, char *logformat); void logger_deinit(void); diff --git a/src/main.c b/src/main.c index 95301614..008ddbe8 100644 --- a/src/main.c +++ b/src/main.c @@ -495,6 +495,7 @@ main(int argc, char **argv) int loglevel = -1; char *logdomains = NULL; char *logfile = NULL; + char *logformat = NULL; char *ffid = NULL; char *pidfile = PIDFILE; char *webroot = WEB_ROOT; @@ -510,26 +511,26 @@ main(int argc, char **argv) int i; int ret; - struct option option_map[] = - { - { "ffid", 1, NULL, 'b' }, - { "debug", 1, NULL, 'd' }, - { "logdomains", 1, NULL, 'D' }, - { "foreground", 0, NULL, 'f' }, - { "config", 1, NULL, 'c' }, - { "pidfile", 1, NULL, 'P' }, - { "version", 0, NULL, 'v' }, - { "webroot", 1, NULL, 'w' }, - { "sqliteext", 1, NULL, 's' }, - { "testrun", 0, NULL, 't' }, // Used for CI, not documented to user + struct option option_map[] = { + { "ffid", 1, NULL, 'b' }, + { "debug", 1, NULL, 'd' }, + { "logdomains", 1, NULL, 'D' }, + { "foreground", 0, NULL, 'f' }, + { "config", 1, NULL, 'c' }, + { "pidfile", 1, NULL, 'P' }, + { "version", 0, NULL, 'v' }, + { "webroot", 1, NULL, 'w' }, + { "sqliteext", 1, NULL, 's' }, + { "testrun", 0, NULL, 't' }, // Used for CI, not documented to user - { "mdns-no-rsp", 0, NULL, 512 }, - { "mdns-no-daap", 0, NULL, 513 }, - { "mdns-no-cname",0, NULL, 514 }, - { "mdns-no-web", 0, NULL, 515 }, + { "mdns-no-rsp", 0, NULL, 512 }, + { "mdns-no-daap", 0, NULL, 513 }, + { "mdns-no-cname", 0, NULL, 514 }, + { "mdns-no-web", 0, NULL, 515 }, + { "logformat", 1, NULL, 516 }, - { NULL, 0, NULL, 0 } - }; + { NULL, 0, NULL, 0 } + }; while ((option = getopt_long(argc, argv, "D:d:c:P:ftb:vw:s:", option_map, NULL)) != -1) { @@ -551,6 +552,10 @@ main(int argc, char **argv) mdns_no_web = true; break; + case 516: + logformat = optarg; + break; + case 't': testrun = true; break; @@ -603,7 +608,7 @@ main(int argc, char **argv) } } - ret = logger_init(NULL, NULL, (loglevel < 0) ? E_LOG : loglevel); + ret = logger_init(NULL, NULL, (loglevel < 0) ? E_LOG : loglevel, NULL); if (ret != 0) { fprintf(stderr, "Could not initialize log facility\n"); @@ -625,10 +630,11 @@ main(int argc, char **argv) /* Reinit log facility with configfile values */ if (loglevel < 0) loglevel = cfg_getint(cfg_getsec(cfg, "general"), "loglevel"); - + if (!logformat) + logformat = cfg_getstr(cfg_getsec(cfg, "general"), "logformat"); logfile = cfg_getstr(cfg_getsec(cfg, "general"), "logfile"); - ret = logger_init(logfile, logdomains, loglevel); + ret = logger_init(logfile, logdomains, loglevel, logformat); if (ret != 0) { fprintf(stderr, "Could not reinitialize log facility with config file settings\n");