Skip to content

Commit 0e4fb90

Browse files
authored
Merge pull request #76 from splitio/extended-logger
Adding extended logger
2 parents f4a86ca + f28cb36 commit 0e4fb90

File tree

6 files changed

+173
-6
lines changed

6 files changed

+173
-6
lines changed

.gitignore

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,5 @@
1414
.glide/
1515

1616
*.swp
17-
17+
.idea
1818
vendor/

CHANGES

+3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
5.1.0 (Apr 7, 2022)
2+
- Adding ExtendedLevelFilteredLoggerWrapper to improve performance parsing log calls parameters only if the set level applies
3+
14
5.0.3 (Jan 12, 2021)
25
- Cleanup cache datastructure & multi-level revamp to support contexts
36
- Fix HTTP-Proxy from env vars in sse client

logging/interface.go

+15
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,18 @@ type LoggerInterface interface {
1010
Debug(msg ...interface{})
1111
Verbose(msg ...interface{})
1212
}
13+
14+
// ParamsFn is a function that returns a slice of interface{}
15+
type ParamsFn = func() []interface{}
16+
17+
// ExtendedLoggerInterface ...
18+
// If a custom logger object is to be used, it should comply with the following
19+
// interface. (Standard go-lang library log.Logger.Println method signature)
20+
type ExtendedLoggerInterface interface {
21+
LoggerInterface
22+
ErrorFn(format string, params ParamsFn)
23+
WarningFn(format string, params ParamsFn)
24+
InfoFn(format string, params ParamsFn)
25+
DebugFn(format string, params ParamsFn)
26+
VerboseFn(format string, params ParamsFn)
27+
}

logging/levels.go

+46
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package logging
22

33
import (
4+
"fmt"
45
"math"
56
)
67

@@ -91,3 +92,48 @@ func Level(level string) int {
9192
}
9293
return l
9394
}
95+
96+
// ExtendedLevelFilteredLoggerWrapper leveled logger improving message format performance
97+
type ExtendedLevelFilteredLoggerWrapper struct {
98+
*LevelFilteredLoggerWrapper
99+
}
100+
101+
// sprintf apply parameter function to parse the given message
102+
func (l *ExtendedLevelFilteredLoggerWrapper) sprintf(format string, params func() []interface{}) string {
103+
return fmt.Sprintf(format, params()...)
104+
}
105+
106+
// ErrorFn forwards error logging messages getting parameters from a function to improve performance
107+
func (l *ExtendedLevelFilteredLoggerWrapper) ErrorFn(format string, params ParamsFn) {
108+
if l.level >= LevelError {
109+
l.delegate.Error(l.sprintf(format, params))
110+
}
111+
}
112+
113+
// WarningFn forwards warning logging messages getting parameters from a function to improve performance
114+
func (l *ExtendedLevelFilteredLoggerWrapper) WarningFn(format string, params ParamsFn) {
115+
if l.level >= LevelWarning {
116+
l.delegate.Warning(l.sprintf(format, params))
117+
}
118+
}
119+
120+
// InfoFn forwards info logging messages getting parameters from a function to improve performance
121+
func (l *ExtendedLevelFilteredLoggerWrapper) InfoFn(format string, params ParamsFn) {
122+
if l.level >= LevelInfo {
123+
l.delegate.Info(l.sprintf(format, params))
124+
}
125+
}
126+
127+
// DebugFn forwards debug logging messages getting parameters from a function to improve performance
128+
func (l *ExtendedLevelFilteredLoggerWrapper) DebugFn(format string, params ParamsFn) {
129+
if l.level >= LevelDebug {
130+
l.delegate.Debug(l.sprintf(format, params))
131+
}
132+
}
133+
134+
// VerboseFn forwards verbose logging messages getting parameters from a function to improve performance
135+
func (l *ExtendedLevelFilteredLoggerWrapper) VerboseFn(format string, params ParamsFn) {
136+
if l.level >= LevelVerbose {
137+
l.delegate.Verbose(l.sprintf(format, params))
138+
}
139+
}

logging/levels_test.go

+82
Original file line numberDiff line numberDiff line change
@@ -255,3 +255,85 @@ func TestNoneLevel(t *testing.T) {
255255
}
256256
}
257257
}
258+
259+
func writelog(logger *ExtendedLevelFilteredLoggerWrapper) {
260+
logger.ErrorFn("hello %s", func() []interface{} { return []interface{}{"world"} })
261+
logger.WarningFn("hello %s", func() []interface{} { return []interface{}{"world"} })
262+
logger.InfoFn("hello %s", func() []interface{} { return []interface{}{"world"} })
263+
logger.DebugFn("hello %s", func() []interface{} { return []interface{}{"world"} })
264+
logger.VerboseFn("hello %s", func() []interface{} { return []interface{}{"world"} })
265+
}
266+
267+
func assertWrites(t *testing.T, currentLevel string, delegate *mockedLogger, shouldBeCalled []string, shouldNotBeCalled []string) {
268+
for _, level := range shouldBeCalled {
269+
if !delegate.msgs[level] {
270+
t.Errorf("Call to log level function \"%s\" should have been forwarded, current level=%s", level, currentLevel)
271+
}
272+
}
273+
274+
for _, level := range shouldNotBeCalled {
275+
if delegate.msgs[level] {
276+
t.Errorf("Call to log level function \"%s\" should NOT have been forwarded, current level=%s", level, currentLevel)
277+
}
278+
}
279+
}
280+
281+
func TestExtendedLevelFilteredLogger(t *testing.T) {
282+
283+
delegate := &mockedLogger{}
284+
delegate.reset()
285+
286+
logger := &ExtendedLevelFilteredLoggerWrapper{&LevelFilteredLoggerWrapper{
287+
delegate: delegate,
288+
level: LevelError,
289+
}}
290+
291+
t.Run("Error", func(t *testing.T) {
292+
logger.level = LevelError
293+
delegate.reset()
294+
writelog(logger)
295+
assertWrites(t, "ERROR", delegate, []string{"Error"}, []string{"Warning", "Info", "Debug", "Verbose"})
296+
})
297+
298+
t.Run("Waring", func(t *testing.T) {
299+
logger.level = LevelWarning
300+
delegate.reset()
301+
writelog(logger)
302+
assertWrites(t, "WARNING", delegate, []string{"Error", "Warning"}, []string{"Info", "Debug", "Verbose"})
303+
})
304+
305+
t.Run("Info", func(t *testing.T) {
306+
logger.level = LevelInfo
307+
delegate.reset()
308+
writelog(logger)
309+
assertWrites(t, "INFO", delegate, []string{"Error", "Warning", "Info"}, []string{"Debug", "Verbose"})
310+
})
311+
312+
t.Run("Debug", func(t *testing.T) {
313+
logger.level = LevelDebug
314+
delegate.reset()
315+
writelog(logger)
316+
assertWrites(t, "DEBUG", delegate, []string{"Error", "Warning", "Info", "Debug"}, []string{"Verbose"})
317+
})
318+
319+
t.Run("Verbose", func(t *testing.T) {
320+
logger.level = LevelVerbose
321+
delegate.reset()
322+
writelog(logger)
323+
assertWrites(t, "VERBOSE", delegate, []string{"Error", "Warning", "Info", "Debug", "Verbose"}, []string{})
324+
})
325+
326+
t.Run("All", func(t *testing.T) {
327+
logger.level = LevelAll
328+
delegate.reset()
329+
writelog(logger)
330+
assertWrites(t, "ALL", delegate, []string{"Error", "Warning", "Info", "Debug", "Verbose"}, []string{})
331+
})
332+
333+
t.Run("None", func(t *testing.T) {
334+
logger.level = LevelNone
335+
delegate.reset()
336+
writelog(logger)
337+
assertWrites(t, "NONE", delegate, []string{}, []string{"Error", "Warning", "Info", "Debug", "Verbose"})
338+
})
339+
}

logging/logging.go

+26-5
Original file line numberDiff line numberDiff line change
@@ -105,25 +105,46 @@ func normalizeOptions(options *LoggerOptions) *LoggerOptions {
105105
return toRet
106106
}
107107

108-
// NewLogger instantiates a new Logger instance. Requires a pointer to a LoggerOptions struct to be passed.
109-
func NewLogger(options *LoggerOptions) LoggerInterface {
110-
111-
options = normalizeOptions(options)
108+
// newLogger constructor of Logger instance.
109+
// Returns: a pointer to *Logger
110+
// Assumes: that options are alredy normalized
111+
func newLogger(options *LoggerOptions) *Logger {
112112
prefix := ""
113113
if options.Prefix != "" {
114114
prefix = fmt.Sprintf("%s - ", options.Prefix)
115115
}
116-
logger := &Logger{
116+
return &Logger{
117117
debugLogger: *log.New(options.DebugWriter, fmt.Sprintf("%sDEBUG - ", prefix), options.StandardLoggerFlags),
118118
infoLogger: *log.New(options.InfoWriter, fmt.Sprintf("%sINFO - ", prefix), options.StandardLoggerFlags),
119119
warningLogger: *log.New(options.WarningWriter, fmt.Sprintf("%sWARNING - ", prefix), options.StandardLoggerFlags),
120120
errorLogger: *log.New(options.ErrorWriter, fmt.Sprintf("%sERROR - ", prefix), options.StandardLoggerFlags),
121121
verboseLogger: *log.New(options.VerboseWriter, fmt.Sprintf("%sVERBOSE - ", prefix), options.StandardLoggerFlags),
122122
framesToSkip: 3 + options.ExtraFramesToSkip,
123123
}
124+
}
125+
126+
// NewLogger instantiates a new Logger instance. Requires a pointer to a LoggerOptions struct to be passed.
127+
func NewLogger(options *LoggerOptions) LoggerInterface {
128+
129+
options = normalizeOptions(options)
130+
131+
logger := newLogger(options)
124132

125133
return &LevelFilteredLoggerWrapper{
126134
delegate: logger,
127135
level: options.LogLevel,
128136
}
129137
}
138+
139+
// NewExtendedLogger instantiates a new Logger instance. Requires a pointer to a LoggerOptions struct to be passed.
140+
func NewExtendedLogger(options *LoggerOptions) ExtendedLoggerInterface {
141+
142+
options = normalizeOptions(options)
143+
144+
logger := newLogger(options)
145+
146+
return &ExtendedLevelFilteredLoggerWrapper{&LevelFilteredLoggerWrapper{
147+
delegate: logger,
148+
level: options.LogLevel,
149+
}}
150+
}

0 commit comments

Comments
 (0)