153a5a1b3Sopenharmony_ci/***
253a5a1b3Sopenharmony_ci  This file is part of PulseAudio.
353a5a1b3Sopenharmony_ci
453a5a1b3Sopenharmony_ci  Copyright 2004-2006 Lennart Poettering
553a5a1b3Sopenharmony_ci  Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
653a5a1b3Sopenharmony_ci
753a5a1b3Sopenharmony_ci  PulseAudio is free software; you can redistribute it and/or modify
853a5a1b3Sopenharmony_ci  it under the terms of the GNU Lesser General Public License as
953a5a1b3Sopenharmony_ci  published by the Free Software Foundation; either version 2.1 of the
1053a5a1b3Sopenharmony_ci  License, or (at your option) any later version.
1153a5a1b3Sopenharmony_ci
1253a5a1b3Sopenharmony_ci  PulseAudio is distributed in the hope that it will be useful, but
1353a5a1b3Sopenharmony_ci  WITHOUT ANY WARRANTY; without even the implied warranty of
1453a5a1b3Sopenharmony_ci  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1553a5a1b3Sopenharmony_ci  General Public License for more details.
1653a5a1b3Sopenharmony_ci
1753a5a1b3Sopenharmony_ci  You should have received a copy of the GNU Lesser General Public
1853a5a1b3Sopenharmony_ci  License along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
1953a5a1b3Sopenharmony_ci***/
2053a5a1b3Sopenharmony_ci
2153a5a1b3Sopenharmony_ci#ifdef HAVE_CONFIG_H
2253a5a1b3Sopenharmony_ci#include <config.h>
2353a5a1b3Sopenharmony_ci#endif
2453a5a1b3Sopenharmony_ci
2553a5a1b3Sopenharmony_ci#include <stdarg.h>
2653a5a1b3Sopenharmony_ci#include <stdio.h>
2753a5a1b3Sopenharmony_ci#include <unistd.h>
2853a5a1b3Sopenharmony_ci#include <string.h>
2953a5a1b3Sopenharmony_ci#include <errno.h>
3053a5a1b3Sopenharmony_ci#include <fcntl.h>
3153a5a1b3Sopenharmony_ci#include <sys/stat.h>
3253a5a1b3Sopenharmony_ci
3353a5a1b3Sopenharmony_ci#ifdef HAVE_EXECINFO_H
3453a5a1b3Sopenharmony_ci#include <execinfo.h>
3553a5a1b3Sopenharmony_ci#endif
3653a5a1b3Sopenharmony_ci
3753a5a1b3Sopenharmony_ci#ifdef HAVE_SYSLOG_H
3853a5a1b3Sopenharmony_ci#include <syslog.h>
3953a5a1b3Sopenharmony_ci#endif
4053a5a1b3Sopenharmony_ci
4153a5a1b3Sopenharmony_ci#ifdef HAVE_SYSTEMD_JOURNAL
4253a5a1b3Sopenharmony_ci
4353a5a1b3Sopenharmony_ci/* sd_journal_send() implicitly add fields for the source file,
4453a5a1b3Sopenharmony_ci * function name and code line from where it's invoked. As the
4553a5a1b3Sopenharmony_ci * correct code location fields CODE_FILE, CODE_LINE and
4653a5a1b3Sopenharmony_ci * CODE_FUNC are already handled by this module, we do not want
4753a5a1b3Sopenharmony_ci * the automatic values supplied by the systemd journal API.
4853a5a1b3Sopenharmony_ci *
4953a5a1b3Sopenharmony_ci * Without suppressing these, both the actual log event source
5053a5a1b3Sopenharmony_ci * and the call to sd_journal_send() will be logged. */
5153a5a1b3Sopenharmony_ci#define SD_JOURNAL_SUPPRESS_LOCATION
5253a5a1b3Sopenharmony_ci
5353a5a1b3Sopenharmony_ci#include <systemd/sd-journal.h>
5453a5a1b3Sopenharmony_ci#endif
5553a5a1b3Sopenharmony_ci
5653a5a1b3Sopenharmony_ci#include <pulse/gccmacro.h>
5753a5a1b3Sopenharmony_ci#include <pulse/rtclock.h>
5853a5a1b3Sopenharmony_ci#include <pulse/utf8.h>
5953a5a1b3Sopenharmony_ci#include <pulse/xmalloc.h>
6053a5a1b3Sopenharmony_ci#include <pulse/util.h>
6153a5a1b3Sopenharmony_ci#include <pulse/timeval.h>
6253a5a1b3Sopenharmony_ci
6353a5a1b3Sopenharmony_ci#include <pulsecore/macro.h>
6453a5a1b3Sopenharmony_ci#include <pulsecore/core-util.h>
6553a5a1b3Sopenharmony_ci#include <pulsecore/core-error.h>
6653a5a1b3Sopenharmony_ci#include <pulsecore/once.h>
6753a5a1b3Sopenharmony_ci#include <pulsecore/ratelimit.h>
6853a5a1b3Sopenharmony_ci#include <pulsecore/thread.h>
6953a5a1b3Sopenharmony_ci#include <pulsecore/i18n.h>
7053a5a1b3Sopenharmony_ci
7153a5a1b3Sopenharmony_ci#include "log.h"
7253a5a1b3Sopenharmony_ci
7353a5a1b3Sopenharmony_ci#define ENV_LOG_SYSLOG "PULSE_LOG_SYSLOG"
7453a5a1b3Sopenharmony_ci#define ENV_LOG_JOURNAL "PULSE_LOG_JOURNAL"
7553a5a1b3Sopenharmony_ci#define ENV_LOG_LEVEL "PULSE_LOG"
7653a5a1b3Sopenharmony_ci#define ENV_LOG_COLORS "PULSE_LOG_COLORS"
7753a5a1b3Sopenharmony_ci#define ENV_LOG_PRINT_TIME "PULSE_LOG_TIME"
7853a5a1b3Sopenharmony_ci#define ENV_LOG_PRINT_FILE "PULSE_LOG_FILE"
7953a5a1b3Sopenharmony_ci#define ENV_LOG_PRINT_META "PULSE_LOG_META"
8053a5a1b3Sopenharmony_ci#define ENV_LOG_PRINT_LEVEL "PULSE_LOG_LEVEL"
8153a5a1b3Sopenharmony_ci#define ENV_LOG_BACKTRACE "PULSE_LOG_BACKTRACE"
8253a5a1b3Sopenharmony_ci#define ENV_LOG_BACKTRACE_SKIP "PULSE_LOG_BACKTRACE_SKIP"
8353a5a1b3Sopenharmony_ci#define ENV_LOG_NO_RATELIMIT "PULSE_LOG_NO_RATE_LIMIT"
8453a5a1b3Sopenharmony_ci#define LOG_MAX_SUFFIX_NUMBER 99
8553a5a1b3Sopenharmony_ci
8653a5a1b3Sopenharmony_cistatic char *ident = NULL; /* in local charset format */
8753a5a1b3Sopenharmony_cistatic pa_log_target target = { PA_LOG_STDERR, NULL };
8853a5a1b3Sopenharmony_cistatic pa_log_target_type_t target_override;
8953a5a1b3Sopenharmony_cistatic bool target_override_set = false;
9053a5a1b3Sopenharmony_cistatic pa_log_level_t maximum_level = PA_LOG_ERROR, maximum_level_override = PA_LOG_ERROR;
9153a5a1b3Sopenharmony_cistatic unsigned show_backtrace = 0, show_backtrace_override = 0, skip_backtrace = 0;
9253a5a1b3Sopenharmony_cistatic pa_log_flags_t flags = 0, flags_override = 0;
9353a5a1b3Sopenharmony_cistatic bool no_rate_limit = false;
9453a5a1b3Sopenharmony_cistatic int log_fd = -1;
9553a5a1b3Sopenharmony_cistatic int write_type = 0;
9653a5a1b3Sopenharmony_ci
9753a5a1b3Sopenharmony_ci#ifdef HAVE_SYSLOG_H
9853a5a1b3Sopenharmony_cistatic const int level_to_syslog[] = {
9953a5a1b3Sopenharmony_ci    [PA_LOG_ERROR] = LOG_ERR,
10053a5a1b3Sopenharmony_ci    [PA_LOG_WARN] = LOG_WARNING,
10153a5a1b3Sopenharmony_ci    [PA_LOG_NOTICE] = LOG_NOTICE,
10253a5a1b3Sopenharmony_ci    [PA_LOG_INFO] = LOG_INFO,
10353a5a1b3Sopenharmony_ci    [PA_LOG_DEBUG] = LOG_DEBUG
10453a5a1b3Sopenharmony_ci};
10553a5a1b3Sopenharmony_ci#endif
10653a5a1b3Sopenharmony_ci
10753a5a1b3Sopenharmony_ci/* These are actually equivalent to the syslog ones
10853a5a1b3Sopenharmony_ci * but we don't want to depend on syslog.h */
10953a5a1b3Sopenharmony_ci#ifdef HAVE_SYSTEMD_JOURNAL
11053a5a1b3Sopenharmony_cistatic const int level_to_journal[] = {
11153a5a1b3Sopenharmony_ci    [PA_LOG_ERROR]  = 3,
11253a5a1b3Sopenharmony_ci    [PA_LOG_WARN]   = 4,
11353a5a1b3Sopenharmony_ci    [PA_LOG_NOTICE] = 5,
11453a5a1b3Sopenharmony_ci    [PA_LOG_INFO]   = 6,
11553a5a1b3Sopenharmony_ci    [PA_LOG_DEBUG]  = 7
11653a5a1b3Sopenharmony_ci};
11753a5a1b3Sopenharmony_ci#endif
11853a5a1b3Sopenharmony_ci
11953a5a1b3Sopenharmony_cistatic const char level_to_char[] = {
12053a5a1b3Sopenharmony_ci    [PA_LOG_ERROR] = 'E',
12153a5a1b3Sopenharmony_ci    [PA_LOG_WARN] = 'W',
12253a5a1b3Sopenharmony_ci    [PA_LOG_NOTICE] = 'N',
12353a5a1b3Sopenharmony_ci    [PA_LOG_INFO] = 'I',
12453a5a1b3Sopenharmony_ci    [PA_LOG_DEBUG] = 'D'
12553a5a1b3Sopenharmony_ci};
12653a5a1b3Sopenharmony_ci
12753a5a1b3Sopenharmony_civoid pa_log_set_ident(const char *p) {
12853a5a1b3Sopenharmony_ci    pa_xfree(ident);
12953a5a1b3Sopenharmony_ci
13053a5a1b3Sopenharmony_ci    if (!(ident = pa_utf8_to_locale(p)))
13153a5a1b3Sopenharmony_ci        ident = pa_ascii_filter(p);
13253a5a1b3Sopenharmony_ci}
13353a5a1b3Sopenharmony_ci
13453a5a1b3Sopenharmony_ci/* To make valgrind shut up. */
13553a5a1b3Sopenharmony_cistatic void ident_destructor(void) PA_GCC_DESTRUCTOR;
13653a5a1b3Sopenharmony_cistatic void ident_destructor(void) {
13753a5a1b3Sopenharmony_ci    if (!pa_in_valgrind())
13853a5a1b3Sopenharmony_ci        return;
13953a5a1b3Sopenharmony_ci
14053a5a1b3Sopenharmony_ci    pa_xfree(ident);
14153a5a1b3Sopenharmony_ci}
14253a5a1b3Sopenharmony_ci
14353a5a1b3Sopenharmony_civoid pa_log_set_level(pa_log_level_t l) {
14453a5a1b3Sopenharmony_ci    pa_assert(l < PA_LOG_LEVEL_MAX);
14553a5a1b3Sopenharmony_ci
14653a5a1b3Sopenharmony_ci    maximum_level = l;
14753a5a1b3Sopenharmony_ci}
14853a5a1b3Sopenharmony_ci
14953a5a1b3Sopenharmony_ciint pa_log_set_target(pa_log_target *t) {
15053a5a1b3Sopenharmony_ci    int fd = -1;
15153a5a1b3Sopenharmony_ci    int old_fd;
15253a5a1b3Sopenharmony_ci
15353a5a1b3Sopenharmony_ci    pa_assert(t);
15453a5a1b3Sopenharmony_ci
15553a5a1b3Sopenharmony_ci    switch (t->type) {
15653a5a1b3Sopenharmony_ci        case PA_LOG_STDERR:
15753a5a1b3Sopenharmony_ci        case PA_LOG_SYSLOG:
15853a5a1b3Sopenharmony_ci#ifdef HAVE_SYSTEMD_JOURNAL
15953a5a1b3Sopenharmony_ci        case PA_LOG_JOURNAL:
16053a5a1b3Sopenharmony_ci#endif
16153a5a1b3Sopenharmony_ci        case PA_LOG_NULL:
16253a5a1b3Sopenharmony_ci            break;
16353a5a1b3Sopenharmony_ci        case PA_LOG_FILE:
16453a5a1b3Sopenharmony_ci            if ((fd = pa_open_cloexec(t->file, O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR)) < 0) {
16553a5a1b3Sopenharmony_ci                pa_log(_("Failed to open target file '%s'."), t->file);
16653a5a1b3Sopenharmony_ci                return -1;
16753a5a1b3Sopenharmony_ci            }
16853a5a1b3Sopenharmony_ci            break;
16953a5a1b3Sopenharmony_ci        case PA_LOG_NEWFILE: {
17053a5a1b3Sopenharmony_ci            char *file_path;
17153a5a1b3Sopenharmony_ci            char *p;
17253a5a1b3Sopenharmony_ci            unsigned version;
17353a5a1b3Sopenharmony_ci
17453a5a1b3Sopenharmony_ci            file_path = pa_sprintf_malloc("%s.xx", t->file);
17553a5a1b3Sopenharmony_ci            p = file_path + strlen(t->file);
17653a5a1b3Sopenharmony_ci
17753a5a1b3Sopenharmony_ci            for (version = 0; version <= LOG_MAX_SUFFIX_NUMBER; version++) {
17853a5a1b3Sopenharmony_ci                memset(p, 0, 3); /* Overwrite the ".xx" part in file_path with zero bytes. */
17953a5a1b3Sopenharmony_ci
18053a5a1b3Sopenharmony_ci                if (version > 0)
18153a5a1b3Sopenharmony_ci                    pa_snprintf(p, 4, ".%u", version); /* Why 4? ".xx" + termitating zero byte. */
18253a5a1b3Sopenharmony_ci
18353a5a1b3Sopenharmony_ci                if ((fd = pa_open_cloexec(file_path, O_WRONLY | O_TRUNC | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR)) >= 0)
18453a5a1b3Sopenharmony_ci                    break;
18553a5a1b3Sopenharmony_ci            }
18653a5a1b3Sopenharmony_ci
18753a5a1b3Sopenharmony_ci            if (version > LOG_MAX_SUFFIX_NUMBER) {
18853a5a1b3Sopenharmony_ci                pa_log(_("Tried to open target file '%s', '%s.1', '%s.2' ... '%s.%d', but all failed."),
18953a5a1b3Sopenharmony_ci                        t->file, t->file, t->file, t->file, LOG_MAX_SUFFIX_NUMBER);
19053a5a1b3Sopenharmony_ci                pa_xfree(file_path);
19153a5a1b3Sopenharmony_ci                return -1;
19253a5a1b3Sopenharmony_ci            } else
19353a5a1b3Sopenharmony_ci                pa_log_debug("Opened target file %s\n", file_path);
19453a5a1b3Sopenharmony_ci
19553a5a1b3Sopenharmony_ci            pa_xfree(file_path);
19653a5a1b3Sopenharmony_ci            break;
19753a5a1b3Sopenharmony_ci        }
19853a5a1b3Sopenharmony_ci    }
19953a5a1b3Sopenharmony_ci
20053a5a1b3Sopenharmony_ci    target.type = t->type;
20153a5a1b3Sopenharmony_ci    pa_xfree(target.file);
20253a5a1b3Sopenharmony_ci    target.file = pa_xstrdup(t->file);
20353a5a1b3Sopenharmony_ci
20453a5a1b3Sopenharmony_ci    old_fd = log_fd;
20553a5a1b3Sopenharmony_ci    log_fd = fd;
20653a5a1b3Sopenharmony_ci
20753a5a1b3Sopenharmony_ci    if (old_fd >= 0)
20853a5a1b3Sopenharmony_ci        pa_close(old_fd);
20953a5a1b3Sopenharmony_ci
21053a5a1b3Sopenharmony_ci    return 0;
21153a5a1b3Sopenharmony_ci}
21253a5a1b3Sopenharmony_ci
21353a5a1b3Sopenharmony_civoid pa_log_set_flags(pa_log_flags_t _flags, pa_log_merge_t merge) {
21453a5a1b3Sopenharmony_ci    pa_assert(!(_flags & ~(PA_LOG_COLORS|PA_LOG_PRINT_TIME|PA_LOG_PRINT_FILE|PA_LOG_PRINT_META|PA_LOG_PRINT_LEVEL)));
21553a5a1b3Sopenharmony_ci
21653a5a1b3Sopenharmony_ci    if (merge == PA_LOG_SET)
21753a5a1b3Sopenharmony_ci        flags |= _flags;
21853a5a1b3Sopenharmony_ci    else if (merge == PA_LOG_UNSET)
21953a5a1b3Sopenharmony_ci        flags &= ~_flags;
22053a5a1b3Sopenharmony_ci    else
22153a5a1b3Sopenharmony_ci        flags = _flags;
22253a5a1b3Sopenharmony_ci}
22353a5a1b3Sopenharmony_ci
22453a5a1b3Sopenharmony_civoid pa_log_set_show_backtrace(unsigned nlevels) {
22553a5a1b3Sopenharmony_ci    show_backtrace = nlevels;
22653a5a1b3Sopenharmony_ci}
22753a5a1b3Sopenharmony_ci
22853a5a1b3Sopenharmony_civoid pa_log_set_skip_backtrace(unsigned nlevels) {
22953a5a1b3Sopenharmony_ci    skip_backtrace = nlevels;
23053a5a1b3Sopenharmony_ci}
23153a5a1b3Sopenharmony_ci
23253a5a1b3Sopenharmony_ci#ifdef HAVE_EXECINFO_H
23353a5a1b3Sopenharmony_ci
23453a5a1b3Sopenharmony_cistatic char* get_backtrace(unsigned show_nframes) {
23553a5a1b3Sopenharmony_ci    void* trace[32];
23653a5a1b3Sopenharmony_ci    int n_frames;
23753a5a1b3Sopenharmony_ci    char **symbols, *e, *r;
23853a5a1b3Sopenharmony_ci    unsigned j, n, s;
23953a5a1b3Sopenharmony_ci    size_t a;
24053a5a1b3Sopenharmony_ci
24153a5a1b3Sopenharmony_ci    pa_assert(show_nframes > 0);
24253a5a1b3Sopenharmony_ci
24353a5a1b3Sopenharmony_ci    n_frames = backtrace(trace, PA_ELEMENTSOF(trace));
24453a5a1b3Sopenharmony_ci
24553a5a1b3Sopenharmony_ci    if (n_frames <= 0)
24653a5a1b3Sopenharmony_ci        return NULL;
24753a5a1b3Sopenharmony_ci
24853a5a1b3Sopenharmony_ci    symbols = backtrace_symbols(trace, n_frames);
24953a5a1b3Sopenharmony_ci
25053a5a1b3Sopenharmony_ci    if (!symbols)
25153a5a1b3Sopenharmony_ci        return NULL;
25253a5a1b3Sopenharmony_ci
25353a5a1b3Sopenharmony_ci    s = skip_backtrace;
25453a5a1b3Sopenharmony_ci    n = PA_MIN((unsigned) n_frames, s + show_nframes);
25553a5a1b3Sopenharmony_ci
25653a5a1b3Sopenharmony_ci    a = 4;
25753a5a1b3Sopenharmony_ci
25853a5a1b3Sopenharmony_ci    for (j = s; j < n; j++) {
25953a5a1b3Sopenharmony_ci        if (j > s)
26053a5a1b3Sopenharmony_ci            a += 2;
26153a5a1b3Sopenharmony_ci        a += strlen(pa_path_get_filename(symbols[j]));
26253a5a1b3Sopenharmony_ci    }
26353a5a1b3Sopenharmony_ci
26453a5a1b3Sopenharmony_ci    r = pa_xnew(char, a);
26553a5a1b3Sopenharmony_ci
26653a5a1b3Sopenharmony_ci    strcpy(r, " (");
26753a5a1b3Sopenharmony_ci    e = r + 2;
26853a5a1b3Sopenharmony_ci
26953a5a1b3Sopenharmony_ci    for (j = s; j < n; j++) {
27053a5a1b3Sopenharmony_ci        const char *sym;
27153a5a1b3Sopenharmony_ci
27253a5a1b3Sopenharmony_ci        if (j > s) {
27353a5a1b3Sopenharmony_ci            strcpy(e, "<<");
27453a5a1b3Sopenharmony_ci            e += 2;
27553a5a1b3Sopenharmony_ci        }
27653a5a1b3Sopenharmony_ci
27753a5a1b3Sopenharmony_ci        sym = pa_path_get_filename(symbols[j]);
27853a5a1b3Sopenharmony_ci
27953a5a1b3Sopenharmony_ci        strcpy(e, sym);
28053a5a1b3Sopenharmony_ci        e += strlen(sym);
28153a5a1b3Sopenharmony_ci    }
28253a5a1b3Sopenharmony_ci
28353a5a1b3Sopenharmony_ci    strcpy(e, ")");
28453a5a1b3Sopenharmony_ci
28553a5a1b3Sopenharmony_ci    free(symbols);
28653a5a1b3Sopenharmony_ci
28753a5a1b3Sopenharmony_ci    return r;
28853a5a1b3Sopenharmony_ci}
28953a5a1b3Sopenharmony_ci
29053a5a1b3Sopenharmony_ci#endif
29153a5a1b3Sopenharmony_ci
29253a5a1b3Sopenharmony_cistatic void init_defaults(void) {
29353a5a1b3Sopenharmony_ci    PA_ONCE_BEGIN {
29453a5a1b3Sopenharmony_ci
29553a5a1b3Sopenharmony_ci        const char *e;
29653a5a1b3Sopenharmony_ci
29753a5a1b3Sopenharmony_ci        if (!ident) {
29853a5a1b3Sopenharmony_ci            char binary[256];
29953a5a1b3Sopenharmony_ci            if (pa_get_binary_name(binary, sizeof(binary)))
30053a5a1b3Sopenharmony_ci                pa_log_set_ident(binary);
30153a5a1b3Sopenharmony_ci        }
30253a5a1b3Sopenharmony_ci
30353a5a1b3Sopenharmony_ci        if (getenv(ENV_LOG_SYSLOG)) {
30453a5a1b3Sopenharmony_ci            target_override = PA_LOG_SYSLOG;
30553a5a1b3Sopenharmony_ci            target_override_set = true;
30653a5a1b3Sopenharmony_ci        }
30753a5a1b3Sopenharmony_ci
30853a5a1b3Sopenharmony_ci#ifdef HAVE_SYSTEMD_JOURNAL
30953a5a1b3Sopenharmony_ci        if (getenv(ENV_LOG_JOURNAL)) {
31053a5a1b3Sopenharmony_ci            target_override = PA_LOG_JOURNAL;
31153a5a1b3Sopenharmony_ci            target_override_set = true;
31253a5a1b3Sopenharmony_ci        }
31353a5a1b3Sopenharmony_ci#endif
31453a5a1b3Sopenharmony_ci
31553a5a1b3Sopenharmony_ci        if ((e = getenv(ENV_LOG_LEVEL))) {
31653a5a1b3Sopenharmony_ci            maximum_level_override = (pa_log_level_t) atoi(e);
31753a5a1b3Sopenharmony_ci
31853a5a1b3Sopenharmony_ci            if (maximum_level_override >= PA_LOG_LEVEL_MAX)
31953a5a1b3Sopenharmony_ci                maximum_level_override = PA_LOG_LEVEL_MAX-1;
32053a5a1b3Sopenharmony_ci        }
32153a5a1b3Sopenharmony_ci
32253a5a1b3Sopenharmony_ci        if (getenv(ENV_LOG_COLORS))
32353a5a1b3Sopenharmony_ci            flags_override |= PA_LOG_COLORS;
32453a5a1b3Sopenharmony_ci
32553a5a1b3Sopenharmony_ci        if (getenv(ENV_LOG_PRINT_TIME))
32653a5a1b3Sopenharmony_ci            flags_override |= PA_LOG_PRINT_TIME;
32753a5a1b3Sopenharmony_ci
32853a5a1b3Sopenharmony_ci        if (getenv(ENV_LOG_PRINT_FILE))
32953a5a1b3Sopenharmony_ci            flags_override |= PA_LOG_PRINT_FILE;
33053a5a1b3Sopenharmony_ci
33153a5a1b3Sopenharmony_ci        if (getenv(ENV_LOG_PRINT_META))
33253a5a1b3Sopenharmony_ci            flags_override |= PA_LOG_PRINT_META;
33353a5a1b3Sopenharmony_ci
33453a5a1b3Sopenharmony_ci        if (getenv(ENV_LOG_PRINT_LEVEL))
33553a5a1b3Sopenharmony_ci            flags_override |= PA_LOG_PRINT_LEVEL;
33653a5a1b3Sopenharmony_ci
33753a5a1b3Sopenharmony_ci        if ((e = getenv(ENV_LOG_BACKTRACE))) {
33853a5a1b3Sopenharmony_ci            show_backtrace_override = (unsigned) atoi(e);
33953a5a1b3Sopenharmony_ci
34053a5a1b3Sopenharmony_ci            if (show_backtrace_override <= 0)
34153a5a1b3Sopenharmony_ci                show_backtrace_override = 0;
34253a5a1b3Sopenharmony_ci        }
34353a5a1b3Sopenharmony_ci
34453a5a1b3Sopenharmony_ci        if ((e = getenv(ENV_LOG_BACKTRACE_SKIP))) {
34553a5a1b3Sopenharmony_ci            skip_backtrace = (unsigned) atoi(e);
34653a5a1b3Sopenharmony_ci
34753a5a1b3Sopenharmony_ci            if (skip_backtrace <= 0)
34853a5a1b3Sopenharmony_ci                skip_backtrace = 0;
34953a5a1b3Sopenharmony_ci        }
35053a5a1b3Sopenharmony_ci
35153a5a1b3Sopenharmony_ci        if (getenv(ENV_LOG_NO_RATELIMIT))
35253a5a1b3Sopenharmony_ci            no_rate_limit = true;
35353a5a1b3Sopenharmony_ci
35453a5a1b3Sopenharmony_ci    } PA_ONCE_END;
35553a5a1b3Sopenharmony_ci}
35653a5a1b3Sopenharmony_ci
35753a5a1b3Sopenharmony_ci#ifdef HAVE_SYSLOG_H
35853a5a1b3Sopenharmony_cistatic void log_syslog(pa_log_level_t level, char *t, char *timestamp, char *location, char *bt) {
35953a5a1b3Sopenharmony_ci    char *local_t;
36053a5a1b3Sopenharmony_ci
36153a5a1b3Sopenharmony_ci    openlog(ident, LOG_PID, LOG_USER);
36253a5a1b3Sopenharmony_ci
36353a5a1b3Sopenharmony_ci    if ((local_t = pa_utf8_to_locale(t)))
36453a5a1b3Sopenharmony_ci        t = local_t;
36553a5a1b3Sopenharmony_ci
36653a5a1b3Sopenharmony_ci    syslog(level_to_syslog[level], "%s%s%s%s", timestamp, location, t, pa_strempty(bt));
36753a5a1b3Sopenharmony_ci    pa_xfree(local_t);
36853a5a1b3Sopenharmony_ci}
36953a5a1b3Sopenharmony_ci#endif
37053a5a1b3Sopenharmony_ci
37153a5a1b3Sopenharmony_civoid pa_log_levelv_meta(
37253a5a1b3Sopenharmony_ci        pa_log_level_t level,
37353a5a1b3Sopenharmony_ci        const char*file,
37453a5a1b3Sopenharmony_ci        int line,
37553a5a1b3Sopenharmony_ci        const char *func,
37653a5a1b3Sopenharmony_ci        const char *format,
37753a5a1b3Sopenharmony_ci        va_list ap) {
37853a5a1b3Sopenharmony_ci
37953a5a1b3Sopenharmony_ci    char *t, *n;
38053a5a1b3Sopenharmony_ci    int saved_errno = errno;
38153a5a1b3Sopenharmony_ci    char *bt = NULL;
38253a5a1b3Sopenharmony_ci    pa_log_target_type_t _target;
38353a5a1b3Sopenharmony_ci    pa_log_level_t _maximum_level;
38453a5a1b3Sopenharmony_ci    unsigned _show_backtrace;
38553a5a1b3Sopenharmony_ci    pa_log_flags_t _flags;
38653a5a1b3Sopenharmony_ci
38753a5a1b3Sopenharmony_ci    /* We don't use dynamic memory allocation here to minimize the hit
38853a5a1b3Sopenharmony_ci     * in RT threads */
38953a5a1b3Sopenharmony_ci    char text[256], location[128], timestamp[32];
39053a5a1b3Sopenharmony_ci
39153a5a1b3Sopenharmony_ci    pa_assert(level < PA_LOG_LEVEL_MAX);
39253a5a1b3Sopenharmony_ci    pa_assert(format);
39353a5a1b3Sopenharmony_ci
39453a5a1b3Sopenharmony_ci    init_defaults();
39553a5a1b3Sopenharmony_ci
39653a5a1b3Sopenharmony_ci    _target = target_override_set ? target_override : target.type;
39753a5a1b3Sopenharmony_ci    _maximum_level = PA_MAX(maximum_level, maximum_level_override);
39853a5a1b3Sopenharmony_ci    _show_backtrace = PA_MAX(show_backtrace, show_backtrace_override);
39953a5a1b3Sopenharmony_ci    _flags = flags | flags_override;
40053a5a1b3Sopenharmony_ci
40153a5a1b3Sopenharmony_ci    if (PA_LIKELY(level > _maximum_level)) {
40253a5a1b3Sopenharmony_ci        errno = saved_errno;
40353a5a1b3Sopenharmony_ci        return;
40453a5a1b3Sopenharmony_ci    }
40553a5a1b3Sopenharmony_ci
40653a5a1b3Sopenharmony_ci    pa_vsnprintf(text, sizeof(text), format, ap);
40753a5a1b3Sopenharmony_ci
40853a5a1b3Sopenharmony_ci    const char *filename = strrchr(file, '/');
40953a5a1b3Sopenharmony_ci    if (filename) {
41053a5a1b3Sopenharmony_ci        filename++;
41153a5a1b3Sopenharmony_ci    } else {
41253a5a1b3Sopenharmony_ci        filename = file;
41353a5a1b3Sopenharmony_ci    }
41453a5a1b3Sopenharmony_ci
41553a5a1b3Sopenharmony_ci    if (level == PA_LOG_ERROR) {
41653a5a1b3Sopenharmony_ci        AUDIO_ERR_LOG("%{public}s:%{public}u (%{public}s) %{public}s", filename, line, func, text);
41753a5a1b3Sopenharmony_ci    } else if (level == PA_LOG_WARN) {
41853a5a1b3Sopenharmony_ci        AUDIO_WARNING_LOG("%{public}s:%{public}u (%{public}s) %{public}s", filename, line, func, text);
41953a5a1b3Sopenharmony_ci    } else if (level == PA_LOG_NOTICE || level == PA_LOG_INFO) {
42053a5a1b3Sopenharmony_ci        AUDIO_INFO_LOG("%{public}s:%{public}u (%{public}s) %{public}s", filename, line, func, text);
42153a5a1b3Sopenharmony_ci    } else if (level == PA_LOG_DEBUG) {
42253a5a1b3Sopenharmony_ci        AUDIO_DEBUG_LOG("%{public}s:%{public}u (%{public}s) %{public}s", filename, line, func, text);
42353a5a1b3Sopenharmony_ci    }
42453a5a1b3Sopenharmony_ci
42553a5a1b3Sopenharmony_ci    if ((_flags & PA_LOG_PRINT_META) && file && line > 0 && func)
42653a5a1b3Sopenharmony_ci        pa_snprintf(location, sizeof(location), "[%s][%s:%i %s()] ",
42753a5a1b3Sopenharmony_ci                    pa_strnull(pa_thread_get_name(pa_thread_self())), file, line, func);
42853a5a1b3Sopenharmony_ci    else if ((_flags & (PA_LOG_PRINT_META|PA_LOG_PRINT_FILE)) && file)
42953a5a1b3Sopenharmony_ci        pa_snprintf(location, sizeof(location), "[%s] %s: ",
43053a5a1b3Sopenharmony_ci                    pa_strnull(pa_thread_get_name(pa_thread_self())), pa_path_get_filename(file));
43153a5a1b3Sopenharmony_ci    else
43253a5a1b3Sopenharmony_ci        location[0] = 0;
43353a5a1b3Sopenharmony_ci
43453a5a1b3Sopenharmony_ci    if (_flags & PA_LOG_PRINT_TIME) {
43553a5a1b3Sopenharmony_ci        static pa_usec_t start, last;
43653a5a1b3Sopenharmony_ci        pa_usec_t u, a, r;
43753a5a1b3Sopenharmony_ci
43853a5a1b3Sopenharmony_ci        u = pa_rtclock_now();
43953a5a1b3Sopenharmony_ci
44053a5a1b3Sopenharmony_ci        PA_ONCE_BEGIN {
44153a5a1b3Sopenharmony_ci            start = u;
44253a5a1b3Sopenharmony_ci            last = u;
44353a5a1b3Sopenharmony_ci        } PA_ONCE_END;
44453a5a1b3Sopenharmony_ci
44553a5a1b3Sopenharmony_ci        r = u - last;
44653a5a1b3Sopenharmony_ci        a = u - start;
44753a5a1b3Sopenharmony_ci
44853a5a1b3Sopenharmony_ci        /* This is not thread safe, but this is a debugging tool only
44953a5a1b3Sopenharmony_ci         * anyway. */
45053a5a1b3Sopenharmony_ci        last = u;
45153a5a1b3Sopenharmony_ci
45253a5a1b3Sopenharmony_ci        pa_snprintf(timestamp, sizeof(timestamp), "(%4llu.%03llu|%4llu.%03llu) ",
45353a5a1b3Sopenharmony_ci                    (unsigned long long) (a / PA_USEC_PER_SEC),
45453a5a1b3Sopenharmony_ci                    (unsigned long long) (((a / PA_USEC_PER_MSEC)) % 1000),
45553a5a1b3Sopenharmony_ci                    (unsigned long long) (r / PA_USEC_PER_SEC),
45653a5a1b3Sopenharmony_ci                    (unsigned long long) (((r / PA_USEC_PER_MSEC)) % 1000));
45753a5a1b3Sopenharmony_ci
45853a5a1b3Sopenharmony_ci    } else
45953a5a1b3Sopenharmony_ci        timestamp[0] = 0;
46053a5a1b3Sopenharmony_ci
46153a5a1b3Sopenharmony_ci#ifdef HAVE_EXECINFO_H
46253a5a1b3Sopenharmony_ci    if (_show_backtrace > 0)
46353a5a1b3Sopenharmony_ci        bt = get_backtrace(_show_backtrace);
46453a5a1b3Sopenharmony_ci#endif
46553a5a1b3Sopenharmony_ci
46653a5a1b3Sopenharmony_ci    if (!pa_utf8_valid(text))
46753a5a1b3Sopenharmony_ci        pa_logl(level, "Invalid UTF-8 string following below:");
46853a5a1b3Sopenharmony_ci
46953a5a1b3Sopenharmony_ci    for (t = text; t; t = n) {
47053a5a1b3Sopenharmony_ci        if ((n = strchr(t, '\n'))) {
47153a5a1b3Sopenharmony_ci            *n = 0;
47253a5a1b3Sopenharmony_ci            n++;
47353a5a1b3Sopenharmony_ci        }
47453a5a1b3Sopenharmony_ci
47553a5a1b3Sopenharmony_ci        /* We ignore strings only made out of whitespace */
47653a5a1b3Sopenharmony_ci        if (t[strspn(t, "\t ")] == 0)
47753a5a1b3Sopenharmony_ci            continue;
47853a5a1b3Sopenharmony_ci
47953a5a1b3Sopenharmony_ci        switch (_target) {
48053a5a1b3Sopenharmony_ci
48153a5a1b3Sopenharmony_ci            case PA_LOG_STDERR: {
48253a5a1b3Sopenharmony_ci                const char *prefix = "", *suffix = "", *grey = "";
48353a5a1b3Sopenharmony_ci                char *local_t;
48453a5a1b3Sopenharmony_ci
48553a5a1b3Sopenharmony_ci#ifndef OS_IS_WIN32
48653a5a1b3Sopenharmony_ci                /* Yes indeed. Useless, but fun! */
48753a5a1b3Sopenharmony_ci                if ((_flags & PA_LOG_COLORS) && isatty(STDERR_FILENO)) {
48853a5a1b3Sopenharmony_ci                    if (level <= PA_LOG_ERROR)
48953a5a1b3Sopenharmony_ci                        prefix = "\x1B[1;31m";
49053a5a1b3Sopenharmony_ci                    else if (level <= PA_LOG_WARN)
49153a5a1b3Sopenharmony_ci                        prefix = "\x1B[1m";
49253a5a1b3Sopenharmony_ci
49353a5a1b3Sopenharmony_ci                    if (bt)
49453a5a1b3Sopenharmony_ci                        grey = "\x1B[2m";
49553a5a1b3Sopenharmony_ci
49653a5a1b3Sopenharmony_ci                    if (grey[0] || prefix[0])
49753a5a1b3Sopenharmony_ci                        suffix = "\x1B[0m";
49853a5a1b3Sopenharmony_ci                }
49953a5a1b3Sopenharmony_ci#endif
50053a5a1b3Sopenharmony_ci
50153a5a1b3Sopenharmony_ci                /* We shouldn't be using dynamic allocation here to
50253a5a1b3Sopenharmony_ci                 * minimize the hit in RT threads */
50353a5a1b3Sopenharmony_ci                if ((local_t = pa_utf8_to_locale(t)))
50453a5a1b3Sopenharmony_ci                    t = local_t;
50553a5a1b3Sopenharmony_ci
50653a5a1b3Sopenharmony_ci                if (_flags & PA_LOG_PRINT_LEVEL)
50753a5a1b3Sopenharmony_ci                    fprintf(stderr, "%s%c: %s%s%s%s%s%s\n", timestamp, level_to_char[level], location, prefix, t, grey, pa_strempty(bt), suffix);
50853a5a1b3Sopenharmony_ci                else
50953a5a1b3Sopenharmony_ci                    fprintf(stderr, "%s%s%s%s%s%s%s\n", timestamp, location, prefix, t, grey, pa_strempty(bt), suffix);
51053a5a1b3Sopenharmony_ci#ifdef OS_IS_WIN32
51153a5a1b3Sopenharmony_ci                fflush(stderr);
51253a5a1b3Sopenharmony_ci#endif
51353a5a1b3Sopenharmony_ci
51453a5a1b3Sopenharmony_ci                pa_xfree(local_t);
51553a5a1b3Sopenharmony_ci
51653a5a1b3Sopenharmony_ci                break;
51753a5a1b3Sopenharmony_ci            }
51853a5a1b3Sopenharmony_ci
51953a5a1b3Sopenharmony_ci#ifdef HAVE_SYSLOG_H
52053a5a1b3Sopenharmony_ci            case PA_LOG_SYSLOG:
52153a5a1b3Sopenharmony_ci                log_syslog(level, t, timestamp, location, bt);
52253a5a1b3Sopenharmony_ci                break;
52353a5a1b3Sopenharmony_ci#endif
52453a5a1b3Sopenharmony_ci
52553a5a1b3Sopenharmony_ci#ifdef HAVE_SYSTEMD_JOURNAL
52653a5a1b3Sopenharmony_ci            case PA_LOG_JOURNAL:
52753a5a1b3Sopenharmony_ci                if (sd_journal_send("MESSAGE=%s", t,
52853a5a1b3Sopenharmony_ci                                "PRIORITY=%i", level_to_journal[level],
52953a5a1b3Sopenharmony_ci                                "CODE_FILE=%s", file,
53053a5a1b3Sopenharmony_ci                                "CODE_FUNC=%s", func,
53153a5a1b3Sopenharmony_ci                                "CODE_LINE=%d", line,
53253a5a1b3Sopenharmony_ci                                "PULSE_BACKTRACE=%s", pa_strempty(bt),
53353a5a1b3Sopenharmony_ci                                NULL) < 0) {
53453a5a1b3Sopenharmony_ci#ifdef HAVE_SYSLOG_H
53553a5a1b3Sopenharmony_ci                    pa_log_target new_target = { .type = PA_LOG_SYSLOG, .file = NULL };
53653a5a1b3Sopenharmony_ci
53753a5a1b3Sopenharmony_ci                    syslog(level_to_syslog[PA_LOG_ERROR], "%s%s%s", timestamp, __FILE__,
53853a5a1b3Sopenharmony_ci                           "Error writing logs to the journal. Redirect log messages to syslog.");
53953a5a1b3Sopenharmony_ci                    log_syslog(level, t, timestamp, location, bt);
54053a5a1b3Sopenharmony_ci#else
54153a5a1b3Sopenharmony_ci                    pa_log_target new_target = { .type = PA_LOG_STDERR, .file = NULL };
54253a5a1b3Sopenharmony_ci
54353a5a1b3Sopenharmony_ci                    saved_errno = errno;
54453a5a1b3Sopenharmony_ci                    fprintf(stderr, "%s\n", "Error writing logs to the journal. Redirect log messages to console.");
54553a5a1b3Sopenharmony_ci                    fprintf(stderr, "%s\n", t);
54653a5a1b3Sopenharmony_ci#endif
54753a5a1b3Sopenharmony_ci                    pa_log_set_target(&new_target);
54853a5a1b3Sopenharmony_ci                }
54953a5a1b3Sopenharmony_ci                break;
55053a5a1b3Sopenharmony_ci#endif
55153a5a1b3Sopenharmony_ci
55253a5a1b3Sopenharmony_ci            case PA_LOG_FILE:
55353a5a1b3Sopenharmony_ci            case PA_LOG_NEWFILE: {
55453a5a1b3Sopenharmony_ci                char *local_t;
55553a5a1b3Sopenharmony_ci
55653a5a1b3Sopenharmony_ci                if ((local_t = pa_utf8_to_locale(t)))
55753a5a1b3Sopenharmony_ci                    t = local_t;
55853a5a1b3Sopenharmony_ci
55953a5a1b3Sopenharmony_ci                if (log_fd >= 0) {
56053a5a1b3Sopenharmony_ci                    char metadata[256];
56153a5a1b3Sopenharmony_ci
56253a5a1b3Sopenharmony_ci                    if (_flags & PA_LOG_PRINT_LEVEL)
56353a5a1b3Sopenharmony_ci                        pa_snprintf(metadata, sizeof(metadata), "%s%c: %s", timestamp, level_to_char[level], location);
56453a5a1b3Sopenharmony_ci                    else
56553a5a1b3Sopenharmony_ci                        pa_snprintf(metadata, sizeof(metadata), "%s%s", timestamp, location);
56653a5a1b3Sopenharmony_ci
56753a5a1b3Sopenharmony_ci                    if ((pa_write(log_fd, metadata, strlen(metadata), &write_type) < 0)
56853a5a1b3Sopenharmony_ci                            || (pa_write(log_fd, t, strlen(t), &write_type) < 0)
56953a5a1b3Sopenharmony_ci                            || (bt && pa_write(log_fd, bt, strlen(bt), &write_type) < 0)
57053a5a1b3Sopenharmony_ci                            || (pa_write(log_fd, "\n", 1, &write_type) < 0)) {
57153a5a1b3Sopenharmony_ci                        pa_log_target new_target = { .type = PA_LOG_STDERR, .file = NULL };
57253a5a1b3Sopenharmony_ci                        saved_errno = errno;
57353a5a1b3Sopenharmony_ci                        fprintf(stderr, "%s\n", "Error writing logs to a file descriptor. Redirect log messages to console.");
57453a5a1b3Sopenharmony_ci                        fprintf(stderr, "%s %s\n", metadata, t);
57553a5a1b3Sopenharmony_ci                        pa_log_set_target(&new_target);
57653a5a1b3Sopenharmony_ci                    }
57753a5a1b3Sopenharmony_ci                }
57853a5a1b3Sopenharmony_ci
57953a5a1b3Sopenharmony_ci                pa_xfree(local_t);
58053a5a1b3Sopenharmony_ci
58153a5a1b3Sopenharmony_ci                break;
58253a5a1b3Sopenharmony_ci            }
58353a5a1b3Sopenharmony_ci            case PA_LOG_NULL:
58453a5a1b3Sopenharmony_ci            default:
58553a5a1b3Sopenharmony_ci                break;
58653a5a1b3Sopenharmony_ci        }
58753a5a1b3Sopenharmony_ci    }
58853a5a1b3Sopenharmony_ci
58953a5a1b3Sopenharmony_ci    pa_xfree(bt);
59053a5a1b3Sopenharmony_ci    errno = saved_errno;
59153a5a1b3Sopenharmony_ci}
59253a5a1b3Sopenharmony_ci
59353a5a1b3Sopenharmony_civoid PrintCallStackInfo()
59453a5a1b3Sopenharmony_ci{
59553a5a1b3Sopenharmony_ci    const int32_t maxDepth = 20;
59653a5a1b3Sopenharmony_ci    void *stacks[maxDepth];
59753a5a1b3Sopenharmony_ci
59853a5a1b3Sopenharmony_ci    int stackNum = backtrace(stacks, maxDepth);
59953a5a1b3Sopenharmony_ci    AUDIO_ERR_LOG("backtrace() returned %{public}d addresses\n", stackNum);
60053a5a1b3Sopenharmony_ci
60153a5a1b3Sopenharmony_ci    char **symbols = backtrace_symbols(stacks, stackNum);
60253a5a1b3Sopenharmony_ci    if (symbols == NULL) {
60353a5a1b3Sopenharmony_ci        AUDIO_ERR_LOG("backtrace_symbols faile.");
60453a5a1b3Sopenharmony_ci        for (int i = 0; i < stackNum; i++) {
60553a5a1b3Sopenharmony_ci            AUDIO_ERR_LOG("  [%{public}02d] addr: %{public}p\n", i, stacks[i]);
60653a5a1b3Sopenharmony_ci        }
60753a5a1b3Sopenharmony_ci        return;
60853a5a1b3Sopenharmony_ci    }
60953a5a1b3Sopenharmony_ci
61053a5a1b3Sopenharmony_ci    for (int i = 0; i < stackNum; i++) {
61153a5a1b3Sopenharmony_ci        AUDIO_ERR_LOG("  [%{public}02d] %{public}s\n", i, symbols[i]);
61253a5a1b3Sopenharmony_ci    }
61353a5a1b3Sopenharmony_ci
61453a5a1b3Sopenharmony_ci    free(symbols);
61553a5a1b3Sopenharmony_ci}
61653a5a1b3Sopenharmony_ci
61753a5a1b3Sopenharmony_civoid pa_log_level_meta(
61853a5a1b3Sopenharmony_ci        pa_log_level_t level,
61953a5a1b3Sopenharmony_ci        const char*file,
62053a5a1b3Sopenharmony_ci        int line,
62153a5a1b3Sopenharmony_ci        const char *func,
62253a5a1b3Sopenharmony_ci        const char *format, ...) {
62353a5a1b3Sopenharmony_ci
62453a5a1b3Sopenharmony_ci    va_list ap;
62553a5a1b3Sopenharmony_ci    va_start(ap, format);
62653a5a1b3Sopenharmony_ci    pa_log_levelv_meta(level, file, line, func, format, ap);
62753a5a1b3Sopenharmony_ci    va_end(ap);
62853a5a1b3Sopenharmony_ci}
62953a5a1b3Sopenharmony_ci
63053a5a1b3Sopenharmony_civoid pa_log_levelv(pa_log_level_t level, const char *format, va_list ap) {
63153a5a1b3Sopenharmony_ci    pa_log_levelv_meta(level, NULL, 0, NULL, format, ap);
63253a5a1b3Sopenharmony_ci}
63353a5a1b3Sopenharmony_ci
63453a5a1b3Sopenharmony_civoid pa_log_level(pa_log_level_t level, const char *format, ...) {
63553a5a1b3Sopenharmony_ci    va_list ap;
63653a5a1b3Sopenharmony_ci
63753a5a1b3Sopenharmony_ci    va_start(ap, format);
63853a5a1b3Sopenharmony_ci    pa_log_levelv_meta(level, NULL, 0, NULL, format, ap);
63953a5a1b3Sopenharmony_ci    va_end(ap);
64053a5a1b3Sopenharmony_ci}
64153a5a1b3Sopenharmony_ci
64253a5a1b3Sopenharmony_cibool pa_log_ratelimit(pa_log_level_t level) {
64353a5a1b3Sopenharmony_ci    /* Not more than 10 messages every 5s */
64453a5a1b3Sopenharmony_ci    static PA_DEFINE_RATELIMIT(ratelimit, 5 * PA_USEC_PER_SEC, 10);
64553a5a1b3Sopenharmony_ci
64653a5a1b3Sopenharmony_ci    init_defaults();
64753a5a1b3Sopenharmony_ci
64853a5a1b3Sopenharmony_ci    if (no_rate_limit)
64953a5a1b3Sopenharmony_ci        return true;
65053a5a1b3Sopenharmony_ci
65153a5a1b3Sopenharmony_ci    return pa_ratelimit_test(&ratelimit, level);
65253a5a1b3Sopenharmony_ci}
65353a5a1b3Sopenharmony_ci
65453a5a1b3Sopenharmony_cipa_log_target *pa_log_target_new(pa_log_target_type_t type, const char *file) {
65553a5a1b3Sopenharmony_ci    pa_log_target *t = NULL;
65653a5a1b3Sopenharmony_ci
65753a5a1b3Sopenharmony_ci    t = pa_xnew(pa_log_target, 1);
65853a5a1b3Sopenharmony_ci
65953a5a1b3Sopenharmony_ci    t->type = type;
66053a5a1b3Sopenharmony_ci    t->file = pa_xstrdup(file);
66153a5a1b3Sopenharmony_ci
66253a5a1b3Sopenharmony_ci    return t;
66353a5a1b3Sopenharmony_ci}
66453a5a1b3Sopenharmony_ci
66553a5a1b3Sopenharmony_civoid pa_log_target_free(pa_log_target *t) {
66653a5a1b3Sopenharmony_ci    pa_assert(t);
66753a5a1b3Sopenharmony_ci
66853a5a1b3Sopenharmony_ci    pa_xfree(t->file);
66953a5a1b3Sopenharmony_ci    pa_xfree(t);
67053a5a1b3Sopenharmony_ci}
67153a5a1b3Sopenharmony_ci
67253a5a1b3Sopenharmony_cipa_log_target *pa_log_parse_target(const char *string) {
67353a5a1b3Sopenharmony_ci    pa_log_target *t = NULL;
67453a5a1b3Sopenharmony_ci
67553a5a1b3Sopenharmony_ci    pa_assert(string);
67653a5a1b3Sopenharmony_ci
67753a5a1b3Sopenharmony_ci    if (pa_streq(string, "stderr"))
67853a5a1b3Sopenharmony_ci        t = pa_log_target_new(PA_LOG_STDERR, NULL);
67953a5a1b3Sopenharmony_ci    else if (pa_streq(string, "syslog"))
68053a5a1b3Sopenharmony_ci        t = pa_log_target_new(PA_LOG_SYSLOG, NULL);
68153a5a1b3Sopenharmony_ci#ifdef HAVE_SYSTEMD_JOURNAL
68253a5a1b3Sopenharmony_ci    else if (pa_streq(string, "journal"))
68353a5a1b3Sopenharmony_ci        t = pa_log_target_new(PA_LOG_JOURNAL, NULL);
68453a5a1b3Sopenharmony_ci#endif
68553a5a1b3Sopenharmony_ci    else if (pa_streq(string, "null"))
68653a5a1b3Sopenharmony_ci        t = pa_log_target_new(PA_LOG_NULL, NULL);
68753a5a1b3Sopenharmony_ci    else if (pa_startswith(string, "file:"))
68853a5a1b3Sopenharmony_ci        t = pa_log_target_new(PA_LOG_FILE, string + 5);
68953a5a1b3Sopenharmony_ci    else if (pa_startswith(string, "newfile:"))
69053a5a1b3Sopenharmony_ci        t = pa_log_target_new(PA_LOG_NEWFILE, string + 8);
69153a5a1b3Sopenharmony_ci    else
69253a5a1b3Sopenharmony_ci        pa_log(_("Invalid log target."));
69353a5a1b3Sopenharmony_ci
69453a5a1b3Sopenharmony_ci    return t;
69553a5a1b3Sopenharmony_ci}
69653a5a1b3Sopenharmony_ci
69753a5a1b3Sopenharmony_cichar *pa_log_target_to_string(const pa_log_target *t) {
69853a5a1b3Sopenharmony_ci    char *string = NULL;
69953a5a1b3Sopenharmony_ci
70053a5a1b3Sopenharmony_ci    pa_assert(t);
70153a5a1b3Sopenharmony_ci
70253a5a1b3Sopenharmony_ci    switch (t->type) {
70353a5a1b3Sopenharmony_ci        case PA_LOG_STDERR:
70453a5a1b3Sopenharmony_ci            string = pa_xstrdup("stderr");
70553a5a1b3Sopenharmony_ci            break;
70653a5a1b3Sopenharmony_ci        case PA_LOG_SYSLOG:
70753a5a1b3Sopenharmony_ci            string = pa_xstrdup("syslog");
70853a5a1b3Sopenharmony_ci            break;
70953a5a1b3Sopenharmony_ci#ifdef HAVE_SYSTEMD_JOURNAL
71053a5a1b3Sopenharmony_ci        case PA_LOG_JOURNAL:
71153a5a1b3Sopenharmony_ci            string = pa_xstrdup("journal");
71253a5a1b3Sopenharmony_ci            break;
71353a5a1b3Sopenharmony_ci#endif
71453a5a1b3Sopenharmony_ci        case PA_LOG_NULL:
71553a5a1b3Sopenharmony_ci            string = pa_xstrdup("null");
71653a5a1b3Sopenharmony_ci            break;
71753a5a1b3Sopenharmony_ci        case PA_LOG_FILE:
71853a5a1b3Sopenharmony_ci            string = pa_sprintf_malloc("file:%s", t->file);
71953a5a1b3Sopenharmony_ci            break;
72053a5a1b3Sopenharmony_ci        case PA_LOG_NEWFILE:
72153a5a1b3Sopenharmony_ci            string = pa_sprintf_malloc("newfile:%s", t->file);
72253a5a1b3Sopenharmony_ci            break;
72353a5a1b3Sopenharmony_ci    }
72453a5a1b3Sopenharmony_ci
72553a5a1b3Sopenharmony_ci    return string;
72653a5a1b3Sopenharmony_ci}
727