From d8ffaed2c59622d136737c76350e89417a3ed834 Mon Sep 17 00:00:00 2001 From: Frank Mueller Date: Thu, 7 Sep 2017 22:26:27 +0200 Subject: [PATCH 1/6] Fixed typo --- gjp/doc.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gjp/doc.go b/gjp/doc.go index 09dbf51..412c966 100644 --- a/gjp/doc.go +++ b/gjp/doc.go @@ -16,7 +16,7 @@ // ... // } // name := doc.ValueAt("name").AsString("") -// street := doc.ValueAAt("address/street").AsString("unknown") +// street := doc.ValueAt("address/street").AsString("unknown") // // The value passed to AsString() and the others are default values if // there's none at the path. Another way is to create an empty document From 3eeb6c1d8c4e82adda8819176be9306075ec151b Mon Sep 17 00:00:00 2001 From: Frank Mueller Date: Thu, 7 Sep 2017 23:39:56 +0200 Subject: [PATCH 2/6] Loop logging now only with description --- loop/loop.go | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/loop/loop.go b/loop/loop.go index 2104b44..5d4e8c5 100644 --- a/loop/loop.go +++ b/loop/loop.go @@ -219,7 +219,7 @@ func goLoop(lf LoopFunc, rf RecoverFunc, o Observable, s *sentinel, d string) *l l.owner = l } // Start the loop. - logger.Infof("loop %q starts", l) + l.logf(false, "loop %q starts", l) go l.run() <-l.startedC return l @@ -264,7 +264,7 @@ func (l *loop) Restart() error { l.stopC = make(chan struct{}) l.doneC = make(chan struct{}) // Restart the goroutine. - logger.Infof("loop %q restarts", l) + l.logf(false, "loop %q restarts", l) go l.run() <-l.startedC return nil @@ -366,7 +366,7 @@ func (l *loop) checkTermination(reason interface{}) { if l.err != nil { l.status = Stopping } else { - logger.Infof("loop %q recovered", l) + l.logf(false, "loop %q recovered", l) } } } @@ -399,9 +399,21 @@ func (l *loop) finalizeTermination() { } } if l.err != nil { - logger.Errorf("loop %q stopped with error: %v", l, l.err) + l.logf(true, "loop %q stopped with error: %v", l, l.err) } else { - logger.Infof("loop %q stopped", l) + l.logf(false, "loop %q stopped", l) + } +} + +// log writes information or error only if the loop has a description. +func (l *loop) logf(isError bool, format string, a ...interface{}) { + if l.descr == "" { + return + } + if isError { + logger.Errorf(format, a...) + } else { + logger.Infof(format, a...) } } From 11f4739412d1e0d86b5dbbf0459879955e8c1657 Mon Sep 17 00:00:00 2001 From: Frank Mueller Date: Fri, 8 Sep 2017 18:45:43 +0200 Subject: [PATCH 3/6] Added logger for testing --- logger/doc.go | 10 ++- logger/logger.go | 188 ++++++++++++++++++++++++++++-------------- logger/logger_test.go | 102 ++++++----------------- loop/loop_test.go | 5 +- 4 files changed, 161 insertions(+), 144 deletions(-) diff --git a/logger/doc.go b/logger/doc.go index d054bbe..a011ca8 100644 --- a/logger/doc.go +++ b/logger/doc.go @@ -13,10 +13,12 @@ // name, and line number while logger.Fatalf() may end the program // depending on the set FatalExiterFunc. // -// Multiple backend may be set. The StandardLogger writes to an -// io.Writer (initially os.Stdout), the GoLogger uses the Go log -// package, and the SysLogger uses the Go syslog package on the -// according operating systems. +// Different backends may be set. The standard logger writes to an +// io.Writer (initially os.Stdout), the go logger uses the Go log +// package, and the sys logger uses the Go syslog package on the +// according operating systems. For testing the test logger exists. +// When created also a fetch function is return. It returns the +// logged strings which can be used inside of tests then. // // Changes to the standard behavior can be made with logger.SetLevel(), // logger.SetLogger(), and logger.SetFatalExiter(). Own logger diff --git a/logger/logger.go b/logger/logger.go index 4c66f96..0286893 100644 --- a/logger/logger.go +++ b/logger/logger.go @@ -67,24 +67,25 @@ type FilterFunc func(level LogLevel, info, msg string) bool // Log control variables. var ( - logMutex sync.RWMutex + logMux sync.RWMutex logLevel LogLevel = LevelInfo + logBackend Logger = NewStandardLogger(os.Stdout) logFatalExiter FatalExiterFunc = OsFatalExiter logFilter FilterFunc ) // Level returns the current log level. func Level() LogLevel { - logMutex.Lock() - defer logMutex.Unlock() + logMux.Lock() + defer logMux.Unlock() return logLevel } // SetLevel switches to a new log level and returns // the current one. func SetLevel(level LogLevel) LogLevel { - logMutex.Lock() - defer logMutex.Unlock() + logMux.Lock() + defer logMux.Unlock() current := logLevel switch { case level <= LevelDebug: @@ -103,8 +104,8 @@ func SetLevel(level LogLevel) LogLevel { // be set to lower-case. The function is intended to be used // when then log level is read out of a configuration. func SetLevelString(levelstr string) LogLevel { - logMutex.Lock() - defer logMutex.Unlock() + logMux.Lock() + defer logMux.Unlock() current := logLevel switch strings.ToLower(levelstr) { case "debug": @@ -123,11 +124,18 @@ func SetLevelString(levelstr string) LogLevel { return current } +// SetLogger sets a new logger. +func SetLogger(l Logger) { + logMux.Lock() + defer logMux.Unlock() + logBackend = l +} + // SetFatalExiter sets the fatal exiter function and // returns the current one. func SetFatalExiter(fef FatalExiterFunc) FatalExiterFunc { - logMutex.Lock() - defer logMutex.Unlock() + logMux.Lock() + defer logMux.Unlock() current := logFatalExiter logFatalExiter = fef return current @@ -136,8 +144,8 @@ func SetFatalExiter(fef FatalExiterFunc) FatalExiterFunc { // SetFilter sets the global output filter and returns // the current one. func SetFilter(ff FilterFunc) FilterFunc { - logMutex.Lock() - defer logMutex.Unlock() + logMux.Lock() + defer logMux.Unlock() current := logFilter logFilter = ff return current @@ -146,8 +154,8 @@ func SetFilter(ff FilterFunc) FilterFunc { // UnsetFilter removes the global output folter and // returns the current one. func UnsetFilter() FilterFunc { - logMutex.Lock() - defer logMutex.Unlock() + logMux.Lock() + defer logMux.Unlock() current := logFilter logFilter = nil return current @@ -159,8 +167,8 @@ func UnsetFilter() FilterFunc { // Debugf logs a message at debug level. func Debugf(format string, args ...interface{}) { - logMutex.RLock() - defer logMutex.RUnlock() + logMux.RLock() + defer logMux.RUnlock() if logLevel <= LevelDebug { info := retrieveCallInfo().verboseFormat() msg := fmt.Sprintf(format, args...) @@ -173,8 +181,8 @@ func Debugf(format string, args ...interface{}) { // Infof logs a message at info level. func Infof(format string, args ...interface{}) { - logMutex.RLock() - defer logMutex.RUnlock() + logMux.RLock() + defer logMux.RUnlock() if logLevel <= LevelInfo { info := retrieveCallInfo().shortFormat() msg := fmt.Sprintf(format, args...) @@ -187,8 +195,8 @@ func Infof(format string, args ...interface{}) { // Warningf logs a message at warning level. func Warningf(format string, args ...interface{}) { - logMutex.RLock() - defer logMutex.RUnlock() + logMux.RLock() + defer logMux.RUnlock() if logLevel <= LevelWarning { info := retrieveCallInfo().shortFormat() msg := fmt.Sprintf(format, args...) @@ -201,8 +209,8 @@ func Warningf(format string, args ...interface{}) { // Errorf logs a message at error level. func Errorf(format string, args ...interface{}) { - logMutex.RLock() - defer logMutex.RUnlock() + logMux.RLock() + defer logMux.RUnlock() if logLevel <= LevelError { info := retrieveCallInfo().shortFormat() msg := fmt.Sprintf(format, args...) @@ -215,8 +223,8 @@ func Errorf(format string, args ...interface{}) { // Criticalf logs a message at critical level. func Criticalf(format string, args ...interface{}) { - logMutex.RLock() - defer logMutex.RUnlock() + logMux.RLock() + defer logMux.RUnlock() if logLevel <= LevelCritical { info := retrieveCallInfo().verboseFormat() msg := fmt.Sprintf(format, args...) @@ -232,8 +240,8 @@ func Criticalf(format string, args ...interface{}) { // function, which by default means exiting the application // with error code -1. func Fatalf(format string, args ...interface{}) { - logMutex.RLock() - defer logMutex.RUnlock() + logMux.RLock() + defer logMux.RUnlock() info := retrieveCallInfo().verboseFormat() msg := fmt.Sprintf(format, args...) @@ -242,7 +250,7 @@ func Fatalf(format string, args ...interface{}) { } //-------------------- -// LOGGER +// LOGGER INTERFACE //-------------------- // Logger is the interface for different logger backends. @@ -266,21 +274,17 @@ type Logger interface { Fatal(info, msg string) } -// logger references the used application logger. -var logBackend Logger = NewStandardLogger(os.Stdout) - -// SetLogger sets a new logger. -func SetLogger(l Logger) { - logBackend = l -} - // defaultTimeFormat controls how the timestamp of the standard // logger is printed by default. const defaultTimeFormat = "2006-01-02 15:04:05 Z07:00" -// StandardLogger is a simple logger writing to the given writer. Beside +//-------------------- +// STANDARD LOGGER +//-------------------- + +// standardLogger is a simple logger writing to the given writer. Beside // the output it doesn't handle the levels differently. -type StandardLogger struct { +type standardLogger struct { mutex sync.Mutex out io.Writer timeFormat string @@ -289,7 +293,7 @@ type StandardLogger struct { // NewTimeformatLogger creates a logger writing to the passed // output and with the time formatted with the passed time format. func NewTimeformatLogger(out io.Writer, timeFormat string) Logger { - return &StandardLogger{ + return &standardLogger{ out: out, timeFormat: timeFormat, } @@ -301,38 +305,38 @@ func NewStandardLogger(out io.Writer) Logger { return NewTimeformatLogger(out, defaultTimeFormat) } -// Debug is specified on the Logger interface. -func (sl *StandardLogger) Debug(info, msg string) { +// Debug implements Logger. +func (sl *standardLogger) Debug(info, msg string) { sl.writeLog("DEBUG", info, msg) } -// Info is specified on the Logger interface. -func (sl *StandardLogger) Info(info, msg string) { +// Info implements Logger. +func (sl *standardLogger) Info(info, msg string) { sl.writeLog("INFO", info, msg) } -// Warning is specified on the Logger interface. -func (sl *StandardLogger) Warning(info, msg string) { +// Warning implements Logger. +func (sl *standardLogger) Warning(info, msg string) { sl.writeLog("WARNING", info, msg) } -// Error is specified on the Logger interface. -func (sl *StandardLogger) Error(info, msg string) { +// Error implements Logger. +func (sl *standardLogger) Error(info, msg string) { sl.writeLog("ERROR", info, msg) } -// Critical is specified on the Logger interface. -func (sl *StandardLogger) Critical(info, msg string) { +// Critical implements Logger. +func (sl *standardLogger) Critical(info, msg string) { sl.writeLog("CRITICAL", info, msg) } -// Fatal is specified on the Logger interface. -func (sl *StandardLogger) Fatal(info, msg string) { +// Fatal implements Logger. +func (sl *standardLogger) Fatal(info, msg string) { sl.writeLog("FATAL", info, msg) } -// writeLog writes the concrete log output. -func (sl *StandardLogger) writeLog(level, info, msg string) { +// writeLog writes the log output. +func (sl *standardLogger) writeLog(level, info, msg string) { sl.mutex.Lock() defer sl.mutex.Unlock() @@ -346,45 +350,105 @@ func (sl *StandardLogger) writeLog(level, info, msg string) { io.WriteString(sl.out, "\n") } -// GoLogger just uses the standard go log package. -type GoLogger struct{} +// goLogger just uses the standard go log package. +type goLogger struct{} // NewGoLogger returns a logger implementation using the // Go log package. func NewGoLogger() Logger { - return &GoLogger{} + return &goLogger{} } // Debug is specified on the Logger interface. -func (gl *GoLogger) Debug(info, msg string) { +func (gl *goLogger) Debug(info, msg string) { log.Println("[DEBUG]", info, msg) } // Info is specified on the Logger interface. -func (gl *GoLogger) Info(info, msg string) { +func (gl *goLogger) Info(info, msg string) { log.Println("[INFO]", info, msg) } // Warning is specified on the Logger interface. -func (gl *GoLogger) Warning(info, msg string) { +func (gl *goLogger) Warning(info, msg string) { log.Println("[WARNING]", info, msg) } // Error is specified on the Logger interface. -func (gl *GoLogger) Error(info, msg string) { +func (gl *goLogger) Error(info, msg string) { log.Println("[ERROR]", info, msg) } // Critical is specified on the Logger interface. -func (gl *GoLogger) Critical(info, msg string) { +func (gl *goLogger) Critical(info, msg string) { log.Println("[CRITICAL]", info, msg) } // Fatal is specified on the Logger interface. -func (gl *GoLogger) Fatal(info, msg string) { +func (gl *goLogger) Fatal(info, msg string) { log.Println("[FATAL]", info, msg) } +// testLogger simply collects logs to be evaluated inside of tests. +type testLogger struct { + mux sync.Mutex + logs []string +} + +func NewTestLogger() (Logger, func() []string) { + tl := &testLogger{} + fetch := func() []string { + tl.mux.Lock() + defer tl.mux.Unlock() + logs := tl.logs + tl.logs = nil + return logs + } + return tl, fetch +} + +// Debug implements Logger. +func (tl *testLogger) Debug(info, msg string) { + tl.mux.Lock() + defer tl.mux.Unlock() + tl.logs = append(tl.logs, "[DEBUG] "+info+" "+msg) +} + +// Info implements Logger. +func (tl *testLogger) Info(info, msg string) { + tl.mux.Lock() + defer tl.mux.Unlock() + tl.logs = append(tl.logs, "[INFO] "+info+" "+msg) +} + +// Warning implements Logger. +func (tl *testLogger) Warning(info, msg string) { + tl.mux.Lock() + defer tl.mux.Unlock() + tl.logs = append(tl.logs, "[WARNING] "+info+" "+msg) +} + +// Error implements Logger. +func (tl *testLogger) Error(info, msg string) { + tl.mux.Lock() + defer tl.mux.Unlock() + tl.logs = append(tl.logs, "[ERROR] "+info+" "+msg) +} + +// Critical implements Logger. +func (tl *testLogger) Critical(info, msg string) { + tl.mux.Lock() + defer tl.mux.Unlock() + tl.logs = append(tl.logs, "[CRITICAL] "+info+" "+msg) +} + +// Fatal implements Logger. +func (tl *testLogger) Fatal(info, msg string) { + tl.mux.Lock() + defer tl.mux.Unlock() + tl.logs = append(tl.logs, "[FATAL] "+info+" "+msg) +} + //-------------------- // HELPER //-------------------- @@ -436,8 +500,8 @@ func retrieveCallInfo() *callInfo { // shallLog is used inside the logging functions to check if // logging is wanted. func shallLog(level LogLevel, info, msg string) bool { - logMutex.RLock() - defer logMutex.RUnlock() + logMux.RLock() + defer logMux.RUnlock() if logFilter == nil { return true } diff --git a/logger/logger_test.go b/logger/logger_test.go index 526f5bd..4f5484d 100644 --- a/logger/logger_test.go +++ b/logger/logger_test.go @@ -30,25 +30,26 @@ func TestGetSetLevel(t *testing.T) { level := logger.Level() defer logger.SetLevel(level) - ownLogger := &testLogger{} - logger.SetLogger(ownLogger) + tl, fetch := logger.NewTestLogger() + logger.SetLogger(tl) + logger.SetLevel(logger.LevelDebug) logger.Debugf("Debug.") logger.Infof("Info.") logger.Warningf("Warning.") logger.Errorf("Error.") logger.Criticalf("Critical.") - assert.Length(ownLogger.logs, 5) - ownLogger = &testLogger{} - logger.SetLogger(ownLogger) + assert.Length(fetch(), 5) + logger.SetLevel(logger.LevelError) logger.Debugf("Debug.") logger.Infof("Info.") logger.Warningf("Warning.") logger.Errorf("Error.") logger.Criticalf("Critical.") - assert.Length(ownLogger.logs, 2) + + assert.Length(fetch(), 2) } // TestGetSetLevelString tests the setting of the @@ -58,35 +59,35 @@ func TestGetSetLevelString(t *testing.T) { level := logger.Level() defer logger.SetLevel(level) - ownLogger := &testLogger{} - logger.SetLogger(ownLogger) + tl, fetch := logger.NewTestLogger() + logger.SetLogger(tl) + logger.SetLevelString("dEbUg") logger.Debugf("Debug.") logger.Infof("Info.") logger.Warningf("Warning.") logger.Errorf("Error.") logger.Criticalf("Critical.") - assert.Length(ownLogger.logs, 5) - ownLogger = &testLogger{} - logger.SetLogger(ownLogger) + assert.Length(fetch(), 5) + logger.SetLevelString("error") logger.Debugf("Debug.") logger.Infof("Info.") logger.Warningf("Warning.") logger.Errorf("Error.") logger.Criticalf("Critical.") - assert.Length(ownLogger.logs, 2) - ownLogger = &testLogger{} - logger.SetLogger(ownLogger) + assert.Length(fetch(), 2) + logger.SetLevelString("dont-know-what-you-mean") logger.Debugf("Debug.") logger.Infof("Info.") logger.Warningf("Warning.") logger.Errorf("Error.") logger.Criticalf("Critical.") - assert.Length(ownLogger.logs, 2) + + assert.Length(fetch(), 2) } // TestFiltering tests the filtering of the logging. @@ -95,8 +96,9 @@ func TestFiltering(t *testing.T) { level := logger.Level() defer logger.SetLevel(level) - ownLogger := &testLogger{} - logger.SetLogger(ownLogger) + tl, fetch := logger.NewTestLogger() + logger.SetLogger(tl) + logger.SetLevel(logger.LevelDebug) logger.SetFilter(func(level logger.LogLevel, info, msg string) bool { return level >= logger.LevelWarning && level <= logger.LevelError @@ -107,18 +109,18 @@ func TestFiltering(t *testing.T) { logger.Warningf("Warning.") logger.Errorf("Error.") logger.Criticalf("Critical.") - assert.Length(ownLogger.logs, 3) + + assert.Length(fetch(), 3) logger.UnsetFilter() - ownLogger = &testLogger{} - logger.SetLogger(ownLogger) logger.Debugf("Debug.") logger.Infof("Info.") logger.Warningf("Warning.") logger.Errorf("Error.") logger.Criticalf("Critical.") - assert.Length(ownLogger.logs, 5) + + assert.Length(fetch(), 5) } // TestGoLogger tests logging with the go logger. @@ -157,76 +159,26 @@ func TestSysLogger(t *testing.T) { logger.Criticalf("Critical.") } -// TestOwnLogger tests logging with an own logger. -func TestOwnLogger(t *testing.T) { - assert := audit.NewTestingAssertion(t, true) - ownLogger := &testLogger{} - level := logger.Level() - defer logger.SetLevel(level) - - logger.SetLevel(logger.LevelDebug) - logger.SetLogger(ownLogger) - - logger.Debugf("Debug.") - logger.Infof("Info.") - logger.Warningf("Warning.") - logger.Errorf("Error.") - logger.Criticalf("Critical.") - - assert.Length(ownLogger.logs, 5) -} - // TestFatalExit tests the call of the fatal exiter after a // fatal error log. func TestFatalExit(t *testing.T) { assert := audit.NewTestingAssertion(t, true) - ownLogger := &testLogger{} level := logger.Level() defer logger.SetLevel(level) + tl, fetch := logger.NewTestLogger() + logger.SetLogger(tl) + exited := false fatalExiter := func() { exited = true } - logger.SetLogger(ownLogger) logger.SetFatalExiter(fatalExiter) logger.Fatalf("fatal") - assert.Length(ownLogger.logs, 1) + assert.Length(fetch(), 1) assert.True(exited) } -//-------------------- -// LOGGER -//-------------------- - -type testLogger struct { - logs []string -} - -func (tl *testLogger) Debug(info, msg string) { - tl.logs = append(tl.logs, "[DEBUG] "+info+" "+msg) -} - -func (tl *testLogger) Info(info, msg string) { - tl.logs = append(tl.logs, "[INFO] "+info+" "+msg) -} - -func (tl *testLogger) Warning(info, msg string) { - tl.logs = append(tl.logs, "[WARNING] "+info+" "+msg) -} - -func (tl *testLogger) Error(info, msg string) { - tl.logs = append(tl.logs, "[ERROR] "+info+" "+msg) -} - -func (tl *testLogger) Critical(info, msg string) { - tl.logs = append(tl.logs, "[CRITICAL] "+info+" "+msg) -} - -func (tl *testLogger) Fatal(info, msg string) { - tl.logs = append(tl.logs, "[FATAL] "+info+" "+msg) -} - // EOF diff --git a/loop/loop_test.go b/loop/loop_test.go index 9dc81f4..f3866bc 100644 --- a/loop/loop_test.go +++ b/loop/loop_test.go @@ -24,9 +24,8 @@ import ( // CONSTANTS //-------------------- -var ( - timeout time.Duration = 5 * time.Second -) +// timeout is the waitng time for events from inside of loops. +var timeout time.Duration = 5 * time.Second //-------------------- // TESTS From 2c83a9db6c47da41879cb07a736c055b7c68855e Mon Sep 17 00:00:00 2001 From: Frank Mueller Date: Sat, 9 Sep 2017 21:52:58 +0200 Subject: [PATCH 4/6] Improved the TestLogger --- logger/logger.go | 81 ++++++++++++++++++++++++++++++++----------- logger/logger_test.go | 44 ++++++++++++++--------- 2 files changed, 88 insertions(+), 37 deletions(-) diff --git a/logger/logger.go b/logger/logger.go index 0286893..4791d1b 100644 --- a/logger/logger.go +++ b/logger/logger.go @@ -125,10 +125,12 @@ func SetLevelString(levelstr string) LogLevel { } // SetLogger sets a new logger. -func SetLogger(l Logger) { +func SetLogger(l Logger) Logger { logMux.Lock() defer logMux.Unlock() + old := logBackend logBackend = l + return old } // SetFatalExiter sets the fatal exiter function and @@ -389,64 +391,101 @@ func (gl *goLogger) Fatal(info, msg string) { log.Println("[FATAL]", info, msg) } +// TestLogger extends the Logger interface with methods to retrieve +// and reset the collected data. +type TestLogger interface { + Logger + + // Len returns the number of collected entries. + Len() int + + // Entries returns the collected entries. + Entries() []string + + // Reset clears the collected entries. + Reset() +} + // testLogger simply collects logs to be evaluated inside of tests. type testLogger struct { - mux sync.Mutex - logs []string -} - -func NewTestLogger() (Logger, func() []string) { - tl := &testLogger{} - fetch := func() []string { - tl.mux.Lock() - defer tl.mux.Unlock() - logs := tl.logs - tl.logs = nil - return logs - } - return tl, fetch + mux sync.Mutex + entries []string +} + +// NewTestLogger returns a special logger for testing. +func NewTestLogger() TestLogger { + return &testLogger{} } // Debug implements Logger. func (tl *testLogger) Debug(info, msg string) { tl.mux.Lock() defer tl.mux.Unlock() - tl.logs = append(tl.logs, "[DEBUG] "+info+" "+msg) + entry := fmt.Sprintf("%d [DEBUG] %s %s", time.Now().UnixNano(), info, msg) + tl.entries = append(tl.entries, entry) } // Info implements Logger. func (tl *testLogger) Info(info, msg string) { tl.mux.Lock() defer tl.mux.Unlock() - tl.logs = append(tl.logs, "[INFO] "+info+" "+msg) + entry := fmt.Sprintf("%d [INFO] %s %s", time.Now().UnixNano(), info, msg) + tl.entries = append(tl.entries, entry) } // Warning implements Logger. func (tl *testLogger) Warning(info, msg string) { tl.mux.Lock() defer tl.mux.Unlock() - tl.logs = append(tl.logs, "[WARNING] "+info+" "+msg) + entry := fmt.Sprintf("%d [WARNING] %s %s", time.Now().UnixNano(), info, msg) + tl.entries = append(tl.entries, entry) } // Error implements Logger. func (tl *testLogger) Error(info, msg string) { tl.mux.Lock() defer tl.mux.Unlock() - tl.logs = append(tl.logs, "[ERROR] "+info+" "+msg) + entry := fmt.Sprintf("%d [ERROR] %s %s", time.Now().UnixNano(), info, msg) + tl.entries = append(tl.entries, entry) } // Critical implements Logger. func (tl *testLogger) Critical(info, msg string) { tl.mux.Lock() defer tl.mux.Unlock() - tl.logs = append(tl.logs, "[CRITICAL] "+info+" "+msg) + entry := fmt.Sprintf("%d [CRITICAL] %s %s", time.Now().UnixNano(), info, msg) + tl.entries = append(tl.entries, entry) } // Fatal implements Logger. func (tl *testLogger) Fatal(info, msg string) { tl.mux.Lock() defer tl.mux.Unlock() - tl.logs = append(tl.logs, "[FATAL] "+info+" "+msg) + entry := fmt.Sprintf("%d [CRITICAL] %s %s", time.Now().UnixNano(), info, msg) + tl.entries = append(tl.entries, entry) +} + +// Len implements TestLogger. +func (tl *testLogger) Len() int { + tl.mux.Lock() + defer tl.mux.Unlock() + return len(tl.entries) +} + +// Entries implements TestLogger. +func (tl *testLogger) Entries() []string { + tl.mux.Lock() + defer tl.mux.Unlock() + entries := make([]string, len(tl.entries)) + copy(entries, tl.entries) + return entries +} + +// Reset implements TestLogger. +func (tl *testLogger) Reset() { + tl.mux.Lock() + defer tl.mux.Unlock() + tl.entries = nil } //-------------------- diff --git a/logger/logger_test.go b/logger/logger_test.go index 4f5484d..ce005c6 100644 --- a/logger/logger_test.go +++ b/logger/logger_test.go @@ -30,8 +30,9 @@ func TestGetSetLevel(t *testing.T) { level := logger.Level() defer logger.SetLevel(level) - tl, fetch := logger.NewTestLogger() - logger.SetLogger(tl) + tl := logger.NewTestLogger() + ol := logger.SetLogger(tl) + defer logger.SetLogger(ol) logger.SetLevel(logger.LevelDebug) logger.Debugf("Debug.") @@ -40,7 +41,8 @@ func TestGetSetLevel(t *testing.T) { logger.Errorf("Error.") logger.Criticalf("Critical.") - assert.Length(fetch(), 5) + assert.Length(tl, 5) + tl.Reset() logger.SetLevel(logger.LevelError) logger.Debugf("Debug.") @@ -49,7 +51,8 @@ func TestGetSetLevel(t *testing.T) { logger.Errorf("Error.") logger.Criticalf("Critical.") - assert.Length(fetch(), 2) + assert.Length(tl, 2) + tl.Reset() } // TestGetSetLevelString tests the setting of the @@ -59,8 +62,9 @@ func TestGetSetLevelString(t *testing.T) { level := logger.Level() defer logger.SetLevel(level) - tl, fetch := logger.NewTestLogger() - logger.SetLogger(tl) + tl := logger.NewTestLogger() + ol := logger.SetLogger(tl) + defer logger.SetLogger(ol) logger.SetLevelString("dEbUg") logger.Debugf("Debug.") @@ -69,7 +73,8 @@ func TestGetSetLevelString(t *testing.T) { logger.Errorf("Error.") logger.Criticalf("Critical.") - assert.Length(fetch(), 5) + assert.Length(tl, 5) + tl.Reset() logger.SetLevelString("error") logger.Debugf("Debug.") @@ -78,7 +83,8 @@ func TestGetSetLevelString(t *testing.T) { logger.Errorf("Error.") logger.Criticalf("Critical.") - assert.Length(fetch(), 2) + assert.Length(tl, 2) + tl.Reset() logger.SetLevelString("dont-know-what-you-mean") logger.Debugf("Debug.") @@ -87,7 +93,8 @@ func TestGetSetLevelString(t *testing.T) { logger.Errorf("Error.") logger.Criticalf("Critical.") - assert.Length(fetch(), 2) + assert.Length(tl, 2) + tl.Reset() } // TestFiltering tests the filtering of the logging. @@ -96,8 +103,9 @@ func TestFiltering(t *testing.T) { level := logger.Level() defer logger.SetLevel(level) - tl, fetch := logger.NewTestLogger() - logger.SetLogger(tl) + tl := logger.NewTestLogger() + ol := logger.SetLogger(tl) + defer logger.SetLogger(ol) logger.SetLevel(logger.LevelDebug) logger.SetFilter(func(level logger.LogLevel, info, msg string) bool { @@ -110,7 +118,8 @@ func TestFiltering(t *testing.T) { logger.Errorf("Error.") logger.Criticalf("Critical.") - assert.Length(fetch(), 3) + assert.Length(tl, 3) + tl.Reset() logger.UnsetFilter() @@ -120,7 +129,8 @@ func TestFiltering(t *testing.T) { logger.Errorf("Error.") logger.Criticalf("Critical.") - assert.Length(fetch(), 5) + assert.Length(tl, 5) + tl.Reset() } // TestGoLogger tests logging with the go logger. @@ -166,8 +176,9 @@ func TestFatalExit(t *testing.T) { level := logger.Level() defer logger.SetLevel(level) - tl, fetch := logger.NewTestLogger() - logger.SetLogger(tl) + tl := logger.NewTestLogger() + ol := logger.SetLogger(tl) + defer logger.SetLogger(ol) exited := false fatalExiter := func() { @@ -177,8 +188,9 @@ func TestFatalExit(t *testing.T) { logger.SetFatalExiter(fatalExiter) logger.Fatalf("fatal") - assert.Length(fetch(), 1) + assert.Length(tl, 1) assert.True(exited) + tl.Reset() } // EOF From 85853a6d802860b63e5b87c460767140c98ffd0a Mon Sep 17 00:00:00 2001 From: Frank Mueller Date: Sat, 9 Sep 2017 22:42:19 +0200 Subject: [PATCH 5/6] Added testing of loop without logging Now when a loop has no description the typical logging messages are surpressed. --- loop/loop.go | 4 ---- loop/loop_test.go | 38 +++++++++++++++++++++++++++++++++++++- 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/loop/loop.go b/loop/loop.go index 5d4e8c5..3edeb9d 100644 --- a/loop/loop.go +++ b/loop/loop.go @@ -210,10 +210,6 @@ func goLoop(lf LoopFunc, rf RecoverFunc, o Observable, s *sentinel, d string) *l owner: o, sentinel: s, } - // Check description. - if l.descr == "" { - l.descr = identifier.NewUUID().String() - } // Check owner, at least we should own ourself. if l.owner == nil { l.owner = l diff --git a/loop/loop_test.go b/loop/loop_test.go index f3866bc..1f2f912 100644 --- a/loop/loop_test.go +++ b/loop/loop_test.go @@ -17,6 +17,7 @@ import ( "time" "github.com/tideland/golib/audit" + "github.com/tideland/golib/logger" "github.com/tideland/golib/loop" ) @@ -47,6 +48,42 @@ func TestSimpleStop(t *testing.T) { assert.Equal(loop.Stopped, status, "loop is stopped") } +// TestLogging tests running a loop without logging. +func TestLogging(t *testing.T) { + assert := audit.NewTestingAssertion(t, true) + tl := logger.NewTestLogger() + ol := logger.SetLogger(tl) + defer logger.SetLogger(ol) + + // With description, so logging. + bundle := newChannelBundle() + l := loop.Go(makeSimpleLF(bundle), "logger") + + assert.Wait(bundle.startedc, true, timeout) + assert.Nil(l.Stop(), "no error after simple stop") + assert.Wait(bundle.donec, true, timeout) + + status, _ := l.Error() + + assert.Equal(loop.Stopped, status, "loop is stopped") + assert.Length(tl, 2) + tl.Reset() + + // Without description, so no logging. + bundle = newChannelBundle() + l = loop.Go(makeSimpleLF(bundle)) + + assert.Wait(bundle.startedc, true, timeout) + assert.Nil(l.Stop(), "no error after simple stop") + assert.Wait(bundle.donec, true, timeout) + + status, _ = l.Error() + + assert.Equal(loop.Stopped, status, "loop is stopped") + assert.Length(tl, 0) + tl.Reset() +} + // TestSimpleRestart tests restarting when not stopped and // when stopped. func TestSimpleRestart(t *testing.T) { @@ -226,7 +263,6 @@ func TestDescription(t *testing.T) { assert.Equal(s.String(), "one") assert.Equal(lA.String(), "two::three::four") - assert.Match(lB.String(), "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}") assert.Nil(s.Stop()) } From 7f840cd50f0fc98a2b34ef5f29f7b4988de2c1d6 Mon Sep 17 00:00:00 2001 From: Frank Mueller Date: Sat, 9 Sep 2017 23:27:28 +0200 Subject: [PATCH 6/6] Final documentation fixes --- CHANGELOG.md | 8 +++++++- README.md | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 19688f4..381c468 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,14 @@ # Tideland Go Library +## 2017-09-09 + +- Fixed a *GJP* documentation typo +- Added a *TestLogger* to be used in unit tests +- Changed *Loop* to not log anymore if no description is given + ## 2017-07-20 -- Fixed GJP handling of empty objects and arrays +- Fixed *GJP* handling of empty objects and arrays ## 2017-07-13 diff --git a/README.md b/README.md index 8f66c6e..1adc0c7 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ I hope you like them. ;) ## Version -Version 4.24.1 +Version 4.24.2 ## Packages