Skip to content

feat: add metrics API v2 endpoints#21

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

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

Conversation

@mukama
Copy link
Contributor

@mukama mukama commented Feb 19, 2026

Summary

  • Adds 9 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

GET /auth/metrics/containers/:id — real-time container telemetry snapshot (miners list + sensor data) via listThings + tailLog RPC
GET /auth/metrics/containers/bitdeer-9a?overwriteCache=true
Returns { id, miners, telemetry } where telemetry contains the latest sensor readings (temperatures, pressure) from container_specific_stats_group_aggr

GET /auth/metrics/containers/:id/history — container sensor history time series via tailLog RPC
GET /auth/metrics/containers/bitdeer-9a/history?start=1700000000000&end=1700100000000&limit=10080&overwriteCache=true
Optional: start (default: 24h ago), end (default: now), limit (default: 10080), overwriteCache
Returns { log } with timestamped sensor readings sorted ascending

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
@mukama mukama requested review from paragmore and tekwani February 26, 2026 17:37
tekwani
tekwani previously approved these changes Mar 2, 2026
Resolve conflicts in constants.js and server/index.js to include
both metrics and alerts endpoints and exports.
Add GET /auth/metrics/containers/:id and GET /auth/metrics/containers/:id/history
endpoints to complete the metrics API v2 surface. These extract per-container sensor
data from the container_specific_stats_group_aggr aggregation field.
Address PR review: replace { tags: 1 } with DEVICE_LIST_FIELDS constant
to return full device data (id, type, code, ip, tags, info, rack)
instead of only tag fields.
@@ -570,7 +571,7 @@ async function getContainerTelemetry (ctx, req) {
requestRpcEachLimit(ctx, RPC_METHODS.LIST_THINGS, {
query: { tags: { $in: [containerTag] } },
status: 1,
Copy link
Contributor

Choose a reason for hiding this comment

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

status can be removed as DEVICE_LIST_FIELDS don't have snap properties

@@ -570,7 +571,7 @@ async function getContainerTelemetry (ctx, req) {
requestRpcEachLimit(ctx, RPC_METHODS.LIST_THINGS, {
Copy link
Contributor

Choose a reason for hiding this comment

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

should fetch all the objects in a loop

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