mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-13 08:36:54 +00:00
9059a9c68d
* refactor(logging): standardize concurrency and proxy events * chore(logging): extend guardrails for concurrency and proxies * feat(skill): add rustfs logging governance skill
252 lines
8.1 KiB
Rust
252 lines
8.1 KiB
Rust
// Copyright 2024 RustFS Team
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
//! Metrics and monitoring for proxy validation performance and results.
|
|
|
|
use crate::{ProxyError, ValidationMode};
|
|
use metrics::{counter, describe_counter, describe_gauge, describe_histogram, gauge, histogram};
|
|
use std::time::Duration;
|
|
use tracing::info;
|
|
|
|
/// Collector for proxy validation metrics.
|
|
#[derive(Debug, Clone)]
|
|
pub struct ProxyMetrics {
|
|
/// Whether metrics collection is enabled.
|
|
enabled: bool,
|
|
/// Application name used as a label for metrics.
|
|
app_name: String,
|
|
}
|
|
|
|
impl ProxyMetrics {
|
|
/// Creates a new `ProxyMetrics` collector.
|
|
pub fn new(app_name: &str, enabled: bool) -> Self {
|
|
let metrics = Self {
|
|
enabled,
|
|
app_name: app_name.to_string(),
|
|
};
|
|
|
|
// Register metric descriptions for Prometheus.
|
|
metrics.register_descriptions();
|
|
|
|
metrics
|
|
}
|
|
|
|
/// Registers descriptions for all metrics.
|
|
fn register_descriptions(&self) {
|
|
if !self.enabled {
|
|
return;
|
|
}
|
|
|
|
describe_counter!(
|
|
"rustfs_trusted_proxy_validation_attempts_total",
|
|
"Total number of proxy validation attempts"
|
|
);
|
|
describe_counter!(
|
|
"rustfs_trusted_proxy_validation_success_total",
|
|
"Total number of successful proxy validations"
|
|
);
|
|
describe_counter!(
|
|
"rustfs_trusted_proxy_validation_failure_total",
|
|
"Total number of failed proxy validations"
|
|
);
|
|
describe_counter!(
|
|
"rustfs_trusted_proxy_validation_failure_by_type_total",
|
|
"Total number of failed proxy validations categorized by error type"
|
|
);
|
|
describe_gauge!("rustfs_trusted_proxy_chain_length", "Current length of proxy chains being validated");
|
|
describe_histogram!(
|
|
"rustfs_trusted_proxy_validation_duration_seconds",
|
|
"Time taken to validate a proxy chain in seconds"
|
|
);
|
|
describe_gauge!(
|
|
"rustfs_trusted_proxy_cache_size",
|
|
"Current number of entries in the proxy validation cache"
|
|
);
|
|
describe_counter!("rustfs_trusted_proxy_cache_hits_total", "Total number of cache hits for proxy validation");
|
|
describe_counter!(
|
|
"rustfs_trusted_proxy_cache_misses_total",
|
|
"Total number of cache misses for proxy validation"
|
|
);
|
|
}
|
|
|
|
/// Increments the total number of validation attempts.
|
|
pub fn increment_validation_attempts(&self) {
|
|
if !self.enabled {
|
|
return;
|
|
}
|
|
|
|
counter!(
|
|
"rustfs_trusted_proxy_validation_attempts_total",
|
|
"app" => self.app_name.clone()
|
|
)
|
|
.increment(1);
|
|
}
|
|
|
|
/// Records a successful validation.
|
|
pub fn record_validation_success(&self, from_trusted_proxy: bool, proxy_hops: usize, duration: Duration) {
|
|
if !self.enabled {
|
|
return;
|
|
}
|
|
|
|
counter!(
|
|
"rustfs_trusted_proxy_validation_success_total",
|
|
"app" => self.app_name.clone(),
|
|
"trusted" => from_trusted_proxy.to_string()
|
|
)
|
|
.increment(1);
|
|
|
|
gauge!(
|
|
"rustfs_trusted_proxy_chain_length",
|
|
"app" => self.app_name.clone()
|
|
)
|
|
.set(proxy_hops as f64);
|
|
|
|
histogram!(
|
|
"rustfs_trusted_proxy_validation_duration_seconds",
|
|
"app" => self.app_name.clone()
|
|
)
|
|
.record(duration.as_secs_f64());
|
|
}
|
|
|
|
/// Records a failed validation with the specific error type.
|
|
pub fn record_validation_failure(&self, error: &ProxyError, duration: Duration) {
|
|
if !self.enabled {
|
|
return;
|
|
}
|
|
|
|
let error_type = match error {
|
|
ProxyError::InvalidXForwardedFor(_) => "invalid_x_forwarded_for",
|
|
ProxyError::InvalidForwardedHeader(_) => "invalid_forwarded_header",
|
|
ProxyError::ChainValidationFailed(_) => "chain_validation_failed",
|
|
ProxyError::ChainTooLong(_, _) => "chain_too_long",
|
|
ProxyError::UntrustedProxy(_) => "untrusted_proxy",
|
|
ProxyError::ChainNotContinuous => "chain_not_continuous",
|
|
ProxyError::IpParseError(_) => "ip_parse_error",
|
|
ProxyError::HeaderParseError(_) => "header_parse_error",
|
|
ProxyError::Timeout => "timeout",
|
|
ProxyError::Internal(_) => "internal",
|
|
};
|
|
|
|
counter!(
|
|
"rustfs_trusted_proxy_validation_failure_total",
|
|
"app" => self.app_name.clone(),
|
|
"error_type" => error_type
|
|
)
|
|
.increment(1);
|
|
|
|
counter!(
|
|
"rustfs_trusted_proxy_validation_failure_by_type_total",
|
|
"app" => self.app_name.clone(),
|
|
"error_type" => error_type
|
|
)
|
|
.increment(1);
|
|
|
|
histogram!(
|
|
"rustfs_trusted_proxy_validation_duration_seconds",
|
|
"app" => self.app_name.clone(),
|
|
"error_type" => error_type
|
|
)
|
|
.record(duration.as_secs_f64());
|
|
}
|
|
|
|
/// Records the validation mode currently in use.
|
|
pub fn record_validation_mode(&self, mode: ValidationMode) {
|
|
if !self.enabled {
|
|
return;
|
|
}
|
|
|
|
gauge!(
|
|
"rustfs_trusted_proxy_validation_mode",
|
|
"app" => self.app_name.clone(),
|
|
"mode" => mode.as_str()
|
|
)
|
|
.set(match mode {
|
|
ValidationMode::Lenient => 0.0,
|
|
ValidationMode::Strict => 1.0,
|
|
ValidationMode::HopByHop => 2.0,
|
|
});
|
|
}
|
|
|
|
/// Records a cache hit.
|
|
pub fn record_cache_hit(&self) {
|
|
if !self.enabled {
|
|
return;
|
|
}
|
|
|
|
counter!("rustfs_trusted_proxy_cache_hits_total", "app" => self.app_name.clone()).increment(1);
|
|
}
|
|
|
|
/// Records a cache miss.
|
|
pub fn record_cache_miss(&self) {
|
|
if !self.enabled {
|
|
return;
|
|
}
|
|
|
|
counter!("rustfs_trusted_proxy_cache_misses_total", "app" => self.app_name.clone()).increment(1);
|
|
}
|
|
|
|
/// Updates only the cache size gauge.
|
|
pub fn set_cache_size(&self, size: usize) {
|
|
if !self.enabled {
|
|
return;
|
|
}
|
|
|
|
gauge!("rustfs_trusted_proxy_cache_size", "app" => self.app_name.clone()).set(size as f64);
|
|
}
|
|
|
|
/// Records cache performance metrics.
|
|
pub fn record_cache_metrics(&self, hits: u64, misses: u64, size: usize) {
|
|
if !self.enabled {
|
|
return;
|
|
}
|
|
|
|
counter!("rustfs_trusted_proxy_cache_hits_total", "app" => self.app_name.clone()).increment(hits);
|
|
counter!("rustfs_trusted_proxy_cache_misses_total", "app" => self.app_name.clone()).increment(misses);
|
|
gauge!("rustfs_trusted_proxy_cache_size", "app" => self.app_name.clone()).set(size as f64);
|
|
}
|
|
|
|
/// Prints a summary of enabled metrics to the log.
|
|
pub fn print_summary(&self) {
|
|
if !self.enabled {
|
|
info!(
|
|
event = "trusted_proxies.metrics",
|
|
component = "trusted_proxies",
|
|
subsystem = "metrics",
|
|
state = "disabled",
|
|
app = %self.app_name,
|
|
"trusted proxies metrics state changed"
|
|
);
|
|
return;
|
|
}
|
|
|
|
info!(
|
|
event = "trusted_proxies.metrics",
|
|
component = "trusted_proxies",
|
|
subsystem = "metrics",
|
|
state = "enabled",
|
|
app = %self.app_name,
|
|
metric_count = 9,
|
|
"trusted proxies metrics state changed"
|
|
);
|
|
}
|
|
}
|
|
|
|
/// Default application name for metrics.
|
|
const DEFAULT_APP_NAME: &str = "trusted-proxy";
|
|
|
|
/// Creates a default `ProxyMetrics` collector.
|
|
pub fn default_proxy_metrics(enabled: bool) -> ProxyMetrics {
|
|
ProxyMetrics::new(DEFAULT_APP_NAME, enabled)
|
|
}
|