redirect stdout/stderr to log file

Wed, 16 Nov 2022 12:14:45 +0100

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Wed, 16 Nov 2022 12:14:45 +0100
changeset 434
ff576305ae6e
parent 433
39fe86ae4db0
child 435
713ec3da79ec

redirect stdout/stderr to log file

src/server/daemon/log.c file | annotate | diff | comparison | revisions
src/server/daemon/log.h file | annotate | diff | comparison | revisions
src/server/daemon/main.c file | annotate | diff | comparison | revisions
src/server/public/nsapi.h file | annotate | diff | comparison | revisions
--- 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 */
 

mercurial