LogBackend.cxx 3.56 KB
Newer Older
1
/*
2
 * Copyright 2003-2016 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

#include <assert.h>
27 28
#include <stdio.h>
#include <string.h>
29
#include <time.h>
30

31 32 33 34
#ifdef HAVE_SYSLOG
#include <syslog.h>
#endif

35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
#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

62
static LogLevel log_threshold = LogLevel::INFO;
63

64 65 66 67 68 69 70 71 72 73 74 75 76 77
static bool enable_timestamp;

#ifdef HAVE_SYSLOG
static bool enable_syslog;
#endif

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

void
EnableLogTimestamp()
78
{
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
#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);
104
	return StripRight(p, length);
105 106 107 108 109 110 111 112
}

#ifdef HAVE_SYSLOG

static int
ToSysLogLevel(LogLevel log_level)
{
	switch (log_level) {
113
	case LogLevel::DEBUG:
114
		return LOG_DEBUG;
115 116

	case LogLevel::INFO:
117
		return LOG_INFO;
118 119

	case LogLevel::DEFAULT:
120
		return LOG_NOTICE;
121 122

	case LogLevel::WARNING:
123 124
		return LOG_WARNING;

125
	case LogLevel::ERROR:
126
		return LOG_ERR;
127 128 129 130 131 132
	}

	assert(false);
	gcc_unreachable();
}

133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164
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)
{
	fprintf(stderr, "%s%s: %.*s\n",
		enable_timestamp ? log_date() : "",
		domain.GetName(),
		chomp_length(message), message);

165 166 167 168 169
#ifdef WIN32
	/* force-flush the log file, because setvbuf() does not seem
	   to have an effect on WIN32 */
	fflush(stderr);
#endif
170 171
}

172 173
#endif /* !ANDROID */

174 175 176
void
Log(const Domain &domain, LogLevel level, const char *msg)
{
177 178 179 180 181
#ifdef ANDROID
	__android_log_print(ToAndroidLogLevel(level), "MPD",
			    "%s: %s", domain.GetName(), msg);
#else

182 183 184 185 186 187 188 189 190 191 192
	if (level < log_threshold)
		return;

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

	FileLog(domain, msg);
193
#endif /* !ANDROID */
194
}