package probes import ( "fmt" "sync" "time" ) // Result of the execution of a probe. type Result struct { ID string Spec SpecCommon Ok bool Error string Start time.Time Duration time.Duration Logs string } // Nice displayable string. func (r *Result) String() string { return fmt.Sprintf("%s(%s)", r.Spec.Name, r.ID) } // ResultStore keeps the most recent probe results in storage, and // allows access to them (mostly for debugging purposes, as this part // isn't required by the prober functionality). The results buffer has // a fixed size, so older results will be dropped as more recent ones // come in. Failures are kept in a separate buffer, with the hope of // keeping errors around for longer for inspection purposes, even // after they've recovered. type ResultStore interface { Push(*Result) Each(func(*Result)) EachErrs(func(*Result)) Find(string) *Result } // Very simple overwriting circular buffer of results. type resultBuffer struct { buf []*Result sz, head int } func newResultBuffer(sz int) *resultBuffer { return &resultBuffer{ buf: make([]*Result, sz), sz: sz, } } func (b *resultBuffer) Push(result *Result) { b.buf[b.head] = result b.head++ if b.head >= b.sz { b.head -= b.sz } } func (b *resultBuffer) Each(f func(*Result)) { for i := 0; i < b.sz; i++ { pos := b.head + i if pos >= b.sz { pos -= b.sz } if b.buf[pos] != nil { f(b.buf[pos]) } } } // ResultStore that keeps recent results in memory. type memResultStore struct { mx sync.Mutex last *resultBuffer errs *resultBuffer } func NewResultStore(numOk, numErrs int) ResultStore { return &memResultStore{ last: newResultBuffer(numOk), errs: newResultBuffer(numErrs), } } func (r *memResultStore) Push(result *Result) { r.mx.Lock() r.last.Push(result) if !result.Ok { r.errs.Push(result) } r.mx.Unlock() } func (r *memResultStore) Each(f func(*Result)) { r.mx.Lock() r.last.Each(f) r.mx.Unlock() } func (r *memResultStore) EachErrs(f func(*Result)) { r.mx.Lock() r.errs.Each(f) r.mx.Unlock() } func (r *memResultStore) Find(id string) (out *Result) { r.mx.Lock() defer r.mx.Unlock() r.last.Each(func(r *Result) { if r.ID == id { out = r } }) if out != nil { return } r.errs.Each(func(r *Result) { if r.ID == id { out = r } }) return }