feat: add monitoring trends
This commit is contained in:
1 parent
19fc29c72c
commit
4d360fac42
18 files changed
+1683
No files matched your search
@@ -0,0 +1,98 @@
|
||||
"""Typed contracts for bounded historical telemetry trends."""
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Literal
|
||||
from uuid import UUID
|
||||
|
||||
from pydantic import BaseModel, ConfigDict, Field, model_validator
|
||||
|
||||
|
||||
TrendScopeType = Literal["fleet", "site", "room", "miner"]
|
||||
TrendRange = Literal["6h", "24h", "7d"]
|
||||
TrendMetric = Literal["hashrate", "power"]
|
||||
TrendAttribution = Literal["current_placement_cohort", "miner_identity", "fleet"]
|
||||
|
||||
|
||||
class MonitoringTrendQuery(BaseModel):
|
||||
model_config = ConfigDict(populate_by_name=True)
|
||||
|
||||
scope: TrendScopeType = "fleet"
|
||||
scope_id: UUID | None = None
|
||||
time_range: TrendRange = Field(default="24h", alias="range")
|
||||
|
||||
@model_validator(mode="after")
|
||||
def validate_scope_identity(self) -> "MonitoringTrendQuery":
|
||||
if self.scope == "fleet" and self.scope_id is not None:
|
||||
raise ValueError("scope_id is not allowed for fleet scope")
|
||||
if self.scope != "fleet" and self.scope_id is None:
|
||||
raise ValueError("scope_id is required for this scope")
|
||||
return self
|
||||
|
||||
|
||||
class MonitoringScope(BaseModel):
|
||||
type: TrendScopeType
|
||||
id: UUID | None = None
|
||||
label: str
|
||||
|
||||
|
||||
class MonitoringSiteOption(BaseModel):
|
||||
id: UUID
|
||||
name: str
|
||||
|
||||
|
||||
class MonitoringRoomOption(BaseModel):
|
||||
id: UUID
|
||||
site_id: UUID
|
||||
name: str
|
||||
|
||||
|
||||
class MonitoringAvailableScopes(BaseModel):
|
||||
fleet: bool = True
|
||||
sites: list[MonitoringSiteOption] = Field(default_factory=list)
|
||||
rooms: list[MonitoringRoomOption] = Field(default_factory=list)
|
||||
|
||||
|
||||
class MonitoringTrendPoint(BaseModel):
|
||||
bucket_start: datetime
|
||||
bucket_end: datetime
|
||||
value: float | None = None
|
||||
observation_count: int
|
||||
metric_sample_count: int
|
||||
observed_miner_count: int
|
||||
contributing_miner_count: int
|
||||
scoped_miner_count: int
|
||||
incomplete: bool = False
|
||||
|
||||
|
||||
class MonitoringTrendSeries(BaseModel):
|
||||
metric: TrendMetric
|
||||
unit: Literal["TH/s", "W"]
|
||||
label: str
|
||||
points: list[MonitoringTrendPoint]
|
||||
|
||||
|
||||
class MonitoringTrendData(BaseModel):
|
||||
scope: MonitoringScope
|
||||
series: list[MonitoringTrendSeries]
|
||||
available_scopes: MonitoringAvailableScopes
|
||||
|
||||
|
||||
class MonitoringTrendMeta(BaseModel):
|
||||
generated_at: datetime
|
||||
latest_observed_at: datetime | None = None
|
||||
source: Literal["raw_snapshots"] = "raw_snapshots"
|
||||
attribution: TrendAttribution
|
||||
time_range: TrendRange = Field(alias="range")
|
||||
bucket_seconds: int
|
||||
maximum_points: int = 200
|
||||
completeness: Literal["not_guaranteed"] = "not_guaranteed"
|
||||
current_bucket_incomplete: bool
|
||||
database_query_count: int = Field(ge=1, le=2)
|
||||
|
||||
model_config = ConfigDict(populate_by_name=True)
|
||||
|
||||
|
||||
class MonitoringTrendResponse(BaseModel):
|
||||
data: MonitoringTrendData
|
||||
meta: MonitoringTrendMeta
|
||||
error: None = None
|
||||
Reference in new issue
Block a user