Change initialization order for logsys logging to files to work properly.
[openais.git] / exec / logsys.c
blob7e3c54718716e247446da79228ba65cc5b0f0e79
1 /*
2 * Copyright (c) 2002-2004 MontaVista Software, Inc.
3 * Copyright (c) 2006-2007 Red Hat, Inc.
5 * Author: Steven Dake (sdake@redhat.com)
6 * Author: Lon Hohberger (lhh@redhat.com)
8 * All rights reserved.
10 * This software licensed under BSD license, the text of which follows:
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions are met:
15 * - Redistributions of source code must retain the above copyright notice,
16 * this list of conditions and the following disclaimer.
17 * - Redistributions in binary form must reproduce the above copyright notice,
18 * this list of conditions and the following disclaimer in the documentation
19 * and/or other materials provided with the distribution.
20 * - Neither the name of the MontaVista Software, Inc. nor the names of its
21 * contributors may be used to endorse or promote products derived from this
22 * software without specific prior written permission.
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
25 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
28 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
34 * THE POSSIBILITY OF SUCH DAMAGE.
36 #include <assert.h>
37 #include <stdio.h>
38 #include <string.h>
39 #include <stdarg.h>
40 #include <sys/time.h>
41 #include <time.h>
42 #include <errno.h>
43 #include <sys/types.h>
44 #include <sys/socket.h>
45 #if defined(OPENAIS_LINUX)
46 #include <linux/un.h>
47 #endif
48 #if defined(OPENAIS_BSD) || defined(OPENAIS_DARWIN)
49 #include <sys/un.h>
50 #endif
51 #define SYSLOG_NAMES
52 #include <syslog.h>
53 #include <stdlib.h>
54 #include <pthread.h>
56 #include "swab.h"
57 #include "logsys.h"
58 #include "totemip.h"
59 //#include "../include/saAis.h"
60 #include "mainconfig.h"
61 #include "wthread.h"
64 * Configuration parameters for logging system
66 static char *logsys_name = NULL;
68 static unsigned int logsys_mode = 0;
70 static char *logsys_file = NULL;
72 static FILE *logsys_file_fp = NULL;
74 static int logsys_facility = LOG_DAEMON;
76 static int logsys_nosubsys = 0;
78 static int logsys_wthread_active = 0;
80 static pthread_mutex_t logsys_config_mutex = PTHREAD_MUTEX_INITIALIZER;
82 static pthread_mutex_t logsys_new_log_mutex = PTHREAD_MUTEX_INITIALIZER;
84 static struct worker_thread_group log_thread_group;
86 static unsigned int dropped_log_entries = 0;
88 #ifndef MAX_LOGGERS
89 #define MAX_LOGGERS 32
90 #endif
91 struct logsys_logger logsys_loggers[MAX_LOGGERS];
94 struct log_entry {
95 char *file;
96 int line;
97 int priority;
98 char str[128];
99 struct log_entry *next;
102 static struct log_entry *head;
104 static struct log_entry *tail;
106 struct log_data {
107 unsigned int syslog_pos;
108 unsigned int priority;
109 char *log_string;
112 enum logsys_config_mutex_state {
113 LOGSYS_CONFIG_MUTEX_LOCKED,
114 LOGSYS_CONFIG_MUTEX_UNLOCKED
117 static void logsys_atexit (void);
119 #define LEVELMASK 0x07 /* 3 bits */
120 #define LOG_LEVEL(p) ((p) & LEVELMASK)
121 #define LOGSYS_IDMASK (0x3f << 3) /* 6 bits */
122 #define LOG_ID(p) (((p) & LOGSYS_IDMASK) >> 3)
124 static void logsys_buffer_flush (void);
126 void _logsys_nosubsys_set (void)
128 logsys_nosubsys = 1;
131 int logsys_facility_id_get (const char *name)
133 unsigned int i;
135 for (i = 0; facilitynames[i].c_name != NULL; i++) {
136 if (strcasecmp(name, facilitynames[i].c_name) == 0) {
137 return (facilitynames[i].c_val);
140 return (-1);
143 int logsys_priority_id_get (const char *name)
145 unsigned int i;
147 for (i = 0; prioritynames[i].c_name != NULL; i++) {
148 if (strcasecmp(name, prioritynames[i].c_name) == 0) {
149 return (prioritynames[i].c_val);
152 return (-1);
155 static inline char *logsys_priority_name_get (unsigned int priority)
157 unsigned int i;
159 for (i = 0; prioritynames[i].c_name != NULL; i++) {
160 if (priority == prioritynames[i].c_val) {
161 return (prioritynames[i].c_name);
164 return (NULL);
167 unsigned int logsys_config_subsys_set (
168 const char *subsys,
169 unsigned int tags,
170 unsigned int priority)
172 int i;
174 pthread_mutex_lock (&logsys_config_mutex);
175 for (i = 0; i < MAX_LOGGERS; i++) {
176 if (strcmp (logsys_loggers[i].subsys, subsys) == 0) {
177 logsys_loggers[i].tags = tags;
178 logsys_loggers[i].priority = priority;
180 if (priority > logsys_loggers[i].priority) {
181 logsys_loggers[i].priority = priority;
183 break;
187 if (i == MAX_LOGGERS) {
188 for (i = 0; i < MAX_LOGGERS; i++) {
189 if (strcmp (logsys_loggers[i].subsys, "") == 0) {
190 strncpy (logsys_loggers[i].subsys, subsys,
191 sizeof(logsys_loggers[i].subsys));
192 logsys_loggers[i].tags = tags;
193 logsys_loggers[i].priority = priority;
194 break;
198 assert(i < MAX_LOGGERS);
200 pthread_mutex_unlock (&logsys_config_mutex);
201 return i;
204 inline int logsys_mkpri (int priority, int id)
206 return (((id) << 3) | (priority));
209 int logsys_config_subsys_get (
210 const char *subsys,
211 unsigned int *tags,
212 unsigned int *priority)
214 unsigned int i;
216 pthread_mutex_lock (&logsys_config_mutex);
218 for (i = 0; i < MAX_LOGGERS; i++) {
219 if (strcmp (logsys_loggers[i].subsys, subsys) == 0) {
220 *tags = logsys_loggers[i].tags;
221 *priority = logsys_loggers[i].priority;
222 pthread_mutex_unlock (&logsys_config_mutex);
223 return (0);
227 pthread_mutex_unlock (&logsys_config_mutex);
229 return (-1);
232 static void buffered_log_printf (
233 char *file,
234 int line,
235 int priority,
236 char *format,
237 va_list ap)
239 struct log_entry *entry = malloc(sizeof(struct log_entry));
241 entry->file = file;
242 entry->line = line;
243 entry->priority = priority;
244 entry->next = NULL;
245 if (head == NULL) {
246 head = tail = entry;
247 } else {
248 tail->next = entry;
249 tail = entry;
251 vsnprintf(entry->str, sizeof(entry->str), format, ap);
254 static void log_printf_worker_fn (void *thread_data, void *work_item)
256 struct log_data *log_data = (struct log_data *)work_item;
258 if (logsys_wthread_active)
259 pthread_mutex_lock (&logsys_config_mutex);
261 * Output the log data
263 if (logsys_mode & LOG_MODE_OUTPUT_FILE && logsys_file_fp != 0) {
264 fprintf (logsys_file_fp, "%s", log_data->log_string);
265 fflush (logsys_file_fp);
267 if (logsys_mode & LOG_MODE_OUTPUT_STDERR) {
268 fprintf (stderr, "%s", log_data->log_string);
269 fflush (stdout);
272 if (logsys_mode & LOG_MODE_OUTPUT_SYSLOG_THREADED) {
273 syslog (log_data->priority,
274 &log_data->log_string[log_data->syslog_pos]);
276 free (log_data->log_string);
277 if (logsys_wthread_active)
278 pthread_mutex_unlock (&logsys_config_mutex);
281 static void _log_printf (
282 enum logsys_config_mutex_state config_mutex_state,
283 char *file,
284 int line,
285 int priority,
286 int id,
287 char *format,
288 va_list ap)
290 char newstring[4096];
291 char log_string[4096];
292 char char_time[512];
293 struct timeval tv;
294 int i = 0;
295 int len;
296 struct log_data log_data;
297 unsigned int res = 0;
299 assert (id < MAX_LOGGERS);
301 if (config_mutex_state == LOGSYS_CONFIG_MUTEX_UNLOCKED) {
302 pthread_mutex_lock (&logsys_config_mutex);
304 pthread_mutex_lock (&logsys_new_log_mutex);
306 ** Buffer before log has been configured has been called.
308 if (logsys_mode & LOG_MODE_BUFFER_BEFORE_CONFIG) {
309 buffered_log_printf(file, line, logsys_mkpri(priority, id), format, ap);
310 pthread_mutex_unlock (&logsys_new_log_mutex);
311 if (config_mutex_state == LOGSYS_CONFIG_MUTEX_UNLOCKED) {
312 pthread_mutex_unlock (&logsys_config_mutex);
314 return;
317 if (((logsys_mode & LOG_MODE_OUTPUT_FILE) || (logsys_mode & LOG_MODE_OUTPUT_STDERR)) &&
318 (logsys_mode & LOG_MODE_DISPLAY_TIMESTAMP)) {
319 gettimeofday (&tv, NULL);
320 strftime (char_time, sizeof (char_time), "%b %e %k:%M:%S",
321 localtime (&tv.tv_sec));
322 i = sprintf (newstring, "%s.%06ld ", char_time, (long)tv.tv_usec);
325 if ((priority == LOG_LEVEL_DEBUG) || (logsys_mode & LOG_MODE_DISPLAY_FILELINE)) {
326 sprintf (&newstring[i], "[%s:%04u] %s", file, line, format);
327 } else {
328 if (logsys_nosubsys == 1) {
329 sprintf (&newstring[i], "%s", format);
330 } else {
331 sprintf (&newstring[i], "[%-5s] %s", logsys_loggers[id].subsys, format);
334 if (dropped_log_entries) {
336 * Get rid of \n if there is one
338 if (newstring[strlen (newstring) - 1] == '\n') {
339 newstring[strlen (newstring) - 1] = '\0';
341 len = sprintf (log_string,
342 "%s - prior to this log entry, openais logger dropped '%d' messages because of overflow.", newstring, dropped_log_entries + 1);
343 } else {
344 len = vsprintf (log_string, newstring, ap);
348 ** add line feed if not done yet
350 if (log_string[len - 1] != '\n') {
351 log_string[len] = '\n';
352 log_string[len + 1] = '\0';
356 * Create work thread data
358 log_data.syslog_pos = i;
359 log_data.priority = priority;
360 log_data.log_string = strdup (log_string);
361 if (log_data.log_string == NULL) {
362 goto drop_log_msg;
365 if (logsys_wthread_active) {
366 res = worker_thread_group_work_add (&log_thread_group, &log_data);
367 if (res == 0) {
368 dropped_log_entries = 0;
369 } else {
370 dropped_log_entries += 1;
372 } else {
373 log_printf_worker_fn (NULL, &log_data);
376 pthread_mutex_unlock (&logsys_new_log_mutex);
377 if (config_mutex_state == LOGSYS_CONFIG_MUTEX_UNLOCKED) {
378 pthread_mutex_unlock (&logsys_config_mutex);
380 return;
382 drop_log_msg:
383 dropped_log_entries++;
384 pthread_mutex_unlock (&logsys_new_log_mutex);
385 if (config_mutex_state == LOGSYS_CONFIG_MUTEX_UNLOCKED) {
386 pthread_mutex_unlock (&logsys_config_mutex);
390 unsigned int _logsys_subsys_create (
391 const char *subsys,
392 unsigned int priority)
394 assert (subsys != NULL);
396 return logsys_config_subsys_set (
397 subsys,
398 LOGSYS_TAG_LOG,
399 priority);
403 void logsys_config_mode_set (unsigned int mode)
405 pthread_mutex_lock (&logsys_config_mutex);
406 logsys_mode = mode;
407 if (mode & LOG_MODE_FLUSH_AFTER_CONFIG) {
408 _logsys_wthread_create ();
409 logsys_buffer_flush ();
411 pthread_mutex_unlock (&logsys_config_mutex);
414 int logsys_config_file_set (char **error_string, char *file)
416 static char error_string_response[512];
418 if (file == NULL) {
419 return (0);
422 pthread_mutex_lock (&logsys_new_log_mutex);
423 pthread_mutex_lock (&logsys_config_mutex);
425 if (logsys_mode & LOG_MODE_OUTPUT_FILE) {
426 logsys_file = file;
427 if (logsys_file_fp != NULL) {
428 fclose (logsys_file_fp);
430 logsys_file_fp = fopen (file, "a+");
431 if (logsys_file_fp == 0) {
432 sprintf (error_string_response,
433 "Can't open logfile '%s' for reason (%s).\n",
434 file, strerror (errno));
435 *error_string = error_string_response;
436 pthread_mutex_unlock (&logsys_config_mutex);
437 pthread_mutex_unlock (&logsys_new_log_mutex);
438 return (-1);
442 pthread_mutex_unlock (&logsys_config_mutex);
443 pthread_mutex_unlock (&logsys_new_log_mutex);
444 return (0);
447 void logsys_config_facility_set (char *name, unsigned int facility)
449 pthread_mutex_lock (&logsys_new_log_mutex);
450 pthread_mutex_lock (&logsys_config_mutex);
452 logsys_name = name;
453 logsys_facility = facility;
455 pthread_mutex_unlock (&logsys_config_mutex);
456 pthread_mutex_unlock (&logsys_new_log_mutex);
459 void _logsys_config_priority_set (unsigned int id, unsigned int priority)
461 pthread_mutex_lock (&logsys_new_log_mutex);
463 logsys_loggers[id].priority = priority;
465 if (priority > logsys_loggers[id].priority) {
466 logsys_loggers[id].priority = priority;
469 pthread_mutex_unlock (&logsys_new_log_mutex);
472 static void child_cleanup (void)
474 memset(&log_thread_group, 0, sizeof(log_thread_group));
475 logsys_wthread_active = 0;
476 pthread_mutex_init(&logsys_config_mutex, NULL);
477 pthread_mutex_init(&logsys_new_log_mutex, NULL);
480 int _logsys_wthread_create (void)
482 worker_thread_group_init (
483 &log_thread_group,
485 1024,
486 sizeof (struct log_data),
488 NULL,
489 log_printf_worker_fn);
491 logsys_flush();
493 atexit (logsys_atexit);
494 pthread_atfork(NULL, NULL, child_cleanup);
496 if (logsys_mode & LOG_MODE_OUTPUT_SYSLOG_THREADED && logsys_name != NULL) {
497 openlog (logsys_name, LOG_CONS|LOG_PID, logsys_facility);
500 logsys_wthread_active = 1;
502 return (0);
505 void logsys_log_printf (
506 char *file,
507 int line,
508 int priority,
509 char *format,
510 ...)
512 int id = LOG_ID(priority);
513 int level = LOG_LEVEL(priority);
514 va_list ap;
516 assert (id < MAX_LOGGERS);
518 if (LOG_LEVEL(priority) > logsys_loggers[id].priority) {
519 return;
522 va_start (ap, format);
523 _log_printf (LOGSYS_CONFIG_MUTEX_UNLOCKED, file, line, level, id,
524 format, ap);
525 va_end(ap);
528 static void logsys_log_printf_locked (
529 char *file,
530 int line,
531 int priority,
532 char *format,
533 ...)
535 int id = LOG_ID(priority);
536 int level = LOG_LEVEL(priority);
537 va_list ap;
539 assert (id < MAX_LOGGERS);
541 if (LOG_LEVEL(priority) > logsys_loggers[id].priority) {
542 return;
545 va_start (ap, format);
546 _log_printf (LOGSYS_CONFIG_MUTEX_LOCKED, file, line, level, id,
547 format, ap);
548 va_end(ap);
551 void _logsys_log_printf2 (
552 char *file,
553 int line,
554 int priority,
555 int id,
556 char *format, ...)
558 va_list ap;
560 assert (id < MAX_LOGGERS);
562 va_start (ap, format);
563 _log_printf (LOGSYS_CONFIG_MUTEX_UNLOCKED, file, line, priority, id,
564 format, ap);
565 va_end(ap);
568 void _logsys_trace (char *file, int line, int tag, int id, char *format, ...)
570 assert (id < MAX_LOGGERS);
572 pthread_mutex_lock (&logsys_config_mutex);
574 if (tag & logsys_loggers[id].tags) {
575 va_list ap;
577 va_start (ap, format);
578 _log_printf (LOGSYS_CONFIG_MUTEX_LOCKED, file, line,
579 LOG_LEVEL_DEBUG, id, format, ap);
580 va_end(ap);
582 pthread_mutex_unlock (&logsys_config_mutex);
585 static void logsys_atexit (void)
587 if (logsys_wthread_active) {
588 worker_thread_group_wait (&log_thread_group);
590 if (logsys_mode & LOG_MODE_OUTPUT_SYSLOG_THREADED) {
591 closelog ();
595 static void logsys_buffer_flush (void)
597 struct log_entry *entry = head;
598 struct log_entry *tmp;
600 if (logsys_mode & LOG_MODE_FLUSH_AFTER_CONFIG) {
601 logsys_mode &= ~LOG_MODE_FLUSH_AFTER_CONFIG;
603 while (entry) {
604 logsys_log_printf_locked (
605 entry->file,
606 entry->line,
607 entry->priority,
608 entry->str);
609 tmp = entry;
610 entry = entry->next;
611 free (tmp);
615 head = tail = NULL;
618 void logsys_flush (void)
620 worker_thread_group_wait (&log_thread_group);