feat(metrics): add injector service metrics and observability (#9945)

Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
This commit is contained in:
Shivansh Mathur
2025-11-19 15:14:48 +05:30
committed by GitHub
parent e35884ee38
commit 5e89187c49
3 changed files with 119 additions and 1 deletions

View File

@@ -17,6 +17,7 @@ pub mod core {
use crate as injector_types;
use crate::{
metrics,
types::{ContentType, InjectorRequest, InjectorResponse, IntoInjectorResponse},
vault_metadata::VaultMetadataExtractorExt,
};
@@ -332,9 +333,46 @@ pub mod core {
pub async fn injector_core(
request: InjectorRequest,
) -> error_stack::Result<InjectorResponse, InjectorError> {
let start_time = std::time::Instant::now();
logger::info!("Starting injector_core processing");
// Extract values for metrics before moving request
let vault_connector_str = format!("{:?}", request.token_data.vault_connector);
let http_method_str = format!("{:?}", request.connection_config.http_method);
// Track total number of invocations with vault connector dimension
metrics::INJECTOR_INVOCATIONS_COUNT.add(
1,
router_env::metric_attributes!(("vault_connector", vault_connector_str.clone())),
);
// Extract endpoint host for dimension (privacy-friendly)
let endpoint_host = request
.connection_config
.endpoint
.parse::<url::Url>()
.map(|url| url.host_str().unwrap_or("unknown").to_string())
.unwrap_or_else(|_| "invalid_url".to_string());
let injector = Injector::new();
injector.injector_core(request).await
let result = injector.injector_core(request).await;
// Record total request time and track success/failure
let request_duration = start_time.elapsed();
let base_attributes = router_env::metric_attributes!(
("vault_connector", vault_connector_str.clone()),
("http_method", http_method_str.clone()),
("endpoint_host", endpoint_host.clone())
);
metrics::INJECTOR_REQUEST_TIME.record(request_duration.as_secs_f64(), base_attributes);
// Track success/failure metrics
result.inspect_err(|e| {
logger::error!("Injector core failed: {:?}", e);
metrics::INJECTOR_FAILED_TOKEN_REPLACEMENTS_COUNT.add(1, base_attributes);
})
}
/// Represents a token reference found in a template string
@@ -440,6 +478,7 @@ pub mod core {
vault_data: &Value,
vault_connector: &injector_types::VaultConnectors,
) -> error_stack::Result<String, InjectorError> {
let token_replacement_start = std::time::Instant::now();
// Find all tokens using nom parser
let tokens = find_all_tokens(&template);
let mut result = template;
@@ -460,6 +499,14 @@ pub mod core {
result = result.replace(&token_pattern, &token_str);
}
// Record token replacement time with vault connector dimension
let token_replacement_duration = token_replacement_start.elapsed();
let vault_connector_str = format!("{:?}", vault_connector);
metrics::INJECTOR_TOKEN_REPLACEMENT_TIME.record(
token_replacement_duration.as_secs_f64(),
router_env::metric_attributes!(("vault_connector", vault_connector_str)),
);
Ok(result)
}
@@ -692,6 +739,21 @@ pub mod core {
Proxy::default()
};
// Track outgoing HTTP calls with dimensions
let endpoint_host = config
.endpoint
.parse::<url::Url>()
.map(|url| url.host_str().unwrap_or("unknown").to_string())
.unwrap_or_else(|_| "invalid_url".to_string());
metrics::INJECTOR_OUTGOING_CALLS_COUNT.add(
1,
router_env::metric_attributes!(
("http_method", format!("{:?}", config.http_method)),
("endpoint_host", endpoint_host)
),
);
// Send request using local standalone http client
let response = send_request(&proxy, request, None).await?;
@@ -776,6 +838,27 @@ pub mod core {
"Token injection completed successfully"
);
// Track successful token replacements with comprehensive dimensions
let endpoint_host = request
.connection_config
.endpoint
.parse::<url::Url>()
.map(|url| url.host_str().unwrap_or("unknown").to_string())
.unwrap_or_else(|_| "invalid_url".to_string());
let vault_connector_str = format!("{:?}", request.token_data.vault_connector);
let http_method_str = format!("{:?}", request.connection_config.http_method);
metrics::INJECTOR_SUCCESSFUL_TOKEN_REPLACEMENTS_COUNT.add(
1,
router_env::metric_attributes!(
("status_code", response.status_code.to_string()),
("vault_connector", vault_connector_str),
("http_method", http_method_str),
("endpoint_host", endpoint_host)
),
);
Ok(response)
}
}

View File

@@ -1,5 +1,6 @@
pub mod consts;
pub mod injector;
pub mod metrics;
pub mod types;
pub mod vault_metadata;

View File

@@ -0,0 +1,34 @@
use router_env::{counter_metric, global_meter, histogram_metric_f64};
global_meter!(GLOBAL_METER, "INJECTOR");
// Invocation metrics
counter_metric!(INJECTOR_INVOCATIONS_COUNT, GLOBAL_METER); // Total number of invocations
counter_metric!(INJECTOR_OUTGOING_CALLS_COUNT, GLOBAL_METER); // Total number of outgoing calls
counter_metric!(INJECTOR_SUCCESSFUL_TOKEN_REPLACEMENTS_COUNT, GLOBAL_METER); // Successful token replacements with status code dimensions
counter_metric!(INJECTOR_FAILED_TOKEN_REPLACEMENTS_COUNT, GLOBAL_METER); // Failed token replacements
// Performance metrics
histogram_metric_f64!(INJECTOR_REQUEST_TIME, GLOBAL_METER); // Time taken for complete injector operation
histogram_metric_f64!(INJECTOR_TOKEN_REPLACEMENT_TIME, GLOBAL_METER); // Time taken for token replacement operation
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_metrics_are_defined() {
// This test ensures that all metrics are properly defined and accessible
// The actual functionality will be tested through integration tests
// Test that we can access the counters (this will compile-fail if metrics aren't properly defined)
let _ = &INJECTOR_INVOCATIONS_COUNT;
let _ = &INJECTOR_OUTGOING_CALLS_COUNT;
let _ = &INJECTOR_SUCCESSFUL_TOKEN_REPLACEMENTS_COUNT;
let _ = &INJECTOR_FAILED_TOKEN_REPLACEMENTS_COUNT;
// Test that we can access the histograms
let _ = &INJECTOR_REQUEST_TIME;
let _ = &INJECTOR_TOKEN_REPLACEMENT_TIME;
}
}