Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Don't report expected exceptions #4

Merged
merged 5 commits into from
Nov 11, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 46 additions & 52 deletions nameko_sentry.py
Original file line number Diff line number Diff line change
@@ -1,84 +1,78 @@
import logging

from eventlet.queue import Queue
from nameko.extensions import DependencyProvider
from raven import Client


class SentryReporter(DependencyProvider):
""" Send exceptions generated by entrypoints to a sentry server.
"""
_gt = None
queue = None
client = None

def _run(self):

while True:
item = self.queue.get()
if item is None:
break

exc_info, message, extra, data = item
self.client.captureException(
exc_info, message=message, extra=extra, data=data)

# these will remain in scope until the next iteration and
# can potentially be large, so delete to reclaim the memory now
del exc_info, message, extra, data, item

def start(self):
self._gt = self.container.spawn_managed_thread(
self._run, protected=True)

def stop(self):
self.queue.put(None)

if self._gt is not None:
self._gt.wait()

def setup(self):
sentry_config = self.container.config.get('SENTRY')

dsn = sentry_config['DSN']
kwargs = sentry_config.get('CLIENT_CONFIG', {})
report_expected_exceptions = sentry_config.get(
'REPORT_EXPECTED_EXCEPTIONS', True
)

self.queue = Queue()
self.client = Client(dsn, **kwargs)
self.report_expected_exceptions = report_expected_exceptions

def format_message(self, worker_ctx, exc_info):
exc_type, exc, _ = exc_info
return (
'Unhandled exception in call {}: '
'{} {!r}'.format(worker_ctx.call_id, exc_type.__name__, str(exc))
)

def is_expected_exception(self, worker_ctx, exc_info):
_, exc, _ = exc_info
expected_exceptions = getattr(
worker_ctx.entrypoint, 'expected_exceptions', tuple())
return isinstance(exc, expected_exceptions)

def build_tags(self, worker_ctx, exc_info):
return {
'call_id': worker_ctx.call_id,
'parent_call_id': worker_ctx.immediate_parent_call_id,
}

def build_extra(self, worker_ctx, exc_info):
_, exc, _ = exc_info
return {
'exc': exc
}

def worker_result(self, worker_ctx, result, exc_info):
if exc_info is None:
return
self.capture_exception(worker_ctx, exc_info)

exc = exc_info[1]
call_id = worker_ctx.call_id
parent_call_id = worker_ctx.immediate_parent_call_id
def capture_exception(self, worker_ctx, exc_info):

expected_exceptions = getattr(
worker_ctx.entrypoint, 'expected_exceptions', tuple())
logger = '{}.{}'.format(
worker_ctx.service_name, worker_ctx.entrypoint.method_name
)

level = logging.ERROR
if expected_exceptions and isinstance(exc, expected_exceptions):
if self.is_expected_exception(worker_ctx, exc_info):
if not self.report_expected_exceptions:
return # nothing to do
level = logging.WARNING
else:
level = logging.ERROR

message = (
'Unhandled exception in call {}: '
'{} {!r}'.format(call_id, exc_info[0].__name__, str(exc))
)

logger = '{}.{}'.format(
worker_ctx.service_name, worker_ctx.entrypoint.method_name)
message = self.format_message(worker_ctx, exc_info)
extra = self.build_extra(worker_ctx, exc_info)
tags = self.build_tags(worker_ctx, exc_info)

data = {
'logger': logger,
'level': level,
'message': message,
'tags': {
'call_id': call_id,
'parent_call_id': parent_call_id,
},
'tags': tags
}

extra = {'exc': exc}

self.queue.put((exc_info, message, extra, data))
self.client.captureException(
exc_info, message=message, extra=extra, data=data
)
Loading