0.34.6_repo_cleanup
This commit is contained in:
1 parent
ce1a90397c
commit
133d2f0f91
273 files changed
+5969
-6926
No files matched your search
@@ -411,8 +411,6 @@ impl Metrics {
|
||||
}
|
||||
}
|
||||
|
||||
/// Fixed-cardinality per-vhost counters. Retained across config updates by ID,
|
||||
/// released when a vhost is removed, and finalized after complete body lifetime.
|
||||
pub const DURATION_BUCKETS_US: [u64; 10] = [
|
||||
5_000, 10_000, 25_000, 50_000, 100_000, 250_000, 500_000, 1_000_000, 2_500_000, 5_000_000,
|
||||
];
|
||||
@@ -1,5 +1,3 @@
|
||||
// Bounded pull-driven rate sampling for the JSON summary. No per-client state,
|
||||
// background task, or unbounded history. A cached sample is shared by readers.
|
||||
use std::sync::Mutex;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
@@ -34,8 +32,6 @@ impl RateSampler {
|
||||
let mut state = self.0.lock().unwrap_or_else(|error| error.into_inner());
|
||||
if let Some((previous_at, previous)) = state.baseline {
|
||||
let elapsed = now.saturating_duration_since(previous_at);
|
||||
// Do not turn rapid parallel polls into zero/spiky rates. Reuse
|
||||
// the last measured rate until a useful sampling interval passes.
|
||||
if elapsed < Duration::from_secs(1) {
|
||||
return state.latest;
|
||||
}
|
||||
@@ -47,14 +43,19 @@ impl RateSampler {
|
||||
if continuous {
|
||||
let seconds = elapsed.as_secs_f64();
|
||||
state.latest = SummaryRates {
|
||||
requests_per_second: Some((counters.requests - previous.requests) as f64 / seconds),
|
||||
requests_per_second: Some(
|
||||
(counters.requests - previous.requests) as f64 / seconds,
|
||||
),
|
||||
errors_per_second: Some((counters.errors - previous.errors) as f64 / seconds),
|
||||
bytes_in_per_second: Some((counters.bytes_in - previous.bytes_in) as f64 / seconds),
|
||||
bytes_out_per_second: Some((counters.bytes_out - previous.bytes_out) as f64 / seconds),
|
||||
bytes_in_per_second: Some(
|
||||
(counters.bytes_in - previous.bytes_in) as f64 / seconds,
|
||||
),
|
||||
bytes_out_per_second: Some(
|
||||
(counters.bytes_out - previous.bytes_out) as f64 / seconds,
|
||||
),
|
||||
sample_interval_seconds: Some(seconds),
|
||||
};
|
||||
} else {
|
||||
// Long polling gaps or counter resets invalidate the baseline.
|
||||
state.latest = SummaryRates::default();
|
||||
}
|
||||
}
|
||||
@@ -65,12 +66,15 @@ impl RateSampler {
|
||||
|
||||
impl Metrics {
|
||||
pub fn summary_rates(&self) -> SummaryRates {
|
||||
self.summary_rate_sampler.sample(SummaryCounters {
|
||||
requests: self.requests.load(Ordering::Relaxed),
|
||||
errors: self.errors.load(Ordering::Relaxed),
|
||||
bytes_in: self.bytes_in.load(Ordering::Relaxed),
|
||||
bytes_out: self.bytes_out.load(Ordering::Relaxed),
|
||||
}, Instant::now())
|
||||
self.summary_rate_sampler.sample(
|
||||
SummaryCounters {
|
||||
requests: self.requests.load(Ordering::Relaxed),
|
||||
errors: self.errors.load(Ordering::Relaxed),
|
||||
bytes_in: self.bytes_in.load(Ordering::Relaxed),
|
||||
bytes_out: self.bytes_out.load(Ordering::Relaxed),
|
||||
},
|
||||
Instant::now(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,18 +87,40 @@ mod summary_rate_tests {
|
||||
let sampler = RateSampler::default();
|
||||
let at = Instant::now();
|
||||
let counts = |requests, errors, bytes_in, bytes_out| SummaryCounters {
|
||||
requests, errors, bytes_in, bytes_out
|
||||
requests,
|
||||
errors,
|
||||
bytes_in,
|
||||
bytes_out,
|
||||
};
|
||||
assert!(sampler.sample(counts(10, 2, 100, 200), at).requests_per_second.is_none());
|
||||
assert!(sampler
|
||||
.sample(counts(10, 2, 100, 200), at)
|
||||
.requests_per_second
|
||||
.is_none());
|
||||
let rate = sampler.sample(counts(20, 4, 300, 500), at + Duration::from_secs(2));
|
||||
assert_eq!(rate.requests_per_second, Some(5.0));
|
||||
assert_eq!(rate.errors_per_second, Some(1.0));
|
||||
assert_eq!(rate.bytes_in_per_second, Some(100.0));
|
||||
assert_eq!(rate.bytes_out_per_second, Some(150.0));
|
||||
assert_eq!(rate.sample_interval_seconds, Some(2.0));
|
||||
assert_eq!(sampler.sample(counts(21, 4, 310, 520), at + Duration::from_millis(2300)).requests_per_second, Some(5.0));
|
||||
assert!(sampler.sample(counts(22, 4, 330, 550), at + Duration::from_secs(40)).requests_per_second.is_none());
|
||||
assert!(sampler.sample(counts(1, 0, 0, 0), at + Duration::from_secs(42)).requests_per_second.is_none());
|
||||
assert_eq!(sampler.sample(counts(5, 0, 200, 300), at + Duration::from_secs(44)).requests_per_second, Some(2.0));
|
||||
assert_eq!(
|
||||
sampler
|
||||
.sample(counts(21, 4, 310, 520), at + Duration::from_millis(2300))
|
||||
.requests_per_second,
|
||||
Some(5.0)
|
||||
);
|
||||
assert!(sampler
|
||||
.sample(counts(22, 4, 330, 550), at + Duration::from_secs(40))
|
||||
.requests_per_second
|
||||
.is_none());
|
||||
assert!(sampler
|
||||
.sample(counts(1, 0, 0, 0), at + Duration::from_secs(42))
|
||||
.requests_per_second
|
||||
.is_none());
|
||||
assert_eq!(
|
||||
sampler
|
||||
.sample(counts(5, 0, 200, 300), at + Duration::from_secs(44))
|
||||
.requests_per_second,
|
||||
Some(2.0)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -62,15 +62,10 @@ impl VhostMetrics {
|
||||
Err(observed) => current = observed,
|
||||
}
|
||||
}
|
||||
// Write exactly one exclusive histogram bin per exchange. Prometheus
|
||||
// cumulative le=... buckets are reconstructed only when scraped.
|
||||
// This removes up to 11 contended atomics for short 1 KiB responses.
|
||||
let bucket = DURATION_BUCKETS_US.partition_point(|threshold| micros > *threshold);
|
||||
self.buckets[bucket].fetch_add(1, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
/// A scrape-consistent cumulative representation of exclusive bins. The
|
||||
/// sum of atomic snapshots is monotonic and the final count includes +Inf.
|
||||
pub fn duration_histogram(&self) -> ([u64; DURATION_BUCKETS_US.len()], u64) {
|
||||
let mut cumulative = [0u64; DURATION_BUCKETS_US.len()];
|
||||
let mut count = 0u64;
|
||||
@@ -104,4 +99,4 @@ impl VhostMetrics {
|
||||
}
|
||||
}
|
||||
#[cfg(test)]
|
||||
include!("vhost/tests.rs");
|
||||
include!("tests.rs");
|
||||
@@ -5,7 +5,13 @@ mod vhost_tests {
|
||||
let m = VhostMetrics::default();
|
||||
m.active.store(5, Ordering::Relaxed);
|
||||
for micros in [1, 5_000, 5_001, 25_000, 5_000_001] {
|
||||
m.complete(200, false, std::time::Duration::from_micros(micros), 0, 1040);
|
||||
m.complete(
|
||||
200,
|
||||
false,
|
||||
std::time::Duration::from_micros(micros),
|
||||
0,
|
||||
1040,
|
||||
);
|
||||
}
|
||||
let (cumulative, total) = m.duration_histogram();
|
||||
assert_eq!(total, 5);
|
||||
@@ -28,7 +34,7 @@ mod vhost_tests {
|
||||
assert_eq!(n(&m.status[4]), 1);
|
||||
assert_eq!(n(&m.buckets[1]), 0);
|
||||
assert_eq!(n(&m.buckets[2]), 1);
|
||||
assert_eq!(n(&m.buckets[10]), 0); // exclusive +Inf bin
|
||||
assert_eq!(n(&m.buckets[10]), 0);
|
||||
let (buckets, count) = m.duration_histogram();
|
||||
assert_eq!(buckets[1], 0);
|
||||
assert_eq!(buckets[2], 1);
|
||||
|
||||
Reference in new issue
Block a user