feat: added gauge type & some tests

mem-usage
Jef Roosens 2022-12-26 18:17:27 +01:00
parent a1049943a4
commit 52fbf8ce5d
8 changed files with 227 additions and 50 deletions

2
.gitignore vendored 100644
View File

@ -0,0 +1,2 @@
*.c
*.so

View File

@ -2,12 +2,12 @@ module metrics
import sync.stdatomic import sync.stdatomic
struct CounterEntry { struct Counter {
metric Metric metric Metric
index int data u64
} }
struct HistogramEntry { struct FloatSeries {
metric Metric metric Metric
pub mut: pub mut:
data shared []f64 data shared []f64
@ -16,72 +16,66 @@ pub mut:
[heap] [heap]
struct DefaultCollector { struct DefaultCollector {
mut: mut:
// The mutex for counters also applies to counter_indexes. Both data counters shared map[string]&Counter
// structuress are only ever updated together. Note that only registering a histograms shared map[string]&FloatSeries
// new metric actually changes these; all operations on already existing gauges shared map[string]&FloatSeries
// metrics use atomic operations on the elements of the counters array.
counters shared []u64
counter_indexes map[string]CounterEntry
histograms shared map[string]HistogramEntry
} }
pub fn new_default_collector() &DefaultCollector { pub fn new_default_collector() &DefaultCollector {
return &DefaultCollector{ return &DefaultCollector{
counters: []u64{} counters: map[string]&Counter{}
counter_indexes: map[string]CounterEntry{} histograms: map[string]&FloatSeries{}
histograms: map[string]HistogramEntry{} gauges: map[string]&FloatSeries{}
} }
} }
pub fn (mut c DefaultCollector) counter_register(value u64, metric Metric) { pub fn (mut c DefaultCollector) counter_register(value u64, metric Metric) {
lock c.counters { lock c.counters {
c.counters << value c.counters[metric.str()] = &Counter{
c.counter_indexes[metric.str()] = CounterEntry{
metric: metric metric: metric
index: c.counters.len - 1 data: value
} }
} }
} }
pub fn (c &DefaultCollector) counter_increment(metric Metric) { pub fn (c &DefaultCollector) counter_increment(metric Metric) {
rlock c.counters { rlock c.counters {
entry := c.counter_indexes[metric.str()] entry := c.counters[metric.str()]
stdatomic.add_u64(&c.counters[entry.index], 1) stdatomic.add_u64(&entry.data, 1)
} }
} }
pub fn (c &DefaultCollector) counter_get(metric Metric) ?u64 { pub fn (c &DefaultCollector) counter_get(metric Metric) ?u64 {
return rlock c.counters { return rlock c.counters {
entry := c.counter_indexes[metric.str()] or { return none } entry := c.counters[metric.str()] or { return none }
stdatomic.load_u64(&c.counters[entry.index]) stdatomic.load_u64(&entry.data)
} }
} }
pub fn (c &DefaultCollector) counters() []Metric { pub fn (c &DefaultCollector) counters() []Metric {
mut metrics := []Metric{} mut metrics := []Metric{}
rlock c.counters { rlock c.counters {
for _, entry in c.counter_indexes { for _, entry in c.counters {
metrics << entry.metric metrics << entry.metric
} }
} }
return metrics return metrics
} }
pub fn (mut c DefaultCollector) histogram_register(metric Metric) { pub fn (mut c DefaultCollector) histogram_register(metric Metric) {
lock c.histograms { lock c.histograms {
c.histograms[metric.str()] = HistogramEntry{ c.histograms[metric.str()] = &FloatSeries{
metric: metric metric: metric
data: []f64{} data: []f64{}
} }
} }
} }
pub fn (c &DefaultCollector) histogram_add(value f64, metric Metric) { pub fn (c &DefaultCollector) histogram_record(value f64, metric Metric) {
entry := rlock c.histograms { entry := rlock c.histograms {
c.histograms[metric.str()] c.histograms[metric.str()]
} }
@ -102,3 +96,52 @@ pub fn (c &DefaultCollector) histogram_get(metric Metric) ?[]f64 {
entry.data.clone() entry.data.clone()
} }
} }
pub fn (mut c DefaultCollector) gauge_register(value f64, metric Metric) {
lock c.gauges {
c.gauges[metric.str()] = &FloatSeries{
metric: metric
data: [value]
}
}
}
pub fn (c &DefaultCollector) gauge_add(value f64, metric Metric) {
entry := rlock c.gauges {
c.gauges[metric.str()]
}
lock entry.data {
entry.data[0] += value
}
}
pub fn (c &DefaultCollector) gauge_sub(value f64, metric Metric) {
entry := rlock c.gauges {
c.gauges[metric.str()]
}
lock entry.data {
entry.data[0] -= value
}
}
pub fn (c &DefaultCollector) gauge_set(value f64, metric Metric) {
entry := rlock c.gauges {
c.gauges[metric.str()]
}
lock entry.data {
entry.data[0] = value
}
}
pub fn (c &DefaultCollector) gauge_get(metric Metric) ?f64 {
entry := rlock c.gauges {
c.gauges[metric.str()]
}
return rlock entry.data {
entry.data[0]
}
}

112
collector_test.v 100644
View File

@ -0,0 +1,112 @@
module metrics
fn test_implements_interface() {
_ := MetricsCollector(new_default_collector())
}
fn test_null_implements_interface() {
_ := MetricsCollector(new_null_collector())
}
fn test_counter_increment() {
mut m := new_default_collector()
m.counter_register(0, name: 'test')
m.counter_increment(name: 'test')
assert m.counter_get(name: 'test')? == u64(1)
m.counter_increment(name: 'test')
assert m.counter_get(name: 'test')? == u64(2)
// Test with labels
metric := Metric{
name: 'test2'
labels: [['hi', 'label']!, ['hi2', 'label2']!]
}
m.counter_register(15, metric)
m.counter_increment(metric)
assert m.counter_get(metric)? == u64(16)
}
fn test_histogram() {
mut m := new_default_collector()
m.histogram_register(name: 'test')
m.histogram_record(5.0, name: 'test')
assert m.histogram_get(name: 'test')? == [5.0]
m.histogram_record(7.0, name: 'test')
assert m.histogram_get(name: 'test')? == [5.0, 7.0]
// Test with labels
metric := Metric{
name: 'test2'
labels: [['hi', 'label']!, ['hi2', 'label2']!]
}
m.histogram_register(metric)
m.histogram_record(5.0, metric)
assert m.histogram_get(metric)? == [5.0]
m.histogram_record(7.0, metric)
assert m.histogram_get(metric)? == [5.0, 7.0]
}
fn test_gauge_add() {
mut m := new_default_collector()
m.gauge_register(0.0, name: 'test')
m.gauge_add(5.0, name: 'test')
assert m.gauge_get(name: 'test')? == 5.0
// Test with labels
metric := Metric{
name: 'test2'
labels: [['hi', 'label']!, ['hi2', 'label2']!]
}
m.gauge_register(3.0, metric)
m.gauge_add(5.0, metric)
assert m.gauge_get(metric)? == 8.0
}
fn test_gauge_sub() {
mut m := new_default_collector()
m.gauge_register(0.0, name: 'test')
m.gauge_sub(5.0, name: 'test')
assert m.gauge_get(name: 'test')? == -5.0
// Test with labels
metric := Metric{
name: 'test2'
labels: [['hi', 'label']!, ['hi2', 'label2']!]
}
m.gauge_register(3.0, metric)
m.gauge_sub(5.0, metric)
assert m.gauge_get(metric)? == -2.0
}
fn test_gauge_set() {
mut m := new_default_collector()
m.gauge_register(0.0, name: 'test')
m.gauge_set(3.0, name: 'test')
assert m.gauge_get(name: 'test')? == 3.0
m.gauge_set(5.0, name: 'test')
assert m.gauge_get(name: 'test')? == 5.0
// Test with labels
metric := Metric{
name: 'test2'
labels: [['hi', 'label']!, ['hi2', 'label2']!]
}
m.gauge_register(0.0, metric)
m.gauge_set(3.0, metric)
assert m.gauge_get(metric)? == 3.0
m.gauge_set(5.0, metric)
assert m.gauge_get(metric)? == 5.0
}

View File

@ -1,14 +0,0 @@
module metrics
fn test_counter_increment() {
mut m := new_default_collector()
m.counter_register(0, name: 'test')
m.counter_increment(name: 'test')
assert m.counter_get(name: 'test')? == u64(1)
m.counter_increment(name: 'test')
assert m.counter_get(name: 'test')? == u64(2)
}

View File

@ -0,0 +1,10 @@
module exporter
import io
import metrics { MetricsCollector }
pub interface MetricsExporter {
load(collector MetricsCollector)
export_to_writer(writer io.Writer) !
export_to_string() string !
}

View File

@ -0,0 +1,4 @@
module exporter
pub struct PrometheusExporter {
}

View File

@ -20,11 +20,17 @@ pub fn (m &Metric) str() string {
} }
pub interface MetricsCollector { pub interface MetricsCollector {
counter_register(value u64, metric Metric)
counter_increment(metric Metric) counter_increment(metric Metric)
counter_get(metric Metric) ?u64 counter_get(metric Metric) ?u64
counters() []Metric counters() []Metric
histogram_record(value f64, metric Metric)
histogram_get(metric Metric) ?[]f64
gauge_add(value f64, metric Metric)
gauge_sub(value f64, metric Metric)
gauge_set(value f64, metric Metric)
gauge_get(metric Metric) ?f64
mut:
counter_register(value u64, metric Metric)
histogram_register(metric Metric) histogram_register(metric Metric)
histogram_add(value f64, metric Metric) gauge_register(value f64, metric Metric)
histogram_get(metric Metric) ?
} }

18
null.v
View File

@ -15,12 +15,26 @@ pub fn (c &NullCollector) counter_get(metric Metric) ?u64 {
return none return none
} }
pub fn (c &NullCollector) counters() []Metric { return [] } pub fn (c &NullCollector) counters() []Metric {
return []
}
pub fn (c &NullCollector) histogram_register(metric Metric) {} pub fn (c &NullCollector) histogram_register(metric Metric) {}
pub fn (c &NullCollector) histogram_add(value f64, metric Metric) {} pub fn (c &NullCollector) histogram_record(value f64, metric Metric) {}
pub fn (c &NullCollector) histogram_get(metric Metric) ?[]f64 { pub fn (c &NullCollector) histogram_get(metric Metric) ?[]f64 {
return none return none
} }
pub fn (c &NullCollector) gauge_register(value f64, metric Metric) {}
pub fn (c &NullCollector) gauge_add(value f64, metric Metric) {}
pub fn (c &NullCollector) gauge_sub(value f64, metric Metric) {}
pub fn (c &NullCollector) gauge_set(value f64, metric Metric) {}
pub fn (c &NullCollector) gauge_get(metric Metric) ?f64 {
return none
}