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>
55 #define ENV_LOG_SYSLOG "PULSE_LOG_SYSLOG"
56 #define ENV_LOG_LEVEL "PULSE_LOG"
57 #define ENV_LOG_COLORS "PULSE_LOG_COLORS"
58 #define ENV_LOG_PRINT_TIME "PULSE_LOG_TIME"
59 #define ENV_LOG_PRINT_FILE "PULSE_LOG_FILE"
60 #define ENV_LOG_PRINT_META "PULSE_LOG_META"
61 #define ENV_LOG_PRINT_LEVEL "PULSE_LOG_LEVEL"
62 #define ENV_LOG_BACKTRACE "PULSE_LOG_BACKTRACE"
63 #define ENV_LOG_BACKTRACE_SKIP "PULSE_LOG_BACKTRACE_SKIP"
65 static char *ident
= NULL
; /* in local charset format */
66 static pa_log_target_t target
= PA_LOG_STDERR
, target_override
;
67 static pa_bool_t target_override_set
= FALSE
;
68 static pa_log_level_t maximum_level
= PA_LOG_ERROR
, maximum_level_override
= PA_LOG_ERROR
;
69 static unsigned show_backtrace
= 0, show_backtrace_override
= 0, skip_backtrace
= 0;
70 static pa_log_flags_t flags
= 0, flags_override
= 0;
73 static const int level_to_syslog
[] = {
74 [PA_LOG_ERROR
] = LOG_ERR
,
75 [PA_LOG_WARN
] = LOG_WARNING
,
76 [PA_LOG_NOTICE
] = LOG_NOTICE
,
77 [PA_LOG_INFO
] = LOG_INFO
,
78 [PA_LOG_DEBUG
] = LOG_DEBUG
82 static const char level_to_char
[] = {
85 [PA_LOG_NOTICE
] = 'N',
90 void pa_log_set_ident(const char *p
) {
93 if (!(ident
= pa_utf8_to_locale(p
)))
94 ident
= pa_ascii_filter(p
);
97 /* To make valgrind shut up. */
98 static void ident_destructor(void) PA_GCC_DESTRUCTOR
;
99 static void ident_destructor(void) {
100 if (!pa_in_valgrind())
106 void pa_log_set_level(pa_log_level_t l
) {
107 pa_assert(l
< PA_LOG_LEVEL_MAX
);
112 void pa_log_set_target(pa_log_target_t t
) {
113 pa_assert(t
< PA_LOG_TARGET_MAX
);
118 void pa_log_set_flags(pa_log_flags_t _flags
, pa_log_merge_t merge
) {
119 pa_assert(!(_flags
& ~(PA_LOG_COLORS
|PA_LOG_PRINT_TIME
|PA_LOG_PRINT_FILE
|PA_LOG_PRINT_META
|PA_LOG_PRINT_LEVEL
)));
121 if (merge
== PA_LOG_SET
)
123 else if (merge
== PA_LOG_UNSET
)
129 void pa_log_set_show_backtrace(unsigned nlevels
) {
130 show_backtrace
= nlevels
;
133 void pa_log_set_skip_backtrace(unsigned nlevels
) {
134 skip_backtrace
= nlevels
;
137 #ifdef HAVE_EXECINFO_H
139 static char* get_backtrace(unsigned show_nframes
) {
142 char **symbols
, *e
, *r
;
146 pa_assert(show_nframes
> 0);
148 n_frames
= backtrace(trace
, PA_ELEMENTSOF(trace
));
153 symbols
= backtrace_symbols(trace
, n_frames
);
159 n
= PA_MIN((unsigned) n_frames
, s
+ show_nframes
);
163 for (j
= s
; j
< n
; j
++) {
166 a
+= strlen(pa_path_get_filename(symbols
[j
]));
169 r
= pa_xnew(char, a
);
174 for (j
= s
; j
< n
; j
++) {
182 sym
= pa_path_get_filename(symbols
[j
]);
197 static void init_defaults(void) {
202 if (pa_get_binary_name(binary
, sizeof(binary
)))
203 pa_log_set_ident(binary
);
206 if (getenv(ENV_LOG_SYSLOG
)) {
207 target_override
= PA_LOG_SYSLOG
;
208 target_override_set
= TRUE
;
211 if ((e
= getenv(ENV_LOG_LEVEL
))) {
212 maximum_level_override
= (pa_log_level_t
) atoi(e
);
214 if (maximum_level_override
>= PA_LOG_LEVEL_MAX
)
215 maximum_level_override
= PA_LOG_LEVEL_MAX
-1;
218 if (getenv(ENV_LOG_COLORS
))
219 flags_override
|= PA_LOG_COLORS
;
221 if (getenv(ENV_LOG_PRINT_TIME
))
222 flags_override
|= PA_LOG_PRINT_TIME
;
224 if (getenv(ENV_LOG_PRINT_FILE
))
225 flags_override
|= PA_LOG_PRINT_FILE
;
227 if (getenv(ENV_LOG_PRINT_META
))
228 flags_override
|= PA_LOG_PRINT_META
;
230 if (getenv(ENV_LOG_PRINT_LEVEL
))
231 flags_override
|= PA_LOG_PRINT_LEVEL
;
233 if ((e
= getenv(ENV_LOG_BACKTRACE
))) {
234 show_backtrace_override
= (unsigned) atoi(e
);
236 if (show_backtrace_override
<= 0)
237 show_backtrace_override
= 0;
240 if ((e
= getenv(ENV_LOG_BACKTRACE_SKIP
))) {
241 skip_backtrace
= (unsigned) atoi(e
);
243 if (skip_backtrace
<= 0)
248 void pa_log_levelv_meta(
249 pa_log_level_t level
,
257 int saved_errno
= errno
;
259 pa_log_target_t _target
;
260 pa_log_level_t _maximum_level
;
261 unsigned _show_backtrace
;
262 pa_log_flags_t _flags
;
264 /* We don't use dynamic memory allocation here to minimize the hit
266 char text
[16*1024], location
[128], timestamp
[32];
268 pa_assert(level
< PA_LOG_LEVEL_MAX
);
275 _target
= target_override_set
? target_override
: target
;
276 _maximum_level
= PA_MAX(maximum_level
, maximum_level_override
);
277 _show_backtrace
= PA_MAX(show_backtrace
, show_backtrace_override
);
278 _flags
= flags
| flags_override
;
280 if (PA_LIKELY(level
> _maximum_level
)) {
285 pa_vsnprintf(text
, sizeof(text
), format
, ap
);
287 if ((_flags
& PA_LOG_PRINT_META
) && file
&& line
> 0 && func
)
288 pa_snprintf(location
, sizeof(location
), "[%s:%i %s()] ", file
, line
, func
);
289 else if ((_flags
& (PA_LOG_PRINT_META
|PA_LOG_PRINT_FILE
)) && file
)
290 pa_snprintf(location
, sizeof(location
), "%s: ", pa_path_get_filename(file
));
294 if (_flags
& PA_LOG_PRINT_TIME
) {
295 static pa_usec_t start
, last
;
298 u
= pa_rtclock_now();
308 /* This is not thread safe, but this is a debugging tool only
312 pa_snprintf(timestamp
, sizeof(timestamp
), "(%4llu.%03llu|%4llu.%03llu) ",
313 (unsigned long long) (a
/ PA_USEC_PER_SEC
),
314 (unsigned long long) (((a
/ PA_USEC_PER_MSEC
)) % 1000),
315 (unsigned long long) (r
/ PA_USEC_PER_SEC
),
316 (unsigned long long) (((r
/ PA_USEC_PER_MSEC
)) % 1000));
321 #ifdef HAVE_EXECINFO_H
322 if (_show_backtrace
> 0)
323 bt
= get_backtrace(_show_backtrace
);
326 if (!pa_utf8_valid(text
))
327 pa_logl(level
, "Invalid UTF-8 string following below:");
329 for (t
= text
; t
; t
= n
) {
330 if ((n
= strchr(t
, '\n'))) {
335 /* We ignore strings only made out of whitespace */
336 if (t
[strspn(t
, "\t ")] == 0)
341 case PA_LOG_STDERR
: {
342 const char *prefix
= "", *suffix
= "", *grey
= "";
346 /* Yes indeed. Useless, but fun! */
347 if ((_flags
& PA_LOG_COLORS
) && isatty(STDERR_FILENO
)) {
348 if (level
<= PA_LOG_ERROR
)
349 prefix
= "\x1B[1;31m";
350 else if (level
<= PA_LOG_WARN
)
356 if (grey
[0] || prefix
[0])
361 /* We shouldn't be using dynamic allocation here to
362 * minimize the hit in RT threads */
363 if ((local_t
= pa_utf8_to_locale(t
)))
366 if (_flags
& PA_LOG_PRINT_LEVEL
)
367 fprintf(stderr
, "%s%c: %s%s%s%s%s%s\n", timestamp
, level_to_char
[level
], location
, prefix
, t
, grey
, pa_strempty(bt
), suffix
);
369 fprintf(stderr
, "%s%s%s%s%s%s%s\n", timestamp
, location
, prefix
, t
, grey
, pa_strempty(bt
), suffix
);
377 case PA_LOG_SYSLOG
: {
380 openlog(ident
, LOG_PID
, LOG_USER
);
382 if ((local_t
= pa_utf8_to_locale(t
)))
385 syslog(level_to_syslog
[level
], "%s%s%s%s", timestamp
, location
, t
, pa_strempty(bt
));
402 void pa_log_level_meta(
403 pa_log_level_t level
,
407 const char *format
, ...) {
410 va_start(ap
, format
);
411 pa_log_levelv_meta(level
, file
, line
, func
, format
, ap
);
415 void pa_log_levelv(pa_log_level_t level
, const char *format
, va_list ap
) {
416 pa_log_levelv_meta(level
, NULL
, 0, NULL
, format
, ap
);
419 void pa_log_level(pa_log_level_t level
, const char *format
, ...) {
422 va_start(ap
, format
);
423 pa_log_levelv_meta(level
, NULL
, 0, NULL
, format
, ap
);
427 pa_bool_t
pa_log_ratelimit(void) {
428 /* Not more than 10 messages every 5s */
429 static PA_DEFINE_RATELIMIT(ratelimit
, 5 * PA_USEC_PER_SEC
, 10);
431 return pa_ratelimit_test(&ratelimit
);