142 lines
3.0 KiB
Go
142 lines
3.0 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"net/http"
|
|
)
|
|
|
|
type HealthcheckShortResult struct {
|
|
ResponseTime float64 `json:"response_time"`
|
|
SuccessPercentage float64 `json:"success_percentage"`
|
|
}
|
|
|
|
func healthCheckHandler(w http.ResponseWriter, r *http.Request) {
|
|
rows, err := db.Query(`
|
|
SELECT h.public_name, r.success_percentage, r.response_time
|
|
FROM hosts h
|
|
JOIN results r ON h.id = r.host_id
|
|
ORDER BY r.timestamp DESC, r.id DESC
|
|
LIMIT 1000;
|
|
`)
|
|
if err != nil {
|
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
defer rows.Close()
|
|
|
|
results := make(map[string][]HealthcheckShortResult)
|
|
|
|
for rows.Next() {
|
|
var publicName string
|
|
var successPercentage float64
|
|
var responseTime float64
|
|
|
|
err := rows.Scan(&publicName, &successPercentage, &responseTime)
|
|
if err != nil {
|
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
if len(results[publicName]) >= 50 {
|
|
continue
|
|
}
|
|
|
|
result := HealthcheckShortResult{
|
|
ResponseTime: responseTime,
|
|
SuccessPercentage: successPercentage,
|
|
}
|
|
|
|
results[publicName] = append(results[publicName], result)
|
|
}
|
|
|
|
w.Header().Set("Content-Type", "application/json")
|
|
json.NewEncoder(w).Encode(results)
|
|
}
|
|
|
|
func statusHandler(w http.ResponseWriter, r *http.Request) {
|
|
|
|
statuses, err := getHostStatus()
|
|
if err != nil {
|
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
w.Header().Set("Content-Type", "application/json")
|
|
json.NewEncoder(w).Encode(statuses)
|
|
}
|
|
|
|
type HostStatus map[string]string
|
|
|
|
func getHostStatus() (map[string]string, error) {
|
|
resultByHost := make(map[string][]float64)
|
|
statuses := make(HostStatus)
|
|
|
|
hosts, err := db.Query(`select id, public_name from hosts`)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
for hosts.Next() {
|
|
var id int64
|
|
var publicName string
|
|
|
|
err := hosts.Scan(&id, &publicName)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
results, err := db.Query(`select success_percentage from results where host_id = $1 order by timestamp desc, id desc limit 10`, id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
for results.Next() {
|
|
var successPercentage float64
|
|
results.Scan(&successPercentage)
|
|
resultByHost[publicName] = append(resultByHost[publicName], successPercentage)
|
|
}
|
|
}
|
|
|
|
for publicName, result := range resultByHost {
|
|
total := 10
|
|
if len(result) < total {
|
|
continue
|
|
}
|
|
var sum float64 = 0.0
|
|
var halfSum float64 = 0.0
|
|
|
|
for _, value := range result[len(result)-total:] {
|
|
sum += value
|
|
}
|
|
for _, value := range result[len(result)-total/2:] {
|
|
halfSum += value
|
|
}
|
|
|
|
average := sum / float64(total)
|
|
recent := halfSum / float64(total/2)
|
|
|
|
var status string
|
|
|
|
if average > 0.95 {
|
|
status = "healthy"
|
|
} else if average > 0.6 {
|
|
if recent < 0.5 {
|
|
status = "unstable failing"
|
|
} else if recent > 0.8 {
|
|
status = "unstable recovering"
|
|
} else {
|
|
status = "unstable"
|
|
}
|
|
} else {
|
|
if recent > 0.6 {
|
|
status = "unhealthy recovering"
|
|
} else {
|
|
status = "unhealthy"
|
|
}
|
|
}
|
|
|
|
statuses[publicName] = status
|
|
}
|
|
return statuses, nil
|
|
}
|