Update copyright year.
[umurmur.git] / src / log.c
1 /* Copyright (C) 2009-2013, Martin Johansson <martin@fatbob.nu>
2    Copyright (C) 2005-2013, 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         
186         if (termprint || logfile)
187                 offset = sprintf(buf, "INFO: ");
188
189         va_start(argp, logstring);
190         offset += vsnprintf(&buf[offset], STRSIZE - offset, logstring, argp);
191         va_end(argp);
192         
193         offset += snprintf(&buf[offset], STRSIZE - offset, " - [%d] %s@%s:%d",
194                                            client->sessionId,
195                                            client->username == NULL ? "" : client->username,
196                                            inet_ntoa(client->remote_tcp.sin_addr),
197                                            ntohs(client->remote_tcp.sin_port));
198         if (termprint)
199                 fprintf(stderr, "%s\n", buf);
200         else if (logfile)
201                 fprintf(logfile, "%s %s\n", timestring(), buf);
202         else
203                 syslog(LOG_INFO, "%s", buf);
204 }
205
206 #ifdef DEBUG
207 void Log_debug(const char *logstring, ...)
208 {
209         va_list argp;
210         char buf[STRSIZE + 1];
211         int offset = 0;
212         
213         if (termprint || logfile)
214                 offset = sprintf(buf, "DEBUG: ");
215         
216         va_start(argp, logstring);      
217         vsnprintf(&buf[offset], STRSIZE - offset, logstring, argp);
218         va_end(argp);
219         if (termprint)
220                 fprintf(stderr, "%s\n", buf);
221         else if (logfile)
222                 fprintf(logfile, "%s %s\n", timestring(), buf);
223         else
224                 syslog(LOG_DEBUG, "%s", buf);
225 }
226 #endif
227
228 void Log_fatal(const char *logstring, ...)
229 {
230         va_list argp;
231         char buf[STRSIZE + 1];
232         int offset = 0;
233         
234         if (termprint || logfile)
235                 offset = sprintf(buf, "FATAL: ");
236         
237         va_start(argp, logstring);      
238         vsnprintf(&buf[offset], STRSIZE - offset, logstring, argp);
239         va_end(argp);
240         
241         if (termprint)
242                 fprintf(stderr, "%s\n", buf);
243         else if (logfile)
244                 fprintf(logfile, "%s %s\n", timestring(), buf);
245         else { /* If logging subsystem is not initialized, fall back to stderr +
246                         * syslog logging for fatal errors. 
247                         */
248                 if (!init) {
249                         openlog("uMurmurd", LOG_PID, LOG_DAEMON);
250                         fprintf(stderr, "%s\n", buf);
251                 }
252                 syslog(LOG_CRIT, "%s", buf);
253         }
254         
255         exit(1);
256 }