From: Mike Brady Date: Thu, 28 May 2020 11:19:59 +0000 (+0100) Subject: Add the ability to direct logs etc. to a file or pipe. X-Git-Tag: 3.3.7d12~72 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c0e5d0473ecdff35386af98abd091bff4a8f56e2;p=thirdparty%2Fshairport-sync.git Add the ability to direct logs etc. to a file or pipe. --- diff --git a/common.c b/common.c index bb824ca6..f10ef7bf 100644 --- a/common.c +++ b/common.c @@ -41,6 +41,7 @@ #include #include #include +#include #ifdef COMPILE_FOR_OSX #include @@ -139,8 +140,70 @@ void do_sps_log_to_stdout(__attribute__((unused)) int prio, const char *t, ...) fprintf(stdout, "%s\n", s); } +int create_log_file(const char* path) { + int fd = -1; + if (path != NULL) { + char *dirc = strdup(path); + if (dirc) { + char *dname = dirname(dirc); + // create the directory, if necessary + int result = 0; + if (dname) { + char *pdir = realpath(dname, NULL); // will return a NULL if the directory doesn't exist + if (pdir == NULL) { + mode_t oldumask = umask(000); + result = mkpath(dname, 0777); + umask(oldumask); + } else { + free(pdir); + } + if ((result == 0) || (result == -EEXIST)) { + // now open the file + fd = open(path, O_WRONLY | O_NONBLOCK | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + if ((fd == -1) && (errno == EEXIST)) + fd = open(path, O_WRONLY | O_APPEND | O_NONBLOCK); + + if (fd >= 0) { + // now we switch to blocking mode + int flags = fcntl(fd, F_GETFL); + if ((flags == -1)) { +// strerror_r(errno, (char *)errorstring, sizeof(errorstring)); +// debug(1, "create_log_file -- error %d (\"%s\") getting flags of pipe: \"%s\".", errno, +// (char *)errorstring, pathname); + } else { + flags = fcntl(fd, F_SETFL,flags & ~O_NONBLOCK); +// if (flags == -1) { +// strerror_r(errno, (char *)errorstring, sizeof(errorstring)); +// debug(1, "create_log_file -- error %d (\"%s\") unsetting NONBLOCK of pipe: \"%s\".", errno, +// (char *)errorstring, pathname); + } + } + } + } + free(dirc); + } + } + return fd; +} + +void do_sps_log_to_fd(__attribute__((unused)) int prio, const char *t, ...) { + char s[1024]; + va_list args; + va_start(args, t); + vsnprintf(s, sizeof(s), t, args); + va_end(args); + if (config.log_fd == -1) + config.log_fd = create_log_file(config.log_file_path); + if (config.log_fd >= 0) { + dprintf(config.log_fd, "%s\n", s); + } else if (errno != ENXIO) { // maybe there is a pipe there but not hooked up + fprintf(stderr, "%s\n", s); + } +} + void log_to_stderr() { sps_log = do_sps_log_to_stderr; } void log_to_stdout() { sps_log = do_sps_log_to_stdout; } +void log_to_file() { sps_log = do_sps_log_to_fd; } void log_to_syslog() { #ifdef CONFIG_LIBDAEMON sps_log = daemon_log; diff --git a/common.h b/common.h index df4243a9..3540bcd0 100644 --- a/common.h +++ b/common.h @@ -182,6 +182,8 @@ typedef struct { char *pidfile; #endif + int log_fd; // file descriptor of the file or pipe to log stuff to. + char *log_file_path; // path to file or pipe to log to, if any int logOutputLevel; // log output level int debugger_show_elapsed_time; // in the debug message, display the time since startup int debugger_show_relative_time; // in the debug message, display the time since the last one @@ -298,6 +300,8 @@ void memory_barrier(); void log_to_stderr(); // call this to direct logging to stderr; void log_to_stdout(); // call this to direct logging to stdout; void log_to_syslog(); // call this to direct logging to the system log; +void log_to_file(); // call this to direct logging to a file or (pre-existing) pipe; + // true if Shairport Sync is supposed to be sending output to the output device, false otherwise diff --git a/scripts/shairport-sync.conf b/scripts/shairport-sync.conf index 1b6105cb..efa34996 100644 --- a/scripts/shairport-sync.conf +++ b/scripts/shairport-sync.conf @@ -245,7 +245,7 @@ mqtt = diagnostics = { // disable_resend_requests = "no"; // set this to yes to stop Shairport Sync from requesting the retransmission of missing packets. Default is "no". -// log_output_to = "syslog"; // set this to "syslog" (default), "STDERR" or "STDOUT" to specify were all logs, statistics and diagnostic messages are written to. +// log_output_to = "syslog"; // set this to "syslog" (default), "stderr" or "stdout" or a file or pipe path to specify were all logs, statistics and diagnostic messages are written to. If there's anything wrong with the file spec, output will be to "stderr". // statistics = "no"; // set to "yes" to print statistics in the log // log_verbosity = 0; // "0" means no debug verbosity, "3" is most verbose. // log_show_file_and_line = "yes"; // set this to yes if you want the file and line number of the message source in the log file diff --git a/shairport.c b/shairport.c index fc1643ab..af11ade2 100644 --- a/shairport.c +++ b/shairport.c @@ -671,8 +671,9 @@ int parse_options(int argc, char **argv) { } else if (strcasecmp(str, "stderr") == 0) { log_to_stderr(); } else { - log_to_syslog(); - die("Invalid diagnostics log_output_to setting \"%s\". It should be \"syslog\", \"STDERR\" or \"STDOUT\". It is set to syslog."); + config.log_file_path = (char *)str; + config.log_fd = -1; + log_to_file(); } } /* Get the ignore_volume_control setting. */ @@ -1423,6 +1424,7 @@ int main(int argc, char **argv) { #ifdef CONFIG_LIBDAEMON pid = getpid(); #endif + config.log_fd = -1; conns = NULL; // no connections active memset((void *)&main_thread_id, 0, sizeof(main_thread_id)); memset(&config, 0, sizeof(config)); // also clears all strings, BTW