#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 char *ident = NULL; /* in local charset format */
static pa_log_target target = { PA_LOG_STDERR, NULL };
static pa_log_target_type_t target_override;
-static pa_bool_t target_override_set = FALSE;
+static bool target_override_set = false;
static pa_log_level_t maximum_level = PA_LOG_ERROR, maximum_level_override = PA_LOG_ERROR;
static unsigned show_backtrace = 0, show_backtrace_override = 0, skip_backtrace = 0;
static pa_log_flags_t flags = 0, flags_override = 0;
-static pa_bool_t no_rate_limit = FALSE;
+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:
if (version > LOG_MAX_SUFFIX_NUMBER) {
pa_log(_("Tried to open target file '%s', '%s.1', '%s.2' ... '%s.%d', but all failed."),
- file_path, file_path, file_path, file_path, LOG_MAX_SUFFIX_NUMBER);
+ t->file, t->file, t->file, t->file, LOG_MAX_SUFFIX_NUMBER);
pa_xfree(file_path);
return -1;
} else
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;
}
if (getenv(ENV_LOG_SYSLOG)) {
target_override = PA_LOG_SYSLOG;
- target_override_set = TRUE;
+ target_override_set = true;
}
if ((e = getenv(ENV_LOG_LEVEL))) {
}
if (getenv(ENV_LOG_NO_RATELIMIT))
- no_rate_limit = TRUE;
+ no_rate_limit = true;
} 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,
pa_vsnprintf(text, sizeof(text), format, ap);
if ((_flags & PA_LOG_PRINT_META) && file && line > 0 && func)
- pa_snprintf(location, sizeof(location), "[%s][%s:%i %s()] ", pa_thread_get_name(pa_thread_self()), file, line, func);
+ pa_snprintf(location, sizeof(location), "[%s][%s:%i %s()] ",
+ pa_strnull(pa_thread_get_name(pa_thread_self())), file, line, func);
else if ((_flags & (PA_LOG_PRINT_META|PA_LOG_PRINT_FILE)) && file)
- pa_snprintf(location, sizeof(location), "[%s] %s: ", pa_thread_get_name(pa_thread_self()), pa_path_get_filename(file));
+ pa_snprintf(location, sizeof(location), "[%s] %s: ",
+ pa_strnull(pa_thread_get_name(pa_thread_self())), pa_path_get_filename(file));
else
location[0] = 0;
}
#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:
va_end(ap);
}
-pa_bool_t pa_log_ratelimit(pa_log_level_t level) {
+bool pa_log_ratelimit(pa_log_level_t level) {
/* Not more than 10 messages every 5s */
static PA_DEFINE_RATELIMIT(ratelimit, 5 * PA_USEC_PER_SEC, 10);
init_defaults();
if (no_rate_limit)
- return TRUE;
+ return true;
return pa_ratelimit_test(&ratelimit, level);
}
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;