summaryrefslogtreecommitdiffstats
path: root/agents/virt/common/log.c
diff options
context:
space:
mode:
Diffstat (limited to 'agents/virt/common/log.c')
-rw-r--r--agents/virt/common/log.c204
1 files changed, 204 insertions, 0 deletions
diff --git a/agents/virt/common/log.c b/agents/virt/common/log.c
new file mode 100644
index 0000000..61018ed
--- /dev/null
+++ b/agents/virt/common/log.c
@@ -0,0 +1,204 @@
+/**
+ * Syslog wrapper that does not block
+ *
+ * Lon Hohberger, 2009
+ */
+
+#include "config.h"
+
+#include <pthread.h>
+#include <unistd.h>
+#include <sys/syslog.h>
+#include <signal.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <errno.h>
+
+#include "list.h"
+
+struct log_entry {
+ list_head();
+ char *message;
+ int sev;
+ int bufsz;
+};
+
+#define MAX_QUEUE_LENGTH 10
+#define LOGLEN 256
+
+static struct log_entry *_log_entries = NULL;
+static pthread_mutex_t log_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t log_cond = PTHREAD_COND_INITIALIZER;
+static int log_size = 0;
+static int dropped = 0;
+static pthread_t thread_id = 0;
+
+void __real_syslog(int severity, const char *fmt, ...);
+void __wrap_syslog(int severity, const char *fmt, ...);
+void __wrap_closelog(void);
+
+static void *
+_log_thread(void *arg)
+{
+ struct timeval tv;
+ struct timespec ts;
+ struct log_entry *entry;
+
+ do {
+ gettimeofday(&tv, NULL);
+ ts.tv_sec = tv.tv_sec + 10;
+ ts.tv_nsec = tv.tv_usec;
+
+ pthread_mutex_lock(&log_mutex);
+
+ while (!(entry = _log_entries)) {
+ if (pthread_cond_timedwait(&log_cond,
+ &log_mutex,
+ &ts) == ETIMEDOUT)
+ goto out;
+ }
+
+ list_remove(&_log_entries, entry);
+ --log_size;
+ if (log_size < 0)
+ raise(SIGSEGV);
+ pthread_mutex_unlock(&log_mutex);
+
+ __real_syslog(entry->sev, entry->message);
+ free(entry->message);
+ free(entry);
+ } while (1);
+
+out:
+ thread_id = (pthread_t)0;
+ pthread_mutex_unlock(&log_mutex);
+ return NULL;
+}
+
+
+static int
+insert_entry(int sev, char *buf, int bufsz)
+{
+ struct log_entry *lent;
+ pthread_attr_t attrs;
+
+ lent = malloc(sizeof(*lent));
+ if (!lent)
+ return -1;
+ lent->sev = sev;
+ lent->message = buf;
+ lent->bufsz = bufsz;
+
+ pthread_mutex_lock(&log_mutex);
+ if (log_size >= MAX_QUEUE_LENGTH) {
+ free(lent->message);
+ free(lent);
+
+ ++dropped;
+ lent = (struct log_entry *)(le(_log_entries)->le_prev);
+
+ lent->sev = LOG_WARNING;
+ snprintf(lent->message, lent->bufsz,
+ "%d message(s) lost due to syslog load\n",
+ dropped + 1);
+ /* Dropped +1 because we overwrote a message to
+ * give the 'dropped' message */
+ } else {
+ ++log_size;
+ dropped = 0;
+ list_insert(&_log_entries, lent);
+ }
+
+ if (!thread_id) {
+ pthread_attr_init(&attrs);
+ pthread_attr_setinheritsched(&attrs, PTHREAD_INHERIT_SCHED);
+
+ if (pthread_create(&thread_id, &attrs, _log_thread, NULL) < 0)
+ thread_id = 0;
+ pthread_mutex_unlock(&log_mutex);
+ } else {
+ pthread_mutex_unlock(&log_mutex);
+ pthread_cond_signal(&log_cond);
+ }
+
+ return 0;
+}
+
+
+__attribute__((__format__ (__printf__, 2, 0)))
+void
+__wrap_syslog(int severity, const char *fmt, ...)
+{
+ va_list args;
+ char *logmsg;
+
+ logmsg = malloc(LOGLEN);
+ if (!logmsg)
+ return;
+ memset(logmsg, 0, LOGLEN);
+
+ va_start(args, fmt);
+ vsnprintf(logmsg + strlen(logmsg), LOGLEN - strlen(logmsg),
+ fmt, args);
+ va_end(args);
+
+ insert_entry(severity, logmsg, LOGLEN);
+
+ return;
+}
+
+
+void __real_closelog(void);
+
+void
+__wrap_closelog(void)
+{
+ struct log_entry *lent;
+#ifdef DEBUG
+ int lost = 0;
+#endif
+
+ if (thread_id != 0) {
+ pthread_cancel(thread_id);
+ pthread_join(thread_id, NULL);
+ thread_id = 0;
+ }
+ __real_closelog();
+ while (_log_entries) {
+#ifdef DEBUG
+ ++lost;
+#endif
+ lent = _log_entries;
+ list_remove(&_log_entries, lent);
+ free(lent->message);
+ free(lent);
+ }
+
+#ifdef DEBUG
+ printf("%d lost\n", lost);
+#endif
+}
+
+
+#ifdef STANDALONE
+int
+main(int argc, char**argv)
+{
+ int x;
+
+ for (x = 0; x < 100; x++) {
+ syslog(1, "Yo %d\n", x);
+ }
+ sleep(1);
+
+ closelog();
+
+ return 0;
+}
+
+#endif