diff --git a/NEWS b/NEWS index fa56bd244..9ceeae55e 100644 --- a/NEWS +++ b/NEWS @@ -6,6 +6,7 @@ ver 0.15 - (200?/??/??) * Add RVA2 tag support * the option "error_file" was removed, all messages are logged into "log_file" +* support logging to syslog ver 0.14 (2008/12/25) * audio outputs: diff --git a/configure.ac b/configure.ac index 37085d475..864eb1184 100644 --- a/configure.ac +++ b/configure.ac @@ -54,6 +54,21 @@ if test -z "$prefix" || test "x$prefix" = xNONE; then fi +dnl +dnl libc features +dnl + +AC_CHECK_FUNCS(syslog) +if test $ac_cv_func_syslog = no; then + # syslog is not in the default libraries. See if it's in some other. + for lib in bsd socket inet; do + AC_CHECK_LIB($lib, syslog, + [AC_DEFINE(HAVE_SYSLOG) + LIBS="$LIBS -l$lib"; break]) + done +fi + + dnl dnl build options dnl diff --git a/doc/mpd.conf.5 b/doc/mpd.conf.5 index fc31c7e67..5feefc36e 100644 --- a/doc/mpd.conf.5 +++ b/doc/mpd.conf.5 @@ -51,6 +51,7 @@ This specifies where the db file will be stored. .TP .B log_file This specifies where the log file should be located. +The special value "syslog" makes MPD use the local syslog daemon. .SH OPTIONAL PARAMETERS .TP .B pid_file diff --git a/doc/mpdconf.example b/doc/mpdconf.example index 797549da4..2de2e05e5 100644 --- a/doc/mpdconf.example +++ b/doc/mpdconf.example @@ -25,6 +25,10 @@ db_file "~/.mpd/database" # These logs are great for troubleshooting, depending on your log_level # settings. # +# The special value "syslog" makes MPD use the local syslog daemon. +# On most systems, log messages will appear in /var/log/daemon.log +# then. +# log_file "~/.mpd/log" ############################################################################### diff --git a/src/log.c b/src/log.c index fdb470447..9797abe71 100644 --- a/src/log.c +++ b/src/log.c @@ -18,6 +18,8 @@ #include "log.h" #include "conf.h" +#include "utils.h" +#include "config.h" #include #include @@ -33,6 +35,10 @@ #include #include +#ifdef HAVE_SYSLOG +#include +#endif + #define LOG_LEVEL_SECURE G_LOG_LEVEL_INFO #define LOG_DATE_BUF_SIZE 16 @@ -119,6 +125,68 @@ log_init_file(const char *path, unsigned line) g_log_set_default_handler(file_log_func, NULL); } +#ifdef HAVE_SYSLOG + +static int +glib_to_syslog_level(GLogLevelFlags log_level) +{ + switch (log_level & G_LOG_LEVEL_MASK) { + case G_LOG_LEVEL_ERROR: + case G_LOG_LEVEL_CRITICAL: + return LOG_ERR; + + case G_LOG_LEVEL_WARNING: + return LOG_WARNING; + + case G_LOG_LEVEL_MESSAGE: + return LOG_NOTICE; + + case G_LOG_LEVEL_INFO: + return LOG_INFO; + + case G_LOG_LEVEL_DEBUG: + return LOG_DEBUG; + + default: + return LOG_NOTICE; + } +} + +static void +syslog_log_func(const gchar *log_domain, + GLogLevelFlags log_level, const gchar *message, + G_GNUC_UNUSED gpointer user_data) +{ + if (stdout_mode) { + /* fall back to the file log function during + startup */ + file_log_func(log_domain, log_level, + message, user_data); + return; + } + + if (log_level > log_threshold) + return; + + if (log_domain == NULL) + log_domain = ""; + + syslog(glib_to_syslog_level(log_level), "%s%s%s", + log_domain, *log_domain == 0 ? "" : ": ", + message); +} + +static void +log_init_syslog(void) +{ + assert(out_filename == NULL); + + openlog(PACKAGE, 0, LOG_DAEMON); + g_log_set_default_handler(syslog_log_func, NULL); +} + +#endif + static inline GLogLevelFlags parse_log_level(const char *value, unsigned line) { @@ -147,8 +215,31 @@ void log_init(bool verbose, bool use_stdout) if (use_stdout) { log_init_stdout(); } else { - param = parseConfigFilePath(CONF_LOG_FILE, 1); - log_init_file(param->value, param->line); + param = getConfigParam(CONF_LOG_FILE); + if (param == NULL) { +#ifdef HAVE_SYSLOG + /* no configuration: default to syslog (if + available) */ + log_init_syslog(); +#else + FATAL("config parameter \"%s\" not found\n", + CONF_LOG_FILE); +#endif +#ifdef HAVE_SYSLOG + } else if (strcmp(param->value, "syslog") == 0) { + log_init_syslog(); +#endif + } else { + char *path = parsePath(param->value); + g_free(param->value); + + if (path == NULL) + FATAL("error parsing \"%s\" at line %i\n", + CONF_LOG_FILE, param->line); + param->value = path; + + log_init_file(param->value, param->line); + } } } @@ -156,7 +247,8 @@ void setup_log_output(bool use_stdout) { fflush(NULL); if (!use_stdout) { - redirect_logs(); + if (out_filename != NULL) + redirect_logs(); stdout_mode = false; log_charset = NULL; } @@ -192,7 +284,7 @@ G_GNUC_PRINTF(1, 2) G_GNUC_NORETURN void FATAL(const char *fmt, ...) int cycle_log_files(void) { - if (stdout_mode) + if (stdout_mode || out_filename == NULL) return 0; assert(out_filename); @@ -214,7 +306,12 @@ void close_log_files(void) { if (stdout_mode) return; - assert(out_fd >= 0); - close(out_fd); + + if (out_filename == NULL) + closelog(); + else { + assert(out_fd >= 0); + close(out_fd); + } }