///|
/// A structured failure returned by a framework-neutral custom collector.
///
/// `CollectorAdapter` deliberately uses an explicit `Result` rather than a
/// trait object. MoonBit packages can therefore register heterogeneous
/// collectors on every supported target without relying on runtime trait
/// object dispatch.
pub(all) suberror CollectorError {
Failed(String)
} derive(Debug, Eq)
///|
/// A custom collector represented by immutable descriptors and a collection
/// callback. The callback may produce zero or more samples for each
/// descriptor, but may not introduce an undeclared family.
pub struct CollectorAdapter {
descriptors : Array[@metric.Descriptor]
collect : () -> Result[Array[FamilySnapshot], CollectorError]
}
///|
/// Construct a framework-neutral custom collector adapter.
///
/// Descriptor uniqueness and all cross-registry conflict checks happen in
/// `Registry::register_collector`, where they can be checked atomically.
pub fn CollectorAdapter::new(
descriptors : Array[@metric.Descriptor],
collect : () -> Result[Array[FamilySnapshot], CollectorError],
) -> CollectorAdapter {
{ descriptors: descriptors.copy(), collect }
}
///|
pub fn CollectorAdapter::descriptors(
self : CollectorAdapter,
) -> Array[@metric.Descriptor] {
self.descriptors.copy()
}
///|
fn CollectorAdapter::collect_snapshots(
self : CollectorAdapter,
) -> Result[Array[FamilySnapshot], CollectorError] {
(self.collect)()
}
///|
enum CollectorEntry {
CounterEntry(Int, @metric.Counter, DescriptorInfo)
GaugeEntry(Int, @metric.Gauge, DescriptorInfo)
HistogramEntry(Int, @metric.Histogram, DescriptorInfo)
CounterVecEntry(Int, @vector.CounterVec, DescriptorInfo)
GaugeVecEntry(Int, @vector.GaugeVec, DescriptorInfo)
HistogramVecEntry(Int, @vector.HistogramVec, DescriptorInfo)
AdapterEntry(Int, CollectorAdapter, Array[DescriptorInfo])
}
///|
fn CollectorEntry::token(self : CollectorEntry) -> Int {
match self {
CounterEntry(token, _, _) => token
GaugeEntry(token, _, _) => token
HistogramEntry(token, _, _) => token
CounterVecEntry(token, _, _) => token
GaugeVecEntry(token, _, _) => token
HistogramVecEntry(token, _, _) => token
AdapterEntry(token, _, _) => token
}
}
///|
fn CollectorEntry::descriptors(self : CollectorEntry) -> Array[DescriptorInfo] {
match self {
CounterEntry(_, _, descriptor) => [descriptor]
GaugeEntry(_, _, descriptor) => [descriptor]
HistogramEntry(_, _, descriptor) => [descriptor]
CounterVecEntry(_, _, descriptor) => [descriptor]
GaugeVecEntry(_, _, descriptor) => [descriptor]
HistogramVecEntry(_, _, descriptor) => [descriptor]
AdapterEntry(_, _, descriptors) => descriptors.copy()
}
}
///|
fn collect_counter_vec_samples(
vector : @vector.CounterVec,
) -> Array[ScalarSampleSnapshot] {
let samples : Array[ScalarSampleSnapshot] = []
for child in vector.children() {
samples.push(scalar_sample(child.labels(), child.snapshot().value))
}
samples
}
///|
fn collect_gauge_vec_samples(
vector : @vector.GaugeVec,
) -> Array[ScalarSampleSnapshot] {
let samples : Array[ScalarSampleSnapshot] = []
for child in vector.children() {
samples.push(scalar_sample(child.labels(), child.snapshot().value))
}
samples
}
///|
fn collect_histogram_vec_samples(
vector : @vector.HistogramVec,
) -> Array[HistogramSampleSnapshot] {
let samples : Array[HistogramSampleSnapshot] = []
for child in vector.children() {
samples.push(histogram_sample(child.labels(), child.snapshot()))
}
samples
}
///|
fn CollectorEntry::collect(
self : CollectorEntry,
) -> Result[Array[FamilySnapshot], CollectorError] {
match self {
CounterEntry(_, counter, descriptor) =>
Ok([
FamilySnapshot::scalar(
descriptor.name,
descriptor.help,
descriptor.family_type(),
[scalar_sample(descriptor.const_labels, counter.snapshot().value)],
descriptor.unit,
),
])
GaugeEntry(_, gauge, descriptor) =>
Ok([
FamilySnapshot::scalar(
descriptor.name,
descriptor.help,
descriptor.family_type(),
[scalar_sample(descriptor.const_labels, gauge.snapshot().value)],
descriptor.unit,
),
])
HistogramEntry(_, histogram, descriptor) =>
Ok([
FamilySnapshot::histogram(
descriptor.name,
descriptor.help,
[histogram_sample(descriptor.const_labels, histogram.snapshot())],
descriptor.unit,
),
])
CounterVecEntry(_, vector, descriptor) =>
Ok([
FamilySnapshot::scalar(
descriptor.name,
descriptor.help,
descriptor.family_type(),
collect_counter_vec_samples(vector),
descriptor.unit,
),
])
GaugeVecEntry(_, vector, descriptor) =>
Ok([
FamilySnapshot::scalar(
descriptor.name,
descriptor.help,
descriptor.family_type(),
collect_gauge_vec_samples(vector),
descriptor.unit,
),
])
HistogramVecEntry(_, vector, descriptor) =>
Ok([
FamilySnapshot::histogram(
descriptor.name,
descriptor.help,
collect_histogram_vec_samples(vector),
descriptor.unit,
),
])
AdapterEntry(_, adapter, _) => adapter.collect_snapshots()
}
}