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.
27 #include <sys/types.h>
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;
57 static const char *out_filename
;
59 static void redirect_logs(int fd
)
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
));
77 * Determines the length of the string excluding trailing whitespace
81 chomp_length(const char *p
)
83 size_t length
= strlen(p
);
85 while (length
> 0 && g_ascii_isspace(p
[length
- 1]))
92 file_log_func(const gchar
*log_domain
,
93 GLogLevelFlags log_level
,
94 const gchar
*message
, G_GNUC_UNUSED gpointer user_data
)
98 if (log_level
> log_threshold
)
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
)
110 if (log_domain
== NULL
)
113 fprintf(stderr
, "%s%s%s%.*s\n",
114 stdout_mode
? "" : log_date(),
115 log_domain
, *log_domain
== 0 ? "" : ": ",
116 chomp_length(message
), message
);
122 log_init_stdout(void)
124 g_log_set_default_handler(file_log_func
, NULL
);
130 assert(out_filename
!= NULL
);
132 return open_cloexec(out_filename
, O_CREAT
| O_WRONLY
| O_APPEND
, 0666);
136 log_init_file(const char *path
, unsigned line
)
139 out_fd
= open_log_file();
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
);
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
:
157 case G_LOG_LEVEL_WARNING
:
160 case G_LOG_LEVEL_MESSAGE
:
163 case G_LOG_LEVEL_INFO
:
166 case G_LOG_LEVEL_DEBUG
:
175 syslog_log_func(const gchar
*log_domain
,
176 GLogLevelFlags log_level
, const gchar
*message
,
177 G_GNUC_UNUSED gpointer user_data
)
180 /* fall back to the file log function during
182 file_log_func(log_domain
, log_level
,
187 if (log_level
> log_threshold
)
190 if (log_domain
== NULL
)
193 syslog(glib_to_syslog_level(log_level
), "%s%s%.*s",
194 log_domain
, *log_domain
== 0 ? "" : ": ",
195 chomp_length(message
), message
);
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
);
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
;
219 g_error("unknown log level \"%s\" at line %u\n",
221 return G_LOG_LEVEL_MESSAGE
;
226 log_early_init(bool verbose
)
229 log_threshold
= G_LOG_LEVEL_DEBUG
;
234 void log_init(bool verbose
, bool use_stdout
)
236 const struct config_param
*param
;
238 g_get_charset(&log_charset
);
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
);
248 param
= config_get_param(CONF_LOG_FILE
);
251 /* no configuration: default to syslog (if
255 g_error("config parameter \"%s\" not found\n",
259 } else if (strcmp(param
->value
, "syslog") == 0) {
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
)
275 if (out_filename
== NULL
)
276 out_fd
= open("/dev/null", O_WRONLY
);
279 redirect_logs(out_fd
);
288 int cycle_log_files(void)
292 if (stdout_mode
|| out_filename
== NULL
)
294 assert(out_filename
);
296 g_debug("Cycling log files...\n");
299 fd
= open_log_file();
301 g_warning("error re-opening log file: %s\n", out_filename
);
306 g_debug("Done cycling log files\n");
310 void close_log_files(void)
316 if (out_filename
== NULL
)