Merge commit 'origin/master-tx'
[platform/upstream/pulseaudio.git] / src / pulsecore / log.c
1 /***
2   This file is part of PulseAudio.
3
4   Copyright 2004-2006 Lennart Poettering
5   Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
6
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.
11
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.
16
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
20   USA.
21 ***/
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <stdarg.h>
28 #include <stdio.h>
29 #include <unistd.h>
30 #include <string.h>
31 #include <errno.h>
32
33 #ifdef HAVE_EXECINFO_H
34 #include <execinfo.h>
35 #endif
36
37 #ifdef HAVE_SYSLOG_H
38 #include <syslog.h>
39 #endif
40
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>
46
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>
52
53 #include "log.h"
54
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
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;
71
72 #ifdef HAVE_SYSLOG_H
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
79 };
80 #endif
81
82 static const char level_to_char[] = {
83     [PA_LOG_ERROR] = 'E',
84     [PA_LOG_WARN] = 'W',
85     [PA_LOG_NOTICE] = 'N',
86     [PA_LOG_INFO] = 'I',
87     [PA_LOG_DEBUG] = 'D'
88 };
89
90 void pa_log_set_ident(const char *p) {
91     pa_xfree(ident);
92
93     if (!(ident = pa_utf8_to_locale(p)))
94         ident = pa_ascii_filter(p);
95 }
96
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())
101         return;
102
103     pa_xfree(ident);
104 }
105
106 void pa_log_set_level(pa_log_level_t l) {
107     pa_assert(l < PA_LOG_LEVEL_MAX);
108
109     maximum_level = l;
110 }
111
112 void pa_log_set_target(pa_log_target_t t) {
113     pa_assert(t < PA_LOG_TARGET_MAX);
114
115     target = t;
116 }
117
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)));
120
121     if (merge == PA_LOG_SET)
122         flags |= _flags;
123     else if (merge == PA_LOG_UNSET)
124         flags &= ~_flags;
125     else
126         flags = _flags;
127 }
128
129 void pa_log_set_show_backtrace(unsigned nlevels) {
130     show_backtrace = nlevels;
131 }
132
133 void pa_log_set_skip_backtrace(unsigned nlevels) {
134     skip_backtrace = nlevels;
135 }
136
137 #ifdef HAVE_EXECINFO_H
138
139 static char* get_backtrace(unsigned show_nframes) {
140     void* trace[32];
141     int n_frames;
142     char **symbols, *e, *r;
143     unsigned j, n, s;
144     size_t a;
145
146     pa_assert(show_nframes > 0);
147
148     n_frames = backtrace(trace, PA_ELEMENTSOF(trace));
149
150     if (n_frames <= 0)
151         return NULL;
152
153     symbols = backtrace_symbols(trace, n_frames);
154
155     if (!symbols)
156         return NULL;
157
158     s = skip_backtrace;
159     n = PA_MIN((unsigned) n_frames, s + show_nframes);
160
161     a = 4;
162
163     for (j = s; j < n; j++) {
164         if (j > s)
165             a += 2;
166         a += strlen(pa_path_get_filename(symbols[j]));
167     }
168
169     r = pa_xnew(char, a);
170
171     strcpy(r, " (");
172     e = r + 2;
173
174     for (j = s; j < n; j++) {
175         const char *sym;
176
177         if (j > s) {
178             strcpy(e, "<<");
179             e += 2;
180         }
181
182         sym = pa_path_get_filename(symbols[j]);
183
184         strcpy(e, sym);
185         e += strlen(sym);
186     }
187
188     strcpy(e, ")");
189
190     free(symbols);
191
192     return r;
193 }
194
195 #endif
196
197 static void init_defaults(void) {
198     const char *e;
199
200     if (!ident) {
201         char binary[256];
202         if (pa_get_binary_name(binary, sizeof(binary)))
203             pa_log_set_ident(binary);
204     }
205
206     if (getenv(ENV_LOG_SYSLOG)) {
207         target_override = PA_LOG_SYSLOG;
208         target_override_set = TRUE;
209     }
210
211     if ((e = getenv(ENV_LOG_LEVEL))) {
212         maximum_level_override = (pa_log_level_t) atoi(e);
213
214         if (maximum_level_override >= PA_LOG_LEVEL_MAX)
215             maximum_level_override = PA_LOG_LEVEL_MAX-1;
216     }
217
218     if (getenv(ENV_LOG_COLORS))
219         flags_override |= PA_LOG_COLORS;
220
221     if (getenv(ENV_LOG_PRINT_TIME))
222         flags_override |= PA_LOG_PRINT_TIME;
223
224     if (getenv(ENV_LOG_PRINT_FILE))
225         flags_override |= PA_LOG_PRINT_FILE;
226
227     if (getenv(ENV_LOG_PRINT_META))
228         flags_override |= PA_LOG_PRINT_META;
229
230     if (getenv(ENV_LOG_PRINT_LEVEL))
231         flags_override |= PA_LOG_PRINT_LEVEL;
232
233     if ((e = getenv(ENV_LOG_BACKTRACE))) {
234         show_backtrace_override = (unsigned) atoi(e);
235
236         if (show_backtrace_override <= 0)
237             show_backtrace_override = 0;
238     }
239
240     if ((e = getenv(ENV_LOG_BACKTRACE_SKIP))) {
241         skip_backtrace = (unsigned) atoi(e);
242
243         if (skip_backtrace <= 0)
244             skip_backtrace = 0;
245     }
246 }
247
248 void pa_log_levelv_meta(
249         pa_log_level_t level,
250         const char*file,
251         int line,
252         const char *func,
253         const char *format,
254         va_list ap) {
255
256     char *t, *n;
257     int saved_errno = errno;
258     char *bt = NULL;
259     pa_log_target_t _target;
260     pa_log_level_t _maximum_level;
261     unsigned _show_backtrace;
262     pa_log_flags_t _flags;
263
264     /* We don't use dynamic memory allocation here to minimize the hit
265      * in RT threads */
266     char text[16*1024], location[128], timestamp[32];
267
268     pa_assert(level < PA_LOG_LEVEL_MAX);
269     pa_assert(format);
270
271     PA_ONCE_BEGIN {
272         init_defaults();
273     } PA_ONCE_END;
274
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;
279
280     if (PA_LIKELY(level > _maximum_level)) {
281         errno = saved_errno;
282         return;
283     }
284
285     pa_vsnprintf(text, sizeof(text), format, ap);
286
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));
291     else
292         location[0] = 0;
293
294     if (_flags & PA_LOG_PRINT_TIME) {
295         static pa_usec_t start, last;
296         pa_usec_t u, a, r;
297
298         u = pa_rtclock_now();
299
300         PA_ONCE_BEGIN {
301             start = u;
302             last = u;
303         } PA_ONCE_END;
304
305         r = u - last;
306         a = u - start;
307
308         /* This is not thread safe, but this is a debugging tool only
309          * anyway. */
310         last = u;
311
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));
317
318     } else
319         timestamp[0] = 0;
320
321 #ifdef HAVE_EXECINFO_H
322     if (_show_backtrace > 0)
323         bt = get_backtrace(_show_backtrace);
324 #endif
325
326     if (!pa_utf8_valid(text))
327         pa_logl(level, "Invalid UTF-8 string following below:");
328
329     for (t = text; t; t = n) {
330         if ((n = strchr(t, '\n'))) {
331             *n = 0;
332             n++;
333         }
334
335         /* We ignore strings only made out of whitespace */
336         if (t[strspn(t, "\t ")] == 0)
337             continue;
338
339         switch (_target) {
340
341             case PA_LOG_STDERR: {
342                 const char *prefix = "", *suffix = "", *grey = "";
343                 char *local_t;
344
345 #ifndef OS_IS_WIN32
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)
351                         prefix = "\x1B[1m";
352
353                     if (bt)
354                         grey = "\x1B[2m";
355
356                     if (grey[0] || prefix[0])
357                         suffix = "\x1B[0m";
358                 }
359 #endif
360
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)))
364                     t = local_t;
365
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);
368                 else
369                     fprintf(stderr, "%s%s%s%s%s%s%s\n", timestamp, location, prefix, t, grey, pa_strempty(bt), suffix);
370
371                 pa_xfree(local_t);
372
373                 break;
374             }
375
376 #ifdef HAVE_SYSLOG_H
377             case PA_LOG_SYSLOG: {
378                 char *local_t;
379
380                 openlog(ident, LOG_PID, LOG_USER);
381
382                 if ((local_t = pa_utf8_to_locale(t)))
383                     t = local_t;
384
385                 syslog(level_to_syslog[level], "%s%s%s%s", timestamp, location, t, pa_strempty(bt));
386                 pa_xfree(local_t);
387
388                 break;
389             }
390 #endif
391
392             case PA_LOG_NULL:
393             default:
394                 break;
395         }
396     }
397
398     pa_xfree(bt);
399     errno = saved_errno;
400 }
401
402 void pa_log_level_meta(
403         pa_log_level_t level,
404         const char*file,
405         int line,
406         const char *func,
407         const char *format, ...) {
408
409     va_list ap;
410     va_start(ap, format);
411     pa_log_levelv_meta(level, file, line, func, format, ap);
412     va_end(ap);
413 }
414
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);
417 }
418
419 void pa_log_level(pa_log_level_t level, const char *format, ...) {
420     va_list ap;
421
422     va_start(ap, format);
423     pa_log_levelv_meta(level, NULL, 0, NULL, format, ap);
424     va_end(ap);
425 }
426
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);
430
431     return pa_ratelimit_test(&ratelimit);
432 }