def prepare_composite_report_json(self, reports): invocation_report = None for report in reports: if report["type"] == "Invocation": invocation_report = report if not invocation_report: return [] common_fields = composite.init_composite_data_common_fields( invocation_report["data"]) batches = self.get_report_batches(reports) batched_reports = [] for batch in batches: all_monitoring_data = [ composite.remove_common_fields(report["data"]) for report in batch ] composite_data = composite.get_composite_data( all_monitoring_data, self.api_key, common_fields) try: batched_reports.append( to_json(composite_data, separators=(',', ':'))) except TypeError: logger.error( "Couldn't dump report with type Composite to json string, " "probably it contains a byte array") return batched_reports
def test_create_span_listener_with_multiple_filter_and_listener( span_listener_with_multiple_filterers_and_listeners): sl_env_var = to_json(span_listener_with_multiple_filterers_and_listeners) ConfigProvider.set(config_names.THUNDRA_TRACE_SPAN_LISTENERCONFIG, sl_env_var) trace_support._parse_span_listeners() sl = trace_support.get_span_listeners()[0] f1 = sl.filterer.span_filters[0] f2 = sl.filterer.span_filters[1] assert type(sl) is FilteringSpanListener assert type(sl.listener) is LatencyInjectorSpanListener assert sl.listener.delay == 370 assert sl.listener.distribution == 'normal' assert sl.listener.sigma == 73 assert sl.listener.variation == 37 assert f1.class_name == 'AWS-SQS' assert f1.domain_name == 'Messaging' assert f1.tags == {'foo': 'bar'} assert f2.class_name == 'HTTP' assert f2.operation_name == 'http_request' assert f2.tags == {'http.host': 'foobar.com'}
def send_reports(self, reports, **opts): if not self.api_key: debug_logger("API key not set, not sending report to Thundra.") return [] headers = { 'Content-Type': 'application/json', 'Authorization': 'ApiKey ' + self.api_key } test_run_event = opts.get("test_run_event", False) rest_composite_data_enabled = ConfigProvider.get( config_names.THUNDRA_REPORT_REST_COMPOSITE_ENABLE, True) if not test_run_event: path = constants.COMPOSITE_DATA_PATH if rest_composite_data_enabled else constants.PATH else: path = constants.PATH base_url = self.get_collector_url() request_url = base_url + path if ConfigProvider.get(config_names.THUNDRA_REPORT_CLOUDWATCH_ENABLE): if ConfigProvider.get( config_names.THUNDRA_REPORT_CLOUDWATCH_COMPOSITE_ENABLE, True): if not test_run_event: reports_json = self.prepare_composite_report_json(reports) else: reports_json = self.prepare_report_json(reports) for report in reports_json: print(report) else: for report in reports: try: print(to_json(report, separators=(',', ':'))) except TypeError: logger.error(( "Couldn't dump report with type {} to json string, " "probably it contains a byte array").format( report.get('type'))) return [] if not test_run_event and rest_composite_data_enabled: reports_json = self.prepare_composite_report_json(reports) else: reports_json = self.prepare_report_json(reports) responses = [] if len(reports_json) > 0: _futures = [ self.pool.submit(self.send_batch, (request_url, headers, data)) for data in reports_json ] responses = [ future.result() for future in futures.as_completed(_futures) ] if ConfigProvider.get(config_names.THUNDRA_DEBUG_ENABLE): debug_logger("Thundra API responses: " + str(responses)) return responses
def after_invocation(self, execution_context): executor = self.plugin_context.executor if executor: executor.finish_invocation(execution_context) report_data = { 'apiKey': self.plugin_context.api_key, 'type': 'Invocation', 'dataModelVersion': constants.DATA_FORMAT_VERSION, 'data': execution_context.invocation_data } execution_context.report(json.loads(to_json(report_data)))
def test_create_empty_span_listener(empty_span_listener): sl_env_var = to_json(empty_span_listener) ConfigProvider.set(config_names.THUNDRA_TRACE_SPAN_LISTENERCONFIG, sl_env_var) trace_support._parse_span_listeners() sl = trace_support.get_span_listeners()[0] assert type(sl) is FilteringSpanListener assert type(sl.listener) is ErrorInjectorSpanListener assert type(sl.filterer) is StandardSpanFilterer
def test_create_span_listener_with_only_listener( span_listener_with_one_listener): sl_env_var = to_json(span_listener_with_one_listener) ConfigProvider.set(config_names.THUNDRA_TRACE_SPAN_LISTENERCONFIG, sl_env_var) trace_support._parse_span_listeners() sl = trace_support.get_span_listeners()[0] assert type(sl) is FilteringSpanListener assert type(sl.listener) is ErrorInjectorSpanListener assert sl.listener.error_type is NameError assert sl.listener.error_message == 'foo' assert type(sl.filterer) is StandardSpanFilterer
def prepare_report_json(self, reports): batches = self.get_report_batches(reports) batched_reports = [] for batch in batches: report_jsons = [] for report in batch: try: report_jsons.append(to_json(report, separators=(',', ':'))) except TypeError: logger.error( ("Couldn't dump report with type {} to json string, " "probably it contains a byte array").format( report.get('type'))) json_string = "[{}]".format(','.join(report_jsons)) batched_reports.append(json_string) return batched_reports
def test_create_span_listener_with_only_filterer( span_listener_with_one_filterer): sl_env_var = to_json(span_listener_with_one_filterer) ConfigProvider.set(config_names.THUNDRA_TRACE_SPAN_LISTENERCONFIG, sl_env_var) trace_support._parse_span_listeners() sl = trace_support.get_span_listeners()[0] f = sl.filterer.span_filters[0] assert type(sl) is FilteringSpanListener assert sl.listener is None assert f.class_name == 'AWS-SQS' assert f.domain_name == 'Messaging' assert f.tags == {'foo': 'bar'}
def test_send_report_to_url(mock_requests, mock_report): ConfigProvider.set(config_names.THUNDRA_REPORT_REST_BASEURL, 'different_url/api') ConfigProvider.set(config_names.THUNDRA_REPORT_REST_COMPOSITE_ENABLE, 'false') test_session = mock_requests.Session() reporter = Reporter('api key', session=test_session) responses = reporter.send_reports([mock_report]) post_url = 'different_url/api/monitoring-data' headers = { 'Content-Type': 'application/json', 'Authorization': 'ApiKey api key' } reporter.session.post.assert_called_once_with(post_url, data=to_json([mock_report], separators=(',', ':')), headers=headers, timeout=constants.DEFAULT_REPORT_TIMEOUT) reporter.session.post.return_value.status_code = 200 for response in responses: assert response.status_code == 200
def before_call(self, scope, wrapped, instance, args, kwargs, response, exception): scope.span.domain_name = constants.DomainNames['AWS'] scope.span.class_name = constants.ClassNames['STEPFUNCTIONS'] _, request_data = args state_machine_arn = request_data.get('stateMachineArn', '') execution_name = request_data.get('name', '') service_name = instance.__class__.__name__.lower() try: orig_input = request_data.get('input', None) if orig_input != None and ConfigProvider.get( config_names.THUNDRA_LAMBDA_AWS_STEPFUNCTIONS): parsed_input = json.loads(orig_input) trace_link = str(uuid.uuid4()) parsed_input['_thundra'] = { "trace_link": trace_link, "step": 0 } scope.span.set_tag( constants.AwsStepFunctionsTags['EXECUTION_INPUT'], orig_input) request_data['input'] = to_json(parsed_input) scope.span.set_tag(constants.SpanTags['TRACE_LINKS'], [trace_link]) scope.span.resource_trace_links = [trace_link] except: pass if len(args) > 0: scope.span.set_tag(constants.AwsSDKTags['REQUEST_NAME'], args[0]) scope.span.set_tag( constants.SpanTags['OPERATION_TYPE'], get_operation_type(scope.span.class_name, args[0])) scope.span.set_tag(constants.AwsSDKTags['SERVICE_NAME'], service_name) scope.span.set_tag(constants.AwsStepFunctionsTags['STATE_MACHINE_ARN'], state_machine_arn) scope.span.set_tag(constants.AwsStepFunctionsTags['EXECUTION_NAME'], execution_name) scope.span.set_tag(constants.SpanTags['TOPOLOGY_VERTEX'], True)
def test_create_span_listener_with_filterer_and_listener( span_listener_with_filterer_and_listener): sl_env_var = to_json(span_listener_with_filterer_and_listener) ConfigProvider.set(config_names.THUNDRA_TRACE_SPAN_LISTENERCONFIG, sl_env_var) trace_support._parse_span_listeners() sl = trace_support.get_span_listeners()[0] f = sl.filterer.span_filters[0] assert type(sl) is FilteringSpanListener assert type(sl.listener) is ErrorInjectorSpanListener assert sl.listener.error_type is NameError assert sl.listener.error_message == 'foo' assert sl.listener.inject_on_finish assert sl.listener.inject_count_freq assert f.class_name == 'AWS-SQS' assert f.domain_name == 'Messaging' assert f.tags == {'foo': 'bar'}