Skip to content

Commit b7f161a

Browse files
committed
refactor: rename Metrics gear URL /history → /metrics; clarify the term
The Metrics gear was historically called "history" because the page shows time-series data. That name leaked into the URL (/history), the API endpoints (/api/{boxID}/history/*), the templ file (history.templ), the handler functions (HistoryPage, APIStatsHistoryHandler, …), and assorted comments / docs / README entries. With nginx / Apache / Caddy / Traefik detection now landing (issue #95) and "metric source" / "primary source" terminology in the new code, the dual naming has become genuinely confusing. This commit renames the metrics-gear identity end-to-end: - Page route: /history → /metrics (plugin.go SidebarItem.Path, base.templ path-prefix match + sidebar links, gears-page.js). - API routes: /api/{boxID}/history/stats → /api/{boxID}/metrics/stats /api/{boxID}/history/metrics → /api/{boxID}/metrics/system /api/{boxID}/history/backend/{name} → /api/{boxID}/metrics/backend/{name} (Last one coexists with /metrics/backend/{name}/details — the time-series endpoint vs the drill-down details endpoint added in #87.) - Handler functions: HistoryPage → MetricsPage APIStatsHistoryHandler → APIMetricsStatsHandler APIBackendHistoryHandler → APIMetricsBackendHandler APISystemMetricsHistoryHandler → APIMetricsSystemHandler - File: pages/history.templ → pages/metrics.templ (templ component History() → Metrics()) - JS callers: history.templ + details.templ + chart_partials.templ (8 fetch() URLs updated). - Docs: metrics gear README routes table + architecture diagram + development snippet; cmd/server/main.go route-group comment; pages.go migration-history comment; permissions.go field comment; docs/gears.md gear list. Intentionally **kept** as legitimate "history" concepts (per design discussion): - DB tables stats_history, system_metrics_history, backend_history — the rows ARE historical records. Renaming requires a migration with no user-visible benefit; the names accurately describe what they contain. The DB query methods that read them (GetStatsHistory, GetBackendHistory, GetSystemMetricsHistory) keep their names for the same reason. - Snapshot interval / retention config: HistoryIntervalSeconds, store_history, history_retention_days — these control how the historical record is kept. Same reasoning. - Local `history` variable names inside the renamed handler functions — they reflect what the DB methods return. - OS-update apt/zypper/dnf/pacman history — distinct concept. /api/v1/system/updates/history on the agent, /os-updates/history on the dashboard, parseAptHistoryLog, /var/log/apt/history.log, etc. All untouched. - HAProxy config change history — distinct concept. /{boxID}/haproxy/config/history, templates/pages/haproxy_config/change_history.templ, etc. Untouched. Agent module: no changes. The agent's "history" references are all OS-update package-manager history (apt/zypper/dnf/pacman/apk/yum), which is the legitimate concept. Tests + build green on both modules.
1 parent 5819f15 commit b7f161a

13 files changed

Lines changed: 94 additions & 70 deletions

File tree

docs/gears.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ Client gears run in the **gearbox** web application (the monitoring client) and
138138
- `traffic` - Traffic analysis and visualization page
139139
- `alerts` - Alert management page
140140
- `services` - Service status and control page
141-
- `metrics` - System metrics and history page
141+
- `metrics` - Time-series system + HAProxy metrics page (`/metrics`)
142142

143143
### Gear Scope: Box vs System
144144

gearbox/cmd/server/main.go

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -627,7 +627,7 @@ func main() {
627627

628628
// Gear-registered routes
629629
// Gears handle: / (haproxy overview), /status-grid (haproxy), /logs (logs),
630-
// /services (services), /history (metrics), /certificates (certificates),
630+
// /services (services), /metrics (metrics gear), /certificates (certificates),
631631
// /traffic (traffic), /alerts (alerts)
632632
gearManager.RegisterRoutes(r)
633633

@@ -676,10 +676,13 @@ func main() {
676676
r.Get("/{boxID}/charts/error-rates", h.APIChartsErrorRatesHandler)
677677
r.Get("/{boxID}/logs/{logName}", h.APILogsHandler)
678678
r.Get("/{boxID}/log-sources", h.APILogSourcesHandler) // Get enabled log sources
679-
// History API endpoints
680-
r.Get("/{boxID}/history/stats", h.APIStatsHistoryHandler)
681-
r.Get("/{boxID}/history/metrics", h.APISystemMetricsHistoryHandler)
682-
r.Get("/{boxID}/history/backend/{backendName}", h.APIBackendHistoryHandler)
679+
// Metrics gear — time-series endpoints (HAProxy stats,
680+
// system metrics, per-backend stats). These power the
681+
// charts on the /metrics page; the /metrics/* "v2"
682+
// endpoints just below power the KPI band + insights.
683+
r.Get("/{boxID}/metrics/stats", h.APIMetricsStatsHandler)
684+
r.Get("/{boxID}/metrics/system", h.APIMetricsSystemHandler)
685+
r.Get("/{boxID}/metrics/backend/{backendName}", h.APIMetricsBackendHandler)
683686
r.Get("/{boxID}/incidents", h.APIIncidentsHandler)
684687

685688
// Metrics gear v2 — insights & drill-down endpoints

gearbox/internal/framework/handler/api_stats.go

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -102,8 +102,12 @@ func (h *Handler) APISystemMetricsHandler(w http.ResponseWriter, r *http.Request
102102
h.writeJSON(w, response)
103103
}
104104

105-
// APIStatsHistoryHandler returns historical stats data.
106-
func (h *Handler) APIStatsHistoryHandler(w http.ResponseWriter, r *http.Request) {
105+
// APIMetricsStatsHandler returns time-series HAProxy stats for the
106+
// Metrics page's per-backend chart. Served at /api/{boxID}/metrics/stats.
107+
// The underlying DB method is still named GetStatsHistory because the
108+
// data it returns IS historical records; the URL renamed for clarity
109+
// with issue #97.
110+
func (h *Handler) APIMetricsStatsHandler(w http.ResponseWriter, r *http.Request) {
107111
boxID := chi.URLParam(r, "boxID")
108112
if boxID == "" {
109113
http.Error(w, "Server ID required", http.StatusBadRequest)
@@ -142,8 +146,12 @@ func (h *Handler) APIStatsHistoryHandler(w http.ResponseWriter, r *http.Request)
142146
})
143147
}
144148

145-
// APIBackendHistoryHandler returns historical data for a specific backend.
146-
func (h *Handler) APIBackendHistoryHandler(w http.ResponseWriter, r *http.Request) {
149+
// APIMetricsBackendHandler returns time-series stats for a specific
150+
// backend on the Metrics page. Served at
151+
// /api/{boxID}/metrics/backend/{backendName}. Coexists with the
152+
// /metrics/backend/{name}/details drill-down (which returns aggregate
153+
// insights rather than the time-series).
154+
func (h *Handler) APIMetricsBackendHandler(w http.ResponseWriter, r *http.Request) {
147155
// Check if user has permission to view metrics
148156
if !h.authManager.HasPermission(r, models.ComponentMetrics, models.PermissionView) {
149157
http.Error(w, "Forbidden: insufficient permissions to view metrics", http.StatusForbidden)
@@ -191,8 +199,10 @@ func (h *Handler) APIBackendHistoryHandler(w http.ResponseWriter, r *http.Reques
191199
})
192200
}
193201

194-
// APISystemMetricsHistoryHandler returns historical system metrics.
195-
func (h *Handler) APISystemMetricsHistoryHandler(w http.ResponseWriter, r *http.Request) {
202+
// APIMetricsSystemHandler returns time-series host-level metrics for
203+
// the Metrics page (CPU, memory, disk, network). Served at
204+
// /api/{boxID}/metrics/system.
205+
func (h *Handler) APIMetricsSystemHandler(w http.ResponseWriter, r *http.Request) {
196206
// Check if user has permission to view metrics
197207
if !h.authManager.HasPermission(r, models.ComponentMetrics, models.PermissionView) {
198208
http.Error(w, "Forbidden: insufficient permissions to view metrics", http.StatusForbidden)

gearbox/internal/framework/handler/pages.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import (
1515
// - OverviewPage -> plugins/haproxy
1616
// - StatusGridPage -> plugins/haproxy
1717
// - LogsPage -> plugins/logs
18-
// - HistoryPage -> plugins/metrics
18+
// - MetricsPage -> plugins/metrics
1919
// - ServicesPage -> plugins/services
2020
// - CertificatesPage -> plugins/certificates
2121
// - TrafficPage -> plugins/traffic

gearbox/internal/framework/models/permissions.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -335,7 +335,7 @@ func GetAvailablePermissionsForComponent(c Component) []Permission {
335335
}
336336
case ComponentMetrics:
337337
return []Permission{
338-
PermissionView, // View metrics/history page and data
338+
PermissionView, // View the Metrics page and its data
339339
PermissionConfigure, // Configure metrics storage settings
340340
}
341341
case ComponentGears:

gearbox/internal/framework/templates/layouts/base.templ

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ func gearLabelForPath(path string) string {
3636
return ""
3737
case path == "/haproxy" || strings.HasPrefix(path, "/haproxy/"):
3838
return "HAProxy"
39-
case path == "/history" || strings.HasPrefix(path, "/history/"):
39+
case path == "/metrics" || strings.HasPrefix(path, "/metrics/"):
4040
return "Metrics"
4141
case path == "/logs" || strings.HasPrefix(path, "/logs/"):
4242
return "Logs"
@@ -2175,7 +2175,7 @@ func integrationPath(name string) string {
21752175
case "haproxy":
21762176
return "/haproxy"
21772177
case "metrics":
2178-
return "/history"
2178+
return "/metrics"
21792179
case "logs":
21802180
return "/logs"
21812181
case "services":
@@ -2287,7 +2287,7 @@ templ OrderedIntegrationLinks(currentPath string) {
22872287
@SidebarLinkWithIntegration("/haproxy", "HAProxy", SidebarIconHAProxy(), currentPath, "haproxy")
22882288
}
22892289
if canViewIntegration(ctx, "metrics") {
2290-
@SidebarLinkWithIntegration("/history", "Metrics", SidebarIconMetrics(), currentPath, "metrics")
2290+
@SidebarLinkWithIntegration("/metrics", "Metrics", SidebarIconMetrics(), currentPath, "metrics")
22912291
}
22922292
if canViewIntegration(ctx, "logs") {
22932293
@SidebarLinkWithIntegration("/logs", "Logs", SidebarIconLogs(), currentPath, "logs")
@@ -2332,7 +2332,7 @@ templ renderIntegrationLink(name string, currentPath string) {
23322332
case "haproxy":
23332333
@SidebarLinkDraggable("/haproxy", "HAProxy", SidebarIconHAProxy(), currentPath, "haproxy")
23342334
case "metrics":
2335-
@SidebarLinkDraggable("/history", "Metrics", SidebarIconMetrics(), currentPath, "metrics")
2335+
@SidebarLinkDraggable("/metrics", "Metrics", SidebarIconMetrics(), currentPath, "metrics")
23362336
case "logs":
23372337
@SidebarLinkDraggable("/logs", "Logs", SidebarIconLogs(), currentPath, "logs")
23382338
case "services":

gearbox/internal/framework/templates/pages/details.templ

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -714,7 +714,7 @@ templ BackendDetail(user *models.User, backendName string, stats *models.HAProxy
714714
function loadBackendHistory() {
715715
updateResolutionLabel();
716716
var hours = document.getElementById('hours-select').value;
717-
fetch('/api/' + backendServerID + '/history/backend/' + encodeURIComponent(backendNameVar) + '?hours=' + hours)
717+
fetch('/api/' + backendServerID + '/metrics/backend/' + encodeURIComponent(backendNameVar) + '?hours=' + hours)
718718
.then(function(response) { return response.json(); })
719719
.then(function(result) {
720720
cachedBackendData = result.data || [];

gearbox/internal/framework/templates/pages/history.templ renamed to gearbox/internal/framework/templates/pages/metrics.templ

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ import "github.com/sarg3nt/gearbox/internal/framework/models"
44
import "github.com/sarg3nt/gearbox/internal/framework/templates/layouts"
55
import "github.com/sarg3nt/gearbox/internal/framework/templates/components"
66

7-
templ History(user *models.User, servers []models.BoxConfig) {
8-
@layouts.Base("Metrics", user, "/history") {
7+
templ Metrics(user *models.User, servers []models.BoxConfig) {
8+
@layouts.Base("Metrics", user, "/metrics") {
99
<!-- Hidden container for page header content. Title + box selector
1010
live in the global header breadcrumb + chip. -->
1111
<div id="page-header-source" class="hidden">
@@ -843,12 +843,12 @@ templ History(user *models.User, servers []models.BoxConfig) {
843843
await applyCapabilities(serverID);
844844

845845
try {
846-
// Fetch stats history
847-
const statsResponse = await fetch(`/api/${serverID}/history/stats?hours=${hours}`);
846+
// Fetch HAProxy stats time series
847+
const statsResponse = await fetch(`/api/${serverID}/metrics/stats?hours=${hours}`);
848848
const statsData = await statsResponse.json();
849849

850-
// Fetch system metrics history
851-
const metricsResponse = await fetch(`/api/${serverID}/history/metrics?hours=${hours}`);
850+
// Fetch system-metrics time series
851+
const metricsResponse = await fetch(`/api/${serverID}/metrics/system?hours=${hours}`);
852852
const metricsData = await metricsResponse.json();
853853

854854
// Cache the data for fullscreen toggle

gearbox/internal/gears/metrics/README.md

Lines changed: 27 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
# Metrics Gear
22

3-
The Metrics gear surfaces historical metrics for HAProxy and the underlying
4-
host. It's the place users land when they want to answer *"how busy was the
5-
proxy, and what went wrong?"*
3+
The Metrics gear surfaces time-series metrics for HAProxy and the underlying
4+
host at the dashboard's `/metrics` URL. It's the place users land when they
5+
want to answer *"how busy was the proxy, and what went wrong?"*
6+
7+
> The page used to live at `/history` and was internally referred to as the
8+
> "history" gear; issue #97 renamed it to `/metrics` to keep "history"
9+
> reserved for genuinely distinct concepts (OS-update apt/zypper history,
10+
> HAProxy config change history).
611
712
## Layout
813

@@ -44,7 +49,7 @@ The page has four stacked sections:
4449

4550
| Permission | Description |
4651
|---------------------|----------------------------|
47-
| `metrics:view` | View metrics and history |
52+
| `metrics:view` | View the Metrics page |
4853
| `metrics:configure` | Configure metrics settings |
4954

5055
The drill-down drawer's *Recent 5xx log lines* section additionally
@@ -53,21 +58,21 @@ shows a "logs unavailable" hint instead of failing.
5358

5459
## Routes
5560

56-
| Method | Path | Description |
57-
|--------|------------|---------------------------|
58-
| GET | `/history` | Main history/metrics page |
61+
| Method | Path | Description |
62+
|--------|------------|-------------------|
63+
| GET | `/metrics` | Main Metrics page |
5964

6065
## API endpoints (main handler)
6166

62-
Existing endpoints kept for backwards compatibility:
67+
Time-series endpoints (chart data):
6368

64-
| Method | Path | Description |
65-
|--------|-------------------------------------------------|-------------------------------|
66-
| GET | `/api/{serverID}/history/stats` | Get historical HAProxy stats |
67-
| GET | `/api/{serverID}/history/metrics` | Get historical system metrics |
68-
| GET | `/api/{serverID}/history/backend/{backendName}` | Get backend-specific history |
69-
| GET | `/api/{serverID}/metrics/storage-stats` | Get storage statistics |
70-
| POST | `/api/{serverID}/metrics/clear` | Clear metrics data |
69+
| Method | Path | Description |
70+
|--------|-------------------------------------------------|-----------------------------------------------|
71+
| GET | `/api/{serverID}/metrics/stats` | Time-series HAProxy stats (per-snapshot rows) |
72+
| GET | `/api/{serverID}/metrics/system` | Time-series host metrics (CPU/mem/disk/net) |
73+
| GET | `/api/{serverID}/metrics/backend/{backendName}` | Time-series per-backend stats |
74+
| GET | `/api/{serverID}/metrics/storage-stats` | Storage statistics |
75+
| POST | `/api/{serverID}/metrics/clear` | Clear metrics data |
7176

7277
New in v2 ("insights" surface — see `api_metrics_insights.go`):
7378

@@ -87,7 +92,8 @@ default 2000) and an optional `backend` filter.
8792
The new endpoints sit on top of existing tables — no new collection runs
8893
on the agent. Specifically:
8994

90-
- KPI summary aggregates `stats_history` (per-snapshot HAProxy stats) and
95+
- KPI summary aggregates `stats_history` (per-snapshot HAProxy stats — table
96+
name unchanged from the pre-rename schema; the records IS historical) and
9197
`traffic_flows` (per-minute response-code buckets from the Traffic gear's
9298
collector).
9399
- Error Insights and backend details query `traffic_flows` exclusively —
@@ -100,16 +106,17 @@ on the agent. Specifically:
100106

101107
```text
102108
internal/gears/metrics/
103-
├── plugin.go # Gear registration
104-
├── handlers.go # HTTP handler (/history page)
109+
├── plugin.go # Gear registration (/metrics route)
110+
├── handlers.go # MetricsPage handler
105111
├── partials.templ # CPU / memory / disk / etc. widget partials
106112
├── chart_partials.templ # Reusable chart components for the home gear
107113
├── icons.go # Sidebar icon
108114
├── settings.go # Settings page component
109115
└── README.md # This file
110116
111117
internal/framework/handler/
112-
├── api_stats.go # Existing /history/* endpoints
118+
├── api_stats.go # Time-series endpoints
119+
│ # (/api/{boxID}/metrics/{stats,system,backend/*})
113120
├── api_metrics_insights.go # KPI / error breakdown / drill-down / log-errors
114121
└── api_metrics_insights_helpers.go # KPI math, sparkline downsampling
115122
@@ -121,7 +128,7 @@ internal/framework/database/
121128
## Development
122129

123130
The gear is automatically included in the build via its `init()` function.
124-
After editing `history.templ`, run:
131+
After editing `metrics.templ`, run:
125132

126133
```bash
127134
make templ-generate && make build

gearbox/internal/gears/metrics/chart_partials.templ

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ script initSessionsRequestsChart(boxID string, hours int, limit int) {
2828
var canvasId = 'chart-sessions-requests-' + boxID;
2929

3030
function loadChart() {
31-
fetch('/api/' + boxID + '/history/stats?hours=' + hours + '&limit=' + limit)
31+
fetch('/api/' + boxID + '/metrics/stats?hours=' + hours + '&limit=' + limit)
3232
.then(function(r) { return r.json(); })
3333
.then(function(json) {
3434
var data = json.data || [];
@@ -84,7 +84,7 @@ script initServerHealthChart(boxID string, hours int, limit int) {
8484
var canvasId = 'chart-server-health-' + boxID;
8585

8686
function loadChart() {
87-
fetch('/api/' + boxID + '/history/stats?hours=' + hours + '&limit=' + limit)
87+
fetch('/api/' + boxID + '/metrics/stats?hours=' + hours + '&limit=' + limit)
8888
.then(function(r) { return r.json(); })
8989
.then(function(json) {
9090
var data = json.data || [];
@@ -140,7 +140,7 @@ script initCPULoadChart(boxID string, hours int, limit int) {
140140
var canvasId = 'chart-cpu-load-' + boxID;
141141

142142
function loadChart() {
143-
fetch('/api/' + boxID + '/history/metrics?hours=' + hours + '&limit=' + limit)
143+
fetch('/api/' + boxID + '/metrics/system?hours=' + hours + '&limit=' + limit)
144144
.then(function(r) { return r.json(); })
145145
.then(function(json) {
146146
var data = json.data || [];
@@ -197,7 +197,7 @@ script initMemoryUsageChart(boxID string, hours int, limit int) {
197197
var canvasId = 'chart-memory-usage-' + boxID;
198198

199199
function loadChart() {
200-
fetch('/api/' + boxID + '/history/metrics?hours=' + hours + '&limit=' + limit)
200+
fetch('/api/' + boxID + '/metrics/system?hours=' + hours + '&limit=' + limit)
201201
.then(function(r) { return r.json(); })
202202
.then(function(json) {
203203
var data = json.data || [];
@@ -252,7 +252,7 @@ script initNetworkThroughputChart(boxID string, hours int, limit int) {
252252
var canvasId = 'chart-network-throughput-' + boxID;
253253

254254
function loadChart() {
255-
fetch('/api/' + boxID + '/history/metrics?hours=' + hours + '&limit=' + limit)
255+
fetch('/api/' + boxID + '/metrics/system?hours=' + hours + '&limit=' + limit)
256256
.then(function(r) { return r.json(); })
257257
.then(function(json) {
258258
var data = json.data || [];
@@ -328,7 +328,7 @@ script initResponseTimesChart(boxID string, hours int, limit int) {
328328
var canvasId = 'chart-response-times-' + boxID;
329329

330330
function loadChart() {
331-
fetch('/api/' + boxID + '/history/stats?hours=' + hours + '&limit=' + limit)
331+
fetch('/api/' + boxID + '/metrics/stats?hours=' + hours + '&limit=' + limit)
332332
.then(function(r) { return r.json(); })
333333
.then(function(json) {
334334
var data = json.data || [];
@@ -383,7 +383,7 @@ script initErrorRatesChart(boxID string, hours int, limit int) {
383383
var canvasId = 'chart-error-rates-' + boxID;
384384

385385
function loadChart() {
386-
fetch('/api/' + boxID + '/history/stats?hours=' + hours + '&limit=' + limit)
386+
fetch('/api/' + boxID + '/metrics/stats?hours=' + hours + '&limit=' + limit)
387387
.then(function(r) { return r.json(); })
388388
.then(function(json) {
389389
var data = json.data || [];

0 commit comments

Comments
 (0)