mirror of
https://github.com/healthchecks/healthchecks.git
synced 2025-04-10 23:40:11 +00:00
Switch back to using integer timestamps in the log page
The live-updating code still needs float timestamps, but we only need them for the most recent event (so we know the lower threshold for fetching new events). We now send the float timestamp separately: * in the `/log/` view, we put it in HTML content, in a <script> tag * in the `/log_events/` view we put it in response header The main benefit of this is smaller response sizes for the `/log/` and `/log_events/` views.
This commit is contained in:
parent
d7948d9939
commit
27c065230a
6 changed files with 67 additions and 50 deletions
hc/front
static/js
templates/front
|
@ -185,8 +185,8 @@ def now_isoformat() -> str:
|
|||
|
||||
|
||||
@register.filter
|
||||
def timestamp(dt: datetime) -> float:
|
||||
return dt.timestamp()
|
||||
def timestamp(dt: datetime) -> int:
|
||||
return int(dt.timestamp())
|
||||
|
||||
|
||||
@register.filter
|
||||
|
|
|
@ -90,44 +90,6 @@ class LogTestCase(BaseTestCase):
|
|||
r = self.client.get(self.url)
|
||||
self.assertEqual(r.status_code, 404)
|
||||
|
||||
def test_it_shows_email_notification(self) -> None:
|
||||
ch = Channel(kind="email", project=self.project)
|
||||
ch.value = json.dumps({"value": "alice@example.org", "up": True, "down": True})
|
||||
ch.save()
|
||||
|
||||
Notification(owner=self.check, channel=ch, check_status="down").save()
|
||||
|
||||
self.client.login(username="alice@example.org", password="password")
|
||||
r = self.client.get(self.url)
|
||||
self.assertContains(r, "Sent email to alice@example.org", status_code=200)
|
||||
|
||||
def test_it_shows_pushover_notification(self) -> None:
|
||||
ch = Channel.objects.create(kind="po", project=self.project)
|
||||
|
||||
Notification(owner=self.check, channel=ch, check_status="down").save()
|
||||
|
||||
self.client.login(username="alice@example.org", password="password")
|
||||
r = self.client.get(self.url)
|
||||
self.assertContains(r, "Sent a Pushover notification", status_code=200)
|
||||
|
||||
def test_it_shows_webhook_notification(self) -> None:
|
||||
ch = Channel(kind="webhook", project=self.project)
|
||||
ch.value = json.dumps(
|
||||
{
|
||||
"method_down": "GET",
|
||||
"url_down": "foo/$NAME",
|
||||
"body_down": "",
|
||||
"headers_down": {},
|
||||
}
|
||||
)
|
||||
ch.save()
|
||||
|
||||
Notification(owner=self.check, channel=ch, check_status="down").save()
|
||||
|
||||
self.client.login(username="alice@example.org", password="password")
|
||||
r = self.client.get(self.url)
|
||||
self.assertContains(r, "Called webhook foo/$NAME", status_code=200)
|
||||
|
||||
def test_it_shows_ignored_nonzero_exitstatus(self) -> None:
|
||||
self.ping.kind = "ign"
|
||||
self.ping.exitstatus = 123
|
||||
|
|
|
@ -141,3 +141,41 @@ class LogTestCase(BaseTestCase):
|
|||
r = self.client.get(self.url(flip=False))
|
||||
self.assertContains(r, "hello world")
|
||||
self.assertNotContains(r, "new ➔ down")
|
||||
|
||||
def test_it_shows_email_notification(self) -> None:
|
||||
ch = Channel(kind="email", project=self.project)
|
||||
ch.value = json.dumps({"value": "alice@example.org", "up": True, "down": True})
|
||||
ch.save()
|
||||
|
||||
Notification(owner=self.check, channel=ch, check_status="down").save()
|
||||
|
||||
self.client.login(username="alice@example.org", password="password")
|
||||
r = self.client.get(self.url())
|
||||
self.assertContains(r, "Sent email to alice@example.org", status_code=200)
|
||||
|
||||
def test_it_shows_pushover_notification(self) -> None:
|
||||
ch = Channel.objects.create(kind="po", project=self.project)
|
||||
|
||||
Notification(owner=self.check, channel=ch, check_status="down").save()
|
||||
|
||||
self.client.login(username="alice@example.org", password="password")
|
||||
r = self.client.get(self.url())
|
||||
self.assertContains(r, "Sent a Pushover notification", status_code=200)
|
||||
|
||||
def test_it_shows_webhook_notification(self) -> None:
|
||||
ch = Channel(kind="webhook", project=self.project)
|
||||
ch.value = json.dumps(
|
||||
{
|
||||
"method_down": "GET",
|
||||
"url_down": "foo/$NAME",
|
||||
"body_down": "",
|
||||
"headers_down": {},
|
||||
}
|
||||
)
|
||||
ch.save()
|
||||
|
||||
Notification(owner=self.check, channel=ch, check_status="down").save()
|
||||
|
||||
self.client.login(username="alice@example.org", password="password")
|
||||
r = self.client.get(self.url())
|
||||
self.assertContains(r, "Called webhook foo/$NAME", status_code=200)
|
||||
|
|
|
@ -920,16 +920,23 @@ def log(request: AuthenticatedHttpRequest, code: UUID) -> HttpResponse:
|
|||
if oldest_ping:
|
||||
smin = max(smin, oldest_ping.created)
|
||||
|
||||
events = _get_events(check, 1000, start=smin, end=smax)
|
||||
ctx = {
|
||||
"page": "log",
|
||||
"project": check.project,
|
||||
"check": check,
|
||||
"min": smin,
|
||||
"max": smax,
|
||||
"events": _get_events(check, 1000, start=smin, end=smax),
|
||||
"events": events,
|
||||
"oldest_ping": oldest_ping,
|
||||
}
|
||||
|
||||
if events:
|
||||
# A full precision timestamp of the most recent event.
|
||||
# This will be used client-side for fetching live updates to specify
|
||||
# "return any events after *this* point".
|
||||
ctx["last_event_timestamp"] = events[0].created.timestamp()
|
||||
|
||||
return render(request, "front/log.html", ctx)
|
||||
|
||||
|
||||
|
@ -2750,11 +2757,19 @@ def log_events(request: AuthenticatedHttpRequest, code: UUID) -> HttpResponse:
|
|||
if oldest_ping:
|
||||
start = max(start, oldest_ping.created)
|
||||
|
||||
events = _get_events(check, 1000, start=start, end=end, kinds=form.kinds())
|
||||
ctx = {
|
||||
"events": _get_events(check, 1000, start=start, end=end, kinds=form.kinds()),
|
||||
"events": events,
|
||||
"describe_body": True,
|
||||
}
|
||||
return render(request, "front/log_rows.html", ctx)
|
||||
response = render(request, "front/log_rows.html", ctx)
|
||||
|
||||
if events:
|
||||
# Include a full precision timestamp of the most recent event in a
|
||||
# response header. This will be used client-side for fetching live updates
|
||||
# to specify "return any events after *this* point".
|
||||
response["X-Last-Event-Timestamp"] = str(events[0].created.timestamp())
|
||||
return response
|
||||
|
||||
|
||||
# Forks: add custom views after this line
|
||||
|
|
|
@ -87,6 +87,7 @@ $(function () {
|
|||
// Once it's ready, set it to visible:
|
||||
$("#log").css("visibility", "visible");
|
||||
|
||||
var lastUpdated = document.getElementById("last-event-timestamp").textContent;
|
||||
function fetchNewEvents() {
|
||||
// Do not fetch updates if the slider is not set to "now"
|
||||
// or there's an AJAX request in flight
|
||||
|
@ -97,19 +98,19 @@ $(function () {
|
|||
var url = document.getElementById("log").dataset.refreshUrl;
|
||||
var qs = $("#filters").serialize();
|
||||
|
||||
var firstRow = $("#log tr").get(0);
|
||||
if (firstRow) {
|
||||
qs += "&u=" + firstRow.dataset.dt;
|
||||
if (lastUpdated) {
|
||||
qs += "&u=" + lastUpdated;
|
||||
}
|
||||
|
||||
activeRequest = $.ajax({
|
||||
url: url + "?" + qs,
|
||||
timeout: 2000,
|
||||
success: function(data) {
|
||||
success: function(data, textStatus, xhr) {
|
||||
activeRequest = null;
|
||||
if (!data)
|
||||
return;
|
||||
|
||||
lastUpdated = xhr.getResponseHeader("X-Last-Event-Timestamp");
|
||||
var tbody = document.createElement("tbody");
|
||||
tbody.setAttribute("class", "new");
|
||||
tbody.innerHTML = data;
|
||||
|
|
|
@ -71,9 +71,9 @@
|
|||
id="end"
|
||||
type="range"
|
||||
name="end"
|
||||
min="{{ min|timestamp|floatformat:"0" }}"
|
||||
max="{{ max|timestamp|floatformat:"0" }}"
|
||||
value="{{ max|timestamp|floatformat:"0" }}"
|
||||
min="{{ min|timestamp }}"
|
||||
max="{{ max|timestamp }}"
|
||||
value="{{ max|timestamp }}"
|
||||
autocomplete="off">
|
||||
|
||||
<p id="end-help" class="text-muted">
|
||||
|
@ -123,6 +123,7 @@
|
|||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script id="last-event-timestamp" type="data">{{ last_event_timestamp }}</script>
|
||||
{% compress js %}
|
||||
<script src="{% static 'js/moment.min.js' %}"></script>
|
||||
<script src="{% static 'js/moment-timezone-with-data-10-year-range.min.js' %}"></script>
|
||||
|
|
Loading…
Add table
Reference in a new issue