#include <sys/select.h>
#include "libmultilog.h"
#include "async_logger.h"
+#include "multilog_internal.h"
#include <unistd.h>
*
* priority:file:line:msg
*/
-void write_to_buf(void *data, int priority, const char *file, int line,
+void write_to_buf(int priority, const char *file, int line,
const char *string)
{
char buf[CBUFSIZE];
* then how to we handle pthread_cond_signal?
*/
pthread_mutex_unlock(&cbuf.mutex);
- syslog(priority, "%s", mybuf);
+ logit(priority, file, line, mybuf);
pthread_mutex_lock(&cbuf.mutex);
}
* Handle logging to syslog through circular buffer so that syslog
* blocking doesn't hold anyone up.
*/
-static void *process_syslog(void *arg)
+static void *process_log(void *arg)
{
char mybuf[CBUFSIZE] = {0};
int priority;
cbuf.initialized = 1;
pthread_cleanup_push(finish_processing, NULL);
- /* FIXME: The program name needs to be variable. */
- openlog("dmeventd", LOG_NDELAY | LOG_PID, LOG_DAEMON);
-
while (1) {
/* check write_pos & read_pos */
if (cbuf.write_pos != cbuf.read_pos) {
* so we don't block the writer threads.
*/
pthread_mutex_unlock(&cbuf.mutex);
- syslog(priority, "%s", mybuf);
+ logit(priority, file, line, mybuf);
+/* syslog(priority, "%s", mybuf);*/
pthread_mutex_lock(&cbuf.mutex);
} else {
/*
}
}
- closelog();
pthread_cleanup_pop(0);
return NULL;
{
struct timeval ts = {0, usecs};
- pthread_create(thread, NULL, process_syslog, NULL);
+ /* FIXME: should i protect this with the mutex? */
+ if(cbuf.initialized)
+ return 1;
+
+ pthread_create(thread, NULL, process_log, NULL);
select(0, NULL, NULL, NULL, &ts);
/*
{
pthread_cancel(thread);
pthread_join(thread, NULL);
-
+ /* FIXME: should i protect this with the mutex? */
+ cbuf.initialized = 0;
return 1;
}
#include <sys/select.h>
#include "list.h"
#include "libmultilog.h"
+#include "multilog_internal.h"
#include <unistd.h>
#define DEFAULT_VERBOSITY 4
-struct threaded_syslog_log {
+struct threaded_log {
pthread_t thread;
void *dlh;
+ int (*start_log) (pthread_t *t, long usecs);
+ int (*stop_log) (pthread_t t);
+ void (*log) (int priority, const char *file,
+ int line, const char *string);
+ int enabled;
};
union log_info {
FILE *logfile;
- struct threaded_syslog_log threaded_syslog;
struct custom_log cl;
};
/* FIXME: probably shouldn't do it this way, but... */
static LIST_INIT(logs);
+static struct threaded_log tl;
+
/* locking for log accesss */
static void* (*init_lock_fn)(void) = NULL;
static int (*lock_fn)(void *) = NULL;
void *dlh;
if (!(dlh = dlopen("libmultilog_pthread_lock.so", RTLD_NOW))) {
- //fprintf(stderr, "%s\n", dlerror());
+ /* fprintf(stderr, "%s\n", dlerror()); */
if(strstr(dlerror(), "undefined symbol: pthread")) {
fprintf(stderr, "pthread library not linked in - using nop locking\n");
init_lock_fn = init_nop_lock;
};
}
-static int start_threaded_syslog(struct log_list *logl)
+static int start_threaded_log(void)
{
- void (*log_fxn) (void *data, int priority, const char *file, int line,
- const char *string);
- int (*start_syslog) (pthread_t *t, long usecs);
- int (*stop_syslog) (pthread_t t);
- struct log_data *logdata = &logl->data;
+ /*
+ * We set this immediately so that even if the threaded
+ * logging can't load, we don't log in a blocking manner - the
+ * non-blocking behavior overrides the fact that we won't see
+ * any logs if the async logging can't load
+ */
+ tl.enabled = 1;
- if (!(logdata->info.threaded_syslog.dlh = dlopen("libmultilog_async.so", RTLD_NOW))) {
+ if (!(tl.dlh = dlopen("libmultilog_async.so", RTLD_NOW))) {
fprintf(stderr, "%s\n", dlerror());
return 0;
}
- log_fxn = dlsym(logdata->info.threaded_syslog.dlh, "write_to_buf");
- start_syslog = dlsym(logdata->info.threaded_syslog.dlh, "start_syslog_thread");
- stop_syslog = dlsym(logl->data.info.threaded_syslog.dlh, "stop_syslog_thread");
+ tl.start_log = dlsym(tl.dlh, "start_syslog_thread");
+ tl.stop_log = dlsym(tl.dlh, "stop_syslog_thread");
+ tl.log = dlsym(tl.dlh, "write_to_buf");
- if (!log_fxn || !start_syslog || !stop_syslog) {
- dlclose(logdata->info.threaded_syslog.dlh);
+ if (!tl.start_log || !tl.stop_log || !tl.log) {
+ fprintf(stderr, "Unable to load all fxns\n");
+ dlclose(tl.dlh);
+ tl.dlh = NULL;
return 0;
}
/* FIXME: the timeout here probably can be tweaked */
/* FIXME: Probably want to do something if this fails */
- if (start_syslog(&(logdata->info.threaded_syslog.thread), 100000))
- logl->log = log_fxn;
+ if (tl.start_log(&(tl.thread), 100000)) {
+ return 1;
+ }
+ fprintf(stderr, "Bleh!\n");
+ return 0;
+}
- return logl->log ? 1 : 0;
+static int stop_threaded_log(void)
+{
+ if(tl.enabled) {
+ tl.enabled = 0;
+ if(tl.dlh) {
+ tl.stop_log(tl.thread);
+ dlclose(tl.dlh);
+ tl.dlh = NULL;
+ }
+ }
+ return 1;
}
int multilog_add_type(enum log_type type, void *data)
case std_syslog: {
struct sys_log *sld = data;
/* FIXME: pass in the name and facility */
- init_sys_log(sld->ident, sld->facility);
+ if(sld) {
+ init_sys_log(sld->ident, sld->facility);
+ }
logl->log = sys_log;
break;
}
- case threaded_syslog:
- if (!start_threaded_syslog(logl)) {
- lock_list(lock_handle);
- list_del(&logl->list);
- unlock_list(lock_handle);
- free(logl);
- return 0;
- }
-
- break;
case custom:
/* Caller should use multilog_custom to set their
* logging fxn */
unlock_list(lock_handle);
if (ll) {
- if (ll->type == threaded_syslog) {
- int (*stop_syslog) (pthread_t t);
- stop_syslog = dlsym(logl->data.info.threaded_syslog.dlh, "stop_syslog_thread");
- if(stop_syslog)
- stop_syslog(ll->data.info.threaded_syslog.thread);
-
- dlclose(ll->data.info.threaded_syslog.dlh);
- }
if (ll->type == custom) {
if(ll->data.info.cl.destructor) {
ll->data.info.cl.destructor(ll->data.info.cl.custom);
{
/* FIXME: stack allocation of large buffer. */
char buf[4096];
- struct log_list *logl;
va_list args;
va_start(args, format);
vsnprintf(buf, 4096, format, args);
va_end(args);
- lock_list(lock_handle);
-
- list_iterate_items(logl, &logs) {
- /* Custom logging types do just get the custom data
- * they setup initially - multilog doesn't do any
- * handling of custom loggers data */
- if(logl->type == custom)
- logl->log(logl->data.info.cl.custom, priority, file, line, buf);
- else
- logl->log(&logl->data, priority, file, line, buf);
+ if(tl.enabled) {
+ /* send to async code */
+ if(tl.dlh) {
+ tl.log(priority, file, line, buf);
+ }
}
- unlock_list(lock_handle);
+ else
+ /* Log directly */
+ logit(priority, file, line, buf);
}
unlock_list(lock_handle);
}
+
+/* Toggle asynchronous logging */
+int multilog_async(int enabled)
+{
+ if(enabled)
+ return start_threaded_log();
+ else
+ return stop_threaded_log();
+}
+
+
+/* Internal function */
+void logit(int priority, const char *file, int line, char *buf)
+{
+ struct log_list *logl;
+
+ lock_list(lock_handle);
+
+ list_iterate_items(logl, &logs) {
+ /* Custom logging types do just get the custom data
+ * they setup initially - multilog doesn't do any
+ * handling of custom loggers data */
+ if(logl->type == custom)
+ logl->log(logl->data.info.cl.custom, priority, file, line, buf);
+ else
+ logl->log(&logl->data, priority, file, line, buf);
+ }
+ unlock_list(lock_handle);
+
+}