Add logging to file
[umurmur.git] / src / log.c
1 /* Copyright (C) 2009-2010, Martin Johansson <martin@fatbob.nu>
2    Copyright (C) 2005-2010, 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         /* XXX - Is it neccessary/appropriate that logging to file is non-blocking?
57          * If not, there's a risk that execution blocks, meaning that voice blocks
58          * as well since uMurmur is single threaded by design. OTOH, what could
59          * cause a block? If the disk causes blocking, it is probably br0ken. but
60          * the log could be on a nfs or smb share, so let's set it up as
61          * non-blocking and we'll see what happens.
62          */
63         fd = fileno(logfile);
64         flags = fcntl(fd, F_GETFL, 0);
65         fcntl(fd, F_SETFL, flags | O_NONBLOCK);
66 }
67
68 void Log_init(bool_t terminal)
69 {
70         const char *logfilename;
71         
72         termprint = terminal;           
73         if (termprint)
74                 return;
75         
76         logfilename = getStrConf(LOGFILE);
77         if (logfilename != NULL) {
78                 openlogfile(logfilename);
79         }
80         else openlog("uMurmurd", LOG_PID, LOG_DAEMON);
81         init = true;
82 }
83
84 void Log_free()
85 {
86         if (termprint)
87                 return;
88         else if (logfile)
89                 fclose(logfile);
90         else 
91                 closelog();
92 }
93                 
94 void Log_reset()
95 {
96         const char *logfilename;
97         
98         if (logfile) {
99                 logfilename = getStrConf(LOGFILE);
100                 fclose(logfile);
101                 openlogfile(logfilename);
102         }
103 }
104
105 void logthis(const char *logstring, ...)
106 {
107         va_list argp;
108         char buf[STRSIZE + 1];
109         
110         va_start(argp, logstring);
111         vsnprintf(&buf[0], STRSIZE, logstring, argp);
112         va_end(argp);
113         if (termprint)
114                 fprintf(stderr, "%s\n", buf);
115         else if (logfile)
116                 fprintf(logfile, "%s\n", buf);
117         else
118                 syslog(LOG_INFO, "%s", buf);
119 }
120
121 void Log_warn(const char *logstring, ...)
122 {
123         va_list argp;
124         char buf[STRSIZE + 1];
125         int offset = 0;
126         
127         va_start(argp, logstring);
128         offset = sprintf(buf, "WARN: ");
129         vsnprintf(&buf[offset], STRSIZE - offset, logstring, argp);
130         va_end(argp);
131         if (termprint)
132                 fprintf(stderr, "%s\n", buf);
133         else if (logfile)
134                 fprintf(logfile, "%s\n", buf);
135         else
136                 syslog(LOG_WARNING, "%s", buf);
137 }
138
139 void Log_info(const char *logstring, ...)
140 {
141         va_list argp;
142         char buf[STRSIZE + 1];
143         int offset = 0;
144         
145         va_start(argp, logstring);
146         offset = sprintf(buf, "INFO: ");
147         vsnprintf(&buf[offset], STRSIZE - offset, logstring, argp);
148         va_end(argp);
149         if (termprint)
150                 fprintf(stderr, "%s\n", buf);
151         else if (logfile) {
152                 fprintf(logfile, "%s\n", buf);
153                 fflush(logfile);
154         }
155         else
156                 syslog(LOG_INFO, "%s", buf);
157 }
158
159 void Log_info_client(client_t *client, const char *logstring, ...)
160 {
161         va_list argp;
162         char buf[STRSIZE + 1];
163         int offset = 0;
164         
165         va_start(argp, logstring);
166         offset = sprintf(buf, "INFO: ");
167         offset += vsnprintf(&buf[offset], STRSIZE - offset, logstring, argp);
168         va_end(argp);
169         offset += snprintf(&buf[offset], STRSIZE - offset, " - [%d] %s@%s:%d",
170                                            client->sessionId,
171                                            client->username == NULL ? "" : client->username,
172                                            inet_ntoa(client->remote_tcp.sin_addr),
173                                            ntohs(client->remote_tcp.sin_port));
174         if (termprint)
175                 fprintf(stderr, "%s\n", buf);
176         else if (logfile)
177                 fprintf(logfile, "%s\n", buf);
178         else
179                 syslog(LOG_INFO, "%s", buf);
180 }
181
182 #ifdef DEBUG
183 void Log_debug(const char *logstring, ...)
184 {
185         va_list argp;
186         char buf[STRSIZE + 1];
187         int offset = 0;
188         
189         va_start(argp, logstring);
190         offset = sprintf(buf, "DEBUG: ");
191         vsnprintf(&buf[offset], STRSIZE - offset, logstring, argp);
192         va_end(argp);
193         if (termprint)
194                 fprintf(stderr, "%s\n", buf);
195         else if (logfile)
196                 fprintf(logfile, "%s\n", buf);
197         else
198                 syslog(LOG_DEBUG, "%s", buf);
199 }
200 #endif
201
202 void Log_fatal(const char *logstring, ...)
203 {
204         va_list argp;
205         char buf[STRSIZE + 1];
206         int offset = 0;
207         va_start(argp, logstring);
208         offset = sprintf(buf, "FATAL: ");
209         vsnprintf(&buf[offset], STRSIZE - offset, logstring, argp);
210         va_end(argp);
211         if (termprint)
212                 fprintf(stderr, "%s\n", buf);
213         else if (logfile)
214                 fprintf(logfile, "%s\n", buf);
215         else { /* If logging subsystem is not initialized, fall back to syslog logging
216                         * for fatal errors. Only config file reading that needs this currently.
217                         */
218                 if (!init)
219                         openlog("uMurmurd", LOG_PID, LOG_DAEMON);
220                 syslog(LOG_CRIT, "%s", buf);
221         }
222         
223         exit(1);
224 }