Log: instead of timeline, show placeholders for "expected but not received" pings.

This commit is contained in:
Pēteris Caune 2016-01-03 02:43:56 +02:00
parent 4e12193d8c
commit f178981334
3 changed files with 56 additions and 85 deletions

View File

@ -1,5 +1,6 @@
from collections import Counter from collections import Counter
from datetime import timedelta as td from datetime import timedelta as td
from itertools import tee
from django.conf import settings from django.conf import settings
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
@ -15,6 +16,14 @@ from hc.api.models import Channel, Check, Ping
from hc.front.forms import AddChannelForm, NameTagsForm, TimeoutForm from hc.front.forms import AddChannelForm, NameTagsForm, TimeoutForm
# from itertools recipes:
def pairwise(iterable):
"s -> (s0,s1), (s1,s2), (s2, s3), ..."
a, b = tee(iterable)
next(b, None)
return zip(a, b)
@login_required @login_required
def my_checks(request): def my_checks(request):
checks = Check.objects.filter(user=request.user).order_by("created") checks = Check.objects.filter(user=request.user).order_by("created")
@ -185,30 +194,31 @@ def log(request, code):
profile = Profile.objects.for_user(request.user) profile = Profile.objects.for_user(request.user)
limit = profile.ping_log_limit limit = profile.ping_log_limit
pings = Ping.objects.filter(owner=check).order_by("-created")[:limit] pings = Ping.objects.filter(owner=check).order_by("created")[:limit]
pings = list(pings)
# Add a dummy ping object at the end. We iterate over *pairs* of pings
# and don't want to handle a special case of a check with a single ping.
pings.append(Ping(created=timezone.now()))
# Now go through pings, calculate time gaps, and decorate # Now go through pings, calculate time gaps, and decorate
# the pings list for convenient use in template # the pings list for convenient use in template
wrapped = [] wrapped = []
now = timezone.now()
for i, ping in enumerate(pings):
prev = now if i == 0 else pings[i - 1].created
duration = prev - ping.created early = False
if duration > check.timeout: for older, newer in pairwise(pings):
downtime = {"prev_date": prev, "date": ping.created} wrapped.append({"ping": older, "early": early})
if i > 0:
wrapped[-1]["status"] = "late"
if duration > check.timeout + check.grace: # Fill in "missed ping" placeholders:
downtime["down"] = True expected_date = older.created + check.timeout
if i > 0: while expected_date + check.grace < newer.created:
wrapped[-1]["status"] = "down" wrapped.append({"placeholder_date": expected_date})
expected_date = expected_date + check.timeout
wrapped.append(downtime) # Prepare early flag for next ping to come
early = older.created + check.timeout > newer.created + check.grace
wrapped.append({"ping": ping})
wrapped.reverse()
ctx = { ctx = {
"check": check, "check": check,
"pings": wrapped "pings": wrapped

View File

@ -5,7 +5,6 @@
#log td { #log td {
color: #444; color: #444;
padding: 16px 8px;
position: relative; position: relative;
border: 0; border: 0;
border-bottom: 1px solid #E5E5E5; border-bottom: 1px solid #E5E5E5;
@ -15,7 +14,7 @@
white-space: nowrap; white-space: nowrap;
} }
#log .date { #log .date, #log .time {
display: inline-block; display: inline-block;
width: 70px; width: 70px;
} }
@ -36,52 +35,12 @@
font-size: 11px; font-size: 11px;
} }
#log .ok {
#log .bullet { color: #5cb85c;
position: absolute;
display: block;
top: 50%;
margin-top: -6px;
left: 0;
width: 12px;
height: 12px;
border: 2px solid #FFF;
border-radius: 6px;
background: #376f37;
} }
#log .tl { #log tr.missing td {
position: absolute;
left: 4px;
width: 4px;
background: #5cb85c;
}
#log .top {
top: 0;
height: 50%;
}
#log .bottom {
top: 50%;
height: 50%;
}
#log .full-down {
top: 0;
height: 100%;
background: #d9534f;
}
#log .down { background: #d9534f; }
#log .late { background: #f0ad4e; }
#log .tl-cell {
border: 0;
}
#log .downtime-cell {
border: 0;
font-size: small;
color: #d9534f; color: #d9534f;
} background: #fff3f2;
}

View File

@ -20,7 +20,6 @@
Note: Dates and times are displayed in <strong>UTC</strong>. Note: Dates and times are displayed in <strong>UTC</strong>.
</p> </p>
<div class="table-responsive"> <div class="table-responsive">
<table class="table" id="log"> <table class="table" id="log">
<tr> <tr>
@ -35,11 +34,9 @@
</tr> </tr>
{% for record in pings %} {% for record in pings %}
{% if record.ping %} {% if record.ping %}
<tr> <tr class="ok {% if record.early %} early {% endif %}">
<td class="tl-cell"> <td class="icon">
<div class="tl top"></div> <span class="glyphicon glyphicon-ok ok"></span>
<div class="tl bottom {{ record.status }}"></div>
<div class="bullet"></div>
</td> </td>
<td class="datetime"> <td class="datetime">
<div> <div>
@ -49,6 +46,9 @@
<span class="time"> <span class="time">
{{ record.ping.created|date:"H:i" }} {{ record.ping.created|date:"H:i" }}
</span> </span>
{% if record.early %}
<span class="label label-tag">early</span>
{% endif %}
</div> </div>
</td> </td>
<td class="ip"> <td class="ip">
@ -62,22 +62,24 @@
{{ record.ping.ua }} {{ record.ping.ua }}
</td> </td>
</tr> </tr>
{% else %}
{% if record.down %}
<tr>
<td class="tl-cell">
<div class="tl full-down"></div>
</td>
<td class="downtime-cell" colspan="4">
<p>No ping received for {{ record.date|timesince:record.prev_date }}</p>
</td>
</tr>
{% endif %} {% endif %}
<tr> {% if record.placeholder_date %}
<td class="tl-cell"> <tr class="missing">
<div class="tl top late"></div> <td class="icon">
<div class="tl bottom"></div> <span class="glyphicon glyphicon-remove"></span>
</td>
<td class="datetime">
<div>
<span class="date">
{{ record.placeholder_date|date:"N j" }}
</span>
<span class="time">
{{ record.placeholder_date|date:"H:i" }}
</span>
</div>
</td>
<td colspan="4">
<small>Ping expected but not received</small>
</td> </td>
</tr> </tr>
{% endif %} {% endif %}