mirror of
https://github.com/XRPLF/rippled.git
synced 2026-07-31 02:50:24 +00:00
ci: Enforce lower_snake_case attribute keys in OTel naming check
Add Rule G to check_otel_naming.py: every span-attribute key must be lower_snake_case (^[a-z][a-z0-9_]*$ per dot-separated segment). This catches camelCase, UPPERCASE, and spaces in keys, which the structural (dotted) and source (literal) rules did not. Document it in the script README and CONTRIBUTING.md. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
1
.github/scripts/otel-naming/README.md
vendored
1
.github/scripts/otel-naming/README.md
vendored
@@ -36,6 +36,7 @@ hardcoded allowlist:
|
||||
| Rule | Check |
|
||||
| ---- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| A | No stray dotted span-attribute key (only the derived resource keys may be dotted). |
|
||||
| G | Attribute keys are `lower_snake_case` (`^[a-z][a-z0-9_]*$` per dot-segment) — no camelCase, UPPERCASE, or spaces. |
|
||||
| F | No string literals as attribute keys or span-name arguments in `setAttribute`/`addEvent`/`span`/`childSpan`. Attribute _values_ are exempt (runtime data). `*SpanNames.h` definitions are exempt. |
|
||||
| B | Every collector `spanmetrics.dimensions` name exists in the L1 key set. |
|
||||
| C | Every Tempo span-filter tag exists in the L1 key set. |
|
||||
|
||||
27
.github/scripts/otel-naming/check_otel_naming.py
vendored
27
.github/scripts/otel-naming/check_otel_naming.py
vendored
@@ -41,6 +41,8 @@ Rules (each FAILS the build, when its inputs are present)
|
||||
---------------------------------------------------------
|
||||
A No stray dotted span-attribute key. A dotted `<a>.<b>` used as a span
|
||||
attribute that is not in the derived resource-key set is a violation.
|
||||
G Attribute keys must be lower_snake_case (^[a-z][a-z0-9_]*$ per segment).
|
||||
Flags camelCase, UPPERCASE, spaces, and other stray characters.
|
||||
F No string literals as attribute keys/values or span-name arguments. Every
|
||||
setAttribute/addEvent/span/childSpan argument must reference a *SpanNames.h
|
||||
constant, never a "literal". Definitions inside *SpanNames.h are exempt.
|
||||
@@ -303,6 +305,9 @@ def main() -> None:
|
||||
# --- Rule A: no stray dotted span-attribute keys -----------------------
|
||||
if l1_keys:
|
||||
run_rule_a(keys_by_header, dotted_allow, report)
|
||||
# --- Rule G: keys must be lower_snake_case -----------------------------
|
||||
if l1_keys:
|
||||
run_rule_g(keys_by_header, report)
|
||||
# --- Rule F: no string literals at telemetry call-sites ----------------
|
||||
if headers:
|
||||
run_rule_f(root, report)
|
||||
@@ -363,6 +368,28 @@ def run_rule_a(
|
||||
report.ok("A: no stray dotted span-attribute keys")
|
||||
|
||||
|
||||
# A lower_snake_case identifier segment: starts lowercase, then lowercase /
|
||||
# digits / underscores. No uppercase, no spaces, no camelCase.
|
||||
SNAKE_SEGMENT = re.compile(r"^[a-z][a-z0-9_]*$")
|
||||
|
||||
|
||||
def run_rule_g(keys_by_header: Dict[Path, Set[str]], report: Report) -> None:
|
||||
"""Every attribute key must be lower_snake_case. Bare/underscore keys must
|
||||
match ^[a-z][a-z0-9_]*$; dotted resource keys must be lowercase
|
||||
dot-separated segments (each segment lower_snake_case). Flags camelCase,
|
||||
UPPERCASE, spaces, and other stray characters."""
|
||||
found = False
|
||||
for h in sorted(keys_by_header):
|
||||
for key in sorted(keys_by_header[h]):
|
||||
segments = key.split(".")
|
||||
if all(SNAKE_SEGMENT.match(seg) for seg in segments):
|
||||
continue
|
||||
found = True
|
||||
report.violation("G", h.name, key, "must be lower_snake_case")
|
||||
if not found:
|
||||
report.ok("G: all attribute keys are lower_snake_case")
|
||||
|
||||
|
||||
# Which argument positions of each call must be a constant (0-based). The
|
||||
# attribute VALUE position is intentionally absent: values are runtime data
|
||||
# (command names, hashes, counts), not naming-convention surface.
|
||||
|
||||
Reference in New Issue
Block a user