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]

Reply via email to