summary refs log tree commit diff
diff options
context:
space:
mode:
authorLeah Neukirchen <leah@vuxu.org>2022-01-07 17:46:46 +0100
committerLeah Neukirchen <leah@vuxu.org>2022-01-07 17:46:46 +0100
commitf7311a2127f49a1530e34184425ea5801734dd6b (patch)
treed0e674ee19f5860e46a9d155829dd50cf127b1fe
parent258eda0337e0e4d5502657e96f8e793627f68457 (diff)
downloadrvnit-f7311a2127f49a1530e34184425ea5801734dd6b.tar.gz
rvnit-f7311a2127f49a1530e34184425ea5801734dd6b.tar.xz
rvnit-f7311a2127f49a1530e34184425ea5801734dd6b.zip
add global logging support (G)
-rw-r--r--rvnit.c64
1 files changed, 60 insertions, 4 deletions
diff --git a/rvnit.c b/rvnit.c
index 6e8de20..77cd4bd 100644
--- a/rvnit.c
+++ b/rvnit.c
@@ -54,6 +54,9 @@ pthread_t logger_thread;
 
 int selflogfd[2];
 int newlogfd[2];
+int globallogfd[2];
+
+int use_global_log;
 
 sig_atomic_t want_shutdown;
 sig_atomic_t want_rescan;
@@ -119,6 +122,11 @@ restart(int i)
 		}
 	}
 
+	if (services[i].name[2] == 'G') {
+		// enable global logger
+		use_global_log = 1;
+	}
+
 	pid_t child = fork();
 	if (child == 0) {
 		dup2(services[i].logfd[1], 1);
@@ -127,6 +135,13 @@ restart(int i)
 			close(loggerpipe[0]);
 			close(loggerpipe[1]);
 		}
+		if (services[i].name[2] == 'G') {
+			// global loggers get read end of global log pipe
+			dup2(globallogfd[0], 0);
+
+			// global loggers write to stderr, to avoid lopos
+			dup2(2, 1);
+		}
 
 		close(services[i].logfd[0]);
 		close(services[i].logfd[1]);
@@ -245,6 +260,7 @@ socket_loop(void* ignored)
 			pthread_mutex_lock(&services_lock);
 			for (int i = 0; i < MAX_SV; i++) {
 				if (services[i].name[2] == 'D' ||
+				    services[i].name[2] == 'G' ||
 				    services[i].name[2] == 'L')
 					dprintf(connfd, "%-25s pid=%d state=%s uptime=%ld status=%d\n",
 					    services[i].name,
@@ -387,10 +403,12 @@ logger_loop(void* ignored)
 
 			const char *sv = "<unknown>";
 			long pid = -1;
+			int pass_thru = 0;
 
 			if (fds[j].fd == selflogfd[0]) {
 				sv = "rvnit";
 				pid = getpid();
+				pass_thru = (level != 100);
 			} else {
 				pthread_mutex_lock(&services_lock);
 				for (int i = 0; i < MAX_SV; i++) {
@@ -410,9 +428,23 @@ logger_loop(void* ignored)
 				if (!eol)
 					eol = e;
 
-				printf("%s.%05ld %s[%ld]: %.*s\n",
-				    timestamp, now.tv_nsec / 10000,
-				    sv, pid, (int)(eol - s), s);
+				int r = 0;
+				if (use_global_log) {
+					r = dprintf(globallogfd[1],
+					    "%s.%05ld %s[%ld]: %.*s\n",
+					    timestamp, now.tv_nsec / 10000,
+					    sv, pid, (int)(eol - s), s);
+				}
+				if (!use_global_log || pass_thru || r < 0) {
+					/* print own messages, and messages
+					   during boot/shutdown, or when writing
+					   to logger failed (potentially because
+					   the pipe is full, we don't want to
+					   stall here) */
+					dprintf(2, "%s.%05ld %s[%ld]: %.*s\n",
+					    timestamp, now.tv_nsec / 10000,
+					    sv, pid, (int)(eol - s), s);
+				}
 
 				s = eol + 1;
 			}
@@ -595,6 +627,12 @@ main(int argc, char *argv[])
 	fcntl(newlogfd[0], F_SETFD, FD_CLOEXEC);
 	fcntl(newlogfd[1], F_SETFD, FD_CLOEXEC);
 
+	pipe(globallogfd);
+	// don't care about read end
+	fcntl(globallogfd[1], F_SETFL, O_NONBLOCK);
+	fcntl(globallogfd[0], F_SETFD, FD_CLOEXEC);
+	fcntl(globallogfd[1], F_SETFD, FD_CLOEXEC);
+
 	if (pthread_mutex_init(&services_lock, 0) != 0) {
 		perror("pthread_mutex_init");
 		return 111;
@@ -635,7 +673,7 @@ main(int argc, char *argv[])
 				restart(i);
 		}
 
-		// spawn oneshots and daemons
+		// spawn oneshots, daemons, global logger
 		for (i = 0; i < MAX_SV; i++) {
 			if (services[i].level != level)
 				continue;
@@ -648,6 +686,8 @@ main(int argc, char *argv[])
 				oneshot++;
 			} else if (services[i].name[2] == 'D') {
 				restart(i);
+			} else if (services[i].name[2] == 'G') {
+				restart(i);
 			}
 		}
 
@@ -688,6 +728,7 @@ main(int argc, char *argv[])
 
 				oneshot--;
 			} else if (services[i].name[2] == 'D' ||
+			    services[i].name[2] == 'G' ||
 			    services[i].name[2] == 'L') {
 				restart(i);
 			}
@@ -740,6 +781,18 @@ cont1:
 						kill(services[i].pid, SIGTERM);
 				}
 			}
+			for (i = 0; i < MAX_SV; i++) {
+				if (services[i].name[2] == 'G') {
+					if (services[i].state == UP &&
+					    services[i].pid == 0)
+						restart(i);
+					if (services[i].state == DOWN &&
+					    services[i].pid > 0) {
+						kill(services[i].pid, SIGTERM);
+						use_global_log = 0;
+					}
+				}
+			}
 			pthread_mutex_unlock(&services_lock);
 
 			want_rescan = 0;
@@ -763,6 +816,7 @@ cont1:
 			goto cont2;
 
 		if (services[i].name[2] == 'D' ||
+		    services[i].name[2] == 'G' ||
 		    services[i].name[2] == 'L') {
 			LOG("%s terminated with status %d", services[i].name, services[i].status);
 			if (services[i].state == UP) {
@@ -917,6 +971,8 @@ cont4:
 	else
 		dprintf(selflogfd[1], "shutdown\n");
 
+	close(globallogfd[1]);
+
 	close(selflogfd[1]);
 	pthread_join(logger_thread, 0);
 }