feat(dashboard): set Feed Expiration visualization to Bar Gauge - #113
feat(dashboard): set Feed Expiration visualization to Bar Gauge#113anant-shipit wants to merge 2 commits into
Conversation
📝 WalkthroughWalkthroughThe Feed Expiration Grafana panel now uses a horizontal bar gauge. Its queries convert days to seconds for duration formatting. The panel also adds countdown documentation, thresholds, bounds, gradient coloring, sizing, and value display settings. ChangesFeed expiration visualization
Estimated code review effort: 2 (Simple) | ~10 minutes Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Hey @anant-shipit, great work on this. I like the way you visualized this metric, and I think this is the right approach. One change I'd like to see is displaying the duration in both weeks and days instead of a single unit. For example, instead of 8.29 weeks, display 8 weeks and 2 days. That representation is easier to read.
|
… days Changed the unit from 'd' (days) to 'dtdurations' and multiplied the PromQL queries by 86400 to convert days to seconds. Grafana's dtdurations unit auto-formats this into human-readable 'X wk Y d' format. Thresholds updated to seconds equivalents: - Red: < 7 days (604800s) - Yellow: 7-30 days - Green: > 30 days (2592000s) Signed-off-by: anant-shipit <anantsinghrathore97@gmail.com>
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@grafana/dashboards/watchdog_metrics_dashboard.json`:
- Around line 199-200: Update the panel 201 field using the "dtdurations" unit
to include "decimals": 1, ensuring Grafana displays the day-level countdown
component while preserving the existing unit configuration.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 5a7a8568-b908-45d3-98bb-b9dd2963757c
📒 Files selected for processing (1)
grafana/dashboards/watchdog_metrics_dashboard.json
| "unit": "dtdurations" | ||
| }, |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
python3 - <<'PY'
import json
from pathlib import Path
dashboard = json.loads(
Path("grafana/dashboards/watchdog_metrics_dashboard.json").read_text()
)
panel = next(panel for panel in dashboard["panels"] if panel.get("id") == 201)
defaults = panel["fieldConfig"]["defaults"]
assert defaults["unit"] == "dtdurations"
assert defaults.get("decimals") == 1
PYRepository: OneBusAway/watchdog
Length of output: 246
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== dashboard context =="
python3 - <<'PY'
import json
from pathlib import Path
dashboard = json.loads(Path("grafana/dashboards/watchdog_metrics_dashboard.json").read_text())
for panel in dashboard["panels"]:
if panel.get("id") == 201:
defaults = panel["fieldConfig"]["defaults"]
print(json.dumps({"id": panel.get("id"), "title": panel.get("title"), "type": panel.get("type")}, indent=2))
print(json.dumps(defaults, indent=2))
PY
echo
echo "== occurrences around dashboards and duration formatter usage =="
rg -n '"dtdurations"|valueFormats|decimals|8 weeks|week|days' grafana/dashboards/watchdog_metrics_dashboard.jsonRepository: OneBusAway/watchdog
Length of output: 1408
🌐 Web query:
Grafana dtdurations value format decimals behavior display next duration component
💡 Result:
In Grafana, the dtdurations unit (Duration (s)) is a specialized formatter designed to represent numeric values (interpreted as seconds) as human-readable durations [1][2][3]. The behavior of decimals and the display of duration components is governed by Grafana's internal display processor, which dynamically handles unit scaling based on the magnitude of the value [4][5][6]. Key behaviors include: 1. Automatic Scaling and Precision: By default, Grafana automatically determines the scale (e.g., seconds, milliseconds) and truncates decimals based on the magnitude of the data [6]. When the Decimals option is left empty, Grafana attempts to automatically truncate excess precision [6]. If a specific decimal count is provided, it dictates the precision used in the formatted output [4]. 2. Decimals Behavior: Setting the Decimals option to a fixed number (e.g., 0) can influence how Grafana renders values [7][5]. Users have reported that forcing 0 decimals can sometimes cause issues with Y-axis granularity or result in NaN values when data ranges are very tight, as the formatter may struggle to represent small variations within a single unit interval (e.g., sub-second differences) [7][5]. 3. Display of Duration Components: The dtdurations unit generally scales automatically to the most appropriate unit [6]. If you require a specific format that explicitly displays multiple components (like days, hours, minutes, and seconds), you may need to use other dedicated units, such as: - dthms (Duration (hh:mm:ss)) [1][2] - dtdhms (Duration (d hh:mm:ss)) [1][2] Because dtdurations is a dynamic formatter, it does not always offer granular control over exactly which "next" duration component is displayed if the value is very small; it will shift the display to milliseconds or other smaller units as necessary to maintain accuracy [4][5]. If you encounter rendering issues (such as NaN or loss of data), it is often related to how the automatic scaling interacts with fixed decimal constraints on the axis [7][5].
Citations:
- 1: https://github.com/grafana/grafana/blob/main/packages/grafana-data/src/valueFormats/categories.ts
- 2: https://github.com/grafana/grafana/blob/fec7c3e13336d85fe7e2f5c0e19fa351bf73868d/packages/grafana-ui/src/utils/valueFormats/categories.ts
- 3: https://pkg.go.dev/github.com/grafana/grafana-foundation-sdk/go/units
- 4: https://github.com/grafana/grafana/blob/main/packages/grafana-data/src/field/displayProcessor.ts
- 5: When using decimal 0 and unit time seconds with metric data in seconds with decimals the Y axis loses granularity. grafana/grafana#57337
- 6: https://grafana.com/docs/grafana/latest/visualizations/panels-visualizations/configure-standard-options/
- 7: Time series: y-axis becomes NaN for close values with hh:mm:ss grafana/grafana#73795
🌐 Web query:
Grafana dtdurations formatter days weeks decimals components source Grafana v13.0.2
💡 Result:
In Grafana v13.0.2, the dtdurations formatter (labeled as "duration (s)" in the UI) is designed to automatically scale duration values based on their magnitude [1][2]. It is not currently possible to manually force this formatter to use specific components like days or weeks while excluding others, nor is there a setting to explicitly lock the units to a specific scale while allowing decimal values [3]. Technical details for the dtdurations formatter: 1. Functionality: The formatter is defined by the toDurationInSeconds function within Grafana's codebase [1]. It applies automatic unit scaling based on the magnitude of the input value [2]. 2. Scaling Logic: The formatter automatically transitions between units based on thresholds [2]: - Less than 1 µs: Uses ns - Less than 1 ms: Uses µs - Less than 1 s: Uses ms - Less than 60 s: Uses s - Less than 3600 s: Uses minutes (min) - Less than 86400 s: Uses hours (hour) - Less than 604800 s: Uses days (day) - Less than 31536000 s: Uses weeks (week) - Above this threshold: Uses years [2]. 3. Decimals: The formatter accepts a DecimalCount parameter which controls the precision of the output [2]. When the value reaches the threshold for a specific unit (e.g., days), the value is divided by the relevant constant (e.g., 86400 for days) and displayed with the specified number of decimals [2]. Because this behavior is hardcoded in the data transformation logic, users seeking to force specific units (such as only days) are generally advised to either perform the unit conversion directly in their data source query or use a custom expression to divide the input value by the desired unit interval (e.g., dividing seconds by 86400) and applying a custom unit label [3].
Citations:
- 1: https://github.com/grafana/grafana/blob/main/packages/grafana-data/src/valueFormats/categories.ts
- 2: https://fossies.org/linux/grafana/packages/grafana-data/src/valueFormats/dateTimeFormatters.ts
- 3: https://community.grafana.com/t/how-to-force-a-time-value-to-be-in-a-specific-format/136889
Set dtdurations to show the day-level countdown.
Panel 201 uses "unit": "dtdurations" without "decimals", so Grafana renders the largest duration component only. Add "decimals": 1 so values such as several weeks and a day show the day component instead of only weeks.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@grafana/dashboards/watchdog_metrics_dashboard.json` around lines 199 - 200,
Update the panel 201 field using the "dtdurations" unit to include "decimals":
1, ensuring Grafana displays the day-level countdown component while preserving
the existing unit configuration.
Source: MCP tools
|
Hey @anant-shipit, make sure to apply the CodeRabbit suggestions. |

Fixes #98
Design Decisions Summary
Grouping & Panel Choice:
Grouped under "Static GTFS Health", this metric requires an intuitive countdown visualization rather than historical tracking.
Visualization Rationale:
I chose a horizontal Bar Gauge. Feed expiration is effectively a countdown timer. Rendering it as a horizontal bar gauge allows operators to stack multiple feeds side-by-side. The bars shift from green to warning yellow/red as the days until expiration drop below critical thresholds (30 days / 7 days).
Go Metric Modifications:
No Go metric types were modified.
Summary by CodeRabbit