-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtimeline.go
126 lines (110 loc) · 2.82 KB
/
timeline.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
package main
import (
"log"
"github.com/pkg/errors"
"github.com/McKael/checkup"
)
// TimelineState is a Timeline item.
type TimelineState struct {
Result *checkup.Result
StateChange bool
Timestamp int64
}
// Timeline is a list of checks for a give site.
type Timeline []TimelineState
var globalTimeline Timeline
var timelines map[string]Timeline
func buildTimelines(checkFiles []string) {
// Note: 'timelines' is not reset, so that the build can be incremental
if timelines == nil {
timelines = make(map[string]Timeline)
}
for _, f := range checkFiles {
t := index[f]
results, err := storageReader.Fetch(f)
if err != nil {
log.Printf("Error: cannot read '%s' (%s), skipping...\n", f, err.Error())
// Remove from the index so that it's retried later.
delete(index, f)
continue
}
for _, r := range results {
r := r
changed := timelineAppend(r.Title, t, r)
gtlst := TimelineState{
Result: &r,
Timestamp: t,
StateChange: changed,
}
globalTimeline = append(globalTimeline, gtlst)
}
}
}
func timelineAppend(title string, timestamp int64, r checkup.Result) (changed bool) {
tlst := TimelineState{
Result: &r,
Timestamp: timestamp,
}
tl, ok := timelines[title]
if !ok {
tlst.StateChange = true
} else {
l := len(tl)
if l > 0 { // changed ?
prevRes := tl[l-1].Result
if prevRes.Healthy != r.Healthy ||
prevRes.Degraded != r.Degraded ||
prevRes.Down != r.Down {
tlst.StateChange = true
}
}
}
changed = tlst.StateChange
timelines[title] = append(timelines[title], tlst)
return
}
// GetTimeline returns the timeline for a given title.
// If changes is true, only the checks with a state change are returned.
// Start & End timestamps can be provided, they are ignored if set to 0.
// Those timestamps are in nanoseconds since 1970-01-01 00:00:00 UTC.
// The maximum number of items to be returned can be set with the 'limit' value.
func GetTimeline(title string, changes bool, startTS, endTS int64, limit int) (Timeline, error) {
var tl Timeline
if title == "" {
tl = globalTimeline
} else {
var ok bool
tl, ok = timelines[title]
if !ok {
return nil, errors.Errorf("timeline for '%s' not found", title)
}
}
if !changes && startTS == 0 && endTS == 0 {
// Return all checks
if limit == 0 || limit >= len(tl) {
return tl, nil
}
return tl[len(tl)-limit:], nil
}
// Return only state changes
var newTl Timeline
for _, tlst := range tl {
// Filter boundaries
if startTS > 0 && tlst.Result.Timestamp < startTS {
continue
}
if endTS > 0 && tlst.Result.Timestamp > endTS {
continue
}
// Filter state changes
if changes && !tlst.StateChange {
continue
}
newTl = append(newTl, tlst)
}
// Return all checks
if limit > 0 && limit < len(newTl) {
return newTl[len(newTl)-limit:], nil
}
return newTl, nil
}