launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #14627
[Merge] lp:~james-w/python-oops-tools/recent-oopses into lp:python-oops-tools
James Westby has proposed merging lp:~james-w/python-oops-tools/recent-oopses into lp:python-oops-tools.
Commit message:
Show the (paginated) oopses for each report.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~james-w/python-oops-tools/recent-oopses/+merge/137055
Hi,
Showing the day-old reports is of limited use, because you don't know
if there are issues with the site at this moment. To try and help with that
show the oopses, sorted with the most recent first, on the report page.
It uses pagination to keep the number of oopses displayed small.
Thanks,
James
--
https://code.launchpad.net/~james-w/python-oops-tools/recent-oopses/+merge/137055
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~james-w/python-oops-tools/recent-oopses into lp:python-oops-tools.
=== modified file 'src/oopstools/oops/static/oops.css'
--- src/oopstools/oops/static/oops.css 2011-10-13 20:18:51 +0000
+++ src/oopstools/oops/static/oops.css 2012-11-29 21:37:20 +0000
@@ -7,7 +7,13 @@
padding:0px;
}
table {
- border: 1px #000;
+ border: 1px solid #000;
+}
+td {
+ padding: 4px;
+}
+tr:nth-child(2n) {
+ background-color: #eee;
}
p,h1,pre {
margin:0px 10px 10px 10px;
=== modified file 'src/oopstools/oops/templates/report.html'
--- src/oopstools/oops/templates/report.html 2011-10-13 20:18:51 +0000
+++ src/oopstools/oops/templates/report.html 2012-11-29 21:37:20 +0000
@@ -13,5 +13,41 @@
<li><a href="{{SUMMARY_URI}}/{{report.name}}-{{date|date:"Y-m-d"}}.html">{{report.title}} {{date|date:"Y-m-d"}}</a></li>
{% endfor %}
<ul>
+ <h2>Recent Oopses</h2>
+ <table>
+ <th><tr>
+ <td>Date/Time</td>
+ <td>HTTP Method</td>
+ <td>URL</td>
+ <td>Duration (ms)</td>
+ <td>Exception Type</td>
+ <td>Oops</td>
+ </tr></th>
+ {% for oops in recent.object_list %}
+ <tr>
+ <td>{{oops.date|date:"Y-m-d H:i:s"}}</td>
+ <td>{{oops.http_method}}</td>
+ <td>{% if oops.url %}<a href="{{oops.url}}">{{oops.url}}</a>{% endif %}</td>
+ <td>{{oops.total_time}}</td>
+ <td>{{oops.exception_type}}</td>
+ <td><a href="{% url oopstools.oops.views.index %}?oopsid={{oops.oopsid}}">{{oops.oopsid}}</a></td>
+ </tr>
+ {% endfor %}
+ </table>
+ <div class="pagination">
+ <span class="step-links">
+ {% if recent.has_previous %}
+ <a href="?page={{ recent.previous_page_number }}">newer</a>
+ {% endif %}
+
+ <span class="current">
+ Page {{ recent.number }} of {{ recent.paginator.num_pages }}.
+ </span>
+
+ {% if recent.has_next %}
+ <a href="?page={{ recent.next_page_number }}">older</a>
+ {% endif %}
+ </span>
+ </div>
</body>
</html>
=== modified file 'src/oopstools/oops/test/__init__.py'
--- src/oopstools/oops/test/__init__.py 2011-10-13 20:18:51 +0000
+++ src/oopstools/oops/test/__init__.py 2012-11-29 21:37:20 +0000
@@ -12,5 +12,3 @@
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-
=== added file 'src/oopstools/oops/test/test_report.py'
--- src/oopstools/oops/test/test_report.py 1970-01-01 00:00:00 +0000
+++ src/oopstools/oops/test/test_report.py 2012-11-29 21:37:20 +0000
@@ -0,0 +1,79 @@
+# Copyright 2005-2012 Canonical Ltd. All rights reserved.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+from datetime import datetime
+from operator import attrgetter
+
+from django.test import TestCase
+from testtools import TestCase as TesttoolsTestCase
+
+from oopstools.oops.models import (
+ AppInstance,
+ Classification,
+ Infestation,
+ Oops,
+ Prefix,
+ Report,
+)
+
+
+class ReportTests(TestCase, TesttoolsTestCase):
+
+ def test_no_report(self):
+ resp = self.client.get('/reports/some-report/')
+ self.assertEqual(404, resp.status_code)
+
+ def test_inactive_report(self):
+ report_name = 'areport'
+ Report.objects.create(name=report_name, active=False)
+ resp = self.client.get('/reports/%s/' % (report_name,))
+ self.assertEqual(404, resp.status_code)
+
+ def test_no_recent_oopses(self):
+ report_name = 'areport'
+ Report.objects.create(name=report_name, active=True)
+ resp = self.client.get('/reports/%s/' % (report_name,))
+ self.assertEqual(200, resp.status_code)
+ self.assertQuerysetEqual(resp.context['recent'].object_list, [])
+
+ def make_oops(self, prefix):
+ classification = Classification.objects.create(
+ title=self.getUniqueString(prefix="classification"))
+ infestation = Infestation.objects.create(
+ exception_type=self.getUniqueString(prefix="exc_type"),
+ exception_value=self.getUniqueString(prefix="exc_value"))
+ return Oops.objects.create(
+ prefix=prefix, classification=classification,
+ oopsinfestation=infestation, statements_count=100,
+ appinstance=prefix.appinstance, total_time=3,
+ date=datetime.now())
+
+ def make_prefix(self):
+ appinstance = AppInstance.objects.create(
+ title=self.getUniqueString(prefix="appinstance"))
+ return Prefix.objects.create(
+ value=self.getUniqueString(prefix="prefix"),
+ appinstance=appinstance)
+
+ def test_recent_oopses(self):
+ report_name = 'areport'
+ report = Report.objects.create(name=report_name, active=True)
+ prefix = self.make_prefix()
+ report.prefixes.add(prefix)
+ oops = self.make_oops(prefix)
+ resp = self.client.get('/reports/%s/' % (report_name,))
+ self.assertEqual(200, resp.status_code)
+ self.assertQuerysetEqual(
+ resp.context['recent'].object_list, [oops.pk], transform=attrgetter('pk'))
=== modified file 'src/oopstools/oops/views.py'
--- src/oopstools/oops/views.py 2011-11-03 00:08:18 +0000
+++ src/oopstools/oops/views.py 2012-11-29 21:37:20 +0000
@@ -18,6 +18,7 @@
from datetime import datetime, timedelta
from django.conf import settings
+from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from django.http import Http404, HttpResponseRedirect
from django.shortcuts import render_to_response
@@ -96,6 +97,19 @@
"prefixes": prefixes})
+def get_page_from_query_args(paginator, query_args):
+ page_num = query_args.get('page', 1)
+ try:
+ page = paginator.page(page_num)
+ except PageNotAnInteger:
+ # If page is not an integer, deliver first page.
+ page = paginator.page(1)
+ except EmptyPage:
+ # If page is out of range (e.g. 9999), deliver last page of results.
+ page = paginator.page(paginator.num_pages)
+ return page
+
+
def report(request, report_name):
try:
r = Report.objects.get(name=report_name, active=True)
@@ -108,10 +122,15 @@
dates = []
for day in range(1, 11):
dates.append(now - timedelta(day))
+ oopses = Oops.objects.filter(
+ prefix__report=r).order_by('-date')
+ paginator = Paginator(oopses, 50)
+ recent_oopses = get_page_from_query_args(paginator, request.GET)
data = {
'report': r,
'dates': dates,
'SUMMARY_URI': settings.SUMMARY_URI,
+ 'recent': recent_oopses,
}
return render_to_response("report.html", dictionary=data)