fix: safely parse metric labels (#948)

This commit is contained in:
Jacob Molz 2026-05-26 07:43:58 -04:00 committed by GitHub
parent 6af12f416f
commit c10f2694a0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 96 additions and 2 deletions

View file

@ -0,0 +1,73 @@
"""
Tests for ontology monitoring metrics.
"""
import importlib.util
import sys
from pathlib import Path
MODULE_PATH = (
Path(__file__).resolve().parents[3]
/ "trustgraph-flow"
/ "trustgraph"
/ "query"
/ "ontology"
/ "monitoring.py"
)
spec = importlib.util.spec_from_file_location("ontology_monitoring", MODULE_PATH)
assert spec is not None and spec.loader is not None
monitoring = importlib.util.module_from_spec(spec)
sys.modules[spec.name] = monitoring
spec.loader.exec_module(monitoring)
PerformanceMonitor = monitoring.PerformanceMonitor
_extract_metric_label = monitoring._extract_metric_label
def test_extract_metric_label_reads_unquoted_label_value():
metric_name = "cache_requests_total{cache_type=entity,component=ontology}"
assert _extract_metric_label(metric_name, "cache_type") == "entity"
def test_extract_metric_label_reads_quoted_label_value():
metric_name = 'cache_requests_total{cache_type="entity",component="ontology"}'
assert _extract_metric_label(metric_name, "cache_type") == "entity"
def test_extract_metric_label_returns_none_when_label_missing():
metric_name = "cache_requests_total{component=ontology}"
assert _extract_metric_label(metric_name, "cache_type") is None
def test_performance_report_ignores_counters_without_cache_type_label():
monitor = PerformanceMonitor({"enabled": False})
monitor.metrics_collector.increment(
"cache_requests_total",
labels={"component": "ontology"},
)
monitor.metrics_collector.increment(
"cache_type=not_a_label",
labels={"component": "ontology"},
)
monitor.metrics_collector.increment(
"cache_requests_total",
labels={"cache_type": "entity"},
)
monitor.metrics_collector.increment(
"cache_hits_total",
labels={"cache_type": "entity"},
)
report = monitor.get_performance_report()
assert report["cache_performance"] == {
"entity": {
"hit_rate": 1.0,
"total_requests": 1.0,
"total_hits": 1.0,
}
}

View file

@ -4,6 +4,7 @@ Provides comprehensive monitoring of system performance, query patterns, and res
"""
import logging
import re
import time
import asyncio
import inspect
@ -276,6 +277,26 @@ class MetricsCollector:
return f"{name}{{{label_str}}}"
def _extract_metric_label(metric_name: str, label: str) -> Optional[str]:
"""Extract a label value from an internal metric key."""
labels_start = metric_name.find('{')
labels_end = metric_name.find('}', labels_start + 1)
if labels_start == -1 or labels_end == -1:
return None
labels = metric_name[labels_start + 1:labels_end]
label_match = re.search(
rf'(?:^|,){re.escape(label)}=(?:"([^"]*)"|([^,]*))',
labels,
)
if not label_match:
return None
quoted_value, unquoted_value = label_match.groups()
return quoted_value if quoted_value is not None else unquoted_value
class PerformanceMonitor:
"""Monitors system performance and component health."""
@ -474,8 +495,8 @@ class PerformanceMonitor:
# Cache performance
cache_types = set()
for metric_name in self.metrics_collector.counters.keys():
if 'cache_type=' in metric_name:
cache_type = metric_name.split('cache_type=')[1].split(',')[0].split('}')[0]
cache_type = _extract_metric_label(metric_name, 'cache_type')
if cache_type is not None:
cache_types.add(cache_type)
for cache_type in cache_types: