Wed, 16 Nov 2022 12:14:45 +0100
redirect stdout/stderr to log file
--- a/src/server/daemon/log.c Sun Nov 13 12:58:25 2022 +0100 +++ b/src/server/daemon/log.c Wed Nov 16 12:14:45 2022 +0100 @@ -84,7 +84,7 @@ "Dec" }; -static char *log_levels[] = { +static const char *log_levels[] = { "warning", "config", "security", @@ -176,19 +176,21 @@ sbuf_put(ui_buffer, '\n'); } -void log_file_writeln(char *str, size_t len) { - if(!is_initialized) { - log_uninitialized_writeln(str, len); - return; - } - +void log_file_writeln(char *str, size_t len) { struct iovec io[] = { { str, len }, { "\n", 1} }; - writev(log_file_fd, io, 2); /* TODO: aio? */ - if(!main_is_daemon()) { + WSBool write_to_stdout = !main_is_daemon(); + if(is_initialized) { + writev(log_file_fd, io, 2); /* TODO: aio? */ + } else { + write_to_stdout = TRUE; + log_uninitialized_writeln(str, len); + } + + if(write_to_stdout) { writev(STDOUT_FILENO, io, 2); } @@ -208,7 +210,7 @@ } } -cxmutstr log_get_prefix(int level) { +cxmutstr log_get_prefix_str(const char *level) { time_t t = time(NULL); cxmutstr d; @@ -229,7 +231,7 @@ date.tm_hour, date.tm_min, date.tm_sec, - log_levels[level]); + level); if(len > 0) { d.ptr = buf; @@ -239,6 +241,10 @@ return d; } +cxmutstr log_get_prefix(int level) { + return log_get_prefix_str(log_levels[level]); +} + void log_add_logdup(LogDup *dup) { pthread_mutex_lock(&mutex); cxListAdd(log_dup_list, dup); @@ -323,6 +329,38 @@ return log_ereport(degree, format, args); } +int log_message(const char *degree, const char *format, ...) { + va_list args; + va_start(args, format); + int ret = log_message_v(degree, format, args); + va_end(args); + return ret; +} + +int log_message_v(const char *degree, const char *format, va_list args) { + cxmutstr lmsg; + lmsg.ptr = NULL; + + cxmutstr lpre = log_get_prefix_str(degree); + + /* format message */ + int len = vasprintf(&lmsg.ptr, format, args); + lmsg.length = len; + + /* create message string */ + cxmutstr message = cx_strcat(2, lpre, lmsg); + + /* write message to the log file */ + log_file_writeln(message.ptr, message.length); + + /* cleanup */ + free(lmsg.ptr); + free(lpre.ptr); + free(message.ptr); + + return 0; +} + void ws_log_assert(const char *file, const char *func, int line) { log_ereport(
--- a/src/server/daemon/log.h Sun Nov 13 12:58:25 2022 +0100 +++ b/src/server/daemon/log.h Wed Nov 16 12:14:45 2022 +0100 @@ -70,6 +70,7 @@ void log_file_writeln(char *str, size_t len); cxmutstr log_get_prefix(int level); +cxmutstr log_get_prefix_str(const char *level); void log_add_logdup(LogDup *dup); void log_remove_logdup(LogDup *dup);
--- a/src/server/daemon/main.c Sun Nov 13 12:58:25 2022 +0100 +++ b/src/server/daemon/main.c Wed Nov 16 12:14:45 2022 +0100 @@ -33,6 +33,8 @@ #include <signal.h> #include <errno.h> #include <pthread.h> +#include <fcntl.h> +#include <poll.h> #include "../util/pool.h" #include "../public/nsapi.h" @@ -49,7 +51,12 @@ #include "configmanager.h" -static int std_pipe_fds[2]; +#define LOG_THREAD_STACK_SIZE 32768 +#define LOG_THREAD_MAX_POLL_FAILS 10 +#define LOG_THREAD_READ_BUF 2048 + +static int std_out[2]; +static int std_err[2]; static WSBool is_daemon; void test() { @@ -93,25 +100,97 @@ //exit(EXIT_SUCCESS); } -void* log_pipe_thread(void *data) { - //FILE *log_out = fopen("log.txt", "a"); +static void set_pipe_nonblocking(int fd) { + int flags = 0; + flags = fcntl(fd, F_GETFL, 0); + fcntl(fd, F_SETFL, flags & ~O_NONBLOCK); +} + +static char log_pipe_readbuf[LOG_THREAD_READ_BUF]; +static char log_pipe_stdout_buf[LOG_THREAD_READ_BUF]; +static char log_pipe_stderr_buf[LOG_THREAD_READ_BUF]; +static size_t log_pipe_stdout_tmp_pos = 0; +static size_t log_pipe_stderr_tmp_pos = 0; - char buf[1024]; - ssize_t r; - while((r = read(std_pipe_fds[0], buf, 1024)) > 0) { - //fwrite(buf, 1, r, log_out); - //fflush(log_out); +static int log_pipe(const char *name, int fd, char *buf, size_t *pos) { + ssize_t r = read(fd, log_pipe_readbuf, 2); + if(r <= 0) { + return 1; + } + + char *tmp = buf; + int tmplen = *pos; + + int s = 0; + for(int i=0;i<r;i++) { + if(log_pipe_readbuf[i] == '\n') { + if(tmplen + i-s > 0) { + log_message(name, "%.*s%.*s", tmplen, tmp, i-s, log_pipe_readbuf + s); + } + tmplen = 0; + *pos = 0; + s = i+1; + } + } + + int remaining = r - s; + if(tmplen + remaining >= LOG_THREAD_READ_BUF) { + log_message(name, "%.*s%.*s", tmplen, tmp, remaining, log_pipe_readbuf + s); + *pos = 0; + } else if(remaining > 0) { + memcpy(buf + *pos, log_pipe_readbuf + s, remaining); + *pos += remaining; } + + return 0; +} - //fclose(log_out); +void* log_pipe_thread(void *data) { + set_pipe_nonblocking(std_out[0]); + set_pipe_nonblocking(std_err[0]); + + struct pollfd fds[2]; + fds[0].fd = std_out[0]; + fds[0].events = POLLIN; + fds[1].fd = std_err[0]; + fds[1].events = POLLIN; + int poll_fails = 0; + for(;;) { + if(poll(fds, 1, 1000000) < 0) { + if(errno == EINTR) { + continue; + } + log_ereport(LOG_FAILURE, "log thread poll failed: %s", strerror(errno)); + if(poll_fails++ > LOG_THREAD_MAX_POLL_FAILS) { + break; + } + } + + // check stdout + if(fds[0].revents & POLLIN) { + if(log_pipe("stdout", fds[0].fd, log_pipe_stdout_buf, &log_pipe_stdout_tmp_pos)) { + break; + } + } + + // check stderr + if(fds[1].revents & POLLIN) { + if(log_pipe("stderr", fds[0].fd, log_pipe_stderr_buf, &log_pipe_stderr_tmp_pos)) { + break; + } + } + } + + log_ereport(LOG_INFORM, "log thread end"); + return NULL; } int main(int argc, char **argv) { //test(); - /* if the -c parameter is specified, we don't create a daemon */ + // if the -c parameter is specified, we don't create a daemon is_daemon = 1; for(int i=0;i<argc;i++) { char *p = argv[i]; @@ -121,7 +200,7 @@ } } if(is_daemon) { - /* create daemon */ + // create daemon pid_t pid = fork(); if(pid < 0) { return EXIT_FAILURE; @@ -139,25 +218,33 @@ close(i); } - /* stdio redirection */ - /* create pipes */ - if(pipe(std_pipe_fds) != 0) { + // stdio redirection + // create pipes + if(pipe(std_out) != 0) { + perror("pipe"); + return EXIT_FAILURE; + } + if(pipe(std_err) != 0) { perror("pipe"); return EXIT_FAILURE; } - //FILE *ws_out = fdopen(std_pipe_fds[1], "w"); - //*stdout = *ws_out; - //*stderr = *ws_out; - //dup2(std_pipe_fds[1], 1); - //dup2(std_pipe_fds[1], 2); + + dup2(std_out[1], 1); + dup2(std_err[1], 2); + close(std_err[1]); + + // set log thread stack size + pthread_attr_t tattr; + pthread_attr_init(&tattr); + pthread_attr_setstacksize(&tattr, LOG_THREAD_STACK_SIZE); pthread_t tid; - pthread_create(&tid, NULL, log_pipe_thread, NULL); + pthread_create(&tid, &tattr, log_pipe_thread, NULL); } pool_init(NULL, NULL, NULL); - - /* add signal handler */ + + // add signal handler signal(SIGUSR1, sig_usr1_reload); signal(SIGTERM, sig_term); signal(SIGINT, sig_term); @@ -167,7 +254,7 @@ act.sa_handler = SIG_IGN; sigaction(SIGPIPE, &act, NULL); - /* start webserver */ + // start webserver log_ereport(LOG_INFORM, "startup"); int status;
--- a/src/server/public/nsapi.h Sun Nov 13 12:58:25 2022 +0100 +++ b/src/server/public/nsapi.h Wed Nov 16 12:14:45 2022 +0100 @@ -1610,6 +1610,8 @@ const char *format, ...); int log_error_v(int degree, const char *func, Session *sn, Request *rq, const char *format, va_list args); +int log_message(const char *degree, const char *format, ...); +int log_message_v(const char *degree, const char *format, va_list args); /* new macro and function definitions begin */