sentry_core/
units.rs

1//! Type definitions for Sentry metrics.
2
3use std::borrow::Cow;
4use std::fmt;
5
6/// The unit of measurement of a metric value.
7///
8/// Units augment metric values by giving them a magnitude and semantics. There are certain types of
9/// units that are subdivided in their precision:
10///  - [`DurationUnit`]: time durations
11///  - [`InformationUnit`]: sizes of information
12///  - [`FractionUnit`]: fractions
13///
14/// You are not restricted to these units, but can use any `&'static str` or `String` as a unit.
15#[derive(Clone, Debug, Eq, PartialEq, Hash, Default)]
16pub enum MetricUnit {
17    /// A time duration, defaulting to `"millisecond"`.
18    Duration(DurationUnit),
19    /// Size of information derived from bytes, defaulting to `"byte"`.
20    Information(InformationUnit),
21    /// Fractions such as percentages, defaulting to `"ratio"`.
22    Fraction(FractionUnit),
23    /// user-defined units without builtin conversion or default.
24    Custom(Cow<'static, str>),
25    /// Untyped value without a unit (`""`).
26    #[default]
27    None,
28}
29
30impl MetricUnit {
31    /// Returns `true` if the metric_unit is [`None`].
32    pub fn is_none(&self) -> bool {
33        matches!(self, Self::None)
34    }
35}
36
37impl fmt::Display for MetricUnit {
38    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
39        match self {
40            MetricUnit::Duration(u) => u.fmt(f),
41            MetricUnit::Information(u) => u.fmt(f),
42            MetricUnit::Fraction(u) => u.fmt(f),
43            MetricUnit::Custom(u) => u.fmt(f),
44            MetricUnit::None => f.write_str("none"),
45        }
46    }
47}
48
49impl std::str::FromStr for MetricUnit {
50    type Err = ParseMetricUnitError;
51
52    fn from_str(s: &str) -> Result<Self, Self::Err> {
53        Ok(match s {
54            "nanosecond" | "ns" => Self::Duration(DurationUnit::NanoSecond),
55            "microsecond" => Self::Duration(DurationUnit::MicroSecond),
56            "millisecond" | "ms" => Self::Duration(DurationUnit::MilliSecond),
57            "second" | "s" => Self::Duration(DurationUnit::Second),
58            "minute" => Self::Duration(DurationUnit::Minute),
59            "hour" => Self::Duration(DurationUnit::Hour),
60            "day" => Self::Duration(DurationUnit::Day),
61            "week" => Self::Duration(DurationUnit::Week),
62
63            "bit" => Self::Information(InformationUnit::Bit),
64            "byte" => Self::Information(InformationUnit::Byte),
65            "kilobyte" => Self::Information(InformationUnit::KiloByte),
66            "kibibyte" => Self::Information(InformationUnit::KibiByte),
67            "megabyte" => Self::Information(InformationUnit::MegaByte),
68            "mebibyte" => Self::Information(InformationUnit::MebiByte),
69            "gigabyte" => Self::Information(InformationUnit::GigaByte),
70            "gibibyte" => Self::Information(InformationUnit::GibiByte),
71            "terabyte" => Self::Information(InformationUnit::TeraByte),
72            "tebibyte" => Self::Information(InformationUnit::TebiByte),
73            "petabyte" => Self::Information(InformationUnit::PetaByte),
74            "pebibyte" => Self::Information(InformationUnit::PebiByte),
75            "exabyte" => Self::Information(InformationUnit::ExaByte),
76            "exbibyte" => Self::Information(InformationUnit::ExbiByte),
77
78            "ratio" => Self::Fraction(FractionUnit::Ratio),
79            "percent" => Self::Fraction(FractionUnit::Percent),
80
81            "" | "none" => Self::None,
82            _ => Self::Custom(s.to_owned().into()),
83        })
84    }
85}
86
87impl From<DurationUnit> for MetricUnit {
88    fn from(unit: DurationUnit) -> Self {
89        Self::Duration(unit)
90    }
91}
92
93impl From<InformationUnit> for MetricUnit {
94    fn from(unit: InformationUnit) -> Self {
95        Self::Information(unit)
96    }
97}
98
99impl From<FractionUnit> for MetricUnit {
100    fn from(unit: FractionUnit) -> Self {
101        Self::Fraction(unit)
102    }
103}
104
105impl From<&'static str> for MetricUnit {
106    fn from(unit: &'static str) -> Self {
107        Self::Custom(unit.into())
108    }
109}
110
111impl From<String> for MetricUnit {
112    fn from(unit: String) -> Self {
113        Self::Custom(unit.into())
114    }
115}
116
117impl From<Cow<'static, str>> for MetricUnit {
118    fn from(unit: Cow<'static, str>) -> Self {
119        Self::Custom(unit)
120    }
121}
122
123impl From<Option<String>> for MetricUnit {
124    fn from(unit: Option<String>) -> Self {
125        unit.map_or_else(|| Self::None, |u| Self::Custom(u.into()))
126    }
127}
128
129/// Time duration units used in [`MetricUnit::Duration`].
130///
131/// Defaults to `millisecond`.
132#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
133pub enum DurationUnit {
134    /// Nanosecond (`"nanosecond"`), 10^-9 seconds.
135    NanoSecond,
136    /// Microsecond (`"microsecond"`), 10^-6 seconds.
137    MicroSecond,
138    /// Millisecond (`"millisecond"`), 10^-3 seconds.
139    MilliSecond,
140    /// Full second (`"second"`).
141    Second,
142    /// Minute (`"minute"`), 60 seconds.
143    Minute,
144    /// Hour (`"hour"`), 3600 seconds.
145    Hour,
146    /// Day (`"day"`), 86,400 seconds.
147    Day,
148    /// Week (`"week"`), 604,800 seconds.
149    Week,
150}
151
152impl Default for DurationUnit {
153    fn default() -> Self {
154        Self::MilliSecond
155    }
156}
157
158impl fmt::Display for DurationUnit {
159    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
160        match self {
161            Self::NanoSecond => f.write_str("nanosecond"),
162            Self::MicroSecond => f.write_str("microsecond"),
163            Self::MilliSecond => f.write_str("millisecond"),
164            Self::Second => f.write_str("second"),
165            Self::Minute => f.write_str("minute"),
166            Self::Hour => f.write_str("hour"),
167            Self::Day => f.write_str("day"),
168            Self::Week => f.write_str("week"),
169        }
170    }
171}
172
173/// An error parsing a [`MetricUnit`] or one of its variants.
174#[derive(Clone, Copy, Debug)]
175pub struct ParseMetricUnitError(());
176
177/// Size of information derived from bytes, used in [`MetricUnit::Information`].
178///
179/// Defaults to `byte`. See also [Units of
180/// information](https://en.wikipedia.org/wiki/Units_of_information).
181#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
182pub enum InformationUnit {
183    /// Bit (`"bit"`), corresponding to 1/8 of a byte.
184    ///
185    /// Note that there are computer systems with a different number of bits per byte.
186    Bit,
187    /// Byte (`"byte"`).
188    Byte,
189    /// Kilobyte (`"kilobyte"`), 10^3 bytes.
190    KiloByte,
191    /// Kibibyte (`"kibibyte"`), 2^10 bytes.
192    KibiByte,
193    /// Megabyte (`"megabyte"`), 10^6 bytes.
194    MegaByte,
195    /// Mebibyte (`"mebibyte"`), 2^20 bytes.
196    MebiByte,
197    /// Gigabyte (`"gigabyte"`), 10^9 bytes.
198    GigaByte,
199    /// Gibibyte (`"gibibyte"`), 2^30 bytes.
200    GibiByte,
201    /// Terabyte (`"terabyte"`), 10^12 bytes.
202    TeraByte,
203    /// Tebibyte (`"tebibyte"`), 2^40 bytes.
204    TebiByte,
205    /// Petabyte (`"petabyte"`), 10^15 bytes.
206    PetaByte,
207    /// Pebibyte (`"pebibyte"`), 2^50 bytes.
208    PebiByte,
209    /// Exabyte (`"exabyte"`), 10^18 bytes.
210    ExaByte,
211    /// Exbibyte (`"exbibyte"`), 2^60 bytes.
212    ExbiByte,
213}
214
215impl Default for InformationUnit {
216    fn default() -> Self {
217        Self::Byte
218    }
219}
220
221impl fmt::Display for InformationUnit {
222    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
223        match self {
224            Self::Bit => f.write_str("bit"),
225            Self::Byte => f.write_str("byte"),
226            Self::KiloByte => f.write_str("kilobyte"),
227            Self::KibiByte => f.write_str("kibibyte"),
228            Self::MegaByte => f.write_str("megabyte"),
229            Self::MebiByte => f.write_str("mebibyte"),
230            Self::GigaByte => f.write_str("gigabyte"),
231            Self::GibiByte => f.write_str("gibibyte"),
232            Self::TeraByte => f.write_str("terabyte"),
233            Self::TebiByte => f.write_str("tebibyte"),
234            Self::PetaByte => f.write_str("petabyte"),
235            Self::PebiByte => f.write_str("pebibyte"),
236            Self::ExaByte => f.write_str("exabyte"),
237            Self::ExbiByte => f.write_str("exbibyte"),
238        }
239    }
240}
241
242/// Units of fraction used in [`MetricUnit::Fraction`].
243///
244/// Defaults to `ratio`.
245#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
246pub enum FractionUnit {
247    /// Floating point fraction of `1`.
248    Ratio,
249    /// Ratio expressed as a fraction of `100`. `100%` equals a ratio of `1.0`.
250    Percent,
251}
252
253impl Default for FractionUnit {
254    fn default() -> Self {
255        Self::Ratio
256    }
257}
258
259impl fmt::Display for FractionUnit {
260    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
261        match self {
262            Self::Ratio => f.write_str("ratio"),
263            Self::Percent => f.write_str("percent"),
264        }
265    }
266}