launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #21814
[Merge] lp:~cjwatson/launchpad/upgrade-oops into lp:launchpad
Colin Watson has proposed merging lp:~cjwatson/launchpad/upgrade-oops into lp:launchpad.
Commit message:
Upgrade to oops 0.0.13 and compatible versions of related packages.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~cjwatson/launchpad/upgrade-oops/+merge/330118
This depends on https://code.launchpad.net/~cjwatson/python-oops-twisted/new-oops-publisher-api/+merge/330117.
Aside from it probably being a good idea to catch up a bit, the main benefit of this is that we can get rid of pymongo from our dependency graph. That was an obstruction to converting to pip, because pymongo installs bson as a top-level module and thus conflicts with the bson package. We got away with that with buildout because each package was installed as a separate egg, but with pip they all end up in the same site-packages directory so we can no longer ignore the problem.
--
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~cjwatson/launchpad/upgrade-oops into lp:launchpad.
=== modified file 'lib/lp/codehosting/codeimport/tests/test_workermonitor.py'
--- lib/lp/codehosting/codeimport/tests/test_workermonitor.py 2017-05-12 08:08:26 +0000
+++ lib/lp/codehosting/codeimport/tests/test_workermonitor.py 2017-09-02 13:43:11 +0000
@@ -582,7 +582,8 @@
# loggingsupport.set_up_oops_reporting).
errorlog.globalErrorUtility.configure(
config_factory=oops_twisted.Config,
- publisher_adapter=oops_twisted.defer_publisher)
+ publisher_adapter=oops_twisted.defer_publisher,
+ publisher_helpers=oops_twisted.publishers)
self.addCleanup(errorlog.globalErrorUtility.configure)
worker_monitor = self.WorkerMonitor(defer.fail(RuntimeError()))
return worker_monitor.run().addCallback(
@@ -611,7 +612,8 @@
# callFinishJob logs a failure from the child process.
errorlog.globalErrorUtility.configure(
config_factory=oops_twisted.Config,
- publisher_adapter=oops_twisted.defer_publisher)
+ publisher_adapter=oops_twisted.defer_publisher,
+ publisher_helpers=oops_twisted.publishers)
self.addCleanup(errorlog.globalErrorUtility.configure)
failure_msg = "test_callFinishJob_logs_failure expected failure"
worker_monitor = self.WorkerMonitor(
=== modified file 'lib/lp/services/scripts/tests/cronscript-crash.py'
--- lib/lp/services/scripts/tests/cronscript-crash.py 2012-01-01 02:58:52 +0000
+++ lib/lp/services/scripts/tests/cronscript-crash.py 2017-09-02 13:43:11 +0000
@@ -1,5 +1,5 @@
#!/usr/bin/python -S
-# Copyright 2010 Canonical Ltd. This software is licensed under the
+# Copyright 2010-2017 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Cronscript that raises an unhandled exception."""
@@ -17,7 +17,12 @@
def main(self):
self.oopses = []
- globalErrorUtility._oops_config.publishers[:] = [self.oopses.append]
+
+ def publish(report):
+ self.oopses.append(report)
+ return []
+
+ globalErrorUtility._oops_config.publisher = publish
self.logger.debug("This is debug level")
# Debug messages do not generate an OOPS.
=== modified file 'lib/lp/services/twistedsupport/loggingsupport.py'
--- lib/lp/services/twistedsupport/loggingsupport.py 2015-07-08 16:05:11 +0000
+++ lib/lp/services/twistedsupport/loggingsupport.py 2017-09-02 13:43:11 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2017 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Integration between the normal Launchpad logging and Twisted's."""
@@ -55,7 +55,8 @@
errorlog.globalErrorUtility.configure(
configuration,
config_factory=oops_twisted.Config,
- publisher_adapter=oops_twisted.defer_publisher)
+ publisher_adapter=oops_twisted.defer_publisher,
+ publisher_helpers=oops_twisted.publishers)
log_observer = RotatableFileLogObserver(logfile)
oops_observer = OOPSObserver(errorlog.globalErrorUtility._oops_config,
log_observer)
=== modified file 'lib/lp/services/webapp/errorlog.py'
--- lib/lp/services/webapp/errorlog.py 2016-09-14 11:55:45 +0000
+++ lib/lp/services/webapp/errorlog.py 2017-09-02 13:43:11 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2016 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2017 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Error logging facilities."""
@@ -89,7 +89,7 @@
if not report.get('id'):
report['id'] = str(id(report))
notify(ErrorReportEvent(report))
- return report['id']
+ return [report['id']]
def attach_adapter_duration(report, context):
@@ -268,7 +268,7 @@
index for index, _ignored in enumerate(repeat(None)))
def configure(self, section_name=None, config_factory=oops.Config,
- publisher_adapter=None):
+ publisher_adapter=None, publisher_helpers=oops.publishers):
"""Configure the utility using the named section from the config.
The 'error_reports' section is used if section_name is None.
@@ -312,26 +312,37 @@
# And any active feature flags.
self._oops_config.on_create.append(attach_feature_info)
- def add_publisher(publisher):
+ def adapted_publisher(publisher):
if publisher_adapter is not None:
- publisher = publisher_adapter(publisher)
- self._oops_config.publishers.append(publisher)
+ return publisher_adapter(publisher)
+ else:
+ return publisher
+ # Exposed for introspection by tests. Don't expect modifying these
+ # to be useful.
+ self._main_publishers = []
+ self._all_publishers = []
# If amqp is configured we want to publish over amqp.
if (config.error_reports.error_exchange and rabbit.is_configured()):
exchange = config.error_reports.error_exchange
routing_key = config.error_reports.error_queue_key
- amqp_publisher = oops_amqp.Publisher(
- rabbit.connect, exchange, routing_key)
- add_publisher(amqp_publisher)
+ # Exposed for tests.
+ self._main_publishers.append(adapted_publisher(oops_amqp.Publisher(
+ rabbit.connect, exchange, routing_key)))
# We want to publish reports to disk for gathering to the central
# analysis server, but only if we haven't already published to rabbit.
self._oops_datedir_repo = DateDirRepo(
config[self._default_config_section].error_dir)
- add_publisher(oops.publish_new_only(self._oops_datedir_repo.publish))
+ self._main_publishers.append(
+ adapted_publisher(self._oops_datedir_repo.publish))
+ self._all_publishers.append(
+ publisher_helpers.publish_with_fallback(*self._main_publishers))
# And send everything within the zope application server (only for
# testing).
- add_publisher(notify_publisher)
+ self._all_publishers.append(adapted_publisher(notify_publisher))
+ self._oops_config.publisher = publisher_helpers.publish_to_many(
+ *self._all_publishers)
+
#
# Reports are filtered if:
# - There is a key 'ignore':True in the report. This is set during
=== modified file 'lib/lp/services/webapp/tests/test_errorlog.py'
--- lib/lp/services/webapp/tests/test_errorlog.py 2016-09-14 11:12:13 +0000
+++ lib/lp/services/webapp/tests/test_errorlog.py 2017-09-02 13:43:11 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2016 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2017 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Tests for error logging & OOPS reporting."""
@@ -92,22 +92,21 @@
self.assertEqual(config.error_reports.oops_prefix,
utility.oops_prefix)
- # We should have had three publishers setup:
- oops_config = utility._oops_config
- self.assertEqual(3, len(oops_config.publishers))
- # - a rabbit publisher
- self.assertIsInstance(oops_config.publishers[0], oops_amqp.Publisher)
- # - a datedir publisher wrapped in a publish_new_only wrapper
- datedir_repo = utility._oops_datedir_repo
- publisher = oops_config.publishers[1].func_closure[0].cell_contents
- self.assertEqual(publisher, datedir_repo.publish)
+ # We should have had two publishers set up:
+ self.assertEqual(2, len(utility._all_publishers))
+ # - a fallback publisher chaining a rabbit publisher and a datedir
+ # publisher
+ self.assertIsInstance(
+ utility._main_publishers[0], oops_amqp.Publisher)
+ self.assertEqual(
+ utility._main_publishers[1], utility._oops_datedir_repo.publish)
# - a notify publisher
- self.assertEqual(oops_config.publishers[2], notify_publisher)
+ self.assertEqual(utility._all_publishers[1], notify_publisher)
def test_multiple_raises_in_request(self):
"""An OOPS links to the previous OOPS in the request, if any."""
utility = ErrorReportingUtility()
- del utility._oops_config.publishers[0]
+ utility._main_publishers[0].__call__ = lambda report: []
request = TestRequestWithPrincipal()
try:
@@ -128,7 +127,7 @@
def test_raising_with_request(self):
"""Test ErrorReportingUtility.raising() with a request"""
utility = ErrorReportingUtility()
- del utility._oops_config.publishers[0]
+ utility._main_publishers[0].__call__ = lambda report: []
request = TestRequestWithPrincipal(
environ={
@@ -174,7 +173,7 @@
directlyProvides(request, IXMLRPCRequest)
request.getPositionalArguments = lambda: (1, 2)
utility = ErrorReportingUtility()
- del utility._oops_config.publishers[:]
+ utility._oops_config.publisher = None
try:
raise ArbitraryException('xyz\nabc')
except ArbitraryException:
@@ -186,7 +185,7 @@
# still be unicode (or utf8).
request = TestRequest(form={'foo\x85': 'bar'})
utility = ErrorReportingUtility()
- del utility._oops_config.publishers[:]
+ utility._oops_config.publisher = None
try:
raise ArbitraryException('foo')
except ArbitraryException:
@@ -203,7 +202,7 @@
request = TestRequest()
directlyProvides(request, WebServiceLayer)
utility = ErrorReportingUtility()
- del utility._oops_config.publishers[:]
+ utility._oops_config.publisher = None
# Exceptions that don't use error_status result in OOPSes.
try:
@@ -236,7 +235,7 @@
def test_raising_for_script(self):
"""Test ErrorReportingUtility.raising with a ScriptRequest."""
utility = ErrorReportingUtility()
- del utility._oops_config.publishers[:]
+ utility._oops_config.publisher = None
# A list because code using ScriptRequest expects that - ScriptRequest
# translates it to a dict for now.
@@ -264,7 +263,7 @@
__repr__ = __str__
utility = ErrorReportingUtility()
- del utility._oops_config.publishers[:]
+ utility._oops_config.publisher = None
try:
raise UnprintableException()
except UnprintableException:
@@ -278,7 +277,7 @@
def test_raising_unauthorized_without_request(self):
"""Unauthorized exceptions are logged when there's no request."""
utility = ErrorReportingUtility()
- del utility._oops_config.publishers[:]
+ utility._oops_config.publisher = None
try:
raise Unauthorized('xyz')
except Unauthorized:
@@ -289,7 +288,7 @@
"""Unauthorized exceptions are logged when the request has no
principal."""
utility = ErrorReportingUtility()
- del utility._oops_config.publishers[:]
+ utility._oops_config.publisher = None
request = ScriptRequest([('name2', 'value2')])
try:
raise Unauthorized('xyz')
@@ -301,7 +300,7 @@
"""Unauthorized exceptions are not logged when the request has an
unauthenticated principal."""
utility = ErrorReportingUtility()
- del utility._oops_config.publishers[:]
+ utility._oops_config.publisher = None
request = TestRequestWithUnauthenticatedPrincipal()
try:
raise Unauthorized('xyz')
@@ -312,7 +311,7 @@
"""Unauthorized exceptions are logged when the request has an
authenticated principal."""
utility = ErrorReportingUtility()
- del utility._oops_config.publishers[:]
+ utility._oops_config.publisher = None
request = TestRequestWithPrincipal()
try:
raise Unauthorized('xyz')
@@ -328,7 +327,7 @@
raised.
"""
utility = ErrorReportingUtility()
- del utility._oops_config.publishers[:]
+ utility._oops_config.publisher = None
self.assertTrue(
TranslationUnavailable.__name__ in utility._ignored_exceptions,
'TranslationUnavailable is not in _ignored_exceptions.')
@@ -340,7 +339,7 @@
def test_ignored_exceptions_for_offsite_referer(self):
# Exceptions caused by bad URLs that may not be an Lp code issue.
utility = ErrorReportingUtility()
- del utility._oops_config.publishers[:]
+ utility._oops_config.publisher = None
errors = set([
GoneError.__name__, InvalidBatchSizeError.__name__,
NotFound.__name__])
@@ -351,7 +350,7 @@
# Oopses are reported when Launchpad is the referer for a URL
# that caused an exception.
utility = ErrorReportingUtility()
- del utility._oops_config.publishers[:]
+ utility._oops_config.publisher = None
request = TestRequest(
environ={
'SERVER_URL': 'http://launchpad.dev/fnord',
@@ -366,7 +365,7 @@
# Oopses are reported when a Launchpad vhost is the referer for a URL
# that caused an exception.
utility = ErrorReportingUtility()
- del utility._oops_config.publishers[:]
+ utility._oops_config.publisher = None
request = TestRequest(
environ={
'SERVER_URL': 'http://launchpad.dev/fnord',
@@ -381,7 +380,7 @@
# Oopses are reported when a Launchpad referer for a bad URL on a
# vhost that caused an exception.
utility = ErrorReportingUtility()
- del utility._oops_config.publishers[:]
+ utility._oops_config.publisher = None
request = TestRequest(
environ={
'SERVER_URL': 'http://bazaar.launchpad.dev/fnord',
@@ -395,7 +394,7 @@
def test_ignored_exceptions_for_offsite_referer_not_reported(self):
# Oopses are not reported when Launchpad is not the referer.
utility = ErrorReportingUtility()
- del utility._oops_config.publishers[:]
+ utility._oops_config.publisher = None
# There is no HTTP_REFERER header in this request
request = TestRequest(
environ={'SERVER_URL': 'http://launchpad.dev/fnord'})
@@ -412,7 +411,7 @@
raised.
"""
utility = ErrorReportingUtility()
- del utility._oops_config.publishers[:]
+ utility._oops_config.publisher = None
try:
raise NoReferrerError('xyz')
except NoReferrerError:
@@ -434,7 +433,7 @@
exc_tb = traceback.format_exc()
utility = ErrorReportingUtility()
- del utility._oops_config.publishers[:]
+ utility._oops_config.publisher = None
report = utility.raising((exc_type, exc_value, exc_tb))
# traceback is what we supplied.
self.assertEqual(exc_tb, report['tb_text'])
@@ -442,7 +441,7 @@
def test_oopsMessage(self):
"""oopsMessage pushes and pops the messages."""
utility = ErrorReportingUtility()
- del utility._oops_config.publishers[:]
+ utility._oops_config.publisher = None
with utility.oopsMessage({'a': 'b', 'c': 'd'}):
self.assertEqual(
{0: {'a': 'b', 'c': 'd'}}, utility._oops_messages)
@@ -460,7 +459,7 @@
def test__makeErrorReport_includes_oops_messages(self):
"""The error report should include the oops messages."""
utility = ErrorReportingUtility()
- del utility._oops_config.publishers[:]
+ utility._oops_config.publisher = None
with utility.oopsMessage(dict(a='b', c='d')):
try:
raise ArbitraryException('foo')
@@ -474,7 +473,7 @@
def test__makeErrorReport_combines_request_and_error_vars(self):
"""The oops messages should be distinct from real request vars."""
utility = ErrorReportingUtility()
- del utility._oops_config.publishers[:]
+ utility._oops_config.publisher = None
request = ScriptRequest([('c', 'd')])
with utility.oopsMessage(dict(a='b')):
try:
@@ -504,7 +503,7 @@
def test_session_queries_filtered(self):
"""Test that session queries are filtered."""
utility = ErrorReportingUtility()
- del utility._oops_config.publishers[:]
+ utility._oops_config.publisher = None
timeline = Timeline()
timeline.start("SQL-session", "SELECT 'gone'").finish()
try:
@@ -567,7 +566,7 @@
# A request originating from another site that generates a NotFound
# (404) is ignored (i.e., no OOPS is logged).
utility = ErrorReportingUtility()
- del utility._oops_config.publishers[:]
+ utility._oops_config.publisher = None
report = {'type': 'NotFound',
'url': 'http://example.com',
'req_vars': {'HTTP_REFERER': 'example.com'}}
@@ -577,7 +576,7 @@
# A request originating from a local site that generates a NotFound
# (404) produces an OOPS.
utility = ErrorReportingUtility()
- del utility._oops_config.publishers[:]
+ utility._oops_config.publisher = None
report = {'type': 'NotFound',
'url': 'http://example.com',
'req_vars': {'HTTP_REFERER': 'http://launchpad.dev/'}}
@@ -587,7 +586,7 @@
# If a 404 is generated and there is no HTTP referer, we don't produce
# an OOPS.
utility = ErrorReportingUtility()
- del utility._oops_config.publishers[:]
+ utility._oops_config.publisher = None
report = {'type': 'NotFound',
'url': 'http://example.com',
'req_vars': {}}
@@ -595,7 +594,7 @@
def test_ignored_report_filtered(self):
utility = ErrorReportingUtility()
- del utility._oops_config.publishers[:]
+ utility._oops_config.publisher = None
report = {'ignore': True}
self.assertEqual(None, utility._oops_config.publish(report))
=== modified file 'lib/lp/testing/fixture.py'
--- lib/lp/testing/fixture.py 2015-10-02 11:35:31 +0000
+++ lib/lp/testing/fixture.py 2017-09-02 13:43:11 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2015 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2017 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Launchpad test fixtures that have no better home."""
@@ -298,7 +298,7 @@
self.channel = self.connection.channel()
self.addCleanup(self.channel.close)
self.oops_config = oops.Config()
- self.oops_config.publishers.append(self._add_oops)
+ self.oops_config.publisher = self._add_oops
self.setUpQueue()
def setUpQueue(self):
@@ -325,6 +325,7 @@
if report['id'] not in self.oops_ids:
self.oopses.append(report)
self.oops_ids.add(report['id'])
+ return [report['id']]
@adapter(ErrorReportEvent)
def _recordOops(self, event):
=== modified file 'lib/lp/testing/tests/test_fixture.py'
--- lib/lp/testing/tests/test_fixture.py 2015-10-06 00:02:50 +0000
+++ lib/lp/testing/tests/test_fixture.py 2017-09-02 13:43:11 +0000
@@ -245,14 +245,14 @@
def test_subscribes_to_events(self):
capture = self.useFixture(CaptureOops())
- publishers = globalErrorUtility._oops_config.publishers[:]
+ publisher = globalErrorUtility._oops_config.publisher
try:
- globalErrorUtility._oops_config.publishers[:] = [notify_publisher]
+ globalErrorUtility._oops_config.publisher = notify_publisher
id = globalErrorUtility.raising(sys.exc_info())['id']
self.assertEqual(id, capture.oopses[0]['id'])
self.assertEqual(1, len(capture.oopses))
finally:
- globalErrorUtility._oops_config.publishers[:] = publishers
+ globalErrorUtility._oops_config.publisher = publisher
class TestCaptureOopsRabbit(TestCase):
@@ -272,9 +272,9 @@
amqp_publisher = oops_amqp.Publisher(
factory, exchange, routing_key, inherit_id=True)
oops = {'id': 'fnor', 'foo': 'dr'}
- self.assertEqual('fnor', amqp_publisher(oops))
+ self.assertEqual(['fnor'], amqp_publisher(oops))
oops2 = {'id': 'quux', 'foo': 'strangelove'}
- self.assertEqual('quux', amqp_publisher(oops2))
+ self.assertEqual(['quux'], amqp_publisher(oops2))
capture.sync()
self.assertEqual([oops, oops2], capture.oopses)
=== modified file 'versions.cfg'
--- versions.cfg 2017-09-01 22:43:16 +0000
+++ versions.cfg 2017-09-02 13:43:11 +0000
@@ -70,11 +70,11 @@
mock = 1.0.1
mocker = 1.1.1
oauth = 1.0
-oops = 0.0.10
-oops-amqp = 0.0.6
-oops-datedir-repo = 0.0.14
+oops = 0.0.13
+oops-amqp = 0.0.8b1
+oops-datedir-repo = 0.0.23
oops-timeline = 0.0.1
-oops-twisted = 0.0.6
+oops-twisted = 0.0.7
oops-wsgi = 0.0.8
ordereddict = 1.1
oslo.config = 1.1.1
@@ -90,7 +90,6 @@
pygpgme = 0.2
pyinotify = 0.9.4
pymacaroons = 0.9.2
-pymongo = 2.1.1
pyOpenSSL = 0.13
pystache = 0.5.3
python-dateutil = 1.5
Follow ups