From fc1d956f37d3ab0cbd7602d5bf1b30edb77af11b Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Fri, 1 Aug 2014 13:14:03 +1000 Subject: [PATCH] Make a per-process logger allowing logging to be line buffered yet asynchronous --- src/ckpool.c | 52 +++++++++++++++++++++++++++++++++++++++++++++------- src/ckpool.h | 41 ++++++++++++++++++++++------------------- 2 files changed, 67 insertions(+), 26 deletions(-) diff --git a/src/ckpool.c b/src/ckpool.c index b4fbd941..4490ab84 100644 --- a/src/ckpool.c +++ b/src/ckpool.c @@ -34,6 +34,30 @@ ckpool_t *global_ckp; +static void proclog(ckpool_t *ckp, char *msg) +{ + FILE *LOGFP; + int logfd; + + if (unlikely(!msg)) { + fprintf(stderr, "Proclog received null message"); + return; + } + if (unlikely(!strlen(msg))) { + fprintf(stderr, "Proclog received zero length message"); + free(msg); + return; + } + LOGFP = ckp->logfp; + logfd = ckp->logfd; + + flock(logfd, LOCK_EX); + fprintf(LOGFP, "%s", msg); + flock(logfd, LOCK_UN); + + free(msg); +} + /* Log everything to the logfile, but display warnings on the console as well */ void logmsg(int loglevel, const char *fmt, ...) { if (global_ckp->loglevel >= loglevel && fmt) { @@ -58,14 +82,13 @@ void logmsg(int loglevel, const char *fmt, ...) { tm->tm_min, tm->tm_sec); if (logfd) { - FILE *LOGFP = global_ckp->logfp; + char *msg; - flock(logfd, LOCK_EX); - fprintf(LOGFP, "%s %s", stamp, buf); if (loglevel <= LOG_ERR && errno != 0) - fprintf(LOGFP, " with errno %d: %s", errno, strerror(errno)); - fprintf(LOGFP, "\n"); - flock(logfd, LOCK_UN); + ASPRINTF(&msg, "%s %s with errno %d: %s\n", stamp, buf, errno, strerror(errno)); + else + ASPRINTF(&msg, "%s %s\n", stamp, buf); + ckmsgq_add(global_ckp->logger, msg); } if (loglevel <= LOG_WARNING) {\ if (loglevel <= LOG_ERR && errno != 0) @@ -677,6 +700,17 @@ static void childsighandler(int sig) kill(ppid, sig); } +static void launch_logger(proc_instance_t *pi) +{ + ckpool_t *ckp = pi->ckp; + char loggername[16]; + + /* Note that the logger is unique per process so it is the only value + * in ckp that differs between processes */ + snprintf(loggername, 15, "%clogger", pi->processname[0]); + ckp->logger = create_ckmsgq(ckp, loggername, &proclog); +} + static void launch_process(proc_instance_t *pi) { pid_t pid; @@ -688,6 +722,7 @@ static void launch_process(proc_instance_t *pi) struct sigaction handler; int ret; + launch_logger(pi); handler.sa_handler = &childsighandler; handler.sa_flags = 0; sigemptyset(&handler.sa_mask); @@ -1131,13 +1166,16 @@ int main(int argc, char **argv) ckp.logfp = fopen(buf, "a"); if (!ckp.logfp) quit(1, "Failed to make open log file %s", buf); - ckp.logfd = fileno(ckp.logfp); + /* Make logging line buffered */ + setvbuf(ckp.logfp, NULL, _IOLBF, 0); ckp.main.ckp = &ckp; ckp.main.processname = strdup("main"); ckp.main.sockname = strdup("listener"); write_namepid(&ckp.main); create_process_unixsock(&ckp.main); + launch_logger(&ckp.main); + ckp.logfd = fileno(ckp.logfp); create_pthread(&ckp.pth_listener, listener, &ckp.main); diff --git a/src/ckpool.h b/src/ckpool.h index a785b1bc..94d64e13 100644 --- a/src/ckpool.h +++ b/src/ckpool.h @@ -20,6 +20,26 @@ struct ckpool_instance; typedef struct ckpool_instance ckpool_t; +struct ckmsg { + struct ckmsg *next; + struct ckmsg *prev; + void *data; +}; + +typedef struct ckmsg ckmsg_t; + +struct ckmsgq { + ckpool_t *ckp; + char name[16]; + pthread_t pth; + pthread_mutex_t lock; + pthread_cond_t cond; + ckmsg_t *msgs; + void (*func)(ckpool_t *, void *); +}; + +typedef struct ckmsgq ckmsgq_t; + struct proc_instance { ckpool_t *ckp; unixsock_t us; @@ -81,6 +101,8 @@ struct ckpool_instance { FILE *logfp; int logfd; + /* Logger message queue NOTE: Unique per process */ + ckmsgq_t *logger; /* Process instance data of parent/child processes */ proc_instance_t main; @@ -129,25 +151,6 @@ struct ckpool_instance { char **proxypass; }; -struct ckmsg { - struct ckmsg *next; - struct ckmsg *prev; - void *data; -}; - -typedef struct ckmsg ckmsg_t; - -struct ckmsgq { - ckpool_t *ckp; - char name[16]; - pthread_t pth; - pthread_mutex_t lock; - pthread_cond_t cond; - ckmsg_t *msgs; - void (*func)(ckpool_t *, void *); -}; - -typedef struct ckmsgq ckmsgq_t; ckmsgq_t *create_ckmsgq(ckpool_t *ckp, const char *name, const void *func); void ckmsgq_add(ckmsgq_t *ckmsgq, void *data);