log: support syslog()

Allow logging to syslog if log_file is configured to "syslog".
This commit is contained in:
Max Kellermann 2008-12-28 19:48:53 +01:00
parent c6cb611065
commit c01aa53e6a
5 changed files with 124 additions and 6 deletions

1
NEWS
View File

@ -6,6 +6,7 @@ ver 0.15 - (200?/??/??)
* Add RVA2 tag support * Add RVA2 tag support
* the option "error_file" was removed, all messages are logged into * the option "error_file" was removed, all messages are logged into
"log_file" "log_file"
* support logging to syslog
ver 0.14 (2008/12/25) ver 0.14 (2008/12/25)
* audio outputs: * audio outputs:

View File

@ -54,6 +54,21 @@ if test -z "$prefix" || test "x$prefix" = xNONE; then
fi 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
dnl build options dnl build options
dnl dnl

View File

@ -51,6 +51,7 @@ This specifies where the db file will be stored.
.TP .TP
.B log_file <file> .B log_file <file>
This specifies where the log file should be located. This specifies where the log file should be located.
The special value "syslog" makes MPD use the local syslog daemon.
.SH OPTIONAL PARAMETERS .SH OPTIONAL PARAMETERS
.TP .TP
.B pid_file <file> .B pid_file <file>

View File

@ -25,6 +25,10 @@ db_file "~/.mpd/database"
# These logs are great for troubleshooting, depending on your log_level # These logs are great for troubleshooting, depending on your log_level
# settings. # 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" log_file "~/.mpd/log"
############################################################################### ###############################################################################

109
src/log.c
View File

@ -18,6 +18,8 @@
#include "log.h" #include "log.h"
#include "conf.h" #include "conf.h"
#include "utils.h"
#include "config.h"
#include <assert.h> #include <assert.h>
#include <sys/types.h> #include <sys/types.h>
@ -33,6 +35,10 @@
#include <pthread.h> #include <pthread.h>
#include <glib.h> #include <glib.h>
#ifdef HAVE_SYSLOG
#include <syslog.h>
#endif
#define LOG_LEVEL_SECURE G_LOG_LEVEL_INFO #define LOG_LEVEL_SECURE G_LOG_LEVEL_INFO
#define LOG_DATE_BUF_SIZE 16 #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); 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 static inline GLogLevelFlags
parse_log_level(const char *value, unsigned line) parse_log_level(const char *value, unsigned line)
{ {
@ -147,8 +215,31 @@ void log_init(bool verbose, bool use_stdout)
if (use_stdout) { if (use_stdout) {
log_init_stdout(); log_init_stdout();
} else { } else {
param = parseConfigFilePath(CONF_LOG_FILE, 1); param = getConfigParam(CONF_LOG_FILE);
log_init_file(param->value, param->line); 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); fflush(NULL);
if (!use_stdout) { if (!use_stdout) {
redirect_logs(); if (out_filename != NULL)
redirect_logs();
stdout_mode = false; stdout_mode = false;
log_charset = NULL; 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) int cycle_log_files(void)
{ {
if (stdout_mode) if (stdout_mode || out_filename == NULL)
return 0; return 0;
assert(out_filename); assert(out_filename);
@ -214,7 +306,12 @@ void close_log_files(void)
{ {
if (stdout_mode) if (stdout_mode)
return; return;
assert(out_fd >= 0);
close(out_fd); if (out_filename == NULL)
closelog();
else {
assert(out_fd >= 0);
close(out_fd);
}
} }