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/gccmacro.h>
42 #include <pulse/rtclock.h>
43 #include <pulse/utf8.h>
44 #include <pulse/xmalloc.h>
45 #include <pulse/util.h>
46 #include <pulse/timeval.h>
48 #include <pulsecore/macro.h>
49 #include <pulsecore/core-util.h>
50 #include <pulsecore/once.h>
51 #include <pulsecore/ratelimit.h>
52 #include <pulsecore/thread.h>
56 #define ENV_LOG_SYSLOG "PULSE_LOG_SYSLOG"
57 #define ENV_LOG_LEVEL "PULSE_LOG"
58 #define ENV_LOG_COLORS "PULSE_LOG_COLORS"
59 #define ENV_LOG_PRINT_TIME "PULSE_LOG_TIME"
60 #define ENV_LOG_PRINT_FILE "PULSE_LOG_FILE"
61 #define ENV_LOG_PRINT_META "PULSE_LOG_META"
62 #define ENV_LOG_PRINT_LEVEL "PULSE_LOG_LEVEL"
63 #define ENV_LOG_BACKTRACE "PULSE_LOG_BACKTRACE"
64 #define ENV_LOG_BACKTRACE_SKIP "PULSE_LOG_BACKTRACE_SKIP"
65 #define ENV_LOG_NO_RATELIMIT "PULSE_LOG_NO_RATE_LIMIT"
67 static char *ident
= NULL
; /* in local charset format */
68 static pa_log_target_t target
= PA_LOG_STDERR
, target_override
;
69 static pa_bool_t target_override_set
= FALSE
;
70 static pa_log_level_t maximum_level
= PA_LOG_ERROR
, maximum_level_override
= PA_LOG_ERROR
;
71 static unsigned show_backtrace
= 0, show_backtrace_override
= 0, skip_backtrace
= 0;
72 static pa_log_flags_t flags
= 0, flags_override
= 0;
73 static pa_bool_t no_rate_limit
= FALSE
;
74 static int log_fd
= -1;
77 static const int level_to_syslog
[] = {
78 [PA_LOG_ERROR
] = LOG_ERR
,
79 [PA_LOG_WARN
] = LOG_WARNING
,
80 [PA_LOG_NOTICE
] = LOG_NOTICE
,
81 [PA_LOG_INFO
] = LOG_INFO
,
82 [PA_LOG_DEBUG
] = LOG_DEBUG
86 static const char level_to_char
[] = {
89 [PA_LOG_NOTICE
] = 'N',
94 void pa_log_set_ident(const char *p
) {
97 if (!(ident
= pa_utf8_to_locale(p
)))
98 ident
= pa_ascii_filter(p
);
101 /* To make valgrind shut up. */
102 static void ident_destructor(void) PA_GCC_DESTRUCTOR
;
103 static void ident_destructor(void) {
104 if (!pa_in_valgrind())
110 void pa_log_set_level(pa_log_level_t l
) {
111 pa_assert(l
< PA_LOG_LEVEL_MAX
);
116 void pa_log_set_target(pa_log_target_t t
) {
117 pa_assert(t
< PA_LOG_TARGET_MAX
);
122 void pa_log_set_flags(pa_log_flags_t _flags
, pa_log_merge_t merge
) {
123 pa_assert(!(_flags
& ~(PA_LOG_COLORS
|PA_LOG_PRINT_TIME
|PA_LOG_PRINT_FILE
|PA_LOG_PRINT_META
|PA_LOG_PRINT_LEVEL
)));
125 if (merge
== PA_LOG_SET
)
127 else if (merge
== PA_LOG_UNSET
)
133 void pa_log_set_fd(int fd
) {
136 else if (log_fd
>= 0) {
142 void pa_log_set_show_backtrace(unsigned nlevels
) {
143 show_backtrace
= nlevels
;
146 void pa_log_set_skip_backtrace(unsigned nlevels
) {
147 skip_backtrace
= nlevels
;
150 #ifdef HAVE_EXECINFO_H
152 static char* get_backtrace(unsigned show_nframes
) {
155 char **symbols
, *e
, *r
;
159 pa_assert(show_nframes
> 0);
161 n_frames
= backtrace(trace
, PA_ELEMENTSOF(trace
));
166 symbols
= backtrace_symbols(trace
, n_frames
);
172 n
= PA_MIN((unsigned) n_frames
, s
+ show_nframes
);
176 for (j
= s
; j
< n
; j
++) {
179 a
+= strlen(pa_path_get_filename(symbols
[j
]));
182 r
= pa_xnew(char, a
);
187 for (j
= s
; j
< n
; j
++) {
195 sym
= pa_path_get_filename(symbols
[j
]);
210 static void init_defaults(void) {
217 if (pa_get_binary_name(binary
, sizeof(binary
)))
218 pa_log_set_ident(binary
);
221 if (getenv(ENV_LOG_SYSLOG
)) {
222 target_override
= PA_LOG_SYSLOG
;
223 target_override_set
= TRUE
;
226 if ((e
= getenv(ENV_LOG_LEVEL
))) {
227 maximum_level_override
= (pa_log_level_t
) atoi(e
);
229 if (maximum_level_override
>= PA_LOG_LEVEL_MAX
)
230 maximum_level_override
= PA_LOG_LEVEL_MAX
-1;
233 if (getenv(ENV_LOG_COLORS
))
234 flags_override
|= PA_LOG_COLORS
;
236 if (getenv(ENV_LOG_PRINT_TIME
))
237 flags_override
|= PA_LOG_PRINT_TIME
;
239 if (getenv(ENV_LOG_PRINT_FILE
))
240 flags_override
|= PA_LOG_PRINT_FILE
;
242 if (getenv(ENV_LOG_PRINT_META
))
243 flags_override
|= PA_LOG_PRINT_META
;
245 if (getenv(ENV_LOG_PRINT_LEVEL
))
246 flags_override
|= PA_LOG_PRINT_LEVEL
;
248 if ((e
= getenv(ENV_LOG_BACKTRACE
))) {
249 show_backtrace_override
= (unsigned) atoi(e
);
251 if (show_backtrace_override
<= 0)
252 show_backtrace_override
= 0;
255 if ((e
= getenv(ENV_LOG_BACKTRACE_SKIP
))) {
256 skip_backtrace
= (unsigned) atoi(e
);
258 if (skip_backtrace
<= 0)
262 if (getenv(ENV_LOG_NO_RATELIMIT
))
263 no_rate_limit
= TRUE
;
268 void pa_log_levelv_meta(
269 pa_log_level_t level
,
277 int saved_errno
= errno
;
279 pa_log_target_t _target
;
280 pa_log_level_t _maximum_level
;
281 unsigned _show_backtrace
;
282 pa_log_flags_t _flags
;
284 /* We don't use dynamic memory allocation here to minimize the hit
286 char text
[16*1024], location
[128], timestamp
[32];
288 pa_assert(level
< PA_LOG_LEVEL_MAX
);
293 _target
= target_override_set
? target_override
: target
;
294 _maximum_level
= PA_MAX(maximum_level
, maximum_level_override
);
295 _show_backtrace
= PA_MAX(show_backtrace
, show_backtrace_override
);
296 _flags
= flags
| flags_override
;
298 if (PA_LIKELY(level
> _maximum_level
)) {
303 pa_vsnprintf(text
, sizeof(text
), format
, ap
);
305 if ((_flags
& PA_LOG_PRINT_META
) && file
&& line
> 0 && func
)
306 pa_snprintf(location
, sizeof(location
), "[%s][%s:%i %s()] ", pa_thread_get_name(pa_thread_self()), file
, line
, func
);
307 else if ((_flags
& (PA_LOG_PRINT_META
|PA_LOG_PRINT_FILE
)) && file
)
308 pa_snprintf(location
, sizeof(location
), "[%s] %s: ", pa_thread_get_name(pa_thread_self()), pa_path_get_filename(file
));
312 if (_flags
& PA_LOG_PRINT_TIME
) {
313 static pa_usec_t start
, last
;
316 u
= pa_rtclock_now();
326 /* This is not thread safe, but this is a debugging tool only
330 pa_snprintf(timestamp
, sizeof(timestamp
), "(%4llu.%03llu|%4llu.%03llu) ",
331 (unsigned long long) (a
/ PA_USEC_PER_SEC
),
332 (unsigned long long) (((a
/ PA_USEC_PER_MSEC
)) % 1000),
333 (unsigned long long) (r
/ PA_USEC_PER_SEC
),
334 (unsigned long long) (((r
/ PA_USEC_PER_MSEC
)) % 1000));
339 #ifdef HAVE_EXECINFO_H
340 if (_show_backtrace
> 0)
341 bt
= get_backtrace(_show_backtrace
);
344 if (!pa_utf8_valid(text
))
345 pa_logl(level
, "Invalid UTF-8 string following below:");
347 for (t
= text
; t
; t
= n
) {
348 if ((n
= strchr(t
, '\n'))) {
353 /* We ignore strings only made out of whitespace */
354 if (t
[strspn(t
, "\t ")] == 0)
359 case PA_LOG_STDERR
: {
360 const char *prefix
= "", *suffix
= "", *grey
= "";
364 /* Yes indeed. Useless, but fun! */
365 if ((_flags
& PA_LOG_COLORS
) && isatty(STDERR_FILENO
)) {
366 if (level
<= PA_LOG_ERROR
)
367 prefix
= "\x1B[1;31m";
368 else if (level
<= PA_LOG_WARN
)
374 if (grey
[0] || prefix
[0])
379 /* We shouldn't be using dynamic allocation here to
380 * minimize the hit in RT threads */
381 if ((local_t
= pa_utf8_to_locale(t
)))
384 if (_flags
& PA_LOG_PRINT_LEVEL
)
385 fprintf(stderr
, "%s%c: %s%s%s%s%s%s\n", timestamp
, level_to_char
[level
], location
, prefix
, t
, grey
, pa_strempty(bt
), suffix
);
387 fprintf(stderr
, "%s%s%s%s%s%s%s\n", timestamp
, location
, prefix
, t
, grey
, pa_strempty(bt
), suffix
);
398 case PA_LOG_SYSLOG
: {
401 openlog(ident
, LOG_PID
, LOG_USER
);
403 if ((local_t
= pa_utf8_to_locale(t
)))
406 syslog(level_to_syslog
[level
], "%s%s%s%s", timestamp
, location
, t
, pa_strempty(bt
));
417 pa_snprintf(metadata
, sizeof(metadata
), "\n%c %s %s", level_to_char
[level
], timestamp
, location
);
419 if ((write(log_fd
, metadata
, strlen(metadata
)) < 0) || (write(log_fd
, t
, strlen(t
)) < 0)) {
422 fprintf(stderr
, "%s\n", "Error writing logs to a file descriptor. Redirect log messages to console.");
423 fprintf(stderr
, "%s %s\n", metadata
, t
);
424 pa_log_set_target(PA_LOG_STDERR
);
440 void pa_log_level_meta(
441 pa_log_level_t level
,
445 const char *format
, ...) {
448 va_start(ap
, format
);
449 pa_log_levelv_meta(level
, file
, line
, func
, format
, ap
);
453 void pa_log_levelv(pa_log_level_t level
, const char *format
, va_list ap
) {
454 pa_log_levelv_meta(level
, NULL
, 0, NULL
, format
, ap
);
457 void pa_log_level(pa_log_level_t level
, const char *format
, ...) {
460 va_start(ap
, format
);
461 pa_log_levelv_meta(level
, NULL
, 0, NULL
, format
, ap
);
465 pa_bool_t
pa_log_ratelimit(pa_log_level_t level
) {
466 /* Not more than 10 messages every 5s */
467 static PA_DEFINE_RATELIMIT(ratelimit
, 5 * PA_USEC_PER_SEC
, 10);
474 return pa_ratelimit_test(&ratelimit
, level
);