use std::{
collections::BTreeSet,
fmt::Debug,
sync::{
atomic::{AtomicBool, AtomicI64, AtomicU64, Ordering},
Arc,
},
};
use atomic_float::AtomicF64;
use crate::{snapshot::HistogramSnapshot, HdrHistogram};
pub struct Counter {
value: AtomicU64,
reset_on_flush: AtomicBool,
}
impl Counter {
pub(crate) fn new(reset_on_flush: bool) -> Self {
Self {
value: AtomicU64::new(0),
reset_on_flush: AtomicBool::new(reset_on_flush),
}
}
pub fn set_reset_on_flush(&self, reset_on_flush: bool) {
self.reset_on_flush.store(reset_on_flush, Ordering::Relaxed)
}
pub fn increment(&self) {
self.add(1)
}
pub fn add(&self, val: u64) {
self.value.fetch_add(val, Ordering::Relaxed);
}
pub(crate) fn flush(&self) -> u64 {
if self.reset_on_flush.load(Ordering::Relaxed) {
self.value.swap(0, Ordering::Relaxed)
} else {
self.value.load(Ordering::Relaxed)
}
}
}
impl Debug for Counter {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Counter")
.field("value", &self.value)
.finish()
}
}
pub struct GaugeF64 {
value: Arc<AtomicF64>,
reset_on_flush: AtomicBool,
}
impl GaugeF64 {
pub(crate) fn new(reset_on_flush: bool) -> Self {
Self {
value: Arc::new(AtomicF64::new(0.0)),
reset_on_flush: AtomicBool::new(reset_on_flush),
}
}
pub fn set_reset_on_flush(&self, reset_on_flush: bool) {
self.reset_on_flush.store(reset_on_flush, Ordering::Relaxed)
}
pub fn set(&self, val: f64) {
self.value.store(val, Ordering::Relaxed)
}
pub(crate) fn flush(&self) -> f64 {
if self.reset_on_flush.load(Ordering::Relaxed) {
self.value.swap(0.0, Ordering::Relaxed)
} else {
self.value.load(Ordering::Relaxed)
}
}
}
impl Debug for GaugeF64 {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("GaugeF64")
.field("value", &self.value)
.finish()
}
}
pub struct GaugeI64 {
value: Arc<AtomicI64>,
reset_on_flush: AtomicBool,
}
impl GaugeI64 {
pub(crate) fn new(reset_on_flush: bool) -> Self {
Self {
value: Arc::new(AtomicI64::new(0)),
reset_on_flush: AtomicBool::new(reset_on_flush),
}
}
pub fn set_reset_on_flush(&self, reset_on_flush: bool) {
self.reset_on_flush.store(reset_on_flush, Ordering::Relaxed)
}
pub fn set(&self, val: i64) {
self.value.store(val, Ordering::Relaxed)
}
pub(crate) fn flush(&self) -> i64 {
if self.reset_on_flush.load(Ordering::Relaxed) {
self.value.swap(0, Ordering::Relaxed)
} else {
self.value.load(Ordering::Relaxed)
}
}
}
impl Debug for GaugeI64 {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("GaugeI64")
.field("value", &self.value)
.finish()
}
}
pub struct Histogram {
hist: spin::Mutex<HdrHistogram>,
reset_on_flush: AtomicBool,
}
impl Histogram {
pub(crate) fn new(reset_on_flush: bool) -> Self {
Self {
hist: spin::Mutex::new(HdrHistogram::new(3).expect("hdrhistogram with 3 sigfigs")),
reset_on_flush: AtomicBool::new(reset_on_flush),
}
}
pub fn set_reset_on_flush(&self, reset_on_flush: bool) {
self.reset_on_flush.store(reset_on_flush, Ordering::Relaxed)
}
pub fn record(&self, val: u64) {
let mut hist = self.hist.lock();
hist.record(val).ok();
}
pub(crate) fn flush(&self, percentiles: &Vec<f64>) -> HistogramSnapshot {
let mut hist = self.hist.lock();
let count = hist.len();
let mut percentile_values = Vec::new();
if count > 0 {
for p in percentiles {
let p = *p;
let v = if p == 0.0 {
hist.min()
} else if p == 100.0 {
hist.max()
} else {
hist.value_at_percentile(p)
};
percentile_values.push((p, v));
}
}
if self.reset_on_flush.load(Ordering::Relaxed) {
hist.clear();
}
HistogramSnapshot {
count,
percentiles: percentile_values,
}
}
}
impl Debug for Histogram {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let hist = self.hist.lock();
let count = hist.len();
if count == 0 {
f.debug_struct("Histogram").field("count", &count).finish()
} else {
f.debug_struct("Histogram")
.field("count", &count)
.field("min", &hist.min())
.field("max", &hist.max())
.field("p50", &hist.value_at_percentile(50.0))
.finish()
}
}
}
pub struct Set {
values: Arc<scc::HashSet<String>>,
reset_on_flush: AtomicBool,
}
impl Set {
pub(crate) fn new(reset_on_flush: bool) -> Self {
Self {
values: Arc::new(scc::HashSet::new()),
reset_on_flush: AtomicBool::new(reset_on_flush),
}
}
pub fn set_reset_on_flush(&self, reset_on_flush: bool) {
self.reset_on_flush.store(reset_on_flush, Ordering::Relaxed)
}
pub fn clear(&self) {
self.values.clear()
}
pub fn insert<T: Into<String>>(&self, val: T) {
self.values.insert(val.into()).ok();
}
pub fn remove(&self, val: &str) {
self.values.remove(val);
}
pub(crate) fn flush(&self) -> Vec<String> {
let mut result = BTreeSet::new();
self.values.scan(|x| {
result.insert(x.clone());
});
if self.reset_on_flush.load(Ordering::Relaxed) {
for v in result.iter() {
self.values.remove(v);
}
}
result.into_iter().collect()
}
}
impl Debug for Set {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Set").field("values", &self.values).finish()
}
}