add nim-metrics -> logos openmetrics serializer

This commit is contained in:
gmega 2026-06-17 19:18:20 -03:00
parent 6a6482c217
commit 60ddfc241e
No known key found for this signature in database
GPG Key ID: 6290D34EAD824B18
5 changed files with 103 additions and 10 deletions

View File

@ -152,7 +152,7 @@ testIntegration: | build deps
$(ENV_SCRIPT) nim testIntegration $(TEST_PARAMS) $(NIM_PARAMS) build.nims
# Builds a C example that uses the libstorage C library and runs it
testLibstorage: | build deps
testLibstorageC: | build deps
$(MAKE) $(if $(ncpu),-j$(ncpu),) libstorage
cd tests/cbindings && \
if [ "$(detected_OS)" = "Windows" ]; then \
@ -163,6 +163,10 @@ testLibstorage: | build deps
LD_LIBRARY_PATH=../../build ./storage; \
fi
testLibstorage: | testLibstorageC
echo -e $(BUILD_MSG) "build/$@" && \
$(ENV_SCRIPT) nim testLibstorage $(TEST_PARAMS) $(NIM_PARAMS) build.nims
# Builds and runs all tests
testAll: | build deps
echo -e $(BUILD_MSG) "build/$@" && \

View File

@ -69,18 +69,17 @@ task storage, "build logos storage binary":
task mixTools, "build mix tools (mix_pool, mix_relay_dht)":
let (desc, ec) = gorgeEx("git describe --always --dirty")
let mixVersion =
if ec == 0 and desc.strip().len > 0: desc.strip() else: "unknown"
if ec == 0 and desc.strip().len > 0:
desc.strip()
else:
"unknown"
let mixParams =
"-d:chronicles_runtime_filtering -d:chronicles_log_level=TRACE " &
"-d:mixVersion:" & mixVersion
"-d:chronicles_runtime_filtering -d:chronicles_log_level=TRACE " & "-d:mixVersion:" &
mixVersion
buildBinary "mix_pool",
outName = "mix_pool",
srcDir = "tools/mix/",
params = mixParams
outName = "mix_pool", srcDir = "tools/mix/", params = mixParams
buildBinary "mix_relay_dht",
outName = "mix_relay_dht",
srcDir = "tools/mix/",
params = mixParams
outName = "mix_relay_dht", srcDir = "tools/mix/", params = mixParams
task testStorage, "Build & run Logos Storage tests":
test "testStorage", outName = "testStorage"
@ -94,6 +93,9 @@ task testIntegration, "Run integration tests":
# test "testIntegration", params = "-d:chronicles_sinks=textlines[notimestamps,stdout],textlines[dynamic] " &
# "-d:chronicles_enabled_topics:integration:TRACE"
task testLibstorage, "Run libstorage Nim tests":
test "testLibstorage", outName = "testLibstorage"
task build, "build Logos Storage binary":
storageTask()

38
library/logosmetrics.nim Normal file
View File

@ -0,0 +1,38 @@
import std/[json, locks, times, sets]
import pkg/metrics
proc toJson(collector: Collector, metrics: var seq[JsonNode] = @[]) =
# We know the closure won't outlive `metrics` so this is
# an acceptable hack.
let metricsPtr = addr metrics
proc serializeMetric(
name: string,
value: float64,
labels: openArray[string] = [],
labelValues: openArray[string] = [],
timestamp: Time,
) {.raises: [].} =
# The logos openmetrics format (https://github.com/logos-co/openmetrics-module)
# does not include the timestamp, so we don't include it either.
var labelMap = newJObject()
for i in 0 ..< labels.len:
labelMap[labels[i]] = %labelValues[i]
metricsPtr[].add(%*{"name": name, "value": value, "labels": labelMap})
collector.collect(serializeMetric)
# Serializes all collectors in a given registry to a Logos openmetrics-compatible
# format. Allows including only specific collectors by name.
proc toJson*(registry: Registry, includeOnly: openArray[string] = []): JsonNode =
var metrics = newSeq[JsonNode]()
withLock registry.lock:
for collector in registry.collectors:
if includeOnly.len > 0:
if collector.name notin includeOnly:
continue
collector.toJson(metrics)
result = %*{"metrics": metrics}

View File

@ -0,0 +1,47 @@
import std/json
import pkg/unittest2
import pkg/metrics
import ../../library/logosmetrics
declareCounter myCounter, "Parts Counter", ["part_type"]
declareGauge myGauge, "My gauge"
declareHistogram myHistogram, "My histogram", buckets = [0.0, 1.0, 2.0]
suite "Metrics":
test "should serialize Nim metrics to Logos Metrics format":
myCounter.inc(labelValues = ["screws"])
myCounter.inc(labelValues = ["washers"])
myGauge.set(42.0)
myHistogram.observe(1)
myHistogram.observe(2)
myHistogram.observe(3)
myHistogram.observe(4)
myHistogram.observe(5)
let metrics = defaultRegistry.toJson(@["myCounter", "myGauge", "myHistogram"])
# Remove "created" metrics as we can't pin those down.
var filteredMetrics = %*{"metrics": @[]}
for metric in metrics["metrics"]:
if metric["name"].getStr() != "myCounter_created" and
metric["name"].getStr() != "myHistogram_created":
filteredMetrics["metrics"].add(metric)
check filteredMetrics ==
%*{
"metrics": [
{"name": "myCounter_total", "value": 1.0, "labels": {"part_type": "screws"}},
{"name": "myCounter_total", "value": 1.0, "labels": {"part_type": "washers"}},
{"name": "myGauge", "value": 42.0, "labels": {}},
{"name": "myHistogram_sum", "value": 15.0, "labels": {}},
{"name": "myHistogram_count", "value": 5.0, "labels": {}},
{"name": "myHistogram_bucket", "value": 0.0, "labels": {"le": "0.0"}},
{"name": "myHistogram_bucket", "value": 1.0, "labels": {"le": "1.0"}},
{"name": "myHistogram_bucket", "value": 2.0, "labels": {"le": "2.0"}},
{"name": "myHistogram_bucket", "value": 5.0, "labels": {"le": "+Inf"}},
]
}

2
tests/testLibstorage.nim Normal file
View File

@ -0,0 +1,2 @@
# Tests the Nim side of libstorage.
import ./libstorage/logosmetrics