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
struct CounterEntry {
struct Counter {
metric Metric
index int
data u64
}
struct HistogramEntry {
struct FloatSeries {
metric Metric
pub mut:
data shared []f64
@ -16,72 +16,66 @@ pub mut:
[heap]
struct DefaultCollector {
mut:
// The mutex for counters also applies to counter_indexes. Both data
// structuress are only ever updated together. Note that only registering a
// new metric actually changes these; all operations on already existing
// metrics use atomic operations on the elements of the counters array.
counters shared []u64
counter_indexes map[string]CounterEntry
histograms shared map[string]HistogramEntry
counters shared map[string]&Counter
histograms shared map[string]&FloatSeries
gauges shared map[string]&FloatSeries
}
pub fn new_default_collector() &DefaultCollector {
return &DefaultCollector{
counters: []u64{}
counter_indexes: map[string]CounterEntry{}
histograms: map[string]HistogramEntry{}
counters: map[string]&Counter{}
histograms: map[string]&FloatSeries{}
gauges: map[string]&FloatSeries{}
}
}
pub fn (mut c DefaultCollector) counter_register(value u64, metric Metric) {
lock c.counters {
c.counters << value
c.counter_indexes[metric.str()] = CounterEntry{
c.counters[metric.str()] = &Counter{
metric: metric
index: c.counters.len - 1
data: value
}
}
}
pub fn (c &DefaultCollector) counter_increment(metric Metric) {
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 {
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 {
mut metrics := []Metric{}
mut metrics := []Metric{}
rlock c.counters {
for _, entry in c.counter_indexes {
metrics << entry.metric
}
}
rlock c.counters {
for _, entry in c.counters {
metrics << entry.metric
}
}
return metrics
return metrics
}
pub fn (mut c DefaultCollector) histogram_register(metric Metric) {
lock c.histograms {
c.histograms[metric.str()] = HistogramEntry{
c.histograms[metric.str()] = &FloatSeries{
metric: metric
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 {
c.histograms[metric.str()]
}
@ -102,3 +96,52 @@ pub fn (c &DefaultCollector) histogram_get(metric Metric) ?[]f64 {
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 {
counter_register(value u64, metric Metric)
counter_increment(metric Metric)
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_add(value f64, metric Metric)
histogram_get(metric Metric) ?
gauge_register(value f64, metric Metric)
}

18
null.v
View File

@ -15,12 +15,26 @@ pub fn (c &NullCollector) counter_get(metric Metric) ?u64 {
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_add(value f64, metric Metric) {}
pub fn (c &NullCollector) histogram_record(value f64, metric Metric) {}
pub fn (c &NullCollector) histogram_get(metric Metric) ?[]f64 {
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
}