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 }