Skip to content

Commit e75572f

Browse files
authored
Merge pull request #113 from statping-ng/dev
[pull] master from statping-ng:dev
2 parents d86236e + c02149f commit e75572f

12 files changed

Lines changed: 162 additions & 37 deletions

File tree

database/grouping.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,10 @@ func ParseRequest(r *http.Request) (*GroupQuery, error) {
186186
}
187187

188188
func ParseQueries(r *http.Request, o isObject) (*GroupQuery, error) {
189+
return ParseQueriesForTable(r, o, "")
190+
}
191+
192+
func ParseQueriesForTable(r *http.Request, o isObject, whereTable string) (*GroupQuery, error) {
189193
fields := parseGet(r)
190194
grouping := fields.Get("group")
191195
startField := utils.ToInt(fields.Get("start"))
@@ -240,7 +244,11 @@ func ParseQueries(r *http.Request, o isObject) (*GroupQuery, error) {
240244
q = q.Offset(query.Offset)
241245
}
242246

243-
q = q.Where("created_at BETWEEN ? AND ?", q.FormatTime(query.Start), q.FormatTime(query.End))
247+
if len(whereTable) > 0 {
248+
whereTable = fmt.Sprintf("%s.", whereTable)
249+
}
250+
251+
q = q.Where(fmt.Sprintf("%screated_at BETWEEN ? AND ?", whereTable), q.FormatTime(query.Start), q.FormatTime(query.End))
244252

245253
if query.Order != "" {
246254
q = q.Order(query.Order)

frontend/src/components/Service/ServiceTopStats.vue

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
<template>
22
<div class="row stats_area mt-5 mb-4">
3-
<div class="col-4">
3+
<div class="col-4" v-if="showResponseTime">
44
<span class="font-5 d-block font-weight-bold">{{humanTime(service.avg_response)}}</span>
55
<span class="font-1 subtitle">{{$t('average_response')}}</span>
66
</div>
7-
<div class="col-4">
7+
<div :class="showResponseTime ? 'col-4' : 'col-6'">
88
<span class="font-5 d-block font-weight-bold">{{service.online_24_hours}} %</span>
99
<span class="font-1 subtitle">{{$t('last_uptime')}} 24 {{$tc('hour', 24)}}</span>
1010
</div>
11-
<div class="col-4">
11+
<div :class="showResponseTime ? 'col-4' : 'col-6'">
1212
<span class="font-5 d-block font-weight-bold">{{service.online_7_days}} %</span>
1313
<span class="font-1 subtitle">{{$t('last_uptime')}} 7 {{$tc('day', 7)}}</span>
1414
</div>
@@ -23,7 +23,12 @@
2323
type: Object,
2424
required: true
2525
},
26-
}
26+
},
27+
computed: {
28+
showResponseTime() {
29+
return this.service.avg_response !== 0 || this.service.type !== 'static'
30+
},
31+
},
2732
}
2833
</script>
2934

handlers/checkin.go

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package handlers
33
import (
44
"net"
55
"net/http"
6+
"time"
67

78
"github.com/gorilla/mux"
89
"github.com/statping-ng/statping-ng/types/checkins"
@@ -63,12 +64,18 @@ func checkinHitHandler(w http.ResponseWriter, r *http.Request) {
6364
sendErrorJson(err, w, r)
6465
return
6566
}
66-
log.Infof("Checking %s was requested", checkin.Name)
67+
68+
service, err := services.Find(checkin.ServiceId)
69+
if err != nil {
70+
sendErrorJson(err, w, r)
71+
return
72+
}
6773

6874
ip, _, _ := net.SplitHostPort(r.RemoteAddr)
6975

70-
if last := checkin.LastHit(); last == nil {
71-
checkin.Start()
76+
lastHit := checkin.LastHit()
77+
if lastHit == nil {
78+
checkin.Start(&service.Timeout)
7279
}
7380

7481
hit := &checkins.CheckinHit{
@@ -82,7 +89,22 @@ func checkinHitHandler(w http.ResponseWriter, r *http.Request) {
8289
return
8390
}
8491
checkin.Failing = false
85-
checkin.LastHitTime = utils.Now()
92+
checkin.LastHitTime = hit.CreatedAt
93+
94+
var latency int64 = 0
95+
if lastHit != nil {
96+
latency = hit.CreatedAt.Sub(lastHit.CreatedAt.Add(checkin.Period())).Microseconds()
97+
if latency > (checkin.Period() + (time.Duration(latency) * time.Second)).Microseconds() {
98+
latency = 0
99+
}
100+
}
101+
102+
service.PingTime = latency
103+
service.Latency = latency
104+
service.LastResponse = ""
105+
service.Online = true
106+
107+
services.RecordCheckinSuccess(service, checkin, hit, latency)
86108

87109
sendJsonAction(hit.Id, "update", w, r)
88110
}

handlers/services.go

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package handlers
33
import (
44
"github.com/gorilla/mux"
55
"github.com/statping-ng/statping-ng/database"
6+
"github.com/statping-ng/statping-ng/types/checkins"
67
"github.com/statping-ng/statping-ng/types/errors"
78
"github.com/statping-ng/statping-ng/types/failures"
89
"github.com/statping-ng/statping-ng/types/hits"
@@ -210,6 +211,12 @@ func apiServiceTimeDataHandler(w http.ResponseWriter, r *http.Request) {
210211
return
211212
}
212213

214+
groupCheckinHits, err := database.ParseQueriesForTable(r, service.AllCheckinHits(), "checkin_hits")
215+
if err != nil {
216+
sendErrorJson(err, w, r)
217+
return
218+
}
219+
213220
groupFailures, err := database.ParseQueries(r, service.AllFailures())
214221
if err != nil {
215222
sendErrorJson(err, w, r)
@@ -218,18 +225,24 @@ func apiServiceTimeDataHandler(w http.ResponseWriter, r *http.Request) {
218225

219226
var allFailures []*failures.Failure
220227
var allHits []*hits.Hit
228+
var allCheckinHits []*checkins.CheckinHit
221229

222230
if err := groupHits.Find(&allHits); err != nil {
223231
sendErrorJson(err, w, r)
224232
return
225233
}
226234

235+
if err := groupCheckinHits.Find(&allCheckinHits); err != nil {
236+
sendErrorJson(err, w, r)
237+
return
238+
}
239+
227240
if err := groupFailures.Find(&allFailures); err != nil {
228241
sendErrorJson(err, w, r)
229242
return
230243
}
231244

232-
uptimeData, err := service.UptimeData(allHits, allFailures)
245+
uptimeData, err := service.UptimeData(allHits, allCheckinHits, allFailures)
233246
if err != nil {
234247
sendErrorJson(err, w, r)
235248
return

types/checkins/database_hits.go

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,36 @@
11
package checkins
22

3+
import (
4+
"time"
5+
6+
"github.com/statping-ng/statping-ng/database"
7+
)
8+
9+
type CheckinHitters struct {
10+
db database.Database
11+
}
12+
13+
func (h CheckinHitters) Db() database.Database {
14+
return h.db
15+
}
16+
17+
func (h CheckinHitters) First() *CheckinHit {
18+
var checkinHit CheckinHit
19+
h.db.Order("checkin_hits.id ASC").Limit(1).Find(&checkinHit)
20+
return &checkinHit
21+
}
22+
23+
func (h CheckinHitters) Count() int {
24+
var count int
25+
h.db.Count(&count)
26+
return count
27+
}
28+
29+
func (h CheckinHitters) Since(t time.Time) CheckinHitters {
30+
timestamp := db.FormatTime(t)
31+
return CheckinHitters{h.db.Where("checkin_hits.created_at > ?", timestamp)}
32+
}
33+
334
func (c *Checkin) LastHit() *CheckinHit {
435
var hit CheckinHit
536
dbHits.Where("checkin = ?", c.Id).Last(&hit)
@@ -8,7 +39,7 @@ func (c *Checkin) LastHit() *CheckinHit {
839

940
func (c *Checkin) Hits() []*CheckinHit {
1041
var hits []*CheckinHit
11-
dbHits.Where("checkin = ?", c.Id).Order("id DESC").Find(&hits)
42+
dbHits.Where("checkin = ?", c.Id).Order("id DESC").Limit(32).Find(&hits)
1243
c.AllHits = hits
1344
return hits
1445
}
@@ -27,3 +58,7 @@ func (c *CheckinHit) Delete() error {
2758
q := dbHits.Delete(c)
2859
return q.Error()
2960
}
61+
62+
func AllCheckinHits(serviceId int64) CheckinHitters {
63+
return CheckinHitters{dbHits.Joins("JOIN checkins ON checkins.id = checkin").Where("checkins.service = ?", serviceId).Order("checkin_hits.id DESC")}
64+
}

types/checkins/methods.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,10 @@ func (c *Checkin) Period() time.Duration {
1818
}
1919

2020
// Start will create a channel for the checkin checking go routine
21-
func (c *Checkin) Start() {
21+
func (c *Checkin) Start(serviceTimeout *int) {
2222
log.Infoln(fmt.Sprintf("Starting checkin routine: %s", c.Name))
2323
c.Running = make(chan bool)
24-
go c.checkinRoutine()
24+
go c.checkinRoutine(serviceTimeout)
2525
}
2626

2727
// Close will stop the checkin routine

types/checkins/routine.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import (
1010
var log = utils.Log.WithField("type", "checkin")
1111

1212
// checkinRoutine for checking if the last Checkin was within its interval
13-
func (c *Checkin) checkinRoutine() {
13+
func (c *Checkin) checkinRoutine(serviceTimeout *int) {
1414
reCheck := c.Period()
1515

1616
CheckinLoop:
@@ -26,7 +26,7 @@ CheckinLoop:
2626

2727
log.Infoln(fmt.Sprintf("Checkin '%s' expects a request every %s last request was %s ago", c.Name, c.Period(), utils.DurationReadable(ago)))
2828

29-
if ago.Seconds() > c.Period().Seconds() {
29+
if ago.Seconds() > c.Period().Seconds()+float64(*serviceTimeout) {
3030
issue := fmt.Sprintf("Checkin expects a request every %d minutes", c.Interval)
3131
log.Warnln(issue)
3232

@@ -41,7 +41,7 @@ CheckinLoop:
4141
log.Errorln(err)
4242
}
4343
}
44-
reCheck = c.Period()
44+
reCheck = c.Period() + time.Duration(*serviceTimeout*int(time.Second))
4545
}
4646
}
4747
}

types/services/checkins.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ package services
44
func CheckinProcess(s *Service) {
55
for _, c := range s.Checkins {
66
if last := c.LastHit(); last != nil {
7-
c.Start()
7+
c.Start(&s.Timeout)
88
}
99
}
1010
}

types/services/hits.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
package services
22

33
import (
4-
"github.com/statping-ng/statping-ng/types/hits"
54
"time"
5+
6+
"github.com/statping-ng/statping-ng/types/checkins"
7+
"github.com/statping-ng/statping-ng/types/hits"
68
)
79

810
func (s *Service) HitsColumnID() (string, int64) {
@@ -21,6 +23,14 @@ func (s *Service) AllHits() hits.Hitters {
2123
return hits.AllHits(s)
2224
}
2325

26+
func (s *Service) AllCheckinHits() checkins.CheckinHitters {
27+
return checkins.AllCheckinHits(s.Id)
28+
}
29+
30+
func (s *Service) FirstCheckinHit() *checkins.CheckinHit {
31+
return checkins.AllCheckinHits(s.Id).First()
32+
}
33+
2434
func (s *Service) HitsSince(t time.Time) hits.Hitters {
2535
return hits.Since(t, s)
2636
}

types/services/methods.go

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"time"
1313

1414
"github.com/statping-ng/statping-ng/types"
15+
"github.com/statping-ng/statping-ng/types/checkins"
1516
"github.com/statping-ng/statping-ng/types/errors"
1617
"github.com/statping-ng/statping-ng/types/failures"
1718
"github.com/statping-ng/statping-ng/types/hits"
@@ -85,8 +86,8 @@ func (s Service) Duration() time.Duration {
8586
}
8687

8788
// Start will create a channel for the service checking go routine
88-
func (s Service) UptimeData(hits []*hits.Hit, fails []*failures.Failure) (*UptimeSeries, error) {
89-
if len(hits) == 0 {
89+
func (s Service) UptimeData(hits []*hits.Hit, checkinHits []*checkins.CheckinHit, fails []*failures.Failure) (*UptimeSeries, error) {
90+
if len(hits) == 0 && len(checkinHits) == 0 {
9091
return nil, errors.New("service does not have any successful hits")
9192
}
9293
// if theres no failures, then its been online 100%,
@@ -117,6 +118,9 @@ func (s Service) UptimeData(hits []*hits.Hit, fails []*failures.Failure) (*Uptim
117118
for _, v := range hits {
118119
tMap[v.CreatedAt] = true
119120
}
121+
for _, v := range checkinHits {
122+
tMap[v.CreatedAt] = true
123+
}
120124
for _, v := range fails {
121125
tMap[v.CreatedAt] = false
122126
}
@@ -212,13 +216,6 @@ func (s *Service) Close() {
212216
}
213217
}
214218

215-
func humanMicro(val int64) string {
216-
if val < 10000 {
217-
return fmt.Sprintf("%d μs", val)
218-
}
219-
return fmt.Sprintf("%0.0f ms", float64(val)*0.001)
220-
}
221-
222219
// IsRunning returns true if the service go routine is running
223220
func (s *Service) IsRunning() bool {
224221
if s.Running == nil {
@@ -272,10 +269,15 @@ func (s *Service) UpdateStats() *Service {
272269
}
273270
}
274271

272+
firstHit := s.FirstHit().CreatedAt
273+
if checkinHit := s.FirstCheckinHit(); checkinHit != nil && checkinHit.CreatedAt.After(firstHit) {
274+
firstHit = checkinHit.CreatedAt
275+
}
276+
275277
s.Stats = &Stats{
276278
Failures: allFails.Count(),
277-
Hits: s.AllHits().Count(),
278-
FirstHit: s.FirstHit().CreatedAt,
279+
Hits: s.AllHits().Count() + s.AllCheckinHits().Count(),
280+
FirstHit: firstHit,
279281
}
280282
return s
281283
}
@@ -293,20 +295,21 @@ func (s Service) OnlineDaysPercent(days int) float32 {
293295

294296
// OnlineSince accepts a time since parameter to return the percent of a service's uptime.
295297
func (s *Service) OnlineSince(ago time.Time) float32 {
296-
failsList := s.FailuresSince(ago).Count()
297-
hitsList := s.HitsSince(ago).Count()
298+
failsCount := s.FailuresSince(ago).Count()
299+
hitsCount := s.HitsSince(ago).Count()
300+
checkinHitsCount := s.AllCheckinHits().Since(ago).Count()
298301

299-
if failsList == 0 {
302+
if failsCount == 0 {
300303
s.Online24Hours = 100.00
301304
return s.Online24Hours
302305
}
303306

304-
if hitsList == 0 {
307+
if hitsCount == 0 && checkinHitsCount == 0 {
305308
s.Online24Hours = 0
306309
return s.Online24Hours
307310
}
308311

309-
avg := (float64(failsList) / float64(hitsList)) * 100
312+
avg := (float64(failsCount) / float64(hitsCount+checkinHitsCount)) * 100
310313
avg = 100 - avg
311314
if avg < 0 {
312315
avg = 0

0 commit comments

Comments
 (0)