mirror of
https://github.com/TwiN/gatus.git
synced 2024-10-05 01:32:25 +02:00
feat(api): Configurable response time badge thresholds (#309)
* recreated all changes for setting thresholds on Uptime Badges * Suggestion accepted: Update core/ui/ui.go Co-authored-by: TwiN <twin@linux.com> * Suggestion accepted: Update core/ui/ui.go Co-authored-by: TwiN <twin@linux.com> * implemented final suggestions by Twin * Update controller/handler/badge.go * Update README.md * test: added the suggestons to set the UiConfig at another line Co-authored-by: TwiN <twin@linux.com>
This commit is contained in:
parent
1aa94a3365
commit
1bce4e727e
19
README.md
19
README.md
@ -178,6 +178,7 @@ If you want to test it locally, see [Docker](#docker).
|
|||||||
| `endpoints[].ui.hide-hostname` | Whether to hide the hostname in the result. | `false` |
|
| `endpoints[].ui.hide-hostname` | Whether to hide the hostname in the result. | `false` |
|
||||||
| `endpoints[].ui.hide-url` | Whether to ensure the URL is not displayed in the results. Useful if the URL contains a token. | `false` |
|
| `endpoints[].ui.hide-url` | Whether to ensure the URL is not displayed in the results. Useful if the URL contains a token. | `false` |
|
||||||
| `endpoints[].ui.dont-resolve-failed-conditions` | Whether to resolve failed conditions for the UI. | `false` |
|
| `endpoints[].ui.dont-resolve-failed-conditions` | Whether to resolve failed conditions for the UI. | `false` |
|
||||||
|
| `endpoints[].ui.badge.reponse-time` | List of response time thresholds. Each time a threshold is reached, the badge has a different color. | `[50, 200, 300, 500, 750]` |
|
||||||
| `alerting` | [Alerting configuration](#alerting). | `{}` |
|
| `alerting` | [Alerting configuration](#alerting). | `{}` |
|
||||||
| `security` | [Security configuration](#security). | `{}` |
|
| `security` | [Security configuration](#security). | `{}` |
|
||||||
| `disable-monitoring-lock` | Whether to [disable the monitoring lock](#disable-monitoring-lock). | `false` |
|
| `disable-monitoring-lock` | Whether to [disable the monitoring lock](#disable-monitoring-lock). | `false` |
|
||||||
@ -1469,6 +1470,24 @@ Where:
|
|||||||
- `{duration}` is `7d`, `24h` or `1h`
|
- `{duration}` is `7d`, `24h` or `1h`
|
||||||
- `{key}` has the pattern `<GROUP_NAME>_<ENDPOINT_NAME>` in which both variables have ` `, `/`, `_`, `,` and `.` replaced by `-`.
|
- `{key}` has the pattern `<GROUP_NAME>_<ENDPOINT_NAME>` in which both variables have ` `, `/`, `_`, `,` and `.` replaced by `-`.
|
||||||
|
|
||||||
|
##### How to change the color thresholds of the response time badge
|
||||||
|
To change the response time badges threshold, a corresponding configuration can be added to an endpoint.
|
||||||
|
The values in the array correspond to the levels [Awesome, Great, Good, Passable, Bad]
|
||||||
|
All five values must be given in milliseconds (ms).
|
||||||
|
|
||||||
|
```
|
||||||
|
endpoints:
|
||||||
|
- name: nas
|
||||||
|
group: internal
|
||||||
|
url: "https://example.org/"
|
||||||
|
interval: 5m
|
||||||
|
conditions:
|
||||||
|
- "[STATUS] == 200"
|
||||||
|
ui:
|
||||||
|
badge:
|
||||||
|
response-time:
|
||||||
|
thresholds: [550, 850, 1350, 1650, 1750]
|
||||||
|
```
|
||||||
|
|
||||||
### API
|
### API
|
||||||
Gatus provides a simple read-only API that can be queried in order to programmatically determine endpoint status and history.
|
Gatus provides a simple read-only API that can be queried in order to programmatically determine endpoint status and history.
|
||||||
|
@ -16,6 +16,7 @@ import (
|
|||||||
"github.com/TwiN/gatus/v4/core"
|
"github.com/TwiN/gatus/v4/core"
|
||||||
"github.com/TwiN/gatus/v4/security"
|
"github.com/TwiN/gatus/v4/security"
|
||||||
"github.com/TwiN/gatus/v4/storage"
|
"github.com/TwiN/gatus/v4/storage"
|
||||||
|
"github.com/TwiN/gatus/v4/util"
|
||||||
"gopkg.in/yaml.v2"
|
"gopkg.in/yaml.v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -94,6 +95,16 @@ type Config struct {
|
|||||||
lastFileModTime time.Time // last modification time
|
lastFileModTime time.Time // last modification time
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (config *Config) GetEndpointByKey(key string) *core.Endpoint {
|
||||||
|
for i := 0; i < len(config.Endpoints); i++ {
|
||||||
|
ep := config.Endpoints[i]
|
||||||
|
if util.ConvertGroupAndEndpointNameToKey(ep.Group, ep.Name) == key {
|
||||||
|
return ep
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// HasLoadedConfigurationFileBeenModified returns whether the file that the
|
// HasLoadedConfigurationFileBeenModified returns whether the file that the
|
||||||
// configuration has been loaded from has been modified since it was last read
|
// configuration has been loaded from has been modified since it was last read
|
||||||
func (config Config) HasLoadedConfigurationFileBeenModified() bool {
|
func (config Config) HasLoadedConfigurationFileBeenModified() bool {
|
||||||
|
@ -7,6 +7,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/TwiN/gatus/v4/config"
|
||||||
"github.com/TwiN/gatus/v4/storage/store"
|
"github.com/TwiN/gatus/v4/storage/store"
|
||||||
"github.com/TwiN/gatus/v4/storage/store/common"
|
"github.com/TwiN/gatus/v4/storage/store/common"
|
||||||
"github.com/TwiN/gatus/v4/storage/store/common/paging"
|
"github.com/TwiN/gatus/v4/storage/store/common/paging"
|
||||||
@ -28,6 +29,10 @@ const (
|
|||||||
HealthStatusUnknown = "?"
|
HealthStatusUnknown = "?"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
badgeColors = []string{badgeColorHexAwesome, badgeColorHexGreat, badgeColorHexGood, badgeColorHexPassable, badgeColorHexBad}
|
||||||
|
)
|
||||||
|
|
||||||
// UptimeBadge handles the automatic generation of badge based on the group name and endpoint name passed.
|
// UptimeBadge handles the automatic generation of badge based on the group name and endpoint name passed.
|
||||||
//
|
//
|
||||||
// Valid values for {duration}: 7d, 24h, 1h
|
// Valid values for {duration}: 7d, 24h, 1h
|
||||||
@ -68,38 +73,40 @@ func UptimeBadge(writer http.ResponseWriter, request *http.Request) {
|
|||||||
// ResponseTimeBadge handles the automatic generation of badge based on the group name and endpoint name passed.
|
// ResponseTimeBadge handles the automatic generation of badge based on the group name and endpoint name passed.
|
||||||
//
|
//
|
||||||
// Valid values for {duration}: 7d, 24h, 1h
|
// Valid values for {duration}: 7d, 24h, 1h
|
||||||
func ResponseTimeBadge(writer http.ResponseWriter, request *http.Request) {
|
func ResponseTimeBadge(config *config.Config) http.HandlerFunc {
|
||||||
variables := mux.Vars(request)
|
return func(writer http.ResponseWriter, request *http.Request) {
|
||||||
duration := variables["duration"]
|
variables := mux.Vars(request)
|
||||||
var from time.Time
|
duration := variables["duration"]
|
||||||
switch duration {
|
var from time.Time
|
||||||
case "7d":
|
switch duration {
|
||||||
from = time.Now().Add(-7 * 24 * time.Hour)
|
case "7d":
|
||||||
case "24h":
|
from = time.Now().Add(-7 * 24 * time.Hour)
|
||||||
from = time.Now().Add(-24 * time.Hour)
|
case "24h":
|
||||||
case "1h":
|
from = time.Now().Add(-24 * time.Hour)
|
||||||
from = time.Now().Add(-2 * time.Hour) // Because response time metrics are stored by hour, we have to cheat a little
|
case "1h":
|
||||||
default:
|
from = time.Now().Add(-2 * time.Hour) // Because response time metrics are stored by hour, we have to cheat a little
|
||||||
http.Error(writer, "Durations supported: 7d, 24h, 1h", http.StatusBadRequest)
|
default:
|
||||||
return
|
http.Error(writer, "Durations supported: 7d, 24h, 1h", http.StatusBadRequest)
|
||||||
}
|
return
|
||||||
key := variables["key"]
|
|
||||||
averageResponseTime, err := store.Get().GetAverageResponseTimeByKey(key, from, time.Now())
|
|
||||||
if err != nil {
|
|
||||||
if err == common.ErrEndpointNotFound {
|
|
||||||
http.Error(writer, err.Error(), http.StatusNotFound)
|
|
||||||
} else if err == common.ErrInvalidTimeRange {
|
|
||||||
http.Error(writer, err.Error(), http.StatusBadRequest)
|
|
||||||
} else {
|
|
||||||
http.Error(writer, err.Error(), http.StatusInternalServerError)
|
|
||||||
}
|
}
|
||||||
return
|
key := variables["key"]
|
||||||
|
averageResponseTime, err := store.Get().GetAverageResponseTimeByKey(key, from, time.Now())
|
||||||
|
if err != nil {
|
||||||
|
if err == common.ErrEndpointNotFound {
|
||||||
|
http.Error(writer, err.Error(), http.StatusNotFound)
|
||||||
|
} else if err == common.ErrInvalidTimeRange {
|
||||||
|
http.Error(writer, err.Error(), http.StatusBadRequest)
|
||||||
|
} else {
|
||||||
|
http.Error(writer, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
writer.Header().Set("Content-Type", "image/svg+xml")
|
||||||
|
writer.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
|
||||||
|
writer.Header().Set("Expires", "0")
|
||||||
|
writer.WriteHeader(http.StatusOK)
|
||||||
|
_, _ = writer.Write(generateResponseTimeBadgeSVG(duration, averageResponseTime, key, config))
|
||||||
}
|
}
|
||||||
writer.Header().Set("Content-Type", "image/svg+xml")
|
|
||||||
writer.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
|
|
||||||
writer.Header().Set("Expires", "0")
|
|
||||||
writer.WriteHeader(http.StatusOK)
|
|
||||||
_, _ = writer.Write(generateResponseTimeBadgeSVG(duration, averageResponseTime))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// HealthBadge handles the automatic generation of badge based on the group name and endpoint name passed.
|
// HealthBadge handles the automatic generation of badge based on the group name and endpoint name passed.
|
||||||
@ -199,7 +206,7 @@ func getBadgeColorFromUptime(uptime float64) string {
|
|||||||
return badgeColorHexVeryBad
|
return badgeColorHexVeryBad
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateResponseTimeBadgeSVG(duration string, averageResponseTime int) []byte {
|
func generateResponseTimeBadgeSVG(duration string, averageResponseTime int, key string, cfg *config.Config) []byte {
|
||||||
var labelWidth, valueWidth int
|
var labelWidth, valueWidth int
|
||||||
switch duration {
|
switch duration {
|
||||||
case "7d":
|
case "7d":
|
||||||
@ -210,7 +217,7 @@ func generateResponseTimeBadgeSVG(duration string, averageResponseTime int) []by
|
|||||||
labelWidth = 105
|
labelWidth = 105
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
color := getBadgeColorFromResponseTime(averageResponseTime)
|
color := getBadgeColorFromResponseTime(averageResponseTime, key, cfg)
|
||||||
sanitizedValue := strconv.Itoa(averageResponseTime) + "ms"
|
sanitizedValue := strconv.Itoa(averageResponseTime) + "ms"
|
||||||
valueWidth = len(sanitizedValue) * 11
|
valueWidth = len(sanitizedValue) * 11
|
||||||
width := labelWidth + valueWidth
|
width := labelWidth + valueWidth
|
||||||
@ -247,17 +254,13 @@ func generateResponseTimeBadgeSVG(duration string, averageResponseTime int) []by
|
|||||||
return svg
|
return svg
|
||||||
}
|
}
|
||||||
|
|
||||||
func getBadgeColorFromResponseTime(responseTime int) string {
|
func getBadgeColorFromResponseTime(responseTime int, key string, cfg *config.Config) string {
|
||||||
if responseTime <= 50 {
|
endpoint := cfg.GetEndpointByKey(key)
|
||||||
return badgeColorHexAwesome
|
// the threshold config requires 5 values, so we can be sure it's set here
|
||||||
} else if responseTime <= 200 {
|
for i := 0; i < 5; i++ {
|
||||||
return badgeColorHexGreat
|
if responseTime <= endpoint.UIConfig.Badge.ResponseTime.Thresholds[i] {
|
||||||
} else if responseTime <= 300 {
|
return badgeColors[i]
|
||||||
return badgeColorHexGood
|
}
|
||||||
} else if responseTime <= 500 {
|
|
||||||
return badgeColorHexPassable
|
|
||||||
} else if responseTime <= 750 {
|
|
||||||
return badgeColorHexBad
|
|
||||||
}
|
}
|
||||||
return badgeColorHexVeryBad
|
return badgeColorHexVeryBad
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ import (
|
|||||||
|
|
||||||
"github.com/TwiN/gatus/v4/config"
|
"github.com/TwiN/gatus/v4/config"
|
||||||
"github.com/TwiN/gatus/v4/core"
|
"github.com/TwiN/gatus/v4/core"
|
||||||
|
"github.com/TwiN/gatus/v4/core/ui"
|
||||||
"github.com/TwiN/gatus/v4/storage/store"
|
"github.com/TwiN/gatus/v4/storage/store"
|
||||||
"github.com/TwiN/gatus/v4/watchdog"
|
"github.com/TwiN/gatus/v4/watchdog"
|
||||||
)
|
)
|
||||||
@ -29,6 +30,36 @@ func TestBadge(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
testSuccessfulResult = core.Result{
|
||||||
|
Hostname: "example.org",
|
||||||
|
IP: "127.0.0.1",
|
||||||
|
HTTPStatus: 200,
|
||||||
|
Errors: nil,
|
||||||
|
Connected: true,
|
||||||
|
Success: true,
|
||||||
|
Timestamp: timestamp,
|
||||||
|
Duration: 150 * time.Millisecond,
|
||||||
|
CertificateExpiration: 10 * time.Hour,
|
||||||
|
ConditionResults: []*core.ConditionResult{
|
||||||
|
{
|
||||||
|
Condition: "[STATUS] == 200",
|
||||||
|
Success: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Condition: "[RESPONSE_TIME] < 500",
|
||||||
|
Success: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Condition: "[CERTIFICATE_EXPIRATION] < 72h",
|
||||||
|
Success: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg.Endpoints[0].UIConfig = ui.GetDefaultConfig()
|
||||||
|
cfg.Endpoints[1].UIConfig = ui.GetDefaultConfig()
|
||||||
|
|
||||||
watchdog.UpdateEndpointStatuses(cfg.Endpoints[0], &core.Result{Success: true, Connected: true, Duration: time.Millisecond, Timestamp: time.Now()})
|
watchdog.UpdateEndpointStatuses(cfg.Endpoints[0], &core.Result{Success: true, Connected: true, Duration: time.Millisecond, Timestamp: time.Now()})
|
||||||
watchdog.UpdateEndpointStatuses(cfg.Endpoints[1], &core.Result{Success: false, Connected: false, Duration: time.Second, Timestamp: time.Now()})
|
watchdog.UpdateEndpointStatuses(cfg.Endpoints[1], &core.Result{Success: false, Connected: false, Duration: time.Second, Timestamp: time.Now()})
|
||||||
router := CreateRouter("../../web/static", cfg)
|
router := CreateRouter("../../web/static", cfg)
|
||||||
@ -180,7 +211,61 @@ func TestGetBadgeColorFromUptime(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
firstCondition = core.Condition("[STATUS] == 200")
|
||||||
|
secondCondition = core.Condition("[RESPONSE_TIME] < 500")
|
||||||
|
thirdCondition = core.Condition("[CERTIFICATE_EXPIRATION] < 72h")
|
||||||
|
)
|
||||||
|
|
||||||
func TestGetBadgeColorFromResponseTime(t *testing.T) {
|
func TestGetBadgeColorFromResponseTime(t *testing.T) {
|
||||||
|
defer store.Get().Clear()
|
||||||
|
defer cache.Clear()
|
||||||
|
|
||||||
|
testEndpoint = core.Endpoint{
|
||||||
|
Name: "name",
|
||||||
|
Group: "group",
|
||||||
|
URL: "https://example.org/what/ever",
|
||||||
|
Method: "GET",
|
||||||
|
Body: "body",
|
||||||
|
Interval: 30 * time.Second,
|
||||||
|
Conditions: []core.Condition{firstCondition, secondCondition, thirdCondition},
|
||||||
|
Alerts: nil,
|
||||||
|
NumberOfFailuresInARow: 0,
|
||||||
|
NumberOfSuccessesInARow: 0,
|
||||||
|
UIConfig: ui.GetDefaultConfig(),
|
||||||
|
}
|
||||||
|
testSuccessfulResult = core.Result{
|
||||||
|
Hostname: "example.org",
|
||||||
|
IP: "127.0.0.1",
|
||||||
|
HTTPStatus: 200,
|
||||||
|
Errors: nil,
|
||||||
|
Connected: true,
|
||||||
|
Success: true,
|
||||||
|
Timestamp: timestamp,
|
||||||
|
Duration: 150 * time.Millisecond,
|
||||||
|
CertificateExpiration: 10 * time.Hour,
|
||||||
|
ConditionResults: []*core.ConditionResult{
|
||||||
|
{
|
||||||
|
Condition: "[STATUS] == 200",
|
||||||
|
Success: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Condition: "[RESPONSE_TIME] < 500",
|
||||||
|
Success: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Condition: "[CERTIFICATE_EXPIRATION] < 72h",
|
||||||
|
Success: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
cfg := &config.Config{
|
||||||
|
Metrics: true,
|
||||||
|
Endpoints: []*core.Endpoint{&testEndpoint},
|
||||||
|
}
|
||||||
|
|
||||||
|
store.Get().Insert(&testEndpoint, &testSuccessfulResult)
|
||||||
|
|
||||||
scenarios := []struct {
|
scenarios := []struct {
|
||||||
ResponseTime int
|
ResponseTime int
|
||||||
ExpectedColor string
|
ExpectedColor string
|
||||||
@ -228,8 +313,8 @@ func TestGetBadgeColorFromResponseTime(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for _, scenario := range scenarios {
|
for _, scenario := range scenarios {
|
||||||
t.Run("response-time-"+strconv.Itoa(scenario.ResponseTime), func(t *testing.T) {
|
t.Run("response-time-"+strconv.Itoa(scenario.ResponseTime), func(t *testing.T) {
|
||||||
if getBadgeColorFromResponseTime(scenario.ResponseTime) != scenario.ExpectedColor {
|
if getBadgeColorFromResponseTime(scenario.ResponseTime, "group_name", cfg) != scenario.ExpectedColor {
|
||||||
t.Errorf("expected %s from %d, got %v", scenario.ExpectedColor, scenario.ResponseTime, getBadgeColorFromResponseTime(scenario.ResponseTime))
|
t.Errorf("expected %s from %d, got %v", scenario.ExpectedColor, scenario.ResponseTime, getBadgeColorFromResponseTime(scenario.ResponseTime, "group_name", cfg))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,7 @@ func CreateRouter(staticFolder string, cfg *config.Config) *mux.Router {
|
|||||||
protected.HandleFunc("/v1/endpoints/{key}/statuses", GzipHandlerFunc(EndpointStatus)).Methods("GET")
|
protected.HandleFunc("/v1/endpoints/{key}/statuses", GzipHandlerFunc(EndpointStatus)).Methods("GET")
|
||||||
unprotected.HandleFunc("/v1/endpoints/{key}/health/badge.svg", HealthBadge).Methods("GET")
|
unprotected.HandleFunc("/v1/endpoints/{key}/health/badge.svg", HealthBadge).Methods("GET")
|
||||||
unprotected.HandleFunc("/v1/endpoints/{key}/uptimes/{duration}/badge.svg", UptimeBadge).Methods("GET")
|
unprotected.HandleFunc("/v1/endpoints/{key}/uptimes/{duration}/badge.svg", UptimeBadge).Methods("GET")
|
||||||
unprotected.HandleFunc("/v1/endpoints/{key}/response-times/{duration}/badge.svg", ResponseTimeBadge).Methods("GET")
|
unprotected.HandleFunc("/v1/endpoints/{key}/response-times/{duration}/badge.svg", ResponseTimeBadge(cfg)).Methods("GET")
|
||||||
unprotected.HandleFunc("/v1/endpoints/{key}/response-times/{duration}/chart.svg", ResponseTimeChart).Methods("GET")
|
unprotected.HandleFunc("/v1/endpoints/{key}/response-times/{duration}/chart.svg", ResponseTimeChart).Methods("GET")
|
||||||
// Misc
|
// Misc
|
||||||
router.Handle("/health", health.Handler().WithJSON(true)).Methods("GET")
|
router.Handle("/health", health.Handler().WithJSON(true)).Methods("GET")
|
||||||
|
@ -145,6 +145,10 @@ func (endpoint *Endpoint) ValidateAndSetDefaults() error {
|
|||||||
}
|
}
|
||||||
if endpoint.UIConfig == nil {
|
if endpoint.UIConfig == nil {
|
||||||
endpoint.UIConfig = ui.GetDefaultConfig()
|
endpoint.UIConfig = ui.GetDefaultConfig()
|
||||||
|
} else {
|
||||||
|
if err := endpoint.UIConfig.ValidateAndSetDefaults(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if endpoint.Interval == 0 {
|
if endpoint.Interval == 0 {
|
||||||
endpoint.Interval = 1 * time.Minute
|
endpoint.Interval = 1 * time.Minute
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package ui
|
package ui
|
||||||
|
|
||||||
|
import "errors"
|
||||||
|
|
||||||
// Config is the UI configuration for core.Endpoint
|
// Config is the UI configuration for core.Endpoint
|
||||||
type Config struct {
|
type Config struct {
|
||||||
// HideHostname whether to hide the hostname in the Result
|
// HideHostname whether to hide the hostname in the Result
|
||||||
@ -7,7 +9,36 @@ type Config struct {
|
|||||||
// HideURL whether to ensure the URL is not displayed in the results. Useful if the URL contains a token.
|
// HideURL whether to ensure the URL is not displayed in the results. Useful if the URL contains a token.
|
||||||
HideURL bool `yaml:"hide-url"`
|
HideURL bool `yaml:"hide-url"`
|
||||||
// DontResolveFailedConditions whether to resolve failed conditions in the Result for display in the UI
|
// DontResolveFailedConditions whether to resolve failed conditions in the Result for display in the UI
|
||||||
DontResolveFailedConditions bool `yaml:"dont-resolve-failed-conditions"`
|
DontResolveFailedConditions bool `yaml:"dont-resolve-failed-conditions"`
|
||||||
|
// Badge is the configuration for the badges generated
|
||||||
|
Badge *Badge `yaml:"badge"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Badge struct {
|
||||||
|
ResponseTime *ResponseTime `yaml:"response-time"`
|
||||||
|
}
|
||||||
|
type ResponseTime struct {
|
||||||
|
Thresholds []int `yaml:"thresholds"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrInvalidBadgeResponseTimeConfig = errors.New("invalid response time badge configuration: expected parameter 'response-time' to have 5 ascending numerical values")
|
||||||
|
)
|
||||||
|
|
||||||
|
func (config *Config) ValidateAndSetDefaults() error {
|
||||||
|
if config.Badge != nil {
|
||||||
|
if len(config.Badge.ResponseTime.Thresholds) != 5 {
|
||||||
|
return ErrInvalidBadgeResponseTimeConfig
|
||||||
|
}
|
||||||
|
for i := 4; i > 0; i-- {
|
||||||
|
if config.Badge.ResponseTime.Thresholds[i] < config.Badge.ResponseTime.Thresholds[i-1] {
|
||||||
|
return ErrInvalidBadgeResponseTimeConfig
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
config.Badge = GetDefaultConfig().Badge
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDefaultConfig retrieves the default UI configuration
|
// GetDefaultConfig retrieves the default UI configuration
|
||||||
@ -16,5 +47,10 @@ func GetDefaultConfig() *Config {
|
|||||||
HideHostname: false,
|
HideHostname: false,
|
||||||
HideURL: false,
|
HideURL: false,
|
||||||
DontResolveFailedConditions: false,
|
DontResolveFailedConditions: false,
|
||||||
|
Badge: &Badge{
|
||||||
|
ResponseTime: &ResponseTime{
|
||||||
|
Thresholds: []int{50, 200, 300, 500, 750},
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user