github.com/gramework/gramework@v1.8.1-0.20231027140105-82555c9057f5/healthchecks/hc_internal.go (about)

     1  package healthchecks
     2  
     3  import (
     4  	"errors"
     5  	"runtime"
     6  	"strings"
     7  
     8  	sigar "github.com/cloudfoundry/gosigar"
     9  	"github.com/gramework/gramework"
    10  	"github.com/gramework/gramework/internal/gfmt"
    11  )
    12  
    13  type hc struct {
    14  	CPUClock string  `json:"cpu_clock"`
    15  	RAM      ramJSON `json:"ram_usage"`
    16  	Swap     ramJSON `json:"swap_usage"`
    17  
    18  	LA         laJSON `json:"load_average"`
    19  	LoadStatus string `json:"load_alert_status"`
    20  
    21  	Uptime string `json:"uptime"`
    22  
    23  	Custom map[string]interface{} `json:"custom_metrics,omitempty"`
    24  }
    25  
    26  type laJSON struct {
    27  	One     float64 `json:"one"`
    28  	Five    float64 `json:"five"`
    29  	Fifteen float64 `json:"fifteen"`
    30  }
    31  
    32  type ramJSON struct {
    33  	Used  string `json:"used"`
    34  	Total string `json:"total"`
    35  }
    36  
    37  type sigarWrapper struct {
    38  	sigar.ConcreteSigar
    39  }
    40  
    41  func (s sigarWrapper) swap() ramJSON {
    42  	swap, err := s.GetSwap()
    43  	if err != nil {
    44  		err = swap.Get()
    45  		_ = err
    46  	}
    47  	return ramJSON{
    48  		Used:  gfmt.Si(swap.Used),
    49  		Total: gfmt.Si(swap.Total),
    50  	}
    51  }
    52  func (s sigarWrapper) ram() ramJSON {
    53  	mem, err := s.GetMem()
    54  	if err != nil {
    55  		err = mem.Get()
    56  		_ = err
    57  	}
    58  	return ramJSON{
    59  		Used:  gfmt.Si(mem.Used),
    60  		Total: gfmt.Si(mem.Total),
    61  	}
    62  }
    63  
    64  func doReg(r interface{}, collectors []func() (statKey string, stats interface{}), registerPing, registerHC bool) error {
    65  	app, isApp := r.(*gramework.App)
    66  	sr, isSr := r.(*gramework.SubRouter)
    67  	if !isApp && !isSr {
    68  		return errors.New("unsupported handler type")
    69  	}
    70  
    71  	if isApp {
    72  		sr = app.Sub("")
    73  	}
    74  
    75  	if registerPing {
    76  		sr.GET("/ping", "pong")
    77  	}
    78  	if registerHC {
    79  		sr.GET("/healthcheck", ServeHealthcheck(collectors...))
    80  	}
    81  
    82  	return nil
    83  }
    84  
    85  func check(collectors ...func() (statKey string, stats interface{})) interface{} {
    86  	s := sigarWrapper{sigar.ConcreteSigar{}}
    87  	currentCheck := &hc{
    88  		CPUClock:   gfmt.Si(uint64(gramework.TicksPerSecond())),
    89  		RAM:        s.ram(),
    90  		Swap:       s.swap(),
    91  		LoadStatus: "<unknown>",
    92  	}
    93  	la, err := s.GetLoadAverage()
    94  	if err != nil {
    95  		err = la.Get() // retry
    96  	}
    97  
    98  	if err == nil {
    99  		maxLA := float64(runtime.NumCPU() + 2)
   100  		currentCheck.LA = laJSON(la)
   101  		diffOne := maxLA - la.One
   102  		diffFive := maxLA - la.Five
   103  		diffFifteen := maxLA - la.Fifteen
   104  
   105  		alertTrigger := float64(-3)
   106  		warnTrigger := float64(0)
   107  
   108  		if diffOne < alertTrigger || diffFive < alertTrigger || diffFifteen < alertTrigger {
   109  			currentCheck.LoadStatus = "alert"
   110  		} else if diffOne < warnTrigger || diffFive < warnTrigger || diffFifteen < warnTrigger {
   111  			currentCheck.LoadStatus = "warn"
   112  		} else {
   113  			currentCheck.LoadStatus = "ok"
   114  		}
   115  	}
   116  
   117  	uptime := sigar.Uptime{}
   118  	err = uptime.Get()
   119  	if err != nil {
   120  		err = uptime.Get() // retry
   121  	}
   122  	if err == nil {
   123  		currentCheck.Uptime = strings.TrimSpace(uptime.Format())
   124  	}
   125  
   126  	if len(collectors) > 0 {
   127  		currentCheck.Custom = make(map[string]interface{})
   128  	}
   129  	for _, cb := range collectors {
   130  		if cb != nil {
   131  			key, stats := cb()
   132  			currentCheck.Custom[key] = stats
   133  		}
   134  	}
   135  	return currentCheck
   136  }