diff --git a/Cargo.toml b/Cargo.toml index dbc77491..efbd8285 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,6 +36,7 @@ futures-util = { version = "0.3.15", optional = true } secrecy = "0.8.0" cfg-if = "1.0.0" either = "1.8.0" +tracing = { version = "0.1", optional = true } [dev-dependencies] tokio = { version = "1.17.0", default-features = false, features = [ @@ -48,6 +49,7 @@ wiremock = "0.5.3" [features] default = ["native-tls"] rustls = ["rustls-tls"] # Leagcy support (<=0.17.0) +trace = ["tracing"] # Enables native-tls specific functionality not available by default. native-tls = ["reqwest/native-tls"] diff --git a/src/lib.rs b/src/lib.rs index 1803a353..69625276 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -179,6 +179,12 @@ pub use self::{ page::Page, }; +#[cfg(feature = "trace")] +use tracing::{self, field}; + +#[cfg(feature = "trace")] +const GITHUB_SERVICE: &str = "github.com"; + /// A convenience type with a default error type of [`Error`]. pub type Result = std::result::Result; @@ -893,6 +899,38 @@ impl Octocrab { } } + #[cfg(feature = "trace")] + #[tracing::instrument( + level="info", + name="github api call", + skip(self, request_builder), + fields(err, attempt, url=field::Empty, service.name=field::Empty, http.method=field::Empty, http.url=field::Empty, status_code=field::Empty) + )] + async fn send_call(&self, request_builder: reqwest::RequestBuilder, attempt: u32) -> Result { + let span = tracing::Span::current(); + let service = self.base_url.host_str().unwrap_or(GITHUB_SERVICE); + span.record("service.name", service); + let request = request_builder.build()?; + span.record("http.method", request.method().as_str()); + span.record("http.url", request.url().as_str()); + let result = self.client.execute(request).await; + match &result { + Ok(v) => { + span.record("status_code", v.status().as_u16()); + }, + Err(e) => { + let status = e.status().and_then(|s| Some(s.as_u16())); + span.record("status_code", status); + }, + }; + result + } + + #[cfg(not(feature = "trace"))] + async fn send_call(&self, request: reqwest::RequestBuilder, _: u32) -> Result { + request.send().await + } + /// Execute the given `request` using octocrab's Client. pub async fn execute(&self, mut request: reqwest::RequestBuilder) -> Result { let mut retries = 0; @@ -920,10 +958,14 @@ impl Octocrab { } }; - let result = request.send().await; + let result = self.send_call(request, retries).await; let status = match &result { - Ok(v) => Some(v.status()), - Err(e) => e.status(), + Ok(v) => { + Some(v.status()) + }, + Err(e) => { + e.status() + }, }; if let Some(StatusCode::UNAUTHORIZED) = status { if let AuthState::Installation { ref token, .. } = self.auth_state {