mirror of
https://github.com/tailscale/tailscale.git
synced 2024-11-25 11:05:45 +00:00
prober web page improvements
Signed-off-by: Percy Wegmann <percy@tailscale.com>
This commit is contained in:
parent
888e3cb097
commit
8d25ad0c0a
@ -106,7 +106,7 @@ func getOverallStatus(p *prober.Prober) (o overallStatus) {
|
||||
// Do not show probes that have not finished yet.
|
||||
continue
|
||||
}
|
||||
if i.Result {
|
||||
if i.Status == prober.ProbeStatusSucceeded {
|
||||
o.addGoodf("%s: %s", p, i.Latency)
|
||||
} else {
|
||||
o.addBadf("%s: %s", p, i.Error)
|
||||
|
@ -345,6 +345,11 @@ func (p *Probe) run() (pi ProbeInfo, err error) {
|
||||
var cancel func()
|
||||
ctx, cancel = context.WithTimeout(ctx, timeout)
|
||||
defer cancel()
|
||||
} else {
|
||||
// For continuous probes, reset last error
|
||||
p.mu.Lock()
|
||||
p.lastErr = nil
|
||||
p.mu.Unlock()
|
||||
}
|
||||
|
||||
err = p.probeClass.Probe(ctx)
|
||||
@ -385,6 +390,16 @@ func (p *Probe) recordEnd(err error) {
|
||||
p.successHist = p.successHist.Next()
|
||||
}
|
||||
|
||||
// ProbeStatus indicates the status of a probe.
|
||||
type ProbeStatus string
|
||||
|
||||
const (
|
||||
ProbeStatusUnknown = "unknown"
|
||||
ProbeStatusRunning = "running"
|
||||
ProbeStatusFailed = "failed"
|
||||
ProbeStatusSucceeded = "succeeded"
|
||||
)
|
||||
|
||||
// ProbeInfo is a snapshot of the configuration and state of a Probe.
|
||||
type ProbeInfo struct {
|
||||
Name string
|
||||
@ -394,7 +409,7 @@ type ProbeInfo struct {
|
||||
Start time.Time
|
||||
End time.Time
|
||||
Latency time.Duration
|
||||
Result bool
|
||||
Status ProbeStatus
|
||||
Error string
|
||||
RecentResults []bool
|
||||
RecentLatencies []time.Duration
|
||||
@ -422,6 +437,10 @@ func (pb ProbeInfo) RecentMedianLatency() time.Duration {
|
||||
return pb.RecentLatencies[len(pb.RecentLatencies)/2]
|
||||
}
|
||||
|
||||
func (pb ProbeInfo) Continuous() bool {
|
||||
return pb.Interval < 0
|
||||
}
|
||||
|
||||
// ProbeInfo returns the state of all probes.
|
||||
func (p *Prober) ProbeInfo() map[string]ProbeInfo {
|
||||
out := map[string]ProbeInfo{}
|
||||
@ -449,9 +468,14 @@ func (probe *Probe) probeInfoLocked() ProbeInfo {
|
||||
Labels: probe.metricLabels,
|
||||
Start: probe.start,
|
||||
End: probe.end,
|
||||
Result: probe.succeeded,
|
||||
}
|
||||
if probe.lastErr != nil {
|
||||
inf.Status = ProbeStatusUnknown
|
||||
if probe.end.Before(probe.start) {
|
||||
inf.Status = ProbeStatusRunning
|
||||
} else if probe.succeeded {
|
||||
inf.Status = ProbeStatusSucceeded
|
||||
} else if probe.lastErr != nil {
|
||||
inf.Status = ProbeStatusFailed
|
||||
inf.Error = probe.lastErr.Error()
|
||||
}
|
||||
if probe.latency > 0 {
|
||||
|
@ -316,7 +316,7 @@ func TestProberProbeInfo(t *testing.T) {
|
||||
Interval: probeInterval,
|
||||
Labels: map[string]string{"class": "", "name": "probe1"},
|
||||
Latency: 500 * time.Millisecond,
|
||||
Result: true,
|
||||
Status: ProbeStatusSucceeded,
|
||||
RecentResults: []bool{true},
|
||||
RecentLatencies: []time.Duration{500 * time.Millisecond},
|
||||
},
|
||||
@ -324,6 +324,7 @@ func TestProberProbeInfo(t *testing.T) {
|
||||
Name: "probe2",
|
||||
Interval: probeInterval,
|
||||
Labels: map[string]string{"class": "", "name": "probe2"},
|
||||
Status: ProbeStatusFailed,
|
||||
Error: "error2",
|
||||
RecentResults: []bool{false},
|
||||
RecentLatencies: nil, // no latency for failed probes
|
||||
@ -349,7 +350,7 @@ type probeResult struct {
|
||||
}{
|
||||
{
|
||||
name: "no_runs",
|
||||
wantProbeInfo: ProbeInfo{},
|
||||
wantProbeInfo: ProbeInfo{Status: ProbeStatusUnknown},
|
||||
wantRecentSuccessRatio: 0,
|
||||
wantRecentMedianLatency: 0,
|
||||
},
|
||||
@ -358,7 +359,7 @@ type probeResult struct {
|
||||
results: []probeResult{{latency: 100 * time.Millisecond, err: nil}},
|
||||
wantProbeInfo: ProbeInfo{
|
||||
Latency: 100 * time.Millisecond,
|
||||
Result: true,
|
||||
Status: ProbeStatusSucceeded,
|
||||
RecentResults: []bool{true},
|
||||
RecentLatencies: []time.Duration{100 * time.Millisecond},
|
||||
},
|
||||
@ -369,7 +370,7 @@ type probeResult struct {
|
||||
name: "single_failure",
|
||||
results: []probeResult{{latency: 100 * time.Millisecond, err: errors.New("error123")}},
|
||||
wantProbeInfo: ProbeInfo{
|
||||
Result: false,
|
||||
Status: ProbeStatusFailed,
|
||||
RecentResults: []bool{false},
|
||||
RecentLatencies: nil,
|
||||
Error: "error123",
|
||||
@ -390,7 +391,7 @@ type probeResult struct {
|
||||
{latency: 80 * time.Millisecond, err: nil},
|
||||
},
|
||||
wantProbeInfo: ProbeInfo{
|
||||
Result: true,
|
||||
Status: ProbeStatusSucceeded,
|
||||
Latency: 80 * time.Millisecond,
|
||||
RecentResults: []bool{false, true, true, false, true, true, false, true},
|
||||
RecentLatencies: []time.Duration{
|
||||
@ -420,7 +421,7 @@ type probeResult struct {
|
||||
{latency: 110 * time.Millisecond, err: nil},
|
||||
},
|
||||
wantProbeInfo: ProbeInfo{
|
||||
Result: true,
|
||||
Status: ProbeStatusSucceeded,
|
||||
Latency: 110 * time.Millisecond,
|
||||
RecentResults: []bool{true, true, true, true, true, true, true, true, true, true},
|
||||
RecentLatencies: []time.Duration{
|
||||
@ -483,7 +484,7 @@ func TestProberRunHandler(t *testing.T) {
|
||||
ProbeInfo: ProbeInfo{
|
||||
Name: "success",
|
||||
Interval: probeInterval,
|
||||
Result: true,
|
||||
Status: ProbeStatusSucceeded,
|
||||
RecentResults: []bool{true, true},
|
||||
},
|
||||
PreviousSuccessRatio: 1,
|
||||
@ -498,7 +499,7 @@ func TestProberRunHandler(t *testing.T) {
|
||||
ProbeInfo: ProbeInfo{
|
||||
Name: "failure",
|
||||
Interval: probeInterval,
|
||||
Result: false,
|
||||
Status: ProbeStatusFailed,
|
||||
Error: "error123",
|
||||
RecentResults: []bool{false, false},
|
||||
},
|
||||
|
@ -62,8 +62,9 @@ func (p *Prober) StatusHandler(opts ...statusHandlerOpt) tsweb.ReturnHandlerFunc
|
||||
return func(w http.ResponseWriter, r *http.Request) error {
|
||||
type probeStatus struct {
|
||||
ProbeInfo
|
||||
TimeSinceLast time.Duration
|
||||
Links map[string]template.URL
|
||||
TimeSinceLastStart time.Duration
|
||||
TimeSinceLastEnd time.Duration
|
||||
Links map[string]template.URL
|
||||
}
|
||||
vars := struct {
|
||||
Title string
|
||||
@ -81,12 +82,15 @@ type probeStatus struct {
|
||||
|
||||
for name, info := range p.ProbeInfo() {
|
||||
vars.TotalProbes++
|
||||
if !info.Result {
|
||||
if info.Error != "" {
|
||||
vars.UnhealthyProbes++
|
||||
}
|
||||
s := probeStatus{ProbeInfo: info}
|
||||
if !info.Start.IsZero() {
|
||||
s.TimeSinceLastStart = time.Since(info.Start).Truncate(time.Second)
|
||||
}
|
||||
if !info.End.IsZero() {
|
||||
s.TimeSinceLast = time.Since(info.End).Truncate(time.Second)
|
||||
s.TimeSinceLastEnd = time.Since(info.End).Truncate(time.Second)
|
||||
}
|
||||
for textTpl, urlTpl := range params.probeLinks {
|
||||
text, err := renderTemplate(textTpl, info)
|
||||
|
@ -73,8 +73,9 @@
|
||||
<th>Name</th>
|
||||
<th>Probe Class & Labels</th>
|
||||
<th>Interval</th>
|
||||
<th>Last Attempt</th>
|
||||
<th>Success</th>
|
||||
<th>Last Finished</th>
|
||||
<th>Last Started</th>
|
||||
<th>Status</th>
|
||||
<th>Latency</th>
|
||||
<th>Last Error</th>
|
||||
</tr></thead>
|
||||
@ -85,9 +86,11 @@
|
||||
{{$name}}
|
||||
{{range $text, $url := $probeInfo.Links}}
|
||||
<br/>
|
||||
<button onclick="location.href='{{$url}}';" type="button">
|
||||
{{$text}}
|
||||
</button>
|
||||
{{if not $probeInfo.Continuous}}
|
||||
<button onclick="location.href='{{$url}}';" type="button">
|
||||
{{$text}}
|
||||
</button>
|
||||
{{end}}
|
||||
{{end}}
|
||||
</td>
|
||||
<td>{{$probeInfo.Class}}<br/>
|
||||
@ -97,28 +100,48 @@
|
||||
{{end}}
|
||||
</div>
|
||||
</td>
|
||||
<td>{{$probeInfo.Interval}}</td>
|
||||
<td data-sort="{{$probeInfo.TimeSinceLast.Milliseconds}}">
|
||||
{{if $probeInfo.TimeSinceLast}}
|
||||
{{$probeInfo.TimeSinceLast.String}} ago<br/>
|
||||
<td>
|
||||
{{if $probeInfo.Continuous}}
|
||||
Continuous
|
||||
{{else}}
|
||||
{{$probeInfo.Interval}}
|
||||
{{end}}
|
||||
</td>
|
||||
<td data-sort="{{$probeInfo.TimeSinceLastEnd.Milliseconds}}">
|
||||
{{if $probeInfo.TimeSinceLastEnd}}
|
||||
{{$probeInfo.TimeSinceLastEnd.String}} ago<br/>
|
||||
<span class="small">{{$probeInfo.End.Format "2006-01-02T15:04:05Z07:00"}}</span>
|
||||
{{else}}
|
||||
Never
|
||||
{{end}}
|
||||
</td>
|
||||
<td>
|
||||
{{if $probeInfo.Result}}
|
||||
{{$probeInfo.Result}}
|
||||
<td data-sort="{{$probeInfo.TimeSinceLastStart.Milliseconds}}">
|
||||
{{if $probeInfo.TimeSinceLastStart}}
|
||||
{{$probeInfo.TimeSinceLastStart.String}} ago<br/>
|
||||
<span class="small">{{$probeInfo.Start.Format "2006-01-02T15:04:05Z07:00"}}</span>
|
||||
{{else}}
|
||||
<span class="error">{{$probeInfo.Result}}</span>
|
||||
Never
|
||||
{{end}}
|
||||
</td>
|
||||
<td>
|
||||
{{if $probeInfo.Error}}
|
||||
<span class="error">{{$probeInfo.Status}}</span>
|
||||
{{else}}
|
||||
{{$probeInfo.Status}}
|
||||
{{end}}<br/>
|
||||
<div class="small">Recent: {{$probeInfo.RecentResults}}</div>
|
||||
<div class="small">Mean: {{$probeInfo.RecentSuccessRatio}}</div>
|
||||
{{if not $probeInfo.Continuous}}
|
||||
<div class="small">Recent: {{$probeInfo.RecentResults}}</div>
|
||||
<div class="small">Mean: {{$probeInfo.RecentSuccessRatio}}</div>
|
||||
{{end}}
|
||||
</td>
|
||||
<td data-sort="{{$probeInfo.Latency.Milliseconds}}">
|
||||
{{$probeInfo.Latency.String}}
|
||||
<div class="small">Recent: {{$probeInfo.RecentLatencies}}</div>
|
||||
<div class="small">Median: {{$probeInfo.RecentMedianLatency}}</div>
|
||||
{{if $probeInfo.Continuous}}
|
||||
n/a
|
||||
{{else}}
|
||||
{{$probeInfo.Latency.String}}
|
||||
<div class="small">Recent: {{$probeInfo.RecentLatencies}}</div>
|
||||
<div class="small">Median: {{$probeInfo.RecentMedianLatency}}</div>
|
||||
{{end}}
|
||||
</td>
|
||||
<td class="small">{{$probeInfo.Error}}</td>
|
||||
</tr>
|
||||
|
Loading…
Reference in New Issue
Block a user