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:
		
							
								
								
									
										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,7 +73,8 @@ 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 { | ||||||
|  | 	return func(writer http.ResponseWriter, request *http.Request) { | ||||||
| 		variables := mux.Vars(request) | 		variables := mux.Vars(request) | ||||||
| 		duration := variables["duration"] | 		duration := variables["duration"] | ||||||
| 		var from time.Time | 		var from time.Time | ||||||
| @ -99,7 +105,8 @@ func ResponseTimeBadge(writer http.ResponseWriter, request *http.Request) { | |||||||
| 		writer.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate") | 		writer.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate") | ||||||
| 		writer.Header().Set("Expires", "0") | 		writer.Header().Set("Expires", "0") | ||||||
| 		writer.WriteHeader(http.StatusOK) | 		writer.WriteHeader(http.StatusOK) | ||||||
| 	_, _ = writer.Write(generateResponseTimeBadgeSVG(duration, averageResponseTime)) | 		_, _ = writer.Write(generateResponseTimeBadgeSVG(duration, averageResponseTime, key, config)) | ||||||
|  | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| // 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 | ||||||
| @ -8,6 +10,35 @@ type Config struct { | |||||||
| 	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}, | ||||||
|  | 			}, | ||||||
|  | 		}, | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user