metrique_core/lib.rs
1// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2// SPDX-License-Identifier: Apache-2.0
3
4#![deny(missing_docs)]
5#![doc = include_str!("../README.md")]
6
7use metrique_writer_core::{EntryWriter, entry::SampleGroupElement};
8
9mod atomics;
10mod close_value_impls;
11mod inflectable_entry_impls;
12mod namestyle;
13
14pub use atomics::Counter;
15pub use namestyle::NameStyle;
16
17/// Close a given value
18///
19/// This gives an opportunity do things like stopping timers, collecting fanned-in data, etc.
20///
21/// If possible, implement this trait for both `&MyValue` and `MyValue`, as this will allow
22/// use via smart pointers (e.g. on Arc<MyValue>).
23///
24/// ```
25/// use metrique::{CloseValue, CloseValueRef};
26///
27/// struct MyValue;
28///
29/// impl CloseValue for &'_ MyValue {
30/// type Closed = u32;
31/// fn close(self) -> Self::Closed { 42 }
32/// }
33///
34/// impl CloseValue for MyValue {
35/// type Closed = u32;
36/// fn close(self) -> Self::Closed { self.close_ref() /* delegate to by-ref implementation */ }
37/// }
38/// ```
39#[diagnostic::on_unimplemented(
40 message = "CloseValue is not implemented for {Self}",
41 note = "You may need to add `#[metrics]` to `{Self}` or implement `CloseValue` directly."
42)]
43pub trait CloseValue {
44 /// The type produced by closing this value
45 type Closed;
46
47 /// Close the value
48 fn close(self) -> Self::Closed;
49}
50
51mod private {
52 pub trait Sealed {}
53}
54
55/// Close a value without taking ownership
56///
57/// This trait is meant to be used for [`CloseValue`] impls for smart-pointer-like
58/// types, as in
59///
60/// ```
61/// use metrique::{CloseValue, CloseValueRef};
62///
63/// struct Smaht<T>(T);
64///
65/// impl<T: CloseValueRef> CloseValue for &'_ Smaht<T> {
66/// type Closed = T::Closed;
67/// fn close(self) -> T::Closed { self.0.close_ref() }
68/// }
69///
70/// impl<T: CloseValueRef> CloseValue for Smaht<T> {
71/// type Closed = T::Closed;
72/// fn close(self) -> T::Closed { self.0.close_ref() }
73/// }
74/// ```
75///
76/// This trait is not to be implemented or called directly. It mostly exists
77/// because it makes trait inference a bit smarter (it's also not a full
78/// trait alias due to trait inference reasons).
79#[diagnostic::on_unimplemented(
80 message = "CloseValueRef is not implemented for {Self}",
81 note = "You may need to add `#[metrics]` to `{Self}` or implement `CloseValueRef` directly."
82)]
83pub trait CloseValueRef: private::Sealed {
84 /// The type produced by closing this value
85 type Closed;
86
87 /// Close the value
88 fn close_ref(&self) -> Self::Closed;
89}
90
91impl<C, T> private::Sealed for T where for<'a> &'a Self: CloseValue<Closed = C> {}
92
93impl<C, T> CloseValueRef for T
94where
95 for<'a> &'a Self: CloseValue<Closed = C>,
96{
97 type Closed = C;
98 fn close_ref(&self) -> Self::Closed {
99 <&Self>::close(self)
100 }
101}
102
103/// An object that can be closed into an [InflectableEntry]. This is the
104/// normal way of generating a metric entry - by starting with a a struct
105/// that implements this trait (that is generally generated using the `#[metrics]` macro),
106/// wrapping it in a [`RootEntry`] to generate an [`Entry`], and then emitting that
107/// to an [`EntrySink`].
108///
109/// This is just a trait alias for `CloseValue<Closed: InflectableEntry>`.
110///
111/// [close-value]: CloseValue
112/// [`Entry`]: metrique_writer_core::Entry
113/// [`EntrySink`]: metrique_writer_core::EntrySink
114/// [`RootEntry`]: metrique_writer_core::RootEntry
115pub trait CloseEntry: CloseValue<Closed: InflectableEntry> {}
116impl<T: ?Sized + CloseValue<Closed: InflectableEntry>> CloseEntry for T {}
117
118/// A trait for metric entries where the names of the fields can be "inflected"
119/// using a [`NameStyle`]. This defines the interface for metric *sources*
120/// that want to be able to generate metric structs that can be renamed
121/// without having any string operations happen at runtime.
122///
123/// Both `InflectableEntry` and [`Entry`] are intended to be "pure" structs - all
124/// references to channels, counters and the like are expected to be resolved when
125/// creating the `InflectableEntry`.
126///
127/// An `InflectableEntry` with any specific set of type parameters is equivalent to an
128/// [`Entry`]. It should be wrapped by a wrapper that implements [`Entry`] and delegates
129/// to it with a particular set of type parameters, for example `RootEntry`, and then
130/// emitting that to an [`EntrySink`].
131///
132/// The normal way of generating a metric entry is by starting with a struct
133/// that implements [`CloseEntry`] (that is generally generated
134/// using the `#[metrics]` macro), wrapping it in a `RootEntry` to generate an
135/// [`Entry`], and then emitting that to an entry sink.
136///
137/// Design note: in theory you could have a world where `InflectableEntry`
138/// and [`Entry`] are the same trait (where the sinks use the default type parameters).
139/// In practice, it is desired that the trait [`Entry`] will have very few breaking
140/// changes since it needs to be identical throughout a program that wants to emit
141/// metrics to a single destination, and therefore `InflectableEntry` is kept separate.
142///
143/// ## Manual Implementations
144///
145/// Currently, there is no (stable) non-macro way of generating an [`InflectableEntry`]
146/// that actually inflects names. If you want to make a manual entry, it is recommended
147/// to implement the [`Entry`] trait, then use a field with `#[metrics(flatten_entry)]`
148/// as follows - though note that this will ignore inflections:
149///
150/// ```
151/// use metrique::unit_of_work::metrics;
152/// use metrique_writer::{Entry, EntryWriter};
153///
154/// struct MyCustomEntry;
155///
156/// impl Entry for MyCustomEntry {
157/// fn write<'a>(&'a self, writer: &mut impl EntryWriter<'a>) {
158/// writer.value("custom", "custom");
159/// }
160/// }
161///
162/// #[metrics]
163/// struct MyMetric {
164/// #[metrics(flatten_entry, no_close)]
165/// field: MyCustomEntry,
166/// }
167/// ```
168///
169/// [`Entry`]: metrique_writer_core::Entry
170/// [`NameStyle`]: namestyle::NameStyle
171/// [`Entry`]: metrique_writer_core::Entry
172/// [`EntrySink`]: metrique_writer_core::EntrySink
173pub trait InflectableEntry<NS: namestyle::NameStyle = namestyle::Identity> {
174 /// Write this metric entry to an EntryWriter
175 fn write<'a>(&'a self, w: &mut impl EntryWriter<'a>);
176 /// Sample group
177 fn sample_group(&self) -> impl Iterator<Item = SampleGroupElement> {
178 vec![].into_iter()
179 }
180}