[A-1511] Add OTel spans for repo-checkout git operations - #4098
Conversation
1ba8dbb to
6578fd5
Compare
aff0469 to
c19c2e4
Compare
6578fd5 to
01e4b00
Compare
fa62ad8 to
2223a68
Compare
Add opt-in per-operation git.* child spans (and a handful of attributes) inside the default checkout so a trace shows a waterfall, making the slow step obvious. Gated behind --trace-git-checkout / BUILDKITE_TRACE_GIT_CHECKOUT (default off) so the added span volume is only paid by agents that ask for it. This is pure instrumentation — no git commands, retry policy, or checkout behaviour change. Adapted to the multi-file checkout refactor: spans live in the files owning each operation (checkout.go, checkout_fetch.go, checkout_mirror.go).
6c0a7d7 to
e7fdf5c
Compare
e7fdf5c to
6a85428
Compare
d45acc4 to
6999f72
Compare
6999f72 to
a7d8017
Compare
--trace-git-checkout flag
zhming0
left a comment
There was a problem hiding this comment.
More Otel span the better 🙌🏿 , but I wonder if we can make them less invasive in our code, perhaps we can start by thinking if the flag is worth it.
There was a problem hiding this comment.
I didn't find a concrete defect in the latest revision. Making the git.* spans automatic for either tracing backend across the default checkout path is cross-cutting enough to warrant a human sanity-check.
Want to dig deeper?
Paste this into your agent to explore the findings from this review's Buildkite build:
Download the buildsworth logs from build 8013, then answer my questions about the findings.
Install the reading-buildsworth-logs skill to run this.
--trace-git-checkout flag| "checkout.repo_name": redact.URLCredentials(e.Repository), | ||
| "checkout.refspec": e.RefSpec, | ||
| "checkout.commit": e.Commit, | ||
| "checkout.attempt": strconv.Itoa(previousAttempts + 1), |
There was a problem hiding this comment.
[not blocking] I wonder if this previous attempts attribute is reasonable. Because when we are looking at Otel Spans, they show up in waterfall diagram and it's pretty clear which span is the first and which span is the second.
I recommend a reconsideration but it's not a blocker.
There was a problem hiding this comment.
The main benefit I have in mind for recording the checkout.attempt field is the convenience of querying these spans where there have been retries. I can remove if enumerating/aggregating sibling spans is easy enough.
| func (e *Executor) traceOpSpan(ctx context.Context, name string) (tracetools.Span, context.Context) { | ||
| return tracetools.StartSpanFromContext(ctx, name, e.TracingBackend) | ||
| } |
There was a problem hiding this comment.
[Not blocking, a question] Am I right that the main intention of this abstraction is so people won't need to pass in e.TracingBackend?
There was a problem hiding this comment.
In another word, do we want to consider making repo name a parameter in this helper? so it can set a consistent attribute?
There was a problem hiding this comment.
For me, it was a choice between
1. Inline StartSpanFromContext
mirrorSpan, mirrorCtx := tracetools.StartSpanFromContext(ctx, "git.mirror.update", e.TracingBackend)
mirrorSpan.AddAttributes(…)
mirrorDir, err = e.getOrUpdateMirrorDir(mirrorCtx, e.Repository)
mirrorSpan.FinishWithError(err)2. e.traceOpSpan
mirrorSpan, mirrorCtx := e.traceOpSpan(ctx, "git.mirror.update")
mirrorSpan.AddAttributes(…)
mirrorDir, err = e.getOrUpdateMirrorDir(mirrorCtx, e.Repository)
mirrorSpan.FinishWithError(err)I chose (2) so that e.TracingBackend can be implied. It returns a plain old Span so I think it's okay for the caller to manage the Finish part without an equivalent abstraction.
What do you think? What benefit would an abstraction for Finishing the span give us?
Aside, might the traceOpSpan name be confusing? Perhaps you have a better name in mind?
zhming0
left a comment
There was a problem hiding this comment.
I have doubts in various minor details but they aren't blocking nor one-way door so LGTM 👍
Description
Emit additional
git.*OpenTelemetry spans so customers can see what goes on behind the "Preparing working directory" /repo-checkoutspan and figure out ways to speed up the checkout phase of their jobs.Spans added
git.*builds off its child contextgetOrUpdateMirrorDirclonelockgitCloneupdatelockgitFetchgitClonegitRepackifGitMirrorCheckoutModeis dissociategitClonegitCleanSubmodulesandgitCleangit lfs installfetchSourceverifyCommitsetupSparseCheckoutgitCheckoutupdateGitSubmodulesgetOrUpdateMirrorDir(see git.mirror.update above)git submodule updategitLFSFetchCheckoutgitCleanandgitCleanSubmodulesScreenshot
Changes
traceOp*helper functions to internal/job/tracing.goTesting
go test ./...). Buildkite employees may check this if the pipeline has run automatically.go tool gofumpt -extra -w .)Disclosures / Credits
While this PR was produced with the help of advanced automation tools, I take full credit and responsibility for it.