Skip to content

Commit

Permalink
Add IPubFailure event handler
Browse files Browse the repository at this point in the history
  • Loading branch information
rbu committed May 29, 2018
1 parent 3af5f20 commit f02ffa6
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 16 deletions.
21 changes: 21 additions & 0 deletions src/Products/SiteErrorLog/SiteErrorLog.py
Expand Up @@ -26,17 +26,20 @@
# Python 2
from thread import allocate_lock
from zope.event import notify
from zope.component import adapter
from .interfaces import ErrorRaisedEvent

from AccessControl.class_init import InitializeClass
from AccessControl.SecurityInfo import ClassSecurityInfo
from AccessControl.SecurityManagement import getSecurityManager
from AccessControl.unauthorized import Unauthorized
from Acquisition import aq_base
from Acquisition import aq_acquire
from App.Dialogs import MessageDialog
from OFS.SimpleItem import SimpleItem
from Products.PageTemplates.PageTemplateFile import PageTemplateFile
from zExceptions.ExceptionFormatter import format_exception
from ZPublisher.interfaces import IPubFailure

LOG = logging.getLogger('Zope.SiteErrorLog')

Expand Down Expand Up @@ -329,3 +332,21 @@ def manage_addErrorLog(dispatcher, RESPONSE=None):
RESPONSE.redirect(
dispatcher.DestinationURL() +
'/manage_main?manage_tabs_message=Error+Log+Added.')

@adapter(IPubFailure)
def IPubFailureSubscriber(event):
""" Handles an IPubFailure event triggered by the WSGI Publisher.
This handler forwards the event to the SiteErrorLog object
closest to the published object that the error occured with,
it logs no error if no published object was found.
"""
published = event.request.get('PUBLISHED')
if not published:
return

try:
error_log = aq_acquire(published, '__error_log__', containment=1)
except AttributeError:
pass
else:
error_log.raising(event.exc_info)
2 changes: 2 additions & 0 deletions src/Products/SiteErrorLog/configure.zcml
Expand Up @@ -4,4 +4,6 @@
<five:deprecatedManageAddDelete
class="Products.SiteErrorLog.SiteErrorLog.SiteErrorLog"/>

<subscriber handler=".SiteErrorLog.IPubFailureSubscriber" />

</configure>
36 changes: 20 additions & 16 deletions src/Products/SiteErrorLog/tests/testSiteErrorLog.py
Expand Up @@ -19,6 +19,8 @@
import transaction
from Testing.makerequest import makerequest
from zope.component import adapter, provideHandler
from zope.event import notify
from ZPublisher.pubevents import PubFailure
import Zope2

from Products.SiteErrorLog.interfaces import IErrorRaisedEvent
Expand Down Expand Up @@ -70,13 +72,13 @@ def testSimpleException(self):
dmeth = self.app.doc
dmeth.manage_upload(file="""<dtml-var expr="1/0">""")

# "Faking out" the automatic involvement of the Site Error Log
# by manually calling the method "raising" that gets invoked
# automatically in a normal web request environment.
# Faking the behavior of the WSGIPublisher (object acquisition,
# view calling and failure notification on exception).
try:
dmeth.__call__()
except ZeroDivisionError:
sel_ob.raising(sys.exc_info())
self.app.REQUEST['PUBLISHED'] = dmeth
notify(PubFailure(self.app.REQUEST, sys.exc_info(), False))

# Now look at the SiteErrorLog, it has one more log entry
self.assertEqual(len(sel_ob.getLogEntries()), previous_log_length + 1)
Expand All @@ -94,13 +96,14 @@ def notifyError(evt):
event_logs.append(evt)

provideHandler(notifyError)
# "Faking out" the automatic involvement of the Site Error Log
# by manually calling the method "raising" that gets invoked
# automatically in a normal web request environment.
# Faking the behavior of the WSGIPublisher (object acquisition,
# view calling and failure notification on exception).
try:
dmeth.__call__()
except ZeroDivisionError:
sel_ob.raising(sys.exc_info())
self.app.REQUEST['PUBLISHED'] = dmeth
notify(PubFailure(self.app.REQUEST, sys.exc_info(), False))

self.assertEqual(len(event_logs), 1)
self.assertEqual(event_logs[0]['type'], 'ZeroDivisionError')
self.assertEqual(event_logs[0]['username'], 'Anonymous User')
Expand All @@ -112,8 +115,9 @@ def testForgetException(self):
try:
raise AttributeError("DummyAttribute")
except AttributeError:
info = sys.exc_info()
elog.raising(info)
self.app.REQUEST['PUBLISHED'] = elog
notify(PubFailure(self.app.REQUEST, sys.exc_info(), False))

previous_log_length = len(elog.getLogEntries())

entries = elog.getLogEntries()
Expand Down Expand Up @@ -142,13 +146,13 @@ def testIgnoredException(self):
dmeth = self.app.doc
dmeth.manage_upload(file="""<dtml-var expr="1/0">""")

# "Faking out" the automatic involvement of the Site Error Log
# by manually calling the method "raising" that gets invoked
# automatically in a normal web request environment.
# Faking the behavior of the WSGIPublisher (object acquisition,
# view calling and failure notification on exception).
try:
dmeth.__call__()
except ZeroDivisionError:
sel_ob.raising(sys.exc_info())
self.app.REQUEST['PUBLISHED'] = dmeth
notify(PubFailure(self.app.REQUEST, sys.exc_info(), False))

# Now look at the SiteErrorLog, it must have the same number of
# log entries
Expand All @@ -161,8 +165,8 @@ def testEntryID(self):
try:
raise AttributeError("DummyAttribute")
except AttributeError:
info = sys.exc_info()
elog.raising(info)
self.app.REQUEST['PUBLISHED'] = elog
notify(PubFailure(self.app.REQUEST, sys.exc_info(), False))

entries = elog.getLogEntries()
entry_id = entries[0]['id']
Expand Down

0 comments on commit f02ffa6

Please sign in to comment.