-
Notifications
You must be signed in to change notification settings - Fork 20
Add OpenTelemetry tracing for individual Go tests #321
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Parse go test -json output during the test phase to create spans for each test. Test spans are children of the package span, showing test parallelism and duration in build traces. Co-authored-by: Ona <[email protected]>
CompositeReporter now delegates GetGoTestTracer to any wrapped reporter that implements TestTracingReporter, enabling test tracing when using multiple reporters. Co-authored-by: Ona <[email protected]>
Test tracing is opt-in since it can generate many spans for large test suites. Use --enable-test-tracing to create OpenTelemetry spans for individual Go tests. Co-authored-by: Ona <[email protected]>
e8e3a3e to
ea21843
Compare
In non-verbose mode, only show package-level output and failed test output. Buffer test output and flush on failure to preserve error details while reducing noise for passing tests. Co-authored-by: Ona <[email protected]>
Simplify the design by detecting go test commands in the run() function rather than using a separate TestExecutor. This removes: - TestExecutor field from packageBuild - Special case in executeBuildPhase - GetGoTestTracer from Reporter interface - CompositeReporter delegation for test tracing The tracing is now an implementation detail of command execution. Co-authored-by: Ona <[email protected]>
kylos101
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, I added some questions and nits, but nothing blocking. I didn't get a chance to test, but see you included success and failures, which is great. Also, i see in the results a test ran for 200ms (so much longer than others).
| key := spanKey(event.Package, event.Test) | ||
| if output, ok := testOutput[key]; ok { | ||
| for _, line := range output { | ||
| _, _ = outputWriter.Write([]byte(line)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit, not blocking:
We don't handle when outputWriter is nil for the fail scenario, but do above.
| type testSpanData struct { | ||
| span trace.Span | ||
| startTime time.Time | ||
| pkg string |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Question, not blocking:
How is the pkg field being used? I see it is being set, but not read anywhere.
|
|
||
| // goTestEvent represents a single event from `go test -json` output. | ||
| // See https://pkg.go.dev/cmd/test2json for the format specification. | ||
| type goTestEvent struct { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Question, not blocking:
I see FailedBuild was omitted, intentional?
| _, _ = outputWriter.Write([]byte(event.Output)) | ||
| } else if event.Test == "" { | ||
| // Non-verbose: always show package-level output | ||
| _, _ = outputWriter.Write([]byte(event.Output)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Question, not blocking:
Did you intend to have this be event.Package, instead of Output?
| func (t *GoTestTracer) handleEvent(event *goTestEvent) { | ||
| switch event.Action { | ||
| case "run": | ||
| t.handleRun(event) | ||
| case "pause": | ||
| t.handlePause(event) | ||
| case "cont": | ||
| t.handleCont(event) | ||
| case "pass", "fail", "skip": | ||
| t.handleEnd(event) | ||
| case "output": | ||
| // Output is already written to outputWriter | ||
| case "start": | ||
| // Package test started - we could create a package-level span here | ||
| t.handlePackageStart(event) | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Observation, not blocking:
We are missing bench, which I guess is generally only done locally
Description
Add per-test OpenTelemetry spans during Go package builds. When tracing is enabled, leeway parses
go test -jsonoutput and creates child spans for each test under the package span. This provides visibility into individual test duration and parallelism in build traces.Can be enabled by passing the
--enable-test-tracingflag, disabled by defaulthttps://ui.honeycomb.io/gitpod/environments/ci/datasets/leeway/result/FhLg2E7Cfp4/trace/8cAj6RnnZpf?fields%5B%5D=s_name&fields%5B%5D=s_serviceName&fields%5B%5D=c_leeway.package.name&fields%5B%5D=c_leeway.package.last_phase&span=14df73420d330fac
https://ui.honeycomb.io/gitpod/environments/ci/datasets/leeway/result/chTYCtKiNU8/trace/3gqNBXCwcwZ?fields%5B%5D=s_name&fields%5B%5D=s_serviceName&fields%5B%5D=c_leeway.package.name&fields%5B%5D=c_leeway.package.last_phase&span=2bc30322f9351793
Related Issue(s)
Fixes CORE-6451
How to test