Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions python/kthena/runtime/standard.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class EngineType(Enum):


class StandardMetricNames:
GENERATION_TOKENS_TOTAL = "kthena:generation_tokens_total"
GENERATION_TOKENS = "kthena:generation_tokens"
NUM_REQUESTS_WAITING = "kthena:num_requests_waiting"
TIME_TO_FIRST_TOKEN_SECONDS = "kthena:time_to_first_token_seconds"
TIME_PER_OUTPUT_TOKEN_SECONDS = "kthena:time_per_output_token_seconds"
Expand All @@ -36,8 +36,8 @@ class StandardMetricNames:
STANDARD_RULES: Dict[str, List[MetricOperator]] = {
EngineType.VLLM.value: [
RenameMetric(
"vllm:generation_tokens_total",
StandardMetricNames.GENERATION_TOKENS_TOTAL,
"vllm:generation_tokens",
StandardMetricNames.GENERATION_TOKENS,
),
RenameMetric(
"vllm:num_requests_waiting", StandardMetricNames.NUM_REQUESTS_WAITING
Expand All @@ -57,8 +57,8 @@ class StandardMetricNames:
],
EngineType.SGLANG.value: [
RenameMetric(
"sglang:generation_tokens_total",
StandardMetricNames.GENERATION_TOKENS_TOTAL,
"sglang:generation_tokens",
StandardMetricNames.GENERATION_TOKENS,
),
RenameMetric("sglang:num_queue_reqs", StandardMetricNames.NUM_REQUESTS_WAITING),
RenameMetric(
Expand Down
52 changes: 52 additions & 0 deletions python/kthena/tests/test_metrics.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,3 +95,55 @@ def test_metric_adapter_handles_empty_metrics():

adapter = MetricAdapter(empty_metric_text, standard)
assert len(adapter.metrics) == 0
VLLM_COUNTER_METRICS = """
# HELP vllm:generation_tokens_total Number of generation tokens processed.
# TYPE vllm:generation_tokens_total counter
vllm:generation_tokens_total{model_name="m"} 42.0
""".strip()

SGLANG_COUNTER_METRICS = """
# HELP sglang:generation_tokens_total Number of generation tokens processed.
# TYPE sglang:generation_tokens_total counter
sglang:generation_tokens_total{model_name="m"} 7.0
""".strip()


def _standardized(adapter, name):
return [m for m in adapter.metrics if m.name == name]


def test_vllm_counter_rename_survives_parser_family_munging():
# The parser strips _total from a counter FAMILY name, so the rule must
# match the munged family and the samples must come back out with _total.
standard = MetricStandard("vllm")
adapter = MetricAdapter(VLLM_COUNTER_METRICS, standard)

twins = _standardized(adapter, "kthena:generation_tokens")
assert len(twins) == 1, [m.name for m in adapter.metrics]
twin = twins[0]
assert twin.type == "counter"
sample_names = [s.name for s in twin.samples]
assert "kthena:generation_tokens_total" in sample_names
total = next(s for s in twin.samples if s.name == "kthena:generation_tokens_total")
assert total.value == 42.0
assert total.labels == {"model_name": "m"}


def test_sglang_counter_rename_survives_parser_family_munging():
standard = MetricStandard("sglang")
adapter = MetricAdapter(SGLANG_COUNTER_METRICS, standard)

twins = _standardized(adapter, "kthena:generation_tokens")
assert len(twins) == 1, [m.name for m in adapter.metrics]
sample_names = [s.name for s in twins[0].samples]
assert "kthena:generation_tokens_total" in sample_names


def test_process_metrics_exposes_documented_counter_series():
import asyncio

from kthena.runtime.collect import process_metrics

standard = MetricStandard("vllm")
output = asyncio.run(process_metrics(VLLM_COUNTER_METRICS, standard))
assert b'kthena:generation_tokens_total{model_name="m"} 42.0' in output
Loading