diff --git a/caddy/caddy.go b/caddy/caddy.go index 952480769..ae01593ec 100644 --- a/caddy/caddy.go +++ b/caddy/caddy.go @@ -23,7 +23,6 @@ import ( "errors" "fmt" "io/ioutil" - "log" "net" "os" "path" @@ -183,25 +182,25 @@ func startServers(groupings Group) error { for _, group := range groupings { s, err := server.New(group.BindAddr.String(), group.Configs) if err != nil { - log.Fatal(err) + return err } s.HTTP2 = HTTP2 // TODO: This setting is temporary var ln server.ListenerFile if IsRestart() { // Look up this server's listener in the map of inherited file descriptors; - // if we don't have one, we must make a new one. + // if we don't have one, we must make a new one (later). if fdIndex, ok := loadedGob.ListenerFds[s.Addr]; ok { file := os.NewFile(fdIndex, "") fln, err := net.FileListener(file) if err != nil { - log.Fatal(err) + return err } ln, ok = fln.(server.ListenerFile) if !ok { - log.Fatal("listener was not a ListenerFile") + return errors.New("listener for " + s.Addr + " was not a ListenerFile") } delete(loadedGob.ListenerFds, s.Addr) // mark it as used diff --git a/main.go b/main.go index 3aa99a4dd..e2e6b552d 100644 --- a/main.go +++ b/main.go @@ -20,6 +20,7 @@ var ( cpu string version bool revoke string + logfile string ) const ( @@ -43,14 +44,31 @@ func init() { flag.BoolVar(&letsencrypt.Agreed, "agree", false, "Agree to Let's Encrypt Subscriber Agreement") flag.StringVar(&letsencrypt.DefaultEmail, "email", "", "Default Let's Encrypt account email address") flag.StringVar(&revoke, "revoke", "", "Hostname for which to revoke the certificate") + flag.StringVar(&logfile, "log", "", "Process log file") } func main() { - flag.Parse() + flag.Parse() // called here in main() to allow other packages to set flags in their inits caddy.AppName = appName caddy.AppVersion = appVersion + // set up process log before anything bad happens + switch logfile { + case "stdout": + log.SetOutput(os.Stdout) + case "stderr": + log.SetOutput(os.Stderr) + case "": + log.SetOutput(ioutil.Discard) + default: + file, err := os.Create(logfile) + if err != nil { + log.Fatalf("Error opening log file: %v", err) + } + log.SetOutput(file) + } + if version { fmt.Printf("%s %s\n", caddy.AppName, caddy.AppVersion) os.Exit(0) @@ -67,13 +85,13 @@ func main() { // Set CPU cap err := setCPU(cpu) if err != nil { - log.Fatal(err) + mustLogFatal(err) } // Get Caddyfile input caddyfile, err := caddy.LoadCaddyfile(loadCaddyfile) if err != nil { - log.Fatal(err) + mustLogFatal(err) } // Start your engines @@ -82,7 +100,7 @@ func main() { if caddy.IsRestart() { log.Println("error starting servers:", err) } else { - log.Fatal(err) + mustLogFatal(err) } } @@ -90,6 +108,14 @@ func main() { caddy.Wait() } +// mustLogFatal just wraps log.Fatal() in a way that ensures the +// output is always printed to stderr so the user can see it, +// even if the process log was not enabled. +func mustLogFatal(args ...interface{}) { + log.SetOutput(os.Stderr) + log.Fatal(args...) +} + func loadCaddyfile() (caddy.Input, error) { // -conf flag if conf != "" {