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(symbols
[j
]);
162 r
= pa_xnew(char, a
);
167 for (j
= 0; j
< n
; j
++) {
173 strcpy(e
, symbols
[j
]);
174 e
+= strlen(symbols
[j
]);
186 static void init_defaults(void) {
191 if (pa_get_binary_name(binary
, sizeof(binary
)))
192 pa_log_set_ident(binary
);
195 if (getenv(ENV_LOG_SYSLOG
)) {
196 target_override
= PA_LOG_SYSLOG
;
197 target_override_set
= TRUE
;
200 if ((e
= getenv(ENV_LOG_LEVEL
))) {
201 maximum_level_override
= (pa_log_level_t
) atoi(e
);
203 if (maximum_level_override
>= PA_LOG_LEVEL_MAX
)
204 maximum_level_override
= PA_LOG_LEVEL_MAX
-1;
207 if (getenv(ENV_LOG_COLORS
))
208 flags_override
|= PA_LOG_COLORS
;
210 if (getenv(ENV_LOG_PRINT_TIME
))
211 flags_override
|= PA_LOG_PRINT_TIME
;
213 if (getenv(ENV_LOG_PRINT_FILE
))
214 flags_override
|= PA_LOG_PRINT_FILE
;
216 if (getenv(ENV_LOG_PRINT_META
))
217 flags_override
|= PA_LOG_PRINT_META
;
219 if (getenv(ENV_LOG_PRINT_LEVEL
))
220 flags_override
|= PA_LOG_PRINT_LEVEL
;
222 if ((e
= getenv(ENV_LOG_BACKTRACE
))) {
223 show_backtrace_override
= (unsigned) atoi(e
);
225 if (show_backtrace_override
<= 0)
226 show_backtrace_override
= 0;
230 void pa_log_levelv_meta(
231 pa_log_level_t level
,
239 int saved_errno
= errno
;
241 pa_log_target_t _target
;
242 pa_log_level_t _maximum_level
;
243 unsigned _show_backtrace
;
244 pa_log_flags_t _flags
;
246 /* We don't use dynamic memory allocation here to minimize the hit
248 char text
[4096], location
[128], timestamp
[32];
250 pa_assert(level
< PA_LOG_LEVEL_MAX
);
257 _target
= target_override_set
? target_override
: target
;
258 _maximum_level
= PA_MAX(maximum_level
, maximum_level_override
);
259 _show_backtrace
= PA_MAX(show_backtrace
, show_backtrace_override
);
260 _flags
= flags
| flags_override
;
262 if (PA_LIKELY(level
> _maximum_level
)) {
267 pa_vsnprintf(text
, sizeof(text
), format
, ap
);
269 if ((_flags
& PA_LOG_PRINT_META
) && file
&& line
> 0 && func
)
270 pa_snprintf(location
, sizeof(location
), "[%s:%i %s()] ", file
, line
, func
);
271 else if (_flags
& (PA_LOG_PRINT_META
|PA_LOG_PRINT_FILE
))
272 pa_snprintf(location
, sizeof(location
), "%s: ", pa_path_get_filename(file
));
276 if (_flags
& PA_LOG_PRINT_TIME
) {
277 static pa_usec_t start
, last
;
280 u
= pa_rtclock_usec();
290 /* This is not thread safe, but this is a debugging tool only
294 pa_snprintf(timestamp
, sizeof(timestamp
), "(%4llu.%03llu|%4llu.%03llu) ",
295 (unsigned long long) (a
/ PA_USEC_PER_SEC
),
296 (unsigned long long) (((a
/ PA_USEC_PER_MSEC
)) % 1000),
297 (unsigned long long) (r
/ PA_USEC_PER_SEC
),
298 (unsigned long long) (((r
/ PA_USEC_PER_MSEC
)) % 1000));
303 #ifdef HAVE_EXECINFO_H
304 if (_show_backtrace
> 0)
305 bt
= get_backtrace(_show_backtrace
);
308 if (!pa_utf8_valid(text
))
309 pa_log_level(level
, __FILE__
": invalid UTF-8 string following below:");
311 for (t
= text
; t
; t
= n
) {
312 if ((n
= strchr(t
, '\n'))) {
317 /* We ignore strings only made out of whitespace */
318 if (t
[strspn(t
, "\t ")] == 0)
323 case PA_LOG_STDERR
: {
324 const char *prefix
= "", *suffix
= "", *grey
= "";
328 /* Yes indeed. Useless, but fun! */
329 if ((_flags
& PA_LOG_COLORS
) && isatty(STDERR_FILENO
)) {
330 if (level
<= PA_LOG_ERROR
)
331 prefix
= "\x1B[1;31m";
332 else if (level
<= PA_LOG_WARN
)
338 if (grey
[0] || prefix
[0])
343 /* We shouldn't be using dynamic allocation here to
344 * minimize the hit in RT threads */
345 if ((local_t
= pa_utf8_to_locale(t
)))
348 if (_flags
& PA_LOG_PRINT_LEVEL
)
349 fprintf(stderr
, "%s%c: %s%s%s%s%s%s\n", timestamp
, level_to_char
[level
], location
, prefix
, t
, grey
, pa_strempty(bt
), suffix
);
351 fprintf(stderr
, "%s%s%s%s%s%s%s\n", timestamp
, location
, prefix
, t
, grey
, pa_strempty(bt
), suffix
);
359 case PA_LOG_SYSLOG
: {
362 openlog(ident
, LOG_PID
, LOG_USER
);
364 if ((local_t
= pa_utf8_to_locale(t
)))
367 syslog(level_to_syslog
[level
], "%s%s%s%s", timestamp
, location
, t
, pa_strempty(bt
));
384 void pa_log_level_meta(
385 pa_log_level_t level
,
389 const char *format
, ...) {
392 va_start(ap
, format
);
393 pa_log_levelv_meta(level
, file
, line
, func
, format
, ap
);
397 void pa_log_levelv(pa_log_level_t level
, const char *format
, va_list ap
) {
398 pa_log_levelv_meta(level
, NULL
, 0, NULL
, format
, ap
);
401 void pa_log_level(pa_log_level_t level
, const char *format
, ...) {
404 va_start(ap
, format
);
405 pa_log_levelv_meta(level
, NULL
, 0, NULL
, format
, ap
);
409 pa_bool_t
pa_log_ratelimit(void) {
410 /* Not more than 10 messages every 5s */
411 static PA_DEFINE_RATELIMIT(ratelimit
, 5 * PA_USEC_PER_SEC
, 10);
413 return pa_ratelimit_test(&ratelimit
);