-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* test(notification): strict checks for required keys * test: add edge cases * fix(service): not creating intervalTask when creating service * test: a simple go test server to check if notification can be reached (need to replace with pytest mocker) * feat:add endpoint for statistics for UptimeRecord * test: UptimeRecord based on service ID * feat: chart data API * feat:support define interval for charting API * fix: keep sending notification after a service is recovered. Now limited sending to 3 times. * fix: return UTC time for chartAPI instead of local time * chores: ignore pycache * chores: add source of readme chart
- Loading branch information
1 parent
ce70540
commit 830f8a0
Showing
14 changed files
with
3,563 additions
and
35 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,2 @@ | ||
/django_debug.log | ||
**/__pycache__/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,42 +1,115 @@ | ||
from datetime import timedelta | ||
|
||
from django.db.models import Avg | ||
from django.utils import timezone | ||
from django.utils.timezone import now | ||
|
||
from apps.monitoring.models import UptimeRecord | ||
|
||
|
||
QUERY_TIME_RANGE_TYPE = { | ||
1: "Last 1 hour", | ||
3: "Last 3 hours", | ||
6: "Last 6 hours", | ||
24: "Last 24 hours", | ||
168: "Last 7 days", | ||
720: "Last 30 days", | ||
-1: "All time", | ||
} | ||
|
||
|
||
def calculate_past(time_range=None): | ||
def calculate_past_summary(time_range=None): | ||
""" | ||
Given an time range in HOUR?DATE, query all UptimeRecord and | ||
calculate uptime percentage and the average response time | ||
:return: uptime_percentage and avg_response_time | ||
:return:total_records, uptime_percentage and avg_response_time | ||
""" | ||
|
||
uptime_percentage, avg_response_time = None, None | ||
if not time_range or time_range.value not in QUERY_TIME_RANGE_TYPE.keys(): | ||
if (not time_range) or (time_range not in QUERY_TIME_RANGE_TYPE.keys()): | ||
return uptime_percentage and avg_response_time | ||
time_delta = time_range.value | ||
time_delta = time_range | ||
results = UptimeRecord.objects.filter( | ||
created_at__gte=now() - timedelta(hours=time_delta) | ||
) | ||
# results = UptimeRecord.objects.filter(created_at? range) | ||
sum_avg_time, sum_uptime = 0, 0 | ||
total_records = results.count() | ||
for record in results: | ||
sum_avg_time += record.response_time | ||
sum_uptime += 1 if record.status else 0 | ||
if total_records: | ||
avg_response_time = sum_avg_time / total_records | ||
uptime_percentage = (sum_uptime / total_records) * 100 | ||
return uptime_percentage, avg_response_time | ||
up_records = results.filter(status=True).count() | ||
average_response_time = ( | ||
results.filter(status=True).aggregate(Avg("response_time"))[ | ||
"response_time__avg" | ||
] | ||
or 0 | ||
) | ||
|
||
uptime_percentage = (up_records / total_records) * 100 if total_records else 0 | ||
|
||
return total_records, uptime_percentage, average_response_time | ||
|
||
|
||
def calculate_past_chart(time_range, split_interval): | ||
""" | ||
Given a time range in HOUR, query all UptimeRecord and | ||
calculate uptime_percentage and the average_response_time in the interval for chart, | ||
the interval is calculated by showing 30 records in the chart. E.g. if the time_range is 720 hours, | ||
the chart will show 30 records, each record represents 24 hours. | ||
:return: a json contains a summary of uptime percentage and average response time, following 30 detailed records | ||
where each record contains total_records, uptime_percentage, average_response_time, time_start and time_end | ||
""" | ||
|
||
if (not time_range) or (time_range not in QUERY_TIME_RANGE_TYPE.keys()): | ||
return KeyError("Invalid time range") | ||
# iterate 30 intervals in the given time range | ||
if split_interval < 1: | ||
split_interval = 1 | ||
delta = timedelta(hours=time_range / split_interval) | ||
start_time = now() - timedelta(hours=time_range) | ||
total_records, total_up_records = 0, 0 | ||
all_results = [] | ||
total_avg_response_time = [] | ||
|
||
for _ in range(split_interval): | ||
end_time = start_time + delta | ||
results = UptimeRecord.objects.filter( | ||
created_at__gte=start_time, created_at__lt=end_time | ||
) | ||
interval_total_records = results.count() | ||
interval_up_records = results.filter(status=True).count() | ||
average_response_time = ( | ||
results.filter(status=True).aggregate(Avg("response_time"))[ | ||
"response_time__avg" | ||
] | ||
or 0 | ||
) | ||
all_results.append( | ||
{ | ||
"uptime_percentage": (interval_up_records / interval_total_records) | ||
* 100 | ||
if interval_total_records | ||
else 0, | ||
"average_response_time": average_response_time, | ||
"time_start": timezone.localtime(end_time).strftime("%b. %-d, %H:%M"), | ||
} | ||
) | ||
total_records += interval_total_records | ||
total_up_records += interval_up_records | ||
total_avg_response_time.append(average_response_time) | ||
start_time = end_time | ||
|
||
total_avg_response_time = sum(total_avg_response_time) / len( | ||
total_avg_response_time | ||
) | ||
uptime_percentage = (total_up_records / total_records) * 100 if total_records else 0 | ||
|
||
summary = { | ||
"time_range": time_range, | ||
"total_records": total_records, | ||
"uptime_percentage": uptime_percentage, | ||
"average_response_time": total_avg_response_time, | ||
"time_start": timezone.localtime(now()).strftime("%b. %-d, %H:%M"), | ||
"time_end": timezone.localtime(now()).strftime("%b. %-d, %H:%M"), | ||
} | ||
response = { | ||
"summary": summary, | ||
"data": all_results, | ||
} | ||
return response |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.