github.com/dbernstein1/tyk@v2.9.0-beta9-dl-apic+incompatible/gateway/api_healthcheck.go (about) 1 package gateway 2 3 import ( 4 "strconv" 5 "strings" 6 "time" 7 8 "github.com/TykTechnologies/tyk/config" 9 "github.com/TykTechnologies/tyk/storage" 10 ) 11 12 type HealthPrefix string 13 14 const ( 15 Throttle HealthPrefix = "Throttle" 16 QuotaViolation HealthPrefix = "QuotaViolation" 17 KeyFailure HealthPrefix = "KeyFailure" 18 RequestLog HealthPrefix = "Request" 19 BlockedRequestLog HealthPrefix = "BlockedRequest" 20 ) 21 22 type HealthChecker interface { 23 Init(storage.Handler) 24 ApiHealthValues() (HealthCheckValues, error) 25 StoreCounterVal(HealthPrefix, string) 26 } 27 28 type HealthCheckValues struct { 29 ThrottledRequestsPS float64 `bson:"throttle_reqests_per_second,omitempty" json:"throttle_reqests_per_second"` 30 QuotaViolationsPS float64 `bson:"quota_violations_per_second,omitempty" json:"quota_violations_per_second"` 31 KeyFailuresPS float64 `bson:"key_failures_per_second,omitempty" json:"key_failures_per_second"` 32 AvgUpstreamLatency float64 `bson:"average_upstream_latency,omitempty" json:"average_upstream_latency"` 33 AvgRequestsPS float64 `bson:"average_requests_per_second,omitempty" json:"average_requests_per_second"` 34 } 35 36 type DefaultHealthChecker struct { 37 storage storage.Handler 38 APIID string 39 } 40 41 func (h *DefaultHealthChecker) Init(storeType storage.Handler) { 42 if !config.Global().HealthCheck.EnableHealthChecks { 43 return 44 } 45 46 log.Info("Initializing HealthChecker") 47 h.storage = storeType 48 h.storage.Connect() 49 } 50 51 func (h *DefaultHealthChecker) CreateKeyName(subKey HealthPrefix) string { 52 // Key should be API-ID.SubKey.123456789 53 return h.APIID + "." + string(subKey) 54 } 55 56 // reportHealthValue is a shortcut we can use throughout the app to push a health check value 57 func reportHealthValue(spec *APISpec, counter HealthPrefix, value string) { 58 if !spec.GlobalConfig.HealthCheck.EnableHealthChecks { 59 return 60 } 61 62 spec.Health.StoreCounterVal(counter, value) 63 } 64 65 func (h *DefaultHealthChecker) StoreCounterVal(counterType HealthPrefix, value string) { 66 searchStr := h.CreateKeyName(counterType) 67 log.Debug("Adding Healthcheck to: ", searchStr) 68 log.Debug("Val is: ", value) 69 //go h.storage.SetKey(searchStr, value, config.Global.HealthCheck.HealthCheckValueTimeout) 70 if value != "-1" { 71 // need to ensure uniqueness 72 now_string := strconv.Itoa(int(time.Now().UnixNano())) 73 value = now_string + "." + value 74 log.Debug("Set value to: ", value) 75 } 76 go h.storage.SetRollingWindow(searchStr, config.Global().HealthCheck.HealthCheckValueTimeout, value, false) 77 } 78 79 func (h *DefaultHealthChecker) getAvgCount(prefix HealthPrefix) float64 { 80 searchStr := h.CreateKeyName(prefix) 81 log.Debug("Searching for: ", searchStr) 82 83 count, _ := h.storage.SetRollingWindow(searchStr, config.Global().HealthCheck.HealthCheckValueTimeout, "-1", false) 84 log.Debug("Count is: ", count) 85 divisor := float64(config.Global().HealthCheck.HealthCheckValueTimeout) 86 if divisor == 0 { 87 log.Warning("The Health Check sample timeout is set to 0, samples will never be deleted!!!") 88 divisor = 60.0 89 } 90 if count > 0 { 91 return roundValue((float64(count) - 1) / divisor) 92 } 93 94 return 0.00 95 } 96 97 func roundValue(untruncated float64) float64 { 98 return float64(int(untruncated*100)) / 100 99 } 100 101 func (h *DefaultHealthChecker) ApiHealthValues() (HealthCheckValues, error) { 102 values := HealthCheckValues{} 103 104 // Get the counted / average values 105 values.ThrottledRequestsPS = h.getAvgCount(Throttle) 106 values.QuotaViolationsPS = h.getAvgCount(QuotaViolation) 107 values.KeyFailuresPS = h.getAvgCount(KeyFailure) 108 values.AvgRequestsPS = h.getAvgCount(RequestLog) 109 110 // Get the micro latency graph, an average upstream latency 111 searchStr := h.APIID + "." + string(RequestLog) 112 log.Debug("Searching KV for: ", searchStr) 113 _, vals := h.storage.SetRollingWindow(searchStr, config.Global().HealthCheck.HealthCheckValueTimeout, "-1", false) 114 log.Debug("Found: ", vals) 115 if len(vals) == 0 { 116 return values, nil 117 } 118 var runningTotal int 119 for _, v := range vals { 120 s := string(v.([]byte)) 121 log.Debug("V is: ", s) 122 splitValues := strings.Split(s, ".") 123 if len(splitValues) > 1 { 124 vInt, err := strconv.Atoi(splitValues[1]) 125 if err != nil { 126 log.Error("Couldn't convert tracked latency value to Int, vl is: ", err) 127 } else { 128 runningTotal += vInt 129 } 130 } 131 132 } 133 values.AvgUpstreamLatency = roundValue(float64(runningTotal / len(vals))) 134 return values, nil 135 }