Skip to content

Commit b9af791

Browse files
authored
Merge pull request #915 from bharathi-tenneti/zaplogger
✨ Added Encoder Config Options field.
2 parents af7f192 + c6b1f07 commit b9af791

File tree

5 files changed

+131
-29
lines changed

5 files changed

+131
-29
lines changed

go.mod

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ require (
1515
github.com/onsi/gomega v1.10.1
1616
github.com/prometheus/client_golang v1.7.1
1717
github.com/prometheus/client_model v0.2.0
18-
github.com/spf13/pflag v1.0.5
1918
go.uber.org/zap v1.15.0
2019
golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e
2120
gomodules.xyz/jsonpatch/v2 v2.1.0

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbt
3535
github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
3636
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
3737
github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM=
38+
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc h1:cAKDfWh5VpdgMhJosfJnn5/FoN2SRZ4p7fJNX58YPaU=
3839
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
3940
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
4041
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
@@ -233,6 +234,7 @@ github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7V
233234
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
234235
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
235236
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
237+
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
236238
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
237239
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
238240
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=

pkg/log/zap/flags.go

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,11 @@ limitations under the License.
1919
package zap
2020

2121
import (
22+
"flag"
2223
"fmt"
2324
"strconv"
2425
"strings"
2526

26-
"github.com/spf13/pflag"
2727
"go.uber.org/zap"
2828
"go.uber.org/zap/zapcore"
2929
)
@@ -42,11 +42,11 @@ var stackLevelStrings = map[string]zapcore.Level{
4242
}
4343

4444
type encoderFlag struct {
45-
setFunc func(zapcore.Encoder)
45+
setFunc func(NewEncoderFunc)
4646
value string
4747
}
4848

49-
var _ pflag.Value = &encoderFlag{}
49+
var _ flag.Value = &encoderFlag{}
5050

5151
func (ev *encoderFlag) String() string {
5252
return ev.value
@@ -60,32 +60,22 @@ func (ev *encoderFlag) Set(flagValue string) error {
6060
val := strings.ToLower(flagValue)
6161
switch val {
6262
case "json":
63-
ev.setFunc(newJSONEncoder())
63+
ev.setFunc(newJSONEncoder)
6464
case "console":
65-
ev.setFunc(newConsoleEncoder())
65+
ev.setFunc(newConsoleEncoder)
6666
default:
6767
return fmt.Errorf("invalid encoder value \"%s\"", flagValue)
6868
}
6969
ev.value = flagValue
7070
return nil
7171
}
7272

73-
func newJSONEncoder() zapcore.Encoder {
74-
encoderConfig := zap.NewProductionEncoderConfig()
75-
return zapcore.NewJSONEncoder(encoderConfig)
76-
}
77-
78-
func newConsoleEncoder() zapcore.Encoder {
79-
encoderConfig := zap.NewDevelopmentEncoderConfig()
80-
return zapcore.NewConsoleEncoder(encoderConfig)
81-
}
82-
8373
type levelFlag struct {
8474
setFunc func(zapcore.LevelEnabler)
8575
value string
8676
}
8777

88-
var _ pflag.Value = &levelFlag{}
78+
var _ flag.Value = &levelFlag{}
8979

9080
func (ev *levelFlag) Set(flagValue string) error {
9181
level, validLevel := levelStrings[strings.ToLower(flagValue)]
@@ -120,7 +110,7 @@ type stackTraceFlag struct {
120110
value string
121111
}
122112

123-
var _ pflag.Value = &stackTraceFlag{}
113+
var _ flag.Value = &stackTraceFlag{}
124114

125115
func (ev *stackTraceFlag) Set(flagValue string) error {
126116
level, validLevel := stackLevelStrings[strings.ToLower(flagValue)]

pkg/log/zap/zap.go

Lines changed: 42 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,12 @@ import (
3030
"go.uber.org/zap/zapcore"
3131
)
3232

33+
// EncoderConfigOption is a function that can modify a `zapcore.EncoderConfig`.
34+
type EncoderConfigOption func(*zapcore.EncoderConfig)
35+
36+
// NewEncoderFunc is a function that creates an Encoder using the provided EncoderConfigOptions.
37+
type NewEncoderFunc func(...EncoderConfigOption) zapcore.Encoder
38+
3339
// New returns a brand new Logger configured with Opts. It
3440
// uses KubeAwareEncoder which adds Type information and
3541
// Namespace/Name to the log.
@@ -65,6 +71,22 @@ func Encoder(encoder zapcore.Encoder) func(o *Options) {
6571
}
6672
}
6773

74+
func newJSONEncoder(opts ...EncoderConfigOption) zapcore.Encoder {
75+
encoderConfig := zap.NewProductionEncoderConfig()
76+
for _, opt := range opts {
77+
opt(&encoderConfig)
78+
}
79+
return zapcore.NewJSONEncoder(encoderConfig)
80+
}
81+
82+
func newConsoleEncoder(opts ...EncoderConfigOption) zapcore.Encoder {
83+
encoderConfig := zap.NewDevelopmentEncoderConfig()
84+
for _, opt := range opts {
85+
opt(&encoderConfig)
86+
}
87+
return zapcore.NewConsoleEncoder(encoderConfig)
88+
}
89+
6890
// Level sets the the minimum enabled logging level e.g Debug, Info
6991
// See Options.Level
7092
func Level(level zapcore.LevelEnabler) func(o *Options) {
@@ -99,6 +121,14 @@ type Options struct {
99121
// Encoder configures how Zap will encode the output. Defaults to
100122
// console when Development is true and JSON otherwise
101123
Encoder zapcore.Encoder
124+
// EncoderConfigOptions can modify the EncoderConfig needed to initialize an Encoder.
125+
// See https://godoc.org/go.uber.org/zap/zapcore#EncoderConfig for the list of options
126+
// that can be configured.
127+
// Note that the EncoderConfigOptions are not applied when the Encoder option is already set.
128+
EncoderConfigOptions []EncoderConfigOption
129+
// NewEncoder configures Encoder using the provided EncoderConfigOptions.
130+
// Note that the NewEncoder function is not used when the Encoder option is already set.
131+
NewEncoder NewEncoderFunc
102132
// DestWritter controls the destination of the log output. Defaults to
103133
// os.Stderr.
104134
DestWritter io.Writer
@@ -121,9 +151,8 @@ func (o *Options) addDefaults() {
121151
}
122152

123153
if o.Development {
124-
if o.Encoder == nil {
125-
encCfg := zap.NewDevelopmentEncoderConfig()
126-
o.Encoder = zapcore.NewConsoleEncoder(encCfg)
154+
if o.NewEncoder == nil {
155+
o.NewEncoder = newConsoleEncoder
127156
}
128157
if o.Level == nil {
129158
lvl := zap.NewAtomicLevelAt(zap.DebugLevel)
@@ -136,9 +165,8 @@ func (o *Options) addDefaults() {
136165
o.ZapOpts = append(o.ZapOpts, zap.Development())
137166

138167
} else {
139-
if o.Encoder == nil {
140-
encCfg := zap.NewProductionEncoderConfig()
141-
o.Encoder = zapcore.NewJSONEncoder(encCfg)
168+
if o.NewEncoder == nil {
169+
o.NewEncoder = newJSONEncoder
142170
}
143171
if o.Level == nil {
144172
lvl := zap.NewAtomicLevelAt(zap.InfoLevel)
@@ -157,6 +185,9 @@ func (o *Options) addDefaults() {
157185
}))
158186
}
159187
}
188+
if o.Encoder == nil {
189+
o.Encoder = o.NewEncoder(o.EncoderConfigOptions...)
190+
}
160191
o.ZapOpts = append(o.ZapOpts, zap.AddStacktrace(o.StacktraceLevel))
161192
}
162193

@@ -182,7 +213,7 @@ func NewRaw(opts ...Opts) *zap.Logger {
182213
// BindFlags will parse the given flagset for zap option flags and set the log options accordingly
183214
// zap-devel: Development Mode defaults(encoder=consoleEncoder,logLevel=Debug,stackTraceLevel=Warn)
184215
// Production Mode defaults(encoder=jsonEncoder,logLevel=Info,stackTraceLevel=Error)
185-
// zap-encoder: Zap log encoding ('json' or 'console')
216+
// zap-encoder: Zap log encoding (one of 'json' or 'console')
186217
// zap-log-level: Zap Level to configure the verbosity of logging. Can be one of 'debug', 'info', 'error',
187218
// or any integer value > 0 which corresponds to custom debug levels of increasing verbosity")
188219
// zap-stacktrace-level: Zap Level at and above which stacktraces are captured (one of 'info' or 'error')
@@ -195,10 +226,10 @@ func (o *Options) BindFlags(fs *flag.FlagSet) {
195226

196227
// Set Encoder value
197228
var encVal encoderFlag
198-
encVal.setFunc = func(fromFlag zapcore.Encoder) {
199-
o.Encoder = fromFlag
229+
encVal.setFunc = func(fromFlag NewEncoderFunc) {
230+
o.NewEncoder = fromFlag
200231
}
201-
fs.Var(&encVal, "zap-encoder", "Zap log encoding ('json' or 'console')")
232+
fs.Var(&encVal, "zap-encoder", "Zap log encoding (one of 'json' or 'console')")
202233

203234
// Set the Log Level
204235
var levelVal levelFlag
@@ -221,10 +252,10 @@ func (o *Options) BindFlags(fs *flag.FlagSet) {
221252
// UseFlagOptions configures the logger to use the Options set by parsing zap option flags from the CLI.
222253
// opts := zap.Options{}
223254
// opts.BindFlags(flag.CommandLine)
255+
// flag.Parse()
224256
// log := zap.New(zap.UseFlagOptions(&opts))
225257
func UseFlagOptions(in *Options) Opts {
226258
return func(o *Options) {
227259
*o = *in
228-
o.addDefaults()
229260
}
230261
}

pkg/log/zap/zap_test.go

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -425,4 +425,84 @@ var _ = Describe("Zap log level flag options setup", func() {
425425

426426
})
427427

428+
Context("with only -zap-devel flag provided", func() {
429+
It("Should set dev=true.", func() {
430+
args := []string{"--zap-devel=true"}
431+
fromFlags.BindFlags(&fs)
432+
if err := fs.Parse(args); err != nil {
433+
Expect(err).ToNot(HaveOccurred())
434+
}
435+
out := Options{}
436+
UseFlagOptions(&fromFlags)(&out)
437+
438+
Expect(out.Development).To(BeTrue())
439+
Expect(out.Encoder).To(BeNil())
440+
Expect(out.Level).To(BeNil())
441+
Expect(out.StacktraceLevel).To(BeNil())
442+
Expect(out.EncoderConfigOptions).To(BeNil())
443+
})
444+
It("Should set dev=false", func() {
445+
args := []string{"--zap-devel=false"}
446+
fromFlags.BindFlags(&fs)
447+
if err := fs.Parse(args); err != nil {
448+
Expect(err).ToNot(HaveOccurred())
449+
}
450+
out := Options{}
451+
UseFlagOptions(&fromFlags)(&out)
452+
453+
Expect(out.Development).To(BeFalse())
454+
Expect(out.Encoder).To(BeNil())
455+
Expect(out.Level).To(BeNil())
456+
Expect(out.StacktraceLevel).To(BeNil())
457+
Expect(out.EncoderConfigOptions).To(BeNil())
458+
459+
})
460+
})
461+
462+
Context("with encoder options provided programmatically.", func() {
463+
464+
It("Should set Console Encoder, with given Nanos TimeEncoder option.", func() {
465+
logOut := new(bytes.Buffer)
466+
f := func(ec *zapcore.EncoderConfig) {
467+
if err := ec.EncodeTime.UnmarshalText([]byte("nanos")); err != nil {
468+
Expect(err).ToNot(HaveOccurred())
469+
}
470+
}
471+
opts := func(o *Options) {
472+
o.EncoderConfigOptions = append(o.EncoderConfigOptions, f)
473+
}
474+
log := New(UseDevMode(true), WriteTo(logOut), opts)
475+
log.Info("This is a test message")
476+
outRaw := logOut.Bytes()
477+
// Assert for Console Encoder
478+
res := map[string]interface{}{}
479+
Expect(json.Unmarshal(outRaw, &res)).ToNot(Succeed())
480+
// Assert for Epoch Nanos TimeEncoder
481+
Expect(string(outRaw)).ShouldNot(ContainSubstring("."))
482+
483+
})
484+
It("Should set JSON Encoder, with given Millis TimeEncoder option, and MessageKey", func() {
485+
logOut := new(bytes.Buffer)
486+
f := func(ec *zapcore.EncoderConfig) {
487+
ec.MessageKey = "MillisTimeFormat"
488+
if err := ec.EncodeTime.UnmarshalText([]byte("millis")); err != nil {
489+
Expect(err).ToNot(HaveOccurred())
490+
}
491+
}
492+
opts := func(o *Options) {
493+
o.EncoderConfigOptions = append(o.EncoderConfigOptions, f)
494+
}
495+
log := New(UseDevMode(false), WriteTo(logOut), opts)
496+
log.Info("This is a test message")
497+
outRaw := logOut.Bytes()
498+
// Assert for JSON Encoder
499+
res := map[string]interface{}{}
500+
Expect(json.Unmarshal(outRaw, &res)).To(Succeed())
501+
// Assert for Epoch Nanos TimeEncoder
502+
Expect(string(outRaw)).Should(ContainSubstring("."))
503+
// Assert for MessageKey
504+
Expect(string(outRaw)).Should(ContainSubstring("MillisTimeFormat"))
505+
})
506+
507+
})
428508
})

0 commit comments

Comments
 (0)