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/utf8.h>
42 #include <pulse/xmalloc.h>
43 #include <pulse/util.h>
44 #include <pulse/timeval.h>
46 #include <pulsecore/macro.h>
47 #include <pulsecore/core-util.h>
48 #include <pulsecore/rtclock.h>
49 #include <pulsecore/once.h>
50 #include <pulsecore/ratelimit.h>
54 #define ENV_LOG_SYSLOG "PULSE_LOG_SYSLOG"
55 #define ENV_LOG_LEVEL "PULSE_LOG"
56 #define ENV_LOG_COLORS "PULSE_LOG_COLORS"
57 #define ENV_LOG_PRINT_TIME "PULSE_LOG_TIME"
58 #define ENV_LOG_PRINT_FILE "PULSE_LOG_FILE"
59 #define ENV_LOG_PRINT_META "PULSE_LOG_META"
60 #define ENV_LOG_PRINT_LEVEL "PULSE_LOG_LEVEL"
61 #define ENV_LOG_BACKTRACE "PULSE_LOG_BACKTRACE"
63 static char *ident
= NULL
; /* in local charset format */
64 static pa_log_target_t target
= PA_LOG_STDERR
, target_override
;
65 static pa_bool_t target_override_set
= FALSE
;
66 static pa_log_level_t maximum_level
= PA_LOG_ERROR
, maximum_level_override
= PA_LOG_ERROR
;
67 static unsigned show_backtrace
= 0, show_backtrace_override
= 0;
68 static pa_log_flags_t flags
= 0, flags_override
= 0;
71 static const int level_to_syslog
[] = {
72 [PA_LOG_ERROR
] = LOG_ERR
,
73 [PA_LOG_WARN
] = LOG_WARNING
,
74 [PA_LOG_NOTICE
] = LOG_NOTICE
,
75 [PA_LOG_INFO
] = LOG_INFO
,
76 [PA_LOG_DEBUG
] = LOG_DEBUG
80 static const char level_to_char
[] = {
83 [PA_LOG_NOTICE
] = 'N',
88 void pa_log_set_ident(const char *p
) {
91 if (!(ident
= pa_utf8_to_locale(p
)))
92 ident
= pa_ascii_filter(p
);
95 /* To make valgrind shut up. */
96 static void ident_destructor(void) PA_GCC_DESTRUCTOR
;
97 static void ident_destructor(void) {
98 if (!pa_in_valgrind())
104 void pa_log_set_level(pa_log_level_t l
) {
105 pa_assert(l
< PA_LOG_LEVEL_MAX
);
110 void pa_log_set_target(pa_log_target_t t
) {
111 pa_assert(t
< PA_LOG_TARGET_MAX
);
116 void pa_log_set_flags(pa_log_flags_t _flags
, pa_log_merge_t merge
) {
117 pa_assert(!(_flags
& ~(PA_LOG_COLORS
|PA_LOG_PRINT_TIME
|PA_LOG_PRINT_FILE
|PA_LOG_PRINT_META
|PA_LOG_PRINT_LEVEL
)));
119 if (merge
== PA_LOG_SET
)
121 else if (merge
== PA_LOG_UNSET
)
127 void pa_log_set_show_backtrace(unsigned nlevels
) {
128 show_backtrace
= nlevels
;
131 #ifdef HAVE_EXECINFO_H
133 static char* get_backtrace(unsigned show_nframes
) {
136 char **symbols
, *e
, *r
;
140 pa_assert(show_nframes
> 0);
142 n_frames
= backtrace(trace
, PA_ELEMENTSOF(trace
));
147 symbols
= backtrace_symbols(trace
, n_frames
);
152 n
= PA_MIN((unsigned) n_frames
, show_nframes
);
156 for (j
= 0; j
< n
; j
++) {
159 a
+= strlen(pa_path_get_filename(symbols
[j
]));
162 r
= pa_xnew(char, a
);
167 for (j
= 0; j
< n
; j
++) {
175 sym
= pa_path_get_filename(symbols
[j
]);
190 static void init_defaults(void) {
195 if (pa_get_binary_name(binary
, sizeof(binary
)))
196 pa_log_set_ident(binary
);
199 if (getenv(ENV_LOG_SYSLOG
)) {
200 target_override
= PA_LOG_SYSLOG
;
201 target_override_set
= TRUE
;
204 if ((e
= getenv(ENV_LOG_LEVEL
))) {
205 maximum_level_override
= (pa_log_level_t
) atoi(e
);
207 if (maximum_level_override
>= PA_LOG_LEVEL_MAX
)
208 maximum_level_override
= PA_LOG_LEVEL_MAX
-1;
211 if (getenv(ENV_LOG_COLORS
))
212 flags_override
|= PA_LOG_COLORS
;
214 if (getenv(ENV_LOG_PRINT_TIME
))
215 flags_override
|= PA_LOG_PRINT_TIME
;
217 if (getenv(ENV_LOG_PRINT_FILE
))
218 flags_override
|= PA_LOG_PRINT_FILE
;
220 if (getenv(ENV_LOG_PRINT_META
))
221 flags_override
|= PA_LOG_PRINT_META
;
223 if (getenv(ENV_LOG_PRINT_LEVEL
))
224 flags_override
|= PA_LOG_PRINT_LEVEL
;
226 if ((e
= getenv(ENV_LOG_BACKTRACE
))) {
227 show_backtrace_override
= (unsigned) atoi(e
);
229 if (show_backtrace_override
<= 0)
230 show_backtrace_override
= 0;
234 void pa_log_levelv_meta(
235 pa_log_level_t level
,
243 int saved_errno
= errno
;
245 pa_log_target_t _target
;
246 pa_log_level_t _maximum_level
;
247 unsigned _show_backtrace
;
248 pa_log_flags_t _flags
;
250 /* We don't use dynamic memory allocation here to minimize the hit
252 char text
[4096], location
[128], timestamp
[32];
254 pa_assert(level
< PA_LOG_LEVEL_MAX
);
261 _target
= target_override_set
? target_override
: target
;
262 _maximum_level
= PA_MAX(maximum_level
, maximum_level_override
);
263 _show_backtrace
= PA_MAX(show_backtrace
, show_backtrace_override
);
264 _flags
= flags
| flags_override
;
266 if (PA_LIKELY(level
> _maximum_level
)) {
271 pa_vsnprintf(text
, sizeof(text
), format
, ap
);
273 if ((_flags
& PA_LOG_PRINT_META
) && file
&& line
> 0 && func
)
274 pa_snprintf(location
, sizeof(location
), "[%s:%i %s()] ", file
, line
, func
);
275 else if (_flags
& (PA_LOG_PRINT_META
|PA_LOG_PRINT_FILE
))
276 pa_snprintf(location
, sizeof(location
), "%s: ", pa_path_get_filename(file
));
280 if (_flags
& PA_LOG_PRINT_TIME
) {
281 static pa_usec_t start
, last
;
284 u
= pa_rtclock_usec();
294 /* This is not thread safe, but this is a debugging tool only
298 pa_snprintf(timestamp
, sizeof(timestamp
), "(%4llu.%03llu|%4llu.%03llu) ",
299 (unsigned long long) (a
/ PA_USEC_PER_SEC
),
300 (unsigned long long) (((a
/ PA_USEC_PER_MSEC
)) % 1000),
301 (unsigned long long) (r
/ PA_USEC_PER_SEC
),
302 (unsigned long long) (((r
/ PA_USEC_PER_MSEC
)) % 1000));
307 #ifdef HAVE_EXECINFO_H
308 if (_show_backtrace
> 0)
309 bt
= get_backtrace(_show_backtrace
);
312 if (!pa_utf8_valid(text
))
313 pa_log_level(level
, __FILE__
": invalid UTF-8 string following below:");
315 for (t
= text
; t
; t
= n
) {
316 if ((n
= strchr(t
, '\n'))) {
321 /* We ignore strings only made out of whitespace */
322 if (t
[strspn(t
, "\t ")] == 0)
327 case PA_LOG_STDERR
: {
328 const char *prefix
= "", *suffix
= "", *grey
= "";
332 /* Yes indeed. Useless, but fun! */
333 if ((_flags
& PA_LOG_COLORS
) && isatty(STDERR_FILENO
)) {
334 if (level
<= PA_LOG_ERROR
)
335 prefix
= "\x1B[1;31m";
336 else if (level
<= PA_LOG_WARN
)
342 if (grey
[0] || prefix
[0])
347 /* We shouldn't be using dynamic allocation here to
348 * minimize the hit in RT threads */
349 if ((local_t
= pa_utf8_to_locale(t
)))
352 if (_flags
& PA_LOG_PRINT_LEVEL
)
353 fprintf(stderr
, "%s%c: %s%s%s%s%s%s\n", timestamp
, level_to_char
[level
], location
, prefix
, t
, grey
, pa_strempty(bt
), suffix
);
355 fprintf(stderr
, "%s%s%s%s%s%s%s\n", timestamp
, location
, prefix
, t
, grey
, pa_strempty(bt
), suffix
);
363 case PA_LOG_SYSLOG
: {
366 openlog(ident
, LOG_PID
, LOG_USER
);
368 if ((local_t
= pa_utf8_to_locale(t
)))
371 syslog(level_to_syslog
[level
], "%s%s%s%s", timestamp
, location
, t
, pa_strempty(bt
));
388 void pa_log_level_meta(
389 pa_log_level_t level
,
393 const char *format
, ...) {
396 va_start(ap
, format
);
397 pa_log_levelv_meta(level
, file
, line
, func
, format
, ap
);
401 void pa_log_levelv(pa_log_level_t level
, const char *format
, va_list ap
) {
402 pa_log_levelv_meta(level
, NULL
, 0, NULL
, format
, ap
);
405 void pa_log_level(pa_log_level_t level
, const char *format
, ...) {
408 va_start(ap
, format
);
409 pa_log_levelv_meta(level
, NULL
, 0, NULL
, format
, ap
);
413 pa_bool_t
pa_log_ratelimit(void) {
414 /* Not more than 10 messages every 5s */
415 static PA_DEFINE_RATELIMIT(ratelimit
, 5 * PA_USEC_PER_SEC
, 10);
417 return pa_ratelimit_test(&ratelimit
);