]> code.delx.au - pulseaudio/blob - src/pulsecore/log.c
change default log level for the library to PA_LOG_ERROR to avoid spamming to stderr...
[pulseaudio] / 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 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_SYSLOG_H
34 #include <syslog.h>
35 #endif
36
37 #include <pulse/utf8.h>
38 #include <pulse/xmalloc.h>
39 #include <pulse/util.h>
40 #include <pulse/timeval.h>
41
42 #include <pulsecore/macro.h>
43 #include <pulsecore/core-util.h>
44 #include <pulsecore/rtclock.h>
45 #include <pulsecore/once.h>
46
47 #include "log.h"
48
49 #define ENV_LOGLEVEL "PULSE_LOG"
50 #define ENV_LOGMETA "PULSE_LOG_META"
51 #define ENV_LOGTIME "PULSE_LOG_TIME"
52
53 static char *log_ident = NULL, *log_ident_local = NULL;
54 static pa_log_target_t log_target = PA_LOG_STDERR;
55 static pa_log_func_t user_log_func = NULL;
56 static pa_log_level_t maximal_level = PA_LOG_ERROR;
57
58 #ifdef HAVE_SYSLOG_H
59 static const int level_to_syslog[] = {
60 [PA_LOG_ERROR] = LOG_ERR,
61 [PA_LOG_WARN] = LOG_WARNING,
62 [PA_LOG_NOTICE] = LOG_NOTICE,
63 [PA_LOG_INFO] = LOG_INFO,
64 [PA_LOG_DEBUG] = LOG_DEBUG
65 };
66 #endif
67
68 static const char level_to_char[] = {
69 [PA_LOG_ERROR] = 'E',
70 [PA_LOG_WARN] = 'W',
71 [PA_LOG_NOTICE] = 'N',
72 [PA_LOG_INFO] = 'I',
73 [PA_LOG_DEBUG] = 'D'
74 };
75
76 void pa_log_set_ident(const char *p) {
77 pa_xfree(log_ident);
78 pa_xfree(log_ident_local);
79
80 log_ident = pa_xstrdup(p);
81 if (!(log_ident_local = pa_utf8_to_locale(log_ident)))
82 log_ident_local = pa_xstrdup(log_ident);
83 }
84
85 /* To make valgrind shut up. */
86 static void ident_destructor(void) PA_GCC_DESTRUCTOR;
87 static void ident_destructor(void) {
88 pa_xfree(log_ident);
89 pa_xfree(log_ident_local);
90 }
91
92 void pa_log_set_maximal_level(pa_log_level_t l) {
93 pa_assert(l < PA_LOG_LEVEL_MAX);
94
95 maximal_level = l;
96 }
97
98 void pa_log_set_target(pa_log_target_t t, pa_log_func_t func) {
99 pa_assert(t == PA_LOG_USER || !func);
100
101 log_target = t;
102 user_log_func = func;
103 }
104
105 void pa_log_levelv_meta(
106 pa_log_level_t level,
107 const char*file,
108 int line,
109 const char *func,
110 const char *format,
111 va_list ap) {
112
113 const char *e;
114 char *t, *n;
115 int saved_errno = errno;
116
117 /* We don't use dynamic memory allocation here to minimize the hit
118 * in RT threads */
119 char text[1024], location[128], timestamp[32];
120
121 pa_assert(level < PA_LOG_LEVEL_MAX);
122 pa_assert(format);
123
124 if ((e = getenv(ENV_LOGLEVEL)))
125 maximal_level = atoi(e);
126
127 if (level > maximal_level) {
128 errno = saved_errno;
129 return;
130 }
131
132 pa_vsnprintf(text, sizeof(text), format, ap);
133
134 if (getenv(ENV_LOGMETA) && file && line > 0 && func)
135 pa_snprintf(location, sizeof(location), "[%s:%i %s()] ", file, line, func);
136 else if (file)
137 pa_snprintf(location, sizeof(location), "%s: ", pa_path_get_filename(file));
138 else
139 location[0] = 0;
140
141 if (getenv(ENV_LOGTIME)) {
142 static pa_usec_t start;
143 pa_usec_t u;
144
145 u = pa_rtclock_usec();
146
147 PA_ONCE_BEGIN {
148 start = u;
149 } PA_ONCE_END;
150
151 u -= start;
152
153 pa_snprintf(timestamp, sizeof(timestamp), "(%4llu.%03llu) ", (unsigned long long) (u / PA_USEC_PER_SEC), (unsigned long long) (((u / PA_USEC_PER_MSEC)) % 1000));
154
155 } else
156 timestamp[0] = 0;
157
158 if (!pa_utf8_valid(text))
159 pa_log_level(level, __FILE__": invalid UTF-8 string following below:");
160
161 for (t = text; t; t = n) {
162 if ((n = strchr(t, '\n'))) {
163 *n = 0;
164 n++;
165 }
166
167 if (!*t)
168 continue;
169
170 switch (log_target) {
171 case PA_LOG_STDERR: {
172 const char *prefix = "", *suffix = "";
173 char *local_t;
174
175 #ifndef OS_IS_WIN32
176 /* Yes indeed. Useless, but fun! */
177 if (isatty(STDERR_FILENO)) {
178 if (level <= PA_LOG_ERROR) {
179 prefix = "\x1B[1;31m";
180 suffix = "\x1B[0m";
181 } else if (level <= PA_LOG_WARN) {
182 prefix = "\x1B[1m";
183 suffix = "\x1B[0m";
184 }
185 }
186 #endif
187
188 /* We shouldn't be using dynamic allocation here to
189 * minimize the hit in RT threads */
190 local_t = pa_utf8_to_locale(t);
191 if (!local_t)
192 fprintf(stderr, "%s%c: %s%s%s%s\n", timestamp, level_to_char[level], location, prefix, t, suffix);
193 else {
194 fprintf(stderr, "%s%c: %s%s%s%s\n", timestamp, level_to_char[level], location, prefix, local_t, suffix);
195 pa_xfree(local_t);
196 }
197
198 break;
199 }
200
201 #ifdef HAVE_SYSLOG_H
202 case PA_LOG_SYSLOG: {
203 char *local_t;
204
205 openlog(log_ident_local ? log_ident_local : "???", LOG_PID, LOG_USER);
206
207 local_t = pa_utf8_to_locale(t);
208 if (!local_t)
209 syslog(level_to_syslog[level], "%s%s%s", timestamp, location, t);
210 else {
211 syslog(level_to_syslog[level], "%s%s%s", timestamp, location, local_t);
212 pa_xfree(local_t);
213 }
214
215 closelog();
216 break;
217 }
218 #endif
219
220 case PA_LOG_USER: {
221 char x[1024];
222
223 pa_snprintf(x, sizeof(x), "%s%s%s", timestamp, location, t);
224 user_log_func(level, x);
225
226 break;
227 }
228
229 case PA_LOG_NULL:
230 default:
231 break;
232 }
233 }
234
235 errno = saved_errno;
236 }
237
238 void pa_log_level_meta(
239 pa_log_level_t level,
240 const char*file,
241 int line,
242 const char *func,
243 const char *format, ...) {
244
245 va_list ap;
246 va_start(ap, format);
247 pa_log_levelv_meta(level, file, line, func, format, ap);
248 va_end(ap);
249 }
250
251 void pa_log_levelv(pa_log_level_t level, const char *format, va_list ap) {
252 pa_log_levelv_meta(level, NULL, 0, NULL, format, ap);
253 }
254
255 void pa_log_level(pa_log_level_t level, const char *format, ...) {
256 va_list ap;
257
258 va_start(ap, format);
259 pa_log_levelv_meta(level, NULL, 0, NULL, format, ap);
260 va_end(ap);
261 }