gatus/vendor/github.com/TwiN/health/health.go

126 lines
3.1 KiB
Go
Raw Normal View History

package health
2021-11-16 02:11:13 +01:00
import (
2021-11-20 05:43:24 +01:00
"encoding/json"
2021-11-16 02:11:13 +01:00
"net/http"
"sync"
)
var (
handler = &healthHandler{
useJSON: false,
status: Up,
}
)
2022-04-11 07:39:47 +02:00
// responseBody is the body of the response returned by the health handler.
2021-11-20 05:43:24 +01:00
type responseBody struct {
Status string `json:"status"`
Reason string `json:"reason,omitempty"`
}
// healthHandler is the HTTP handler for serving the health endpoint
type healthHandler struct {
2022-04-11 07:39:47 +02:00
useJSON bool
2021-11-16 02:11:13 +01:00
2021-11-20 05:43:24 +01:00
status Status
reason string
mutex sync.RWMutex
}
// WithJSON configures whether the handler should output a response in JSON or in raw text
//
// Defaults to false
func (h *healthHandler) WithJSON(v bool) *healthHandler {
h.useJSON = v
return h
}
// ServeHTTP serves the HTTP request for the health handler
2021-11-16 02:11:13 +01:00
func (h *healthHandler) ServeHTTP(writer http.ResponseWriter, _ *http.Request) {
var statusCode int
var body []byte
2021-11-20 05:43:24 +01:00
h.mutex.RLock()
status, reason, useJSON := h.status, h.reason, h.useJSON
h.mutex.RUnlock()
if status == Up {
2021-11-16 02:11:13 +01:00
statusCode = http.StatusOK
} else {
2021-11-16 02:11:13 +01:00
statusCode = http.StatusInternalServerError
}
2021-11-20 05:43:24 +01:00
if useJSON {
// We can safely ignore the error here because we know that both values are strings, therefore are supported encoders.
body, _ = json.Marshal(responseBody{Status: string(status), Reason: reason})
writer.Header().Set("Content-Type", "application/json")
} else {
2021-11-20 05:43:24 +01:00
if len(reason) == 0 {
body = []byte(status)
} else {
body = []byte(string(status) + ": " + reason)
}
}
2021-11-16 02:11:13 +01:00
writer.WriteHeader(statusCode)
_, _ = writer.Write(body)
}
// Handler retrieves the health handler
func Handler() *healthHandler {
return handler
}
2021-11-16 02:11:13 +01:00
// GetStatus retrieves the current status returned by the health handler
func GetStatus() Status {
2021-11-20 05:43:24 +01:00
handler.mutex.RLock()
defer handler.mutex.RUnlock()
return handler.status
2021-11-16 02:11:13 +01:00
}
// SetStatus sets the status to be returned by the health handler
func SetStatus(status Status) {
2021-11-20 05:43:24 +01:00
handler.mutex.Lock()
handler.status = status
handler.mutex.Unlock()
}
// GetReason retrieves the current status returned by the health handler
func GetReason() string {
handler.mutex.RLock()
defer handler.mutex.RUnlock()
return handler.reason
}
// SetReason sets a reason for the current status to be returned by the health handler
func SetReason(reason string) {
handler.mutex.Lock()
handler.reason = reason
handler.mutex.Unlock()
}
// SetStatusAndReason sets the status and reason to be returned by the health handler
func SetStatusAndReason(status Status, reason string) {
handler.mutex.Lock()
handler.status = status
handler.reason = reason
handler.mutex.Unlock()
}
2022-04-11 07:39:47 +02:00
// SetHealthy sets the status to Up and the reason to a blank string
func SetHealthy() {
handler.mutex.Lock()
handler.status = Up
handler.reason = ""
handler.mutex.Unlock()
}
// SetUnhealthy sets the status to Down and the reason to the string passed as parameter
//
// Unlike SetHealthy, this function enforces setting a reason, because it's good practice to give at least a bit
// of information as to why an application is unhealthy, and this library attempts to promote good practices.
func SetUnhealthy(reason string) {
handler.mutex.Lock()
handler.status = Down
handler.reason = reason
handler.mutex.Unlock()
}