def test_trace_inline(): try: function12() except Exception: tb = sys.exc_info()[2] actual = exception_stack(tb, limit=14) require = _stack_trace_inline assert actual == require, (actual, require)
def test_trace_truncated(): try: function12() except Exception: tb = sys.exc_info()[2] actual = exception_stack(tb, limit=5) require = _stack_trace_limit_truncated assert actual == require, (actual, require)
def test_trace_current_plus_traceback(): try: raise ZeroDivisionError except ZeroDivisionError: tb = sys.exc_info()[2] frame = tb.tb_frame.f_back limit = 10000 actual = exception_stack(tb) require = _format_stack_trace_from_dicts( _extract_stack(frame, 0, limit)+_extract_tb(tb, limit)) assert actual == require, (actual, require)
def test_trace_line_limit(): settings = global_settings() original = settings.max_stack_trace_lines settings.max_stack_trace_lines = 40 try: function12() except Exception: tb = sys.exc_info()[2] actual = exception_stack(tb) finally: settings.max_stack_trace_lines = original # 40 lines of stack trace and one line that says # 'Traceback (most recent call last):' assert len(actual) == 41
def test_trace_exception_full(): try: function12() except Exception: tb = sys.exc_info()[2] actual = exception_stack(tb)
def _test_trace_passed2b(tb): actual = exception_stack(tb, limit=15) require = _stack_trace_passed2 assert actual == require, (actual, require)
def test_trace_passed1(): tb = _test_trace_passed1() actual = exception_stack(tb, limit=15) require = _stack_trace_passed1 assert actual == require, (actual, require)
def record_exception(self, exc=None, value=None, tb=None, params={}, ignore_errors=[]): # Bail out if the transaction is not active or # collection of errors not enabled. if not self._settings: return settings = self._settings error_collector = settings.error_collector if not error_collector.enabled: return if not settings.collect_errors and not settings.collect_error_events: return # If no exception details provided, use current exception. if exc is None and value is None and tb is None: exc, value, tb = sys.exc_info() # Has to be an error to be logged. if exc is None or value is None or tb is None: return # Where ignore_errors is a callable it should return a # tri-state variable with the following behavior. # # True - Ignore the error. # False- Record the error. # None - Use the default ignore rules. should_ignore = None if callable(ignore_errors): should_ignore = ignore_errors(exc, value, tb) if should_ignore: return module = value.__class__.__module__ name = value.__class__.__name__ if should_ignore is None: # We need to check for module.name and module:name. # Originally we used module.class but that was # inconsistent with everything else which used # module:name. So changed to use ':' as separator, but # for backward compatibility need to support '.' as # separator for time being. Check that with the ':' # last as we will use that name as the exception type. if module: fullname = '%s.%s' % (module, name) else: fullname = name if not callable(ignore_errors) and fullname in ignore_errors: return if fullname in error_collector.ignore_errors: return if module: fullname = '%s:%s' % (module, name) else: fullname = name if not callable(ignore_errors) and fullname in ignore_errors: return if fullname in error_collector.ignore_errors: return else: if module: fullname = '%s:%s' % (module, name) else: fullname = name # Only remember up to limit of what can be caught for a # single transaction. This could be trimmed further # later if there are already recorded errors and would # go over the harvest limit. if len(self._errors) >= settings.agent_limits.errors_per_transaction: return # Only add params if High Security Mode is off. custom_params = {} if settings.high_security: if params: _logger.debug('Cannot add custom parameters in ' 'High Security Mode.') else: try: for k, v in params.items(): name, val = process_user_attribute(k, v) if name: custom_params[name] = val except Exception: _logger.debug('Parameters failed to validate for unknown ' 'reason. Dropping parameters for error: %r. Check ' 'traceback for clues.', fullname, exc_info=True) custom_params = {} # Check to see if we need to strip the message before recording it. if (settings.strip_exception_messages.enabled and fullname not in settings.strip_exception_messages.whitelist): message = STRIP_EXCEPTION_MESSAGE else: try: # Favor unicode in exception messages. message = six.text_type(value) except Exception: try: # If exception cannot be represented in unicode, this means # that it is a byte string encoded with an encoding # that is not compatible with the default system encoding. # So, just pass this byte string along. message = str(value) except Exception: message = '<unprintable %s object>' % type(value).__name__ # Check that we have not recorded this exception # previously for this transaction due to multiple # error traces triggering. This is not going to be # exact but the UI hides exceptions of same type # anyway. Better that we under count exceptions of # same type and message rather than count same one # multiple times. for error in self._errors: if error.type == fullname and error.message == message: return node = newrelic.core.error_node.ErrorNode( timestamp=time.time(), type=fullname, message=message, stack_trace=exception_stack(tb), custom_params=custom_params, file_name=None, line_number=None, source=None) # TODO Errors are recorded in time order. If # there are two exceptions of same type and # different message, the UI displays the first # one. In the PHP agent it was recording the # errors in reverse time order and so the UI # displayed the last one. What is the the # official order in which they should be sent. self._errors.append(node)