Keep a log of pings

This commit is contained in:
Pēteris Caune 2015-07-27 19:46:38 +03:00
parent d8828b2d25
commit 3550218129
9 changed files with 143 additions and 14 deletions

View File

@ -1,16 +1,18 @@
from django.contrib import admin from django.contrib import admin
from hc.api.models import Check from hc.api.models import Check, Ping
@admin.register(Check) @admin.register(Check)
class ChecksAdmin(admin.ModelAdmin): class ChecksAdmin(admin.ModelAdmin):
class Media: class Media:
css = { css = {
'all': ('css/admin/checks.css',) 'all': ('css/admin/checks.css',)
} }
list_display = ("id", "name", "created", "code", "status", "email", "last_ping") list_display = ("id", "name", "created", "code", "status", "email",
"last_ping")
list_select_related = ("user", ) list_select_related = ("user", )
actions = ["send_alert"] actions = ["send_alert"]
@ -24,3 +26,8 @@ class ChecksAdmin(admin.ModelAdmin):
self.message_user(request, "%d alert(s) sent" % qs.count()) self.message_user(request, "%d alert(s) sent" % qs.count())
send_alert.short_description = "Send Alert" send_alert.short_description = "Send Alert"
@admin.register(Ping)
class PingsAdmin(admin.ModelAdmin):
list_display = ("id", "created", "owner", "method", "ua")

View File

@ -0,0 +1,26 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('api', '0006_check_grace'),
]
operations = [
migrations.CreateModel(
name='Ping',
fields=[
('id', models.AutoField(primary_key=True, serialize=False, auto_created=True, verbose_name='ID')),
('created', models.DateTimeField(auto_now_add=True)),
('remote_addr', models.GenericIPAddressField()),
('method', models.CharField(max_length=10)),
('ua', models.CharField(max_length=100, blank=True)),
('body', models.TextField(blank=True)),
('owner', models.ForeignKey(to='api.Check')),
],
),
]

View File

@ -1,3 +1,5 @@
# coding: utf-8
from datetime import timedelta as td from datetime import timedelta as td
import uuid import uuid
@ -24,6 +26,9 @@ class Check(models.Model):
alert_after = models.DateTimeField(null=True, blank=True, editable=False) alert_after = models.DateTimeField(null=True, blank=True, editable=False)
status = models.CharField(max_length=6, choices=STATUSES, default="new") status = models.CharField(max_length=6, choices=STATUSES, default="new")
def __str__(self):
return "Check(%s)" % self.code
def url(self): def url(self):
return settings.PING_ENDPOINT + str(self.code) return settings.PING_ENDPOINT + str(self.code)
@ -53,3 +58,12 @@ class Check(models.Model):
return "grace" return "grace"
return "down" return "down"
class Ping(models.Model):
owner = models.ForeignKey(Check)
created = models.DateTimeField(auto_now_add=True)
remote_addr = models.GenericIPAddressField()
method = models.CharField(max_length=10)
ua = models.CharField(max_length=100, blank=True)
body = models.TextField(blank=True)

View File

@ -5,7 +5,7 @@ from django.http import HttpResponse, HttpResponseBadRequest
from django.utils import timezone from django.utils import timezone
from django.views.decorators.csrf import csrf_exempt from django.views.decorators.csrf import csrf_exempt
from hc.api.models import Check from hc.api.models import Check, Ping
@csrf_exempt @csrf_exempt
@ -21,6 +21,14 @@ def ping(request, code):
check.save() check.save()
ping = Ping(owner=check)
headers = request.META
ping.remote_addr = headers.get("X_REAL_IP", headers["REMOTE_ADDR"])
ping.method = headers["REQUEST_METHOD"]
ping.ua = headers.get("HTTP_USER_AGENT", "")
ping.body = request.body
ping.save()
response = HttpResponse("OK") response = HttpResponse("OK")
response["Access-Control-Allow-Origin"] = "*" response["Access-Control-Allow-Origin"] = "*"
return response return response

View File

@ -3,13 +3,14 @@ from django.conf.urls import url
from hc.front import views from hc.front import views
urlpatterns = [ urlpatterns = [
url(r'^$', views.index, name="hc-index"), url(r'^$', views.index, name="hc-index"),
url(r'^checks/add/$', views.add_check, name="hc-add-check"), url(r'^checks/add/$', views.add_check, name="hc-add-check"),
url(r'^checks/([\w-]+)/name/$', views.update_name, name="hc-update-name"), url(r'^checks/([\w-]+)/name/$', views.update_name, name="hc-update-name"),
url(r'^checks/([\w-]+)/timeout/$', views.update_timeout, name="hc-update-timeout"), url(r'^checks/([\w-]+)/timeout/$', views.update_timeout, name="hc-update-timeout"),
url(r'^checks/([\w-]+)/email/$', views.email_preview), url(r'^checks/([\w-]+)/email/$', views.email_preview),
url(r'^checks/([\w-]+)/remove/$', views.remove, name="hc-remove-check"), url(r'^checks/([\w-]+)/remove/$', views.remove, name="hc-remove-check"),
url(r'^pricing/$', views.pricing, name="hc-pricing"), url(r'^checks/([\w-]+)/log/$', views.log, name="hc-log"),
url(r'^docs/$', views.docs, name="hc-docs"), url(r'^pricing/$', views.pricing, name="hc-pricing"),
url(r'^about/$', views.about, name="hc-about"), url(r'^docs/$', views.docs, name="hc-docs"),
url(r'^about/$', views.about, name="hc-about"),
] ]

View File

@ -6,7 +6,7 @@ from django.http import HttpResponseForbidden
from django.shortcuts import redirect, render from django.shortcuts import redirect, render
from django.utils import timezone from django.utils import timezone
from hc.api.models import Check from hc.api.models import Check, Ping
from hc.front.forms import TimeoutForm from hc.front.forms import TimeoutForm
@ -147,3 +147,21 @@ def remove(request, code):
check.delete() check.delete()
return redirect("hc-index") return redirect("hc-index")
@login_required
def log(request, code):
check = Check.objects.get(code=code)
if check.user != request.user:
return HttpResponseForbidden()
pings = Ping.objects.filter(owner=check).order_by("-created")[:100]
ctx = {
"check": check,
"pings": pings
}
return render(request, "front/log.html", ctx)

View File

@ -131,7 +131,7 @@ table.table tr > th.th-name {
display: block; display: block;
} }
.my-checks-name:hover { #checks-table tr:hover .my-checks-name {
border: 1px dotted #AAA; border: 1px dotted #AAA;
} }
@ -142,6 +142,7 @@ table.table tr > th.th-name {
.url-cell { .url-cell {
font-size: small; font-size: small;
position: relative;
} }
td.inactive .popover { td.inactive .popover {
@ -167,7 +168,7 @@ td.inactive .popover {
display: block; display: block;
} }
.timeout_grace:hover { #checks-table tr:hover .timeout_grace {
border: 1px dotted #AAA; border: 1px dotted #AAA;
} }
@ -243,3 +244,8 @@ tr:hover .check-menu {
font-weight: bold; font-weight: bold;
} }
/* Log */
.log-table .remote-addr, .log-table .ua {
font-family: monospace;
}

42
templates/front/log.html Normal file
View File

@ -0,0 +1,42 @@
{% extends "base.html" %}
{% load compress humanize staticfiles hc_extras %}
{% block title %}My Checks - healthchecks.io{% endblock %}
{% block content %}
<div class="row">
<div class="col-sm-12">
<h1>Log for {{ check.name|default:check.code }}</h1>
{% if pings %}
<table class="table table-striped log-table">
<tr>
<th>Time</th>
<th>Remote IP</th>
<th>Method</th>
<th>User Agent</th>
</tr>
{% for ping in pings %}
<tr>
<td>
<span
data-toggle="tooltip"
title="{{ ping.created }}">
{{ ping.created }}
</span>
</td>
<td class="remote-addr">{{ ping.remote_addr }}</td>
<td class="method">
<span class="label label-default">{{ ping.method }}</span>
</td>
<td class="ua">{{ ping.ua }}</td>
</tr>
{% endfor %}
</table>
{% else %}
<div class="alert alert-info">Log is empty. This check has not received any pings yet.</div>
{% endif %}
</div>
</div>
{% endblock %}

View File

@ -75,6 +75,13 @@
<span class="glyphicon glyphicon-cog" aria-hidden="true"></span> <span class="glyphicon glyphicon-cog" aria-hidden="true"></span>
</button> </button>
<ul class="dropdown-menu"> <ul class="dropdown-menu">
<li>
<a href="{% url 'hc-log' check.code %}">
<span class="glyphicon glyphicon-time"></span>
Log
</a>
</li>
<li role="separator" class="divider"></li>
<li> <li>
<a href="#" class="check-menu-remove" <a href="#" class="check-menu-remove"
data-name="{{ check.name|default:check.code }}" data-name="{{ check.name|default:check.code }}"