diff --git a/server/src/error.rs b/server/src/error.rs index 0c7a9e8a..5c33ff5f 100644 --- a/server/src/error.rs +++ b/server/src/error.rs @@ -6,7 +6,7 @@ use serde::Serialize; use serde_json::json; use tracing::debug; -use crate::types::EdgeToken; +use crate::types::{EdgeToken, UnleashBadRequest}; pub const TRUST_PROXY_PARSE_ERROR: &str = "needs to be a valid ip address (ipv4 or ipv6) or a valid cidr (ipv4 or ipv6)"; @@ -98,7 +98,7 @@ pub enum EdgeError { FeatureNotFound(String), PersistenceError(String), EdgeMetricsError, - EdgeMetricsRequestError(StatusCode), + EdgeMetricsRequestError(StatusCode, Option), EdgeTokenError, EdgeTokenParseError, InvalidBackupFile(String, String), @@ -158,8 +158,8 @@ impl Display for EdgeError { EdgeError::InvalidServerUrl(msg) => write!(f, "Failed to parse server url: [{msg}]"), EdgeError::EdgeTokenError => write!(f, "Edge token error"), EdgeError::EdgeTokenParseError => write!(f, "Failed to parse token response"), - EdgeError::EdgeMetricsRequestError(status_code) => { - write!(f, "Failed to post metrics with status code: {status_code}") + EdgeError::EdgeMetricsRequestError(status_code, message) => { + write!(f, "Failed to post metrics with status code: {status_code} and response {message:?}") } EdgeError::AuthorizationPending => { write!(f, "No validation for token has happened yet") @@ -226,7 +226,7 @@ impl ResponseError for EdgeError { EdgeError::FrontendNotYetHydrated(_) => StatusCode::NETWORK_AUTHENTICATION_REQUIRED, EdgeError::ContextParseError => StatusCode::BAD_REQUEST, EdgeError::ServiceAccountTokenNotEnabled => StatusCode::NETWORK_AUTHENTICATION_REQUIRED, - EdgeError::EdgeMetricsRequestError(status_code) => *status_code, + EdgeError::EdgeMetricsRequestError(status_code, _) => *status_code, EdgeError::HealthCheckError(_) => StatusCode::INTERNAL_SERVER_ERROR, EdgeError::ReadyCheckError(_) => StatusCode::INTERNAL_SERVER_ERROR, EdgeError::ClientHydrationFailed(_) => StatusCode::INTERNAL_SERVER_ERROR, diff --git a/server/src/http/background_send_metrics.rs b/server/src/http/background_send_metrics.rs index 5bfb97a5..a8d11a5d 100644 --- a/server/src/http/background_send_metrics.rs +++ b/server/src/http/background_send_metrics.rs @@ -36,7 +36,7 @@ pub async fn send_metrics_task( if !batch.applications.is_empty() || !batch.metrics.is_empty() { if let Err(edge_error) = unleash_client.send_batch_metrics(batch.clone()).await { match edge_error { - EdgeError::EdgeMetricsRequestError(status_code) => { + EdgeError::EdgeMetricsRequestError(status_code, message) => { METRICS_UPSTREAM_HTTP_ERRORS .with_label_values(&[status_code.as_str()]) .inc(); @@ -46,9 +46,7 @@ pub async fn send_metrics_task( size_of_batch(&batch) ), StatusCode::BAD_REQUEST => { - error!( - "We couldn't format metrics properly. Will drop what we had" - ); + error!("Unleash said [{message:?}]. Dropping this metric bucket to avoid consuming too much memory"); } _ => { warn!("Failed to send metrics. Status code was {status_code}. Will reinsert metrics for next attempt"); diff --git a/server/src/http/unleash_client.rs b/server/src/http/unleash_client.rs index 4abe7f55..a9b4056a 100644 --- a/server/src/http/unleash_client.rs +++ b/server/src/http/unleash_client.rs @@ -17,6 +17,7 @@ use unleash_types::client_features::ClientFeatures; use unleash_types::client_metrics::ClientApplication; use crate::cli::ClientIdentity; +use crate::error::EdgeError::EdgeMetricsRequestError; use crate::error::{CertificateError, FeatureError}; use crate::metrics::client_metrics::MetricsBatch; use crate::tls::build_upstream_certificate; @@ -425,7 +426,13 @@ impl UnleashClient { if result.status().is_success() { Ok(()) } else { - Err(EdgeError::EdgeMetricsRequestError(result.status())) + match result.status() { + StatusCode::BAD_REQUEST => Err(EdgeError::EdgeMetricsRequestError( + result.status(), + result.json().await.ok(), + )), + _ => Err(EdgeMetricsRequestError(result.status(), None)), + } } } diff --git a/server/src/types.rs b/server/src/types.rs index 19004f85..ed89526f 100644 --- a/server/src/types.rs +++ b/server/src/types.rs @@ -185,6 +185,21 @@ pub struct TokenRefresh { pub last_check: Option>, } +#[derive(Clone, Deserialize, Serialize, Debug)] +pub struct UnleashValidationDetail { + pub path: Option, + pub description: Option, + pub message: Option, +} + +#[derive(Clone, Deserialize, Serialize, Debug)] +pub struct UnleashBadRequest { + pub id: Option, + pub name: Option, + pub message: Option, + pub details: Option>, +} + impl TokenRefresh { pub fn new(token: EdgeToken, etag: Option) -> Self { Self {