From 315357bdb9b2c218dc9c4c84ae24b3309e33bdef Mon Sep 17 00:00:00 2001 From: pleimer Date: Thu, 30 Apr 2020 10:14:22 -0400 Subject: [PATCH 1/3] Add console logging option --- logging/logger.go | 94 +++++++++++++++++++++++++++++++---------------- 1 file changed, 63 insertions(+), 31 deletions(-) diff --git a/logging/logger.go b/logging/logger.go index 17a151f..a70fc60 100644 --- a/logging/logger.go +++ b/logging/logger.go @@ -4,9 +4,11 @@ import ( "bytes" "fmt" "os" + "strings" "time" ) +// LogLevel defines log levels type LogLevel int const ( @@ -16,47 +18,72 @@ const ( ERROR ) -func (self LogLevel) String() string { - return [...]string{"DEBUG", "INFO", "WARN", "ERROR"}[self] +func (l LogLevel) String() string { + return [...]string{"DEBUG", "INFO", "WARN", "ERROR"}[l] } +type writeFn func(string) error + +// Logger implements a simple logger with 4 levels type Logger struct { Level LogLevel Timestamp bool metadata map[string]interface{} logfile *os.File + write writeFn } -func NewLogger(level LogLevel, path string) (*Logger, error) { +// NewLogger logger factory +func NewLogger(level LogLevel, target string) (*Logger, error) { var logger Logger logger.Level = level logger.Timestamp = false logger.metadata = make(map[string]interface{}) - logfile, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) - if err != nil { - return nil, err + switch strings.ToLower(target) { + case "console": + logger.write = func(message string) error { + fmt.Print(message) + return nil + } + break + default: + var err error + if logger.logfile == nil { + logger.logfile, err = os.OpenFile(target, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) + if err != nil { + return nil, err + } + } + logger.write = func(message string) error { + _, err := logger.logfile.WriteString(message) + return err + } } - logger.logfile = logfile return &logger, nil } -func (self *Logger) Destroy() error { - return self.logfile.Close() +// Destroy cleanup resources +func (l *Logger) Destroy() error { + if l.logfile != nil { + return l.logfile.Close() + } + return nil } -func (self *Logger) Metadata(metadata map[string]interface{}) { - self.metadata = metadata +// Metadata set metadata to include in message +func (l *Logger) Metadata(metadata map[string]interface{}) { + l.metadata = metadata } -func (self *Logger) formatMetadata() (string, error) { +func (l *Logger) formatMetadata() (string, error) { //var build strings.Builder // Note: we need to support go-1.9.2 because of CentOS7 var build bytes.Buffer - if len(self.metadata) > 0 { + if len(l.metadata) > 0 { joiner := "" - for key, item := range self.metadata { + for key, item := range l.metadata { _, err := fmt.Fprintf(&build, "%s%s: %v", joiner, key, item) if err != nil { return build.String(), err @@ -67,12 +94,12 @@ func (self *Logger) formatMetadata() (string, error) { } } // clear metadata for next use - self.metadata = make(map[string]interface{}) + l.metadata = make(map[string]interface{}) return build.String(), nil } -func (self *Logger) writeRecord(level LogLevel, message string) error { - metadata, err := self.formatMetadata() +func (l *Logger) writeRecord(level LogLevel, message string) error { + metadata, err := l.formatMetadata() if err != nil { return err } @@ -80,7 +107,7 @@ func (self *Logger) writeRecord(level LogLevel, message string) error { //var build strings.Builder // Note: we need to support go-1.9.2 because of CentOS7 var build bytes.Buffer - if self.Timestamp { + if l.Timestamp { _, err = build.WriteString(time.Now().Format("2006-01-02 15:04:05 ")) } @@ -102,34 +129,39 @@ func (self *Logger) writeRecord(level LogLevel, message string) error { if err != nil { return nil } - _, err = self.logfile.WriteString(build.String()) + err = l.write(build.String()) return err } -func (self *Logger) Debug(message string) error { - if self.Level == DEBUG { - return self.writeRecord(DEBUG, message) +// Debug level debug +func (l *Logger) Debug(message string) error { + if l.Level == DEBUG { + return l.writeRecord(DEBUG, message) } return nil } -func (self *Logger) Info(message string) error { - if self.Level <= INFO { - return self.writeRecord(INFO, message) +// Info level info +func (l *Logger) Info(message string) error { + if l.Level <= INFO { + return l.writeRecord(INFO, message) } return nil } -func (self *Logger) Warn(message string) error { - if self.Level <= WARN { - return self.writeRecord(WARN, message) +// Warn level warn +func (l *Logger) Warn(message string) error { + if l.Level <= WARN { + return l.writeRecord(WARN, message) } return nil } -func (self *Logger) Error(message string) error { - if self.Level <= ERROR { - return self.writeRecord(ERROR, message) +// Error level error +func (l *Logger) Error(message string) error { + if l.Level <= ERROR { + return l.writeRecord(ERROR, message) } return nil } + From a841db1c02711d80599eb1ed5600294548de8e2e Mon Sep 17 00:00:00 2001 From: pleimer Date: Thu, 20 Aug 2020 13:56:49 -0400 Subject: [PATCH 2/3] Add SetFile() back in --- logging/logger.go | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/logging/logger.go b/logging/logger.go index a70fc60..e553989 100644 --- a/logging/logger.go +++ b/logging/logger.go @@ -77,6 +77,18 @@ func (l *Logger) Metadata(metadata map[string]interface{}) { l.metadata = metadata } +// SetFile .. +func (l *Logger) SetFile(path string, permissions os.FileMode) error { + newLogfile, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_APPEND, permissions) + if err != nil { + l.Warn("Couldn't open new log file, leaving the old one") + return err + } + l.logfile.Close() + l.logfile = newLogfile + return nil +} + func (l *Logger) formatMetadata() (string, error) { //var build strings.Builder // Note: we need to support go-1.9.2 because of CentOS7 @@ -164,4 +176,3 @@ func (l *Logger) Error(message string) error { } return nil } - From 32bf366631f94291a7364b7bf234950c0779fd15 Mon Sep 17 00:00:00 2001 From: pleimer Date: Thu, 20 Aug 2020 14:48:27 -0400 Subject: [PATCH 3/3] SetConsole() and SetFile() safety --- logging/logger.go | 39 +++++++++++++++++++++++++++++++++++++-- tests/logging_test.go | 14 ++++++++++++++ 2 files changed, 51 insertions(+), 2 deletions(-) diff --git a/logging/logger.go b/logging/logger.go index e553989..2789e79 100644 --- a/logging/logger.go +++ b/logging/logger.go @@ -77,15 +77,50 @@ func (l *Logger) Metadata(metadata map[string]interface{}) { l.metadata = metadata } -// SetFile .. +// SetLogLevel .. +func (l *Logger) SetLogLevel(level LogLevel) { + l.Level = level +} + +// SetConsole sets logger target to console +func (l *Logger) SetConsole() { + if l.logfile != nil { + err := l.logfile.Close() + if err != nil { + l.Warn("Failed to close old log file") + } + l.logfile = nil + } + + l.write = func(message string) error { + fmt.Print(message) + return nil + } +} + +// SetFile sets logfile. If logger target was console, switch to file mode func (l *Logger) SetFile(path string, permissions os.FileMode) error { newLogfile, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_APPEND, permissions) if err != nil { l.Warn("Couldn't open new log file, leaving the old one") return err } - l.logfile.Close() + + if l.logfile != nil { + err = l.logfile.Close() + if err != nil { + l.Warn("Failed to close old log file") + } + l.logfile = newLogfile + return nil + } + + //target was console l.logfile = newLogfile + l.write = func(message string) error { + _, err := l.logfile.WriteString(message) + return err + } return nil } diff --git a/tests/logging_test.go b/tests/logging_test.go index a155579..5e3f91d 100644 --- a/tests/logging_test.go +++ b/tests/logging_test.go @@ -182,6 +182,20 @@ func TestLogger(t *testing.T) { assert.Equal(t, "[ERROR] Test error 4\n", actual) }) + t.Run("Test SetConsole", func(t *testing.T) { + log.Level = logging.INFO + testStr := "should not be in logfile" + log.SetConsole() + + lastInFile1, err := getLastLineWithSeek(logpath) + if err != nil { + t.Fatalf("Failed to fetch last line in log file: %s", err) + } + + log.Info(testStr) + assert.NotEqual(t, lastInFile1, testStr) + }) + t.Run("Test SetFile", func(t *testing.T) { log.Level = logging.ERROR