481905d8bf
Signed-off-by: Lon Hohberger <lhh@redhat.com>
192 lines
3.3 KiB
C
192 lines
3.3 KiB
C
/**
|
|
* Syslog wrapper that does not block
|
|
*
|
|
* Lon Hohberger, 2009
|
|
*/
|
|
#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, ...);
|
|
|
|
static void *
|
|
_log_thread(void *arg)
|
|
{
|
|
struct timeval tv;
|
|
struct timespec ts;
|
|
struct log_entry *entry;
|
|
|
|
pthread_mutex_lock(&log_mutex);
|
|
|
|
do {
|
|
gettimeofday(&tv, NULL);
|
|
ts.tv_sec = tv.tv_sec + 10;
|
|
ts.tv_nsec = tv.tv_usec;
|
|
|
|
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;
|
|
}
|
|
|
|
|
|
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;
|
|
int lost = 0;
|
|
|
|
pthread_cancel(thread_id);
|
|
pthread_join(thread_id, NULL);
|
|
thread_id = 0;
|
|
__real_closelog();
|
|
while (_log_entries) {
|
|
++lost;
|
|
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
|