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