Skip to content

Commit

Permalink
internal/logger: send any logging message to stderr
Browse files Browse the repository at this point in the history
Our internal logger was sending Error messages to stderr and all the
other levels (Info, Warn and Debug) to stdout. However, both POSIX stds
and part of the utility development community that "diagnostic" messages
should go only to stderr, leaving stdout for the actual results of the
program. Even though the logger messages are quite differet (prefixed by
date, file and line) from lab's actual results, it forces a program
receiving the stdout though a, eg., pipe to filter logger messages if
only the actual results are required.

One example of this issue was presented in lab's issue 789 [1], which
was solved in a different way, but failed because a "diagnostic" message
was feed into the `source` utility.

This patch redirects all logging messages (not actual lab results) to
stderr.

[1] #789

Signed-off-by: Bruno Meneguele <bmeneg@redhat.com>
  • Loading branch information
bmeneg committed Feb 12, 2022
1 parent f68cb49 commit 81de4e1
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 23 deletions.
32 changes: 14 additions & 18 deletions internal/logger/logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,9 @@ func GetInstance() *Logger {
// Setting Lmsgprefix preffix make the prefix to be printed before
// the actual message, but after the LstdFlags (date and time)
errorLogger: log.New(os.Stderr, "ERROR: ", log.LstdFlags|log.Lmsgprefix),
warnLogger: log.New(os.Stdout, "WARNING: ", log.LstdFlags|log.Lmsgprefix),
infoLogger: log.New(os.Stdout, "", log.LstdFlags|log.Lmsgprefix),
debugLogger: log.New(os.Stdout, "DEBUG: ", log.LstdFlags|log.Lmsgprefix),
warnLogger: log.New(os.Stderr, "WARNING: ", log.LstdFlags|log.Lmsgprefix),
infoLogger: log.New(os.Stderr, "", log.LstdFlags|log.Lmsgprefix),
debugLogger: log.New(os.Stderr, "DEBUG: ", log.LstdFlags|log.Lmsgprefix),
}
})
return internalLogger
Expand All @@ -68,13 +68,13 @@ func (l *Logger) LogLevel() int {
return l.level
}

// SetStdDest sets what's the desired stdout and stderr for the internal
// log. It can be any io.Writer value.
func (l *Logger) SetStdDest(stdout io.Writer, stderr io.Writer) {
l.errorLogger.SetOutput(stderr)
l.warnLogger.SetOutput(stdout)
l.infoLogger.SetOutput(stdout)
l.debugLogger.SetOutput(stdout)
// SetStdDest sets what's the desired output stream for the internal log.
// It can be any io.Writer value.
func (l *Logger) SetStdDest(dest io.Writer) {
l.errorLogger.SetOutput(dest)
l.warnLogger.SetOutput(dest)
l.infoLogger.SetOutput(dest)
l.debugLogger.SetOutput(dest)
}

// printKeysAndValues prints the keys and valus, as pairs, passed to those
Expand Down Expand Up @@ -133,8 +133,7 @@ func (l *Logger) Fatalln(values ...interface{}) {
}

// Error prints error messages (prefixed with "ERROR:").
// These parameters match the retryablehttp.LeveledLogger, which we want to
// satisfy for silencing their debug messages being printed in the stdout.
// These parameters match the retryablehttp.LeveledLogger.
// Error message are always printed, regardless the log level.
func (l *Logger) Error(msg string, keysAndValues ...interface{}) {
if l.level >= LogLevelError {
Expand Down Expand Up @@ -162,8 +161,7 @@ func (l *Logger) Errorln(values ...interface{}) {
}

// Warn prints warning messages (prefixed with "WARNING:").
// These parameters match the retryablehttp.LeveledLogger, which we want to
// satisfy for silencing their debug messages being printed in the stdout.
// These parameters match the retryablehttp.LeveledLogger.
// Warning messages require at least LogLevelInfo level.
func (l *Logger) Warn(msg string, keysAndValues ...interface{}) {
if l.level >= LogLevelInfo {
Expand Down Expand Up @@ -191,8 +189,7 @@ func (l *Logger) Warnln(values ...interface{}) {
}

// Info prints informational messages (prefixed with "INFO:").
// These parameters match the retryablehttp.LeveledLogger, which we want to
// satisfy for silencing their debug messages being printed in the stdout.
// These parameters match the retryablehttp.LeveledLogger.
// Info messages require at least LogLevelInfo level.
func (l *Logger) Info(msg string, keysAndValues ...interface{}) {
if l.level >= LogLevelInfo {
Expand Down Expand Up @@ -220,8 +217,7 @@ func (l *Logger) Infoln(values ...interface{}) {
}

// Debug prints warning messages (prefixed with "DEBUG:").
// These parameters match the retryablehttp.LeveledLogger, which we want to
// satisfy for silencing thier debug messages being printed in the stdout.
// These parameters match the retryablehttp.LeveledLogger.
// Debug messages require at least LogLevelDebug level.
func (l *Logger) Debug(msg string, keysAndValues ...interface{}) {
if l.level >= LogLevelDebug {
Expand Down
10 changes: 5 additions & 5 deletions internal/logger/logger_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,13 +90,13 @@ func TestLogFunctions(t *testing.T) {
t.Run(test.name, func(t *testing.T) {
// Redirect system stdout to our own so we can check log output
// to stdout
oldStdout := os.Stdout
oldStderr := os.Stderr
r, w, err := os.Pipe()
if err != nil {
t.Errorf("failed to redirect stdout: %s", err)
t.Errorf("failed to redirect stderr: %s", err)
}
os.Stdout = w
log.SetStdDest(w, w)
os.Stderr = w
log.SetStdDest(w)
outChan := make(chan string)

test.fn("test")
Expand All @@ -110,7 +110,7 @@ func TestLogFunctions(t *testing.T) {
}()

w.Close()
os.Stdout = oldStdout
os.Stderr = oldStderr
out := <-outChan

regex := regexp.MustCompile(test.prefix + " logger_test.go:[0-9]+: test")
Expand Down

0 comments on commit 81de4e1

Please sign in to comment.