From 84501beb2330b53c29b1d15b2d7de6ddd2d96d69 Mon Sep 17 00:00:00 2001 From: Luther Wen Xu Date: Thu, 23 Apr 2020 21:44:23 +0800 Subject: [PATCH] server: Implement /api/history/week --- server/api.go | 14 ++++++++++++++ server/cache.go | 49 ++++++++++++++++++++++++++++++++++++++++++------ server/data.go | 31 ++++++++++++++++++++++++++++++ server/server.go | 1 + 4 files changed, 89 insertions(+), 6 deletions(-) create mode 100644 server/data.go diff --git a/server/api.go b/server/api.go index 0c4c735..04c794f 100644 --- a/server/api.go +++ b/server/api.go @@ -39,3 +39,17 @@ func dayHistory(w http.ResponseWriter, req *http.Request) { entries := db.GetFromDB(keys[0], time.Now().Add(time.Duration(-24)*time.Hour), time.Now()) writeJSON(w, entries) } + +func weekHistory(w http.ResponseWriter, req *http.Request) { + keys, ok := req.URL.Query()["service_name"] + if !ok || len(keys) == 0 || len(keys[0]) < 1 { + http.Error(w, "`service_name` not provided", http.StatusBadRequest) + return + } + if len(keys) >= 2 { + http.Error(w, "Only one `service_name` allowed", http.StatusBadRequest) + return + } + entries := getWeek(keys[0]) + writeJSON(w, entries) +} diff --git a/server/cache.go b/server/cache.go index 84661db..2e02a16 100644 --- a/server/cache.go +++ b/server/cache.go @@ -3,17 +3,54 @@ package server import ( "time" + "status/check" "status/db" ) -func getStatus() map[string]db.PingEntry { - entries := db.GetFromDB("", time.Now().Add(time.Duration(-2)*time.Minute), time.Now()) - result := make(map[string]db.PingEntry) +type stat struct { + StartTime time.Time `json:"start_time"` + TotalPing int64 `json:"total_ping"` + SampleCount int `json:"sample_count"` + SuccessCount int `json:"success_count"` + FailCount int `json:"fail_count"` + Summary check.Result `json:"summary"` +} + +var dayAggregation map[string]map[time.Time]stat + +func convertToResult(successCount, totalCount int) check.Result { + if successCount >= totalCount*99/100 { + return check.Online + } + if successCount >= totalCount*9/10 { + return check.Unstable + } + return check.Offline +} + +func getDay(serviceName string, day time.Time) stat { + if cached, ok := dayAggregation[serviceName][day]; ok { + return cached + } + entries := db.GetFromDB(serviceName, day.AddDate(0, 0, -1), day) + result := stat{ + StartTime: day, + } for _, v := range entries { - if v.Time.Before(result[v.ServiceName].Time) { - continue + result.SampleCount++ + result.TotalPing += v.Ping + switch v.Status { + case check.Online: + result.SuccessCount++ + case check.Offline: + result.FailCount++ } - result[v.ServiceName] = v } + result.Summary = convertToResult(result.SuccessCount, result.SampleCount) return result } + +func today() time.Time { + now := time.Now() + return time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.UTC) +} diff --git a/server/data.go b/server/data.go new file mode 100644 index 0000000..9d877e1 --- /dev/null +++ b/server/data.go @@ -0,0 +1,31 @@ +package server + +import ( + "time" + + "status/db" +) + +func getStatus() map[string]db.PingEntry { + entries := db.GetFromDB("", time.Now().Add(time.Duration(-2)*time.Minute), time.Now()) + result := make(map[string]db.PingEntry) + for _, v := range entries { + if v.Time.Before(result[v.ServiceName].Time) { + continue + } + result[v.ServiceName] = v + } + return result +} + +func getWeek(serviceName string) []stat { + currentDay := today() + result := make([]stat, 0) + for i := -6; i <= 0; i++ { + dayData := getDay(serviceName, currentDay.AddDate(0, 0, i)) + if dayData.SampleCount > 0 { + result = append(result, dayData) + } + } + return result +} diff --git a/server/server.go b/server/server.go index c08b938..8da3b9b 100644 --- a/server/server.go +++ b/server/server.go @@ -9,6 +9,7 @@ import ( func apiEndpoints() { http.HandleFunc("/api/latest", allStatus) http.HandleFunc("/api/history/day", dayHistory) + http.HandleFunc("/api/history/week", weekHistory) } func StartServer(port int) {