add an in memory ringbuffer where we store the last 500000 log entries regardless...
[sahlberg/ctdb.git] / server / ctdb_logging.c
1 /* 
2    ctdb logging code
3
4    Copyright (C) Andrew Tridgell  2008
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 3 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
17    along with this program; if not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "includes.h"
21 #include "lib/events/events.h"
22 #include "../include/ctdb.h"
23 #include "../include/ctdb_private.h"
24 #include "system/syslog.h"
25 #include "system/time.h"
26 #include "system/filesys.h"
27
28 struct syslog_message {
29         uint32_t level;
30         uint32_t len;
31         char message[1];
32 };
33
34
35 struct ctdb_syslog_state {
36         int syslog_fd;
37         int fd[2];
38 };
39
40 static int syslogd_is_started = 0;
41
42
43 /* called when child is finished
44  * this is for the syslog daemon, we can not use DEBUG here
45  */
46 static void ctdb_syslog_handler(struct event_context *ev, struct fd_event *fde, 
47                                       uint16_t flags, void *p)
48 {
49         struct ctdb_syslog_state *state = talloc_get_type(p, struct ctdb_syslog_state);
50
51         int count;
52         char str[65536];
53         struct syslog_message *msg;
54
55         if (state == NULL) {
56                 return;
57         }
58
59         count = recv(state->syslog_fd, str, sizeof(str), 0);
60         if (count < sizeof(struct syslog_message)) {
61                 return;
62         }
63         msg = (struct syslog_message *)str;
64
65         syslog(msg->level, "%s", msg->message);
66 }
67
68
69 /* called when the pipd from the main daemon has closed
70  * this is for the syslog daemon, we can not use DEBUG here
71  */
72 static void ctdb_syslog_terminate_handler(struct event_context *ev, struct fd_event *fde, 
73                                       uint16_t flags, void *p)
74 {
75         syslog(LOG_ERR, "Shutting down SYSLOG daemon with pid:%d", (int)getpid());
76         _exit(0);
77 }
78
79
80
81 /*
82  * this is for the syslog daemon, we can not use DEBUG here
83  */
84 int start_syslog_daemon(struct ctdb_context *ctdb)
85 {
86         struct sockaddr_in syslog_sin;
87         struct ctdb_syslog_state *state;
88
89         state = talloc(ctdb, struct ctdb_syslog_state);
90         CTDB_NO_MEMORY(ctdb, state);
91
92         if (pipe(state->fd) != 0) {
93                 printf("Failed to create syslog pipe\n");
94                 talloc_free(state);
95                 return -1;
96         }
97         
98         ctdb->syslogd_pid = fork();
99         if (ctdb->syslogd_pid == (pid_t)-1) {
100                 printf("Failed to create syslog child process\n");
101                 close(state->fd[0]);
102                 close(state->fd[1]);
103                 talloc_free(state);
104                 return -1;
105         }
106
107         syslogd_is_started = 1;
108
109         if (ctdb->syslogd_pid != 0) {
110                 DEBUG(DEBUG_ERR,("Starting SYSLOG child process with pid:%d\n", (int)ctdb->syslogd_pid));
111
112                 close(state->fd[1]);
113                 set_close_on_exec(state->fd[0]);
114
115                 return 0;
116         }
117
118         talloc_free(ctdb->ev);
119         ctdb->ev = event_context_init(NULL);
120
121         syslog(LOG_ERR, "Starting SYSLOG daemon with pid:%d", (int)getpid());
122
123         close(state->fd[0]);
124         event_add_fd(ctdb->ev, state, state->fd[1], EVENT_FD_READ|EVENT_FD_AUTOCLOSE,
125                      ctdb_syslog_terminate_handler, state);
126
127         state->syslog_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
128         if (state->syslog_fd == -1) {
129                 printf("Failed to create syslog socket\n");
130                 return -1;
131         }
132
133         syslog_sin.sin_family = AF_INET;
134         syslog_sin.sin_port   = htons(CTDB_PORT);
135         syslog_sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);    
136
137         if (bind(state->syslog_fd, &syslog_sin, sizeof(syslog_sin)) == -1) {
138                 if (errno == EADDRINUSE) {
139                         /* this is ok, we already have a syslog daemon */
140                         _exit(0);
141                 }
142                 printf("syslog daemon failed to bind to socket. errno:%d(%s)\n", errno, strerror(errno));
143                 _exit(10);
144         }
145
146
147         event_add_fd(ctdb->ev, state, state->syslog_fd, EVENT_FD_READ|EVENT_FD_AUTOCLOSE,
148                      ctdb_syslog_handler, state);
149
150         event_loop_wait(ctdb->ev);
151
152         /* this should not happen */
153         _exit(10);
154 }
155
156 struct ctdb_log_state {
157         int fd, pfd;
158         char buf[1024];
159         uint16_t buf_used;
160         bool use_syslog;
161 };
162
163 /* we need this global to keep the DEBUG() syntax */
164 static struct ctdb_log_state *log_state;
165
166 /*
167   syslog logging function
168  */
169 static void ctdb_syslog_log(const char *format, va_list ap)
170 {
171         struct syslog_message *msg;
172         int level = LOG_DEBUG;
173         char *s = NULL;
174         int len, ret;
175         int syslog_fd;
176         struct sockaddr_in syslog_sin;
177
178         ret = vasprintf(&s, format, ap);
179         if (ret == -1) {
180                 return;
181         }
182
183         switch (this_log_level) {
184         case DEBUG_EMERG: 
185                 level = LOG_EMERG; 
186                 break;
187         case DEBUG_ALERT: 
188                 level = LOG_ALERT; 
189                 break;
190         case DEBUG_CRIT: 
191                 level = LOG_CRIT; 
192                 break;
193         case DEBUG_ERR: 
194                 level = LOG_ERR; 
195                 break;
196         case DEBUG_WARNING: 
197                 level = LOG_WARNING; 
198                 break;
199         case DEBUG_NOTICE: 
200                 level = LOG_NOTICE;
201                 break;
202         case DEBUG_INFO: 
203                 level = LOG_INFO;
204                 break;
205         default:
206                 level = LOG_DEBUG;
207                 break;          
208         }
209
210         len = offsetof(struct syslog_message, message) + strlen(s) + 1;
211         msg = malloc(len);
212         if (msg == NULL) {
213                 free(s);
214                 return;
215         }
216         msg->level = level;
217         msg->len   = strlen(s);
218         strcpy(msg->message, s);
219
220         if (syslogd_is_started == 0) {
221                 syslog(msg->level, "%s", msg->message);
222         } else {
223                 syslog_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
224                 if (syslog_fd == -1) {
225                         printf("Failed to create syslog socket\n");
226                         free(s);
227                         free(msg);
228                         return;
229                 }
230
231                 syslog_sin.sin_family = AF_INET;
232                 syslog_sin.sin_port   = htons(CTDB_PORT);
233                 syslog_sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);    
234
235        
236                 ret = sendto(syslog_fd, msg, len, 0, &syslog_sin, sizeof(syslog_sin));
237                 /* no point in checking here since we cant log an error */
238
239                 close(syslog_fd);
240         }
241
242         free(s);
243         free(msg);
244 }
245
246
247 /*
248   log file logging function
249  */
250 static void ctdb_logfile_log(const char *format, va_list ap)
251 {
252         struct timeval t;
253         char *s = NULL;
254         struct tm *tm;
255         char tbuf[100];
256         char *s2 = NULL;
257         int ret;
258
259         ret = vasprintf(&s, format, ap);
260         if (ret == -1) {
261                 const char *errstr = "vasprintf failed\n";
262
263                 write(log_state->fd, errstr, strlen(errstr));
264                 return;
265         }
266
267         t = timeval_current();
268         tm = localtime(&t.tv_sec);
269
270         strftime(tbuf,sizeof(tbuf)-1,"%Y/%m/%d %H:%M:%S", tm);
271
272         ret = asprintf(&s2, "%s.%06u [%5u]: %s",
273                  tbuf, (unsigned)t.tv_usec, (unsigned)getpid(), s);
274         free(s);
275         if (ret == -1) {
276                 const char *errstr = "asprintf failed\n";
277                 write(log_state->fd, errstr, strlen(errstr));
278                 return;
279         }
280         if (s2) {
281                 write(log_state->fd, s2, strlen(s2));
282                 free(s2);
283         }
284 }
285
286 static void ctdb_logfile_log_add(const char *format, va_list ap)
287 {
288         char *s = NULL;
289         int ret;
290
291         ret = vasprintf(&s, format, ap);
292         if (ret == -1) {
293                 const char *errstr = "vasprintf failed\n";
294
295                 write(log_state->fd, errstr, strlen(errstr));
296                 return;
297         }
298
299         if (s) {
300                 write(log_state->fd, s, strlen(s));
301                 free(s);
302         }
303 }
304
305
306
307 /*
308   choose the logfile location
309 */
310 int ctdb_set_logfile(struct ctdb_context *ctdb, const char *logfile, bool use_syslog)
311 {
312         int ret;
313
314         ctdb->log = talloc_zero(ctdb, struct ctdb_log_state);
315         if (ctdb->log == NULL) {
316                 printf("talloc_zero failed\n");
317                 abort();
318         }
319
320         log_state = ctdb->log;
321
322         if (use_syslog) {
323                 do_debug_v = ctdb_syslog_log;
324                 do_debug_add_v = ctdb_syslog_log;
325                 ctdb->log->use_syslog = true;
326         } else if (logfile == NULL || strcmp(logfile, "-") == 0) {
327                 do_debug_v = ctdb_logfile_log;
328                 do_debug_add_v = ctdb_logfile_log_add;
329                 ctdb->log->fd = 1;
330                 /* also catch stderr of subcommands to stdout */
331                 ret = dup2(1, 2);
332                 if (ret == -1) {
333                         printf("dup2 failed: %s\n", strerror(errno));
334                         abort();
335                 }
336         } else {
337                 do_debug_v = ctdb_logfile_log;
338                 do_debug_add_v = ctdb_logfile_log_add;
339
340                 ctdb->log->fd = open(logfile, O_WRONLY|O_APPEND|O_CREAT, 0666);
341                 if (ctdb->log->fd == -1) {
342                         printf("Failed to open logfile %s\n", logfile);
343                         abort();
344                 }
345         }
346
347         return 0;
348 }
349
350
351
352 /*
353   called when log data comes in from a child process
354  */
355 static void ctdb_log_handler(struct event_context *ev, struct fd_event *fde, 
356                              uint16_t flags, void *private)
357 {
358         struct ctdb_context *ctdb = talloc_get_type(private, struct ctdb_context);
359         char *p;
360         int n;
361
362         if (!(flags & EVENT_FD_READ)) {
363                 return;
364         }
365         
366         n = read(ctdb->log->pfd, &ctdb->log->buf[ctdb->log->buf_used],
367                  sizeof(ctdb->log->buf) - ctdb->log->buf_used);
368         if (n > 0) {
369                 ctdb->log->buf_used += n;
370         }
371
372         this_log_level = script_log_level;
373
374         while (ctdb->log->buf_used > 0 &&
375                (p = memchr(ctdb->log->buf, '\n', ctdb->log->buf_used)) != NULL) {
376                 int n1 = (p - ctdb->log->buf)+1;
377                 int n2 = n1 - 1;
378                 /* swallow \r from child processes */
379                 if (n2 > 0 && ctdb->log->buf[n2-1] == '\r') {
380                         n2--;
381                 }
382                 if (script_log_level <= LogLevel) {
383                         do_debug("%*.*s\n", n2, n2, ctdb->log->buf);
384                         /* log it in the eventsystem as well */
385                         ctdb_log_event_script_output(ctdb, ctdb->log->buf, n2);
386                 }
387                 memmove(ctdb->log->buf, p+1, sizeof(ctdb->log->buf) - n1);
388                 ctdb->log->buf_used -= n1;
389         }
390
391         /* the buffer could have completely filled - unfortunately we have
392            no choice but to dump it out straight away */
393         if (ctdb->log->buf_used == sizeof(ctdb->log->buf)) {
394                 if (script_log_level <= LogLevel) {
395                         do_debug("%*.*s\n", 
396                                 (int)ctdb->log->buf_used, (int)ctdb->log->buf_used, ctdb->log->buf);
397                         /* log it in the eventsystem as well */
398                         ctdb_log_event_script_output(ctdb, ctdb->log->buf, ctdb->log->buf_used);
399                 }
400                 ctdb->log->buf_used = 0;
401         }
402 }
403
404
405
406 /*
407   setup for logging of child process stdout
408 */
409 int ctdb_set_child_logging(struct ctdb_context *ctdb)
410 {
411         int p[2];
412         int ret;
413
414         if (ctdb->log->fd == 1) {
415                 /* not needed for stdout logging */
416                 return 0;
417         }
418
419         /* setup a pipe to catch IO from subprocesses */
420         if (pipe(p) != 0) {
421                 DEBUG(DEBUG_ERR,(__location__ " Failed to setup for child logging pipe\n"));
422                 return -1;
423         }
424
425         event_add_fd(ctdb->ev, ctdb, p[0], EVENT_FD_READ, 
426                      ctdb_log_handler, ctdb);
427         set_close_on_exec(p[0]);
428         ctdb->log->pfd = p[0];
429
430         DEBUG(DEBUG_NOTICE, (__location__ " Created PIPE FD:%d for logging\n", p[0]));
431
432         close(1);
433         close(2);
434         if (p[1] != 1) {
435                 ret = dup2(p[1], 1);
436                 if (ret == -1) {
437                         printf("dup2 failed: %s\n", strerror(errno));
438                         return -1;
439                 }
440                 close(p[1]);
441         }
442         /* also catch stderr of subcommands to the log */
443         ret = dup2(1, 2);
444         if (ret == -1) {
445                 printf("dup2 failed: %s\n", strerror(errno));
446                 return -1;
447         }
448
449         return 0;
450 }
451
452
453
454
455