mirror of
https://github.com/waku-org/nwaku.git
synced 2025-01-28 15:46:33 +00:00
386 lines
13 KiB
Nim
386 lines
13 KiB
Nim
# Copyright (c) 2019-2022 Status Research & Development GmbH
|
|
# Licensed and distributed under either of
|
|
# * MIT license: http://opensource.org/licenses/MIT
|
|
# * Apache License, Version 2.0: http://www.apache.org/licenses/LICENSE-2.0
|
|
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
|
|
|
import net, os, unittest,
|
|
../metrics
|
|
|
|
when defined(metrics):
|
|
import times
|
|
|
|
addExportBackend(
|
|
metricProtocol = STATSD,
|
|
netProtocol = UDP,
|
|
address = "127.0.0.1",
|
|
port = Port(8125)
|
|
)
|
|
addExportBackend(
|
|
metricProtocol = CARBON,
|
|
netProtocol = TCP,
|
|
address = "127.0.0.1",
|
|
port = Port(2003)
|
|
)
|
|
|
|
declareCounter globalCounter, "help"
|
|
declarePublicCounter globalPublicCounter, "help"
|
|
declareGauge globalGauge, "help"
|
|
declarePublicGauge globalPublicGauge, "help"
|
|
|
|
proc gcSafetyTest* {.gcsafe.} = # The test is successful if this proc compiles
|
|
globalCounter.inc 2
|
|
globalPublicCounter.inc(2)
|
|
globalGauge.set 10.0
|
|
globalGauge.inc
|
|
globalGauge.dec
|
|
globalPublicGauge.set(1)
|
|
|
|
suite "counter":
|
|
setup:
|
|
var registry = newRegistry()
|
|
declareCounter myCounter, "help", registry = registry
|
|
|
|
test "basic":
|
|
check myCounter.value == 0
|
|
myCounter.inc()
|
|
check myCounter.value == 1
|
|
myCounter.inc(7)
|
|
check myCounter.value == 8
|
|
myCounter.inc(0.5)
|
|
check myCounter.value == 8.5
|
|
myCounter.inc(-1) # you shouldn't be doing this - but we don't want metrics to crash the app
|
|
check myCounter.value == 8.5
|
|
# name validation (have to use the internal API to get past Nim's identifier validation)
|
|
when defined(metrics):
|
|
expect ValueError:
|
|
var tmp = newCounter("1337", "invalid name")
|
|
|
|
test "alternative API":
|
|
counter("one_off_counter").inc()
|
|
check counter("one_off_counter").value == 1
|
|
counter("one_off_counter").inc(0.5)
|
|
check counter("one_off_counter").value == 1.5
|
|
|
|
# # Can't have different collector types with the same name, but unittest
|
|
# # can't catch an exception raised in the assignment to a {.global.}
|
|
# # variable.
|
|
# expect RegistrationError:
|
|
# check gauge("one_off_counter").value == 0
|
|
|
|
# colons in name
|
|
counter("one:off:counter:colons").inc()
|
|
check counter("one:off:counter:colons").value == 1
|
|
|
|
test "exceptions":
|
|
proc f(switch: bool) =
|
|
if switch:
|
|
raise newException(ValueError, "exc1")
|
|
else:
|
|
raise newException(IndexError, "exc2")
|
|
|
|
expect IndexError:
|
|
myCounter.countExceptions(ValueError):
|
|
f(false)
|
|
check myCounter.value == 0
|
|
|
|
expect ValueError:
|
|
myCounter.countExceptions(ValueError):
|
|
f(true)
|
|
check myCounter.value == 1
|
|
|
|
expect IndexError:
|
|
myCounter.countExceptions:
|
|
f(false)
|
|
check myCounter.value == 2
|
|
|
|
myCounter.countExceptions:
|
|
discard
|
|
check myCounter.value == 2
|
|
|
|
test "labels":
|
|
declareCounter lCounter, "l help", @["foo", "bar"], registry
|
|
expect KeyError:
|
|
discard lCounter.value
|
|
|
|
# you can't access a labelled value before it was initialised
|
|
expect KeyError:
|
|
discard lCounter.value(@["a", "x"])
|
|
|
|
let labelValues = @["a", "x \"y\" \n\\z"]
|
|
lCounter.inc(labelValues = labelValues)
|
|
check lCounter.value(labelValues) == 1
|
|
# echo registry
|
|
|
|
# label validation
|
|
expect ValueError:
|
|
declareCounter invalid1, "invalid", @["123", "foo"]
|
|
expect ValueError:
|
|
declareCounter invalid2, "invalid", @["foo", "123"]
|
|
expect ValueError:
|
|
declareCounter invalid3, "invalid", @["foo", "__bar"]
|
|
|
|
# label names: array instead of sequence
|
|
declareCounter lCounter2, "l2 help", ["foo", "bar"], registry
|
|
let labelValues2 = ["a", "x \"y\" \n\\z"]
|
|
lCounter2.inc(labelValues = labelValues2)
|
|
check lCounter2.value(labelValues2) == 1
|
|
|
|
test "sample rate":
|
|
declareCounter sCounter, "counter with a sample rate set", registry = registry, sampleRate = 0.5
|
|
sCounter.inc()
|
|
# No sampling done on our side, just in sending the increments to a StatsD server
|
|
check sCounter.value == 1
|
|
|
|
test "names with colons":
|
|
declareCounter cCounter, "counter with colons in name", registry = registry, name = "foo:bar:baz"
|
|
cCounter.inc()
|
|
check cCounter.value == 1
|
|
check cCounter.valueByName("foo:bar:baz_total") == 1
|
|
# echo cCounter
|
|
|
|
var myName = "bla:bla"
|
|
declareCounter cCounter2, "another counter with colon in name", registry = registry, name = myName
|
|
cCounter2.inc()
|
|
check cCounter2.value == 1
|
|
check cCounter2.valueByName("bla:bla_total") == 1
|
|
# echo cCounter2
|
|
|
|
suite "gauge":
|
|
setup:
|
|
var registry = newRegistry()
|
|
declareGauge myGauge, "help", registry = registry
|
|
|
|
test "basic":
|
|
check myGauge.value == 0
|
|
myGauge.inc()
|
|
check myGauge.value == 1
|
|
myGauge.dec(3)
|
|
check myGauge.value == -2.0 # weird Nim bug if it's "-2"
|
|
myGauge.dec(0.1)
|
|
check myGauge.value == -2.1
|
|
myGauge.set(9.5)
|
|
check myGauge.value == 9.5
|
|
myGauge.set(1)
|
|
check myGauge.value == 1
|
|
|
|
test "alternative API":
|
|
gauge("one_off_gauge").set(1)
|
|
check gauge("one_off_gauge").value == 1
|
|
gauge("one_off_gauge").inc(0.5)
|
|
check gauge("one_off_gauge").value == 1.5
|
|
|
|
test "in progress":
|
|
myGauge.trackInProgress:
|
|
check myGauge.value == 1
|
|
check myGauge.value == 0
|
|
|
|
declareGauge lgauge, "help", @["foobar"], registry = registry
|
|
let labelValues = @["b"]
|
|
lgauge.trackInProgress(labelValues):
|
|
check lgauge.value(labelValues) == 1
|
|
check lgauge.value(labelValues) == 0
|
|
# echo registry
|
|
|
|
test "timing":
|
|
myGauge.time:
|
|
sleep(1000)
|
|
check myGauge.value == 0
|
|
check myGauge.value >= 1 # may be 2 inside a macOS Travis job
|
|
# echo registry
|
|
|
|
test "timing with labels":
|
|
declareGauge lgauge2, "help", @["foobar"], registry = registry
|
|
let labelValues = @["b"]
|
|
lgauge2.time(labelValues):
|
|
sleep(1000)
|
|
check lgauge2.value(labelValues) >= 1
|
|
|
|
test "names with colons":
|
|
declareGauge cGauge, "gauge with colons in name", registry = registry, name = "foo:bar:baz"
|
|
cGauge.inc()
|
|
check cGauge.value == 1
|
|
check cGauge.valueByName("foo:bar:baz") == 1
|
|
# echo cGauge
|
|
|
|
suite "summary":
|
|
setup:
|
|
var registry = newRegistry()
|
|
declareSummary mySummary, "help", registry = registry
|
|
|
|
test "basic":
|
|
check mySummary.valueByName("mySummary_count") == 0
|
|
check mySummary.valueByName("mySummary_sum") == 0
|
|
mySummary.observe(10)
|
|
check mySummary.valueByName("mySummary_count") == 1
|
|
check mySummary.valueByName("mySummary_sum") == 10
|
|
mySummary.observe(0.5)
|
|
check mySummary.valueByName("mySummary_count") == 2
|
|
check mySummary.valueByName("mySummary_sum") == 10.5
|
|
|
|
test "alternative API":
|
|
summary("one_off_summary").observe(10)
|
|
check summary("one_off_summary").valueByName("one_off_summary_count") == 1
|
|
check summary("one_off_summary").valueByName("one_off_summary_sum") == 10
|
|
|
|
test "timing":
|
|
mySummary.time:
|
|
sleep(1000)
|
|
check mySummary.valueByName("mySummary_sum") == 0
|
|
check mySummary.valueByName("mySummary_sum") >= 1
|
|
|
|
test "timing with labels":
|
|
declareSummary lsummary, "help", ["foobar"], registry = registry
|
|
let labelValues = ["b"]
|
|
lsummary.time(labelValues):
|
|
sleep(1000)
|
|
check lsummary.valueByName("lsummary_sum", labelValues) >= 1
|
|
|
|
test "names with colons":
|
|
declareSummary cSummary, "summary with colons in name", registry = registry, name = "foo:bar:baz"
|
|
cSummary.observe(10)
|
|
check cSummary.valueByName("foo:bar:baz_count") == 1
|
|
check cSummary.valueByName("foo:bar:baz_sum") == 10
|
|
# echo cSummary
|
|
|
|
suite "histogram":
|
|
setup:
|
|
var registry = newRegistry()
|
|
declareHistogram myHistogram, "help", registry = registry
|
|
|
|
test "basic":
|
|
check myHistogram.valueByName("myHistogram_bucket", [], ["1.0"]) == 0
|
|
check myHistogram.valueByName("myHistogram_bucket", [], ["2.5"]) == 0
|
|
check myHistogram.valueByName("myHistogram_bucket", [], ["5.0"]) == 0
|
|
check myHistogram.valueByName("myHistogram_bucket", [], ["+Inf"]) == 0
|
|
check myHistogram.valueByName("myHistogram_count") == 0
|
|
check myHistogram.valueByName("myHistogram_sum") == 0
|
|
|
|
myHistogram.observe(2)
|
|
check myHistogram.valueByName("myHistogram_bucket", [], ["1.0"]) == 0
|
|
check myHistogram.valueByName("myHistogram_bucket", [], ["2.5"]) == 1
|
|
check myHistogram.valueByName("myHistogram_bucket", [], ["5.0"]) == 1
|
|
check myHistogram.valueByName("myHistogram_bucket", [], ["+Inf"]) == 1
|
|
check myHistogram.valueByName("myHistogram_count") == 1
|
|
check myHistogram.valueByName("myHistogram_sum") == 2
|
|
|
|
myHistogram.observe(2.5)
|
|
check myHistogram.valueByName("myHistogram_bucket", [], ["1.0"]) == 0
|
|
check myHistogram.valueByName("myHistogram_bucket", [], ["2.5"]) == 2
|
|
check myHistogram.valueByName("myHistogram_bucket", [], ["5.0"]) == 2
|
|
check myHistogram.valueByName("myHistogram_bucket", [], ["+Inf"]) == 2
|
|
check myHistogram.valueByName("myHistogram_count") == 2
|
|
check myHistogram.valueByName("myHistogram_sum") == 4.5
|
|
|
|
myHistogram.observe(Inf)
|
|
check myHistogram.valueByName("myHistogram_bucket", [], ["1.0"]) == 0
|
|
check myHistogram.valueByName("myHistogram_bucket", [], ["2.5"]) == 2
|
|
check myHistogram.valueByName("myHistogram_bucket", [], ["5.0"]) == 2
|
|
check myHistogram.valueByName("myHistogram_bucket", [], ["+Inf"]) == 3
|
|
check myHistogram.valueByName("myHistogram_count") == 3
|
|
check myHistogram.valueByName("myHistogram_sum") == Inf
|
|
|
|
declareHistogram h1, "help", registry = registry, buckets = [0.0, 1.0, 2.0]
|
|
check h1.valueByName("h1_bucket", [], ["0.0"]) == 0
|
|
check h1.valueByName("h1_bucket", [], ["1.0"]) == 0
|
|
check h1.valueByName("h1_bucket", [], ["2.0"]) == 0
|
|
check h1.valueByName("h1_bucket", [], ["+Inf"]) == 0
|
|
|
|
declareHistogram h2, "help", registry = registry, buckets = [0.0, 1.0, 2.0, Inf]
|
|
check h2.valueByName("h2_bucket", [], ["0.0"]) == 0
|
|
check h2.valueByName("h2_bucket", [], ["1.0"]) == 0
|
|
check h2.valueByName("h2_bucket", [], ["2.0"]) == 0
|
|
check h2.valueByName("h2_bucket", [], ["+Inf"]) == 0
|
|
|
|
expect ValueError:
|
|
declareHistogram h3, "help", registry = registry, buckets = []
|
|
expect ValueError:
|
|
declareHistogram h3, "help", registry = registry, buckets = [Inf]
|
|
expect ValueError:
|
|
declareHistogram h3, "help", registry = registry, buckets = [3.0, 1.0]
|
|
|
|
test "alternative API":
|
|
histogram("one_off_histogram").observe(2)
|
|
check histogram("one_off_histogram").valueByName("one_off_histogram_bucket", [], ["1.0"]) == 0
|
|
check histogram("one_off_histogram").valueByName("one_off_histogram_bucket", [], ["2.5"]) == 1
|
|
check histogram("one_off_histogram").valueByName("one_off_histogram_bucket", [], ["5.0"]) == 1
|
|
check histogram("one_off_histogram").valueByName("one_off_histogram_bucket", [], ["+Inf"]) == 1
|
|
check histogram("one_off_histogram").valueByName("one_off_histogram_count") == 1
|
|
check histogram("one_off_histogram").valueByName("one_off_histogram_sum") == 2
|
|
|
|
test "timing":
|
|
myHistogram.time:
|
|
sleep(1000)
|
|
check myHistogram.valueByName("myHistogram_sum") == 0
|
|
check myHistogram.valueByName("myHistogram_sum") >= 1
|
|
check myHistogram.valueByName("myHistogram_count") == 1
|
|
check myHistogram.valueByName("myHistogram_bucket", [], ["+Inf"]) == 1
|
|
|
|
test "timing with labels":
|
|
declareHistogram lhistogram, "help", ["foobar"], registry = registry
|
|
let labelValues = ["b"]
|
|
lhistogram.time(labelValues):
|
|
sleep(1000)
|
|
check lhistogram.valueByName("lhistogram_sum", labelValues) >= 1
|
|
check lhistogram.valueByName("lhistogram_count", labelValues) == 1
|
|
check lhistogram.valueByName("lhistogram_bucket", labelValues, ["+Inf"]) == 1
|
|
|
|
test "names with colons":
|
|
declareHistogram cHistogram, "histogram with colons in name", registry = registry, name = "foo:bar:baz"
|
|
cHistogram.observe(10)
|
|
check cHistogram.valueByName("foo:bar:baz_count") == 1
|
|
check cHistogram.valueByName("foo:bar:baz_sum") == 10
|
|
# echo cHistogram
|
|
|
|
import ./duplicate_coll_mod
|
|
suite "registry":
|
|
test "duplicate collectors":
|
|
expect RegistrationError:
|
|
declareCounter duplicate_counter, "duplicate counter"
|
|
duplicate_counter.inc()
|
|
|
|
when defined(metrics):
|
|
type MyCustomCollector = ref object of Gauge
|
|
var
|
|
myCustomCollector = MyCustomCollector.newCollector("my_custom_collector", "help")
|
|
registry2 = newRegistry()
|
|
myCustomCollector2 = MyCustomCollector.newCollector("my_custom_collector2", "help2", registry = registry2)
|
|
|
|
method collect(collector: MyCustomCollector): Metrics =
|
|
let timestamp = getTime().toMilliseconds()
|
|
result[@[]] = @[
|
|
Metric(
|
|
name: "custom_metric",
|
|
value: 42,
|
|
timestamp: timestamp,
|
|
)
|
|
]
|
|
|
|
suite "custom collectors":
|
|
test "42":
|
|
check myCustomCollector.value == 42
|
|
|
|
test "custom registry":
|
|
let collectors = registry2.collect()
|
|
check collectors.len == 1
|
|
for collector, metrics in collectors:
|
|
check collector.value == 42
|
|
|
|
suite "system metrics":
|
|
test "change update interval":
|
|
when defined(metrics):
|
|
declareGauge myGauge, "my gauge"
|
|
myGauge.set(1)
|
|
# echo defaultRegistry
|
|
echo getSystemMetricsUpdateInterval()
|
|
setSystemMetricsUpdateInterval(initDuration(seconds = 1))
|
|
echo getSystemMetricsUpdateInterval()
|
|
sleep(2)
|
|
myGauge.set(2)
|
|
# echo defaultRegistry
|
|
echo getSystemMetricsAutomaticUpdate()
|
|
setSystemMetricsAutomaticUpdate(false)
|
|
updateSystemMetrics()
|
|
updateThreadMetrics()
|
|
|