0
0
Fork 0
mirror of https://github.com/healthchecks/healthchecks.git synced 2025-04-07 14:15:34 +00:00

Update Check.downtimes() to return a list of namedtuples

This way it should be easier to add extra fields like uptime
to the returned data structure.
This commit is contained in:
Pēteris Caune 2023-09-27 10:18:52 +03:00
parent e48d361331
commit f0085933c3
No known key found for this signature in database
GPG key ID: E28D7679E9A9EDE2
4 changed files with 35 additions and 34 deletions

View file

@ -7,7 +7,7 @@ import uuid
from datetime import datetime
from datetime import timedelta as td
from datetime import timezone
from typing import Any, TypedDict
from typing import Any, NamedTuple, TypedDict
from urllib.parse import urlencode
from zoneinfo import ZoneInfo
@ -130,6 +130,12 @@ class CheckDict(TypedDict, total=False):
tz: str
class DowntimeRecord(NamedTuple):
boundary: datetime
duration: td
count: int | None
class DowntimeSummary(object):
def __init__(self, boundaries: list[datetime]) -> None:
self.boundaries = list(sorted(boundaries, reverse=True))
@ -143,8 +149,12 @@ class DowntimeSummary(object):
self.counts[i] += 1
return
def as_tuples(self) -> zip[tuple[datetime, td, int]]:
return zip(self.boundaries, self.durations, self.counts)
def as_records(self) -> list[DowntimeRecord]:
result = []
for b, d, c in zip(self.boundaries, self.durations, self.counts):
result.append(DowntimeRecord(b, d, c))
return result
class Check(models.Model):
@ -485,9 +495,7 @@ class Check(models.Model):
threshold = self.n_pings - self.project.owner_profile.ping_log_limit
return self.ping_set.filter(n__gt=threshold)
def downtimes_by_boundary(
self, boundaries: list[datetime]
) -> list[tuple[datetime, td | None, int | None]]:
def downtimes_by_boundary(self, boundaries: list[datetime]) -> list[DowntimeRecord]:
"""Calculate downtime counts and durations for the given time intervals.
Returns a list of (datetime, downtime_in_secs, number_of_outages) tuples
@ -517,24 +525,21 @@ class Check(models.Model):
if prev_status != "---":
status = prev_status
# Convert to a list of tuples and set counters to None
# for intervals when the check didn't exist yet
# Set count to None for intervals when the check didn't exist yet
prev_boundary = None
result: list[tuple[datetime, td | None, int | None]] = []
for triple in summary.as_tuples():
result: list[DowntimeRecord] = []
for record in summary.as_records():
if prev_boundary and self.created > prev_boundary:
result.append((triple[0], None, None))
result.append(DowntimeRecord(record.boundary, record.duration, None))
continue
prev_boundary = triple[0]
result.append(triple)
prev_boundary = record.boundary
result.append(record)
result.sort()
return result
def downtimes(
self, months: int, tz: str
) -> list[tuple[datetime, td | None, int | None]]:
def downtimes(self, months: int, tz: str) -> list[DowntimeRecord]:
boundaries = month_boundaries(months, tz)
return self.downtimes_by_boundary(boundaries)

View file

@ -301,16 +301,13 @@ class CheckModelTestCase(BaseTestCase):
nov, dec, jan = check.downtimes(3, "UTC")
# Nov. 2019
self.assertIsNone(nov[1])
self.assertIsNone(nov[2])
self.assertIsNone(nov.count)
# Dec. 2019
self.assertIsNone(dec[1])
self.assertIsNone(dec[2])
self.assertIsNone(dec.count)
# Jan. 2020
self.assertEqual(jan[1], td())
self.assertEqual(jan[2], 0)
self.assertEqual(jan.count, 0)
@override_settings(S3_BUCKET=None)
def test_it_prunes(self) -> None:

View file

@ -64,16 +64,16 @@
</table>
{% endif %}
</td>
{% for boundary, seconds, count in check.past_downtimes %}
{% if count %}
{% for d in check.past_downtimes %}
{% if d.count %}
<td style="border-top: 1px solid #EDEFF2; padding: 16px 8px; font-family: Helvetica, Arial, sans-serif;">
{{ count }}&nbsp;downtime{{ count|pluralize }},
{{ d.count }}&nbsp;downtime{{ d.count|pluralize }},
<br />
{{ seconds|hc_approx_duration }} total
{{ d.duration|hc_approx_duration }} total
</td>
{% else %}
<td style="border-top: 1px solid #EDEFF2; padding: 16px 8px; font-family: Helvetica, Arial, sans-serif; color: #9BA2AB;">
{% if count is None %}
{% if d.count is None %}
{% comment %} The check didn't exist yet {% endcomment %}
{% else %}
All good!

View file

@ -1,14 +1,13 @@
{% load hc_extras tz %}
{% timezone tz %}
<table id="downtimes" class="table">
{% for boundary, down_duration_secs, count in downtimes reversed %}
{% for d in downtimes reversed %}
<tr>
<th>{{ boundary|date:"N Y"}}</th>
<th>{{ d.boundary|date:"N Y"}}</th>
<td>
{% if count %}
{{ count }} downtime{{ count|pluralize }},
{{ down_duration_secs|hc_approx_duration }} total
{% elif count is None %}
{% if d.count %}
{{ d.count }} downtime{{ d.count|pluralize }}, {{ d.duration|hc_approx_duration }} total
{% elif d.count is None %}
{% else %}
All good!
@ -17,4 +16,4 @@
</tr>
{% endfor %}
</table>
{% endtimezone %}
{% endtimezone %}