2 This file is part of PulseAudio.
4 Copyright 2004-2006 Lennart Poettering
5 Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
7 PulseAudio is free software; you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as
9 published by the Free Software Foundation; either version 2.1 of the
10 License, or (at your option) any later version.
12 PulseAudio is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public
18 License along with PulseAudio; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
33 #ifdef HAVE_EXECINFO_H
41 #include <pulse/gccmacro.h>
42 #include <pulse/rtclock.h>
43 #include <pulse/utf8.h>
44 #include <pulse/xmalloc.h>
45 #include <pulse/util.h>
46 #include <pulse/timeval.h>
48 #include <pulsecore/macro.h>
49 #include <pulsecore/core-util.h>
50 #include <pulsecore/once.h>
51 #include <pulsecore/ratelimit.h>
52 #include <pulsecore/thread.h>
58 #define DLOG_TAG "PULSEAUDIO"
60 #define COLOR_BLACK 30
62 #define COLOR_GREEN 32
64 #define COLOR_MAGENTA 35
66 #define COLOR_WHITE 97
67 #define COLOR_B_GRAY 100
68 #define COLOR_B_RED 101
69 #define COLOR_B_GREEN 102
70 #define COLOR_B_YELLOW 103
71 #define COLOR_B_BLUE 104
72 #define COLOR_B_MAGENTA 105
73 #define COLOR_B_CYAN 106
74 #define COLOR_REVERSE 7
78 #define ENV_LOG_SYSLOG "PULSE_LOG_SYSLOG"
79 #define ENV_LOG_LEVEL "PULSE_LOG"
80 #define ENV_LOG_COLORS "PULSE_LOG_COLORS"
81 #define ENV_LOG_PRINT_TIME "PULSE_LOG_TIME"
82 #define ENV_LOG_PRINT_FILE "PULSE_LOG_FILE"
83 #define ENV_LOG_PRINT_META "PULSE_LOG_META"
84 #define ENV_LOG_PRINT_LEVEL "PULSE_LOG_LEVEL"
85 #define ENV_LOG_BACKTRACE "PULSE_LOG_BACKTRACE"
86 #define ENV_LOG_BACKTRACE_SKIP "PULSE_LOG_BACKTRACE_SKIP"
87 #define ENV_LOG_NO_RATELIMIT "PULSE_LOG_NO_RATE_LIMIT"
89 static char *ident = NULL; /* in local charset format */
90 static pa_log_target_t target = PA_LOG_STDERR, target_override;
91 static pa_bool_t target_override_set = FALSE;
92 static pa_log_level_t maximum_level = PA_LOG_ERROR, maximum_level_override = PA_LOG_ERROR;
93 static unsigned show_backtrace = 0, show_backtrace_override = 0, skip_backtrace = 0;
94 static pa_log_flags_t flags = 0, flags_override = 0;
95 static pa_bool_t no_rate_limit = FALSE;
96 static int log_fd = -1;
99 static const int level_to_syslog[] = {
100 [PA_LOG_ERROR] = LOG_ERR,
101 [PA_LOG_WARN] = LOG_WARNING,
102 [PA_LOG_NOTICE] = LOG_NOTICE,
103 [PA_LOG_INFO] = LOG_INFO,
104 [PA_LOG_DEBUG] = LOG_DEBUG
108 static const char level_to_char[] = {
109 [PA_LOG_ERROR] = 'E',
111 [PA_LOG_NOTICE] = 'N',
116 void pa_log_set_ident(const char *p) {
119 if (!(ident = pa_utf8_to_locale(p)))
120 ident = pa_ascii_filter(p);
123 /* To make valgrind shut up. */
124 static void ident_destructor(void) PA_GCC_DESTRUCTOR;
125 static void ident_destructor(void) {
126 if (!pa_in_valgrind())
132 void pa_log_set_level(pa_log_level_t l) {
133 pa_assert(l < PA_LOG_LEVEL_MAX);
138 void pa_log_set_target(pa_log_target_t t) {
139 pa_assert(t < PA_LOG_TARGET_MAX);
144 void pa_log_set_flags(pa_log_flags_t _flags, pa_log_merge_t merge) {
145 pa_assert(!(_flags & ~(PA_LOG_COLORS|PA_LOG_PRINT_TIME|PA_LOG_PRINT_FILE|PA_LOG_PRINT_META|PA_LOG_PRINT_LEVEL)));
147 if (merge == PA_LOG_SET)
149 else if (merge == PA_LOG_UNSET)
155 void pa_log_set_fd(int fd) {
158 else if (log_fd >= 0) {
164 void pa_log_set_show_backtrace(unsigned nlevels) {
165 show_backtrace = nlevels;
168 void pa_log_set_skip_backtrace(unsigned nlevels) {
169 skip_backtrace = nlevels;
172 #ifdef HAVE_EXECINFO_H
174 static char* get_backtrace(unsigned show_nframes) {
177 char **symbols, *e, *r;
181 pa_assert(show_nframes > 0);
183 n_frames = backtrace(trace, PA_ELEMENTSOF(trace));
188 symbols = backtrace_symbols(trace, n_frames);
194 n = PA_MIN((unsigned) n_frames, s + show_nframes);
198 for (j = s; j < n; j++) {
201 a += strlen(pa_path_get_filename(symbols[j]));
204 r = pa_xnew(char, a);
209 for (j = s; j < n; j++) {
217 sym = pa_path_get_filename(symbols[j]);
232 static void init_defaults(void) {
239 if (pa_get_binary_name(binary, sizeof(binary)))
240 pa_log_set_ident(binary);
243 if (getenv(ENV_LOG_SYSLOG)) {
244 target_override = PA_LOG_SYSLOG;
245 target_override_set = TRUE;
248 if ((e = getenv(ENV_LOG_LEVEL))) {
249 maximum_level_override = (pa_log_level_t) atoi(e);
251 if (maximum_level_override >= PA_LOG_LEVEL_MAX)
252 maximum_level_override = PA_LOG_LEVEL_MAX-1;
255 if (getenv(ENV_LOG_COLORS))
256 flags_override |= PA_LOG_COLORS;
258 if (getenv(ENV_LOG_PRINT_TIME))
259 flags_override |= PA_LOG_PRINT_TIME;
261 if (getenv(ENV_LOG_PRINT_FILE))
262 flags_override |= PA_LOG_PRINT_FILE;
264 if (getenv(ENV_LOG_PRINT_META))
265 flags_override |= PA_LOG_PRINT_META;
267 if (getenv(ENV_LOG_PRINT_LEVEL))
268 flags_override |= PA_LOG_PRINT_LEVEL;
270 if ((e = getenv(ENV_LOG_BACKTRACE))) {
271 show_backtrace_override = (unsigned) atoi(e);
273 if (show_backtrace_override <= 0)
274 show_backtrace_override = 0;
277 if ((e = getenv(ENV_LOG_BACKTRACE_SKIP))) {
278 skip_backtrace = (unsigned) atoi(e);
280 if (skip_backtrace <= 0)
284 if (getenv(ENV_LOG_NO_RATELIMIT))
285 no_rate_limit = TRUE;
290 void pa_log_levelv_meta(
291 pa_log_level_t level,
299 int saved_errno = errno;
301 pa_log_target_t _target;
302 pa_log_level_t _maximum_level;
303 unsigned _show_backtrace;
304 pa_log_flags_t _flags;
306 /* We don't use dynamic memory allocation here to minimize the hit
308 char text[16*1024], location[128], timestamp[32];
310 pa_assert(level < PA_LOG_LEVEL_MAX);
315 _target = target_override_set ? target_override : target;
316 _maximum_level = PA_MAX(maximum_level, maximum_level_override);
317 _show_backtrace = PA_MAX(show_backtrace, show_backtrace_override);
318 _flags = flags | flags_override;
320 if (PA_LIKELY(level > _maximum_level)) {
325 pa_vsnprintf(text, sizeof(text), format, ap);
327 if ((_flags & PA_LOG_PRINT_META) && file && line > 0 && func)
328 pa_snprintf(location, sizeof(location), "[%s][%s:%i %s()] ", pa_thread_get_name(pa_thread_self()), file, line, func);
329 else if ((_flags & (PA_LOG_PRINT_META|PA_LOG_PRINT_FILE)) && file)
330 pa_snprintf(location, sizeof(location), "[%s] %s: ", pa_thread_get_name(pa_thread_self()), pa_path_get_filename(file));
334 if (_flags & PA_LOG_PRINT_TIME) {
335 static pa_usec_t start, last;
338 u = pa_rtclock_now();
348 /* This is not thread safe, but this is a debugging tool only
352 pa_snprintf(timestamp, sizeof(timestamp), "(%4llu.%03llu|%4llu.%03llu) ",
353 (unsigned long long) (a / PA_USEC_PER_SEC),
354 (unsigned long long) (((a / PA_USEC_PER_MSEC)) % 1000),
355 (unsigned long long) (r / PA_USEC_PER_SEC),
356 (unsigned long long) (((r / PA_USEC_PER_MSEC)) % 1000));
361 #ifdef HAVE_EXECINFO_H
362 if (_show_backtrace > 0)
363 bt = get_backtrace(_show_backtrace);
366 if (!pa_utf8_valid(text))
367 pa_logl(level, "Invalid UTF-8 string following below:");
369 for (t = text; t; t = n) {
370 if ((n = strchr(t, '\n'))) {
375 /* We ignore strings only made out of whitespace */
376 if (t[strspn(t, "\t ")] == 0)
381 case PA_LOG_STDERR: {
382 const char *prefix = "", *suffix = "", *grey = "";
386 /* Yes indeed. Useless, but fun! */
387 if ((_flags & PA_LOG_COLORS) && isatty(STDERR_FILENO)) {
388 if (level <= PA_LOG_ERROR)
389 prefix = "\x1B[1;31m";
390 else if (level <= PA_LOG_WARN)
396 if (grey[0] || prefix[0])
401 /* We shouldn't be using dynamic allocation here to
402 * minimize the hit in RT threads */
403 if ((local_t = pa_utf8_to_locale(t)))
406 if (_flags & PA_LOG_PRINT_LEVEL)
407 fprintf(stderr, "%s%c: %s%s%s%s%s%s\n", timestamp, level_to_char[level], location, prefix, t, grey, pa_strempty(bt), suffix);
409 fprintf(stderr, "%s%s%s%s%s%s%s\n", timestamp, location, prefix, t, grey, pa_strempty(bt), suffix);
420 case PA_LOG_SYSLOG: {
423 openlog(ident, LOG_PID, LOG_USER);
425 if ((local_t = pa_utf8_to_locale(t)))
428 syslog(level_to_syslog[level], "%s%s%s%s", timestamp, location, t, pa_strempty(bt));
439 pa_snprintf(metadata, sizeof(metadata), "\n%c %s %s", level_to_char[level], timestamp, location);
441 if ((write(log_fd, metadata, strlen(metadata)) < 0) || (write(log_fd, t, strlen(t)) < 0)) {
444 fprintf(stderr, "%s\n", "Error writing logs to a file descriptor. Redirect log messages to console.");
445 fprintf(stderr, "%s %s\n", metadata, t);
446 pa_log_set_target(PA_LOG_STDERR);
456 openlog(ident, LOG_PID, LOG_USER);
458 if ((local_t = pa_utf8_to_locale(t)))
464 SLOG (LOG_DEBUG, DLOG_TAG, "%s%s%s%s", timestamp, location, t, pa_strempty(bt));
467 case PA_LOG_NOTICE: // no notice category in dlog, use info instead.
468 SLOG (LOG_INFO, DLOG_TAG, "%s%s%s%s", timestamp, location, t, pa_strempty(bt));
471 SLOG (LOG_WARN, DLOG_TAG, "%s%s%s%s", timestamp, location, t, pa_strempty(bt));
474 SLOG (LOG_ERROR, DLOG_TAG, "%s%s%s%s", timestamp, location, t, pa_strempty(bt));
477 SLOG (LOG_DEBUG, DLOG_TAG, "%s%s%s%s", timestamp, location, t, pa_strempty(bt));
485 case PA_LOG_DLOG_COLOR: {
488 openlog(ident, LOG_PID, LOG_USER);
490 if ((local_t = pa_utf8_to_locale(t)))
496 SLOG (LOG_DEBUG, DLOG_TAG, "\033[%dm%s%s%s%s\033[0m", COLOR_GREEN, timestamp, location, t, pa_strempty(bt));
499 case PA_LOG_NOTICE: // no notice category in dlog, use info instead.
500 SLOG (LOG_INFO, DLOG_TAG, "\033[%dm%s%s%s%s\033[0m", COLOR_BLUE, timestamp, location, t, pa_strempty(bt));
503 SLOG (LOG_WARN, DLOG_TAG, "\033[%dm%s%s%s%s\033[0m", COLOR_MAGENTA, timestamp, location, t, pa_strempty(bt));
506 SLOG (LOG_ERROR, DLOG_TAG, "\033[%dm%s%s%s%s\033[0m", COLOR_RED, timestamp, location, t, pa_strempty(bt));
509 SLOG (LOG_DEBUG, DLOG_TAG, "%s%s%s%s", timestamp, location, t, pa_strempty(bt));
529 void pa_log_level_meta(
530 pa_log_level_t level,
534 const char *format, ...) {
537 va_start(ap, format);
538 pa_log_levelv_meta(level, file, line, func, format, ap);
542 void pa_log_levelv(pa_log_level_t level, const char *format, va_list ap) {
543 pa_log_levelv_meta(level, NULL, 0, NULL, format, ap);
546 void pa_log_level(pa_log_level_t level, const char *format, ...) {
549 va_start(ap, format);
550 pa_log_levelv_meta(level, NULL, 0, NULL, format, ap);
554 pa_bool_t pa_log_ratelimit(pa_log_level_t level) {
555 /* Not more than 10 messages every 5s */
556 static PA_DEFINE_RATELIMIT(ratelimit, 5 * PA_USEC_PER_SEC, 10);
563 return pa_ratelimit_test(&ratelimit, level);