Documentation
¶
Overview ¶
Package usagecost allocates a real or configured infrastructure price to the apps and databases that consume it, then rolls the result up per project, environment and team. It is pure arithmetic: collection and persistence live with the callers.
Index ¶
- Constants
- func Buckets(p Period, monthly bool) []string
- func DayKey(t time.Time) string
- func DaysInMonth(t time.Time) int
- func ElapsedDays(now time.Time) float64
- func ForecastMonthEnd(spent, elapsedDays float64, daysInMonth int, recentDaily []float64) float64
- func ParseDay(s string) (time.Time, error)
- func StartOfDay(t time.Time) time.Time
- func StartOfMonth(t time.Time) time.Time
- func SumSamples(samples []Sample, from, to time.Time) float64
- func UnitPricesFromNode(n NodePrice, cpuWeightPct float64) (cpuCoreHour, memGiBHour float64)
- func ValidGroup(g string) bool
- func WriteCSV(w io.Writer, currency string, r Report, labels map[string]string) error
- type Band
- type Breach
- type Budget
- type BudgetStatus
- type DailyCost
- type DailyUsage
- type DayInput
- type DayResult
- type Exploration
- type ExploreInput
- type Group
- type Integrated
- type NodePrice
- type Period
- type Report
- type Sample
- type Series
- type Settings
- type Totals
Constants ¶
const ( ScopeProject = "project" ScopeTeam = "team" )
Budget scope kinds.
const ( LevelWarn = "warn" LevelOver = "over" LevelForecast = "forecast" )
Budget breach levels, also the alert dedupe key suffix.
const ( GroupApp = "app" GroupProject = "project" GroupTag = "tag" GroupNode = "node" GroupKind = "kind" )
Explorer group dimensions.
const ( ConfidenceLow = "low" ConfidenceMedium = "medium" ConfidenceHigh = "high" )
Forecast confidence labels.
const ( DimResource = "resource" DimProject = "project" DimEnvironment = "environment" DimTeam = "team" )
Group dimensions a report rolls cost up by.
const ( ModeUnit = "unit" ModeNode = "node" )
Allocation modes.
const ( BasisAvg = "avg" BasisP50 = "p50" )
Usage bases.
const ( KindApp = "app" KindDatabase = "database" KindIdle = "idle" KindDay = "day" )
Row kinds a daily row can describe.
const DefaultWarnPct = 80.0
DefaultWarnPct is the first alert level when a budget sets none.
const OtherKey = "other"
OtherKey collapses the groups beyond the top series of an exploration.
const UnassignedKey = "unassigned"
UnassignedKey groups resources with no project, environment or team.
const UntaggedKey = "untagged"
UntaggedKey groups resources that carry no tag.
Variables ¶
This section is empty.
Functions ¶
func DaysInMonth ¶
DaysInMonth returns how many days the month containing t has.
func ElapsedDays ¶
ElapsedDays is how many days of the month containing now have passed.
func ForecastMonthEnd ¶
ForecastMonthEnd projects the month's total from spend so far. It uses the mean of the most recent full days when available, so a spike at the start of the month does not dominate, and falls back to the overall average.
func StartOfMonth ¶
StartOfMonth truncates to the first day of the UTC month.
func SumSamples ¶
SumSamples adds every value inside [from, to), for counter delta metrics.
func UnitPricesFromNode ¶
UnitPricesFromNode derives per-core-hour and per-GiB-hour prices from one node's monthly price and capacity, splitting the price by cpuWeightPct.
func ValidGroup ¶
ValidGroup reports whether g is a dimension Explore understands.
Types ¶
type Band ¶
type Band struct {
Spent float64 `json:"spent"`
Mid float64 `json:"mid"`
Low float64 `json:"low"`
High float64 `json:"high"`
Confidence string `json:"confidence"`
Samples int `json:"samples"`
}
Band is a month end forecast with an 80 percent range.
func ForecastBand ¶
ForecastBand projects the month end like ForecastMonthEnd and adds a range from the day to day spread: the remaining days are treated as independent draws, so the band widens with the square root of the days left. With fewer than three full days it falls back to a fixed relative band and reports low confidence, because a spread over one or two samples means nothing.
type Budget ¶
type Budget struct {
ID string `json:"id"`
Scope string `json:"scope"`
ScopeID string `json:"scope_id"`
Monthly float64 `json:"monthly"`
WarnPct float64 `json:"warn_pct"`
}
Budget is a monthly spending limit for a project or a team.
type BudgetStatus ¶
type BudgetStatus struct {
Budget
Name string `json:"name"`
Currency string `json:"currency"`
Spent float64 `json:"spent"`
Forecast float64 `json:"forecast"`
SpentPct float64 `json:"spent_pct"`
ForecastPct float64 `json:"forecast_pct"`
Level string `json:"level"`
}
BudgetStatus is a budget with its month to date position.
func NewStatus ¶
func NewStatus(b Budget, name, currency string, spent, forecast float64) BudgetStatus
NewStatus positions a budget against spend and a month end forecast.
func (BudgetStatus) Breaches ¶
func (s BudgetStatus) Breaches() []Breach
Breaches lists which thresholds the status has crossed. Over implies warn, and a forecast overrun is reported only while spend has not already passed the limit, so one budget never produces redundant lines.
type DailyCost ¶
type DailyCost struct {
DailyUsage
ComputeCost float64 `json:"compute_cost"`
StorageCost float64 `json:"storage_cost"`
EgressCost float64 `json:"egress_cost"`
IdleCost float64 `json:"idle_cost"`
}
DailyCost is a DailyUsage with its allocated cost components.
type DailyUsage ¶
type DailyUsage struct {
Day string `json:"day"`
Kind string `json:"kind"`
Name string `json:"name"`
TeamID string `json:"team_id"`
ProjectID string `json:"project_id"`
EnvironmentID string `json:"environment_id"`
NodeID string `json:"node_id"`
UpSeconds float64 `json:"up_seconds"`
CPUAvgCores float64 `json:"cpu_avg_cores"`
CPUP50Cores float64 `json:"cpu_p50_cores"`
MemAvgBytes float64 `json:"mem_avg_bytes"`
MemP50Bytes float64 `json:"mem_p50_bytes"`
StorageBytes float64 `json:"storage_bytes"`
EgressBytes float64 `json:"egress_bytes"`
}
DailyUsage is one resource's measured usage for one UTC day.
func UsageFromSamples ¶
func UsageFromSamples(base DailyUsage, cpuPercent, memBytes []Sample, from, to time.Time) DailyUsage
UsageFromSamples builds a resource's daily usage from its CPU percent and memory byte series. CPU percent is of one core, so 100 is one core.
type DayInput ¶
type DayInput struct {
Day time.Time
Settings Settings
Nodes map[string]NodePrice
Usage []DailyUsage
// Fraction is the share of the day that has elapsed, 1 for a complete
// day. A partial day scales the node's daily price the same way.
Fraction float64
}
DayInput is everything allocation needs for one UTC day.
type DayResult ¶
type DayResult struct {
Rows []DailyCost
// Unpriced lists node ids whose resources could not be priced.
Unpriced []string
}
DayResult is the allocation of one day.
func AllocateDay ¶
AllocateDay prices one day of usage. Storage and egress unit prices apply in both modes; compute is priced per unit or taken from node bills.
type Exploration ¶
type Exploration struct {
GroupBy string `json:"group_by"`
Buckets []string `json:"buckets"`
Trend []float64 `json:"trend"`
Total float64 `json:"total"`
Previous float64 `json:"previous"`
DeltaPct *float64 `json:"delta_pct,omitempty"`
Series []Series `json:"series"`
// Movers are the groups whose cost grew most against the previous period.
Movers []Series `json:"movers"`
}
Exploration is the result of Explore.
func Explore ¶
func Explore(in ExploreInput) Exploration
Explore aggregates cost per bucket and group, ranks the groups, and finds the largest increases against the previous period.
type ExploreInput ¶
type ExploreInput struct {
Period Period
Previous Period
Rows []DailyCost
Prev []DailyCost
GroupBy string
// Monthly buckets by calendar month instead of by day.
Monthly bool
// TagsOf maps "kind:name" to tag names, used by the tag dimension.
TagsOf map[string][]string
}
ExploreInput selects what Explore aggregates.
type Group ¶
type Group struct {
Key string `json:"key"`
Kind string `json:"kind,omitempty"`
Name string `json:"name,omitempty"`
Total float64 `json:"total"`
Compute float64 `json:"compute"`
Storage float64 `json:"storage"`
Egress float64 `json:"egress"`
Idle float64 `json:"idle_share"`
Previous float64 `json:"previous"`
Delta float64 `json:"delta"`
DeltaPct *float64 `json:"delta_pct,omitempty"`
ProjectID string `json:"project_id,omitempty"`
TeamID string `json:"team_id,omitempty"`
EnvironmentID string `json:"environment_id,omitempty"`
Daily []float64 `json:"daily"`
}
Group is one row of a ranked breakdown.
type Integrated ¶
type Integrated struct {
Avg float64
P50 float64
// UpSeconds is how long the metric was actually reported, so downtime
// counts as zero rather than as the average of the uptime.
UpSeconds float64
}
Integrated is a metric reduced over one window.
type NodePrice ¶
type NodePrice struct {
NodeID string `json:"node_id"`
MonthlyPrice float64 `json:"monthly_price"`
VCPUs float64 `json:"vcpus"`
MemoryGiB float64 `json:"memory_gib"`
}
NodePrice is one node's monthly bill and capacity.
type Period ¶
Period is a half open [From, To) range of UTC days.
func PreviousPeriod ¶
PreviousPeriod returns the comparison window: for month to date, the same number of days at the start of last month; otherwise the window of equal length immediately before.
type Report ¶
type Report struct {
Period Period `json:"period"`
Previous Period `json:"previous"`
Days []string `json:"days"`
Totals Totals `json:"totals"`
Resources []Group `json:"resources"`
Projects []Group `json:"projects"`
Environments []Group `json:"environments"`
Teams []Group `json:"teams"`
Movers []Group `json:"movers"`
Tags []Group `json:"tags"`
// Forecast is the projected month end total, set for periods that
// include the current month's elapsed days.
Forecast *float64 `json:"forecast,omitempty"`
}
Report is the full showback result for one period.
type Series ¶
type Series struct {
Key string `json:"key"`
Total float64 `json:"total"`
Previous float64 `json:"previous"`
Delta float64 `json:"delta"`
DeltaPct *float64 `json:"delta_pct,omitempty"`
Values []float64 `json:"values"`
}
Series is one group's cost over the buckets.
type Settings ¶
type Settings struct {
Mode string `json:"mode"`
Currency string `json:"currency"`
CPUCoreHour float64 `json:"cpu_core_hour"`
MemGiBHour float64 `json:"mem_gib_hour"`
StorageGiBMonth float64 `json:"storage_gib_month"`
EgressGiB float64 `json:"egress_gib"`
// IdleSpreadPct is, in node mode, the share of unattributed node cost
// spread over resources by usage; in unit mode a proportional overhead.
IdleSpreadPct float64 `json:"idle_spread_pct"`
Basis string `json:"basis"`
// CPUWeightPct is the part of a node price attributed to CPU, the rest
// to memory.
CPUWeightPct float64 `json:"cpu_weight_pct"`
}
Settings is the operator's pricing configuration.
func DefaultSettings ¶
func DefaultSettings() Settings
DefaultSettings is what an unconfigured instance reports: unit mode with zero prices, so nothing is invented until the operator sets prices.