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)
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.
43 #include <sys/types.h>
44 #include <sys/socket.h>
45 #if defined(OPENAIS_LINUX)
48 #if defined(OPENAIS_BSD) || defined(OPENAIS_DARWIN)
59 //#include "../include/saAis.h"
60 #include "mainconfig.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;
89 #define MAX_LOGGERS 32
91 struct logsys_logger logsys_loggers
[MAX_LOGGERS
];
99 struct log_entry
*next
;
102 static struct log_entry
*head
;
104 static struct log_entry
*tail
;
107 unsigned int syslog_pos
;
108 unsigned int priority
;
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)
131 int logsys_facility_id_get (const char *name
)
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
);
143 int logsys_priority_id_get (const char *name
)
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
);
155 static inline char *logsys_priority_name_get (unsigned int priority
)
159 for (i
= 0; prioritynames
[i
].c_name
!= NULL
; i
++) {
160 if (priority
== prioritynames
[i
].c_val
) {
161 return (prioritynames
[i
].c_name
);
167 unsigned int logsys_config_subsys_set (
170 unsigned int priority
)
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
;
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
;
198 assert(i
< MAX_LOGGERS
);
200 pthread_mutex_unlock (&logsys_config_mutex
);
204 inline int logsys_mkpri (int priority
, int id
)
206 return (((id
) << 3) | (priority
));
209 int logsys_config_subsys_get (
212 unsigned int *priority
)
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
);
227 pthread_mutex_unlock (&logsys_config_mutex
);
232 static void buffered_log_printf (
239 struct log_entry
*entry
= malloc(sizeof(struct log_entry
));
243 entry
->priority
= priority
;
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
);
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
,
290 char newstring
[4096];
291 char log_string
[4096];
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
);
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
);
328 if (logsys_nosubsys
== 1) {
329 sprintf (&newstring
[i
], "%s", format
);
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);
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
) {
365 if (logsys_wthread_active
) {
366 res
= worker_thread_group_work_add (&log_thread_group
, &log_data
);
368 dropped_log_entries
= 0;
370 dropped_log_entries
+= 1;
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
);
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 (
392 unsigned int priority
)
394 assert (subsys
!= NULL
);
396 return logsys_config_subsys_set (
403 void logsys_config_mode_set (unsigned int mode
)
405 pthread_mutex_lock (&logsys_config_mutex
);
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];
422 pthread_mutex_lock (&logsys_new_log_mutex
);
423 pthread_mutex_lock (&logsys_config_mutex
);
425 if (logsys_mode
& LOG_MODE_OUTPUT_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
);
442 pthread_mutex_unlock (&logsys_config_mutex
);
443 pthread_mutex_unlock (&logsys_new_log_mutex
);
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
);
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 (
486 sizeof (struct log_data
),
489 log_printf_worker_fn
);
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;
505 void logsys_log_printf (
512 int id
= LOG_ID(priority
);
513 int level
= LOG_LEVEL(priority
);
516 assert (id
< MAX_LOGGERS
);
518 if (LOG_LEVEL(priority
) > logsys_loggers
[id
].priority
) {
522 va_start (ap
, format
);
523 _log_printf (LOGSYS_CONFIG_MUTEX_UNLOCKED
, file
, line
, level
, id
,
528 static void logsys_log_printf_locked (
535 int id
= LOG_ID(priority
);
536 int level
= LOG_LEVEL(priority
);
539 assert (id
< MAX_LOGGERS
);
541 if (LOG_LEVEL(priority
) > logsys_loggers
[id
].priority
) {
545 va_start (ap
, format
);
546 _log_printf (LOGSYS_CONFIG_MUTEX_LOCKED
, file
, line
, level
, id
,
551 void _logsys_log_printf2 (
560 assert (id
< MAX_LOGGERS
);
562 va_start (ap
, format
);
563 _log_printf (LOGSYS_CONFIG_MUTEX_UNLOCKED
, file
, line
, priority
, id
,
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
) {
577 va_start (ap
, format
);
578 _log_printf (LOGSYS_CONFIG_MUTEX_LOCKED
, file
, line
,
579 LOG_LEVEL_DEBUG
, id
, format
, 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
) {
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
;
604 logsys_log_printf_locked (
618 void logsys_flush (void)
620 worker_thread_group_wait (&log_thread_group
);