diff --git a/hc/api/transports.py b/hc/api/transports.py index fbcb4be3..53e0a4e6 100644 --- a/hc/api/transports.py +++ b/hc/api/transports.py @@ -161,6 +161,7 @@ class OpsGenie(HttpTransport): return self.post(url, payload) + class PagerDuty(HttpTransport): URL = "https://events.pagerduty.com/generic/2010-04-15/create_event.json" diff --git a/hc/front/forms.py b/hc/front/forms.py index 8bcb112f..daeca968 100644 --- a/hc/front/forms.py +++ b/hc/front/forms.py @@ -1,6 +1,6 @@ from django import forms from hc.front.validators import WebhookValidator -from hc.api.models import CHECK_KINDS, Channel +from hc.api.models import CHECK_KINDS class NameTagsForm(forms.Form): @@ -26,17 +26,6 @@ class TimeoutForm(forms.Form): grace = forms.IntegerField(min_value=60, max_value=2592000) -class AddChannelForm(forms.ModelForm): - - class Meta: - model = Channel - fields = ['kind', 'value'] - - def clean_value(self): - value = self.cleaned_data["value"] - return value.strip() - - class AddPdForm(forms.Form): error_css_class = "has-error" value = forms.CharField(max_length=32) diff --git a/hc/front/views.py b/hc/front/views.py index 7d4bea9c..86823174 100644 --- a/hc/front/views.py +++ b/hc/front/views.py @@ -14,8 +14,9 @@ from django.utils import timezone from django.utils.crypto import get_random_string from django.utils.six.moves.urllib.parse import urlencode from hc.api.decorators import uuid_or_400 -from hc.api.models import DEFAULT_GRACE, DEFAULT_TIMEOUT, Channel, Check, Ping -from hc.front.forms import (AddChannelForm, AddWebhookForm, NameTagsForm, +from hc.api.models import (DEFAULT_GRACE, DEFAULT_TIMEOUT, Channel, Check, + Ping, Notification) +from hc.front.forms import (AddWebhookForm, NameTagsForm, TimeoutForm, AddUrlForm, AddPdForm, AddEmailForm, AddOpsGenieForm) from pytz import all_timezones @@ -175,8 +176,6 @@ def update_timeout(request, code): check.alert_after = check.get_alert_after() check.save() - else: - assert 0, "form is not valid! %s" % form.errors return redirect("hc-checks") @@ -218,45 +217,28 @@ def log(request, code): return HttpResponseForbidden() limit = request.team.ping_log_limit - pings = Ping.objects.filter(owner=check).order_by("-id")[:limit] - - pings = list(pings.iterator()) - # oldest-to-newest order will be more convenient for adding - # "not received" placeholders: - pings.reverse() - - # Add a dummy ping object at the end. We iterate over *pairs* of pings - # and don't want to handle a special case of a check with a single ping. - pings.append(Ping(created=timezone.now())) - - # Now go through pings, calculate time gaps, and decorate - # the pings list for convenient use in template - wrapped = [] - - early = False - for older, newer in pairwise(pings): - wrapped.append({"ping": older, "early": early}) + pings = Ping.objects.filter(owner=check).order_by("-id")[:limit + 1] + pings = list(pings) - # Fill in "missed ping" placeholders: - expected_date = older.created + check.timeout - n_blanks = 0 - while expected_date + check.grace < newer.created and n_blanks < 10: - wrapped.append({"placeholder_date": expected_date}) - expected_date = expected_date + check.timeout - n_blanks += 1 + num_pings = len(pings) + pings = pings[:limit] - # Prepare early flag for next ping to come - early = older.created + check.timeout > newer.created + check.grace + alerts = [] + if len(pings): + cutoff = pings[-1].created + alerts = Notification.objects \ + .select_related("channel") \ + .filter(owner=check, check_status="down", created__gt=cutoff) - reached_limit = len(pings) > limit + events = pings + list(alerts) + events.sort(key=lambda el: el.created, reverse=True) - wrapped.reverse() ctx = { "check": check, - "pings": wrapped, - "num_pings": len(pings), + "events": events, + "num_pings": min(num_pings, limit), "limit": limit, - "show_limit_notice": reached_limit and settings.USE_PAYMENTS + "show_limit_notice": num_pings > limit and settings.USE_PAYMENTS } return render(request, "front/log.html", ctx) diff --git a/static/css/log.css b/static/css/log.css index 7ef7ffc9..c157e40f 100644 --- a/static/css/log.css +++ b/static/css/log.css @@ -59,4 +59,8 @@ #log .hash { color: #aaa; +} + +#log .alert-info { + font-size: 12px; } \ No newline at end of file diff --git a/static/js/channels.js b/static/js/channels.js index 0417f842..3d9d4e57 100644 --- a/static/js/channels.js +++ b/static/js/channels.js @@ -32,8 +32,6 @@ $(function() { $cm.on("click", "#toggle-all", function() { var value = $(this).prop("checked"); $cm.find(".toggle").prop("checked", value); - console.log("aaa", value); - }); $(".channel-remove").click(function() { diff --git a/templates/front/log.html b/templates/front/log.html index fe100d69..77f86148 100644 --- a/templates/front/log.html +++ b/templates/front/log.html @@ -28,7 +28,7 @@ - {% if pings %} + {% if events %}
@@ -41,48 +41,67 @@ - {% for record in pings %} - {% if record.ping %} + {% for event in events %} + {% if event.n %} - {% endif %} - {% if record.placeholder_date %} + {% if event.check_status %} - - {% endif %} diff --git a/templates/integrations/opsgenie_note.html b/templates/integrations/opsgenie_note.html index 1f559849..3e05b665 100644 --- a/templates/integrations/opsgenie_note.html +++ b/templates/integrations/opsgenie_note.html @@ -1,4 +1,4 @@ {% load hc_extras humanize %} -Expecting to receive a ping every {{ check.timeout|hc_duration }}. +{% if check.kind == "simple" %}Expecting to receive a ping every {{ check.timeout|hc_duration }}.{% endif %} Last ping was {{ check.last_ping|naturaltime }}. diff --git a/templates/integrations/slack_message.json b/templates/integrations/slack_message.json index 6f5a0c3e..e55ce3d8 100644 --- a/templates/integrations/slack_message.json +++ b/templates/integrations/slack_message.json @@ -13,31 +13,37 @@ "mrkdwn_in": ["fields"], "text": "“{{ check.name_then_code|escapejs }}” is {{ check.status|upper }}.", "fields": [ - { - "title": "Period", - "value": "{{ check.timeout|hc_duration }}", - "short": true - }, - { - "title": "Last Ping", - {% if check.last_ping %} - "value": "{{ check.last_ping|naturaltime }}", - {% else %} - "value": "Never", - {% endif %} - "short": true + {% if check.kind == "simple" %} + {"title": "Period", + "value": "{{ check.timeout|hc_duration }}", + "short": true + }, + {% elif check.kind == "cron" %} + {"title": "Schedule", + "value": "{{ check.schedule }}", + "short": true + }, + {% endif %} + + {"title": "Last Ping", + {% if check.last_ping %} + "value": "{{ check.last_ping|naturaltime }}", + {% else %} + "value": "Never", + {% endif %} + "short": true }, + {% if check.tags_list %} - { - "title": "Tags", - "value": "{% for tag in check.tags_list %}`{{ tag|escapejs }}` {% endfor %}", - "short": true - }, + {"title": "Tags", + "value": "{% for tag in check.tags_list %}`{{ tag|escapejs }}` {% endfor %}", + "short": true + }, {% endif %} - { - "title": "Total Pings", - "value": "{{ check.n_pings }}", - "short": true + + {"title": "Total Pings", + "value": "{{ check.n_pings }}", + "short": true } ] }]
Protocol User Agent
- {% if record.ping.n %} - #{{ record.ping.n }} - {% endif %} + #{{ event.n }} +
- {% if record.early %} + {% if 0 %} early {% endif %}
- {{ record.ping.remote_addr|default:"" }} + {{ event.remote_addr|default:"" }} - {{ record.ping.scheme }} + {{ event.scheme }} - {{ record.ping.ua }} + {{ event.ua }}
+
- Ping expected but not received + + {% if event.channel.kind == "email" %} + Sent email alert to {{ event.channel.value }} + {% elif event.channel.kind == "slack" %} + Sent Slack alert + {% if event.channel.slack_channel %} + to {{ event.channel.slack_channel }} + {% endif %} + {% elif event.channel.kind == "pd" %} + Sent alert to PagerDuty + {% elif event.channel.kind == "opsgenie" %} + Sent alert to OpsGenie + {% elif event.channel.kind == "hipchat" %} + Sent alert to HipChat + {% elif event.channel.kind == "webhook" %} + Called webhook {{ event.channel.value_down }} + {% else %} + Sent alert to {{ event.channel.kind|capfirst }} + {% endif %} + {% if event.error %} +
+ Error: {{ event.error }} + {% endif %}