From f6f1e0cb65ead5a47e3e88d1edb4d83cd6d713ce Mon Sep 17 00:00:00 2001 From: Gyuho Lee Date: Tue, 17 Apr 2018 11:27:08 -0700 Subject: [PATCH] embed: support multiple log outputs for structured logging Zap support multi-writer by default. Signed-off-by: Gyuho Lee --- embed/config.go | 80 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 53 insertions(+), 27 deletions(-) diff --git a/embed/config.go b/embed/config.go index 55e6a746e..6cb26820d 100644 --- a/embed/config.go +++ b/embed/config.go @@ -23,6 +23,7 @@ import ( "net/url" "os" "path/filepath" + "sort" "strings" "sync" "syscall" @@ -394,7 +395,17 @@ func (cfg *Config) setupLogging() error { } case "zap": - // TODO: make this more configurable + if cfg.LogOutput == "" { + cfg.LogOutput = DefaultLogOutput + } + outputs := strings.Split(cfg.LogOutput, ",") + for _, v := range outputs { + if v == DefaultLogOutput { + panic(fmt.Errorf("multi logoutput for %q is not supported yet", DefaultLogOutput)) + } + } + + // TODO: use zapcore to support more features? lcfg := zap.Config{ Level: zap.NewAtomicLevelAt(zap.InfoLevel), Development: false, @@ -404,35 +415,50 @@ func (cfg *Config) setupLogging() error { }, Encoding: "json", EncoderConfig: zap.NewProductionEncoderConfig(), + + OutputPaths: make([]string, 0), + ErrorOutputPaths: make([]string, 0), } - switch cfg.LogOutput { - case DefaultLogOutput: - if syscall.Getppid() == 1 { - // capnslog initially SetFormatter(NewDefaultFormatter(os.Stderr)) - // where "NewDefaultFormatter" returns "NewJournaldFormatter" - // when syscall.Getppid() == 1, specify 'stdout' or 'stderr' to - // skip journald logging even when running under systemd - fmt.Println("running under init, which may be systemd!") - // TODO: capnlog.NewJournaldFormatter() - lcfg.OutputPaths = []string{"stderr"} - lcfg.ErrorOutputPaths = []string{"stderr"} - } else { - lcfg.OutputPaths = []string{"stderr"} - lcfg.ErrorOutputPaths = []string{"stderr"} + outputPaths, errOutputPaths := make(map[string]struct{}), make(map[string]struct{}) + for _, v := range outputs { + switch v { + case DefaultLogOutput: + if syscall.Getppid() == 1 { + // capnslog initially SetFormatter(NewDefaultFormatter(os.Stderr)) + // where "NewDefaultFormatter" returns "NewJournaldFormatter" + // when syscall.Getppid() == 1, specify 'stdout' or 'stderr' to + // skip journald logging even when running under systemd + // TODO: capnlog.NewJournaldFormatter() + fmt.Println("running under init, which may be systemd!") + outputPaths["stderr"] = struct{}{} + errOutputPaths["stderr"] = struct{}{} + continue + } + + outputPaths["stderr"] = struct{}{} + errOutputPaths["stderr"] = struct{}{} + + case "stderr": + outputPaths["stderr"] = struct{}{} + errOutputPaths["stderr"] = struct{}{} + + case "stdout": + outputPaths["stdout"] = struct{}{} + errOutputPaths["stdout"] = struct{}{} + + default: + outputPaths[v] = struct{}{} + errOutputPaths[v] = struct{}{} } - - case "stderr": - lcfg.OutputPaths = []string{"stderr"} - lcfg.ErrorOutputPaths = []string{"stderr"} - - case "stdout": - lcfg.OutputPaths = []string{"stdout"} - lcfg.ErrorOutputPaths = []string{"stdout"} - - default: - lcfg.OutputPaths = []string{cfg.LogOutput} - lcfg.ErrorOutputPaths = []string{cfg.LogOutput} } + for v := range outputPaths { + lcfg.OutputPaths = append(lcfg.OutputPaths, v) + } + for v := range errOutputPaths { + lcfg.ErrorOutputPaths = append(lcfg.ErrorOutputPaths, v) + } + sort.Strings(lcfg.OutputPaths) + sort.Strings(lcfg.ErrorOutputPaths) if cfg.Debug { lcfg.Level = zap.NewAtomicLevelAt(zap.DebugLevel)