Skip to content

feat(dashboard): set Feed Expiration visualization to Bar Gauge - #113

Open
anant-shipit wants to merge 2 commits into
OneBusAway:mainfrom
anant-shipit:feat/issue-98-feed-expiration
Open

feat(dashboard): set Feed Expiration visualization to Bar Gauge#113
anant-shipit wants to merge 2 commits into
OneBusAway:mainfrom
anant-shipit:feat/issue-98-feed-expiration

Conversation

@anant-shipit

@anant-shipit anant-shipit commented Jul 17, 2026

Copy link
Copy Markdown

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

  • Improvements
    • Updated the “Feed Expiration” dashboard panel to a horizontal bar gauge.
    • Added clearer countdown descriptions and visual guidance.
    • Improved threshold-based coloring, value limits, day units, and gradient rendering for easier status interpretation.

@CLAassistant

CLAassistant commented Jul 17, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@coderabbitai

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The 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.

Changes

Feed expiration visualization

Layer / File(s) Summary
Configure feed expiration bar gauge
grafana/dashboards/watchdog_metrics_dashboard.json
The panel documents countdown semantics, converts expiration days to seconds, adds thresholds and bounds, and renders values with a horizontal gradient bar gauge.

Estimated code review effort: 2 (Simple) | ~10 minutes

Suggested reviewers: 0xaboomar

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main change: changing Feed Expiration visualization to a Bar Gauge.
Linked Issues check ✅ Passed The dashboard implements the requested Feed Expiration visualization, preserves server filtering, and adds readable duration formatting and expiration thresholds [#98].
Out of Scope Changes check ✅ Passed The changes are limited to the Feed Expiration Grafana panel and directly support the linked issue objectives [#98].
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@0xaboomar

Copy link
Copy Markdown
Member

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.

image

… 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>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

📥 Commits

Reviewing files that changed from the base of the PR and between 2c5ee77 and cbc6d50.

📒 Files selected for processing (1)
  • grafana/dashboards/watchdog_metrics_dashboard.json

Comment on lines +199 to +200
"unit": "dtdurations"
},

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 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
PY

Repository: 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.json

Repository: 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:


🌐 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:


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

@0xaboomar

Copy link
Copy Markdown
Member

Hey @anant-shipit, make sure to apply the CodeRabbit suggestions.

@coveralls

Copy link
Copy Markdown

Coverage Status

coverage: 51.371% (+0.03%) from 51.344% — anant-shipit:feat/issue-98-feed-expiration into OneBusAway:main

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feed Expiration

4 participants