Display reqwest error source (#10004)

## Problem

Reqwest errors don't include details about the inner source error. This
means that we get opaque errors like:

```
receive body: error sending request for url (http://localhost:9898/v1/location_config)
```

Instead of the more helpful:

```
receive body: error sending request for url (http://localhost:9898/v1/location_config): operation timed out
```

Touches #9801.

## Summary of changes

Include the source error for `reqwest::Error` wherever it's displayed.
This commit is contained in:
Erik Grinaker
2024-12-04 14:05:53 +01:00
committed by GitHub
parent 9a4157dadb
commit 699a213c5d
7 changed files with 33 additions and 14 deletions

View File

@@ -5,6 +5,7 @@
//! ```text //! ```text
//! .neon/safekeepers/<safekeeper id> //! .neon/safekeepers/<safekeeper id>
//! ``` //! ```
use std::error::Error as _;
use std::future::Future; use std::future::Future;
use std::io::Write; use std::io::Write;
use std::path::PathBuf; use std::path::PathBuf;
@@ -26,7 +27,7 @@ use crate::{
#[derive(Error, Debug)] #[derive(Error, Debug)]
pub enum SafekeeperHttpError { pub enum SafekeeperHttpError {
#[error("Reqwest error: {0}")] #[error("request error: {0}{}", .0.source().map(|e| format!(": {e}")).unwrap_or_default())]
Transport(#[from] reqwest::Error), Transport(#[from] reqwest::Error),
#[error("Error: {0}")] #[error("Error: {0}")]

View File

@@ -1,4 +1,4 @@
use std::collections::HashMap; use std::{collections::HashMap, error::Error as _};
use bytes::Bytes; use bytes::Bytes;
use detach_ancestor::AncestorDetached; use detach_ancestor::AncestorDetached;
@@ -25,10 +25,10 @@ pub struct Client {
#[derive(thiserror::Error, Debug)] #[derive(thiserror::Error, Debug)]
pub enum Error { pub enum Error {
#[error("send request: {0}")] #[error("send request: {0}{}", .0.source().map(|e| format!(": {e}")).unwrap_or_default())]
SendRequest(reqwest::Error), SendRequest(reqwest::Error),
#[error("receive body: {0}")] #[error("receive body: {0}{}", .0.source().map(|e| format!(": {e}")).unwrap_or_default())]
ReceiveBody(reqwest::Error), ReceiveBody(reqwest::Error),
#[error("receive error body: {0}")] #[error("receive error body: {0}")]

View File

@@ -1,3 +1,4 @@
use std::error::Error as _;
use std::time::SystemTime; use std::time::SystemTime;
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
@@ -350,7 +351,11 @@ impl std::fmt::Display for UploadError {
match self { match self {
Rejected(code) => write!(f, "server rejected the metrics with {code}"), Rejected(code) => write!(f, "server rejected the metrics with {code}"),
Reqwest(e) => write!(f, "request failed: {e}"), Reqwest(e) => write!(
f,
"request failed: {e}{}",
e.source().map(|e| format!(": {e}")).unwrap_or_default()
),
Cancelled => write!(f, "cancelled"), Cancelled => write!(f, "cancelled"),
} }
} }

View File

@@ -8,6 +8,7 @@
//! etc. //! etc.
use reqwest::{IntoUrl, Method, StatusCode}; use reqwest::{IntoUrl, Method, StatusCode};
use std::error::Error as _;
use utils::{ use utils::{
http::error::HttpErrorBody, http::error::HttpErrorBody,
id::{NodeId, TenantId, TimelineId}, id::{NodeId, TenantId, TimelineId},
@@ -26,7 +27,7 @@ pub struct Client {
#[derive(thiserror::Error, Debug)] #[derive(thiserror::Error, Debug)]
pub enum Error { pub enum Error {
/// Failed to receive body (reqwest error). /// Failed to receive body (reqwest error).
#[error("receive body: {0}")] #[error("receive body: {0}{}", .0.source().map(|e| format!(": {e}")).unwrap_or_default())]
ReceiveBody(reqwest::Error), ReceiveBody(reqwest::Error),
/// Status is not ok, but failed to parse body as `HttpErrorBody`. /// Status is not ok, but failed to parse body as `HttpErrorBody`.

View File

@@ -1,3 +1,4 @@
use std::error::Error as _;
use std::sync::Arc; use std::sync::Arc;
use std::{collections::HashMap, time::Duration}; use std::{collections::HashMap, time::Duration};
@@ -172,7 +173,7 @@ struct ComputeHookNotifyRequest {
#[derive(thiserror::Error, Debug)] #[derive(thiserror::Error, Debug)]
pub(crate) enum NotifyError { pub(crate) enum NotifyError {
// Request was not send successfully, e.g. transport error // Request was not send successfully, e.g. transport error
#[error("Sending request: {0}")] #[error("Sending request: {0}{}", .0.source().map(|e| format!(": {e}")).unwrap_or_default())]
Request(#[from] reqwest::Error), Request(#[from] reqwest::Error),
// Request could not be serviced right now due to ongoing Operation in control plane, but should be possible soon. // Request could not be serviced right now due to ongoing Operation in control plane, but should be possible soon.
#[error("Control plane tenant busy")] #[error("Control plane tenant busy")]

View File

@@ -1,7 +1,9 @@
use crate::tenant_shard::ObservedState; use crate::tenant_shard::ObservedState;
use pageserver_api::shard::TenantShardId; use pageserver_api::shard::TenantShardId;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::{collections::HashMap, time::Duration}; use std::collections::HashMap;
use std::error::Error as _;
use std::time::Duration;
use tokio_util::sync::CancellationToken; use tokio_util::sync::CancellationToken;
use hyper::Uri; use hyper::Uri;
@@ -17,11 +19,14 @@ pub(crate) struct PeerClient {
#[derive(thiserror::Error, Debug)] #[derive(thiserror::Error, Debug)]
pub(crate) enum StorageControllerPeerError { pub(crate) enum StorageControllerPeerError {
#[error("failed to deserialize error response with status code {0} at {1}: {2}")] #[error(
"failed to deserialize error response with status code {0} at {1}: {2}{}",
.2.source().map(|e| format!(": {e}")).unwrap_or_default()
)]
DeserializationError(StatusCode, Url, reqwest::Error), DeserializationError(StatusCode, Url, reqwest::Error),
#[error("storage controller peer API error ({0}): {1}")] #[error("storage controller peer API error ({0}): {1}")]
ApiError(StatusCode, String), ApiError(StatusCode, String),
#[error("failed to send HTTP request: {0}")] #[error("failed to send HTTP request: {0}{}", .0.source().map(|e| format!(": {e}")).unwrap_or_default())]
SendError(reqwest::Error), SendError(reqwest::Error),
#[error("Cancelled")] #[error("Cancelled")]
Cancelled, Cancelled,

View File

@@ -1,3 +1,5 @@
use std::error::Error as _;
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
use futures::Future; use futures::Future;
use hex::FromHex; use hex::FromHex;
@@ -30,14 +32,18 @@ impl std::fmt::Display for Error {
match &self.kind { match &self.kind {
ErrorKind::RequestSend(e) => write!( ErrorKind::RequestSend(e) => write!(
f, f,
"Failed to send a request. Context: {}, error: {}", "Failed to send a request. Context: {}, error: {}{}",
self.context, e self.context,
e,
e.source().map(|e| format!(": {e}")).unwrap_or_default()
), ),
ErrorKind::BodyRead(e) => { ErrorKind::BodyRead(e) => {
write!( write!(
f, f,
"Failed to read a request body. Context: {}, error: {}", "Failed to read a request body. Context: {}, error: {}{}",
self.context, e self.context,
e,
e.source().map(|e| format!(": {e}")).unwrap_or_default()
) )
} }
ErrorKind::ResponseStatus(status) => { ErrorKind::ResponseStatus(status) => {