daemon: add nice value in service file to improve performance
[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, see <http://www.gnu.org/licenses/>.
19 ***/
20
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24
25 #include <stdarg.h>
26 #include <stdio.h>
27 #include <unistd.h>
28 #include <string.h>
29 #include <errno.h>
30 #include <fcntl.h>
31 #include <sys/stat.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 #ifdef HAVE_SYSTEMD_JOURNAL
42
43 /* sd_journal_send() implicitly add fields for the source file,
44  * function name and code line from where it's invoked. As the
45  * correct code location fields CODE_FILE, CODE_LINE and
46  * CODE_FUNC are already handled by this module, we do not want
47  * the automatic values supplied by the systemd journal API.
48  *
49  * Without suppressing these, both the actual log event source
50  * and the call to sd_journal_send() will be logged. */
51 #define SD_JOURNAL_SUPPRESS_LOCATION
52
53 #include <systemd/sd-journal.h>
54 #endif
55
56 #include <pulse/gccmacro.h>
57 #include <pulse/rtclock.h>
58 #include <pulse/utf8.h>
59 #include <pulse/xmalloc.h>
60 #include <pulse/util.h>
61 #include <pulse/timeval.h>
62
63 #include <pulsecore/macro.h>
64 #include <pulsecore/core-util.h>
65 #include <pulsecore/core-error.h>
66 #include <pulsecore/once.h>
67 #include <pulsecore/ratelimit.h>
68 #include <pulsecore/thread.h>
69 #include <pulsecore/i18n.h>
70
71 #include "log.h"
72
73 #ifdef TIZEN_DLOG
74 #include <dlog.h>
75 #define DLOG_TAG        "PULSEAUDIO"
76
77 #define COLOR_BLACK     30
78 #define COLOR_RED       31
79 #define COLOR_GREEN     32
80 #define COLOR_BLUE      34
81 #define COLOR_MAGENTA   35
82 #define COLOR_CYAN      36
83 #define COLOR_WHITE     97
84 #define COLOR_B_GRAY    100
85 #define COLOR_B_RED     101
86 #define COLOR_B_GREEN   102
87 #define COLOR_B_YELLOW  103
88 #define COLOR_B_BLUE    104
89 #define COLOR_B_MAGENTA 105
90 #define COLOR_B_CYAN    106
91 #define COLOR_REVERSE   7
92
93 #endif
94 #define ENV_LOG_SYSLOG "PULSE_LOG_SYSLOG"
95 #define ENV_LOG_JOURNAL "PULSE_LOG_JOURNAL"
96 #define ENV_LOG_LEVEL "PULSE_LOG"
97 #define ENV_LOG_COLORS "PULSE_LOG_COLORS"
98 #define ENV_LOG_PRINT_TIME "PULSE_LOG_TIME"
99 #define ENV_LOG_PRINT_FILE "PULSE_LOG_FILE"
100 #define ENV_LOG_PRINT_META "PULSE_LOG_META"
101 #define ENV_LOG_PRINT_LEVEL "PULSE_LOG_LEVEL"
102 #define ENV_LOG_BACKTRACE "PULSE_LOG_BACKTRACE"
103 #define ENV_LOG_BACKTRACE_SKIP "PULSE_LOG_BACKTRACE_SKIP"
104 #define ENV_LOG_NO_RATELIMIT "PULSE_LOG_NO_RATE_LIMIT"
105 #define LOG_MAX_SUFFIX_NUMBER 99
106
107 #ifdef TIZEN_DLOG
108 #define ENV_LOG_DLOG_CLIENT "PULSE_LOG_DLOG_CLIENT"
109 #define DAEMON_BINARY_NAME "pulseaudio"
110 #endif
111
112 static char *ident = NULL; /* in local charset format */
113 static pa_log_target target = { PA_LOG_STDERR, NULL };
114 static pa_log_target_type_t target_override;
115 static bool target_override_set = false;
116 static pa_log_level_t maximum_level = PA_LOG_ERROR, maximum_level_override = PA_LOG_ERROR;
117 static unsigned show_backtrace = 0, show_backtrace_override = 0, skip_backtrace = 0;
118 static pa_log_flags_t flags = 0, flags_override = 0;
119 static bool no_rate_limit = false;
120 static int log_fd = -1;
121 static int write_type = 0;
122
123 #ifdef HAVE_SYSLOG_H
124 static const int level_to_syslog[] = {
125     [PA_LOG_ERROR] = LOG_ERR,
126     [PA_LOG_WARN] = LOG_WARNING,
127     [PA_LOG_NOTICE] = LOG_NOTICE,
128     [PA_LOG_INFO] = LOG_INFO,
129     [PA_LOG_DEBUG] = LOG_DEBUG
130 };
131 #endif
132
133 /* These are actually equivalent to the syslog ones
134  * but we don't want to depend on syslog.h */
135 #ifdef HAVE_SYSTEMD_JOURNAL
136 static const int level_to_journal[] = {
137     [PA_LOG_ERROR]  = 3,
138     [PA_LOG_WARN]   = 4,
139     [PA_LOG_NOTICE] = 5,
140     [PA_LOG_INFO]   = 6,
141     [PA_LOG_DEBUG]  = 7
142 };
143 #endif
144
145 static const char level_to_char[] = {
146     [PA_LOG_ERROR] = 'E',
147     [PA_LOG_WARN] = 'W',
148     [PA_LOG_NOTICE] = 'N',
149     [PA_LOG_INFO] = 'I',
150     [PA_LOG_DEBUG] = 'D'
151 };
152
153 void pa_log_set_ident(const char *p) {
154     pa_xfree(ident);
155
156     if (!(ident = pa_utf8_to_locale(p)))
157         ident = pa_ascii_filter(p);
158 }
159
160 /* To make valgrind shut up. */
161 static void ident_destructor(void) PA_GCC_DESTRUCTOR;
162 static void ident_destructor(void) {
163     if (!pa_in_valgrind())
164         return;
165
166     pa_xfree(ident);
167 }
168
169 void pa_log_set_level(pa_log_level_t l) {
170     pa_assert(l < PA_LOG_LEVEL_MAX);
171
172     maximum_level = l;
173 }
174
175 int pa_log_set_target(pa_log_target *t) {
176     int fd = -1;
177     int old_fd;
178
179     pa_assert(t);
180
181     switch (t->type) {
182         case PA_LOG_STDERR:
183         case PA_LOG_SYSLOG:
184 #ifdef HAVE_SYSTEMD_JOURNAL
185         case PA_LOG_JOURNAL:
186 #endif
187 #ifdef TIZEN_DLOG
188         case PA_LOG_DLOG:
189         case PA_LOG_DLOG_COLOR:
190 #endif
191         case PA_LOG_NULL:
192             break;
193         case PA_LOG_FILE:
194             if ((fd = pa_open_cloexec(t->file, O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR)) < 0) {
195                 pa_log(_("Failed to open target file '%s'."), t->file);
196                 return -1;
197             }
198             break;
199         case PA_LOG_NEWFILE: {
200             char *file_path;
201             char *p;
202             unsigned version;
203
204             file_path = pa_sprintf_malloc("%s.xx", t->file);
205             p = file_path + strlen(t->file);
206
207             for (version = 0; version <= LOG_MAX_SUFFIX_NUMBER; version++) {
208                 memset(p, 0, 3); /* Overwrite the ".xx" part in file_path with zero bytes. */
209
210                 if (version > 0)
211                     pa_snprintf(p, 4, ".%u", version); /* Why 4? ".xx" + termitating zero byte. */
212
213                 if ((fd = pa_open_cloexec(file_path, O_WRONLY | O_TRUNC | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR)) >= 0)
214                     break;
215             }
216
217             if (version > LOG_MAX_SUFFIX_NUMBER) {
218                 pa_log(_("Tried to open target file '%s', '%s.1', '%s.2' ... '%s.%d', but all failed."),
219                         t->file, t->file, t->file, t->file, LOG_MAX_SUFFIX_NUMBER);
220                 pa_xfree(file_path);
221                 return -1;
222             } else
223                 pa_log_debug("Opened target file %s\n", file_path);
224
225             pa_xfree(file_path);
226             break;
227         }
228     }
229
230     target.type = t->type;
231     pa_xfree(target.file);
232     target.file = pa_xstrdup(t->file);
233
234     old_fd = log_fd;
235     log_fd = fd;
236
237     if (old_fd >= 0)
238         pa_close(old_fd);
239
240     return 0;
241 }
242
243 void pa_log_set_flags(pa_log_flags_t _flags, pa_log_merge_t merge) {
244     pa_assert(!(_flags & ~(PA_LOG_COLORS|PA_LOG_PRINT_TIME|PA_LOG_PRINT_FILE|PA_LOG_PRINT_META|PA_LOG_PRINT_LEVEL)));
245
246     if (merge == PA_LOG_SET)
247         flags |= _flags;
248     else if (merge == PA_LOG_UNSET)
249         flags &= ~_flags;
250     else
251         flags = _flags;
252 }
253
254 void pa_log_set_show_backtrace(unsigned nlevels) {
255     show_backtrace = nlevels;
256 }
257
258 void pa_log_set_skip_backtrace(unsigned nlevels) {
259     skip_backtrace = nlevels;
260 }
261
262 #ifdef HAVE_EXECINFO_H
263
264 static char* get_backtrace(unsigned show_nframes) {
265     void* trace[32];
266     int n_frames;
267     char **symbols, *e, *r;
268     unsigned j, n, s;
269     size_t a;
270
271     pa_assert(show_nframes > 0);
272
273     n_frames = backtrace(trace, PA_ELEMENTSOF(trace));
274
275     if (n_frames <= 0)
276         return NULL;
277
278     symbols = backtrace_symbols(trace, n_frames);
279
280     if (!symbols)
281         return NULL;
282
283     s = skip_backtrace;
284     n = PA_MIN((unsigned) n_frames, s + show_nframes);
285
286     a = 4;
287
288     for (j = s; j < n; j++) {
289         if (j > s)
290             a += 2;
291         a += strlen(pa_path_get_filename(symbols[j]));
292     }
293
294     r = pa_xnew(char, a);
295
296     strcpy(r, " (");
297     e = r + 2;
298
299     for (j = s; j < n; j++) {
300         const char *sym;
301
302         if (j > s) {
303             strcpy(e, "<<");
304             e += 2;
305         }
306
307         sym = pa_path_get_filename(symbols[j]);
308
309         strcpy(e, sym);
310         e += strlen(sym);
311     }
312
313     strcpy(e, ")");
314
315     free(symbols);
316
317     return r;
318 }
319
320 #endif
321
322 static void init_defaults(void) {
323     PA_ONCE_BEGIN {
324
325         const char *e;
326 #ifdef TIZEN_DLOG
327         char binary[256] = {0, };
328 #endif
329
330         if (!ident) {
331 #ifndef TIZEN_DLOG
332             char binary[256];
333 #endif
334             if (pa_get_binary_name(binary, sizeof(binary)))
335                 pa_log_set_ident(binary);
336         }
337
338         if (getenv(ENV_LOG_SYSLOG)) {
339             target_override = PA_LOG_SYSLOG;
340             target_override_set = true;
341         }
342
343 #ifdef HAVE_SYSTEMD_JOURNAL
344         if (getenv(ENV_LOG_JOURNAL)) {
345             target_override = PA_LOG_JOURNAL;
346             target_override_set = true;
347         }
348 #endif
349
350         if ((e = getenv(ENV_LOG_LEVEL))) {
351             maximum_level_override = (pa_log_level_t) atoi(e);
352
353             if (maximum_level_override >= PA_LOG_LEVEL_MAX)
354                 maximum_level_override = PA_LOG_LEVEL_MAX-1;
355         }
356
357 #ifdef TIZEN_DLOG
358         if (strnlen(binary, sizeof(binary)) > 0 &&
359             !pa_safe_streq(binary, DAEMON_BINARY_NAME)) {
360             target_override = PA_LOG_DLOG;
361             target_override_set = true;
362             maximum_level_override = PA_LOG_INFO;
363         }
364         if ((e = getenv(ENV_LOG_DLOG_CLIENT))) {
365             target_override = PA_LOG_DLOG;
366             target_override_set = true;
367             maximum_level_override = atoi(e);
368         }
369 #endif
370
371         if (getenv(ENV_LOG_COLORS))
372             flags_override |= PA_LOG_COLORS;
373
374         if (getenv(ENV_LOG_PRINT_TIME))
375             flags_override |= PA_LOG_PRINT_TIME;
376
377         if (getenv(ENV_LOG_PRINT_FILE))
378             flags_override |= PA_LOG_PRINT_FILE;
379
380         if (getenv(ENV_LOG_PRINT_META))
381             flags_override |= PA_LOG_PRINT_META;
382
383         if (getenv(ENV_LOG_PRINT_LEVEL))
384             flags_override |= PA_LOG_PRINT_LEVEL;
385
386         if ((e = getenv(ENV_LOG_BACKTRACE))) {
387             show_backtrace_override = (unsigned) atoi(e);
388
389             if (show_backtrace_override <= 0)
390                 show_backtrace_override = 0;
391         }
392
393         if ((e = getenv(ENV_LOG_BACKTRACE_SKIP))) {
394             skip_backtrace = (unsigned) atoi(e);
395
396             if (skip_backtrace <= 0)
397                 skip_backtrace = 0;
398         }
399
400         if (getenv(ENV_LOG_NO_RATELIMIT))
401             no_rate_limit = true;
402
403     } PA_ONCE_END;
404 }
405
406 #ifdef HAVE_SYSLOG_H
407 static void log_syslog(pa_log_level_t level, char *t, char *timestamp, char *location, char *bt) {
408     char *local_t;
409
410     openlog(ident, LOG_PID, LOG_USER);
411
412     if ((local_t = pa_utf8_to_locale(t)))
413         t = local_t;
414
415     syslog(level_to_syslog[level], "%s%s%s%s", timestamp, location, t, pa_strempty(bt));
416     pa_xfree(local_t);
417 }
418 #endif
419
420 void pa_log_levelv_meta(
421         pa_log_level_t level,
422         const char*file,
423         int line,
424         const char *func,
425         const char *format,
426         va_list ap) {
427
428     char *t, *n;
429     int saved_errno = errno;
430     char *bt = NULL;
431     pa_log_target_type_t _target;
432     pa_log_level_t _maximum_level;
433     unsigned _show_backtrace;
434     pa_log_flags_t _flags;
435
436     /* We don't use dynamic memory allocation here to minimize the hit
437      * in RT threads */
438     char text[16*1024], location[128], timestamp[32];
439
440     pa_assert(level < PA_LOG_LEVEL_MAX);
441     pa_assert(format);
442
443     init_defaults();
444
445     _target = target_override_set ? target_override : target.type;
446     _maximum_level = PA_MAX(maximum_level, maximum_level_override);
447     _show_backtrace = PA_MAX(show_backtrace, show_backtrace_override);
448     _flags = flags | flags_override;
449
450     if (PA_LIKELY(level > _maximum_level)) {
451         errno = saved_errno;
452         return;
453     }
454
455     pa_vsnprintf(text, sizeof(text), format, ap);
456
457 #ifdef TIZEN_DLOG
458     if ((_target == PA_LOG_DLOG) && file && line > 0 && func)
459         pa_snprintf(location, sizeof(location), "%s: %s(%i) > ",
460                     pa_path_get_filename(file), func, line);
461     else
462 #endif
463     if ((_flags & PA_LOG_PRINT_META) && file && line > 0 && func)
464         pa_snprintf(location, sizeof(location), "[%s][%s:%i %s()] ",
465                     pa_strnull(pa_thread_get_name(pa_thread_self())), file, line, func);
466     else if ((_flags & (PA_LOG_PRINT_META|PA_LOG_PRINT_FILE)) && file)
467         pa_snprintf(location, sizeof(location), "[%s] %s: ",
468                     pa_strnull(pa_thread_get_name(pa_thread_self())), pa_path_get_filename(file));
469     else
470         location[0] = 0;
471
472     if (_flags & PA_LOG_PRINT_TIME) {
473         static pa_usec_t start, last;
474         pa_usec_t u, a, r;
475
476         u = pa_rtclock_now();
477
478         PA_ONCE_BEGIN {
479             start = u;
480             last = u;
481         } PA_ONCE_END;
482
483         r = u - last;
484         a = u - start;
485
486         /* This is not thread safe, but this is a debugging tool only
487          * anyway. */
488         last = u;
489
490         pa_snprintf(timestamp, sizeof(timestamp), "(%4llu.%03llu|%4llu.%03llu) ",
491                     (unsigned long long) (a / PA_USEC_PER_SEC),
492                     (unsigned long long) (((a / PA_USEC_PER_MSEC)) % 1000),
493                     (unsigned long long) (r / PA_USEC_PER_SEC),
494                     (unsigned long long) (((r / PA_USEC_PER_MSEC)) % 1000));
495
496     } else
497         timestamp[0] = 0;
498
499 #ifdef HAVE_EXECINFO_H
500     if (_show_backtrace > 0)
501         bt = get_backtrace(_show_backtrace);
502 #endif
503
504     if (!pa_utf8_valid(text))
505         pa_logl(level, "Invalid UTF-8 string following below:");
506
507     for (t = text; t; t = n) {
508         if ((n = strchr(t, '\n'))) {
509             *n = 0;
510             n++;
511         }
512
513         /* We ignore strings only made out of whitespace */
514         if (t[strspn(t, "\t ")] == 0)
515             continue;
516
517         switch (_target) {
518
519             case PA_LOG_STDERR: {
520                 const char *prefix = "", *suffix = "", *grey = "";
521                 char *local_t;
522
523 #ifndef OS_IS_WIN32
524                 /* Yes indeed. Useless, but fun! */
525                 if ((_flags & PA_LOG_COLORS) && isatty(STDERR_FILENO)) {
526                     if (level <= PA_LOG_ERROR)
527                         prefix = "\x1B[1;31m";
528                     else if (level <= PA_LOG_WARN)
529                         prefix = "\x1B[1m";
530
531                     if (bt)
532                         grey = "\x1B[2m";
533
534                     if (grey[0] || prefix[0])
535                         suffix = "\x1B[0m";
536                 }
537 #endif
538
539                 /* We shouldn't be using dynamic allocation here to
540                  * minimize the hit in RT threads */
541                 if ((local_t = pa_utf8_to_locale(t)))
542                     t = local_t;
543
544                 if (_flags & PA_LOG_PRINT_LEVEL)
545                     fprintf(stderr, "%s%c: %s%s%s%s%s%s\n", timestamp, level_to_char[level], location, prefix, t, grey, pa_strempty(bt), suffix);
546                 else
547                     fprintf(stderr, "%s%s%s%s%s%s%s\n", timestamp, location, prefix, t, grey, pa_strempty(bt), suffix);
548 #ifdef OS_IS_WIN32
549                 fflush(stderr);
550 #endif
551
552                 pa_xfree(local_t);
553
554                 break;
555             }
556
557 #ifdef HAVE_SYSLOG_H
558             case PA_LOG_SYSLOG:
559                 log_syslog(level, t, timestamp, location, bt);
560                 break;
561 #endif
562
563 #ifdef HAVE_SYSTEMD_JOURNAL
564             case PA_LOG_JOURNAL:
565                 if (sd_journal_send("MESSAGE=%s", t,
566                                 "PRIORITY=%i", level_to_journal[level],
567                                 "CODE_FILE=%s", file,
568                                 "CODE_FUNC=%s", func,
569                                 "CODE_LINE=%d", line,
570                                 "PULSE_BACKTRACE=%s", pa_strempty(bt),
571                                 NULL) < 0) {
572 #ifdef HAVE_SYSLOG_H
573                     pa_log_target new_target = { .type = PA_LOG_SYSLOG, .file = NULL };
574
575                     syslog(level_to_syslog[PA_LOG_ERROR], "%s%s%s", timestamp, __FILE__,
576                            "Error writing logs to the journal. Redirect log messages to syslog.");
577                     log_syslog(level, t, timestamp, location, bt);
578 #else
579                     pa_log_target new_target = { .type = PA_LOG_STDERR, .file = NULL };
580
581                     saved_errno = errno;
582                     fprintf(stderr, "%s\n", "Error writing logs to the journal. Redirect log messages to console.");
583                     fprintf(stderr, "%s\n", t);
584 #endif
585                     pa_log_set_target(&new_target);
586                 }
587                 break;
588 #endif
589
590             case PA_LOG_FILE:
591             case PA_LOG_NEWFILE: {
592                 char *local_t;
593
594                 if ((local_t = pa_utf8_to_locale(t)))
595                     t = local_t;
596
597                 if (log_fd >= 0) {
598                     char metadata[256];
599
600                     if (_flags & PA_LOG_PRINT_LEVEL)
601                         pa_snprintf(metadata, sizeof(metadata), "%s%c: %s", timestamp, level_to_char[level], location);
602                     else
603                         pa_snprintf(metadata, sizeof(metadata), "%s%s", timestamp, location);
604
605                     if ((pa_write(log_fd, metadata, strlen(metadata), &write_type) < 0)
606                             || (pa_write(log_fd, t, strlen(t), &write_type) < 0)
607                             || (bt && pa_write(log_fd, bt, strlen(bt), &write_type) < 0)
608                             || (pa_write(log_fd, "\n", 1, &write_type) < 0)) {
609                         pa_log_target new_target = { .type = PA_LOG_STDERR, .file = NULL };
610                         saved_errno = errno;
611                         fprintf(stderr, "%s\n", "Error writing logs to a file descriptor. Redirect log messages to console.");
612                         fprintf(stderr, "%s %s\n", metadata, t);
613                         pa_log_set_target(&new_target);
614                     }
615                 }
616
617                 pa_xfree(local_t);
618
619                 break;
620             }
621
622 #ifdef TIZEN_DLOG
623             case PA_LOG_DLOG: {
624                 char *local_t;
625
626                 openlog(ident, LOG_PID, LOG_USER);
627
628                 if ((local_t = pa_utf8_to_locale(t)))
629                     t = local_t;
630
631                 switch (level) {
632                     case PA_LOG_DEBUG:
633                         print_system_log(DLOG_DEBUG, DLOG_TAG, "%s%s%s%s", location, timestamp, t, pa_strempty(bt));
634                         break;
635                     case PA_LOG_INFO:
636                     case PA_LOG_NOTICE: /* no notice category in dlog, use info instead */
637                         print_system_log(DLOG_INFO, DLOG_TAG, "%s%s%s%s", location, timestamp, t, pa_strempty(bt));
638                         break;
639                     case PA_LOG_WARN:
640                         print_system_log(DLOG_WARN, DLOG_TAG, "%s%s%s%s", location, timestamp, t, pa_strempty(bt));
641                         break;
642                     case PA_LOG_ERROR:
643                         print_system_log(DLOG_ERROR, DLOG_TAG, "%s%s%s%s", location, timestamp, t, pa_strempty(bt));
644                         break;
645                     default:
646                         print_system_log(DLOG_DEBUG, DLOG_TAG, "%s%s%s%s", location, timestamp, t, pa_strempty(bt));
647                         break;
648                 }
649
650                 pa_xfree(local_t);
651
652                 break;
653             }
654             case PA_LOG_DLOG_COLOR: {
655                 char *local_t;
656
657                 openlog(ident, LOG_PID, LOG_USER);
658
659                 if ((local_t = pa_utf8_to_locale(t)))
660                     t = local_t;
661
662                 switch (level) {
663                     case PA_LOG_DEBUG:
664                         print_system_log(DLOG_DEBUG, DLOG_TAG, "\033[%dm%s%s%s%s\033[0m", COLOR_GREEN, location, timestamp, t, pa_strempty(bt));
665                         break;
666                     case PA_LOG_INFO:
667                     case PA_LOG_NOTICE: /* no notice category in dlog, use info instead */
668                         print_system_log(DLOG_INFO, DLOG_TAG, "\033[%dm%s%s%s%s\033[0m", COLOR_BLUE, location, timestamp, t, pa_strempty(bt));
669                         break;
670                     case PA_LOG_WARN:
671                         print_system_log(DLOG_WARN, DLOG_TAG, "\033[%dm%s%s%s%s\033[0m", COLOR_MAGENTA, location, timestamp, t, pa_strempty(bt));
672                         break;
673                     case PA_LOG_ERROR:
674                         print_system_log(DLOG_ERROR, DLOG_TAG, "\033[%dm%s%s%s%s\033[0m", COLOR_RED, location, timestamp, t, pa_strempty(bt));
675                         break;
676                     default:
677                         print_system_log(DLOG_DEBUG, DLOG_TAG, "\033[%dm%s%s%s%s\033[0m", COLOR_GREEN, location, timestamp, t, pa_strempty(bt));
678                         break;
679                 }
680
681                 pa_xfree(local_t);
682
683                 break;
684             }
685
686 #endif
687             case PA_LOG_NULL:
688             default:
689                 break;
690         }
691     }
692
693     pa_xfree(bt);
694     errno = saved_errno;
695 }
696
697 void pa_log_level_meta(
698         pa_log_level_t level,
699         const char*file,
700         int line,
701         const char *func,
702         const char *format, ...) {
703
704     va_list ap;
705     va_start(ap, format);
706     pa_log_levelv_meta(level, file, line, func, format, ap);
707     va_end(ap);
708 }
709
710 void pa_log_levelv(pa_log_level_t level, const char *format, va_list ap) {
711     pa_log_levelv_meta(level, NULL, 0, NULL, format, ap);
712 }
713
714 void pa_log_level(pa_log_level_t level, const char *format, ...) {
715     va_list ap;
716
717     va_start(ap, format);
718     pa_log_levelv_meta(level, NULL, 0, NULL, format, ap);
719     va_end(ap);
720 }
721
722 bool pa_log_ratelimit(pa_log_level_t level) {
723     /* Not more than 10 messages every 5s */
724     static PA_DEFINE_RATELIMIT(ratelimit, 5 * PA_USEC_PER_SEC, 10);
725
726     init_defaults();
727
728     if (no_rate_limit)
729         return true;
730
731     return pa_ratelimit_test(&ratelimit, level);
732 }
733
734 pa_log_target *pa_log_target_new(pa_log_target_type_t type, const char *file) {
735     pa_log_target *t = NULL;
736
737     t = pa_xnew(pa_log_target, 1);
738
739     t->type = type;
740     t->file = pa_xstrdup(file);
741
742     return t;
743 }
744
745 void pa_log_target_free(pa_log_target *t) {
746     pa_assert(t);
747
748     pa_xfree(t->file);
749     pa_xfree(t);
750 }
751
752 pa_log_target *pa_log_parse_target(const char *string) {
753     pa_log_target *t = NULL;
754
755     pa_assert(string);
756
757     if (pa_streq(string, "stderr"))
758         t = pa_log_target_new(PA_LOG_STDERR, NULL);
759     else if (pa_streq(string, "syslog"))
760         t = pa_log_target_new(PA_LOG_SYSLOG, NULL);
761 #ifdef HAVE_SYSTEMD_JOURNAL
762     else if (pa_streq(string, "journal"))
763         t = pa_log_target_new(PA_LOG_JOURNAL, NULL);
764 #endif
765     else if (pa_streq(string, "null"))
766         t = pa_log_target_new(PA_LOG_NULL, NULL);
767     else if (pa_startswith(string, "file:"))
768         t = pa_log_target_new(PA_LOG_FILE, string + 5);
769     else if (pa_startswith(string, "newfile:"))
770         t = pa_log_target_new(PA_LOG_NEWFILE, string + 8);
771 #ifdef TIZEN_DLOG
772     else if (pa_streq(string, "dlog"))
773         t = pa_log_target_new(PA_LOG_DLOG, NULL);
774     else if (pa_streq(string, "dlog-color"))
775         t = pa_log_target_new(PA_LOG_DLOG_COLOR, NULL);
776 #endif
777     else
778         pa_log(_("Invalid log target."));
779
780     return t;
781 }
782
783 char *pa_log_target_to_string(const pa_log_target *t) {
784     char *string = NULL;
785
786     pa_assert(t);
787
788     switch (t->type) {
789         case PA_LOG_STDERR:
790             string = pa_xstrdup("stderr");
791             break;
792         case PA_LOG_SYSLOG:
793             string = pa_xstrdup("syslog");
794             break;
795 #ifdef HAVE_SYSTEMD_JOURNAL
796         case PA_LOG_JOURNAL:
797             string = pa_xstrdup("journal");
798             break;
799 #endif
800 #ifdef TIZEN_DLOG
801         case PA_LOG_DLOG:
802             string = pa_xstrdup("dlog");
803             break;
804         case PA_LOG_DLOG_COLOR:
805             string = pa_xstrdup("dlog-color");
806             break;
807 #endif
808         case PA_LOG_NULL:
809             string = pa_xstrdup("null");
810             break;
811         case PA_LOG_FILE:
812             string = pa_sprintf_malloc("file:%s", t->file);
813             break;
814         case PA_LOG_NEWFILE:
815             string = pa_sprintf_malloc("newfile:%s", t->file);
816             break;
817     }
818
819     return string;
820 }