Specify the log target. If set to auto
(which is the default), then logging is directed to syslog when
--daemonize is passed, otherwise to
- STDERR. If set to file:PATH, logging is directed to
+ STDERR. If set to journal logging is directed to the systemd
+ journal. If set to file:PATH, logging is directed to
the file indicated by PATH. newfile:PATH is otherwise
the same as file:PATH, but existing files are never overwritten.
If the specified file already exists, a suffix is added to the
diff --git a/src/Makefile.am b/src/Makefile.am
index 0296b3c02..c89cd6d3c 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -687,6 +687,11 @@ libpulsecommon_@PA_MAJORMINOR@_la_CFLAGS += $(X11_CFLAGS)
libpulsecommon_@PA_MAJORMINOR@_la_LDFLAGS += $(X11_LIBS)
endif
+if HAVE_SYSTEMD_JOURNAL
+libpulsecommon_@PA_MAJORMINOR@_la_CFLAGS += $(JOURNAL_FLAGS)
+libpulsecommon_@PA_MAJORMINOR@_la_LDFLAGS += $(JOURNAL_LIBS)
+endif
+
# proplist-util.h uses these header files, but not the library itself!
libpulsecommon_@PA_MAJORMINOR@_la_CFLAGS += $(GLIB20_CFLAGS) $(GTK30_CFLAGS)
diff --git a/src/daemon/cmdline.c b/src/daemon/cmdline.c
index 6361a3df5..0fa84920c 100644
--- a/src/daemon/cmdline.c
+++ b/src/daemon/cmdline.c
@@ -323,7 +323,11 @@ int pa_cmdline_parse(pa_daemon_conf *conf, int argc, char *const argv [], int *d
case ARG_LOG_TARGET:
if (pa_daemon_conf_set_log_target(conf, optarg) < 0) {
+#ifdef HAVE_JOURNAL
+ pa_log(_("Invalid log target: use either 'syslog', 'journal','stderr' or 'auto' or a valid file name 'file:', 'newfile:'."));
+#else
pa_log(_("Invalid log target: use either 'syslog', 'stderr' or 'auto' or a valid file name 'file:', 'newfile:'."));
+#endif
goto fail;
}
break;
diff --git a/src/daemon/main.c b/src/daemon/main.c
index 58cacf80e..e01371ed5 100644
--- a/src/daemon/main.c
+++ b/src/daemon/main.c
@@ -817,7 +817,11 @@ int main(int argc, char *argv[]) {
#endif
if (!conf->log_target) {
+#ifdef HAVE_JOURNAL
+ pa_log_target target = { .type = PA_LOG_JOURNAL, .file = NULL };
+#else
pa_log_target target = { .type = PA_LOG_SYSLOG, .file = NULL };
+#endif
pa_log_set_target(&target);
}
diff --git a/src/pulsecore/log.c b/src/pulsecore/log.c
index 55350451a..cf96dcef1 100644
--- a/src/pulsecore/log.c
+++ b/src/pulsecore/log.c
@@ -40,6 +40,10 @@
#include
#endif
+#ifdef HAVE_JOURNAL
+#include
+#endif
+
#include
#include
#include
@@ -90,6 +94,18 @@ static const int level_to_syslog[] = {
};
#endif
+/* These are actually equivalent to the syslog ones
+ * but we don't want to depend on syslog.h */
+#ifdef HAVE_JOURNAL
+static const int level_to_journal[] = {
+ [PA_LOG_ERROR] = 3,
+ [PA_LOG_WARN] = 4,
+ [PA_LOG_NOTICE] = 5,
+ [PA_LOG_INFO] = 6,
+ [PA_LOG_DEBUG] = 7
+};
+#endif
+
static const char level_to_char[] = {
[PA_LOG_ERROR] = 'E',
[PA_LOG_WARN] = 'W',
@@ -129,6 +145,9 @@ int pa_log_set_target(pa_log_target *t) {
switch (t->type) {
case PA_LOG_STDERR:
case PA_LOG_SYSLOG:
+#ifdef HAVE_JOURNAL
+ case PA_LOG_JOURNAL:
+#endif
case PA_LOG_NULL:
break;
case PA_LOG_FILE:
@@ -318,6 +337,20 @@ static void init_defaults(void) {
} PA_ONCE_END;
}
+#ifdef HAVE_SYSLOG_H
+static void log_syslog(pa_log_level_t level, char *t, char *timestamp, char *location, char *bt) {
+ char *local_t;
+
+ openlog(ident, LOG_PID, LOG_USER);
+
+ if ((local_t = pa_utf8_to_locale(t)))
+ t = local_t;
+
+ syslog(level_to_syslog[level], "%s%s%s%s", timestamp, location, t, pa_strempty(bt));
+ pa_xfree(local_t);
+}
+#endif
+
void pa_log_levelv_meta(
pa_log_level_t level,
const char*file,
@@ -450,19 +483,35 @@ void pa_log_levelv_meta(
}
#ifdef HAVE_SYSLOG_H
- case PA_LOG_SYSLOG: {
- char *local_t;
-
- openlog(ident, LOG_PID, LOG_USER);
-
- if ((local_t = pa_utf8_to_locale(t)))
- t = local_t;
-
- syslog(level_to_syslog[level], "%s%s%s%s", timestamp, location, t, pa_strempty(bt));
- pa_xfree(local_t);
-
+ case PA_LOG_SYSLOG:
+ log_syslog(level, t, timestamp, location, bt);
+ break;
+#endif
+
+#ifdef HAVE_JOURNAL
+ case PA_LOG_JOURNAL:
+ if (sd_journal_send("MESSAGE=%s", t,
+ "PRIORITY=%i", level_to_journal[level],
+ "CODE_FILE=%s", file,
+ "CODE_FUNC=%s", func,
+ "CODE_LINE=%d", line,
+ NULL) < 0) {
+#ifdef HAVE_SYSLOG_H
+ pa_log_target new_target = { .type = PA_LOG_SYSLOG, .file = NULL };
+
+ syslog(level_to_syslog[PA_LOG_ERROR], "%s%s%s", timestamp, __FILE__,
+ "Error writing logs to the journal. Redirect log messages to syslog.");
+ log_syslog(level, t, timestamp, location, bt);
+#else
+ pa_log_target new_target = { .type = PA_LOG_STDERR, .file = NULL };
+
+ saved_errno = errno;
+ fprintf(stderr, "%s\n", "Error writing logs to the journal. Redirect log messages to console.");
+ fprintf(stderr, "%s %s\n", metadata, t);
+#endif
+ pa_log_set_target(&new_target);
+ }
break;
- }
#endif
case PA_LOG_FILE:
@@ -570,6 +619,10 @@ pa_log_target *pa_log_parse_target(const char *string) {
t = pa_log_target_new(PA_LOG_STDERR, NULL);
else if (pa_streq(string, "syslog"))
t = pa_log_target_new(PA_LOG_SYSLOG, NULL);
+#ifdef HAVE_JOURNAL
+ else if (pa_streq(string, "journal"))
+ t = pa_log_target_new(PA_LOG_JOURNAL, NULL);
+#endif
else if (pa_streq(string, "null"))
t = pa_log_target_new(PA_LOG_NULL, NULL);
else if (pa_startswith(string, "file:"))
@@ -594,6 +647,11 @@ char *pa_log_target_to_string(const pa_log_target *t) {
case PA_LOG_SYSLOG:
string = pa_xstrdup("syslog");
break;
+#ifdef HAVE_JOURNAL
+ case PA_LOG_JOURNAL:
+ string = pa_xstrdup("journal");
+ break;
+#endif
case PA_LOG_NULL:
string = pa_xstrdup("null");
break;
diff --git a/src/pulsecore/log.h b/src/pulsecore/log.h
index e7dca88c8..5e9611d6a 100644
--- a/src/pulsecore/log.h
+++ b/src/pulsecore/log.h
@@ -35,6 +35,9 @@
typedef enum pa_log_target_type {
PA_LOG_STDERR, /* default */
PA_LOG_SYSLOG,
+#ifdef HAVE_JOURNAL
+ PA_LOG_JOURNAL, /* systemd journal */
+#endif
PA_LOG_NULL, /* to /dev/null */
PA_LOG_FILE, /* to a user specified file */
PA_LOG_NEWFILE, /* with an automatic suffix to avoid overwriting anything */