LogBackend.cxx 3.96 KB
Newer Older
1
/*
Max Kellermann's avatar
Max Kellermann committed
2
 * Copyright (C) 2003-2014 The Music Player Daemon Project
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
 * http://www.musicpd.org
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include "config.h"
21
#include "LogBackend.hxx"
22 23
#include "Log.hxx"
#include "util/Domain.hxx"
24
#include "util/StringUtil.hxx"
25

26
#ifdef HAVE_GLIB
27
#include <glib.h>
28
#endif
29 30

#include <assert.h>
31 32
#include <stdio.h>
#include <string.h>
33
#include <time.h>
34

35 36 37 38
#ifdef HAVE_SYSLOG
#include <syslog.h>
#endif

39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
#ifdef ANDROID
#include <android/log.h>

static int
ToAndroidLogLevel(LogLevel log_level)
{
	switch (log_level) {
	case LogLevel::DEBUG:
		return ANDROID_LOG_DEBUG;

	case LogLevel::INFO:
	case LogLevel::DEFAULT:
		return ANDROID_LOG_INFO;

	case LogLevel::WARNING:
		return ANDROID_LOG_WARN;

	case LogLevel::ERROR:
		return ANDROID_LOG_ERROR;
	}

	assert(false);
	gcc_unreachable();
}

#else

66
static LogLevel log_threshold = LogLevel::INFO;
67 68

#ifdef HAVE_GLIB
69
static const char *log_charset;
70
#endif
71 72 73 74 75 76 77 78 79 80 81 82 83

static bool enable_timestamp;

#ifdef HAVE_SYSLOG
static bool enable_syslog;
#endif

void
SetLogThreshold(LogLevel _threshold)
{
	log_threshold = _threshold;
}

84 85
#ifdef HAVE_GLIB

86 87 88 89 90 91
void
SetLogCharset(const char *_charset)
{
	log_charset = _charset;
}

92 93
#endif

94 95
void
EnableLogTimestamp()
96
{
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
#ifdef HAVE_SYSLOG
	assert(!enable_syslog);
#endif
	assert(!enable_timestamp);

	enable_timestamp = true;
}

static const char *log_date(void)
{
	static constexpr size_t LOG_DATE_BUF_SIZE = 16;
	static char buf[LOG_DATE_BUF_SIZE];
	time_t t = time(nullptr);
	strftime(buf, LOG_DATE_BUF_SIZE, "%b %d %H:%M : ", localtime(&t));
	return buf;
}

/**
 * Determines the length of the string excluding trailing whitespace
 * characters.
 */
static int
chomp_length(const char *p)
{
	size_t length = strlen(p);
122
	return StripRight(p, length);
123 124 125 126 127 128 129 130
}

#ifdef HAVE_SYSLOG

static int
ToSysLogLevel(LogLevel log_level)
{
	switch (log_level) {
131
	case LogLevel::DEBUG:
132
		return LOG_DEBUG;
133 134

	case LogLevel::INFO:
135
		return LOG_INFO;
136 137

	case LogLevel::DEFAULT:
138
		return LOG_NOTICE;
139 140

	case LogLevel::WARNING:
141 142
		return LOG_WARNING;

143
	case LogLevel::ERROR:
144
		return LOG_ERR;
145 146 147 148 149 150
	}

	assert(false);
	gcc_unreachable();
}

151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
static void
SysLog(const Domain &domain, LogLevel log_level, const char *message)
{
	syslog(ToSysLogLevel(log_level), "%s: %.*s",
	       domain.GetName(),
	       chomp_length(message), message);
}

void
LogInitSysLog()
{
	openlog(PACKAGE, 0, LOG_DAEMON);
	enable_syslog = true;
}

void
LogFinishSysLog()
{
	if (enable_syslog)
		closelog();
}

#endif

static void
FileLog(const Domain &domain, const char *message)
{
178
#ifdef HAVE_GLIB
179 180 181 182 183 184 185 186 187 188 189
	char *converted;

	if (log_charset != nullptr) {
		converted = g_convert_with_fallback(message, -1,
						    log_charset, "utf-8",
						    nullptr, nullptr,
						    nullptr, nullptr);
		if (converted != nullptr)
			message = converted;
	} else
		converted = nullptr;
190
#endif
191 192 193 194 195 196

	fprintf(stderr, "%s%s: %.*s\n",
		enable_timestamp ? log_date() : "",
		domain.GetName(),
		chomp_length(message), message);

197
#ifdef HAVE_GLIB
198
	g_free(converted);
199
#endif
200 201
}

202 203
#endif /* !ANDROID */

204 205 206
void
Log(const Domain &domain, LogLevel level, const char *msg)
{
207 208 209 210 211
#ifdef ANDROID
	__android_log_print(ToAndroidLogLevel(level), "MPD",
			    "%s: %s", domain.GetName(), msg);
#else

212 213 214 215 216 217 218 219 220 221 222
	if (level < log_threshold)
		return;

#ifdef HAVE_SYSLOG
	if (enable_syslog) {
		SysLog(domain, level, msg);
		return;
	}
#endif

	FileLog(domain, msg);
223
#endif /* !ANDROID */
224
}