Description
As suggested in #23213 (comment), I'm filing a new issue with a proposal for how to improve t.Log
and t.Logf
.
What version of Go are you using (go version
)?
go version go1.9.2
Does this issue reproduce with the latest release?
Yes
What operating system and processor architecture are you using (go env
)?
I'm on Darwin, amd64, but this affects all systems/architectures.
Motivation
Consider the following (silly) automated tests:
func TestFoo(t *testing.T) {
t.Parallel()
for i := 0; i < 15; i++ {
t.Logf("%d", i)
time.Sleep(3 * time.Second)
}
}
func TestBar(t *testing.T) {
t.Parallel()
for i := 0; i < 15; i++ {
t.Logf("%d", i)
time.Sleep(2 * time.Second)
}
}
func TestBaz(t *testing.T) {
t.Parallel()
for i := 0; i < 15; i++ {
t.Logf("%d", i)
time.Sleep(1 * time.Second)
}
}
If I run go test -v
, I get no log output until all of TestFoo
is done, then no output until all of TestBar
is done, and again no more output until all of TestBaz
is done. This is fine if the tests are working, but if there is some sort of bug, there are a few cases where buffering log output is problematic:
- When iterating locally, I want to be able to make a change, run my tests, see what's happening in the logs immediately to understand what's going on, hit CTRL+C to shut the test down early if necessary, make another change, re-run the tests, and so on. If
TestFoo
is slow (e.g., it's an integration test), I get no log output until the very end of the test. This significantly slows down iteration. - If
TestFoo
has a bug that causes it to hang and never complete, I'd get no log output whatsoever. In these cases,t.Log
andt.Logf
are of no use at all. This makes debugging very difficult. - Moreover, not only do I get no log output, but if the test hangs too long, either the Go test timeout kills the test after 10 minutes, or if I increase that timeout, many CI servers will also kill off tests if there is no log output after a certain amount of time (e.g., 10 minutes in CircleCI). So now my tests are killed and I have nothing in the logs to tell me what happened.
Current workarounds
The main workaround is to replace all t.Logf
calls with either fmt.Printf
or a custom logger. Since we often want to iterate quickly on tests, and since debugging is such an important use case, in practice, that means we never use t.Logf
at all.
This seems like a missed opportunity. Go has a lot of powerful testing tools built in, and we usually pass the t
variable around to many test methods so they can call t.Fatal()
, t.Name()
, etc. It would be great if t
had a logger built in that we could actually use. Honestly, the only thing it's really missing is some way to configure the logger to write to stdout
immediately, rather than buffering.
Possible solutions
Probably the easiest way to improve t.Log
and t.Logf
is to add a -test.streamlogs
option to the go test
command. When this option is set, t.Log
and t.Logf
write to stdout
immediately, instead of buffering.
This means the output format with this option set wouldn't be backwards compatible, but the expectation is that this option would only be used for local debugging, and not something used in your CI system.