Implement interval + Add timestamp to Result struct

This commit is contained in:
TwinProduction 2019-09-08 21:07:08 -04:00
parent 8a7aa96b97
commit 825906145f
6 changed files with 60 additions and 33 deletions

View File

@ -3,15 +3,25 @@
A service health dashboard in Go A service health dashboard in Go
config should look something like ## Usage
```yaml ```yaml
services: services:
- name: twinnation - name: twinnation # Name of your service, can be anything
url: https://twinnation.org/actuator/health url: https://twinnation.org/actuator/health
interval: 10 interval: 15s # Duration to wait between every status check (opt. default: 10s)
failure-threshold: 3 failure-threshold: 3
conditions: conditions:
- "$STATUS == 200" - "$STATUS == 200"
- "IP == 200" - name: github
url: https://api.github.com/healthz
conditions:
- "$STATUS == 200"
```
## Running the tests
```
go test ./... -mod vendor
``` ```

View File

@ -1,7 +1,7 @@
services: services:
- name: twinnation - name: twinnation
url: https://twinnation.org/actuator/health url: https://twinnation.org/actuator/health
interval: 15 interval: 15s
failure-threshold: 3 failure-threshold: 3
conditions: conditions:
- "$STATUS == 200" - "$STATUS == 200"

View File

@ -4,6 +4,7 @@ import (
"github.com/TwinProduction/gatus/core" "github.com/TwinProduction/gatus/core"
"gopkg.in/yaml.v2" "gopkg.in/yaml.v2"
"io/ioutil" "io/ioutil"
"time"
) )
type Config struct { type Config struct {
@ -37,7 +38,7 @@ func ParseConfigBytes(yamlBytes []byte) *Config {
service.FailureThreshold = 1 service.FailureThreshold = 1
} }
if service.Interval == 0 { if service.Interval == 0 {
service.Interval = 10 service.Interval = 10 * time.Second
} }
} }
return config return config

View File

@ -1,18 +1,22 @@
package config package config
import "testing" import (
"fmt"
"testing"
"time"
)
func TestParseConfigBytes(t *testing.T) { func TestParseConfigBytes(t *testing.T) {
config := ParseConfigBytes([]byte(` config := ParseConfigBytes([]byte(`
services: services:
- name: twinnation - name: twinnation
url: https://twinnation.org/actuator/health url: https://twinnation.org/actuator/health
interval: 15 interval: 15s
failure-threshold: 3 failure-threshold: 3
conditions: conditions:
- "$STATUS == 200" - "$STATUS == 200"
- name: github - name: github
url: https://github.com url: https://api.github.com/healthz
conditions: conditions:
- "$STATUS != 400" - "$STATUS != 400"
- "$STATUS != 500" - "$STATUS != 500"
@ -23,14 +27,15 @@ services:
if config.Services[0].Url != "https://twinnation.org/actuator/health" { if config.Services[0].Url != "https://twinnation.org/actuator/health" {
t.Errorf("URL should have been %s", "https://twinnation.org/actuator/health") t.Errorf("URL should have been %s", "https://twinnation.org/actuator/health")
} }
if config.Services[1].Url != "https://github.com" { if config.Services[1].Url != "https://api.github.com/healthz" {
t.Errorf("URL should have been %s", "https://github.com") t.Errorf("URL should have been %s", "https://api.github.com/healthz")
} }
if config.Services[0].Interval != 15 { fmt.Println(config.Services[0].Interval)
t.Errorf("Interval should have been %d", 15) if config.Services[0].Interval != 15*time.Second {
t.Errorf("Interval should have been %s", 15*time.Second)
} }
if config.Services[1].Interval != 10 { if config.Services[1].Interval != 10*time.Second {
t.Errorf("Interval should have been %d, because it is the default value", 10) t.Errorf("Interval should have been %s, because it is the default value", 10*time.Second)
} }
if config.Services[0].FailureThreshold != 3 { if config.Services[0].FailureThreshold != 3 {
t.Errorf("FailureThreshold should have been %d", 3) t.Errorf("FailureThreshold should have been %d", 3)

View File

@ -24,17 +24,18 @@ type Result struct {
HttpStatus int `json:"status"` HttpStatus int `json:"status"`
Hostname string `json:"hostname"` Hostname string `json:"hostname"`
Ip string `json:"ip"` Ip string `json:"ip"`
Duration string `json:"duration"` Duration time.Duration `json:"duration"`
Errors []error `json:"errors"` Errors []error `json:"errors"`
ConditionResult []*ConditionResult `json:"condition-results"` ConditionResult []*ConditionResult `json:"condition-results"`
Timestamp time.Time `json:"timestamp"`
} }
type Service struct { type Service struct {
Name string `yaml:"name"` Name string `yaml:"name"`
Url string `yaml:"url"` Url string `yaml:"url"`
Interval int `yaml:"interval,omitempty"` // TODO: Implement Interval time.Duration `yaml:"interval,omitempty"`
FailureThreshold int `yaml:"failure-threshold,omitempty"` // TODO: Implement FailureThreshold int `yaml:"failure-threshold,omitempty"` // TODO: Implement
Conditions []*Condition `yaml:"conditions"` Conditions []*Condition `yaml:"conditions"`
} }
func (service *Service) getIp(result *Result) { func (service *Service) getIp(result *Result) {
@ -62,7 +63,7 @@ func (service *Service) getStatus(result *Result) {
result.Errors = append(result.Errors, err) result.Errors = append(result.Errors, err)
return return
} }
result.Duration = time.Now().Sub(startTime).String() result.Duration = time.Now().Sub(startTime)
result.HttpStatus = response.StatusCode result.HttpStatus = response.StatusCode
} }
@ -73,6 +74,7 @@ func (service *Service) EvaluateConditions() *Result {
for _, condition := range service.Conditions { for _, condition := range service.Conditions {
condition.Evaluate(result) condition.Evaluate(result)
} }
result.Timestamp = time.Now()
return result return result
} }

View File

@ -3,6 +3,7 @@ package watchdog
import ( import (
"github.com/TwinProduction/gatus/config" "github.com/TwinProduction/gatus/config"
"github.com/TwinProduction/gatus/core" "github.com/TwinProduction/gatus/core"
"log"
"sync" "sync"
"time" "time"
) )
@ -17,18 +18,26 @@ func GetServiceResults() *map[string][]*core.Result {
} }
func Monitor() { func Monitor() {
for { for _, service := range config.Get().Services {
for _, service := range config.Get().Services { go func(service *core.Service) {
go func(service *core.Service) { for {
log.Printf("[watchdog][Monitor] Waiting interval=%s before monitoring serviceName=%s", service.Interval, service.Name)
time.Sleep(service.Interval)
log.Printf("[watchdog][Monitor] Monitoring serviceName=%s", service.Name)
result := service.EvaluateConditions() result := service.EvaluateConditions()
rwLock.Lock() rwLock.Lock()
defer rwLock.Unlock()
serviceResults[service.Name] = append(serviceResults[service.Name], result) serviceResults[service.Name] = append(serviceResults[service.Name], result)
if len(serviceResults[service.Name]) > 15 { if len(serviceResults[service.Name]) > 10 {
serviceResults[service.Name] = serviceResults[service.Name][15:] serviceResults[service.Name] = serviceResults[service.Name][1:]
} }
}(service) rwLock.Unlock()
} log.Printf(
time.Sleep(10 * time.Second) "[watchdog][Monitor] Finished monitoring serviceName=%s; errors=%d; requestDuration=%s",
service.Name,
len(result.Errors),
result.Duration.Round(time.Millisecond),
)
}
}(service)
} }
} }