Skip to content

Commit

Permalink
feat: Add more query filter options for SLA HTML and JSON API (megaea…
Browse files Browse the repository at this point in the history
…se#158)

* add more query filter option for SLA HTML and JSON API

* forgot the files

* fix the link error in README.md

* bug-fixing: should use the probe time instead of now

* Apply suggestions from code review

Co-authored-by: Pantelis Roditis <[email protected]>

* Update README.md

Co-authored-by: Pantelis Roditis <[email protected]>

* for the how many prober found, using match/total formation

* add the PageSize & PageNum

* reset the cnt

* mv the strings.TrimSpace()

Co-authored-by: Pantelis Roditis <[email protected]>
  • Loading branch information
haoel and proditis committed Jul 6, 2022
1 parent 23c3ec2 commit 00d5519
Show file tree
Hide file tree
Showing 7 changed files with 509 additions and 81 deletions.
18 changes: 11 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -259,12 +259,16 @@ Check the [Notification Configuration](#38-notification-configuration) to see h
- HTML: `http:https://localhost:8181/`
- JSON: `http:https://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.

Expand All @@ -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
Expand Down
2 changes: 2 additions & 0 deletions global/global.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
170 changes: 170 additions & 0 deletions report/filter.go
Original file line number Diff line number Diff line change
@@ -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:https://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 style=\"font-size:9pt; background-color:#666; color:white; padding:0 5px;border-radius: 3px;\">"
_span := "</span> "

result := ""

if strings.TrimSpace(f.Name) != "" {
result += fmt.Sprintf(span+"<b>Name</b>: %s"+_span, f.Name)
}
if strings.TrimSpace(f.Kind) != "" {
result += fmt.Sprintf(span+"<b>Kind</b>: %s"+_span, f.Kind)
}
if strings.TrimSpace(f.Endpoint) != "" {
result += fmt.Sprintf(span+"<b>Endpoint</b>: %s"+_span, f.Endpoint)
}
if f.Status != nil {
result += fmt.Sprintf(span+"<b>Status</b>: %s"+_span, f.Status.String())
}
if strings.TrimSpace(f.Message) != "" {
result += fmt.Sprintf(span+"<b>Message</b>: %s"+_span, f.Message)
}
if f.SLAGreater > 0 || f.SLALess < 100 {
result += fmt.Sprintf(span+"<b>SLA</b>: %.2f%% - %.2f%% "+_span, f.SLAGreater, f.SLALess)
}

color := "#c00"
if f.PageNum <= f.cnt/f.PageSize+1 {
color = "#4E944F"
}
span = `<span style="font-size:9pt; background-color:` + color + `; color:white; padding:0 5px; margin-left:10px;border-radius: 3px;">`
result += fmt.Sprintf(span+"<b>Page %d / %d</b>"+_span, f.PageNum, f.cnt/f.PageSize+1)

span = `<span style="font-size:9pt; background-color:#4E944F; color:white; padding:0 5px; margin-left:10px;border-radius: 3px;">`
result += fmt.Sprintf(span+"<b>%d / %d Probers found!</b>"+_span, f.cnt, f.total)

result += "<br><br>"

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
}
Loading

0 comments on commit 00d5519

Please sign in to comment.