diff --git a/README.md b/README.md
index f44532af..3069b6bd 100644
--- a/README.md
+++ b/README.md
@@ -259,12 +259,16 @@ Check the [Notification Configuration](#38-notification-configuration) to see h
- HTML: `http://localhost:8181/`
- JSON: `http://localhost:8181/api/v1/sla`
-For the HTML report, you can use the following URL query options:
-
- - `refresh`: report refresh rate (ex. `?refresh=30s` refreshes the page every 30 seconds)
- - `status`: only shows the probers with specific status, accepted values `up` or `down` (ex. `?status=up` list only probers with status `up`).
- - `gte`: only shows the probers with SLA greater than or equal to the given percentage (ex. `?gte=50` filter only hosts with SLA percentage `>= 50%`)
- - `lte`: only shows the probers with SLA less than or equal to the given percentage (ex. `?lte=90` filter only hosts with SLA percentage `<= 90%` )
+You can use the following URL query options for both HTML and JSON:
+ - `refresh`: (_HTML only_) refresh the page every given seconds (ex, `?refresh=30s` refreshes the page every 30 seconds)
+ - `pg` & `sz`: page number and page size (ex, `?pg=2&sz=10` shows the second page with 10 probers), default page size is `100`
+ - `name`: filter the probers that contain the value of name (ex, `?name=probe1` list the probers which name containing `probe1`)
+ - `kind`: filter the probers with the kind (ex, `?kind=http` list the probers with kind `http`)
+ - `ep`: filter the probers with the endpoint (ex, `?ep=example.com` list the probers which endpoint containing `example.com`)
+ - `msg`: filter the probers with the message (ex, `?msg=example` list the probers which message containing `example`)
+ - `status`: filter the probers with specific status, accepted values `up` or `down` (ex. `?status=up` list only probers with status `up`).
+ - `gte`: filter the probers with SLA greater than or equal to the given percentage (ex. `?gte=50` filter only hosts with SLA percentage `>= 50%`)
+ - `lte`:filter the probers with SLA less than or equal to the given percentage (ex. `?lte=90` filter only hosts with SLA percentage `<= 90%` )
Refer to the [Global Setting Configuration](#39-global-setting-configuration) to see how to configure the access log.
@@ -283,7 +287,7 @@ For the HTML report, you can use the following URL query options:
data: /path/to/data/file.yaml
```
-For more information, please check the [Global Setting Configuration](#38-global-setting-configuration)
+For more information, please check the [Global Setting Configuration](#39-global-setting-configuration)
### 1.4 Channel
diff --git a/global/global.go b/global/global.go
index 807c99a7..b87bd39d 100644
--- a/global/global.go
+++ b/global/global.go
@@ -68,6 +68,8 @@ const (
DefaultHTTPServerIP = "0.0.0.0"
// DefaultHTTPServerPort is the default port of the HTTP server
DefaultHTTPServerPort = "8181"
+ // DefaultPageSize is the default page size
+ DefaultPageSize = 100
// DefaultAccessLogFile is the default access log file name
DefaultAccessLogFile = "access.log"
// DefaultDataFile is the default data file name
diff --git a/report/filter.go b/report/filter.go
new file mode 100644
index 00000000..361b86af
--- /dev/null
+++ b/report/filter.go
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2022, MegaEase
+ * All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package report
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/megaease/easeprobe/global"
+ "github.com/megaease/easeprobe/probe"
+
+ log "github.com/sirupsen/logrus"
+)
+
+// SLAFilter filter the probers
+type SLAFilter struct {
+ Name string
+ Kind string
+ Endpoint string
+ Status *probe.Status
+ SLAGreater float64
+ SLALess float64
+ Message string
+ PageNum int
+ PageSize int
+ total int // the total number of probers
+ cnt int // the number of probers that match the filter
+}
+
+// NewEmptyFilter create a new SLAFilter
+func NewEmptyFilter() *SLAFilter {
+ return &SLAFilter{
+ Name: "",
+ Kind: "",
+ Endpoint: "",
+ Status: nil,
+ SLAGreater: 0,
+ SLALess: 100,
+ Message: "",
+ PageNum: 1,
+ PageSize: global.DefaultPageSize,
+ total: 0,
+ cnt: 0,
+ }
+}
+
+// Check check the filter is valid or not
+func (f *SLAFilter) Check() error {
+ log.Debugf("[Web] Check filter: %+v", f)
+ if f.SLAGreater > f.SLALess {
+ return fmt.Errorf("Error: Invalid SLA filter: gte(%0.2f) > (%0.2f)", f.SLAGreater, f.SLALess)
+ }
+ if f.SLAGreater > 100 || f.SLAGreater < 0 {
+ return fmt.Errorf("Error: Invalid SLA filter: gte(%0.2f), it must be between 0 - 100", f.SLAGreater)
+ }
+ if f.SLALess > 100 || f.SLALess < 0 {
+ return fmt.Errorf("Error: Invalid SLA filter: lte(%0.2f), it must be between 0 - 100", f.SLALess)
+ }
+ if f.PageNum < 1 {
+ return fmt.Errorf("Error: Invalid page number: %d, it must be greater than 0", f.PageNum)
+ }
+ if f.PageSize < 1 {
+ return fmt.Errorf("Error: Invalid page size: %d, it must be greater than 0", f.PageSize)
+ }
+ return nil
+}
+
+// HTML return the HTML format string
+func (f *SLAFilter) HTML() string {
+
+ span := ""
+ _span := " "
+
+ result := ""
+
+ if strings.TrimSpace(f.Name) != "" {
+ result += fmt.Sprintf(span+"Name: %s"+_span, f.Name)
+ }
+ if strings.TrimSpace(f.Kind) != "" {
+ result += fmt.Sprintf(span+"Kind: %s"+_span, f.Kind)
+ }
+ if strings.TrimSpace(f.Endpoint) != "" {
+ result += fmt.Sprintf(span+"Endpoint: %s"+_span, f.Endpoint)
+ }
+ if f.Status != nil {
+ result += fmt.Sprintf(span+"Status: %s"+_span, f.Status.String())
+ }
+ if strings.TrimSpace(f.Message) != "" {
+ result += fmt.Sprintf(span+"Message: %s"+_span, f.Message)
+ }
+ if f.SLAGreater > 0 || f.SLALess < 100 {
+ result += fmt.Sprintf(span+"SLA: %.2f%% - %.2f%% "+_span, f.SLAGreater, f.SLALess)
+ }
+
+ color := "#c00"
+ if f.PageNum <= f.cnt/f.PageSize+1 {
+ color = "#4E944F"
+ }
+ span = ``
+ result += fmt.Sprintf(span+"Page %d / %d"+_span, f.PageNum, f.cnt/f.PageSize+1)
+
+ span = ``
+ result += fmt.Sprintf(span+"%d / %d Probers found!"+_span, f.cnt, f.total)
+
+ result += "
"
+
+ return result
+}
+
+func (f *SLAFilter) getIndics() (start int, end int) {
+ start = (f.PageNum - 1) * f.PageSize
+ end = f.PageNum*f.PageSize - 1
+ return start, end
+}
+
+// Filter filter the probers
+func (f *SLAFilter) Filter(probers []probe.Prober) []probe.Prober {
+ start, end := f.getIndics()
+ f.cnt = 0
+ result := make([]probe.Prober, 0)
+ for _, p := range probers {
+ // if the name is not empty then filter by name
+ if f.Name != "" && !strings.Contains(p.Name(), f.Name) {
+ continue
+ }
+ // if the kind is not empty then filter by kind
+ if f.Kind != "" && p.Kind() != f.Kind {
+ continue
+ }
+ // if the endpoint is not empty then filter by endpoint
+ if f.Endpoint != "" && !strings.Contains(p.Result().Endpoint, f.Endpoint) {
+ continue
+ }
+ // if the status is not right then ignore it
+ if f.Status != nil && p.Result().Status != *f.Status {
+ continue
+ }
+ // if the message is not empty then filter by message
+ if f.Message != "" && !strings.Contains(p.Result().Message, f.Message) {
+ continue
+ }
+ //if the SLA is not right then ignore it
+ percent := p.Result().SLAPercent()
+ if percent < f.SLAGreater || percent > f.SLALess {
+ continue
+ }
+
+ if f.cnt >= start && f.cnt <= end { // if the prober is in the page
+ result = append(result, p)
+ }
+ f.cnt++ // how many probers are filtered
+ }
+ f.total = len(probers)
+ return result
+}
diff --git a/report/filter_test.go b/report/filter_test.go
new file mode 100644
index 00000000..d7ba4fd7
--- /dev/null
+++ b/report/filter_test.go
@@ -0,0 +1,255 @@
+/*
+ * Copyright (c) 2022, MegaEase
+ * All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package report
+
+import (
+ "fmt"
+ "testing"
+
+ "github.com/megaease/easeprobe/probe"
+ "github.com/megaease/easeprobe/probe/base"
+ "github.com/stretchr/testify/assert"
+)
+
+func initData() []probe.Prober {
+ var probes = []probe.Prober{
+ &dummyProber{
+ DefaultProbe: base.DefaultProbe{
+ ProbeKind: "http",
+ ProbeName: "probe_001",
+ ProbeResult: &probe.Result{
+ Endpoint: "http://probe_001",
+ },
+ },
+ },
+ &dummyProber{
+ DefaultProbe: base.DefaultProbe{
+ ProbeKind: "tcp",
+ ProbeName: "probe_002",
+ ProbeResult: &probe.Result{
+ Endpoint: "probe_002:443",
+ },
+ },
+ },
+ &dummyProber{
+ DefaultProbe: base.DefaultProbe{
+ ProbeKind: "http",
+ ProbeName: "probe_003",
+ ProbeResult: &probe.Result{
+ Endpoint: "https://probe_003:443",
+ },
+ },
+ },
+ &dummyProber{
+ DefaultProbe: base.DefaultProbe{
+ ProbeKind: "tcp",
+ ProbeName: "probe_004",
+ ProbeResult: &probe.Result{
+ Endpoint: "probe_004:443",
+ },
+ },
+ },
+ }
+ probes[0].Result().Status = probe.StatusUp
+ probes[1].Result().Status = probe.StatusDown
+ probes[2].Result().Status = probe.StatusUp
+ probes[3].Result().Status = probe.StatusDown
+
+ for i := 0; i < len(probes); i++ {
+ probes[i].Result().Message = fmt.Sprintf("%s %s %s", probes[i].Kind(), probes[i].Name(), "message")
+ }
+
+ // 80% SLA
+ probes[0].Result().Stat.UpTime = 80
+ probes[0].Result().Stat.DownTime = 20
+
+ // 60% SLA
+ probes[1].Result().Stat.UpTime = 60
+ probes[1].Result().Stat.DownTime = 40
+
+ // 40% SLA
+ probes[2].Result().Stat.UpTime = 40
+ probes[2].Result().Stat.DownTime = 60
+
+ // 20% SLA
+ probes[3].Result().Stat.UpTime = 20
+ probes[3].Result().Stat.DownTime = 80
+
+ return probes
+}
+func TestFilter(t *testing.T) {
+ _probes := initData()
+ filter := NewEmptyFilter()
+
+ probes := filter.Filter(_probes)
+ assert.Equal(t, len(_probes), len(probes))
+ assert.Equal(t, _probes, probes)
+
+ // sla >= 60 && sla <= 40
+ filter.SLAGreater = 60
+ filter.SLALess = 40
+ err := filter.Check()
+ assert.NotNil(t, err)
+ // sla >= 60 && sla <= 200
+ filter.SLALess = 200
+ err = filter.Check()
+ assert.NotNil(t, err)
+ // sla >= -100 && sla <= 60
+ filter.SLALess = 60
+ filter.SLAGreater = -100
+ err = filter.Check()
+ assert.NotNil(t, err)
+ //sla >= 40 && sla <= 60
+ filter.SLAGreater = 40
+ err = filter.Check()
+ assert.Nil(t, err)
+
+ // sla >= 60 && sla <= 40
+ probes = filter.Filter(_probes)
+ assert.Equal(t, 2, len(probes))
+ assert.Equal(t, _probes[1], probes[0])
+ assert.Equal(t, _probes[2], probes[1])
+
+ html := filter.HTML()
+ assert.Contains(t, html, "SLA: 40.00% - 60.00%")
+
+ // filter by message
+ filter = NewEmptyFilter()
+ filter.Message = "http"
+ probes = filter.Filter(_probes)
+ assert.Equal(t, 2, len(probes))
+ assert.Equal(t, _probes[0], probes[0])
+ assert.Equal(t, _probes[2], probes[1])
+
+ html = filter.HTML()
+ assert.Contains(t, html, "Message: http")
+
+ // filter by status
+ filter = NewEmptyFilter()
+ s := probe.StatusUp
+ filter.Status = &s
+ probes = filter.Filter(_probes)
+ assert.Equal(t, 2, len(probes))
+ assert.Equal(t, _probes[0], probes[0])
+ assert.Equal(t, _probes[2], probes[1])
+
+ html = filter.HTML()
+ assert.Contains(t, html, "Status: up")
+
+ // filter by endpoint
+ filter = NewEmptyFilter()
+ filter.Endpoint = ":443"
+ probes = filter.Filter(_probes)
+ assert.Equal(t, 3, len(probes))
+ assert.Equal(t, _probes[1], probes[0])
+ assert.Equal(t, _probes[2], probes[1])
+ assert.Equal(t, _probes[3], probes[2])
+
+ html = filter.HTML()
+ assert.Contains(t, html, "Endpoint: :443")
+
+ // filter by kind
+ filter = NewEmptyFilter()
+ filter.Kind = "tcp"
+ probes = filter.Filter(_probes)
+ assert.Equal(t, 2, len(probes))
+ assert.Equal(t, _probes[1], probes[0])
+ assert.Equal(t, _probes[3], probes[1])
+
+ html = filter.HTML()
+ assert.Contains(t, html, "Kind: tcp")
+
+ // filter by name
+ filter = NewEmptyFilter()
+ filter.Name = "probe_001"
+ probes = filter.Filter(_probes)
+ assert.Equal(t, 1, len(probes))
+ assert.Equal(t, _probes[0], probes[0])
+
+ html = filter.HTML()
+ assert.Contains(t, html, "Name: probe_001")
+
+ // filter by name and kind
+ filter = NewEmptyFilter()
+ filter.Name = "probe"
+ filter.Kind = "http"
+ probes = filter.Filter(_probes)
+ assert.Equal(t, 2, len(probes))
+ assert.Equal(t, _probes[0], probes[0])
+ assert.Equal(t, _probes[2], probes[1])
+
+ // filter by status and kind
+ filter = NewEmptyFilter()
+ filter.Status = &s
+ filter.Kind = "tcp"
+ probes = filter.Filter(_probes)
+ assert.Equal(t, 0, len(probes))
+
+ filter.Kind = "http"
+ probes = filter.Filter(_probes)
+ assert.Equal(t, 2, len(probes))
+ assert.Equal(t, _probes[0], probes[0])
+ assert.Equal(t, _probes[2], probes[1])
+
+ // filter by status and sla
+ filter = NewEmptyFilter()
+ filter.Status = &s
+ filter.SLAGreater = 20
+ filter.SLALess = 100
+ probes = filter.Filter(_probes)
+ assert.Equal(t, 2, len(probes))
+ assert.Equal(t, _probes[0], probes[0])
+ assert.Equal(t, _probes[2], probes[1])
+
+ // filter by status and sla and endpoint
+ filter.Endpoint = ":443"
+ probes = filter.Filter(_probes)
+ assert.Equal(t, 1, len(probes))
+ assert.Equal(t, _probes[2], probes[0])
+}
+
+func NewFilterWithPage(pg, sz int) *SLAFilter {
+ filter := NewEmptyFilter()
+ filter.PageNum = pg
+ filter.PageSize = sz
+ return filter
+}
+func TestPage(t *testing.T) {
+ _probes := initData()
+ filter := NewEmptyFilter()
+ probes := filter.Filter(_probes)
+ assert.Equal(t, _probes, probes)
+
+ filter = NewFilterWithPage(1, 2)
+ probes = filter.Filter(_probes)
+ assert.Equal(t, 2, len(probes))
+ assert.Equal(t, _probes[0], probes[0])
+ assert.Equal(t, _probes[1], probes[1])
+
+ filter = NewFilterWithPage(2, 2)
+ probes = filter.Filter(_probes)
+ assert.Equal(t, 2, len(probes))
+ assert.Equal(t, _probes[2], probes[0])
+ assert.Equal(t, _probes[3], probes[1])
+
+ filter = NewFilterWithPage(2, 3)
+ probes = filter.Filter(_probes)
+ assert.Equal(t, 1, len(probes))
+ assert.Equal(t, _probes[3], probes[0])
+
+}
diff --git a/report/sla.go b/report/sla.go
index 2223e420..974709ff 100644
--- a/report/sla.go
+++ b/report/sla.go
@@ -115,7 +115,7 @@ func SLATextSection(r *probe.Result) string {
return fmt.Sprintf(text, r.Name, r.Endpoint,
DurationStr(r.Stat.UpTime), DurationStr(r.Stat.DownTime), r.SLAPercent(),
r.Stat.Total, SLAStatusText(r.Stat, Text),
- time.Now().UTC().Format(r.TimeFormat),
+ r.StartTime.UTC().Format(r.TimeFormat),
r.Status.Emoji()+" "+r.Status.String(), JSONEscape(r.Message))
}
@@ -134,7 +134,7 @@ func SLALogSection(r *probe.Result) string {
return fmt.Sprintf(text, r.Name, r.Endpoint,
DurationStr(r.Stat.UpTime), DurationStr(r.Stat.DownTime), r.SLAPercent(),
r.Stat.Total, SLAStatusText(r.Stat, Log),
- time.Now().UTC().Format(r.TimeFormat),
+ r.StartTime.UTC().Format(r.TimeFormat),
r.Status.String(), r.Message)
}
@@ -164,7 +164,7 @@ func SLAMarkdownSection(r *probe.Result, f Format) string {
return fmt.Sprintf(text, r.Name, r.Endpoint,
DurationStr(r.Stat.UpTime), DurationStr(r.Stat.DownTime), r.SLAPercent(),
r.Stat.Total, SLAStatusText(r.Stat, MarkdownSocial),
- time.Now().UTC().Format(r.TimeFormat),
+ r.StartTime.UTC().Format(r.TimeFormat),
r.Status.Emoji()+" "+r.Status.String(), r.Message)
}
@@ -214,27 +214,10 @@ func SLAHTMLSection(r *probe.Result) string {
DurationStr(r.Stat.UpTime), DurationStr(r.Stat.DownTime),
r.SLAPercent(),
r.Stat.Total, SLAStatusText(r.Stat, HTML),
- time.Now().UTC().Format(r.TimeFormat),
+ r.StartTime.UTC().Format(r.TimeFormat),
r.Status.Emoji()+" "+r.Status.String(), JSONEscape(r.Message))
}
-// SLAFilter filter the probers
-type SLAFilter struct {
- Status *probe.Status
- SLAGreater float64
- SLALess float64
-}
-
-// HTML return the HTML format string
-func (f *SLAFilter) HTML() string {
- result := fmt.Sprintf("SLA: %.2f%% - %.2f%% ", f.SLAGreater, f.SLALess)
- if f.Status != nil {
- result += fmt.Sprintf(" Status: %s", f.Status.String())
- }
-
- return result
-}
-
// SLAHTML return a full stat report
func SLAHTML(probers []probe.Prober) string {
return SLAHTMLFilter(probers, nil)
@@ -244,27 +227,18 @@ func SLAHTML(probers []probe.Prober) string {
func SLAHTMLFilter(probers []probe.Prober, filter *SLAFilter) string {
html := HTMLHeader("Overall SLA Report")
- cnt := 0
+ if filter == nil {
+ filter = NewEmptyFilter()
+ }
+
+ probers = filter.Filter(probers)
table := ``
for _, p := range probers {
- if filter == nil {
- table += SLAHTMLSection(p.Result())
- cnt++
- } else if p.Result().SLAPercent() >= filter.SLAGreater && p.Result().SLAPercent() <= filter.SLALess {
- if filter.Status == nil || p.Result().Status == *filter.Status {
- table += SLAHTMLSection(p.Result())
- cnt++
- }
- }
+ table += SLAHTMLSection(p.Result())
}
table += `
`
- summary := ""
- if filter != nil {
- summary += filter.HTML() + " : "
- }
- summary += fmt.Sprintf(`( %d Probers found! )`, cnt)
- html = html + summary + table
+ html = html + filter.HTML() + table
timeFmt := "2006-01-02 15:04:05"
if len(probers) > 0 {
@@ -407,7 +381,7 @@ func SLALarkSection(r *probe.Result) string {
return fmt.Sprintf(text, r.Name, r.Endpoint,
DurationStr(r.Stat.UpTime), DurationStr(r.Stat.DownTime), r.SLAPercent(),
r.Stat.Total, SLAStatusText(r.Stat, Lark),
- time.Now().UTC().Format(r.TimeFormat),
+ r.StartTime.UTC().Format(r.TimeFormat),
r.Status.Emoji()+" "+r.Status.String(), JSONEscape(r.Message))
}
diff --git a/report/sla_test.go b/report/sla_test.go
index 77451f96..d37de891 100644
--- a/report/sla_test.go
+++ b/report/sla_test.go
@@ -41,14 +41,14 @@ func (d *dummyProber) Config(g global.ProbeSettings) error {
func (d *dummyProber) DoProbe() (bool, string) {
return rand.Int()%2 == 0, "hello world"
}
-
-var probes = []probe.Prober{
- newDummyProber("probe1"),
- newDummyProber("probe2"),
- newDummyProber("probe3"),
- newDummyProber("probe4"),
+func getProbers() []probe.Prober {
+ return []probe.Prober{
+ newDummyProber("probe1"),
+ newDummyProber("probe2"),
+ newDummyProber("probe3"),
+ newDummyProber("probe4"),
+ }
}
-
func newDummyProber(name string) probe.Prober {
r := newDummyResult(name)
return &dummyProber{
@@ -63,6 +63,7 @@ func newDummyProber(name string) probe.Prober {
func TestSLA(t *testing.T) {
global.InitEaseProbe("DummyProbe", "icon")
+ probes := getProbers()
for f, fn := range FormatFuncs {
sla := fn.StatFn(probes)
assert.NotEmpty(t, sla)
@@ -85,6 +86,7 @@ func TestSLAJSONSection(t *testing.T) {
}
func TestSLAFilter(t *testing.T) {
+ probes := getProbers()
probes[0].Result().Status = probe.StatusUp
probes[1].Result().Status = probe.StatusDown
probes[2].Result().Status = probe.StatusUp
@@ -95,19 +97,15 @@ func TestSLAFilter(t *testing.T) {
assert.Contains(t, html, p.Name())
}
- filter := SLAFilter{
- Status: nil,
- SLAGreater: 0,
- SLALess: 100,
- }
- html = SLAHTMLFilter(probes, &filter)
+ filter := NewEmptyFilter()
+ html = SLAHTMLFilter(probes, filter)
for _, p := range probes {
assert.Contains(t, html, p.Name())
}
status := probe.StatusUp
filter.Status = &status
- html = SLAHTMLFilter(probes, &filter)
+ html = SLAHTMLFilter(probes, filter)
assert.Contains(t, html, probes[0].Name())
assert.NotContains(t, html, probes[1].Name())
assert.Contains(t, html, probes[2].Name())
@@ -132,7 +130,7 @@ func TestSLAFilter(t *testing.T) {
// sla between 50 - 90, status is up
filter.SLAGreater = 50
filter.SLALess = 90
- html = SLAHTMLFilter(probes, &filter)
+ html = SLAHTMLFilter(probes, filter)
assert.Contains(t, html, probes[0].Name())
assert.NotContains(t, html, probes[1].Name())
assert.NotContains(t, html, probes[2].Name())
diff --git a/web/server.go b/web/server.go
index cc56658a..e4b714a8 100644
--- a/web/server.go
+++ b/web/server.go
@@ -18,6 +18,7 @@
package web
import (
+ "encoding/json"
"fmt"
"net"
"net/http"
@@ -52,6 +53,9 @@ func getRefreshInterval(refersh string) time.Duration {
}
func getStatus(status string) *probe.Status {
+ if status == "" {
+ return nil
+ }
var s probe.Status
s.Status(status)
return &s
@@ -63,53 +67,74 @@ func getFloat(f string, _default float64) float64 {
}
flt, err := strconv.ParseFloat(f, 64)
if err != nil {
- log.Errorf("[Web] Invalid float value: %s", err)
+ log.Debugf("[Web] Invalid float value: %s", err)
return _default
}
return flt
}
-func checkFilter(filter report.SLAFilter) error {
- log.Debugf("[Web] Check filter: %+v", filter)
- if filter.SLAGreater > filter.SLALess {
- return fmt.Errorf("Error: Invalid SLA filter: gte(%0.2f) > (%0.2f)", filter.SLAGreater, filter.SLALess)
- }
- if filter.SLAGreater > 100 || filter.SLAGreater < 0 {
- return fmt.Errorf("Error: Invalid SLA filter: gte(%0.2f), it must be between 0 - 100", filter.SLAGreater)
+func getInt(i string, _default int) int {
+ if i == "" {
+ return _default
}
- if filter.SLALess > 100 || filter.SLALess < 0 {
- return fmt.Errorf("Error: Invalid SLA filter: lte(%0.2f), it must be between 0 - 100", filter.SLALess)
+ it, err := strconv.Atoi(i)
+ if err != nil {
+ log.Debugf("[Web] Invalid int value: %s", err)
+ return _default
}
- return nil
+ return it
}
-func slaHTML(w http.ResponseWriter, req *http.Request) {
- interval := getRefreshInterval(req.URL.Query().Get("refresh"))
-
- filter := report.SLAFilter{}
+func getFilter(req *http.Request) (*report.SLAFilter, error) {
+ filter := &report.SLAFilter{}
- if req.URL.Query().Get("status") != "" {
- filter.Status = getStatus(req.URL.Query().Get("status"))
- }
+ filter.Name = strings.TrimSpace(req.URL.Query().Get("name"))
+ filter.Kind = strings.TrimSpace(req.URL.Query().Get("kind"))
+ filter.Endpoint = strings.TrimSpace(req.URL.Query().Get("ep"))
+ filter.Status = getStatus(req.URL.Query().Get("status"))
+ filter.Message = strings.TrimSpace(req.URL.Query().Get("msg"))
filter.SLAGreater = getFloat(req.URL.Query().Get("gte"), 0)
filter.SLALess = getFloat(req.URL.Query().Get("lte"), 100)
+ filter.PageNum = getInt(req.URL.Query().Get("pg"), 1)
+ filter.PageSize = getInt(req.URL.Query().Get("sz"), global.DefaultPageSize)
- if err := checkFilter(filter); err != nil {
+ if err := filter.Check(); err != nil {
log.Errorf(err.Error())
+ return nil, err
+ }
+ return filter, nil
+}
+
+func slaHTML(w http.ResponseWriter, req *http.Request) {
+ interval := getRefreshInterval(req.URL.Query().Get("refresh"))
+
+ filter, err := getFilter(req)
+ if err != nil {
w.Write([]byte(err.Error()))
return
}
refresh := fmt.Sprintf("%d", interval.Milliseconds())
- html := []byte(report.SLAHTMLFilter(*probers, &filter) + report.AutoRefreshJS(refresh))
+ html := []byte(report.SLAHTMLFilter(*probers, filter) + report.AutoRefreshJS(refresh))
w.Header().Set("Content-Type", "text/html; charset=utf-8")
w.Write(html)
}
func slaJSON(w http.ResponseWriter, req *http.Request) {
+ filter, err := getFilter(req)
+ if err != nil {
+ buf, e := json.Marshal(err)
+ if e != nil {
+ w.Write([]byte(err.Error()))
+ return
+ }
+ w.Write(buf)
+ return
+ }
w.Header().Set("Content-Type", "application/json; charset=utf-8")
- w.Write([]byte(report.SLAJSON(*probers)))
+ _probers := filter.Filter(*probers)
+ w.Write([]byte(report.SLAJSON(_probers)))
}
// SetProbers set the probers