Files
corteza/server/pkg/healthcheck/check.go
T

129 lines
1.7 KiB
Go

package healthcheck
import (
"bytes"
"context"
"fmt"
"io"
"strings"
"sync"
)
type (
checkFn func(ctx context.Context) error
Meta struct {
Label string
Description string
}
check struct {
fn checkFn
*Meta
}
result struct {
err error
*Meta
}
results []*result
checks struct {
l sync.RWMutex
cc []*check
}
)
var (
defaults *checks
)
func init() {
defaults = New()
}
func Defaults() *checks {
return defaults
}
func New() *checks {
return &checks{cc: []*check{}}
}
// Add appends new check
func (c *checks) Add(fn checkFn, label string, description ...string) {
c.l.Lock()
defer c.l.Unlock()
c.cc = append(c.cc, &check{fn, &Meta{Label: label, Description: strings.Join(description, "")}})
}
func (c *checks) Run(ctx context.Context) results {
c.l.RLock()
defer c.l.RUnlock()
var rr = make([]*result, len(c.cc))
for i, c := range c.cc {
rr[i] = &result{c.fn(ctx), c.Meta}
}
return rr
}
func (rr results) Healthy() bool {
for _, c := range rr {
if c.err != nil {
return false
}
}
return true
}
func (rr results) String() string {
buf := &bytes.Buffer{}
rr.WriteTo(buf)
return buf.String()
}
func (rr results) WriteTo(w io.Writer) (int64, error) {
var (
p = func(f string, aa ...interface{}) {
_, _ = fmt.Fprintf(w, f, aa...)
}
)
for _, r := range rr {
if r.IsHealthy() {
p("PASS")
} else {
p("FAIL")
}
p(" %s", r.Label)
if !r.IsHealthy() {
p(": %v", r.Error())
}
p("\n")
}
return 0, nil
}
func (r *result) IsHealthy() bool {
return r != nil && r.err == nil
}
func (r *result) Error() string {
if r == nil || r.err == nil {
return ""
}
return r.err.Error()
}