def test_beta_endpoint_call_report_and_refresh_and_do_not_override_one_setting_of_default_agent_configuration( self): self.environment["agent_config_merger"] = AgentConfigurationMerger( default=self.agent_config, user_overrides=AgentConfiguration(sampling_interval=timedelta( seconds=2))) sdk_reporter = SdkReporter(self.environment) sdk_reporter.setup() assert AgentConfiguration.get().should_profile is True assert AgentConfiguration.get().sampling_interval == timedelta( seconds=2) assert AgentConfiguration.get().reporting_interval == timedelta( minutes=13) assert AgentConfiguration.get().minimum_time_reporting == timedelta( minutes=6) assert AgentConfiguration.get().max_stack_depth == 2345 assert AgentConfiguration.get().cpu_limit_percentage == 29 assert sdk_reporter.report(self.profile) is True sdk_reporter.refresh_configuration() assert AgentConfiguration.get().should_profile is True assert AgentConfiguration.get().sampling_interval == timedelta( seconds=2) assert AgentConfiguration.get().reporting_interval == timedelta( minutes=5) assert AgentConfiguration.get().minimum_time_reporting == timedelta( seconds=60) assert AgentConfiguration.get().max_stack_depth == 1000 assert AgentConfiguration.get().cpu_limit_percentage == 10
def before(self): self.mock_collector = MagicMock(name="collector", spec=LocalAggregator) self.mock_disabler = MagicMock(name="profile", spec=ProfilerDisabler) self.mock_disabler.should_stop_profiling.return_value = False self.mock_disabler.should_stop_sampling.return_value = False self.mock_sampler = MagicMock(name="sampler", spec=Sampler) self.environment = { "collector": self.mock_collector, "profiler_disabler": self.mock_disabler, "sampler": self.mock_sampler, "initial_sampling_interval": timedelta(), "profiler_thread_name": "codeguru-profiler-agent-TestProfilerRunner" } self.agent_configuration = AgentConfiguration( should_profile=True, sampling_interval=timedelta(seconds=2), reporting_interval=timedelta(seconds=100)) # mock the collector's refresh_configuration function to actual set agent configuration singleton def set_new_configuration(): AgentConfiguration.set(self.agent_configuration) self.mock_collector.refresh_configuration.side_effect = set_new_configuration # mock the collector's flush function to return True or False according to self.is_time_to_report self.is_time_to_report = False self.mock_collector.flush.side_effect = lambda *args, **kwargs: self.is_time_to_report self.mock_collector.profile = None # we need this as we pass the profile object to the disabler, None is fine self.profiler_runner = ProfilerRunner(self.environment) yield self.profiler_runner.stop()
def before(self): codeguru_client_builder = CodeGuruClientBuilder( environment={"aws_session": boto3.session.Session()}) self.client_stubber = Stubber(codeguru_client_builder.codeguru_client) self.clear_lambda_specific_environment_variables_for_test_run() profile_encoder = MagicMock(name="profile_encoder", spec=ProfileEncoder) profile_encoder.encode.side_effect = lambda **args: args[ "output_stream"].write(b"test-profile-encoder-output") self.environment = { "profiling_group_name": profiling_group_name, "profile_encoder": profile_encoder, "codeguru_profiler_builder": codeguru_client_builder, "agent_metadata": AgentMetadata(fleet_info=DefaultFleetInfo()), "reporting_interval": timedelta(minutes=13), "sampling_interval": timedelta(seconds=13), "minimum_time_reporting": timedelta(minutes=13), "max_stack_depth": 1300 } default_config = AgentConfiguration( should_profile=True, sampling_interval=self.environment["sampling_interval"], reporting_interval=self.environment["reporting_interval"], minimum_time_reporting=self.environment["minimum_time_reporting"]) self.environment["agent_config_merger"] = AgentConfigurationMerger( default_config) self.subject = SdkReporter(environment=self.environment) self.subject.setup()
def before(self): now_millis = int(time.time()) * 1000 five_minutes_ago_millis = now_millis - (5 * 60 * 1000) sample = Sample( stacks=[[Frame(MY_PROFILING_GROUP_NAME_FOR_INTEG_TESTS)]], attempted_sample_threads_count=1, seen_threads_count=1) self.profile = Profile(MY_PROFILING_GROUP_NAME_FOR_INTEG_TESTS, 1.0, 1.0, five_minutes_ago_millis) # FIXME: Remove adding the end time manually below after feature fully support self.profile.end = now_millis self.profile.add(sample) self.environment = { "should_profile": True, "profiling_group_name": MY_PROFILING_GROUP_NAME_FOR_INTEG_TESTS, "aws_session": boto3.session.Session(), "reporting_interval": timedelta(minutes=13), "sampling_interval": timedelta(seconds=1), "minimum_time_reporting": timedelta(minutes=6), "max_stack_depth": 2345, "cpu_limit_percentage": 29, "agent_metadata": AgentMetadata(fleet_info=DefaultFleetInfo()) } self.environment["codeguru_profiler_builder"] = CodeGuruClientBuilder( self.environment) self.agent_config = AgentConfiguration( should_profile=True, sampling_interval=self.environment["sampling_interval"], reporting_interval=self.environment["reporting_interval"], minimum_time_reporting=self.environment["minimum_time_reporting"], max_stack_depth=self.environment["max_stack_depth"], cpu_limit_percentage=self.environment["cpu_limit_percentage"])
def test_user_overrides_are_not_overridden_at_merge_with(self): agent_config_merger = AgentConfigurationMerger( default=AgentConfiguration(), user_overrides=self.config) self.assert_init_values() agent_config_merger.merge_with( configure_agent_response=self.configure_agent_response) self.assert_init_values()
def before(self): self.agent_config = AgentConfiguration( should_profile=True, sampling_interval=timedelta(milliseconds=9100), minimum_time_reporting=timedelta(seconds=7), reporting_interval=timedelta(minutes=7), max_stack_depth=999, cpu_limit_percentage=9) AgentConfiguration.set(self.agent_config)
def before(self): self.config = AgentConfiguration( should_profile=True, sampling_interval=timedelta(milliseconds=1), minimum_time_reporting=timedelta(seconds=1), reporting_interval=timedelta(minutes=1), max_stack_depth=998) self.overide_config = AgentConfiguration(sampling_interval=timedelta( seconds=9)) self.configure_agent_response = { "agentParameters": { "SamplingIntervalInMilliseconds": "2000", "MinimumTimeForReportingInMilliseconds": "21000", "MaxStackDepth": "1001" }, "periodInSeconds": 123, "shouldProfile": False }
def before(self): self.config = AgentConfiguration( should_profile=True, sampling_interval=timedelta(milliseconds=1), minimum_time_reporting=timedelta(seconds=1), reporting_interval=timedelta(minutes=1), max_stack_depth=998) self.agent_config_merger = AgentConfigurationMerger( default=self.config)
def set_agent_config(sampling_interval_seconds=1, cpu_limit_percentage=DEFAULT_CPU_LIMIT_PERCENTAGE): """ Reporting interval needs to have a minimum value and cpu_limit_percentage is used later in tests; the other values can be None as we are not using them here. """ return AgentConfiguration.set( AgentConfiguration( sampling_interval=timedelta(seconds=sampling_interval_seconds), reporting_interval=timedelta(seconds=300), minimum_time_reporting=timedelta(seconds=60), cpu_limit_percentage=cpu_limit_percentage))
def before(self): self.mock_reporter = MagicMock(name="reporter", spec=SdkReporter) self.mock_profile = MagicMock(name="profile", spec=Profile) self.mock_profile_factory = MagicMock(name="profile_factory", spec=Profile, return_value=self.mock_profile) self.timer = mock_timer() self.time_now = CURRENT_TIME_FOR_TESTING_SECOND self.clock = lambda: self.time_now self.reporting_interval = DEFAULT_REPORTING_INTERVAL self.environment = { "profiling_group_name": TEST_PROFILING_GROUP_NAME, "sampling_interval": timedelta(seconds=TEST_SAMPLING_INTERVAL), "host_weight": TEST_HOST_WEIGHT, "profile_factory": self.mock_profile_factory, "errors_metadata": ERRORS_METADATA, "memory_limit_bytes": DEFAULT_MEMORY_LIMIT_BYTES, "clock": self.clock, "timer": self.timer, } self.configuration = { "reporter": self.mock_reporter, "environment": self.environment, } AgentConfiguration.set( AgentConfiguration( should_profile=True, sampling_interval=timedelta(seconds=TEST_SAMPLING_INTERVAL), minimum_time_reporting=INITIAL_MINIMUM_REPORTING_INTERVAL, reporting_interval=self.reporting_interval, max_stack_depth=999, cpu_limit_percentage=10)) assert len(self.environment.keys()) == 8 self.profiler = Profiler( profiling_group_name=TEST_PROFILING_GROUP_NAME, environment_override=self.environment) assert len(self.environment.keys()) == 7 self.subject = LocalAggregator(**self.configuration) self.mock_profile_factory.reset_mock() self.timer.reset_mock() def move_clock_to(duration_timedelta): self.time_now = \ CURRENT_TIME_FOR_TESTING_SECOND + duration_timedelta.total_seconds() self.move_clock_to = move_clock_to
def test_when_orchestrator_says_no_to_profiler(self): self.agent_configuration = AgentConfiguration( should_profile=False, sampling_interval=timedelta(seconds=2), reporting_interval=timedelta(seconds=151)) # calling start in this test, it will start the scheduler and because initial delay is 0 it will execute now self.profiler_runner.start() # still it is safer to wait until the new config has been applied wait_for(lambda: AgentConfiguration.get().reporting_interval. total_seconds() == 151) wait_for(lambda: self.profiler_runner.scheduler. _get_next_delay_seconds() == 151) assert self.profiler_runner.scheduler._get_next_delay_seconds() == 151 self.mock_collector.add.assert_not_called()
def __init__(self, profiling_group_name, region_name=None, aws_session=None, environment_override=dict()): """ NOTE: The profiler MUST be instantiated using keyword arguments. We provide no compatibility for the order (or number) of arguments. - Configuration :param profiling_group_name: name of the profiling group where the profiles will be stored. :param region_name: AWS Region to report to, given profiling group name must exist in that region. Note that this value overwrites what is used in aws_session. If not provided, boto3 will search configuration for the region. (e.g. "us-west-2") :param aws_session: The boto3.Session that this profiler should be using for communicating with the backend Check https://boto3.amazonaws.com/v1/documentation/api/latest/guide/session.html for more details. - Advanced Configuration Options - We recommend not to touch these :param environment_override: custom dependency container dictionary. allows custom behavior to be injected but please note that we do not guarantee compatibility between any different profiler agent versions for this api (default: dict()). Possible keys: - reporting_interval: delay between profile reports in datetime.timedelta (default: None) - sampling_interval: delay between each sample in datetime.timedelta (default: 1 seconds) - reporting_mode: Reporting mode to be used, two modes are supported: "codeguru_service" and "file". "file" mode is only used for testing at the moment. (default: "codeguru_service") - file_prefix: path + file prefix to use for profile reports when in "file" reporting mode (default: './profile-{profiling_group_name}' only used when reporting mode is "file") - cpu_limit_percentage: cpu limit (%) for profiler (default: 30) - max_threads: the max number of threads getting sampled (default: 100) - killswitch_filepath: file path pointing to the killswitch file (default: "/var/tmp/killProfiler") - host_weight: A scale factor used to rescale the profile collected in this host to make the profile representative of the whole fleet (default: 1) - endpoint_url: url used for submitting profile (default: None, will target codeguru prod APIs) - excluded_threads: set of thread names to be excluded from sampling (default: set()) """ self._profiler_runner_instance = None self.environment = {} try: if not profiling_group_name: logger.info( "Profiler must be passed a non empty profiling group name, CodeGuru Profiler will not start. " "Please specify a ``profiling_group_name`` when configuring the ``Profiler`` class." ) return # This is the profiler instance-wide dependency container aka environment # It is used to contain shared dependencies and configuration, and can also be used to override the behavior # on the profiler classes without needing to monkey-patch. self.environment = self._set_default_environment( profiling_group_name) self.environment["profiling_group_name"] = profiling_group_name self.environment["region_name"] = region_name self.environment["aws_session"] = aws_session default_config = AgentConfiguration( should_profile=self.environment["should_profile"], sampling_interval=self.environment["sampling_interval"], reporting_interval=self.environment["reporting_interval"], minimum_time_reporting=self. environment["minimum_time_reporting"], max_stack_depth=self.environment["max_stack_depth"], cpu_limit_percentage=self.environment["cpu_limit_percentage"]) user_overrides = AgentConfiguration( should_profile=environment_override.get('should_profile'), sampling_interval=environment_override.get( 'sampling_interval'), reporting_interval=environment_override.get( 'reporting_interval'), minimum_time_reporting=environment_override.get( 'minimum_time_reporting'), max_stack_depth=environment_override.get('max_stack_depth'), cpu_limit_percentage=environment_override.get( 'cpu_limit_percentage')) agent_config_merger = AgentConfigurationMerger( default=default_config, user_overrides=user_overrides) self.environment["agent_config_merger"] = agent_config_merger # Removing all keys from the environment that were used for the AgentConfigurationMerger # to make sure the rest of the code would read it from the AgentConfiguration. for key in default_config.as_dict().keys(): del self.environment[key] for key in user_overrides.as_dict().keys(): del environment_override[key] self.environment = self._setup_final_environment( self.environment, environment_override) profiler_runner_factory = self.environment.get( "profiler_runner_factory") or ProfilerRunner self._profiler_runner_instance = profiler_runner_factory( environment=self.environment) except: logger.info( "Caught exception while creating the CodeGuru Profiler Agent instance", exc_info=True) if environment_override.get("allow_top_level_exceptions") is True: raise
def test_when_customer_reporting_interval_is_less_than_30_seconds_it_raises_a_value_error( self): with pytest.raises(ValueError): AgentConfiguration(reporting_interval=timedelta(seconds=28), minimum_time_reporting=timedelta(seconds=29))