From a998a32f313362b44ff450ec696d65c6805f5c4b Mon Sep 17 00:00:00 2001 From: Sam Stevens Date: Wed, 6 Aug 2014 21:36:53 +0100 Subject: [PATCH] Added logging sub-system --- .gitignore | 1 + nbproject/Makefile-Debug.mk | 6 ++ nbproject/Makefile-Release.mk | 6 ++ nbproject/configurations.xml | 10 ++ src/log.c | 197 ++++++++++++++++++++++++++++++++++ src/log.h | 82 ++++++++++++++ src/main.c | 5 + src/thread-pool.c | 2 +- src/util.c | 32 ++++-- 9 files changed, 330 insertions(+), 11 deletions(-) create mode 100644 src/log.c create mode 100644 src/log.h diff --git a/.gitignore b/.gitignore index 2247d5f..5016647 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /build /dist +/nbproject/private diff --git a/nbproject/Makefile-Debug.mk b/nbproject/Makefile-Debug.mk index 547a80b..66d3082 100644 --- a/nbproject/Makefile-Debug.mk +++ b/nbproject/Makefile-Debug.mk @@ -41,6 +41,7 @@ OBJECTFILES= \ ${OBJECTDIR}/src/http-reader.o \ ${OBJECTDIR}/src/http-server.o \ ${OBJECTDIR}/src/http.o \ + ${OBJECTDIR}/src/log.o \ ${OBJECTDIR}/src/main.o \ ${OBJECTDIR}/src/mime.o \ ${OBJECTDIR}/src/queue.o \ @@ -103,6 +104,11 @@ ${OBJECTDIR}/src/http.o: nbproject/Makefile-${CND_CONF}.mk src/http.c ${RM} "$@.d" $(COMPILE.c) -g -Werror -DINI_ALLOW_BOM=0 -DINI_ALLOW_MULTILINE=0 -D_GNU_SOURCE -Ilib -std=c99 -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/src/http.o src/http.c +${OBJECTDIR}/src/log.o: nbproject/Makefile-${CND_CONF}.mk src/log.c + ${MKDIR} -p ${OBJECTDIR}/src + ${RM} "$@.d" + $(COMPILE.c) -g -Werror -DINI_ALLOW_BOM=0 -DINI_ALLOW_MULTILINE=0 -D_GNU_SOURCE -Ilib -std=c99 -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/src/log.o src/log.c + ${OBJECTDIR}/src/main.o: nbproject/Makefile-${CND_CONF}.mk src/main.c ${MKDIR} -p ${OBJECTDIR}/src ${RM} "$@.d" diff --git a/nbproject/Makefile-Release.mk b/nbproject/Makefile-Release.mk index 6a01c53..cf1bb2b 100644 --- a/nbproject/Makefile-Release.mk +++ b/nbproject/Makefile-Release.mk @@ -41,6 +41,7 @@ OBJECTFILES= \ ${OBJECTDIR}/src/http-reader.o \ ${OBJECTDIR}/src/http-server.o \ ${OBJECTDIR}/src/http.o \ + ${OBJECTDIR}/src/log.o \ ${OBJECTDIR}/src/main.o \ ${OBJECTDIR}/src/mime.o \ ${OBJECTDIR}/src/queue.o \ @@ -103,6 +104,11 @@ ${OBJECTDIR}/src/http.o: nbproject/Makefile-${CND_CONF}.mk src/http.c ${RM} "$@.d" $(COMPILE.c) -O2 -Werror -DINI_ALLOW_BOM=0 -DINI_ALLOW_MULTILINE=0 -D_GNU_SOURCE -Ilib -std=c99 -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/src/http.o src/http.c +${OBJECTDIR}/src/log.o: nbproject/Makefile-${CND_CONF}.mk src/log.c + ${MKDIR} -p ${OBJECTDIR}/src + ${RM} "$@.d" + $(COMPILE.c) -O2 -Werror -DINI_ALLOW_BOM=0 -DINI_ALLOW_MULTILINE=0 -D_GNU_SOURCE -Ilib -std=c99 -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/src/log.o src/log.c + ${OBJECTDIR}/src/main.o: nbproject/Makefile-${CND_CONF}.mk src/main.c ${MKDIR} -p ${OBJECTDIR}/src ${RM} "$@.d" diff --git a/nbproject/configurations.xml b/nbproject/configurations.xml index 9d9f331..d6f3804 100644 --- a/nbproject/configurations.xml +++ b/nbproject/configurations.xml @@ -10,6 +10,7 @@ src/http.h lib/http_parser.h lib/ini.h + src/log.h src/main.h src/mime.h src/queue.h @@ -30,6 +31,7 @@ src/http.c lib/http_parser.c lib/ini.c + src/log.c src/main.c src/mime.c src/queue.c @@ -115,6 +117,10 @@ + + + + @@ -201,6 +207,10 @@ + + + + diff --git a/src/log.c b/src/log.c new file mode 100644 index 0000000..4680ef4 --- /dev/null +++ b/src/log.c @@ -0,0 +1,197 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ut/utlist.h" + +#include "log.h" + +#define XX(n, s, f) |L##n +const log_level LALL = 0 LOG_LEVEL_TABLE(XX); +#undef XX + +#define XX(n, s, f) [L##n]=s, +const char *log_level_name[] = { + LOG_LEVEL_TABLE(XX) +}; +#undef XX + +log* log_new(const char* name, FILE *output) { + log* l = calloc(1, sizeof(log)); + l->output = output; + l->name = calloc(strlen(name)+1, sizeof(char)); + strcpy(l->name, name); + l->running = false; + + return l; +} +void log_delete(log *l) { + free(l->name); + free(l); +} +bool log_start(log *l) { + if (l->running == true) { + return true; + } + int pfd[2]; + if (pipe(pfd) != 0) { + LOG(LERROR, "Failed to create log pipe"); + return false; + } + l->pRead = pfd[0]; + l->pWrite = pfd[1]; + + + if (pthread_create(&l->thread, NULL, log_loop, (void*)l) != 0) { + LOG(LERROR, "Failed to create log thread"); + close(l->pRead); + close(l->pWrite); + return false; + } + l->running = true; + + return true; + +} +void*log_loop(void* arg) { + log *l = (log*)arg; + void** buf = calloc(1, sizeof(void*)); + char* timestr = calloc(32, sizeof(char)); + time_t ctime; + struct tm *tinfo = calloc(1,sizeof(struct tm)); + while(true) { + if (read(l->pRead, buf, sizeof(void*)) <= 0) { + if (l->running == false) { + break; + } + fprintf(stderr, "log[%s] read failed: %s. logger aborted\n", l->name, strerror(errno)); + log_stop(l); + break; + } + ctime = time(NULL); + localtime_r(&ctime, tinfo); + if (strftime(timestr, 32, "%F %R", tinfo) == 0) { + strcpy(timestr, "N/A"); + } + log_msg* msg = (log_msg*)(*buf); + fprintf(l->output, "[%s][%s] %s\n", timestr, log_level_name[msg->level], msg->msg); + fflush(l->output); + log_msg_delete(msg); + } + free(buf); + free(timestr); +} +void log_stop(log *l) { + l->running = false; + close(l->pWrite); + if (pthread_equal(l->thread, pthread_self())!=0) { + pthread_detach(l->thread); + } else { + pthread_join(l->thread, NULL); + } + close(l->pRead); +} +void log_write(log *l, log_level level, const char* message) { + if (l == NULL) { + fprintf(stderr, "%s\n", message); + return; + } + if (l->running == false) { + return; + } + + char* msgstr = calloc(strlen(message)+1, sizeof(char)); + log_msg *msg = log_msg_new(level, msgstr); + write(l->pWrite, &msg, sizeof(log_msg*)); +} + +log_msg* log_msg_new(log_level level, char *msg) { + log_msg *m = calloc(1, sizeof(log_msg)); + m->level = level; + m->msg = msg; + return m; +} +void log_msg_delete(log_msg* msg) { + free(msg->msg); + free(msg); +} + +static log_register* _register; + +void log_register_add(log *l, bool def, log_level levels) { + if (l->running == false) { + log_start(l); + } + log_register *elem; + if (def == true) { + LL_FOREACH(_register, elem) { + elem->def = false; + } + } + log_register *lr = calloc(1, sizeof(log_register)); + lr->l = l; + lr->def = def; + lr->levels = levels; + LL_APPEND(_register, lr); +} +void log_register_remove(log *l) { + log_register *elem, *tmp; + LL_FOREACH_SAFE(_register, elem, tmp) { + if (elem->l == l) { + LL_DELETE(_register, elem); + free(elem); + break; + } + } +} +log* log_register_get(const char* name) { + log_register *def = NULL, *elem; + LL_FOREACH(_register, elem) { + if (name != NULL && strcasecmp(name, elem->l->name) == 0) { + return elem->l; + } + if (elem->def == true) { + def = elem; + if (name == NULL) { + break; + } + } + } + return (def!=NULL) ? def->l : NULL; +} +void log_register_clear() { + log_register *elem, *tmp; + LL_FOREACH_SAFE(_register, elem, tmp) { + LL_DELETE(_register, elem); + log_stop(elem->l); + log_delete(elem->l); + free(elem); + } +} +void log_register_write(log_level level, const char* fmt, ...) { + char msg[LOG_LENGTH]; + va_list va; + va_start(va, fmt); + vsnprintf(msg, LOG_LENGTH, fmt, va); + va_end(va); + + int count=0; + log_register *elem; + LL_FOREACH(_register, elem) { + if ((elem->levels & level) == level) { + log_write(elem->l, level, msg); + count++; + } + } + //Write to default log if not matched against any registered + if (count == 0) { + log_write(log_register_get(NULL), level, msg); + } +} \ No newline at end of file diff --git a/src/log.h b/src/log.h new file mode 100644 index 0000000..9db9008 --- /dev/null +++ b/src/log.h @@ -0,0 +1,82 @@ +/* + * File: log.h + * Author: sam + * + * Created on 06 August 2014, 12:06 + */ + +#ifndef LOG_H +#define LOG_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +#define LOG_LEVEL_TABLE(XX) \ + XX(DEBUG, "DEBUG", 1 << 0) \ + XX(INFO, "INFO", 1 << 1) \ + XX(WARNING, "WARNING", 1 << 2) \ + XX(ERROR, "ERROR", 1 << 3) \ + XX(FATAL, "FATAL", 1 << 4) + +#define XX(n, s, f) L##n=f, + typedef enum log_level { + LOG_LEVEL_TABLE(XX) + } log_level; +#undef XX + +#define LOG(level, fmt, ...) log_register_write(level, fmt, ##__VA_ARGS__) + +#define LOG_LENGTH 256 + + extern const log_level LALL; + + extern const char *log_level_name[]; + + typedef struct log { + char* name; + int pRead, pWrite; + FILE *output; + pthread_t thread; + bool running; + } log; + + typedef struct log_msg { + log_level level; + char* msg; + } log_msg; + + typedef struct log_register { + log *l; + bool def; + log_level levels; + struct log_register *next; + } log_register; + + log* log_new(const char* name, FILE *output); + void log_delete(log *l); + bool log_start(log *l); + void log_stop(log *l); + void*log_loop(void* arg); + void log_write(log *l, log_level level, const char* message); + + log_msg* log_msg_new(log_level level, char *msg); + void log_msg_delete(log_msg* msg); + + void log_register_add(log *l, bool def, log_level levels); + void log_register_remove(log *l); + log* log_register_get(const char* name); + void log_register_clear(); + void log_register_write(log_level level, const char* fmt, ...); + + +#ifdef __cplusplus +} +#endif + +#endif /* LOG_H */ + diff --git a/src/main.c b/src/main.c index 0c39882..3863ccd 100644 --- a/src/main.c +++ b/src/main.c @@ -30,6 +30,7 @@ #include "mime.h" #include "queue.h" #include "thread-pool.h" +#include "log.h" int serverfd = 0; volatile static bool stop = false; @@ -40,6 +41,9 @@ static void signal_int(int signum) { } int main(int argc, char** argv) { + log_register_add(log_new("stderr", stderr), true, LALL & ~(LINFO|LDEBUG)); + log_register_add(log_new("stdout", stdout), false, LDEBUG | LINFO); + mime_init(NULL); config_server *config = config_server_new(); @@ -158,6 +162,7 @@ int main(int argc, char** argv) { mime_destroy(); config_server_delete(config); svr_release(serverfd); + log_register_clear(); serverfd = 0; return (EXIT_SUCCESS); diff --git a/src/thread-pool.c b/src/thread-pool.c index 0a70d1b..be7ad39 100644 --- a/src/thread-pool.c +++ b/src/thread-pool.c @@ -172,7 +172,7 @@ void* thread_mgt(void* arg) { //Remove threads LL_FOREACH_SAFE(pool->threads, elem, tmp) { thread_stop(elem); - LL_DELETE(pool->threads, elem); + thread_pool_remove_thread(pool, elem); thread_delete(elem); } } \ No newline at end of file diff --git a/src/util.c b/src/util.c index 2f78117..a546337 100644 --- a/src/util.c +++ b/src/util.c @@ -9,39 +9,51 @@ #include #include #include +#include #include "util.h" +#include "log.h" void fatal(char* fmt, ...) { - char msg[128] = {0}; + char msg[LOG_LENGTH] = {0}; va_list va; va_start(va, fmt); - vsnprintf(msg, 128, fmt, va); + vsnprintf(msg, LOG_LENGTH, fmt, va); va_end(va); - fprintf(stderr, "\n"); - perror(msg); + LOG(LFATAL, msg); + log_register_clear(); exit(EXIT_FAILURE); } void warning(bool use_errno, char* fmt, ...) { - char msg[128] = {0}; + char msg[LOG_LENGTH] = {0}; va_list va; va_start(va, fmt); - vsnprintf(msg, 128, fmt, va); + vsnprintf(msg, LOG_LENGTH, fmt, va); va_end(va); if (use_errno == true) { - perror(msg); + char *errnostr = calloc(64, sizeof(char)); + strerror_r(errno, errnostr, 64); + char *errstr = calloc(strlen(msg)+strlen(errnostr)+3, sizeof(char)); + strcat(errstr, msg); + strcat(errstr, ": "); + strcat(errstr, errnostr); + LOG(LWARNING, errstr); + free(errnostr); + free(errstr); } else { - fprintf(stderr, "%s\n", msg); + LOG(LWARNING, msg); } } void info(char* fmt, ...) { + char msg[LOG_LENGTH] = {0}; va_list va; va_start(va, fmt); - vfprintf(stdout, fmt, va); - fputc('\n', stdout); + vsnprintf(msg, LOG_LENGTH, fmt, va); va_end(va); + + LOG(LINFO, msg); } char** str_splitlines(char *str, size_t *line_count) {