summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mirrors/templatetags/mirror_status.py25
-rw-r--r--mirrors/utils.py29
-rw-r--r--templates/mirrors/status.html55
-rw-r--r--templates/mirrors/status_table.html6
4 files changed, 90 insertions, 25 deletions
diff --git a/mirrors/templatetags/mirror_status.py b/mirrors/templatetags/mirror_status.py
index 09c5b331..0031d83b 100644
--- a/mirrors/templatetags/mirror_status.py
+++ b/mirrors/templatetags/mirror_status.py
@@ -1,15 +1,36 @@
+from datetime import timedelta
from django import template
+from django.template.defaultfilters import floatformat
register = template.Library()
@register.filter
def duration(value):
- if not value:
- return u'\u221e'
+ if not value and type(value) != timedelta:
+ return u''
# does not take microseconds into account
total_secs = value.seconds + value.days * 24 * 3600
mins, secs = divmod(total_secs, 60)
hrs, mins = divmod(mins, 60)
return '%d:%02d' % (hrs, mins)
+@register.filter
+def hours(value):
+ if not value and type(value) != timedelta:
+ return u''
+ # does not take microseconds into account
+ total_secs = value.seconds + value.days * 24 * 3600
+ mins, secs = divmod(total_secs, 60)
+ hrs, mins = divmod(mins, 60)
+ if hrs == 1:
+ return '%d hour' % hrs
+ return '%d hours' % hrs
+
+@register.filter
+def percentage(value, arg=-1):
+ if not value and type(value) != float:
+ return u''
+ new_val = value * 100.0
+ return floatformat(new_val, arg) + '%'
+
# vim: set ts=4 sw=4 et:
diff --git a/mirrors/utils.py b/mirrors/utils.py
index cdb705b2..0463247a 100644
--- a/mirrors/utils.py
+++ b/mirrors/utils.py
@@ -16,7 +16,9 @@ def get_mirror_statuses(cutoff=default_cutoff):
mirror__active=True, mirror__public=True,
protocol__in=protocols,
logs__check_time__gte=cutoff_time).annotate(
- check_count=Count('logs'), last_sync=Max('logs__last_sync'),
+ check_count=Count('logs'),
+ success_count=Count('logs__duration'),
+ last_sync=Max('logs__last_sync'),
last_check=Max('logs__check_time'),
duration_avg=Avg('logs__duration'),
duration_stddev=StdDev('logs__duration')
@@ -32,17 +34,6 @@ def get_mirror_statuses(cutoff=default_cutoff):
d = log.check_time - log.last_sync
delays.setdefault(log.url_id, []).append(d)
- for url in urls:
- if url.id in delays:
- url_delays = delays[url.id]
- d = sum(url_delays, datetime.timedelta()) / len(url_delays)
- url.delay = d
- hours = d.days * 24.0 + d.seconds / 3600.0
- url.score = hours + url.duration_avg + url.duration_stddev
- else:
- url.delay = None
- url.score = None
-
if urls:
last_check = max([u.last_check for u in urls])
num_checks = max([u.check_count for u in urls])
@@ -55,7 +46,21 @@ def get_mirror_statuses(cutoff=default_cutoff):
num_checks = 0
check_frequency = None
+ for url in urls:
+ url.completion_pct = float(url.success_count) / num_checks
+ if url.id in delays:
+ url_delays = delays[url.id]
+ d = sum(url_delays, datetime.timedelta()) / len(url_delays)
+ url.delay = d
+ hours = d.days * 24.0 + d.seconds / 3600.0
+ url.score = hours + url.duration_avg + url.duration_stddev
+ else:
+ url.delay = None
+ url.score = None
+ url.completion = 0.0
+
return {
+ 'cutoff': cutoff,
'last_check': last_check,
'num_checks': num_checks,
'check_frequency': check_frequency,
diff --git a/templates/mirrors/status.html b/templates/mirrors/status.html
index 8dbecc07..1111d047 100644
--- a/templates/mirrors/status.html
+++ b/templates/mirrors/status.html
@@ -8,7 +8,7 @@
<h2>Mirror Status</h2>
<p>This page reports the status of all known, public, and active Arch Linux
mirrors. All data on this page reflects the status of the mirrors within
- the <em>last 24 hours</em>. All listed times are UTC. The check script runs
+ the <em>last {{ cutoff|hours }}</em>. All listed times are UTC. The check script runs
on a regular basis and polls for the <tt>lastsync</tt> file in the root of
our repository layout. This file is regularly updated on the central
repository, so checking the value within allows one to see if the mirror
@@ -21,6 +21,9 @@
<tt>lastsync</tt> file on the mirror. If this file could not be
retrieved or contained data we didn't recognize, this column will show
'unknown'.</li>
+ <li><em>Completion %:</em> The number of mirror checks that have
+ successfully connected and disconnected from the given URL. If this is
+ below 100%, the mirror may be unreliable.</li>
<li><em>μ Delay:</em> The calculated average mirroring delay; e.g. the
mean value of <tt>last check − last sync</tt> for each check of
this mirror URL. Due to the timing of mirror checks, any value under
@@ -38,7 +41,7 @@
</ul>
<p>The final table on this page is an error log, which shows any errors
that occurred while contacting mirrors. This only shows errors that
- occurred within the last 24 hours.</p>
+ occurred within the last {{ cutoff|hours }}.</p>
<ul>
<li><a href="#outofsync">Out of Sync Mirrors</a></li>
<li><a href="#successful">Successfully Syncing Mirrors</a></li>
@@ -46,7 +49,7 @@
</ul>
<p>The last mirror check ran at {{ last_check|date:'Y-m-d H:i' }} UTC.
- Checks have ran {{ num_checks }} times in the last 24 hours at an average
+ Checks have ran {{ num_checks }} times in the last {{ cutoff|hours }} at an average
interval of {{ check_frequency|duration }} (hh:mm).</p>
<a name="outofsync" id="outofsync"></a>
@@ -75,7 +78,7 @@
<th>Country</th>
<th>Error Message</th>
<th>Last Occurred</th>
- <th>Occurrences (last 24 hours)</th>
+ <th>Occurrences (last {{ cutoff|hours }})</th>
</tr>
</thead>
<tbody>
@@ -96,12 +99,46 @@
{% load cdn %}{% jquery %}
<script type="text/javascript" src="/media/jquery.tablesorter.min.js"></script>
<script type="text/javascript">
+$.tablesorter.addParser({
+ /* sorts numeric, but put '', 'unknown', and '∞' last. */
+ id: 'mostlydigit',
+ is: function(s,table) {
+ var special = ['', 'unknown', '∞'];
+ var c = table.config;
+ return ($.inArray(s, special) > -1) || $.tablesorter.isDigit(s,c);
+ },
+ format: function(s) {
+ var special = ['', 'unknown', '∞'];
+ if($.inArray(s, special) > -1) return Number.MAX_VALUE;
+ return $.tablesorter.formatFloat(s);
+ },
+ type: 'numeric'
+});
+$.tablesorter.addParser({
+ /* sorts duration; put '', 'unknown', and '∞' last. */
+ id: 'duration',
+ is: function(s,table) {
+ var special = ['', 'unknown', '∞'];
+ return ($.inArray(s, special) > -1) || /^[0-9]+:[0-5][0-9]$/.test(s);
+ },
+ format: function(s) {
+ console.log('duration: ' + s);
+ var special = ['', 'unknown', '∞'];
+ if($.inArray(s, special) > -1) return Number.MAX_VALUE;
+ matches = /^([0-9]+):([0-5][0-9])$/.exec(s);
+ console.log(s, matches[1] * 60 + matches[2]);
+ return matches[1] * 60 + matches[2];
+ },
+ type: 'numeric'
+});
$(document).ready(function() {
- $("#outofsync_mirrors").tablesorter(
- {widgets: ['zebra'], sortList: [[3,1], [5,1]]});
- $("#successful_mirrors").tablesorter(
- {widgets: ['zebra'], sortList: [[7,0]]});
- $("#errorlog_mirrors").tablesorter(
+ $("#outofsync_mirrors:has(tbody tr)").tablesorter(
+ {widgets: ['zebra'], sortList: [[3,1]],
+ headers: { 6: { sorter: 'mostlydigit' }, 7: { sorter: 'mostlydigit' }, 8: { sorter: 'mostlydigit' } } });
+ $("#successful_mirrors:has(tbody tr)").tablesorter(
+ {widgets: ['zebra'], sortList: [[8,0]],
+ headers: { 6: { sorter: 'mostlydigit' }, 7: { sorter: 'mostlydigit' }, 8: { sorter: 'mostlydigit' } } });
+ $("#errorlog_mirrors:has(tbody tr)").tablesorter(
{widgets: ['zebra'], sortList: [[4,1], [5,1]]});
});
</script>
diff --git a/templates/mirrors/status_table.html b/templates/mirrors/status_table.html
index 75157765..240a5452 100644
--- a/templates/mirrors/status_table.html
+++ b/templates/mirrors/status_table.html
@@ -6,6 +6,7 @@
<th>Protocol</th>
<th>Country</th>
<th>Last Sync</th>
+ <th>Completion %</th>
<th>μ Delay (hh:mm)</th>
<th>μ Duration (secs)</th>
<th>σ Duration (secs)</th>
@@ -19,9 +20,10 @@
<td>{{ m_url.protocol }}</td>
<td>{{ m_url.mirror.country }}</td>
<td>{{ m_url.last_sync|date:'Y-m-d H:i'|default:'unknown' }}</td>
+ <td>{{ m_url.completion_pct|percentage:1 }}</td>
<td>{{ m_url.delay|duration|default:'unknown' }}</td>
- <td>{{ m_url.duration_avg|floatformat:2|default:'unknown' }}</td>
- <td>{{ m_url.duration_stddev|floatformat:2|default:'unknown' }}</td>
+ <td>{{ m_url.duration_avg|floatformat:2 }}</td>
+ <td>{{ m_url.duration_stddev|floatformat:2 }}</td>
<td>{{ m_url.score|floatformat:1|default:'∞' }}</td>
</tr>
{% endfor %}