1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294
use std::hash::Hasher;
use ahash::AHasher;
use crate::cow::Cow;
/// An allocation-optimized string.
///
/// We specify `SharedString` to attempt to get the best of both worlds: flexibility to provide a
/// static or dynamic (owned) string, while retaining the performance benefits of being able to
/// take ownership of owned strings and borrows of completely static strings.
///
/// `SharedString` can be converted to from either `&'static str` or `String`, with a method,
/// `const_str`, from constructing `SharedString` from `&'static str` in a `const` fashion.
pub type SharedString = Cow<'static, str>;
/// Key-specific hashing algorithm.
///
/// Currently uses AHash - <https://github.com/tkaitchuck/aHash>
///
/// For any use-case within a `metrics`-owned or adjacent crate, where hashing of a key is required,
/// this is the hasher that will be used.
#[derive(Default)]
pub struct KeyHasher(AHasher);
impl Hasher for KeyHasher {
fn finish(&self) -> u64 {
self.0.finish()
}
fn write(&mut self, bytes: &[u8]) {
self.0.write(bytes)
}
}
/// Value of a gauge operation.
#[derive(Clone, Debug)]
pub enum GaugeValue {
/// Sets the value of the gauge to this value.
Absolute(f64),
/// Increments the value of the gauge by this much.
Increment(f64),
/// Decrements the value of the gauge by this much.
Decrement(f64),
}
impl GaugeValue {
/// Updates an input value based on this gauge value.
pub fn update_value(&self, input: f64) -> f64 {
match self {
GaugeValue::Absolute(val) => *val,
GaugeValue::Increment(val) => input + val,
GaugeValue::Decrement(val) => input - val,
}
}
}
/// Units for a given metric.
///
/// While metrics do not necessarily need to be tied to a particular unit to be recorded, some
/// downstream systems natively support defining units and so they can be specified during registration.
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Unit {
/// Count.
Count,
/// Percentage.
Percent,
/// Seconds.
///
/// One second is equal to 1000 milliseconds.
Seconds,
/// Milliseconds.
///
/// One millisecond is equal to 1000 microseconds.
Milliseconds,
/// Microseconds.
///
/// One microsecond is equal to 1000 nanoseconds.
Microseconds,
/// Nanoseconds.
Nanoseconds,
/// Tebibytes.
///
/// One tebibyte is equal to 1024 gigibytes.
Tebibytes,
/// Gigibytes.
///
/// One gigibyte is equal to 1024 mebibytes.
Gigibytes,
/// Mebibytes.
///
/// One mebibyte is equal to 1024 kibibytes.
Mebibytes,
/// Kibibytes.
///
/// One kibibyte is equal to 1024 bytes.
Kibibytes,
/// Bytes.
Bytes,
/// Terabits per second.
///
/// One terabit is equal to 1000 gigabits.
TerabitsPerSecond,
/// Gigabits per second.
///
/// One gigabit is equal to 1000 megabits.
GigabitsPerSecond,
/// Megabits per second.
///
/// One megabit is equal to 1000 kilobits.
MegabitsPerSecond,
/// Kilobits per second.
///
/// One kilobit is equal to 1000 bits.
KilobitsPerSecond,
/// Bits per second.
BitsPerSecond,
/// Count per second.
CountPerSecond,
}
impl Unit {
/// Gets the string form of this `Unit`.
pub fn as_str(&self) -> &str {
match self {
Unit::Count => "count",
Unit::Percent => "percent",
Unit::Seconds => "seconds",
Unit::Milliseconds => "milliseconds",
Unit::Microseconds => "microseconds",
Unit::Nanoseconds => "nanoseconds",
Unit::Tebibytes => "tebibytes",
Unit::Gigibytes => "gigibytes",
Unit::Mebibytes => "mebibytes",
Unit::Kibibytes => "kibibytes",
Unit::Bytes => "bytes",
Unit::TerabitsPerSecond => "terabits_per_second",
Unit::GigabitsPerSecond => "gigabits_per_second",
Unit::MegabitsPerSecond => "megabits_per_second",
Unit::KilobitsPerSecond => "kilobits_per_second",
Unit::BitsPerSecond => "bits_per_second",
Unit::CountPerSecond => "count_per_second",
}
}
/// Gets the canonical string label for the given unit.
///
/// For example, the canonical label for `Seconds` would be `s`, while for `Nanoseconds`,
/// it would be `ns`.
///
/// Not all units have a meaningful display label and so some may be empty.
pub fn as_canonical_label(&self) -> &str {
match self {
Unit::Count => "",
Unit::Percent => "%",
Unit::Seconds => "s",
Unit::Milliseconds => "ms",
Unit::Microseconds => "μs",
Unit::Nanoseconds => "ns",
Unit::Tebibytes => "TiB",
Unit::Gigibytes => "GiB",
Unit::Mebibytes => "MiB",
Unit::Kibibytes => "KiB",
Unit::Bytes => "B",
Unit::TerabitsPerSecond => "Tbps",
Unit::GigabitsPerSecond => "Gbps",
Unit::MegabitsPerSecond => "Mbps",
Unit::KilobitsPerSecond => "kbps",
Unit::BitsPerSecond => "bps",
Unit::CountPerSecond => "/s",
}
}
/// Converts the string representation of a unit back into `Unit` if possible.
///
/// The value passed here should match the output of [`Unit::as_str`].
pub fn from_string(s: &str) -> Option<Unit> {
match s {
"count" => Some(Unit::Count),
"percent" => Some(Unit::Percent),
"seconds" => Some(Unit::Seconds),
"milliseconds" => Some(Unit::Milliseconds),
"microseconds" => Some(Unit::Microseconds),
"nanoseconds" => Some(Unit::Nanoseconds),
"tebibytes" => Some(Unit::Tebibytes),
"gigibytes" => Some(Unit::Gigibytes),
"mebibytes" => Some(Unit::Mebibytes),
"kibibytes" => Some(Unit::Kibibytes),
"bytes" => Some(Unit::Bytes),
"terabits_per_second" => Some(Unit::TerabitsPerSecond),
"gigabits_per_second" => Some(Unit::GigabitsPerSecond),
"megabits_per_second" => Some(Unit::MegabitsPerSecond),
"kilobits_per_second" => Some(Unit::KilobitsPerSecond),
"bits_per_second" => Some(Unit::BitsPerSecond),
"count_per_second" => Some(Unit::CountPerSecond),
_ => None,
}
}
/// Whether or not this unit relates to the measurement of time.
pub fn is_time_based(&self) -> bool {
matches!(self, Unit::Seconds | Unit::Milliseconds | Unit::Microseconds | Unit::Nanoseconds)
}
/// Whether or not this unit relates to the measurement of data.
pub fn is_data_based(&self) -> bool {
matches!(
self,
Unit::Tebibytes
| Unit::Gigibytes
| Unit::Mebibytes
| Unit::Kibibytes
| Unit::Bytes
| Unit::TerabitsPerSecond
| Unit::GigabitsPerSecond
| Unit::MegabitsPerSecond
| Unit::KilobitsPerSecond
| Unit::BitsPerSecond
)
}
/// Whether or not this unit relates to the measurement of data rates.
pub fn is_data_rate_based(&self) -> bool {
matches!(
self,
Unit::TerabitsPerSecond
| Unit::GigabitsPerSecond
| Unit::MegabitsPerSecond
| Unit::KilobitsPerSecond
| Unit::BitsPerSecond
)
}
}
/// An object which can be converted into a `f64` representation.
///
/// This trait provides a mechanism for existing types, which have a natural representation
/// as a 64-bit floating-point number, to be transparently passed in when recording a histogram.
pub trait IntoF64 {
/// Converts this object to its `f64` representation.
fn into_f64(self) -> f64;
}
impl IntoF64 for f64 {
fn into_f64(self) -> f64 {
self
}
}
impl IntoF64 for core::time::Duration {
fn into_f64(self) -> f64 {
self.as_secs_f64()
}
}
/// Helper method to allow monomorphization of values passed to the `histogram!` macro.
#[doc(hidden)]
pub fn __into_f64<V: IntoF64>(value: V) -> f64 {
value.into_f64()
}
#[cfg(test)]
mod tests {
use super::Unit;
#[test]
fn test_unit_conversions() {
let all_variants = vec![
Unit::Count,
Unit::Percent,
Unit::Seconds,
Unit::Milliseconds,
Unit::Microseconds,
Unit::Nanoseconds,
Unit::Tebibytes,
Unit::Gigibytes,
Unit::Mebibytes,
Unit::Kibibytes,
Unit::Bytes,
Unit::TerabitsPerSecond,
Unit::GigabitsPerSecond,
Unit::MegabitsPerSecond,
Unit::KilobitsPerSecond,
Unit::BitsPerSecond,
Unit::CountPerSecond,
];
for variant in all_variants {
let s = variant.as_str();
let parsed = Unit::from_string(s);
assert_eq!(Some(variant), parsed);
}
}
}