31f96c01d97959db3229deb6d1d4cc8da80c491c
[umurmur.git] / src / log.c
1 /* Copyright (C) 2009-2014, Martin Johansson <martin@fatbob.nu>
2    Copyright (C) 2005-2014, Thorvald Natvig <thorvald@natvig.com>
3
4    All rights reserved.
5
6    Redistribution and use in source and binary forms, with or without
7    modification, are permitted provided that the following conditions
8    are met:
9
10    - Redistributions of source code must retain the above copyright notice,
11      this list of conditions and the following disclaimer.
12    - Redistributions in binary form must reproduce the above copyright notice,
13      this list of conditions and the following disclaimer in the documentation
14      and/or other materials provided with the distribution.
15    - Neither the name of the Developers nor the names of its contributors may
16      be used to endorse or promote products derived from this software without
17      specific prior written permission.
18
19    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20    ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22    A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
23    CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24    EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28    NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <stdarg.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <syslog.h>
36 #include <string.h>
37 #include <unistd.h>
38 #include <fcntl.h>
39
40 #include "log.h"
41 #include "conf.h"
42
43 #define STRSIZE 254
44
45 static bool_t termprint, init;
46 static FILE *logfile;
47
48 static void openlogfile(const char *logfilename)
49 {
50         int fd, flags;
51         logfile = fopen(logfilename, "a");
52         if (logfile == NULL) {
53                 Log_fatal("Failed to open log file '%s' for writing: %s\n", logfilename, strerror(errno));
54         }
55
56         /* Set the stream as line buffered */
57         if (setvbuf(logfile, NULL, _IOLBF, 0) < 0)
58                 Log_fatal("setvbuf() failed: %s\n", strerror(errno));
59
60         /* XXX - Is it neccessary/appropriate that logging to file is non-blocking?
61          * If not, there's a risk that execution blocks, meaning that voice blocks
62          * as well since uMurmur is single threaded by design. OTOH, what could
63          * cause a block? If the disk causes blocking, it is probably br0ken, but
64          * the log could be on a nfs or smb share, so let's set it up as
65          * non-blocking and we'll see what happens.
66          */
67         fd = fileno(logfile);
68         flags = fcntl(fd, F_GETFL, 0);
69         fcntl(fd, F_SETFL, flags | O_NONBLOCK);
70 }
71
72 static char *timestring(void)
73 {
74         static char timebuf[32];
75         time_t t;
76         struct tm *timespec;
77
78         t= time(NULL);
79         timespec = localtime(&t);
80         strftime(timebuf, 32, "%b %e %T", timespec);
81         return timebuf;
82 }
83
84 void Log_init(bool_t terminal)
85 {
86         const char *logfilename;
87
88         termprint = terminal;
89         if (termprint)
90                 return;
91
92         logfilename = getStrConf(LOGFILE);
93         if (logfilename != NULL) {
94                 openlogfile(logfilename);
95         }
96         else openlog("uMurmurd", LOG_PID, LOG_DAEMON);
97         init = true;
98 }
99
100 void Log_free()
101 {
102         if (termprint)
103                 return;
104         else if (logfile)
105                 fclose(logfile);
106         else
107                 closelog();
108 }
109
110 void Log_reset()
111 {
112         const char *logfilename;
113
114         if (logfile) {
115                 logfilename = getStrConf(LOGFILE);
116                 fclose(logfile);
117                 openlogfile(logfilename);
118         }
119 }
120
121 void logthis(const char *logstring, ...)
122 {
123         va_list argp;
124         char buf[STRSIZE + 1];
125
126         va_start(argp, logstring);
127         vsnprintf(&buf[0], STRSIZE, logstring, argp);
128         va_end(argp);
129
130         if (termprint)
131                 fprintf(stderr, "%s\n", buf);
132         else if (logfile)
133                 fprintf(logfile, "%s %s\n", timestring(), buf);
134         else
135                 syslog(LOG_INFO, "%s", buf);
136 }
137
138 void Log_warn(const char *logstring, ...)
139 {
140         va_list argp;
141         char buf[STRSIZE + 1];
142         int offset = 0;
143
144         if (termprint || logfile)
145                 offset = sprintf(buf, "WARN: ");
146
147         va_start(argp, logstring);
148         vsnprintf(&buf[offset], STRSIZE - offset, logstring, argp);
149         va_end(argp);
150
151         if (termprint)
152                 fprintf(stderr, "%s\n", buf);
153         else if (logfile)
154                 fprintf(logfile, "%s %s\n", timestring(), buf);
155         else
156                 syslog(LOG_WARNING, "%s", buf);
157 }
158
159 void Log_info(const char *logstring, ...)
160 {
161         va_list argp;
162         char buf[STRSIZE + 1];
163         int offset = 0;
164
165         if (termprint || logfile)
166                 offset = sprintf(buf, "INFO: ");
167
168         va_start(argp, logstring);
169         vsnprintf(&buf[offset], STRSIZE - offset, logstring, argp);
170         va_end(argp);
171
172         if (termprint)
173                 fprintf(stderr, "%s\n", buf);
174         else if (logfile)
175                 fprintf(logfile, "%s %s\n", timestring(), buf);
176         else
177                 syslog(LOG_INFO, "%s", buf);
178 }
179
180 void Log_info_client(client_t *client, const char *logstring, ...)
181 {
182         va_list argp;
183         char buf[STRSIZE + 1];
184         int offset = 0;
185         uint16_t port;
186
187         if (termprint || logfile)
188                 offset = sprintf(buf, "INFO: ");
189
190         va_start(argp, logstring);
191         offset += vsnprintf(&buf[offset], STRSIZE - offset, logstring, argp);
192         va_end(argp);
193
194         if(client->remote_tcp.ss_family == AF_INET)
195                 port = ntohs(((struct sockaddr_in*)&client->remote_tcp)->sin_port);
196         else
197                 port = ntohs(((struct sockaddr_in6*)&client->remote_tcp)->sin6_port);
198
199         offset += snprintf(&buf[offset], STRSIZE - offset, " - [%d] %s@%s:%d",
200                 client->sessionId,
201                 client->username == NULL ? "" : client->username,
202                 client->addressString,
203                 port);
204
205         if (termprint)
206                 fprintf(stderr, "%s\n", buf);
207         else if (logfile)
208                 fprintf(logfile, "%s %s\n", timestring(), buf);
209         else
210                 syslog(LOG_INFO, "%s", buf);
211 }
212
213 #ifdef DEBUG
214 void Log_debug(const char *logstring, ...)
215 {
216         va_list argp;
217         char buf[STRSIZE + 1];
218         int offset = 0;
219
220         if (termprint || logfile)
221                 offset = sprintf(buf, "DEBUG: ");
222
223         va_start(argp, logstring);
224         vsnprintf(&buf[offset], STRSIZE - offset, logstring, argp);
225         va_end(argp);
226         if (termprint)
227                 fprintf(stderr, "%s\n", buf);
228         else if (logfile)
229                 fprintf(logfile, "%s %s\n", timestring(), buf);
230         else
231                 syslog(LOG_DEBUG, "%s", buf);
232 }
233 #endif
234
235 void Log_fatal(const char *logstring, ...)
236 {
237         va_list argp;
238         char buf[STRSIZE + 1];
239         int offset = 0;
240
241         if (termprint || logfile)
242                 offset = sprintf(buf, "FATAL: ");
243
244         va_start(argp, logstring);
245         vsnprintf(&buf[offset], STRSIZE - offset, logstring, argp);
246         va_end(argp);
247
248         if (termprint)
249                 fprintf(stderr, "%s\n", buf);
250         else if (logfile)
251                 fprintf(logfile, "%s %s\n", timestring(), buf);
252         else { /* If logging subsystem is not initialized, fall back to stderr +
253                         * syslog logging for fatal errors.
254                         */
255                 if (!init) {
256                         openlog("uMurmurd", LOG_PID, LOG_DAEMON);
257                         fprintf(stderr, "%s\n", buf);
258                 }
259                 syslog(LOG_CRIT, "%s", buf);
260         }
261
262         exit(1);
263 }