configure.ac: Move OpenAL to Audio Output Plugins (nonstreaming), add header.
[mpd-mk.git] / src / log.c
blob2538526debfdfd9bb83f99f37889a52a5258ade1
1 /*
2 * Copyright (C) 2003-2010 The Music Player Daemon Project
3 * http://www.musicpd.org
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #include "config.h"
21 #include "log.h"
22 #include "conf.h"
23 #include "utils.h"
24 #include "fd_util.h"
26 #include <assert.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <string.h>
30 #include <stdarg.h>
31 #include <fcntl.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <time.h>
35 #include <unistd.h>
36 #include <errno.h>
37 #include <glib.h>
39 #ifdef HAVE_SYSLOG
40 #include <syslog.h>
41 #endif
43 #undef G_LOG_DOMAIN
44 #define G_LOG_DOMAIN "log"
46 #define LOG_LEVEL_SECURE G_LOG_LEVEL_INFO
48 #define LOG_DATE_BUF_SIZE 16
49 #define LOG_DATE_LEN (LOG_DATE_BUF_SIZE - 1)
51 static GLogLevelFlags log_threshold = G_LOG_LEVEL_MESSAGE;
53 static const char *log_charset;
55 static bool stdout_mode = true;
56 static int out_fd;
57 static const char *out_filename;
59 static void redirect_logs(int fd)
61 assert(fd >= 0);
62 if (dup2(fd, STDOUT_FILENO) < 0)
63 g_error("problems dup2 stdout : %s\n", strerror(errno));
64 if (dup2(fd, STDERR_FILENO) < 0)
65 g_error("problems dup2 stderr : %s\n", strerror(errno));
68 static const char *log_date(void)
70 static char buf[LOG_DATE_BUF_SIZE];
71 time_t t = time(NULL);
72 strftime(buf, LOG_DATE_BUF_SIZE, "%b %d %H:%M : ", localtime(&t));
73 return buf;
76 /**
77 * Determines the length of the string excluding trailing whitespace
78 * characters.
80 static int
81 chomp_length(const char *p)
83 size_t length = strlen(p);
85 while (length > 0 && g_ascii_isspace(p[length - 1]))
86 --length;
88 return (int)length;
91 static void
92 file_log_func(const gchar *log_domain,
93 GLogLevelFlags log_level,
94 const gchar *message, G_GNUC_UNUSED gpointer user_data)
96 char *converted;
98 if (log_level > log_threshold)
99 return;
101 if (log_charset != NULL) {
102 converted = g_convert_with_fallback(message, -1,
103 log_charset, "utf-8",
104 NULL, NULL, NULL, NULL);
105 if (converted != NULL)
106 message = converted;
107 } else
108 converted = NULL;
110 if (log_domain == NULL)
111 log_domain = "";
113 fprintf(stderr, "%s%s%s%.*s\n",
114 stdout_mode ? "" : log_date(),
115 log_domain, *log_domain == 0 ? "" : ": ",
116 chomp_length(message), message);
118 g_free(converted);
121 static void
122 log_init_stdout(void)
124 g_log_set_default_handler(file_log_func, NULL);
127 static int
128 open_log_file(void)
130 assert(out_filename != NULL);
132 return open_cloexec(out_filename, O_CREAT | O_WRONLY | O_APPEND, 0666);
135 static void
136 log_init_file(const char *path, unsigned line)
138 out_filename = path;
139 out_fd = open_log_file();
140 if (out_fd < 0)
141 g_error("problem opening log file \"%s\" (config line %u) for "
142 "writing\n", path, line);
144 g_log_set_default_handler(file_log_func, NULL);
147 #ifdef HAVE_SYSLOG
149 static int
150 glib_to_syslog_level(GLogLevelFlags log_level)
152 switch (log_level & G_LOG_LEVEL_MASK) {
153 case G_LOG_LEVEL_ERROR:
154 case G_LOG_LEVEL_CRITICAL:
155 return LOG_ERR;
157 case G_LOG_LEVEL_WARNING:
158 return LOG_WARNING;
160 case G_LOG_LEVEL_MESSAGE:
161 return LOG_NOTICE;
163 case G_LOG_LEVEL_INFO:
164 return LOG_INFO;
166 case G_LOG_LEVEL_DEBUG:
167 return LOG_DEBUG;
169 default:
170 return LOG_NOTICE;
174 static void
175 syslog_log_func(const gchar *log_domain,
176 GLogLevelFlags log_level, const gchar *message,
177 G_GNUC_UNUSED gpointer user_data)
179 if (stdout_mode) {
180 /* fall back to the file log function during
181 startup */
182 file_log_func(log_domain, log_level,
183 message, user_data);
184 return;
187 if (log_level > log_threshold)
188 return;
190 if (log_domain == NULL)
191 log_domain = "";
193 syslog(glib_to_syslog_level(log_level), "%s%s%.*s",
194 log_domain, *log_domain == 0 ? "" : ": ",
195 chomp_length(message), message);
198 static void
199 log_init_syslog(void)
201 assert(out_filename == NULL);
203 openlog(PACKAGE, 0, LOG_DAEMON);
204 g_log_set_default_handler(syslog_log_func, NULL);
207 #endif
209 static inline GLogLevelFlags
210 parse_log_level(const char *value, unsigned line)
212 if (0 == strcmp(value, "default"))
213 return G_LOG_LEVEL_MESSAGE;
214 if (0 == strcmp(value, "secure"))
215 return LOG_LEVEL_SECURE;
216 else if (0 == strcmp(value, "verbose"))
217 return G_LOG_LEVEL_DEBUG;
218 else {
219 g_error("unknown log level \"%s\" at line %u\n",
220 value, line);
221 return G_LOG_LEVEL_MESSAGE;
225 void
226 log_early_init(bool verbose)
228 if (verbose)
229 log_threshold = G_LOG_LEVEL_DEBUG;
231 log_init_stdout();
234 void log_init(bool verbose, bool use_stdout)
236 const struct config_param *param;
238 g_get_charset(&log_charset);
240 if (verbose)
241 log_threshold = G_LOG_LEVEL_DEBUG;
242 else if ((param = config_get_param(CONF_LOG_LEVEL)) != NULL)
243 log_threshold = parse_log_level(param->value, param->line);
245 if (use_stdout) {
246 log_init_stdout();
247 } else {
248 param = config_get_param(CONF_LOG_FILE);
249 if (param == NULL) {
250 #ifdef HAVE_SYSLOG
251 /* no configuration: default to syslog (if
252 available) */
253 log_init_syslog();
254 #else
255 g_error("config parameter \"%s\" not found\n",
256 CONF_LOG_FILE);
257 #endif
258 #ifdef HAVE_SYSLOG
259 } else if (strcmp(param->value, "syslog") == 0) {
260 log_init_syslog();
261 #endif
262 } else {
263 const char *path = config_get_path(CONF_LOG_FILE);
264 assert(path != NULL);
266 log_init_file(path, param->line);
271 void setup_log_output(bool use_stdout)
273 fflush(NULL);
274 if (!use_stdout) {
275 if (out_filename == NULL)
276 out_fd = open("/dev/null", O_WRONLY);
278 if (out_fd >= 0) {
279 redirect_logs(out_fd);
280 close(out_fd);
283 stdout_mode = false;
284 log_charset = NULL;
288 int cycle_log_files(void)
290 int fd;
292 if (stdout_mode || out_filename == NULL)
293 return 0;
294 assert(out_filename);
296 g_debug("Cycling log files...\n");
297 close_log_files();
299 fd = open_log_file();
300 if (fd < 0) {
301 g_warning("error re-opening log file: %s\n", out_filename);
302 return -1;
305 redirect_logs(fd);
306 g_debug("Done cycling log files\n");
307 return 0;
310 void close_log_files(void)
312 if (stdout_mode)
313 return;
315 #ifdef HAVE_SYSLOG
316 if (out_filename == NULL)
317 closelog();
318 #endif