git » chasquid » commit db81008

Reopen logs on SIGHUP

author ThinkChaos
2020-05-20 23:53:26 UTC
committer Alberto Bertogli
2020-05-22 19:34:42 UTC
parent ade107f62e40f3c11940a47cb626907d9288707c

Reopen logs on SIGHUP

This makes it possible to manage chasquid logs using logrotate.

Amended-by: Alberto Bertogli <albertito@blitiri.com.ar>
  Added tests, minor style and comment changes.

chasquid.go +30 -0
internal/maillog/maillog.go +5 -0
test/t-13-reload/run.sh +32 -0

diff --git a/chasquid.go b/chasquid.go
index 5389a04..97e6cd5 100644
--- a/chasquid.go
+++ b/chasquid.go
@@ -14,8 +14,10 @@ import (
 	"math/rand"
 	"net"
 	"os"
+	"os/signal"
 	"path/filepath"
 	"strconv"
+	"syscall"
 	"time"
 
 	"blitiri.com.ar/go/chasquid/internal/config"
@@ -90,6 +92,8 @@ func main() {
 
 	initMailLog(conf.MailLogPath)
 
+	go signalHandler()
+
 	if conf.MonitoringAddress != "" {
 		launchMonitoringServer(conf.MonitoringAddress)
 	}
@@ -224,6 +228,32 @@ func initMailLog(path string) {
 	}
 }
 
+func signalHandler() {
+	var err error
+
+	signals := make(chan os.Signal, 1)
+	signal.Notify(signals, syscall.SIGHUP)
+
+	for {
+		switch sig := <-signals; sig {
+		case syscall.SIGHUP:
+			// SIGHUP triggers a reopen of the log files. This is used for log
+			// rotation.
+			err = log.Default.Reopen()
+			if err != nil {
+				log.Fatalf("Error reopening log: %v", err)
+			}
+
+			err = maillog.Default.Reopen()
+			if err != nil {
+				log.Fatalf("Error reopening maillog: %v", err)
+			}
+		default:
+			log.Errorf("Unexpected signal %v", sig)
+		}
+	}
+}
+
 // Helper to load a single domain configuration into the server.
 func loadDomain(name, dir string, s *smtpsrv.Server) {
 	log.Infof("  %s", name)
diff --git a/internal/maillog/maillog.go b/internal/maillog/maillog.go
index 674a488..d2954d4 100644
--- a/internal/maillog/maillog.go
+++ b/internal/maillog/maillog.go
@@ -81,6 +81,11 @@ func (l *Logger) printf(format string, args ...interface{}) {
 	}
 }
 
+// Reopen the underlying logger.
+func (l *Logger) Reopen() error {
+	return l.inner.Reopen()
+}
+
 // Listening logs that the daemon is listening on the given address.
 func (l *Logger) Listening(a string) {
 	l.printf("daemon listening on %s\n", a)
diff --git a/test/t-13-reload/run.sh b/test/t-13-reload/run.sh
index 203aaec..a3a0486 100755
--- a/test/t-13-reload/run.sh
+++ b/test/t-13-reload/run.sh
@@ -7,6 +7,10 @@ init
 
 generate_certs_for testserver
 
+#
+# Automatic reload.
+#
+
 # Start with the user with the wrong password, and no aliases.
 add_user someone@testserver password111
 rm -f config/domains/testserver/aliases
@@ -30,4 +34,32 @@ sleep 0.2
 run_msmtp analias@testserver < content
 wait_for_file .mail/someone@testserver
 
+
+#
+# Manual log rotation.
+#
+
+# Rotate logs.
+mv .logs/chasquid.log .logs/chasquid.log-old
+mv .logs/mail_log .logs/mail_log-old
+
+# Send SIGHUP and give it a little for the server to handle it.
+pkill -HUP -s 0 chasquid
+sleep 0.2
+
+# Send another mail.
+rm .mail/someone@testserver
+run_msmtp analias@testserver < content
+wait_for_file .mail/someone@testserver
+
+# Check there are new entries.
+sleep 0.2
+if ! grep -q "from=someone@testserver all done" .logs/mail_log; then
+	fail "new mail log did not have the expected entry"
+fi
+if ! grep -q -E "Queue.SendLoop .*: someone@testserver sent" .logs/chasquid.log;
+then
+	fail "new chasquid log did not have the expected entry"
+fi
+
 success