Files
air/runner/logger_test.go
lif 0d9e5e1344 fix: route air's own log messages to stderr instead of stdout (#887)
* fix: route air's own log messages to stderr instead of stdout

Air's internal loggers (main, build, runner, watcher) were writing to
stdout, causing air's messages to intermix with the user's application
output. This made it impossible to separate them with shell redirections
like `air 2>/dev/null`.

Change the log output destination from os.Stdout/color.Output to
os.Stderr/color.Error so air's messages go to stderr while the user's
app output remains on stdout.

Also remove dead `c.Stdout` and `c.Stderr` assignments in startCmd()
on all platforms — these had no effect after StdoutPipe()/StderrPipe()
were already called.

Fixes #744

Signed-off-by: majiayu000 <1835304752@qq.com>

* test: add regression test for logger stderr routing

Signed-off-by: majiayu000 <1835304752@qq.com>

* fix: route warning messages in config.go to stderr

Signed-off-by: majiayu000 <1835304752@qq.com>

* fix: update smoke test to check stderr for air log messages

Since air's log output now goes to stderr, the smoke test must check
nohup.err instead of nohup.out for the "running" message.

Signed-off-by: majiayu000 <1835304752@qq.com>

* fix: print splash banner to stderr

---------

Signed-off-by: majiayu000 <1835304752@qq.com>
Co-authored-by: xiantang <zhujingdi1998@gmail.com>
2026-04-03 16:20:57 +08:00

53 lines
1.1 KiB
Go

package runner
import (
"io"
"os"
"strings"
"testing"
)
func TestLogFuncWritesToStderr(t *testing.T) {
t.Parallel()
// Capture stderr
oldStderr := os.Stderr
rErr, wErr, err := os.Pipe()
if err != nil {
t.Fatalf("failed to create stderr pipe: %v", err)
}
os.Stderr = wErr
// Capture stdout
oldStdout := os.Stdout
rOut, wOut, err := os.Pipe()
if err != nil {
t.Fatalf("failed to create stdout pipe: %v", err)
}
os.Stdout = wOut
logFn := newLogFunc(rawColor, cfgLog{})
logFn("test message from air")
wErr.Close()
wOut.Close()
os.Stderr = oldStderr
os.Stdout = oldStdout
stderrOut, err := io.ReadAll(rErr)
if err != nil {
t.Fatalf("failed to read stderr: %v", err)
}
stdoutOut, err := io.ReadAll(rOut)
if err != nil {
t.Fatalf("failed to read stdout: %v", err)
}
if !strings.Contains(string(stderrOut), "test message from air") {
t.Errorf("expected log output on stderr, got: %q", stderrOut)
}
if strings.Contains(string(stdoutOut), "test message from air") {
t.Errorf("log output should not appear on stdout, got: %q", stdoutOut)
}
}