def test_add_exception_with_additional_data(): stack_trace_format = 'stack trace %d' message_format = 'message %d' tested_exception_types = [ ZeroDivisionError, RuntimeError, NameError, TypeError ] additional_data = {'key': 'value', 'key2': 'othervalue'} trace = trace_factory.get_or_create_trace() for i, exception_type in enumerate(tested_exception_types): try: raise exception_type(message_format % i) except exception_type as e: trace.add_exception(e, stack_trace_format % i, additional_data) assert len(trace.exceptions) == len(tested_exception_types) for i, exception_type in enumerate(tested_exception_types): current_exception = trace.exceptions[i] assert current_exception['type'] == str(exception_type) assert current_exception['message'] == message_format % i assert current_exception['traceback'] == stack_trace_format % i assert type(current_exception['time']) == float assert current_exception['additional_data'] == additional_data
def _gcp_wrapper(*args, **kwargs): """ Generic google function wrapper """ trace = epsagon.trace.trace_factory.get_or_create_trace() trace.prepare() try: runner = GoogleFunctionRunner(time.time(), ) # pylint: disable=W0703 except Exception as exception: # Regress to python runner. warnings.warn( 'GCP environment is invalid, using simple python wrapper', EpsagonWarning) trace.add_exception(exception, traceback.format_exc()) return epsagon.wrappers.python_function.wrap_python_function( func, args, kwargs) constants.COLD_START = False result = None try: result = func(*args, **kwargs) return result # pylint: disable=W0703 except Exception as exception: runner.set_exception(exception, traceback.format_exc()) raise finally: try: if not trace.metadata_only: runner.resource['metadata']['return_value'] = result # pylint: disable=W0703 except Exception as exception: trace.add_exception(exception, traceback.format_exc()) try: trace.add_event(runner) epsagon.trace.trace_factory.send_traces() # pylint: disable=W0703 except Exception: pass
def _before_request(self): """ Runs when new request comes in. :return: None. """ # Ignoring non relevant content types. self.ignored_request = ignore_request('', request.path.lower()) if self.ignored_request: return trace = epsagon.trace.trace_factory.get_or_create_trace() trace.prepare() # Create flask runner with current request. try: self.runner = epsagon.runners.flask.FlaskRunner( time.time(), self.app, request) trace.set_runner(self.runner) # Collect metadata in case this is a container. collect_container_metadata(self.runner.resource['metadata']) # pylint: disable=W0703 except Exception as exception: # Regress to python runner. warnings.warn('Could not extract request', EpsagonWarning) trace.add_exception(exception, traceback.format_exc()) # Extract HTTP trigger data. try: trigger = epsagon.triggers.http.HTTPTriggerFactory.factory( time.time(), request) if trigger: trace.add_event(trigger) # pylint: disable=W0703 except Exception as exception: trace.add_exception( exception, traceback.format_exc(), )
def test_add_exception(): stack_trace_format = 'stack trace %d' message_format = 'message %d' tested_exception_types = [ ZeroDivisionError, RuntimeError, NameError, TypeError ] trace = trace_factory.get_or_create_trace() for i, exception_type in enumerate(tested_exception_types): try: raise exception_type(message_format % i) except exception_type as e: trace.add_exception(e, stack_trace_format % i) assert len(trace.exceptions) == len(tested_exception_types) for i, exception_type in enumerate(tested_exception_types): current_exception = trace.exceptions[i] assert current_exception['type'] == str(exception_type) assert current_exception['message'] == message_format % i assert current_exception['traceback'] == stack_trace_format % i assert type(current_exception['time']) == float
def _lambda_wrapper(*args, **kwargs): """ Generic Lambda function wrapper """ trace = epsagon.trace.trace_factory.get_or_create_trace() trace.prepare() try: event, context = args except ValueError: # This can happen when someone manually calls handler without # parameters / sends kwargs. In such case we ignore this trace. return func(*args, **kwargs) try: runner = epsagon.runners.aws_lambda.LambdaRunner( time.time(), context) trace.set_runner(runner) # pylint: disable=W0703 except Exception as exception: # Regress to python runner. warnings.warn( 'Lambda context is invalid, using simple python wrapper', EpsagonWarning) trace.add_exception(exception, traceback.format_exc()) return epsagon.wrappers.python_function.wrap_python_function( func, args, kwargs) constants.COLD_START = False try: trace.add_event( epsagon.triggers.aws_lambda.LambdaTriggerFactory.factory( time.time(), event, context)) # pylint: disable=W0703 except Exception as exception: trace.add_exception(exception, traceback.format_exc(), additional_data={'event': event}) if not trace.disable_timeout_send: trace.set_timeout_handler(context) result = None try: result = func(*args, **kwargs) if trace.propagate_lambda_id and isinstance(result, dict): result[EPSAGON_EVENT_ID_KEY] = runner.event_id runner.resource['metadata']['propagation_enabled'] = True return result # pylint: disable=W0703 except Exception as exception: runner.set_exception(exception, traceback.format_exc(), handled=False) raise finally: try: _add_status_code(runner, result) if not trace.metadata_only: runner.resource['metadata']['return_value'] = result # pylint: disable=W0703 except Exception as exception: trace.add_exception( exception, traceback.format_exc(), ) try: if not trace.disable_timeout_send: epsagon.trace.Trace.reset_timeout_handler() # pylint: disable=W0703 except Exception: pass try: epsagon.trace.trace_factory.send_traces() # pylint: disable=W0703 except Exception: pass
def _lambda_wrapper(*args, **kwargs): """ Generic Step Function wrapper """ trace = epsagon.trace.trace_factory.get_or_create_trace() trace.prepare() try: event, context = args except ValueError: # This can happen when someone manually calls handler without # parameters / sends kwargs. In such case we ignore this trace. return func(*args, **kwargs) try: runner = epsagon.runners.aws_lambda.StepLambdaRunner( time.time(), context) trace.set_runner(runner) # pylint: disable=W0703 except Exception as exception: # Regress to python runner. warnings.warn( 'Lambda context is invalid, using simple python wrapper', EpsagonWarning) trace.add_exception(exception, traceback.format_exc()) return epsagon.wrappers.python_function.wrap_python_function( func, args, kwargs) constants.COLD_START = False try: trace.add_event( epsagon.triggers.aws_lambda.LambdaTriggerFactory.factory( time.time(), event, context)) # pylint: disable=W0703 except Exception as exception: trace.add_exception(exception, traceback.format_exc(), additional_data={'event': event}) trace.set_timeout_handler(context) result = None try: result = func(*args, **kwargs) steps_dict = epsagon.utils.find_in_object(event, STEP_DICT_NAME) if isinstance(result, dict): # If the step functions data is not present, then this is the # First step. if steps_dict is None: steps_dict = {'id': str(uuid4()), 'step_num': 0} # Otherwise, just advance the steps number by one. else: # don't change trigger data steps_dict = copy.deepcopy(steps_dict) steps_dict['step_num'] += 1 result[STEP_DICT_NAME] = steps_dict runner.add_step_data(steps_dict) return result # pylint: disable=W0703 except Exception as exception: runner.set_exception(exception, traceback.format_exc(), handled=False) raise finally: try: _add_status_code(runner, result) if not trace.metadata_only: runner.resource['metadata']['return_value'] = ( copy.deepcopy(result)) # pylint: disable=W0703 except Exception as exception: trace.add_exception( exception, traceback.format_exc(), ) try: epsagon.trace.Trace.reset_timeout_handler() # pylint: disable=W0703 except Exception: pass try: epsagon.trace.trace_factory.send_traces() # pylint: disable=W0703 except Exception: pass
def _lambda_wrapper(*args, **kwargs): """ Generic Step Function wrapper """ cold_start_duration = time.time() - constants.COLD_START_TIME trace = epsagon.trace.trace_factory.get_or_create_trace() trace.prepare() try: event, context = args except ValueError: # This can happen when someone manually calls handler without # parameters / sends kwargs. In such case we ignore this trace. return func(*args, **kwargs) try: runner = epsagon.runners.aws_lambda.StepLambdaRunner( time.time(), context ) trace.set_runner(runner) # pylint: disable=W0703 except Exception as exception: # Regress to python runner. warnings.warn( 'Lambda context is invalid, using simple python wrapper', EpsagonWarning ) trace.add_exception( exception, traceback.format_exc() ) return epsagon.wrappers.python_function.wrap_python_function( func, args, kwargs ) if constants.COLD_START: runner.resource['metadata'][ 'aws.lambda.cold_start_duration' ] = cold_start_duration constants.COLD_START = False try: trace.add_event( epsagon.triggers.aws_lambda.LambdaTriggerFactory.factory( time.time(), event, context ) ) # pylint: disable=W0703 except Exception as exception: trace.add_exception( exception, traceback.format_exc(), additional_data={'event': event} ) trace.set_timeout_handler(context) result = None try: result = func(*args, **kwargs) steps_data = epsagon.utils.find_in_object( event, STEP_DICT_NAME ) if isinstance(result, dict): epsagon.utils.print_debug( 'Step function result type is dict, steps_data={}'.format( steps_data ) ) # If the step functions data is not present, then this is the # First step. if steps_data is None: epsagon.utils.print_debug( 'Could not find existing steps data' ) steps_dict = {'id': str(uuid4()), 'step_num': 0} path = [] # Otherwise, just advance the steps number by one. else: # don't change trigger data steps_dict, path = steps_data steps_dict = copy.deepcopy(steps_dict) if 'step_num' in steps_dict: steps_dict['step_num'] += 1 epsagon.utils.print_debug( 'Steps data found, new dict={}'.format(steps_dict) ) else: steps_dict = {'id': str(uuid4()), 'step_num': 0} epsagon.utils.print_debug( 'Steps data not found, new dict={}'.format( steps_dict ) ) result_path = result # Tries to inject the steps data in the configured # or same path where it was found if isinstance(trace.step_dict_output_path, list): path = trace.step_dict_output_path try: for sub_path in path: result_path = result_path.get(sub_path) except Exception as exception: # pylint: disable=broad-except epsagon.utils.print_debug( 'Could not put steps in path={}'.format(path) ) if result_path: epsagon.utils.print_debug( 'Adding steps dict to result_path={}'.format( result_path ) ) result_path[STEP_DICT_NAME] = steps_dict else: epsagon.utils.print_debug( 'Adding steps dict to root result' ) result[STEP_DICT_NAME] = steps_dict runner.add_step_data(steps_dict) return result # pylint: disable=W0703 except Exception as exception: runner.set_exception( exception, traceback.format_exc(), handled=False ) raise finally: try: _add_status_code(runner, result) if not trace.metadata_only: runner.resource['metadata']['return_value'] = ( copy.deepcopy(result) ) # pylint: disable=W0703 except Exception as exception: trace.add_exception( exception, traceback.format_exc(), ) try: epsagon.trace.Trace.reset_timeout_handler() # pylint: disable=W0703 except Exception: pass try: epsagon.trace.trace_factory.send_traces() # pylint: disable=W0703 except Exception: pass
def _lambda_wrapper(*args, **kwargs): """ Generic Lambda function wrapper """ cold_start_duration = time.time() - constants.COLD_START_TIME trace = epsagon.trace.trace_factory.get_or_create_trace() trace.prepare() try: event, context = args except ValueError: # This can happen when someone manually calls handler without # parameters / sends kwargs. In such case we ignore this trace. return func(*args, **kwargs) if isinstance(event, dict): ignored_payloads = _get_ignored_payloads() if ignored_payloads and event in ignored_payloads: return func(*args, **kwargs) if os.environ.get( 'AWS_LAMBDA_INITIALIZATION_TYPE' ) == 'provisioned-concurrency': constants.COLD_START = False try: runner = epsagon.runners.aws_lambda.LambdaRunner( time.time(), context ) trace.set_runner(runner) # pylint: disable=W0703 except Exception as exception: # Regress to python runner. warnings.warn( 'Lambda context is invalid, using simple python wrapper', EpsagonWarning ) trace.add_exception( exception, traceback.format_exc() ) return epsagon.wrappers.python_function.wrap_python_function( func, args, kwargs ) if constants.COLD_START: runner.resource['metadata'][ 'aws.lambda.cold_start_duration' ] = cold_start_duration constants.COLD_START = False try: trace.add_event( epsagon.triggers.aws_lambda.LambdaTriggerFactory.factory( time.time(), event, context ) ) # pylint: disable=W0703 except Exception as exception: trace.add_exception( exception, traceback.format_exc(), additional_data={'event': event} ) if not trace.disable_timeout_send: trace.set_timeout_handler(context) result = None try: result = func(*args, **kwargs) if trace.propagate_lambda_id and isinstance(result, dict): result[EPSAGON_EVENT_ID_KEY] = runner.event_id runner.resource['metadata']['propagation_enabled'] = True return result # pylint: disable=W0703 except Exception as exception: runner.set_exception( exception, traceback.format_exc(), handled=False ) raise finally: try: _add_status_code(runner, result) if not trace.metadata_only: runner.resource['metadata']['return_value'] = result # pylint: disable=W0703 except Exception as exception: trace.add_exception( exception, traceback.format_exc(), ) try: if not trace.disable_timeout_send: epsagon.trace.Trace.reset_timeout_handler() # pylint: disable=W0703 except Exception: pass try: epsagon.trace.trace_factory.send_traces() # pylint: disable=W0703 except Exception: epsagon.utils.print_debug('Failed to send Lambda trace')
def _tencent_function_wrapper(*args, **kwargs): """ Generic SCF function wrapper """ start_time = time.time() cold_start_duration = start_time - constants.COLD_START_TIME trace = epsagon.trace.trace_factory.get_or_create_trace() trace.prepare() try: event, context = args except ValueError: # This can happen when someone manually calls handler without # parameters / sends kwargs. In such case we ignore this trace. return func(*args, **kwargs) try: runner = epsagon.runners.tencent_function.TencentFunctionRunner( start_time, context) trace.set_runner(runner) # pylint: disable=W0703 except Exception as exception: # Regress to python runner. warnings.warn( 'SCF context is invalid, using simple python wrapper', EpsagonWarning) trace.add_exception(exception, traceback.format_exc()) return epsagon.wrappers.python_function.wrap_python_function( func, args, kwargs) if constants.COLD_START: runner.resource['metadata'][ 'tencent.scf.cold_start_duration'] = cold_start_duration constants.COLD_START = False try: trace.add_event( TencentFunctionTriggerFactory.factory(start_time, event, context, runner)) # pylint: disable=W0703 except Exception as exception: trace.add_exception(exception, traceback.format_exc(), additional_data={'event': event}) result = None try: result = func(*args, **kwargs) return result # pylint: disable=W0703 except Exception as exception: runner.set_exception(exception, traceback.format_exc(), handled=False) raise finally: try: _add_status_code(runner, result) if not trace.metadata_only: runner.resource['metadata']['tencent.scf.return_data'] = ( result) # pylint: disable=W0703 except Exception as exception: trace.add_exception( exception, traceback.format_exc(), ) try: epsagon.trace.trace_factory.send_traces() # pylint: disable=W0703 except Exception: epsagon.utils.print_debug('Failed to send SCF trace')