1 /* mpdscribble (MPD Client)
2  * Copyright (C) 2008-2010 The Music Player Daemon Project
3  * Copyright (C) 2005-2008 Kuno Woudt <kuno@frob.nl>
4  * Project homepage: http://musicpd.org
5 
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10 
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15 
16  * You should have received a copy of the GNU General Public License along
17  * with this program; if not, write to the Free Software Foundation, Inc.,
18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20 
21 #include "log.h"
22 #include "config.h"
23 
24 #include <glib.h>
25 
26 #include <assert.h>
27 #include <stdio.h>
28 #include <string.h>
29 #include <errno.h>
30 
31 #ifdef HAVE_SYSLOG
32 #include <syslog.h>
33 #endif
34 
35 static FILE *log_file;
36 static GLogLevelFlags log_threshold = G_LOG_LEVEL_MESSAGE;
37 
38 /**
39  * Determines the length of the string excluding trailing whitespace
40  * characters.
41  */
42 static int
chomp_length(const char * p)43 chomp_length(const char *p)
44 {
45 	size_t length = strlen(p);
46 
47 	while (length > 0 && g_ascii_isspace(p[length - 1]))
48 		--length;
49 
50 	return (int)length;
51 }
52 
53 const char *
log_date(void)54 log_date(void)
55 {
56 	static char buf[32];
57 	time_t t;
58 	struct tm *tmp;
59 
60 	t = time(NULL);
61 	tmp = localtime(&t);
62 	if (tmp == NULL) {
63 		buf[0] = 0;
64 		return buf;
65 	}
66 
67 	if (!strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S%z", tmp)) {
68 		buf[0] = 0;
69 		return buf;
70 	}
71 	return buf;
72 }
73 
74 static void
file_log_func(const gchar * log_domain,GLogLevelFlags log_level,const gchar * message,G_GNUC_UNUSED gpointer user_data)75 file_log_func(const gchar *log_domain, GLogLevelFlags log_level,
76 	      const gchar *message, G_GNUC_UNUSED gpointer user_data)
77 {
78 	if (log_level > log_threshold)
79 		return;
80 
81 	if (log_domain == NULL)
82 		log_domain = "";
83 
84 	fprintf(log_file, "%s %s%s%.*s\n",
85 		log_date(),
86 		log_domain, *log_domain == 0 ? "" : ": ",
87 		chomp_length(message), message);
88 }
89 
90 static void
log_init_file(const char * path)91 log_init_file(const char *path)
92 {
93 	assert(path != NULL);
94 	assert(log_file == NULL);
95 
96 	if (strcmp(path, "-") == 0) {
97 		log_file = stderr;
98 	} else {
99 		log_file = fopen(path, "ab");
100 		if (log_file == NULL)
101 			g_error("cannot open %s: %s\n",
102 				path, g_strerror(errno));
103 	}
104 
105 	setvbuf(log_file, NULL, _IONBF, 0);
106 
107 	g_log_set_default_handler(file_log_func, NULL);
108 }
109 
110 #ifdef HAVE_SYSLOG
111 
112 static int
glib_to_syslog_level(GLogLevelFlags log_level)113 glib_to_syslog_level(GLogLevelFlags log_level)
114 {
115 	switch (log_level & G_LOG_LEVEL_MASK) {
116 	case G_LOG_LEVEL_ERROR:
117 	case G_LOG_LEVEL_CRITICAL:
118 		return LOG_ERR;
119 
120 	case G_LOG_LEVEL_WARNING:
121 		return LOG_WARNING;
122 
123 	case G_LOG_LEVEL_MESSAGE:
124 		return LOG_NOTICE;
125 
126 	case G_LOG_LEVEL_INFO:
127 		return LOG_INFO;
128 
129 	case G_LOG_LEVEL_DEBUG:
130 		return LOG_DEBUG;
131 
132 	default:
133 		return LOG_NOTICE;
134 	}
135 }
136 
137 static void
syslog_log_func(G_GNUC_UNUSED const gchar * log_domain,GLogLevelFlags log_level,const gchar * message,G_GNUC_UNUSED gpointer user_data)138 syslog_log_func(G_GNUC_UNUSED const gchar *log_domain,
139 		GLogLevelFlags log_level, const gchar *message,
140 		G_GNUC_UNUSED gpointer user_data)
141 {
142 	if (log_level > log_threshold)
143 		return;
144 
145 	syslog(glib_to_syslog_level(log_level), "%.*s",
146 	       chomp_length(message), message);
147 }
148 
149 static void
log_init_syslog(void)150 log_init_syslog(void)
151 {
152 	assert(log_file == NULL);
153 
154 	openlog(PACKAGE, 0, LOG_DAEMON);
155 	g_log_set_default_handler(syslog_log_func, NULL);
156 }
157 
158 #endif
159 
160 void
log_init(const char * path,int verbose)161 log_init(const char *path, int verbose)
162 {
163 	assert(path != NULL);
164 	assert(verbose >= 0);
165 	assert(log_file == NULL);
166 
167 	if (verbose == 0)
168 		log_threshold = G_LOG_LEVEL_ERROR;
169 	else if (verbose == 1)
170 		log_threshold = G_LOG_LEVEL_WARNING;
171 	else if (verbose == 2)
172 		log_threshold = G_LOG_LEVEL_INFO;
173 	else
174 		log_threshold = G_LOG_LEVEL_DEBUG;
175 
176 #ifdef HAVE_SYSLOG
177 	if (strcmp(path, "syslog") == 0)
178 		log_init_syslog();
179 	else
180 #endif
181 		log_init_file(path);
182 }
183 
184 void
log_deinit(void)185 log_deinit(void)
186 {
187 #ifndef HAVE_SYSLOG
188 	assert(log_file != NULL);
189 
190 #else
191 	if (log_file == NULL)
192 		closelog();
193 	else
194 #endif
195 		fclose(log_file);
196 }
197