From e04379622e62016d4aaf368cd1e699ca2749bfc2 Mon Sep 17 00:00:00 2001 From: Amaan Sayed <91617804+Amaan729@users.noreply.github.com> Date: Tue, 14 Apr 2026 17:18:26 -0700 Subject: [PATCH] feat: add metrics reference page infrastructure Adds the data/metrics/{version}/ structure and Hugo shortcode template for rendering Jaeger's metrics reference page in the documentation site. Follows the same pattern used for CLI flags documentation. The metrics YAML data file is populated by the jaeger main repo release workflow (see companion PR). The shortcode reads from site.Data.metrics and renders a table of metric names with their labels, mirroring the approach used in layouts/_shortcodes/ for CLI flags. Signed-off-by: Amaan Sayed --- data/metrics/README.md | 38 ++++++++++ data/metrics/next-release/metrics.yaml | 5 ++ layouts/_shortcodes/metrics.html | 59 ++++++++++++++++ scripts/convert-metrics-to-yaml.py | 98 ++++++++++++++++++++++++++ 4 files changed, 200 insertions(+) create mode 100644 data/metrics/README.md create mode 100644 data/metrics/next-release/metrics.yaml create mode 100644 layouts/_shortcodes/metrics.html create mode 100644 scripts/convert-metrics-to-yaml.py diff --git a/data/metrics/README.md b/data/metrics/README.md new file mode 100644 index 00000000..72c33255 --- /dev/null +++ b/data/metrics/README.md @@ -0,0 +1,38 @@ +# Metrics Data + +This directory contains per-version snapshots of Jaeger's metrics in YAML format. +The files are generated automatically by the jaeger main repo release workflow +and follow the same versioned directory convention as `data/cli/`. + +## Structure + +``` +data/metrics/ + {version}/ # e.g. 2.17 + metrics.yaml # combined metrics snapshot for this release +``` + +## Format + +Each `metrics.yaml` contains a list of metric entries scraped from the +Prometheus `/metrics` endpoint of the `jaeger` binary during integration tests: + +```yaml +version: "2.17.0" +metrics: + - name: otelcol_exporter_sent_spans + labels: + - exporter + - service_name + - service_version + - name: otelcol_receiver_accepted_spans + labels: + - receiver + - service_name + - service_version + - transport +``` + +The file is generated by the `scripts/release/publish-metrics-to-docs.sh` +script in the jaeger main repository, which downloads the combined metrics +artifact from the release workflow and converts it to this YAML format. diff --git a/data/metrics/next-release/metrics.yaml b/data/metrics/next-release/metrics.yaml new file mode 100644 index 00000000..ba192f4e --- /dev/null +++ b/data/metrics/next-release/metrics.yaml @@ -0,0 +1,5 @@ +# This file is a placeholder for the next release metrics. +# It will be replaced by the jaeger release workflow when a new version is published. +# See data/metrics/README.md for the format. +version: "next-release" +metrics: [] diff --git a/layouts/_shortcodes/metrics.html b/layouts/_shortcodes/metrics.html new file mode 100644 index 00000000..263693dd --- /dev/null +++ b/layouts/_shortcodes/metrics.html @@ -0,0 +1,59 @@ +{{/* + Shortcode: metrics + + Renders a reference table of all Jaeger metrics for a given documentation + version, sourced from data/metrics/{version}/metrics.yaml. + + Mirrors the pattern used by the CLI flags shortcode. + + Usage in a content .md file: + {{< metrics >}} + + The version is inferred from the page's path (e.g. /docs/v2/2.17/... → "2.17"). + Falls back to "next-release" when no version can be determined. +*/}} + +{{- $version := "next-release" -}} +{{- $pathParts := split .Page.RelPermalink "/" -}} +{{- range $i, $p := $pathParts -}} + {{- if and (eq $p "v2") (gt (len $pathParts) (add $i 1)) -}} + {{- $version = index $pathParts (add $i 1) -}} + {{- end -}} +{{- end -}} + +{{- $data := index site.Data.metrics $version -}} +{{- if not $data -}} + {{- $data = index site.Data.metrics "next-release" -}} +{{- end -}} + +{{- if and $data $data.metrics (gt (len $data.metrics) 0) -}} +

The following metrics are produced by Jaeger {{ if ne $version "next-release" }}v{{ $version }}{{ else }}(next release){{ end }}. +They can be scraped from the /metrics endpoint (default port 8888). +See OpenTelemetry Collector internal telemetry for configuration details.

+ + + + + + + + + + {{- range $data.metrics }} + + + + + {{- end }} + +
Metric nameLabels
{{ .name }} + {{- if .labels -}} + {{- range $i, $l := .labels -}} + {{- if gt $i 0 }}, {{ end -}} + {{ $l }} + {{- end -}} + {{- end -}} +
+{{- else -}} +

Metrics reference not yet available for this version.

+{{- end -}} diff --git a/scripts/convert-metrics-to-yaml.py b/scripts/convert-metrics-to-yaml.py new file mode 100644 index 00000000..9cc94a8e --- /dev/null +++ b/scripts/convert-metrics-to-yaml.py @@ -0,0 +1,98 @@ +#!/usr/bin/env python3 +# Copyright (c) 2026 The Jaeger Authors. +# SPDX-License-Identifier: Apache-2.0 +""" +convert-metrics-to-yaml.py + +Converts a combined Prometheus text-format metrics snapshot (produced by the +jaeger integration tests) into the YAML data file consumed by the Hugo +documentation site. + +Usage: + python3 scripts/convert-metrics-to-yaml.py \\ + --input combined-metrics.txt \\ + --output data/metrics/2.17/metrics.yaml \\ + --version 2.17.0 + +Input format (Prometheus text exposition format): + # HELP otelcol_exporter_sent_spans ... + # TYPE otelcol_exporter_sent_spans counter + otelcol_exporter_sent_spans{exporter="otlp", ...} 42 + +Output format: + version: "2.17.0" + metrics: + - name: otelcol_exporter_sent_spans + labels: + - exporter + - service_name +""" + +import argparse +import re +import sys +from collections import defaultdict + +LABEL_PATTERN = re.compile(r'(\w+)=') +METRIC_LINE = re.compile(r'^([a-zA-Z_:][a-zA-Z0-9_:]*)(?:\{([^}]*)\})?\s') +EXCLUDED_LABELS = {'service_instance_id', 'otel_scope_version', 'otel_scope_schema_url'} + + +def parse_metrics(text: str) -> dict: + """Parse Prometheus text format and return {metric_name: set_of_label_names}.""" + metrics = defaultdict(set) + for line in text.splitlines(): + line = line.strip() + if not line or line.startswith('#'): + continue + m = METRIC_LINE.match(line) + if not m: + continue + name = m.group(1) + labels_str = m.group(2) or '' + labels = set(LABEL_PATTERN.findall(labels_str)) - EXCLUDED_LABELS + metrics[name].update(labels) + return metrics + + +def metrics_to_yaml(metrics: dict, version: str) -> str: + """Render metrics dict as YAML string.""" + lines = [f'version: "{version}"', 'metrics:'] + for name in sorted(metrics): + labels = sorted(metrics[name]) + lines.append(f' - name: {name}') + if labels: + lines.append(' labels:') + for label in labels: + lines.append(f' - {label}') + lines.append('') # trailing newline + return '\n'.join(lines) + + +def main(): + parser = argparse.ArgumentParser(description='Convert Prometheus metrics snapshot to Hugo data YAML') + parser.add_argument('--input', required=True, help='Path to combined Prometheus text-format metrics file') + parser.add_argument('--output', required=True, help='Path to write the output YAML file') + parser.add_argument('--version', required=True, help='Jaeger version string, e.g. 2.17.0') + args = parser.parse_args() + + with open(args.input) as f: + text = f.read() + + metrics = parse_metrics(text) + if not metrics: + print(f'ERROR: no metrics found in {args.input}', file=sys.stderr) + sys.exit(1) + + yaml_out = metrics_to_yaml(metrics, args.version) + + import os + os.makedirs(os.path.dirname(args.output), exist_ok=True) + with open(args.output, 'w') as f: + f.write(yaml_out) + + print(f'Wrote {len(metrics)} metrics to {args.output}') + + +if __name__ == '__main__': + main()