/
server.go
137 lines (123 loc) · 4.29 KB
/
server.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
package gose4
import (
"fmt"
sigar "github.com/cloudfoundry/gosigar"
restful "github.com/emicklei/go-restful"
"net/http"
"runtime"
"time"
)
const (
SE4TimeFormat = "2006-01-02T15:04:05Z"
)
var (
//
GoodToGoFailureLevel = SeverityWarn
)
type TestResults struct {
ReportAsOf string `json:"report_as_of"` //ISO 8601 Representation
ReportDuration string `json:"report_duration"` //
Tests []TestResult `json:"tests"`
}
type TestResult struct {
DurationMillis int64 `json:"duration_millis"`
TestName string `json:"test_name"`
TestResult string `json:"rest_result"`
TestedAt string `json:"tested_at"` //ISO 8601 Representation
}
func StartHttpServer(service HealthCheckService, httpPort int) {
container := restful.NewContainer()
Infof("Starting SE4 server on port %v", httpPort)
container.Add(createRestServer(service))
httpServer := &http.Server{Addr: fmt.Sprintf(":%v", httpPort), Handler: container}
httpServer.ListenAndServe()
}
func HandlerFunc(service *healthCheckService) http.HandlerFunc {
container := restful.NewContainer()
container.Add(createRestServer(service))
return func(w http.ResponseWriter, r *http.Request) {
container.ServeHTTP(w, r)
}
}
func createGetServiceStatus() restful.RouteFunction {
// Populate static runtime status
serviceStartTime := time.Now()
numberOfCpus := runtime.NumCPU()
ServiceStatus.OsNumberProcessors = &numberOfCpus
ServiceStatus.MachineName = GetCurrentHostName()
concreteSigar := sigar.ConcreteSigar{}
ServiceStatus.OsArch = runtime.GOARCH
ServiceStatus.OsName = runtime.GOOS
ServiceStatus.OsVersion = "n/a"
return func(_ *restful.Request, response *restful.Response) {
currentTime := time.Now()
res := ServiceStatus
// Time related field
res.SetCurrentTime(¤tTime)
res.UpSince = timeToIso8601(serviceStartTime)
uptime := currentTime.Sub(serviceStartTime)
res.UpDuration = fmt.Sprintf("%v seconds", uptime.Seconds())
// Get load avg
loadAvg, _ := concreteSigar.GetLoadAverage()
loadAvgString := fmt.Sprintf("%v", loadAvg.Five)
res.OsLoad = &loadAvgString
response.WriteEntity(res)
}
}
func createGetServiceHealthCheck(healthcheckservice HealthCheckService) restful.RouteFunction {
return func(_ *restful.Request, response *restful.Response) {
result := TestResults{}
result.ReportAsOf = timeToIso8601(time.Now().UTC())
result.Tests = []TestResult{}
for check, lastResult := range healthcheckservice.GetResults() {
resultItem := TestResult{}
resultItem.DurationMillis = lastResult.DurationMillis()
resultItem.TestName = check.Configuration().Description
resultItem.TestResult = lastResult.Result.String()
resultItem.TestedAt = timeToIso8601(lastResult.LastCheck)
result.Tests = append(result.Tests, resultItem)
}
response.WriteEntity(result)
}
}
func createGoodToGo(healthcheckservice HealthCheckService) restful.RouteFunction {
return func(_ *restful.Request, response *restful.Response) {
passed := true
results := healthcheckservice.GetResults()
for check, result := range results {
if check.Configuration().Severity >= GoodToGoFailureLevel {
if result.Result == CheckFailed {
passed = false
break
}
}
}
if len(results) == 0 {
response.WriteErrorString(200, "No tests configured")
} else if passed {
response.WriteErrorString(200, "All checks passed")
} else {
response.WriteErrorString(503, fmt.Sprintf("One or more tests with severity %v failed", GoodToGoFailureLevel))
}
}
}
func registerRestEndpoints(ws *restful.WebService, se4 HealthCheckService) {
ws.Route(ws.GET("/service/status").To(createGetServiceStatus()))
ws.Route(ws.GET("/service/healthcheck").To(createGetServiceHealthCheck(se4)))
ws.Route(ws.GET("/service/healthcheck/gtg").To(createGoodToGo(se4)))
}
func createRestServer(service HealthCheckService) *restful.WebService {
webService := new(restful.WebService)
webService.Consumes(restful.MIME_JSON)
webService.Produces(restful.MIME_JSON)
webService.Filter(addPoweredByFilter)
registerRestEndpoints(webService, service)
return webService
}
func addPoweredByFilter(request *restful.Request, response *restful.Response, chain *restful.FilterChain) {
response.AddHeader("X-Generated-By", "goSE4")
chain.ProcessFilter(request, response)
}
func timeToIso8601(t time.Time) string {
return t.Format(SE4TimeFormat)
}