Skip to content

feat: add metrics API v2 endpoints#21

Open
mukama wants to merge 9 commits intotetherto:developfrom
mukama:feat/metrics-endpoints
Open

feat: add metrics API v2 endpoints#21
mukama wants to merge 9 commits intotetherto:developfrom
mukama:feat/metrics-endpoints

Conversation

@mukama
Copy link
Contributor

@mukama mukama commented Feb 19, 2026

Summary

  • Adds 7 GET /auth/metrics/* API v2 endpoints ported from the legacy dashboard, replacing frontend tail-log / tail-log/range-aggr calls with clean REST APIs
  • All endpoints follow the established { log: [...], summary: {...} } response format consistent with finance endpoints
  • Introduces shared interval resolution utilities (auto-selects 1h/1d/1w based on date range)
  • Fixes RPC range-string timestamp parsing for grouped responses (groupRange: '1D'/'1W')
  • Fixes miner-status online count derivation using type_cnt field

Endpoints

GET /auth/metrics/hashrate — daily hashrate (MH/s) with summary averages via tailLogCustomRangeAggr RPC
GET /auth/metrics/hashrate?start=1700000000000&end=1700100000000&overwriteCache=true

GET /auth/metrics/consumption — daily power consumption (W + MWh) via tailLogCustomRangeAggr RPC
GET /auth/metrics/consumption?start=1700000000000&end=1700100000000&overwriteCache=true

GET /auth/metrics/efficiency — daily efficiency (W/TH/s) via tailLogCustomRangeAggr RPC
GET /auth/metrics/efficiency?start=1700000000000&end=1700100000000&overwriteCache=true

GET /auth/metrics/miner-status — daily miner status breakdown (online/offline/sleep/maintenance) via tailLog RPC
GET /auth/metrics/miner-status?start=1700000000000&end=1700100000000&overwriteCache=true

GET /auth/metrics/power-mode — miner power mode distribution over time via tailLog RPC
GET /auth/metrics/power-mode?start=1700000000000&end=1700100000000&interval=1d&overwriteCache=true
Optional: interval ("1h" | "1d" | "1w"), overwriteCache

GET /auth/metrics/power-mode/timeline — per-miner power mode timeline with merged segments via tailLog RPC
GET /auth/metrics/power-mode/timeline?start=1700000000000&end=1700100000000&container=bitdeer-9a&limit=10080&overwriteCache=true
Optional: start, end, container, limit, overwriteCache

GET /auth/metrics/temperature — per-container temperature breakdown with site-wide aggregates via tailLog RPC
GET /auth/metrics/temperature?start=1700000000000&end=1700100000000&interval=1d&container=bitdeer-9a&overwriteCache=true
Optional: interval ("1h" | "1d" | "1w"), container, overwriteCache

Known Issues

  • 1h interval uses 3h granularity — The finest available data is stat-3h entries. Selecting 1h interval returns raw 3h data points, not true 1-hour resolution.

Add metrics hashrate endpoint that queries miner hashrate data via
tailLogCustomRangeAggr RPC and returns daily hashrate with summary.
Add metrics consumption endpoint that queries powermeter data via
tailLogCustomRangeAggr RPC and returns daily power/consumption with summary.
Add metrics efficiency endpoint that queries miner efficiency (W/TH) data
via tailLogCustomRangeAggr RPC. Adds AGGR_FIELDS.EFFICIENCY constant.
Add miner-status endpoint that queries miner status data via tailLog RPC
with aggregated offline/sleep/maintenance counts per day.
…erature endpoints

Add three new metrics endpoints with interval-based aggregation,
per-miner power mode categorization with status overrides, timeline
segmentation, and per-container temperature breakdown with site-wide
aggregates.
…ltering

Curl testing revealed three bugs:
- tailLog with groupRange returns ts as "start-end" string (e.g.
  "1770854400000-1771459199999"), not a number. getStartOfDay(NaN)
  silently dropped all entries. Added parseEntryTs() helper.
- Container names are not valid RPC tags (returns empty []). Changed
  to always use tag 't-miner' and post-filter by container in handler.
- Pre-existing bug in getMinerStatus: same range-string ts issue with
  groupRange '1D' caused empty logs. Now fixed.
total_cnt does not exist in stat-3h RPC entries. The online count was
always 0 because the total was defaulting to 0. Use type_cnt (object
keyed by miner type) with sumObjectValues() to derive the correct total,
enabling accurate online = total - offline - sleep - maintenance.
@mukama mukama changed the title feat: add metrics API v2 endpoints (hashrate, consumption, efficiency, miner-status) feat: add metrics API v2 endpoints Feb 19, 2026
- Extract validateStartEnd(), iterateRpcEntries(), forEachRangeAggrItem()
  shared helpers to eliminate duplicated validation, result unpacking,
  and range-aggr processing across 7 endpoints
- Add TYPE_CNT, OFFLINE_CNT, SLEEP_CNT, MAINTENANCE_CNT to AGGR_FIELDS
  constants replacing hardcoded strings in miner-status handler
- Use proper weighted running average for temperature merging across orks
- Extract DEFAULT_TIMELINE_LIMIT constant and extractContainerFromMinerId()
- Unify entry.error checks and parseEntryTs usage across all endpoints

const interval = resolveInterval(start, end, req.query.interval)
const config = getIntervalConfig(interval)
const limit = Math.ceil((end - start) / config.divisorMs)
Copy link
Contributor

Choose a reason for hiding this comment

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

should start/end be included in the rpcPayload instead of calculating the limit here?

Copy link
Contributor Author

@mukama mukama Feb 26, 2026

Choose a reason for hiding this comment

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

Good question! The tailLog RPC method uses limit (entry count), not start/end dates. tailLogCustomRangeAggr is the one that accepts dates directly. So for the temperature endpoint, limit is the correct parameter to control how many 3-hour stat entries we fetch.

return {
ts: Number(dayTs),
powerW,
consumptionMWh: (powerW * 24) / 1000000

Choose a reason for hiding this comment

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

Why are we multiplying by 24? If its consumption shouldn't it be instantaneous / avg of the day ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

powerW is the average watts for that day (from powermeter aggregation). To convert daily average power to daily energy consumption in MWh: W × 24h / 1,000,000 = MWh. Added a code comment to clarify this.

@mukama mukama requested review from paragmore and tekwani February 26, 2026 17:37
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.

3 participants