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/rtclock.h>
42 #include <pulse/utf8.h>
43 #include <pulse/xmalloc.h>
44 #include <pulse/util.h>
45 #include <pulse/timeval.h>
47 #include <pulsecore/macro.h>
48 #include <pulsecore/core-util.h>
49 #include <pulsecore/core-rtclock.h>
50 #include <pulsecore/once.h>
51 #include <pulsecore/ratelimit.h>
57 #define DLOG_TAG "PULSEAUDIO"
59 #define COLOR_BLACK 30
61 #define COLOR_GREEN 32
63 #define COLOR_MAGENTA 35
65 #define COLOR_WHITE 97
66 #define COLOR_B_GRAY 100
67 #define COLOR_B_RED 101
68 #define COLOR_B_GREEN 102
69 #define COLOR_B_YELLOW 103
70 #define COLOR_B_BLUE 104
71 #define COLOR_B_MAGENTA 105
72 #define COLOR_B_CYAN 106
73 #define COLOR_REVERSE 7
77 #define ENV_LOG_SYSLOG "PULSE_LOG_SYSLOG"
78 #define ENV_LOG_LEVEL "PULSE_LOG"
79 #define ENV_LOG_COLORS "PULSE_LOG_COLORS"
80 #define ENV_LOG_PRINT_TIME "PULSE_LOG_TIME"
81 #define ENV_LOG_PRINT_FILE "PULSE_LOG_FILE"
82 #define ENV_LOG_PRINT_META "PULSE_LOG_META"
83 #define ENV_LOG_PRINT_LEVEL "PULSE_LOG_LEVEL"
84 #define ENV_LOG_BACKTRACE "PULSE_LOG_BACKTRACE"
85 #define ENV_LOG_BACKTRACE_SKIP "PULSE_LOG_BACKTRACE_SKIP"
87 static char *ident = NULL; /* in local charset format */
88 static pa_log_target_t target = PA_LOG_STDERR, target_override;
89 static pa_bool_t target_override_set = FALSE;
90 static pa_log_level_t maximum_level = PA_LOG_ERROR, maximum_level_override = PA_LOG_ERROR;
91 static unsigned show_backtrace = 0, show_backtrace_override = 0, skip_backtrace = 0;
92 static pa_log_flags_t flags = 0, flags_override = 0;
95 static const int level_to_syslog[] = {
96 [PA_LOG_ERROR] = LOG_ERR,
97 [PA_LOG_WARN] = LOG_WARNING,
98 [PA_LOG_NOTICE] = LOG_NOTICE,
99 [PA_LOG_INFO] = LOG_INFO,
100 [PA_LOG_DEBUG] = LOG_DEBUG
104 static const char level_to_char[] = {
105 [PA_LOG_ERROR] = 'E',
107 [PA_LOG_NOTICE] = 'N',
112 void pa_log_set_ident(const char *p) {
115 if (!(ident = pa_utf8_to_locale(p)))
116 ident = pa_ascii_filter(p);
119 /* To make valgrind shut up. */
120 static void ident_destructor(void) PA_GCC_DESTRUCTOR;
121 static void ident_destructor(void) {
122 if (!pa_in_valgrind())
128 void pa_log_set_level(pa_log_level_t l) {
129 pa_assert(l < PA_LOG_LEVEL_MAX);
134 void pa_log_set_target(pa_log_target_t t) {
135 pa_assert(t < PA_LOG_TARGET_MAX);
140 void pa_log_set_flags(pa_log_flags_t _flags, pa_log_merge_t merge) {
141 pa_assert(!(_flags & ~(PA_LOG_COLORS|PA_LOG_PRINT_TIME|PA_LOG_PRINT_FILE|PA_LOG_PRINT_META|PA_LOG_PRINT_LEVEL)));
143 if (merge == PA_LOG_SET)
145 else if (merge == PA_LOG_UNSET)
151 void pa_log_set_show_backtrace(unsigned nlevels) {
152 show_backtrace = nlevels;
155 void pa_log_set_skip_backtrace(unsigned nlevels) {
156 skip_backtrace = nlevels;
159 #ifdef HAVE_EXECINFO_H
161 static char* get_backtrace(unsigned show_nframes) {
164 char **symbols, *e, *r;
168 pa_assert(show_nframes > 0);
170 n_frames = backtrace(trace, PA_ELEMENTSOF(trace));
175 symbols = backtrace_symbols(trace, n_frames);
181 n = PA_MIN((unsigned) n_frames, s + show_nframes);
185 for (j = s; j < n; j++) {
188 a += strlen(pa_path_get_filename(symbols[j]));
191 r = pa_xnew(char, a);
196 for (j = s; j < n; j++) {
204 sym = pa_path_get_filename(symbols[j]);
219 static void init_defaults(void) {
224 if (pa_get_binary_name(binary, sizeof(binary)))
225 pa_log_set_ident(binary);
228 if (getenv(ENV_LOG_SYSLOG)) {
229 target_override = PA_LOG_SYSLOG;
230 target_override_set = TRUE;
233 if ((e = getenv(ENV_LOG_LEVEL))) {
234 maximum_level_override = (pa_log_level_t) atoi(e);
236 if (maximum_level_override >= PA_LOG_LEVEL_MAX)
237 maximum_level_override = PA_LOG_LEVEL_MAX-1;
240 if (getenv(ENV_LOG_COLORS))
241 flags_override |= PA_LOG_COLORS;
243 if (getenv(ENV_LOG_PRINT_TIME))
244 flags_override |= PA_LOG_PRINT_TIME;
246 if (getenv(ENV_LOG_PRINT_FILE))
247 flags_override |= PA_LOG_PRINT_FILE;
249 if (getenv(ENV_LOG_PRINT_META))
250 flags_override |= PA_LOG_PRINT_META;
252 if (getenv(ENV_LOG_PRINT_LEVEL))
253 flags_override |= PA_LOG_PRINT_LEVEL;
255 if ((e = getenv(ENV_LOG_BACKTRACE))) {
256 show_backtrace_override = (unsigned) atoi(e);
258 if (show_backtrace_override <= 0)
259 show_backtrace_override = 0;
262 if ((e = getenv(ENV_LOG_BACKTRACE_SKIP))) {
263 skip_backtrace = (unsigned) atoi(e);
265 if (skip_backtrace <= 0)
270 void pa_log_levelv_meta(
271 pa_log_level_t level,
279 int saved_errno = errno;
281 pa_log_target_t _target;
282 pa_log_level_t _maximum_level;
283 unsigned _show_backtrace;
284 pa_log_flags_t _flags;
286 /* We don't use dynamic memory allocation here to minimize the hit
288 char text[16*1024], location[128], timestamp[32];
290 pa_assert(level < PA_LOG_LEVEL_MAX);
297 _target = target_override_set ? target_override : target;
298 _maximum_level = PA_MAX(maximum_level, maximum_level_override);
299 _show_backtrace = PA_MAX(show_backtrace, show_backtrace_override);
300 _flags = flags | flags_override;
302 if (PA_LIKELY(level > _maximum_level)) {
307 pa_vsnprintf(text, sizeof(text), format, ap);
309 if ((_flags & PA_LOG_PRINT_META) && file && line > 0 && func)
310 pa_snprintf(location, sizeof(location), "[%s:%i %s()] ", file, line, func);
311 else if ((_flags & (PA_LOG_PRINT_META|PA_LOG_PRINT_FILE)) && file)
312 pa_snprintf(location, sizeof(location), "%s: ", pa_path_get_filename(file));
316 if (_flags & PA_LOG_PRINT_TIME) {
317 static pa_usec_t start, last;
320 u = pa_rtclock_now();
330 /* This is not thread safe, but this is a debugging tool only
334 pa_snprintf(timestamp, sizeof(timestamp), "(%4llu.%03llu|%4llu.%03llu) ",
335 (unsigned long long) (a / PA_USEC_PER_SEC),
336 (unsigned long long) (((a / PA_USEC_PER_MSEC)) % 1000),
337 (unsigned long long) (r / PA_USEC_PER_SEC),
338 (unsigned long long) (((r / PA_USEC_PER_MSEC)) % 1000));
343 #ifdef HAVE_EXECINFO_H
344 if (_show_backtrace > 0)
345 bt = get_backtrace(_show_backtrace);
348 if (!pa_utf8_valid(text))
349 pa_logl(level, "Invalid UTF-8 string following below:");
351 for (t = text; t; t = n) {
352 if ((n = strchr(t, '\n'))) {
357 /* We ignore strings only made out of whitespace */
358 if (t[strspn(t, "\t ")] == 0)
363 case PA_LOG_STDERR: {
364 const char *prefix = "", *suffix = "", *grey = "";
368 /* Yes indeed. Useless, but fun! */
369 if ((_flags & PA_LOG_COLORS) && isatty(STDERR_FILENO)) {
370 if (level <= PA_LOG_ERROR)
371 prefix = "\x1B[1;31m";
372 else if (level <= PA_LOG_WARN)
378 if (grey[0] || prefix[0])
383 /* We shouldn't be using dynamic allocation here to
384 * minimize the hit in RT threads */
385 if ((local_t = pa_utf8_to_locale(t)))
388 if (_flags & PA_LOG_PRINT_LEVEL)
389 fprintf(stderr, "%s%c: %s%s%s%s%s%s\n", timestamp, level_to_char[level], location, prefix, t, grey, pa_strempty(bt), suffix);
391 fprintf(stderr, "%s%s%s%s%s%s%s\n", timestamp, location, prefix, t, grey, pa_strempty(bt), suffix);
399 case PA_LOG_SYSLOG: {
402 openlog(ident, LOG_PID, LOG_USER);
404 if ((local_t = pa_utf8_to_locale(t)))
407 syslog(level_to_syslog[level], "%s%s%s%s", timestamp, location, t, pa_strempty(bt));
418 openlog(ident, LOG_PID, LOG_USER);
420 if ((local_t = pa_utf8_to_locale(t)))
426 SLOG (LOG_DEBUG, DLOG_TAG, "%s%s%s%s", timestamp, location, t, pa_strempty(bt));
429 case PA_LOG_NOTICE: // no notice category in dlog, use info instead.
430 SLOG (LOG_INFO, DLOG_TAG, "%s%s%s%s", timestamp, location, t, pa_strempty(bt));
433 SLOG (LOG_WARN, DLOG_TAG, "%s%s%s%s", timestamp, location, t, pa_strempty(bt));
436 SLOG (LOG_ERROR, DLOG_TAG, "%s%s%s%s", timestamp, location, t, pa_strempty(bt));
439 SLOG (LOG_DEBUG, DLOG_TAG, "%s%s%s%s", timestamp, location, t, pa_strempty(bt));
447 case PA_LOG_DLOG_COLOR: {
450 openlog(ident, LOG_PID, LOG_USER);
452 if ((local_t = pa_utf8_to_locale(t)))
458 SLOG (LOG_DEBUG, DLOG_TAG, "\033[%dm%s%s%s%s\033[0m", COLOR_GREEN, timestamp, location, t, pa_strempty(bt));
461 case PA_LOG_NOTICE: // no notice category in dlog, use info instead.
462 SLOG (LOG_INFO, DLOG_TAG, "\033[%dm%s%s%s%s\033[0m", COLOR_BLUE, timestamp, location, t, pa_strempty(bt));
465 SLOG (LOG_WARN, DLOG_TAG, "\033[%dm%s%s%s%s\033[0m", COLOR_MAGENTA, timestamp, location, t, pa_strempty(bt));
468 SLOG (LOG_ERROR, DLOG_TAG, "\033[%dm%s%s%s%s\033[0m", COLOR_RED, timestamp, location, t, pa_strempty(bt));
471 SLOG (LOG_DEBUG, DLOG_TAG, "%s%s%s%s", timestamp, location, t, pa_strempty(bt));
490 void pa_log_level_meta(
491 pa_log_level_t level,
495 const char *format, ...) {
498 va_start(ap, format);
499 pa_log_levelv_meta(level, file, line, func, format, ap);
503 void pa_log_levelv(pa_log_level_t level, const char *format, va_list ap) {
504 pa_log_levelv_meta(level, NULL, 0, NULL, format, ap);
507 void pa_log_level(pa_log_level_t level, const char *format, ...) {
510 va_start(ap, format);
511 pa_log_levelv_meta(level, NULL, 0, NULL, format, ap);
515 pa_bool_t pa_log_ratelimit(void) {
516 /* Not more than 10 messages every 5s */
517 static PA_DEFINE_RATELIMIT(ratelimit, 5 * PA_USEC_PER_SEC, 10);
519 return pa_ratelimit_test(&ratelimit);