Documentation
¶
Overview ¶
Package stats stores per-item resource statistics: 15 minutes at 5 s in memory and 7 days of minutes (avg, min, max per series) in one fixed-size ring file per item. A query never waits for an item's writer (it reads the ring file without the writer's lock); it takes the store read lock for the lookup, so it can wait behind the creation of an item and behind Forget and Sweep, which hold the store lock. Series keys must be stable: a ring never frees a series slot, so after MaxSeries distinct keys every new key is rejected for the life of the item. An error from Record for which IsPartial is true means the other keys of the sample were stored. One known limit: after a clock step back of more than a minute, a query overlapping the rewrite of the same minute may mix that minute's columns in one point of one response.
Index ¶
- Constants
- Variables
- func IsPartial(err error) bool
- func SplitKey(key string) (chart, name string)
- func Unit(chart, name string) string
- type Clock
- type Evaluator
- func (e *Evaluator) Active(item string) []Event
- func (e *Evaluator) LastError() error
- func (e *Evaluator) OnMinute(item string, minute time.Time)
- func (e *Evaluator) Prune()
- func (e *Evaluator) Rebuild(item string)
- func (e *Evaluator) Resolve(item string)
- func (e *Evaluator) Rules(item string) []Rule
- func (e *Evaluator) SetRules(item string, rules []Rule) error
- type Event
- type FakeClock
- type Point
- type Range
- type Result
- type Rule
- type RuleError
- type Sample
- type SeriesData
- type Store
- func (s *Store) Close() error
- func (s *Store) Forget(item string, at time.Time) error
- func (s *Store) Items() []string
- func (s *Store) Quarantined() []string
- func (s *Store) Query(item string, r Range) (Result, error)
- func (s *Store) Record(item string, at time.Time, smp Sample) error
- func (s *Store) SetOnMinute(fn func(item string, minute time.Time))
- func (s *Store) Skipped() []string
- func (s *Store) Sweep(now time.Time) error
- type SystemClock
Constants ¶
const ( Minutes = 10080 // slots in a ring file (7 days of minutes) LiveSlots = 180 // 15 minutes at 5 s MaxSeries = 48 // series per item MaxItems = 256 // live items MaxForgotten = 256 // forgotten items kept MaxKeyLen = 63 // bytes of a series key MaxItemLen = 256 // bytes of an item name FormatVersion = 1 // MaxFileSize is the size of a ring file holding MaxSeries series: // 8192 header bytes + 40320 bytes per column x (1 stamp + 3 x MaxSeries). MaxFileSize = 8192 + 40320*(1+3*MaxSeries) )
Variables ¶
var ( ErrUnknownItem = errors.New("stats: unknown item") ErrBadRange = errors.New("stats: bad range") ErrBadItem = errors.New("stats: bad item name") ErrBadKey = errors.New("stats: bad series key") ErrSeriesCap = errors.New("stats: too many series") ErrTooManyItems = errors.New("stats: too many items") ErrOutOfOrder = errors.New("stats: sample out of order") ErrClosed = errors.New("stats: store closed") ErrRingSkipped = errors.New("stats: ring file unreadable at Open, left untouched") // the error text names the file )
Functions ¶
func IsPartial ¶
IsPartial reports whether err from Record only says that some keys of the sample were rejected (ErrSeriesCap, ErrBadKey): the other keys were stored, so the caller must neither retry nor drop the sample. It is false for nil and for any error that has another cause, alone or joined.
Types ¶
type Evaluator ¶
type Evaluator struct {
// contains filtered or unexported fields
}
Evaluator turns the alert/* series of each committed minute into firing and resolved events. Its settings and state live in <dir>/alerts.json.
func NewEvaluator ¶
NewEvaluator loads <dir>/alerts.json. A missing file means defaults; an unreadable, invalid or other-version file is moved to alerts.json.bad and defaults are used. emit is called after the state is saved, outside every lock.
func (*Evaluator) LastError ¶
LastError returns the error of the last write of alerts.json; nil once the file matches the state again.
func (*Evaluator) OnMinute ¶
OnMinute evaluates the committed minute of item. It is the Store's SetOnMinute hook; services never call it.
func (*Evaluator) Prune ¶
func (e *Evaluator) Prune()
Prune drops the rules and state of the items no longer in the Store. Items is read under e.mu, so the state of an item that commits its first minute meanwhile is not dropped.
func (*Evaluator) Rebuild ¶
Rebuild recounts the runs of item from its history, at start: an alert still holding is kept silently, one that ended while the service was down resolves, one that built up fires.
func (*Evaluator) Resolve ¶
Resolve ends every active alert of item, which is no longer measured, and clears its runs: later minutes fire only after a full new run.
func (*Evaluator) Rules ¶
Rules returns the rules of item: both keys, cpu_high then mem_high, defaults unless overridden.
type FakeClock ¶
type FakeClock struct {
// contains filtered or unexported fields
}
FakeClock is a manually driven Clock, safe for concurrent use.
func NewFakeClock ¶
type Point ¶
Point: T in Unix seconds; nil Avg/Min/Max is a gap.
func (Point) MarshalJSON ¶
MarshalJSON writes [t, avg, min, max] with null for gaps.
func (*Point) UnmarshalJSON ¶
type Range ¶
type Range string
Range is a period asked by the page.
func ParseRange ¶
ParseRange accepts exactly the five lower-case period names.
type Result ¶
type Result struct {
Range Range `json:"range"`
StepSeconds int `json:"step_seconds"`
From int64 `json:"from"`
To int64 `json:"to"`
Series []SeriesData `json:"series"` // never nil: empty gives "series":[]
}
func (Result) MarshalJSON ¶
MarshalJSON writes a nil Series as [].
type Rule ¶
type Rule struct {
Key string `json:"key"`
Enabled bool `json:"enabled"`
Threshold float64 `json:"threshold"`
Minutes int `json:"minutes"`
}
Rule is one alert setting; Key is "cpu_high" or "mem_high".
func DefaultRules ¶
func DefaultRules() []Rule
DefaultRules returns cpu_high 90 % for 10 min and mem_high 90 % for 5 min, both enabled.
type Sample ¶
Sample is a measure at one instant: "chart/name" -> value. An absent key means no data, never 0.
type SeriesData ¶
type Store ¶
type Store struct {
// contains filtered or unexported fields
}
Store keeps, per item, the last 15 minutes in memory (5 s) and 7 days of minutes on disk (one ring file per item).
Lock order: Store.mu, then entry.mu, then ring.mu. Query holds Store.mu (read) only for the lookup, then ring.cmu (read) while it reads the file; ring.Close takes ring.cmu, so a ring is closed, and only then removed, once no query reads it.
func (*Store) Forget ¶
Forget marks item as gone at the given time: its history stays in Items and Query until Sweep removes it 7 days later; a Record revives it. Beyond MaxForgotten, the items forgotten longest ago are removed at once.
func (*Store) Quarantined ¶
Quarantined returns the ring files moved aside to *.bad at Open.
func (*Store) Query ¶
Query returns item over r. It takes no lock a writer holds while writing: the store read lock for the lookup, then plain reads of the ring file (checked by its stamps) and the live ring under its own read lock.
func (*Store) SetOnMinute ¶
SetOnMinute sets the hook called once per item per committed minute.
func (*Store) Skipped ¶
Skipped returns the ring files Open did not load: those it could not read for a reason other than corruption (permissions, a dangling symlink, an I/O error), which stay untouched (Record of their item returns ErrRingSkipped until a later Open reads them), and corrupt ones it could not move to *.bad, which a Record of their item replaces. Their items are absent from the store.
func (*Store) Sweep ¶
Sweep removes every item forgotten, or without data, for 7 days or more, every *.ring.tmp and every *.ring.bad older than 7 days. No other file of the directory is touched. ponytail: it holds the store lock for the whole pass, reading each stamp column, waiting on each entry lock (a commit in flight) and, for a removed ring, on the queries still reading it; Sweep runs hourly and 256 x 40 KiB is quick, a finer lock is not worth it.
type SystemClock ¶
type SystemClock struct{}
SystemClock reads the real time.
func (SystemClock) Now ¶
func (SystemClock) Now() time.Time