def test_session_tracker_adds_session_object_to_queue(self): tracker = SessionTracker(self.config) tracker.auto_sessions = True tracker.start_session() self.assertEqual(len(tracker.session_counts), 1) for key, value in tracker.session_counts.items(): self.assertEqual(value, 1)
def __init__(self, configuration=None, install_sys_hook=True, **kwargs): self.configuration = configuration or Configuration() self.session_tracker = SessionTracker(self.configuration) self.configuration.configure(**kwargs) if install_sys_hook: self.install_sys_hook()
def __init__(self, configuration: Optional[Configuration] = None, install_sys_hook=True, **kwargs): self.configuration = configuration or Configuration() # type: Configuration # noqa: E501 self.session_tracker = SessionTracker(self.configuration) self.configuration.configure(**kwargs) if install_sys_hook: self.install_sys_hook()
def test_session_tracker_stores_session_in_threadlocals(self): locs = ThreadLocals.get_instance() tracker = SessionTracker(self.config) tracker.auto_sessions = True tracker.start_session() session = locs.get_item('bugsnag-session') self.assertTrue('id' in session) self.assertTrue('startedAt' in session) self.assertTrue('events' in session) self.assertTrue('handled' in session['events']) self.assertTrue('unhandled' in session['events']) self.assertEqual(session['events']['handled'], 0) self.assertEqual(session['events']['unhandled'], 0)
def test_session_tracker_sessions_are_unique(self): tracker = SessionTracker(self.config) tracker.auto_sessions = True locs = ThreadLocals.get_instance() tracker.start_session() session_one = locs.get_item('bugsnag-session').copy() tracker.start_session() session_two = locs.get_item('bugsnag-session').copy() self.assertNotEqual(session_one['id'], session_two['id'])
class TestSessionMiddleware(unittest.TestCase): def setUp(self): self.config = Configuration() self.config.configure(api_key='fff', auto_capture_sessions=False) self.sessiontracker = SessionTracker(self.config) self.sessiontracker.auto_sessions = True # Stub session delivery queue def tearDown(self): pass def test_increment_counts(self): """ Every event should keep a list of prior events which occurred in the session """ def next_callable(event): pass middleware = SessionMiddleware(next_callable) self.sessiontracker.start_session() event = Notification(Exception('shucks'), self.config, None) middleware(event) assert event.session['events']['unhandled'] == 0 assert event.session['events']['handled'] == 1 event2 = Notification(Exception('oh no'), self.config, None) middleware(event2) assert event2.session['events']['unhandled'] == 0 assert event2.session['events']['handled'] == 2 # Session counts should not change for events already handled assert event.session['events']['unhandled'] == 0 assert event.session['events']['handled'] == 1
class Client(object): """ A Bugsnag monitoring and reporting client. >>> client = Client(api_key='...') """ def __init__(self, configuration=None, install_sys_hook=True, **kwargs): self.configuration = configuration or Configuration() self.session_tracker = SessionTracker(self.configuration) self.configuration.configure(**kwargs) if install_sys_hook: self.install_sys_hook() def capture(self, exceptions=None, **options): """ Run a block of code within the clients context. Any exception raised will be reported to bugsnag. >>> with client.capture(): >>> raise Exception('an exception passed to bugsnag then reraised') The context can optionally include specific types to capture. >>> with client.capture((TypeError,)): >>> raise Exception('an exception which does get captured') Alternately, functions can be decorated to capture any exceptions thrown during execution and reraised. >>> @client.capture >>> def foo(): >>> raise Exception('an exception passed to bugsnag then reraised') The decoration can optionally include specific types to capture. >>> @client.capture((TypeError,)) >>> def foo(): >>> raise Exception('an exception which does not get captured') """ if isinstance(exceptions, FunctionType): return ClientContext(self, (Exception, ))(exceptions) return ClientContext(self, exceptions, **options) def notify(self, exception, asynchronous=None, **options): """ Notify bugsnag of an exception. >>> client.notify(Exception('Example')) """ notification = Notification(exception, self.configuration, RequestConfiguration.get_instance(), **options) self.deliver(notification, asynchronous=asynchronous) def notify_exc_info(self, exc_type, exc_value, traceback, asynchronous=None, **options): """ Notify bugsnag of an exception via exc_info. >>> client.notify_exc_info(*sys.exc_info()) """ exception = exc_value options['traceback'] = traceback notification = Notification(exception, self.configuration, RequestConfiguration.get_instance(), **options) self.deliver(notification, asynchronous=asynchronous) def excepthook(self, exc_type, exc_value, traceback): if self.configuration.auto_notify: self.notify_exc_info( exc_type, exc_value, traceback, severity='error', unhandled=True, severity_reason={'type': 'unhandledException'}) def install_sys_hook(self): self.sys_excepthook = sys.excepthook def excepthook(*exc_info): self.excepthook(*exc_info) if self.sys_excepthook: self.sys_excepthook(*exc_info) sys.excepthook = excepthook sys.excepthook.bugsnag_client = self if hasattr(threading, 'excepthook'): self.threading_excepthook = threading.excepthook def threadhook(args): self.excepthook(args[0], args[1], args[2]) if self.threading_excepthook: self.threading_excepthook(args) threading.excepthook = threadhook threading.excepthook.bugsnag_client = self def uninstall_sys_hook(self): client = getattr(sys.excepthook, 'bugsnag_client', None) if client is self: sys.excepthook = self.sys_excepthook self.sys_excepthook = None if hasattr(threading, 'excepthook'): client = getattr(threading.excepthook, 'bugsnag_client', None) if client is self: threading.excepthook = self.threading_excepthook self.threading_excepthook = None def deliver(self, notification, asynchronous=None): # type: ignore """ Deliver the exception notification to Bugsnag. """ if not self.should_deliver(notification): return def run_middleware(): initial_severity = notification.severity initial_reason = notification.severity_reason.copy() def send_payload(): if asynchronous is None: options = {} else: options = {'asynchronous': asynchronous} if notification.api_key is None: bugsnag.logger.warning( "No API key configured, couldn't notify") return if initial_severity != notification.severity: notification.severity_reason = { 'type': 'userCallbackSetSeverity' } else: notification.severity_reason = initial_reason payload = notification._payload() try: self.configuration.delivery.deliver( self.configuration, payload, options) except Exception as e: bugsnag.logger.exception('Notifying Bugsnag failed %s', e) # Trigger session delivery self.session_tracker.send_sessions() self.configuration.middleware.run(notification, send_payload) self.configuration.internal_middleware.run(notification, run_middleware) def should_deliver(self, notification): # type: (Notification) -> bool # Return early if we shouldn't notify for current release stage if not self.configuration.should_notify(): return False # Return early if we should ignore exceptions of this type if self.configuration.should_ignore(notification.exception): return False return True def log_handler(self, extra_fields=None): return BugsnagHandler(client=self, extra_fields=extra_fields)
def setUp(self): self.config = Configuration() self.config.configure(api_key='fff', auto_capture_sessions=False) self.sessiontracker = SessionTracker(self.config) self.sessiontracker.auto_sessions = True # Stub session delivery queue
class Client(object): """ A Bugsnag monitoring and reporting client. >>> client = Client(api_key='...') """ def __init__(self, configuration=None, install_sys_hook=True, **kwargs): self.configuration = configuration or Configuration() self.session_tracker = SessionTracker(self.configuration) self.configuration.configure(**kwargs) if install_sys_hook: self.install_sys_hook() def capture(self, exceptions=None, **options): """ Run a block of code within the clients context. Any exception raised will be reported to bugsnag. >>> with client.capture(): >>> raise Exception('an exception passed to bugsnag then reraised') The context can optionally include specific types to capture. >>> with client.capture((TypeError,)): >>> raise Exception('an exception which does get captured') Alternately, functions can be decorated to capture any exceptions thrown during execution and reraised. >>> @client.capture >>> def foo(): >>> raise Exception('an exception passed to bugsnag then reraised') The decoration can optionally include specific types to capture. >>> @client.capture((TypeError,)) >>> def foo(): >>> raise Exception('an exception which does not get captured') """ if isinstance(exceptions, FunctionType): return ClientContext(self, (Exception,))(exceptions) return ClientContext(self, exceptions, **options) def notify(self, exception, **options): """ Notify bugsnag of an exception. >>> client.notify(Exception('Example')) """ notification = Notification(exception, self.configuration, RequestConfiguration.get_instance(), **options) self.deliver(notification) def notify_exc_info(self, exc_type, exc_value, traceback, **options): """ Notify bugsnag of an exception via exc_info. >>> client.notify_exc_info(*sys.exc_info()) """ exception = exc_value options['traceback'] = traceback notification = Notification(exception, self.configuration, RequestConfiguration.get_instance(), **options) self.deliver(notification) def excepthook(self, exc_type, exc_value, traceback): if self.configuration.auto_notify: self.notify_exc_info( exc_type, exc_value, traceback, severity='error', unhandled=True, severity_reason={ 'type': 'unhandledException' }) def install_sys_hook(self): self.sys_excepthook = sys.excepthook def excepthook(*exc_info): self.excepthook(*exc_info) if self.sys_excepthook: self.sys_excepthook(*exc_info) sys.excepthook = excepthook sys.excepthook.bugsnag_client = self def uninstall_sys_hook(self): client = getattr(sys.excepthook, 'bugsnag_client', None) if client is self: sys.excepthook = self.sys_excepthook self.sys_excepthook = None def deliver(self, notification): # type: (Notification) -> None """ Deliver the exception notification to Bugsnag. """ if not self.should_deliver(notification): return def run_middleware(): initial_severity = notification.severity initial_reason = notification.severity_reason.copy() def send_payload(): if notification.api_key is None: bugsnag.logger.warning( "No API key configured, couldn't notify") return if initial_severity != notification.severity: notification.severity_reason = { 'type': 'userCallbackSetSeverity' } else: notification.severity_reason = initial_reason payload = notification._payload() try: self.configuration.delivery.deliver(self.configuration, payload) except Exception as e: bugsnag.logger.exception('Notifying Bugsnag failed %s', e) # Trigger session delivery self.session_tracker.send_sessions() self.configuration.middleware.run(notification, send_payload) self.configuration.internal_middleware.run(notification, run_middleware) def should_deliver(self, notification): # type: (Notification) -> bool # Return early if we shouldn't notify for current release stage if not self.configuration.should_notify(): return False # Return early if we should ignore exceptions of this type if self.configuration.should_ignore(notification.exception): return False return True def log_handler(self, extra_fields=None): return BugsnagHandler(client=self, extra_fields=extra_fields)