0564dd3350859fb386420e6d3d2cd8238541667d
[umurmur.git] / src / log.c
1 /* Copyright (C) 2009-2012, Martin Johansson <martin@fatbob.nu>
2    Copyright (C) 2005-2012, 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 void Log_init(bool_t terminal)
73 {
74         const char *logfilename;
75         
76         termprint = terminal;           
77         if (termprint)
78                 return;
79         
80         logfilename = getStrConf(LOGFILE);
81         if (logfilename != NULL) {
82                 openlogfile(logfilename);
83         }
84         else openlog("uMurmurd", LOG_PID, LOG_DAEMON);
85         init = true;
86 }
87
88 void Log_free()
89 {
90         if (termprint)
91                 return;
92         else if (logfile)
93                 fclose(logfile);
94         else 
95                 closelog();
96 }
97                 
98 void Log_reset()
99 {
100         const char *logfilename;
101         
102         if (logfile) {
103                 logfilename = getStrConf(LOGFILE);
104                 fclose(logfile);
105                 openlogfile(logfilename);
106         }
107 }
108
109 void logthis(const char *logstring, ...)
110 {
111         va_list argp;
112         char buf[STRSIZE + 1];
113         
114         va_start(argp, logstring);
115         vsnprintf(&buf[0], STRSIZE, logstring, argp);
116         va_end(argp);
117         if (termprint)
118                 fprintf(stderr, "%s\n", buf);
119         else if (logfile)
120                 fprintf(logfile, "%s\n", buf);
121         else
122                 syslog(LOG_INFO, "%s", buf);
123 }
124
125 void Log_warn(const char *logstring, ...)
126 {
127         va_list argp;
128         char buf[STRSIZE + 1];
129         int offset = 0;
130         
131         va_start(argp, logstring);
132         offset = sprintf(buf, "WARN: ");
133         vsnprintf(&buf[offset], STRSIZE - offset, logstring, argp);
134         va_end(argp);
135         if (termprint)
136                 fprintf(stderr, "%s\n", buf);
137         else if (logfile)
138                 fprintf(logfile, "%s\n", buf);
139         else
140                 syslog(LOG_WARNING, "%s", buf);
141 }
142
143 void Log_info(const char *logstring, ...)
144 {
145         va_list argp;
146         char buf[STRSIZE + 1];
147         int offset = 0;
148         
149         va_start(argp, logstring);
150         offset = sprintf(buf, "INFO: ");
151         vsnprintf(&buf[offset], STRSIZE - offset, logstring, argp);
152         va_end(argp);
153         if (termprint)
154                 fprintf(stderr, "%s\n", buf);
155         else if (logfile)
156                 fprintf(logfile, "%s\n", buf);
157         else
158                 syslog(LOG_INFO, "%s", buf);
159 }
160
161 void Log_info_client(client_t *client, const char *logstring, ...)
162 {
163         va_list argp;
164         char buf[STRSIZE + 1];
165         int offset = 0;
166         
167         va_start(argp, logstring);
168         offset = sprintf(buf, "INFO: ");
169         offset += vsnprintf(&buf[offset], STRSIZE - offset, logstring, argp);
170         va_end(argp);
171         offset += snprintf(&buf[offset], STRSIZE - offset, " - [%d] %s@%s:%d",
172                                            client->sessionId,
173                                            client->username == NULL ? "" : client->username,
174                                            inet_ntoa(client->remote_tcp.sin_addr),
175                                            ntohs(client->remote_tcp.sin_port));
176         if (termprint)
177                 fprintf(stderr, "%s\n", buf);
178         else if (logfile)
179                 fprintf(logfile, "%s\n", buf);
180         else
181                 syslog(LOG_INFO, "%s", buf);
182 }
183
184 #ifdef DEBUG
185 void Log_debug(const char *logstring, ...)
186 {
187         va_list argp;
188         char buf[STRSIZE + 1];
189         int offset = 0;
190         
191         va_start(argp, logstring);
192         offset = sprintf(buf, "DEBUG: ");
193         vsnprintf(&buf[offset], STRSIZE - offset, logstring, argp);
194         va_end(argp);
195         if (termprint)
196                 fprintf(stderr, "%s\n", buf);
197         else if (logfile)
198                 fprintf(logfile, "%s\n", buf);
199         else
200                 syslog(LOG_DEBUG, "%s", buf);
201 }
202 #endif
203
204 void Log_fatal(const char *logstring, ...)
205 {
206         va_list argp;
207         char buf[STRSIZE + 1];
208         int offset = 0;
209         va_start(argp, logstring);
210         offset = sprintf(buf, "FATAL: ");
211         vsnprintf(&buf[offset], STRSIZE - offset, logstring, argp);
212         va_end(argp);
213         if (termprint)
214                 fprintf(stderr, "%s\n", buf);
215         else if (logfile)
216                 fprintf(logfile, "%s\n", buf);
217         else { /* If logging subsystem is not initialized, fall back to stderr +
218                         * syslog logging for fatal errors. 
219                         */
220                 if (!init) {
221                         openlog("uMurmurd", LOG_PID, LOG_DAEMON);
222                         fprintf(stderr, "%s\n", buf);
223                 }
224                 syslog(LOG_CRIT, "%s", buf);
225         }
226         
227         exit(1);
228 }