diff --git a/config.go b/config.go index 4fbe96e..f29a258 100644 --- a/config.go +++ b/config.go @@ -4,6 +4,7 @@ import ( "errors" "fmt" "os" + "path/filepath" "github.com/foxcpp/maddy/config" "github.com/foxcpp/maddy/log" @@ -34,7 +35,7 @@ func logOutput(m *config.Map, node *config.Node) (interface{}, error) { func LogOutputOption(args []string) (log.Output, error) { outs := make([]log.Output, 0, len(args)) - for _, arg := range args { + for i, arg := range args { switch arg { case "stderr": outs = append(outs, log.WriterOutput(os.Stderr, false)) @@ -52,7 +53,18 @@ func LogOutputOption(args []string) (log.Output, error) { } return nil, nil default: - w, err := os.OpenFile(arg, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0666) + // Log file paths are converted to absolute to make sure + // we will be able to recreate them in right location + // after changing working directory to the state dir. + absPath, err := filepath.Abs(arg) + if err != nil { + return nil, err + } + // We change the actual argument, so logOut object will + // keep the absolute path for reinitialization. + args[i] = absPath + + w, err := os.OpenFile(absPath, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0666) if err != nil { return nil, fmt.Errorf("failed to create log file: %v", err) } @@ -70,3 +82,19 @@ func LogOutputOption(args []string) (log.Output, error) { func defaultLogOutput() (interface{}, error) { return log.DefaultLogger.Out, nil } + +func reinitLogging() { + out, ok := log.DefaultLogger.Out.(logOut) + if !ok { + log.Println("Can't reinitialize logger because it was replaced before, this is a bug") + return + } + + newOut, err := LogOutputOption(out.args) + if err != nil { + log.Println("Can't reinitialize logger:", err) + return + } + + log.DefaultLogger.Out = newOut +} diff --git a/maddy.go b/maddy.go index 19ddead..c022232 100644 --- a/maddy.go +++ b/maddy.go @@ -100,10 +100,21 @@ func Start(cfg []config.Node) error { } sig := make(chan os.Signal, 5) - signal.Notify(sig, os.Interrupt, syscall.SIGTERM, syscall.SIGHUP, syscall.SIGINT) + signal.Notify(sig, os.Interrupt, syscall.SIGTERM, syscall.SIGHUP, syscall.SIGINT, syscall.SIGUSR1) + + for { + switch s := <-sig; s { + case syscall.SIGUSR1: + log.Println("SIGUSR1 received, reinitializing logging") + reinitLogging() + default: + log.Printf("signal received (%v), next signal will force immediate shutdown.", s) + // break inside switch exits switch, not outer loop + goto exitsigloop + } + } +exitsigloop: - s := <-sig - log.Printf("signal received (%v), next signal will force immediate shutdown.", s) go func() { s := <-sig log.Printf("forced shutdown due to signal (%v)!", s)