fix(telemetry): park the span panels in their own row, tighten the site label

Four findings from a review pass over the PR.

The "Spans & traces" row was empty. Moving the row header down to clear
the back-fill panels was only half the change -- the seven span-derived
panels stayed at their old y, one unit below the native panels, so every
pair overlapped and Grafana parented all fifteen to "Back-fill &
persistence". The panels now sit below the row header, which restores
the split the runbook already describes: eight native panels answer "how
much", seven span-derived ones answer "which". Both rows stay expanded,
so the docs no longer call them collapsed.

metric_constants() excises each namespaced block before the flat
prefix pass. The flat pass classifies by identifier prefix and is meant
for headers that name the role in the identifier because they have no
`namespace metric`/`label`/`lval`; it was running over the whole header,
so a `kLabel`-prefixed constant written inside `namespace metric` landed
in both buckets and an instrument name became a valid label key for Rule
D. Nothing in the tree does that today, which is why it went unnoticed,
and why the guard is a test rather than a fix for an observed failure.

The `site` label now keeps a non-default port and drops userinfo residue
from the host. Omitting the port unconditionally merged two local sites
that differ only by port; printing it unconditionally would have renamed
the existing `https://vl.ripple.com` series. Comparing against the
scheme default distinguishes a configured port from the one the Resource
constructor fills in. parseUrl's host group also permits '@', so a
malformed URI with two of them leaves part of the userinfo in `domain`.
This commit is contained in:
Pratik Mankawde
2026-07-28 18:36:22 +01:00
parent 85f45922c4
commit 35e0c0795d
6 changed files with 733 additions and 677 deletions

View File

@@ -966,6 +966,7 @@ def metric_constants(root: Path) -> Tuple[Set[str], Set[str], Set[str]]:
values: Set[str] = set()
for h in find_metricname_headers(root):
text = strip_comments(read_source(h))
flat = text
for ns, bucket in (
("metric", names),
("label", keys),
@@ -974,9 +975,16 @@ def metric_constants(root: Path) -> Tuple[Set[str], Set[str], Set[str]]:
for block in namespace_spans(text, ns):
for m in METRIC_CONST_DEF.finditer(block):
bucket.add(m.group(2))
# Remove the block before the flat pass below, so the
# enclosing namespace stays the only thing that decides a
# namespaced constant's bucket. Without this, a `kLabel`-style
# identifier written inside `namespace metric` lands in both
# `names` and `keys`, and an instrument name silently becomes
# an allowed label key for Rule D.
flat = flat.replace(block, "", 1)
# Flat style: classify by identifier prefix. Only constants outside the
# namespaced blocks reach here, so a namespaced header is unaffected.
for m in METRIC_CONST_DEF.finditer(text):
for m in METRIC_CONST_DEF.finditer(flat):
ident, value = m.group(1), m.group(2)
if ident.startswith("kLabel"):
keys.add(value)

View File

@@ -1041,6 +1041,37 @@ class MetricConstantExtraction(unittest.TestCase):
finally:
shutil.rmtree(d)
def test_namespaced_constant_ignores_its_flat_prefix(self):
# A `kLabel`-prefixed identifier written inside `namespace metric` must
# be an instrument name only. The flat prefix pass exists for headers
# that have no such namespace, so it must not also claim this one:
# letting it through would make an instrument name a valid label key,
# and Rule D would then accept `label_peer_total` as a label.
names, keys, vals = self._run(
_metric_header(
metric_body=_mc("kLabelPeerTotal", "label_peer_total"),
label_body=_mc("outcome", "outcome"),
)
)
self.assertEqual(names, {"label_peer_total"})
self.assertEqual(keys, {"outcome"})
self.assertEqual(vals, set())
def test_flat_prefix_still_read_when_namespaces_absent(self):
# The counterpart to the test above: with no `namespace metric`/`label`
# block to excise, the flat pass must still classify by prefix.
names, keys, vals = self._run(
"#pragma once\n"
"namespace xrpl::telemetry {\n"
+ _mc("kLabelOutcome", "outcome")
+ "\n"
+ _mc("kResultResolved", "resolved")
+ "\n}\n"
)
self.assertEqual(names, set())
self.assertEqual(keys, {"outcome"})
self.assertEqual(vals, {"resolved"})
class RuleIMetricLiterals(unittest.TestCase):
"""Rule I: literal instrument names / label keys at a metric emit site are