Skip to content
This repository has been archived by the owner on Jul 13, 2023. It is now read-only.

Commit

Permalink
feat: send sentry the current stack when lacking a Failure tb
Browse files Browse the repository at this point in the history
it's sent as sentry's top level stacktrace vs its explicit exception
stacktrace

issue #613
  • Loading branch information
pjenvey committed Aug 22, 2016
1 parent 090242d commit 1ecb558
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 14 deletions.
24 changes: 19 additions & 5 deletions autopush/logging.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import boto3
import raven
from raven.transport.twisted import TwistedHTTPTransport
from raven.utils.stacks import iter_stack_frames
from twisted.internet import reactor
from twisted.logger import (
formatEvent,
Expand Down Expand Up @@ -90,11 +91,7 @@ def __init__(self, logger_name, log_level="debug", log_format="json",

def __call__(self, event):
if self.raven_client and 'log_failure' in event:
f = event["log_failure"]
reactor.callFromThread(
self.raven_client.captureException,
exc_info=(f.type, f.value, f.getTracebackObject())
)
self.raven_log(event)

if event["log_level"] < self.log_level:
return
Expand All @@ -108,6 +105,23 @@ def __call__(self, event):
self._output.write(unicode(text))
self._output.flush()

def raven_log(self, event):
f = event["log_failure"]
stack = extra = None
tb = f.getTracebackObject()
if not tb:
# include the current stack for at least some context
stack = list(iter_stack_frames())[4:] # approx.
extra = dict(no_failure_tb=True)
reactor.callFromThread(
self.raven_client.captureException,
exc_info=(f.type, f.value, tb),
stack=stack,
extra=extra,
)
# just incase
del tb

def json_format(self, event):
error = bool(event.get("isError")) or "log_failure" in event
ts = event["log_time"]
Expand Down
48 changes: 39 additions & 9 deletions autopush/tests/test_logging.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import json
import os
import sys

import cyclone.web
import twisted.internet
Expand Down Expand Up @@ -37,28 +38,57 @@ def setUp(self):
self.sentry = sentry
self._site = site
self._port = reactor.listenTCP(9999, site)
os.environ["SENTRY_DSN"] = "http://PUBKEY:SECKEY@localhost:9999/1"

def tearDown(self):
os.environ.pop("SENTRY_DSN", None)
reactor.removeAll()

def test_sentry_logging(self):
dsn = "http://PUBKEY:SECKEY@localhost:9999/1"
os.environ["SENTRY_DSN"] = dsn
pl = PushLogger.setup_logging("Autopush", sentry_dsn=True)

log.failure("error", failure.Failure(Exception("eek")))
self.flushLoggedErrors()
d = Deferred()

def check():
if len(self.sentry.logged):
eq_(len(self.sentry.logged), 1)
self._port.stopListening()
pl.stop()
d.callback(True)
else: # pragma: nocover
logged = self.sentry.logged
if not logged: # pragma: nocover
reactor.callLater(0, check)
del os.environ["SENTRY_DSN"]
return
eq_(len(logged), 1)
self._port.stopListening()
pl.stop()
d.callback(True)
reactor.callLater(0, check)
return d

def test_include_stacktrace_when_no_tb(self):
pl = PushLogger.setup_logging("Autopush", sentry_dsn=True)

log.failure("foo", failure.Failure(ZeroDivisionError(), exc_tb=None))
self.flushLoggedErrors()
d = Deferred()
co = sys._getframe().f_code
filename = co.co_filename
testname = co.co_name

def check():
logged = self.sentry.logged
if not logged: # pragma: nocover
reactor.callLater(0, check)
return

eq_(len(logged), 1)
# Ensure a top level stacktrace was included
stacktrace = logged[0]['stacktrace']
assert any(
filename == f['abs_path'] and testname == f['function']
for f in stacktrace['frames'])

self._port.stopListening()
pl.stop()
d.callback(True)
reactor.callLater(0, check)
return d

Expand Down

0 comments on commit 1ecb558

Please sign in to comment.