forked from GithubBackups/healthchecks
Show the number of downtimes and total downtime minutes in "Check Details" page.
This commit is contained in:
parent
b7320b1b69
commit
b2ebce6cf9
@ -4,7 +4,8 @@ All notable changes to this project will be documented in this file.
|
||||
## Unreleased
|
||||
|
||||
### Improvements
|
||||
- Show the number of outages and total downtime in monthly reports. (#104)
|
||||
- Show the number of downtimes and total downtime minutes in monthly reports (#104)
|
||||
- Show the number of downtimes and total downtime minutes in "Check Details" page
|
||||
|
||||
|
||||
## 1.8.0 - 2019-07-08
|
||||
@ -13,8 +14,8 @@ All notable changes to this project will be documented in this file.
|
||||
- Add the `prunetokenbucket` management command
|
||||
- Show check counts in JSON "badges" (#251)
|
||||
- Webhooks support HTTP PUT (#249)
|
||||
- Webhooks can use different req. bodies and headers for "up" and "down" events. (#249)
|
||||
- Show check's code instead of full URL on 992px - 1200px wide screens. (#253)
|
||||
- Webhooks can use different req. bodies and headers for "up" and "down" events (#249)
|
||||
- Show check's code instead of full URL on 992px - 1200px wide screens (#253)
|
||||
- Add WhatsApp integration (uses Twilio same as the SMS integration)
|
||||
- Webhooks support the $TAGS placeholder
|
||||
- Don't include ping URLs in API responses when the read-only key is used
|
||||
@ -59,7 +60,7 @@ All notable changes to this project will be documented in this file.
|
||||
|
||||
### Improvements
|
||||
- Database schema: add uniqueness constraint to Check.code
|
||||
- Database schema: add Ping.kind field. Remove "start" and "fail" fields.
|
||||
- Database schema: add Ping.kind field. Remove "start" and "fail" fields
|
||||
- Add "Email Settings..." dialog and "Subject Must Contain" setting
|
||||
- Database schema: add the Project model
|
||||
- Move project-specific settings to a new "Project Settings" page
|
||||
|
@ -246,8 +246,8 @@ class Check(models.Model):
|
||||
ping.body = body[:10000]
|
||||
ping.save()
|
||||
|
||||
def outages_by_month(self, months=2):
|
||||
""" Calculate the number of outages and downtime minutes per month.
|
||||
def downtimes(self, months=2):
|
||||
""" Calculate the number of downtimes and downtime minutes per month.
|
||||
|
||||
Returns a list of (datetime, downtime_in_secs, number_of_outages) tuples.
|
||||
|
||||
|
@ -166,24 +166,24 @@ class CheckModelTestCase(BaseTestCase):
|
||||
d = check.to_dict()
|
||||
self.assertEqual(d["next_ping"], "2000-01-01T01:00:00+00:00")
|
||||
|
||||
def test_outages_by_month_handles_no_flips(self):
|
||||
def test_downtimes_handles_no_flips(self):
|
||||
check = Check.objects.create(project=self.project)
|
||||
r = check.outages_by_month(10)
|
||||
r = check.downtimes(10)
|
||||
self.assertEqual(len(r), 10)
|
||||
for dt, downtime, outages in r:
|
||||
self.assertEqual(downtime.total_seconds(), 0)
|
||||
self.assertEqual(outages, 0)
|
||||
|
||||
def test_outages_by_month_handles_currently_down_check(self):
|
||||
def test_downtimes_handles_currently_down_check(self):
|
||||
check = Check.objects.create(project=self.project, status="down")
|
||||
|
||||
r = check.outages_by_month(10)
|
||||
r = check.downtimes(10)
|
||||
self.assertEqual(len(r), 10)
|
||||
for dt, downtime, outages in r:
|
||||
self.assertEqual(outages, 1)
|
||||
|
||||
@patch("hc.api.models.timezone.now")
|
||||
def test_outages_by_month_handles_flip_one_day_ago(self, mock_now):
|
||||
def test_downtimes_handles_flip_one_day_ago(self, mock_now):
|
||||
mock_now.return_value = datetime(2019, 7, 19, tzinfo=timezone.utc)
|
||||
|
||||
check = Check.objects.create(project=self.project, status="down")
|
||||
@ -193,7 +193,7 @@ class CheckModelTestCase(BaseTestCase):
|
||||
flip.new_status = "down"
|
||||
flip.save()
|
||||
|
||||
r = check.outages_by_month(10)
|
||||
r = check.downtimes(10)
|
||||
self.assertEqual(len(r), 10)
|
||||
for dt, downtime, outages in r:
|
||||
if dt.month == 7:
|
||||
@ -204,7 +204,7 @@ class CheckModelTestCase(BaseTestCase):
|
||||
self.assertEqual(outages, 0)
|
||||
|
||||
@patch("hc.api.models.timezone.now")
|
||||
def test_outages_by_month_handles_flip_two_months_ago(self, mock_now):
|
||||
def test_downtimes_handles_flip_two_months_ago(self, mock_now):
|
||||
mock_now.return_value = datetime(2019, 7, 19, tzinfo=timezone.utc)
|
||||
|
||||
check = Check.objects.create(project=self.project, status="down")
|
||||
@ -214,7 +214,7 @@ class CheckModelTestCase(BaseTestCase):
|
||||
flip.new_status = "down"
|
||||
flip.save()
|
||||
|
||||
r = check.outages_by_month(10)
|
||||
r = check.downtimes(10)
|
||||
self.assertEqual(len(r), 10)
|
||||
for dt, downtime, outages in r:
|
||||
if dt.month == 7:
|
||||
|
@ -58,6 +58,7 @@ VALID_SORT_VALUES = ("name", "-name", "last_ping", "-last_ping", "created")
|
||||
STATUS_TEXT_TMPL = get_template("front/log_status_text.html")
|
||||
LAST_PING_TMPL = get_template("front/last_ping_cell.html")
|
||||
EVENTS_TMPL = get_template("front/details_events.html")
|
||||
DOWNTIMES_TMPL = get_template("front/details_downtimes.html")
|
||||
ONE_HOUR = td(hours=1)
|
||||
TWELVE_HOURS = td(hours=12)
|
||||
|
||||
@ -474,6 +475,7 @@ def details(request, code):
|
||||
"check": check,
|
||||
"channels": channels,
|
||||
"timezones": pytz.all_timezones,
|
||||
"downtimes": check.downtimes(months=3),
|
||||
}
|
||||
|
||||
return render(request, "front/details.html", ctx)
|
||||
@ -523,6 +525,7 @@ def status_single(request, code):
|
||||
|
||||
if updated != request.GET.get("u"):
|
||||
doc["events"] = EVENTS_TMPL.render({"check": check, "events": events})
|
||||
doc["downtimes"] = DOWNTIMES_TMPL.render({"downtimes": check.downtimes(3)})
|
||||
|
||||
return JsonResponse(doc)
|
||||
|
||||
|
@ -80,3 +80,18 @@
|
||||
color: #d43f3a;
|
||||
background: #FFF;
|
||||
}
|
||||
|
||||
#downtimes table {
|
||||
width: 350px;
|
||||
}
|
||||
|
||||
#downtimes tr:first-child td, #downtimes tr:first-child th {
|
||||
border-top: 0;
|
||||
}
|
||||
|
||||
#downtimes th {
|
||||
width: 100px;
|
||||
text-align: right;
|
||||
font-weight: normal;
|
||||
color: #888;
|
||||
}
|
||||
|
@ -66,6 +66,10 @@ $(function () {
|
||||
switchDateFormat(lastFormat);
|
||||
}
|
||||
|
||||
if (data.downtimes) {
|
||||
$("#downtimes").html(data.downtimes);
|
||||
}
|
||||
|
||||
if (document.title != data.title) {
|
||||
document.title = data.title;
|
||||
}
|
||||
|
@ -62,10 +62,10 @@
|
||||
</table>
|
||||
{% endif %}
|
||||
</td>
|
||||
{% for boundary, seconds, count in check.outages_by_month %}
|
||||
{% for boundary, seconds, count in check.downtimes %}
|
||||
{% if count %}
|
||||
<td style="border-top: 1px solid #EDEFF2; padding: 16px 8px; font-family: Helvetica, Arial, sans-serif;">
|
||||
{{ count }} outage{{ count|pluralize }},
|
||||
{{ count }} downtime{{ count|pluralize }},
|
||||
<br />
|
||||
{{ seconds|hc_approx_duration }} total
|
||||
</td>
|
||||
|
@ -87,8 +87,14 @@
|
||||
<td>
|
||||
<span id="log-status-icon" class="status icon-{{ check.get_status }}"></span>
|
||||
</td>
|
||||
<td id="log-status-text">
|
||||
{% include "front/log_status_text.html" %}
|
||||
<td >
|
||||
<p id="log-status-text">{% include "front/log_status_text.html" %}</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td id="downtimes">
|
||||
{% include "front/details_downtimes.html" %}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
@ -196,7 +202,6 @@
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div id="events" class="col-sm-7">
|
||||
<h2>
|
||||
Log
|
||||
|
16
templates/front/details_downtimes.html
Normal file
16
templates/front/details_downtimes.html
Normal file
@ -0,0 +1,16 @@
|
||||
{% load hc_extras %}
|
||||
<table class="table">
|
||||
{% for boundary, seconds, count in downtimes reversed %}
|
||||
<tr>
|
||||
<th>{{ boundary|date:"N Y"}}</th>
|
||||
<td>
|
||||
{% if count %}
|
||||
{{ count }} downtime{{ count|pluralize }},
|
||||
{{ seconds|hc_approx_duration }} total
|
||||
{% else %}
|
||||
All good!
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
Loading…
x
Reference in New Issue
Block a user