Skip to content

Commit 4fc8fa1

Browse files
committed
refactor: reorganize modules
1 parent b4af3b6 commit 4fc8fa1

File tree

9 files changed

+225
-179
lines changed

9 files changed

+225
-179
lines changed

Cargo.lock

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/primitives/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ url = "2.5.4"
3030
zerocopy = "0.7"
3131

3232
[dev-dependencies]
33+
approx = "0.5.1"
3334
formatjson = "0.3.1"
3435
pretty_assertions = "1.4.1"
3536
rstest = "0.25.0"
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
use serde::Serialize;
2+
3+
#[derive(Debug, Clone, Serialize, Default, PartialEq)]
4+
pub struct Counter(u64);
5+
6+
impl Counter {
7+
#[must_use]
8+
pub fn new(value: u64) -> Self {
9+
Self(value)
10+
}
11+
12+
#[must_use]
13+
pub fn value(&self) -> u64 {
14+
self.0
15+
}
16+
17+
pub fn increment(&mut self, value: u64) {
18+
self.0 += value;
19+
}
20+
}
21+
22+
#[cfg(test)]
23+
mod tests {
24+
use super::*;
25+
26+
#[test]
27+
fn test_counter() {
28+
let mut counter = Counter::new(0);
29+
assert_eq!(counter.value(), 0);
30+
31+
counter.increment(5);
32+
assert_eq!(counter.value(), 5);
33+
34+
counter.increment(3);
35+
assert_eq!(counter.value(), 8);
36+
}
37+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
use serde::Serialize;
2+
3+
#[derive(Debug, Clone, Serialize, Default, PartialEq)]
4+
pub struct Gauge(f64);
5+
6+
impl Gauge {
7+
#[must_use]
8+
pub fn new(value: f64) -> Self {
9+
Self(value)
10+
}
11+
12+
#[must_use]
13+
pub fn value(&self) -> f64 {
14+
self.0
15+
}
16+
17+
pub fn set(&mut self, value: f64) {
18+
self.0 = value;
19+
}
20+
}
21+
22+
#[cfg(test)]
23+
mod tests {
24+
use approx::assert_relative_eq;
25+
26+
use super::*;
27+
28+
#[test]
29+
fn test_gauge() {
30+
let mut gauge = Gauge::new(0.0);
31+
assert_relative_eq!(gauge.value(), 0.0);
32+
33+
gauge.set(5.5);
34+
assert_relative_eq!(gauge.value(), 5.5);
35+
36+
gauge.set(3.3);
37+
assert_relative_eq!(gauge.value(), 3.3);
38+
}
39+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
use super::sample_collection::SampleCollection;
2+
use super::MetricName;
3+
4+
#[derive(Debug, Clone, Default, PartialEq)]
5+
pub struct Metric<T> {
6+
pub name: MetricName,
7+
pub samples: SampleCollection<T>,
8+
}

packages/primitives/src/metrics/metric_collection.rs

Lines changed: 9 additions & 179 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
use std::collections::{HashMap, HashSet};
22

3-
use chrono::DateTime;
43
use serde::ser::{SerializeSeq, Serializer};
54
use serde::Serialize;
65

6+
use super::counter::Counter;
7+
use super::gauge::Gauge;
78
use super::label_set::LabelSet;
9+
use super::metric::Metric;
810
use super::MetricName;
11+
use crate::metrics::sample_collection::SampleCollection;
912
use crate::DurationSinceUnixEpoch;
1013

1114
#[derive(Debug, Clone, Default, PartialEq)]
@@ -217,160 +220,12 @@ impl MetricKindCollection<Gauge> {
217220
}
218221
}
219222

220-
#[derive(Debug, Clone, Default, PartialEq)]
221-
pub struct Metric<T> {
222-
pub name: MetricName,
223-
pub samples: SampleCollection<T>,
224-
}
225-
226-
impl<T: Serialize> Serialize for SampleCollection<T> {
227-
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
228-
where
229-
S: Serializer,
230-
{
231-
let samples: Vec<&Sample<T>> = self.samples.values().collect();
232-
samples.serialize(serializer)
233-
}
234-
}
235-
236-
#[derive(Debug, Clone, Default, PartialEq)]
237-
pub struct SampleCollection<T> {
238-
samples: HashMap<LabelSet, Sample<T>>,
239-
}
240-
241-
impl<T> SampleCollection<T> {
242-
/// # Panics
243-
///
244-
/// Panics if there are duplicate `LabelSets` in the provided samples.
245-
#[must_use]
246-
pub fn new(samples: Vec<Sample<T>>) -> Self {
247-
let mut map = HashMap::with_capacity(samples.len());
248-
for sample in samples {
249-
assert!(
250-
map.insert(sample.labels().clone(), sample).is_none(),
251-
"Duplicate LabelSet found in SampleCollection"
252-
);
253-
}
254-
Self { samples: map }
255-
}
256-
257-
#[must_use]
258-
pub fn get(&self, label: &LabelSet) -> Option<&Sample<T>> {
259-
self.samples.get(label)
260-
}
261-
262-
#[must_use]
263-
pub fn get_mut(&mut self, label: &LabelSet) -> Option<&mut Sample<T>> {
264-
self.samples.get_mut(label)
265-
}
266-
}
267-
268-
#[derive(Debug, Clone, Serialize, PartialEq)]
269-
pub struct Sample<T> {
270-
value: T,
271-
272-
#[serde(serialize_with = "serialize_duration")]
273-
update_at: DurationSinceUnixEpoch,
274-
275-
labels: LabelSet,
276-
}
277-
278-
impl<T> Sample<T> {
279-
#[must_use]
280-
pub fn new(value: T, update_at: DurationSinceUnixEpoch, labels: LabelSet) -> Self {
281-
Self {
282-
value,
283-
update_at,
284-
labels,
285-
}
286-
}
287-
288-
#[must_use]
289-
pub fn labels(&self) -> &LabelSet {
290-
&self.labels
291-
}
292-
293-
#[must_use]
294-
pub fn value(&self) -> &T {
295-
&self.value
296-
}
297-
298-
pub fn value_mut(&mut self) -> &mut T {
299-
&mut self.value
300-
}
301-
302-
#[must_use]
303-
pub fn update_at(&self) -> DurationSinceUnixEpoch {
304-
self.update_at
305-
}
306-
307-
pub fn set_update_at(&mut self, time: DurationSinceUnixEpoch) {
308-
self.update_at = time;
309-
}
310-
}
311-
312-
/// Serializes the `update_at` field as a string in ISO 8601 format (RFC 3339).
313-
///
314-
/// # Errors
315-
///
316-
/// Returns an error if:
317-
/// - The conversion from `u64` to `i64` fails.
318-
/// - The timestamp is invalid.
319-
fn serialize_duration<S>(duration: &DurationSinceUnixEpoch, serializer: S) -> Result<S::Ok, S::Error>
320-
where
321-
S: Serializer,
322-
{
323-
let secs = i64::try_from(duration.as_secs()).map_err(|_| serde::ser::Error::custom("Timestamp too large"))?;
324-
let nanos = duration.subsec_nanos();
325-
326-
let datetime = DateTime::from_timestamp(secs, nanos).ok_or_else(|| serde::ser::Error::custom("Invalid timestamp"))?;
327-
328-
serializer.serialize_str(&datetime.to_rfc3339()) // Serializes as ISO 8601 (RFC 3339)
329-
}
330-
331-
#[derive(Debug, Clone, Serialize, Default, PartialEq)]
332-
pub struct Counter(u64);
333-
334-
impl Counter {
335-
#[must_use]
336-
pub fn new(value: u64) -> Self {
337-
Self(value)
338-
}
339-
340-
#[must_use]
341-
pub fn value(&self) -> u64 {
342-
self.0
343-
}
344-
345-
pub fn increment(&mut self, value: u64) {
346-
self.0 += value;
347-
}
348-
}
349-
350-
#[derive(Debug, Clone, Serialize, Default, PartialEq)]
351-
pub struct Gauge(f64);
352-
353-
impl Gauge {
354-
#[must_use]
355-
pub fn new(value: f64) -> Self {
356-
Self(value)
357-
}
358-
359-
#[must_use]
360-
pub fn value(&self) -> f64 {
361-
self.0
362-
}
363-
364-
pub fn set(&mut self, value: f64) {
365-
self.0 = value;
366-
}
367-
}
368-
369223
#[cfg(test)]
370224
mod tests {
371225
use pretty_assertions::assert_eq;
372226

373227
use super::*;
228+
use crate::metrics::sample::Sample;
374229
use crate::metrics::{LabelName, LabelValue};
375230

376231
#[test]
@@ -381,11 +236,7 @@ mod tests {
381236
let mut metric_collection = MetricCollection {
382237
counters: MetricKindCollection::new(vec![Metric {
383238
name: MetricName::new("test_counter"),
384-
samples: SampleCollection::new(vec![Sample {
385-
value: Counter::new(0),
386-
update_at: time,
387-
labels: label_set.clone(),
388-
}]),
239+
samples: SampleCollection::new(vec![Sample::new(Counter::new(0), time, label_set.clone())]),
389240
}]),
390241
gauges: MetricKindCollection::new(vec![]),
391242
};
@@ -401,7 +252,7 @@ mod tests {
401252

402253
#[test]
403254
#[should_panic(expected = "Metric names must be unique across counters and gauges")]
404-
fn test_duplicate_names_across_types() {
255+
fn it_should_not_allow_duplicate_names_across_types() {
405256
let counter = MetricKindCollection::new(vec![Metric {
406257
name: MetricName::new("test_metric"),
407258
samples: SampleCollection::new(vec![]),
@@ -428,11 +279,7 @@ mod tests {
428279
let metric_collection = MetricCollection::new(
429280
MetricKindCollection::new(vec![Metric {
430281
name: MetricName::new("announce_requests_received_total"),
431-
samples: SampleCollection::new(vec![Sample {
432-
value: Counter::new(1), // Initialize with 1 to match the test expectation
433-
update_at: time,
434-
labels: label_set.clone(),
435-
}]),
282+
samples: SampleCollection::new(vec![Sample::new(Counter::new(1), time, label_set.clone())]),
436283
}]),
437284
MetricKindCollection::new(vec![]),
438285
);
@@ -487,11 +334,7 @@ mod tests {
487334
let metric_collection = MetricCollection::new(
488335
MetricKindCollection::new(vec![Metric {
489336
name: MetricName::new("announce_requests_received_total"),
490-
samples: SampleCollection::new(vec![Sample {
491-
value: Counter::new(1),
492-
update_at: time,
493-
labels: label_set.clone(),
494-
}]),
337+
samples: SampleCollection::new(vec![Sample::new(Counter::new(1), time, label_set.clone())]),
495338
}]),
496339
MetricKindCollection::new(vec![]),
497340
);
@@ -502,17 +345,4 @@ mod tests {
502345

503346
assert_eq!(prometheus_output, expected);
504347
}
505-
506-
#[test]
507-
fn test_counter() {
508-
let counter = Counter::new(42);
509-
assert_eq!(counter.value(), 42);
510-
}
511-
512-
#[test]
513-
#[allow(clippy::float_cmp)]
514-
fn test_gauge() {
515-
let gauge = Gauge::new(3.35);
516-
assert_eq!(gauge.value(), 3.35);
517-
}
518348
}

packages/primitives/src/metrics/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
1+
pub mod counter;
2+
pub mod gauge;
13
pub mod label_set;
4+
pub mod metric;
25
pub mod metric_collection;
6+
pub mod sample;
7+
pub mod sample_collection;
38

49
use derive_more::Display;
510
use serde::{Deserialize, Serialize};

0 commit comments

Comments
 (0)