#include <string.h>
#include <errno.h>
#include <fcntl.h>
+#include <sys/stat.h>
#ifdef HAVE_EXECINFO_H
#include <execinfo.h>
#include <syslog.h>
#endif
+#ifdef HAVE_JOURNAL
+#include <systemd/sd-journal.h>
+#endif
+
#include <pulse/gccmacro.h>
#include <pulse/rtclock.h>
#include <pulse/utf8.h>
static pa_log_flags_t flags = 0, flags_override = 0;
static bool no_rate_limit = false;
static int log_fd = -1;
+static int write_type = 0;
#ifdef HAVE_SYSLOG_H
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',
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:
flags = _flags;
}
-void pa_log_set_fd(int fd) {
- if (fd >= 0)
- log_fd = fd;
- else if (log_fd >= 0) {
- pa_close(log_fd);
- log_fd = -1;
- }
-}
-
void pa_log_set_show_backtrace(unsigned nlevels) {
show_backtrace = nlevels;
}
} 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,
}
#ifdef HAVE_SYSLOG_H
- case PA_LOG_SYSLOG: {
- char *local_t;
-
- openlog(ident, LOG_PID, LOG_USER);
+ case PA_LOG_SYSLOG:
+ log_syslog(level, t, timestamp, location, bt);
+ break;
+#endif
- if ((local_t = pa_utf8_to_locale(t)))
- t = local_t;
+#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[level], "%s%s%s%s", timestamp, location, t, pa_strempty(bt));
- pa_xfree(local_t);
+ 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:
case PA_LOG_NEWFILE: {
+ char *local_t;
+
+ if ((local_t = pa_utf8_to_locale(t)))
+ t = local_t;
+
if (log_fd >= 0) {
char metadata[256];
- pa_snprintf(metadata, sizeof(metadata), "\n%c %s %s", level_to_char[level], timestamp, location);
+ if (_flags & PA_LOG_PRINT_LEVEL)
+ pa_snprintf(metadata, sizeof(metadata), "%s%c: %s", timestamp, level_to_char[level], location);
+ else
+ pa_snprintf(metadata, sizeof(metadata), "%s%s", timestamp, location);
- if ((write(log_fd, metadata, strlen(metadata)) < 0) || (write(log_fd, t, strlen(t)) < 0)) {
+ if ((pa_write(log_fd, metadata, strlen(metadata), &write_type) < 0)
+ || (pa_write(log_fd, t, strlen(t), &write_type) < 0)
+ || (bt && pa_write(log_fd, bt, strlen(bt), &write_type) < 0)
+ || (pa_write(log_fd, "\n", 1, &write_type) < 0)) {
pa_log_target new_target = { .type = PA_LOG_STDERR, .file = NULL };
saved_errno = errno;
- pa_log_set_fd(-1);
fprintf(stderr, "%s\n", "Error writing logs to a file descriptor. Redirect log messages to console.");
fprintf(stderr, "%s %s\n", metadata, t);
pa_log_set_target(&new_target);
}
}
+ pa_xfree(local_t);
+
break;
}
case PA_LOG_NULL:
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:"))
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;