1// Copyright 2019 The etcd Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package logutil
16
17import (
18	"sort"
19
20	"go.uber.org/zap"
21	"go.uber.org/zap/zapcore"
22)
23
24// DefaultZapLoggerConfig defines default zap logger configuration.
25var DefaultZapLoggerConfig = zap.Config{
26	Level: zap.NewAtomicLevelAt(ConvertToZapLevel(DefaultLogLevel)),
27
28	Development: false,
29	Sampling: &zap.SamplingConfig{
30		Initial:    100,
31		Thereafter: 100,
32	},
33
34	Encoding: "json",
35
36	// copied from "zap.NewProductionEncoderConfig" with some updates
37	EncoderConfig: zapcore.EncoderConfig{
38		TimeKey:        "ts",
39		LevelKey:       "level",
40		NameKey:        "logger",
41		CallerKey:      "caller",
42		MessageKey:     "msg",
43		StacktraceKey:  "stacktrace",
44		LineEnding:     zapcore.DefaultLineEnding,
45		EncodeLevel:    zapcore.LowercaseLevelEncoder,
46		EncodeTime:     zapcore.ISO8601TimeEncoder,
47		EncodeDuration: zapcore.StringDurationEncoder,
48		EncodeCaller:   zapcore.ShortCallerEncoder,
49	},
50
51	// Use "/dev/null" to discard all
52	OutputPaths:      []string{"stderr"},
53	ErrorOutputPaths: []string{"stderr"},
54}
55
56// MergeOutputPaths merges logging output paths, resolving conflicts.
57func MergeOutputPaths(cfg zap.Config) zap.Config {
58	outputs := make(map[string]struct{})
59	for _, v := range cfg.OutputPaths {
60		outputs[v] = struct{}{}
61	}
62	outputSlice := make([]string, 0)
63	if _, ok := outputs["/dev/null"]; ok {
64		// "/dev/null" to discard all
65		outputSlice = []string{"/dev/null"}
66	} else {
67		for k := range outputs {
68			outputSlice = append(outputSlice, k)
69		}
70	}
71	cfg.OutputPaths = outputSlice
72	sort.Strings(cfg.OutputPaths)
73
74	errOutputs := make(map[string]struct{})
75	for _, v := range cfg.ErrorOutputPaths {
76		errOutputs[v] = struct{}{}
77	}
78	errOutputSlice := make([]string, 0)
79	if _, ok := errOutputs["/dev/null"]; ok {
80		// "/dev/null" to discard all
81		errOutputSlice = []string{"/dev/null"}
82	} else {
83		for k := range errOutputs {
84			errOutputSlice = append(errOutputSlice, k)
85		}
86	}
87	cfg.ErrorOutputPaths = errOutputSlice
88	sort.Strings(cfg.ErrorOutputPaths)
89
90	return cfg
91}
92