github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/observability/probe/aggregate.go (about) 1 // Copyright 2022 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package probe 5 6 import ( 7 "github.com/juju/errors" 8 ) 9 10 // Aggregate is an implementation of the Prober interface that returns success 11 // if all probes under it's controler are successful or false if one more of 12 // the probes fail. 13 // Convenience NewAggregate() exists to initialise the map. 14 type Aggregate struct { 15 // Probes is a map of probes to run as part of this aggregate with the key 16 // corresponding to well known name for the probe. 17 Probes map[string]Prober 18 } 19 20 // ProbeResultCallBack is a function signature for receiving the result of a 21 // probers probe call. 22 type ProbeResultCallback func(probeKey string, val bool, err error) 23 24 func NewAggregate() *Aggregate { 25 return &Aggregate{ 26 Probes: make(map[string]Prober), 27 } 28 } 29 30 // Probe implements Prober Probe 31 func (a *Aggregate) Probe() (bool, error) { 32 return a.ProbeWithResultCallback(ProbeResultCallback(func(_ string, _ bool, _ error) {})) 33 } 34 35 // ProbeWithResultCallback functions the same as Probe but for each probe tested 36 // in the aggregate calls the provided callback with probe name and result. 37 // Useful for building more details reports of what probes are failing and 38 // succeeding. 39 func (a *Aggregate) ProbeWithResultCallback( 40 cb ProbeResultCallback, 41 ) (bool, error) { 42 rval := true 43 var errVal error 44 45 for name, p := range a.Probes { 46 val, err := p.Probe() 47 cb(name, val, err) 48 if err != nil && errVal == nil { 49 errVal = errors.Annotatef(err, "probe %s", name) 50 } else if err != nil { 51 errVal = errors.Wrap(errVal, errors.Annotatef(err, "probe %s", name)) 52 } 53 54 // only change rval if it's currently true. All probes in the aggregate 55 // need to return true to get a true answer. 56 rval = rval && val 57 } 58 59 return rval, errVal 60 }