Merge lp:~cjwatson/launchpad/basemailer-oops into lp:launchpad

Proposed by Colin Watson
Status: Merged
Merged at revision: 17683
Proposed branch: lp:~cjwatson/launchpad/basemailer-oops
Merge into: lp:launchpad
Diff against target: 98 lines (+30/-9)
2 files modified
lib/lp/services/mail/basemailer.py (+25/-9)
lib/lp/services/mail/tests/test_basemailer.py (+5/-0)
To merge this branch: bzr merge lp:~cjwatson/launchpad/basemailer-oops
Reviewer Review Type Date Requested Status
William Grant code Approve
Review via email: mp+264856@code.launchpad.net

Commit message

Improve OOPS logging when BaseMailer fails to send a message.

Description of the change

Improve OOPS logging when BaseMailer fails to send a message.

Future scripts using BaseMailer will need to pass in a request argument. At the moment, all uses of BaseMailer are in jobs or in the buildmaster, and I think in both those cases it's OK just to not bother passing in a request.

To post a comment you must log in.
Revision history for this message
William Grant (wgrant) :
review: Approve (code)
Revision history for this message
William Grant (wgrant) :
review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/lp/services/mail/basemailer.py'
2--- lib/lp/services/mail/basemailer.py 2015-07-14 12:55:00 +0000
3+++ lib/lp/services/mail/basemailer.py 2015-07-21 15:47:35 +0000
4@@ -10,6 +10,10 @@
5 from collections import OrderedDict
6 import logging
7 from smtplib import SMTPException
8+import sys
9+
10+from zope.component import getUtility
11+from zope.error.interfaces import IErrorReportingUtility
12
13 from lp.services.mail.helpers import get_email_template
14 from lp.services.mail.notificationrecipientset import NotificationRecipientSet
15@@ -35,7 +39,7 @@
16
17 def __init__(self, subject, template_name, recipients, from_address,
18 delta=None, message_id=None, notification_type=None,
19- mail_controller_class=None):
20+ mail_controller_class=None, request=None):
21 """Constructor.
22
23 :param subject: A Python dict-replacement template for the subject
24@@ -49,6 +53,8 @@
25 not supplied, random message-ids will be used.
26 :param mail_controller_class: The class of the mail controller to
27 use to send the mails. Defaults to `MailController`.
28+ :param request: An optional `IErrorReportRequest` to use when
29+ logging OOPSes.
30 """
31 self._subject_template = subject
32 self._template_name = template_name
33@@ -63,6 +69,7 @@
34 if mail_controller_class is None:
35 mail_controller_class = MailController
36 self._mail_controller_class = mail_controller_class
37+ self.request = request
38
39 def _getToAddresses(self, recipient, email):
40 return [format_address(recipient.displayname, email)]
41@@ -165,20 +172,29 @@
42 """Send notifications to all recipients."""
43 # We never want SMTP errors to propagate from this function.
44 for email, recipient in self._recipients.getRecipientPersons():
45+ ctrl = self.generateEmail(email, recipient)
46 try:
47- ctrl = self.generateEmail(email, recipient)
48 ctrl.send()
49- except SMTPException as e:
50+ except SMTPException:
51 # If the initial sending failed, try again without
52 # attachments.
53+ ctrl = self.generateEmail(
54+ email, recipient, force_no_attachments=True)
55 try:
56- ctrl = self.generateEmail(
57- email, recipient, force_no_attachments=True)
58 ctrl.send()
59- except SMTPException as e:
60- # Don't want an entire stack trace, just some details.
61- self.logger.warning(
62- 'send failed for %s, %s' % (email, e))
63+ except SMTPException:
64+ error_utility = getUtility(IErrorReportingUtility)
65+ oops_vars = {
66+ "message_id": ctrl.headers.get("Message-Id"),
67+ "notification_type": self.notification_type,
68+ "recipient": ", ".join(ctrl.to_addrs),
69+ "subject": ctrl.subject,
70+ }
71+ with error_utility.oopsMessage(oops_vars):
72+ oops = error_utility.raising(
73+ sys.exc_info(), self.request)
74+ self.logger.info(
75+ "Mail resulted in OOPS: %s" % oops.get("id"))
76
77
78 class RecipientReason:
79
80=== modified file 'lib/lp/services/mail/tests/test_basemailer.py'
81--- lib/lp/services/mail/tests/test_basemailer.py 2015-07-14 12:55:00 +0000
82+++ lib/lp/services/mail/tests/test_basemailer.py 2015-07-21 15:47:35 +0000
83@@ -179,6 +179,9 @@
84 notifications = pop_notifications()
85 self.assertEqual(1, len(notifications))
86 self.assertEqual('Good <good@example.com>', notifications[0]['To'])
87+ # And an OOPS is logged.
88+ self.assertEqual(1, len(self.oopses))
89+ self.assertIn("SMTPException: boom", self.oopses[0]["tb_text"])
90
91 def test_sendall_first_failure_strips_attachments(self):
92 # If sending an email fails, we try again without the (almost
93@@ -213,3 +216,5 @@
94 self.assertEqual(
95 'Excessively large attachments removed.',
96 bad_parts[1].get_payload(decode=True))
97+ # And no OOPS is logged.
98+ self.assertEqual(0, len(self.oopses))