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"
64 #define ENV_LOG_NO_RATELIMIT "PULSE_LOG_NO_RATE_LIMIT"
66 static char *ident
= NULL
; /* in local charset format */
67 static pa_log_target_t target
= PA_LOG_STDERR
, target_override
;
68 static pa_bool_t target_override_set
= FALSE
;
69 static pa_log_level_t maximum_level
= PA_LOG_ERROR
, maximum_level_override
= PA_LOG_ERROR
;
70 static unsigned show_backtrace
= 0, show_backtrace_override
= 0, skip_backtrace
= 0;
71 static pa_log_flags_t flags
= 0, flags_override
= 0;
72 static pa_bool_t no_rate_limit
= FALSE
;
75 static const int level_to_syslog
[] = {
76 [PA_LOG_ERROR
] = LOG_ERR
,
77 [PA_LOG_WARN
] = LOG_WARNING
,
78 [PA_LOG_NOTICE
] = LOG_NOTICE
,
79 [PA_LOG_INFO
] = LOG_INFO
,
80 [PA_LOG_DEBUG
] = LOG_DEBUG
84 static const char level_to_char
[] = {
87 [PA_LOG_NOTICE
] = 'N',
92 void pa_log_set_ident(const char *p
) {
95 if (!(ident
= pa_utf8_to_locale(p
)))
96 ident
= pa_ascii_filter(p
);
99 /* To make valgrind shut up. */
100 static void ident_destructor(void) PA_GCC_DESTRUCTOR
;
101 static void ident_destructor(void) {
102 if (!pa_in_valgrind())
108 void pa_log_set_level(pa_log_level_t l
) {
109 pa_assert(l
< PA_LOG_LEVEL_MAX
);
114 void pa_log_set_target(pa_log_target_t t
) {
115 pa_assert(t
< PA_LOG_TARGET_MAX
);
120 void pa_log_set_flags(pa_log_flags_t _flags
, pa_log_merge_t merge
) {
121 pa_assert(!(_flags
& ~(PA_LOG_COLORS
|PA_LOG_PRINT_TIME
|PA_LOG_PRINT_FILE
|PA_LOG_PRINT_META
|PA_LOG_PRINT_LEVEL
)));
123 if (merge
== PA_LOG_SET
)
125 else if (merge
== PA_LOG_UNSET
)
131 void pa_log_set_show_backtrace(unsigned nlevels
) {
132 show_backtrace
= nlevels
;
135 void pa_log_set_skip_backtrace(unsigned nlevels
) {
136 skip_backtrace
= nlevels
;
139 #ifdef HAVE_EXECINFO_H
141 static char* get_backtrace(unsigned show_nframes
) {
144 char **symbols
, *e
, *r
;
148 pa_assert(show_nframes
> 0);
150 n_frames
= backtrace(trace
, PA_ELEMENTSOF(trace
));
155 symbols
= backtrace_symbols(trace
, n_frames
);
161 n
= PA_MIN((unsigned) n_frames
, s
+ show_nframes
);
165 for (j
= s
; j
< n
; j
++) {
168 a
+= strlen(pa_path_get_filename(symbols
[j
]));
171 r
= pa_xnew(char, a
);
176 for (j
= s
; j
< n
; j
++) {
184 sym
= pa_path_get_filename(symbols
[j
]);
199 static void init_defaults(void) {
206 if (pa_get_binary_name(binary
, sizeof(binary
)))
207 pa_log_set_ident(binary
);
210 if (getenv(ENV_LOG_SYSLOG
)) {
211 target_override
= PA_LOG_SYSLOG
;
212 target_override_set
= TRUE
;
215 if ((e
= getenv(ENV_LOG_LEVEL
))) {
216 maximum_level_override
= (pa_log_level_t
) atoi(e
);
218 if (maximum_level_override
>= PA_LOG_LEVEL_MAX
)
219 maximum_level_override
= PA_LOG_LEVEL_MAX
-1;
222 if (getenv(ENV_LOG_COLORS
))
223 flags_override
|= PA_LOG_COLORS
;
225 if (getenv(ENV_LOG_PRINT_TIME
))
226 flags_override
|= PA_LOG_PRINT_TIME
;
228 if (getenv(ENV_LOG_PRINT_FILE
))
229 flags_override
|= PA_LOG_PRINT_FILE
;
231 if (getenv(ENV_LOG_PRINT_META
))
232 flags_override
|= PA_LOG_PRINT_META
;
234 if (getenv(ENV_LOG_PRINT_LEVEL
))
235 flags_override
|= PA_LOG_PRINT_LEVEL
;
237 if ((e
= getenv(ENV_LOG_BACKTRACE
))) {
238 show_backtrace_override
= (unsigned) atoi(e
);
240 if (show_backtrace_override
<= 0)
241 show_backtrace_override
= 0;
244 if ((e
= getenv(ENV_LOG_BACKTRACE_SKIP
))) {
245 skip_backtrace
= (unsigned) atoi(e
);
247 if (skip_backtrace
<= 0)
251 if (getenv(ENV_LOG_NO_RATELIMIT
))
252 no_rate_limit
= TRUE
;
257 void pa_log_levelv_meta(
258 pa_log_level_t level
,
266 int saved_errno
= errno
;
268 pa_log_target_t _target
;
269 pa_log_level_t _maximum_level
;
270 unsigned _show_backtrace
;
271 pa_log_flags_t _flags
;
273 /* We don't use dynamic memory allocation here to minimize the hit
275 char text
[16*1024], location
[128], timestamp
[32];
277 pa_assert(level
< PA_LOG_LEVEL_MAX
);
282 _target
= target_override_set
? target_override
: target
;
283 _maximum_level
= PA_MAX(maximum_level
, maximum_level_override
);
284 _show_backtrace
= PA_MAX(show_backtrace
, show_backtrace_override
);
285 _flags
= flags
| flags_override
;
287 if (PA_LIKELY(level
> _maximum_level
)) {
292 pa_vsnprintf(text
, sizeof(text
), format
, ap
);
294 if ((_flags
& PA_LOG_PRINT_META
) && file
&& line
> 0 && func
)
295 pa_snprintf(location
, sizeof(location
), "[%s:%i %s()] ", file
, line
, func
);
296 else if ((_flags
& (PA_LOG_PRINT_META
|PA_LOG_PRINT_FILE
)) && file
)
297 pa_snprintf(location
, sizeof(location
), "%s: ", pa_path_get_filename(file
));
301 if (_flags
& PA_LOG_PRINT_TIME
) {
302 static pa_usec_t start
, last
;
305 u
= pa_rtclock_now();
315 /* This is not thread safe, but this is a debugging tool only
319 pa_snprintf(timestamp
, sizeof(timestamp
), "(%4llu.%03llu|%4llu.%03llu) ",
320 (unsigned long long) (a
/ PA_USEC_PER_SEC
),
321 (unsigned long long) (((a
/ PA_USEC_PER_MSEC
)) % 1000),
322 (unsigned long long) (r
/ PA_USEC_PER_SEC
),
323 (unsigned long long) (((r
/ PA_USEC_PER_MSEC
)) % 1000));
328 #ifdef HAVE_EXECINFO_H
329 if (_show_backtrace
> 0)
330 bt
= get_backtrace(_show_backtrace
);
333 if (!pa_utf8_valid(text
))
334 pa_logl(level
, "Invalid UTF-8 string following below:");
336 for (t
= text
; t
; t
= n
) {
337 if ((n
= strchr(t
, '\n'))) {
342 /* We ignore strings only made out of whitespace */
343 if (t
[strspn(t
, "\t ")] == 0)
348 case PA_LOG_STDERR
: {
349 const char *prefix
= "", *suffix
= "", *grey
= "";
353 /* Yes indeed. Useless, but fun! */
354 if ((_flags
& PA_LOG_COLORS
) && isatty(STDERR_FILENO
)) {
355 if (level
<= PA_LOG_ERROR
)
356 prefix
= "\x1B[1;31m";
357 else if (level
<= PA_LOG_WARN
)
363 if (grey
[0] || prefix
[0])
368 /* We shouldn't be using dynamic allocation here to
369 * minimize the hit in RT threads */
370 if ((local_t
= pa_utf8_to_locale(t
)))
373 if (_flags
& PA_LOG_PRINT_LEVEL
)
374 fprintf(stderr
, "%s%c: %s%s%s%s%s%s\n", timestamp
, level_to_char
[level
], location
, prefix
, t
, grey
, pa_strempty(bt
), suffix
);
376 fprintf(stderr
, "%s%s%s%s%s%s%s\n", timestamp
, location
, prefix
, t
, grey
, pa_strempty(bt
), suffix
);
387 case PA_LOG_SYSLOG
: {
390 openlog(ident
, LOG_PID
, LOG_USER
);
392 if ((local_t
= pa_utf8_to_locale(t
)))
395 syslog(level_to_syslog
[level
], "%s%s%s%s", timestamp
, location
, t
, pa_strempty(bt
));
412 void pa_log_level_meta(
413 pa_log_level_t level
,
417 const char *format
, ...) {
420 va_start(ap
, format
);
421 pa_log_levelv_meta(level
, file
, line
, func
, format
, ap
);
425 void pa_log_levelv(pa_log_level_t level
, const char *format
, va_list ap
) {
426 pa_log_levelv_meta(level
, NULL
, 0, NULL
, format
, ap
);
429 void pa_log_level(pa_log_level_t level
, const char *format
, ...) {
432 va_start(ap
, format
);
433 pa_log_levelv_meta(level
, NULL
, 0, NULL
, format
, ap
);
437 pa_bool_t
pa_log_ratelimit(pa_log_level_t level
) {
438 /* Not more than 10 messages every 5s */
439 static PA_DEFINE_RATELIMIT(ratelimit
, 5 * PA_USEC_PER_SEC
, 10);
446 return pa_ratelimit_test(&ratelimit
, level
);