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) {