Browse Source

Keep a log of pings

pull/7/head
Pēteris Caune 9 years ago
parent
commit
3550218129
9 changed files with 143 additions and 14 deletions
  1. +9
    -2
      hc/api/admin.py
  2. +26
    -0
      hc/api/migrations/0007_ping.py
  3. +14
    -0
      hc/api/models.py
  4. +9
    -1
      hc/api/views.py
  5. +9
    -8
      hc/front/urls.py
  6. +19
    -1
      hc/front/views.py
  7. +8
    -2
      static/css/style.css
  8. +42
    -0
      templates/front/log.html
  9. +7
    -0
      templates/front/my_checks.html

+ 9
- 2
hc/api/admin.py 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")

+ 26
- 0
hc/api/migrations/0007_ping.py 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')),
],
),
]

+ 14
- 0
hc/api/models.py 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)

+ 9
- 1
hc/api/views.py 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


+ 9
- 8
hc/front/urls.py 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'^checks/add/$', views.add_check, name="hc-add-check"),
url(r'^checks/([\w-]+)/name/$', views.update_name, name="hc-update-name"),
url(r'^$', views.index, name="hc-index"),
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-]+)/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-]+)/remove/$', views.remove, name="hc-remove-check"),
url(r'^pricing/$', views.pricing, name="hc-pricing"),
url(r'^docs/$', views.docs, name="hc-docs"),
url(r'^about/$', views.about, name="hc-about"),
url(r'^checks/([\w-]+)/email/$', views.email_preview),
url(r'^checks/([\w-]+)/remove/$', views.remove, name="hc-remove-check"),
url(r'^checks/([\w-]+)/log/$', views.log, name="hc-log"),
url(r'^pricing/$', views.pricing, name="hc-pricing"),
url(r'^docs/$', views.docs, name="hc-docs"),
url(r'^about/$', views.about, name="hc-about"),
] ]

+ 19
- 1
hc/front/views.py 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)

+ 8
- 2
static/css/style.css 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
- 0
templates/front/log.html 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 %}

+ 7
- 0
templates/front/my_checks.html 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 }}"


Loading…
Cancel
Save