adriangb opened a new pull request, #703:
URL: https://github.com/apache/arrow-rs-object-store/pull/703
## Summary
Adds `ObjectStoreOperation { kind, location, backend }` carried via
`http::Request::extensions` so a wrapping `HttpService` (tower layer, reqwest
middleware, etc.) can produce useful trace spans without sniffing URLs and
headers.
`http::Extensions` is in-process only, so this is invisible on the wire — no
behavior change for remote servers.
## Scope
This PR instruments only the **HTTP** (WebDAV) backend: get / head / put /
delete / copy / list (5 sites). The mechanism is in place and proven
end-to-end, but AWS, GCP, and Azure each have their own request-construction
style and are best landed as separate follow-up PRs (one per backend) to keep
review surface small.
## Mechanism
- `OperationKind` enum (`Get | Head | Put | PutMultipart | Delete | Copy |
List | ListWithDelimiter`), `#[non_exhaustive]` for forward compatibility.
- `ObjectStoreOperation::new(kind, backend).with_location(path)` — also
`#[non_exhaustive]`.
- `OperationKind::as_str()` returns a snake_case identifier suitable for
span attributes (`object_store.operation = \"get\"` etc.).
- `HttpRequestBuilder::operation(op)` helper that calls
`request.extensions_mut().insert(op)` so it composes with the existing
`extensions(http::Extensions)` setter without clobbering user-provided
extensions.
## One subtle ordering constraint
`GetOptionsExt::with_get_options` calls `self.extensions(extensions)` which
**overwrites** the entire `http::Extensions` (existing behavior — not changed
by this PR). So `.operation(...)` must be called *after*
`.with_get_options(...)` on the get path. This is documented inline at the call
site. A follow-up could make `extensions()` additive instead of overwriting if
reviewers prefer that.
## Reading on the receiving side
\`\`\`rust
async fn call(&self, req: HttpRequest) -> Result<HttpResponse, HttpError> {
if let Some(op) = req.extensions().get::<ObjectStoreOperation>() {
span.set_attribute(\"object_store.operation\", op.kind.as_str());
if let Some(loc) = &op.location {
span.set_attribute(\"object_store.path\", loc.as_ref());
}
span.set_attribute(\"object_store.backend\", op.backend);
}
self.inner.call(req).await
}
\`\`\`
## Independence
One of three independent additions for better HTTP integration seams. The
others are \`impl HttpService for ClientWithMiddleware\` and
\`TowerHttpConnector\`. Each PR is self-contained; they can be reviewed in any
order. A tracking issue will follow once all three drafts are CI-green.
## Test plan
- [x] 3 new unit tests in \`http::client::tests\` using a recording
\`HttpService\` wrapper to assert kind/location/backend per operation (get,
put, delete)
- [x] \`cargo test --features=aws,azure,gcp,http --lib\` (190 tests pass)
- [x] \`cargo fmt --all -- --check\`
- [x] \`cargo clippy --features=aws,azure,gcp,http --lib --tests -- -D
warnings\`
- [ ] CI green
- [ ] Follow-ups: instrument AWS, GCP, Azure backends in separate PRs
🤖 Generated with [Claude Code](https://claude.com/claude-code)
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]