Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: Kirill Danshin <k@guava.by>
- Loading branch information
1 parent
32bd735
commit bfe0390
Showing
8 changed files
with
218 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package healthchecks | ||
|
||
// Register both ping and healthcheck endpoints | ||
func Register(r interface{}, collectors ...func() (statKey string, stats interface{})) error { | ||
return doReg(r, collectors, true, true) | ||
} | ||
|
||
// RegisterPing registers ping endpoint | ||
func RegisterPing(r interface{}) error { | ||
return doReg(r, nil, true, false) | ||
} | ||
|
||
// RegisterHealthcheck registers healthcheck endpoint | ||
func RegisterHealthcheck(r interface{}, collectors ...func() (statKey string, stats interface{})) error { | ||
return doReg(r, collectors, false, true) | ||
} | ||
|
||
// ServeHealthcheck serves healthcheck | ||
func ServeHealthcheck(collectors ...func() (statKey string, stats interface{})) func() interface{} { | ||
return func() interface{} { | ||
return check(collectors...) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
package healthchecks | ||
|
||
import ( | ||
"errors" | ||
"runtime" | ||
"strings" | ||
|
||
sigar "github.com/cloudfoundry/gosigar" | ||
"github.com/gramework/gramework" | ||
"github.com/gramework/gramework/internal/gfmt" | ||
) | ||
|
||
type routerable interface{} | ||
|
||
type hc struct { | ||
CPUClock string `json:"cpu_clock"` | ||
RAM ramJSON `json:"ram_usage"` | ||
Swap ramJSON `json:"swap_usage"` | ||
|
||
LA laJSON `json:"load_average"` | ||
LoadStatus string `json:"load_alert_status"` | ||
|
||
Uptime string `json:"uptime"` | ||
|
||
Custom map[string]interface{} `json:"custom_metrics,omitempty"` | ||
} | ||
|
||
type laJSON struct { | ||
One float64 `json:"one"` | ||
Five float64 `json:"five"` | ||
Fifteen float64 `json:"fifteen"` | ||
} | ||
|
||
type ramJSON struct { | ||
Used string `json:"used"` | ||
Total string `json:"total"` | ||
} | ||
|
||
type sigarWrapper struct { | ||
sigar.ConcreteSigar | ||
} | ||
|
||
func (s sigarWrapper) swap() ramJSON { | ||
swap, err := s.GetSwap() | ||
if err != nil { | ||
swap.Get() | ||
} | ||
return ramJSON{ | ||
Used: gfmt.Si(swap.Used), | ||
Total: gfmt.Si(swap.Total), | ||
} | ||
} | ||
func (s sigarWrapper) ram() ramJSON { | ||
mem, err := s.GetMem() | ||
if err != nil { | ||
mem.Get() | ||
} | ||
return ramJSON{ | ||
Used: gfmt.Si(mem.Used), | ||
Total: gfmt.Si(mem.Total), | ||
} | ||
} | ||
|
||
func doReg(r interface{}, collectors []func() (statKey string, stats interface{}), registerPing, registerHC bool) error { | ||
app, isApp := r.(*gramework.App) | ||
sr, isSr := r.(*gramework.SubRouter) | ||
if !isApp && !isSr { | ||
return errors.New("unsupported handler type") | ||
} | ||
|
||
if isApp { | ||
sr = app.Sub("") | ||
} | ||
|
||
if registerPing { | ||
sr.GET("/ping", "pong") | ||
} | ||
if registerHC { | ||
sr.GET("/healthcheck", ServeHealthcheck(collectors...)) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func check(collectors ...func() (statKey string, stats interface{})) interface{} { | ||
s := sigarWrapper{sigar.ConcreteSigar{}} | ||
currentCheck := &hc{ | ||
CPUClock: gfmt.Si(uint64(gramework.TicksPerSecond())), | ||
RAM: s.ram(), | ||
Swap: s.swap(), | ||
LoadStatus: "<unknown>", | ||
} | ||
la, err := s.GetLoadAverage() | ||
if err != nil { | ||
err = la.Get() // retry | ||
} | ||
|
||
if err == nil { | ||
maxLA := float64(runtime.NumCPU() + 2) | ||
currentCheck.LA = laJSON(la) | ||
diffOne := maxLA - la.One | ||
diffFive := maxLA - la.Five | ||
diffFifteen := maxLA - la.Fifteen | ||
|
||
alertTrigger := float64(-3) | ||
warnTrigger := float64(0) | ||
|
||
if diffOne < alertTrigger || diffFive < alertTrigger || diffFifteen < alertTrigger { | ||
currentCheck.LoadStatus = "alert" | ||
} else if diffOne < warnTrigger || diffFive < warnTrigger || diffFifteen < warnTrigger { | ||
currentCheck.LoadStatus = "warn" | ||
} else { | ||
currentCheck.LoadStatus = "ok" | ||
} | ||
} | ||
|
||
uptime := sigar.Uptime{} | ||
err = uptime.Get() | ||
if err != nil { | ||
err = uptime.Get() // retry | ||
} | ||
if err == nil { | ||
currentCheck.Uptime = strings.TrimSpace(uptime.Format()) | ||
} | ||
|
||
if len(collectors) > 0 { | ||
currentCheck.Custom = make(map[string]interface{}) | ||
} | ||
for _, cb := range collectors { | ||
if cb != nil { | ||
key, stats := cb() | ||
currentCheck.Custom[key] = stats | ||
} | ||
} | ||
return currentCheck | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
package gfmt | ||
|
||
import "fmt" | ||
|
||
// Si formats a number in a short si format | ||
func Si(n uint64) string { | ||
suff := siRaw | ||
x := float64(n) | ||
for ; x >= 1024; x = x / 1024 { | ||
suff++ | ||
} | ||
|
||
return fmt.Sprintf("%.2f%s", x, suff.String()) | ||
} | ||
|
||
type siSuff uint | ||
|
||
const ( | ||
siRaw siSuff = iota | ||
siKilo | ||
siMega | ||
siGiga | ||
siTera | ||
) | ||
|
||
func (s siSuff) String() string { | ||
switch s { | ||
case siRaw: | ||
return "" | ||
case siKilo: | ||
return "K" | ||
case siMega: | ||
return "M" | ||
case siGiga: | ||
return "G" | ||
case siTera: | ||
return "T" | ||
default: | ||
return "T" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters