refactor: replace all api_gateway/web-gateway references across codebase

- Rename test functions, variables, bench names (api_gateway → api)
- Update e2e orchestrator executable path (target/debug/api)
- Clean Grafana dashboards: remove dead web-gateway panels, fix trailing
  pipes/commas, update pod selectors
- Update metrics_validation test metric prefixes (api_gateway_ → api_)
- Fix .gitlab-ci.yml remaining path reference
- Fix FXT CLI test flag and function names
- Keep JWT issuer foxhunt-api-gateway (cross-service auth compat)
- Keep serde alias api_gateway_url (config backwards compat)

cargo check --workspace passes cleanly.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
jgrusewski
2026-03-05 00:18:58 +01:00
parent 84877e5146
commit 075f715fa1
16 changed files with 107 additions and 267 deletions

View File

@@ -472,7 +472,7 @@ compile-trading-service:
- if: $CI_COMMIT_BRANCH == "main" && $CI_PIPELINE_SOURCE == "push"
changes:
- services/trading_service/**
- services/api_gateway/**
- services/api/**
- crates/common/**
- crates/config/**
- crates/data/**

View File

@@ -21,7 +21,7 @@ fn test_fxt_help() {
.stdout(predicate::str::contains(
"Foxhunt Trading System Terminal Interface",
))
.stdout(predicate::str::contains("--api-gateway-url"))
.stdout(predicate::str::contains("--api-url"))
.stdout(predicate::str::contains("--log-level"));
}
@@ -124,11 +124,11 @@ fn test_tune_requires_auth() {
.stderr(predicate::str::contains("Not authenticated"));
}
/// Test environment variable support for API Gateway URL
/// Test environment variable support for API URL
#[test]
fn test_env_var_api_gateway_url() {
fn test_env_var_api_url() {
let mut cmd = Command::cargo_bin("fxt").unwrap();
cmd.env("API_GATEWAY_URL", "http://test.example.com:50051")
cmd.env("API_URL", "http://test.example.com:50051")
.arg("--help")
.assert()
.success();
@@ -149,7 +149,7 @@ fn test_env_var_log_level() {
fn test_cli_flag_precedence() {
let mut cmd = Command::cargo_bin("fxt").unwrap();
cmd.env("API_GATEWAY_URL", "http://env.example.com")
.arg("--api-gateway-url")
.arg("--api-url")
.arg("http://cli.example.com")
.arg("--help")
.assert()
@@ -272,7 +272,7 @@ fn test_tune_stop_help() {
#[test]
fn test_multiple_cli_flags() {
let mut cmd = Command::cargo_bin("fxt").unwrap();
cmd.arg("--api-gateway-url")
cmd.arg("--api-url")
.arg("http://test.example.com")
.arg("--log-level")
.arg("debug")

View File

@@ -38,7 +38,7 @@ struct JwtClaims {
}
/// Check if API Gateway is reachable at localhost:50051
async fn check_api_gateway_availability() -> Result<bool> {
async fn check_api_availability() -> Result<bool> {
use tokio::net::TcpStream;
// Try to connect to port 50051 with 2-second timeout
@@ -152,10 +152,10 @@ fn test_jwt_token_format_validation() {
/// Test: API Gateway connectivity check
#[tokio::test]
async fn test_api_gateway_connectivity() {
println!("\n🧪 Testing API Gateway connectivity...");
async fn test_api_connectivity() {
println!("\n🧪 Testing API service connectivity...");
let is_available = check_api_gateway_availability()
let is_available = check_api_availability()
.await
.expect("Connectivity check should not fail");
@@ -164,8 +164,8 @@ async fn test_api_gateway_connectivity() {
} else {
println!("⚠️ API Gateway not available (this is OK for CI/CD)");
println!(" To test live connectivity:");
println!(" 1. cargo run -p api_gateway &");
println!(" 2. cargo test -p tli --test tune_integration_test");
println!(" 1. cargo run -p api &");
println!(" 2. cargo test -p fxt --test tune_integration_test");
}
}
@@ -179,8 +179,8 @@ async fn test_grpc_connection_mock() {
use tonic::transport::Channel;
// Try to parse API Gateway URL (validates URL format)
let api_gateway_url = "http://localhost:50051";
let endpoint = Channel::from_shared(api_gateway_url.to_string());
let api_url = "http://localhost:50051";
let endpoint = Channel::from_shared(api_url.to_string());
assert!(endpoint.is_ok(), "API Gateway URL should be valid");
println!("✅ gRPC endpoint URL parsing successful");
@@ -226,27 +226,27 @@ async fn test_tuning_job_start_mock() {
/// This test is ignored by default - run with `cargo test -- --ignored`
#[tokio::test]
#[ignore = "Requires API Gateway to be running (use --ignored to run)"]
async fn test_api_gateway_connection_live() {
println!("\n🧪 Testing live API Gateway connection...");
async fn test_api_connection_live() {
println!("\n🧪 Testing live API service connection...");
// Check if API Gateway is available
let is_available = check_api_gateway_availability()
let is_available = check_api_availability()
.await
.expect("Connectivity check should not fail");
if !is_available {
println!("❌ SKIPPED: API Gateway not running");
println!(" Start with: cargo run -p api_gateway");
println!(" Start with: cargo run -p api");
return;
}
// Try to establish gRPC connection
use tonic::transport::Channel;
let api_gateway_url = "http://localhost:50051";
let api_url = "http://localhost:50051";
let channel_result = timeout(
Duration::from_secs(5),
Channel::from_shared(api_gateway_url.to_string())
Channel::from_shared(api_url.to_string())
.unwrap()
.connect(),
)
@@ -332,7 +332,7 @@ fn test_integration_summary() {
println!();
println!("🚀 To start services:");
println!(" docker-compose up -d");
println!(" cargo run -p api_gateway &");
println!(" cargo run -p api &");
println!(" cargo run -p ml_training_service &");
}

View File

@@ -86,7 +86,7 @@ use crate::error::CommonResult;
///
/// # Arguments
///
/// * `service_name` - Name of the service (e.g., "api_gateway", "trading_service")
/// * `service_name` - Name of the service (e.g., "api", "trading_service")
/// * `otlp_endpoint` - Optional OTLP collector endpoint (e.g., `Some("http://localhost:4317")`).
/// When `None`, the OTLP tracing layer is disabled and only JSON logging is active.
///

View File

@@ -202,8 +202,8 @@ fn create_test_execution(order_id: u64) -> ExecutionResult {
}
}
/// Simulate API Gateway processing (auth, rate limit, routing)
async fn simulate_api_gateway(order: TradingOrder) -> Result<TradingOrder, String> {
/// Simulate API service processing (auth, rate limit, routing)
async fn simulate_api(order: TradingOrder) -> Result<TradingOrder, String> {
// Simulate auth check (50-100μs)
tokio::time::sleep(Duration::from_micros(75)).await;
@@ -254,12 +254,12 @@ async fn simulate_market_data_to_decision() -> Result<TradingOrder, String> {
// ==================== BENCHMARK 1: API Gateway → Trading Service ====================
//
/// Benchmark 1: API Gateway to Trading Service latency (target: <5ms)
fn bench_api_gateway_to_trading(c: &mut Criterion) {
/// Benchmark 1: API service to Trading Service latency (target: <5ms)
fn bench_api_to_trading(c: &mut Criterion) {
let rt = Runtime::new().unwrap();
let trading_ops = Arc::new(TradingOperations::new());
c.bench_function("e2e_latency/api_gateway_to_trading", |b| {
c.bench_function("e2e_latency/api_to_trading", |b| {
b.iter_custom(|iters| {
let mut metrics = LatencyMetrics::new();
@@ -269,7 +269,7 @@ fn bench_api_gateway_to_trading(c: &mut Criterion) {
let start = Instant::now();
// Step 1: API Gateway processing
let processed_order = simulate_api_gateway(order).await.unwrap();
let processed_order = simulate_api(order).await.unwrap();
// Step 2: Trading service receives and processes order
black_box(trading_ops.submit_order(processed_order).await).ok();
@@ -303,7 +303,7 @@ fn bench_order_to_fill(c: &mut Criterion) {
// Step 1: Order placement
let order = create_test_order(i);
let processed_order = simulate_api_gateway(order).await.unwrap();
let processed_order = simulate_api(order).await.unwrap();
black_box(trading_ops.submit_order(processed_order).await).ok();
// Step 2: Risk check
@@ -398,8 +398,8 @@ fn bench_component_breakdown(c: &mut Criterion) {
let mut group = c.benchmark_group("e2e_latency/components");
let rt = Runtime::new().unwrap();
// Component 1: API Gateway Auth
group.bench_function("api_gateway_auth", |b| {
// Component 1: API Auth
group.bench_function("api_auth", |b| {
b.iter_custom(|iters| {
let start = Instant::now();
rt.block_on(async {
@@ -507,7 +507,7 @@ fn bench_concurrent_latency(c: &mut Criterion) {
// Simulate full flow
let order = create_test_order(i as u64);
let processed = simulate_api_gateway(order).await.unwrap();
let processed = simulate_api(order).await.unwrap();
ops.submit_order(processed).await.ok();
tx.send(req_start.elapsed()).await.ok();
@@ -554,7 +554,7 @@ fn bench_full_e2e_cycle(c: &mut Criterion) {
let order = simulate_market_data_to_decision().await.unwrap();
// Step 2: API Gateway processing
let processed_order = simulate_api_gateway(order).await.unwrap();
let processed_order = simulate_api(order).await.unwrap();
// Step 3: Risk check
simulate_risk_check(&processed_order).await.ok();
@@ -602,7 +602,7 @@ fn bench_latency_by_load(c: &mut Criterion) {
let order_start = Instant::now();
let order = create_test_order(i as u64);
let processed = simulate_api_gateway(order).await.unwrap();
let processed = simulate_api(order).await.unwrap();
black_box(trading_ops.submit_order(processed).await).ok();
metrics.record_latency(order_start.elapsed());
@@ -621,7 +621,7 @@ fn bench_latency_by_load(c: &mut Criterion) {
}
// Criterion benchmark groups
criterion_group!(api_gateway_benches, bench_api_gateway_to_trading,);
criterion_group!(api_benches, bench_api_to_trading,);
criterion_group!(order_flow_benches, bench_order_to_fill,);
@@ -640,7 +640,7 @@ criterion_group!(
criterion_group!(e2e_benches, bench_full_e2e_cycle,);
criterion_main!(
api_gateway_benches,
api_benches,
order_flow_benches,
strategy_benches,
risk_benches,

View File

@@ -463,7 +463,7 @@
{
"id": 9,
"type": "stat",
"title": "api-gateway",
"title": "api",
"gridPos": {
"h": 3,
"w": 3,
@@ -527,7 +527,7 @@
"links": [
{
"title": "Service Detail",
"url": "/d/foxhunt-services?var-service=api-gateway",
"url": "/d/foxhunt-services?var-service=api",
"targetBlank": false
}
],
@@ -538,7 +538,7 @@
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"expr": "sum(kube_pod_status_phase{namespace=\"foxhunt\", pod=~\"api-gateway.*\", phase=\"Running\"}) > 0 or vector(0)",
"expr": "sum(kube_pod_status_phase{namespace=\"foxhunt\", pod=~\"api.*\", phase=\"Running\"}) > 0 or vector(0)",
"instant": true
}
]
@@ -1041,89 +1041,6 @@
}
]
},
{
"id": 16,
"type": "stat",
"title": "web-gateway",
"gridPos": {
"h": 3,
"w": 3,
"x": 21,
"y": 5
},
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"fieldConfig": {
"defaults": {
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "red",
"value": null
},
{
"color": "green",
"value": 1
}
]
},
"mappings": [
{
"type": "value",
"options": {
"0": {
"text": "DOWN",
"color": "red"
},
"1": {
"text": "UP",
"color": "green"
}
}
}
],
"color": {
"mode": "thresholds"
}
},
"overrides": []
},
"options": {
"reduceOptions": {
"calcs": [
"lastNotNull"
],
"fields": "",
"values": false
},
"orientation": "auto",
"textMode": "auto",
"colorMode": "background",
"graphMode": "none",
"justifyMode": "center"
},
"links": [
{
"title": "Service Detail",
"url": "/d/foxhunt-services?var-service=web-gateway",
"targetBlank": false
}
],
"targets": [
{
"refId": "A",
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"expr": "sum(kube_pod_status_phase{namespace=\"foxhunt\", pod=~\"web-gateway.*\", phase=\"Running\"}) > 0 or vector(0)",
"instant": true
}
]
},
{
"id": 100,
"type": "row",
@@ -2387,7 +2304,7 @@
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"expr": "sum by (pod) (container_memory_working_set_bytes{namespace=\"foxhunt\",container!=\"POD\",container!=\"\",pod=~\"(api-gateway|trading-service|ml-training|backtesting|trading-agent|broker-gateway|data-acquisition|web-gateway).*\"})",
"expr": "sum by (pod) (container_memory_working_set_bytes{namespace=\"foxhunt\",container!=\"POD\",container!=\"\",pod=~\"(api|trading-service|ml-training|backtesting|trading-agent|broker-gateway|data-acquisition).*\"})",
"legendFormat": "{{pod}}",
"range": true
}

View File

@@ -40,7 +40,7 @@
{
"name": "service",
"type": "custom",
"query": "api-gateway,trading-service,ml-training-service,backtesting-service,trading-agent-service,broker-gateway,data-acquisition-service,web-gateway",
"query": "api,trading-service,ml-training-service,backtesting-service,trading-agent-service,broker-gateway,data-acquisition-service",
"current": {
"selected": false,
"text": "All",

View File

@@ -460,7 +460,7 @@
{
"id": 11,
"type": "stat",
"title": "api-gateway",
"title": "api",
"gridPos": {
"h": 3,
"w": 3,
@@ -528,7 +528,7 @@
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"expr": "sum(kube_pod_status_phase{namespace=\"foxhunt\", pod=~\"api-gateway.*\", phase=\"Running\"}) > 0 or vector(0)",
"expr": "sum(kube_pod_status_phase{namespace=\"foxhunt\", pod=~\"api.*\", phase=\"Running\"}) > 0 or vector(0)",
"legendFormat": "",
"instant": true
}
@@ -996,83 +996,6 @@
}
]
},
{
"id": 18,
"type": "stat",
"title": "web-gateway",
"gridPos": {
"h": 3,
"w": 3,
"x": 21,
"y": 6
},
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"fieldConfig": {
"defaults": {
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "red",
"value": null
},
{
"color": "green",
"value": 1
}
]
},
"mappings": [
{
"type": "value",
"options": {
"0": {
"text": "DOWN",
"color": "red"
},
"1": {
"text": "UP",
"color": "green"
}
}
}
],
"color": {
"mode": "thresholds"
}
},
"overrides": []
},
"options": {
"reduceOptions": {
"calcs": [
"lastNotNull"
],
"fields": "",
"values": false
},
"orientation": "auto",
"textMode": "auto",
"colorMode": "background",
"graphMode": "none",
"justifyMode": "center"
},
"targets": [
{
"refId": "A",
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"expr": "sum(kube_pod_status_phase{namespace=\"foxhunt\", pod=~\"web-gateway.*\", phase=\"Running\"}) > 0 or vector(0)",
"legendFormat": "",
"instant": true
}
]
},
{
"id": 20,
"type": "row",
@@ -1429,7 +1352,7 @@
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"expr": "sum by (container) (rate(container_cpu_usage_seconds_total{namespace=\"foxhunt\", container=~\"api-gateway|trading-service|ml-training-service|backtesting-service|trading-agent-service|broker-gateway|data-acquisition-service|web-gateway\", image!=\"\"}[$interval]))",
"expr": "sum by (container) (rate(container_cpu_usage_seconds_total{namespace=\"foxhunt\", container=~\"api|trading-service|ml-training-service|backtesting-service|trading-agent-service|broker-gateway|data-acquisition-service\", image!=\"\"}[$interval]))",
"legendFormat": "{{ container }}"
}
]

View File

@@ -40,11 +40,11 @@
{
"name": "service",
"type": "custom",
"query": "api-gateway,trading-service,ml-training-service,backtesting-service,trading-agent-service,broker-gateway,data-acquisition-service,web-gateway",
"query": "api,trading-service,ml-training-service,backtesting-service,trading-agent-service,broker-gateway,data-acquisition-service",
"current": {
"selected": true,
"text": "api-gateway",
"value": "api-gateway"
"text": "api",
"value": "api"
},
"multi": false,
"includeAll": false,

View File

@@ -103,7 +103,7 @@ impl JwtConfig {
Ok(Self {
jwt_secret,
jwt_issuer: "foxhunt-api".to_string(),
jwt_issuer: "foxhunt-api-gateway".to_string(),
jwt_audience: "foxhunt-services".to_string(),
})
}
@@ -454,7 +454,7 @@ mod tests {
.await
.expect("Should create config with valid JWT_SECRET");
assert_eq!(config.jwt_issuer, "foxhunt-api");
assert_eq!(config.jwt_issuer, "foxhunt-api-gateway");
assert_eq!(config.jwt_audience, "foxhunt-services");
assert!(config.jwt_secret.len() >= 64);
@@ -484,7 +484,7 @@ mod tests {
match result {
Ok(config) => {
// Verify config was loaded successfully
assert_eq!(config.jwt_issuer, "foxhunt-api");
assert_eq!(config.jwt_issuer, "foxhunt-api-gateway");
assert_eq!(config.jwt_audience, "foxhunt-services");
assert!(config.jwt_secret.len() >= 64);

View File

@@ -842,7 +842,7 @@ impl MonitoringService for MonitoringServiceImpl {
// ========================================================================
// Training metrics RPCs (not applicable to trading_service; served by
// api_gateway which queries Prometheus directly). Return UNIMPLEMENTED.
// api service which queries Prometheus directly). Return UNIMPLEMENTED.
// ========================================================================
type StreamTrainingMetricsStream = std::pin::Pin<

View File

@@ -197,7 +197,7 @@ fn bench_component_breakdown(c: &mut Criterion) {
});
// Component 3: API Gateway auth (measured: 3.1μs P99)
group.bench_function("api_gateway_auth", |b| {
group.bench_function("api_auth", |b| {
b.iter_custom(|iters| {
let start = Instant::now();
rt.block_on(async {

View File

@@ -194,7 +194,7 @@ async fn start_services(matches: &ArgMatches) -> Result<()> {
let background = matches.get_flag("background");
// API Gateway gets port 50051, backend services start at 50052
let api_gateway_port: u16 = 50051;
let api_port: u16 = 50051;
let backend_base_port: u16 = 50052;
// Get JWT_SECRET from environment (required for API Gateway)
@@ -209,7 +209,7 @@ async fn start_services(matches: &ArgMatches) -> Result<()> {
let ml_training_service_url = format!("http://localhost:{}", backend_base_port + 2);
info!("Starting services: {}", services_arg);
info!("API Gateway port: {}", api_gateway_port);
info!("API service port: {}", api_port);
info!("Backend services starting at port: {}", backend_base_port);
info!("Background mode: {}", background);
@@ -245,41 +245,41 @@ async fn start_services(matches: &ArgMatches) -> Result<()> {
// Start API Gateway FIRST if requested
if services_to_start.contains(&ServiceType::ApiGateway) || services_to_start.len() > 1 {
info!("Starting API Gateway on port {}...", api_gateway_port);
info!("Starting API service on port {}...", api_port);
let mut api_gateway_env = HashMap::new();
api_gateway_env.insert("JWT_SECRET".to_string(), jwt_secret.clone());
api_gateway_env.insert(
let mut api_env = HashMap::new();
api_env.insert("JWT_SECRET".to_string(), jwt_secret.clone());
api_env.insert(
"TRADING_SERVICE_URL".to_string(),
trading_service_url.clone(),
);
api_gateway_env.insert(
api_env.insert(
"BACKTESTING_SERVICE_URL".to_string(),
backtesting_service_url.clone(),
);
api_gateway_env.insert(
api_env.insert(
"ML_TRAINING_SERVICE_URL".to_string(),
ml_training_service_url.clone(),
);
api_gateway_env.insert("GRPC_PORT".to_string(), api_gateway_port.to_string());
api_gateway_env.insert("HTTP_PORT".to_string(), "8080".to_string());
api_gateway_env.insert("METRICS_PORT".to_string(), "9091".to_string());
api_gateway_env.insert("RUST_LOG".to_string(), "info".to_string());
api_gateway_env.insert("FOXHUNT_TEST_MODE".to_string(), "true".to_string());
api_env.insert("GRPC_PORT".to_string(), api_port.to_string());
api_env.insert("HTTP_PORT".to_string(), "8080".to_string());
api_env.insert("METRICS_PORT".to_string(), "9091".to_string());
api_env.insert("RUST_LOG".to_string(), "info".to_string());
api_env.insert("FOXHUNT_TEST_MODE".to_string(), "true".to_string());
let api_gateway_config = ServiceConfig {
let api_config = ServiceConfig {
service_type: ServiceType::ApiGateway,
executable_path: "target/debug/api_gateway".to_string(),
port: api_gateway_port,
executable_path: "target/debug/api".to_string(),
port: api_port,
health_endpoint: "http://localhost:8080/health".to_string(),
startup_timeout: Duration::from_secs(30),
environment: api_gateway_env,
environment: api_env,
working_directory: std::env::current_dir()?,
log_file: Some("/tmp/foxhunt_api_gateway_service.log".to_string()),
log_file: Some("/tmp/foxhunt_api_service.log".to_string()),
};
service_manager.start_service(api_gateway_config).await?;
profiler.checkpoint("api_gateway_started");
service_manager.start_service(api_config).await?;
profiler.checkpoint("api_started");
// Wait for API Gateway to be ready
if wait_ready {
@@ -699,7 +699,7 @@ fn parse_service_list(services_str: &str) -> Result<Vec<ServiceType>> {
];
break;
},
"api_gateway" | "gateway" => services.push(ServiceType::ApiGateway),
"api" | "api_gateway" | "gateway" => services.push(ServiceType::ApiGateway),
"trading" => services.push(ServiceType::TradingService),
"backtesting" => services.push(ServiceType::BacktestingService),
"ml_training" | "ml" => services.push(ServiceType::MLTrainingService),
@@ -715,7 +715,7 @@ fn create_service_config(service_type: &ServiceType, port: u16) -> Result<Servic
let (health_endpoint, executable_path) = match service_type {
ServiceType::ApiGateway => (
"http://localhost:8080/health".to_string(),
"api_gateway".to_string(),
"api".to_string(),
),
ServiceType::TradingService => (
"http://localhost:8081/health".to_string(),

View File

@@ -24,7 +24,7 @@ pub enum ServiceType {
impl ServiceType {
pub fn as_str(&self) -> &str {
match self {
ServiceType::ApiGateway => "api_gateway",
ServiceType::ApiGateway => "api",
ServiceType::TradingService => "trading",
ServiceType::BacktestingService => "backtesting",
ServiceType::MLTrainingService => "ml_training",

View File

@@ -627,7 +627,7 @@ lazy_static::lazy_static! {
pub static ref TEST_PORT_MANAGER: TestPortManager = TestPortManager::new();
}
// TestEventPublisher removed — event streaming moved to web-gateway WebSocket infrastructure
// TestEventPublisher removed — event streaming moved to gRPC server-streaming in api service
/// Performance metrics collector for tests
#[derive(Debug, Default)]

View File

@@ -28,7 +28,7 @@ pub struct MetricsValidationResult {
/// Required metrics per service
pub struct RequiredMetrics {
pub api_gateway: Vec<&'static str>,
pub api: Vec<&'static str>,
pub trading_service: Vec<&'static str>,
pub backtesting_service: Vec<&'static str>,
pub ml_training_service: Vec<&'static str>,
@@ -43,15 +43,15 @@ impl Default for RequiredMetrics {
impl RequiredMetrics {
pub fn new() -> Self {
Self {
api_gateway: vec![
"api_gateway_auth_attempts_total",
"api_gateway_auth_duration_milliseconds",
"api_gateway_backend_requests_total",
"api_gateway_backend_request_duration_milliseconds",
"api_gateway_circuit_breaker_state",
"api_gateway_connection_pool_active",
"api_gateway_health_status",
"api_gateway_rate_limit_hits",
api: vec![
"api_auth_attempts_total",
"api_auth_duration_milliseconds",
"api_backend_requests_total",
"api_backend_request_duration_milliseconds",
"api_circuit_breaker_state",
"api_connection_pool_active",
"api_health_status",
"api_rate_limit_hits",
],
trading_service: vec![
"trading_orders_submitted_total",
@@ -76,7 +76,7 @@ impl RequiredMetrics {
pub fn get_required(&self, service: &str) -> Vec<&'static str> {
match service {
"api_gateway" => self.api_gateway.clone(),
"api" => self.api.clone(),
"trading_service" => self.trading_service.clone(),
"backtesting_service" => self.backtesting_service.clone(),
"ml_training_service" => self.ml_training_service.clone(),
@@ -294,15 +294,15 @@ mod tests {
#[test]
fn test_metrics_parser() {
let content = r#"
# HELP api_gateway_requests_total Total HTTP requests
# TYPE api_gateway_requests_total counter
api_gateway_requests_total{method="GET",status="200"} 1234
api_gateway_requests_total{method="POST",status="201"} 567
# HELP api_requests_total Total HTTP requests
# TYPE api_requests_total counter
api_requests_total{method="GET",status="200"} 1234
api_requests_total{method="POST",status="201"} 567
# HELP api_gateway_latency_seconds Request latency
# TYPE api_gateway_latency_seconds histogram
api_gateway_latency_seconds{quantile="0.5"} 0.05
api_gateway_latency_seconds{quantile="0.99"} 0.5
# HELP api_latency_seconds Request latency
# TYPE api_latency_seconds histogram
api_latency_seconds{quantile="0.5"} 0.05
api_latency_seconds{quantile="0.99"} 0.5
"#;
let metrics = MetricsParser::parse(content);
@@ -310,14 +310,14 @@ api_gateway_latency_seconds{quantile="0.99"} 0.5
assert_eq!(metrics.len(), 4);
// Check first metric
assert_eq!(metrics[0].name, "api_gateway_requests_total");
assert_eq!(metrics[0].name, "api_requests_total");
assert_eq!(metrics[0].value, 1234.0);
assert_eq!(metrics[0].metric_type, Some("counter".to_owned()));
assert_eq!(metrics[0].labels.get("method"), Some(&"GET".to_owned()));
assert_eq!(metrics[0].labels.get("status"), Some(&"200".to_owned()));
// Check histogram metric
assert_eq!(metrics[2].name, "api_gateway_latency_seconds");
assert_eq!(metrics[2].name, "api_latency_seconds");
assert_eq!(metrics[2].labels.get("quantile"), Some(&"0.5".to_owned()));
assert_eq!(metrics[2].value, 0.05);
}
@@ -326,9 +326,9 @@ api_gateway_latency_seconds{quantile="0.99"} 0.5
fn test_required_metrics() {
let required = RequiredMetrics::new();
let api_metrics = required.get_required("api_gateway");
assert!(api_metrics.contains(&"api_gateway_auth_attempts_total"));
assert!(api_metrics.contains(&"api_gateway_circuit_breaker_state"));
let api_metrics = required.get_required("api");
assert!(api_metrics.contains(&"api_auth_attempts_total"));
assert!(api_metrics.contains(&"api_circuit_breaker_state"));
let trading_metrics = required.get_required("trading_service");
assert!(trading_metrics.contains(&"trading_orders_submitted_total"));
@@ -363,14 +363,14 @@ api_gateway_latency_seconds{quantile="0.99"} 0.5
async fn test_api_metrics() {
let required = RequiredMetrics::new();
let result = validate_service_metrics(
"api_gateway",
"api",
"http://localhost:9091/metrics",
&required.api_gateway,
&required.api,
)
.await;
if let Ok(validation) = result {
println!("API Gateway Metrics Validation:");
println!("API Service Metrics Validation:");
println!(" Total Metrics: {}", validation.total_metrics);
println!(" Scrape Duration: {}ms", validation.scrape_duration_ms);
println!(" Success: {}", validation.success);
@@ -389,7 +389,7 @@ api_gateway_latency_seconds{quantile="0.99"} 0.5
}
}
assert!(validation.success, "API Gateway metrics validation failed");
assert!(validation.success, "API service metrics validation failed");
}
}
@@ -424,9 +424,9 @@ api_gateway_latency_seconds{quantile="0.99"} 0.5
let services = vec![
(
"api_gateway",
"api",
"http://localhost:9091/metrics",
required.api_gateway,
required.api,
),
(
"trading_service",