Browse Source

embed: support multiple log outputs for structured logging

Zap support multi-writer by default.

Signed-off-by: Gyuho Lee <gyuhox@gmail.com>
Gyuho Lee 7 years ago
parent
commit
f6f1e0cb65
1 changed files with 52 additions and 26 deletions
  1. 52 26
      embed/config.go

+ 52 - 26
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(),
-		}
-		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"}
-			}
 
-		case "stderr":
-			lcfg.OutputPaths = []string{"stderr"}
-			lcfg.ErrorOutputPaths = []string{"stderr"}
+			OutputPaths:      make([]string, 0),
+			ErrorOutputPaths: make([]string, 0),
+		}
+		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
+				}
 
-		case "stdout":
-			lcfg.OutputPaths = []string{"stdout"}
-			lcfg.ErrorOutputPaths = []string{"stdout"}
+				outputPaths["stderr"] = struct{}{}
+				errOutputPaths["stderr"] = struct{}{}
 
-		default:
-			lcfg.OutputPaths = []string{cfg.LogOutput}
-			lcfg.ErrorOutputPaths = []string{cfg.LogOutput}
+			case "stderr":
+				outputPaths["stderr"] = struct{}{}
+				errOutputPaths["stderr"] = struct{}{}
+
+			case "stdout":
+				outputPaths["stdout"] = struct{}{}
+				errOutputPaths["stdout"] = struct{}{}
+
+			default:
+				outputPaths[v] = struct{}{}
+				errOutputPaths[v] = struct{}{}
+			}
+		}
+		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)