-
Notifications
You must be signed in to change notification settings - Fork 11
Add create_profiling_group call in refresh_configuration and report() #26
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
e283ed0
538f06b
bc2d398
ee6d377
4d23afc
b444e4f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,22 +2,25 @@ | |
|
|
||
| import logging | ||
| import io | ||
| import os | ||
|
|
||
| from botocore.exceptions import ClientError | ||
| from codeguru_profiler_agent.utils.log_exception import log_exception | ||
| from codeguru_profiler_agent.reporter.reporter import Reporter | ||
| from codeguru_profiler_agent.metrics.with_timer import with_timer | ||
| from codeguru_profiler_agent.sdk_reporter.profile_encoder import ProfileEncoder | ||
| from codeguru_profiler_agent.agent_metadata.aws_lambda import HANDLER_ENV_NAME_FOR_CODEGURU_KEY, \ | ||
| LAMBDA_TASK_ROOT, LAMBDA_RUNTIME_DIR | ||
|
|
||
| logger = logging.getLogger(__name__) | ||
|
|
||
| AWS_EXECUTION_ENV_KEY = "AWS_EXECUTION_ENV" | ||
|
|
||
| class SdkReporter(Reporter): | ||
| """ | ||
| Handles communication with the CodeGuru Profiler Service backend. | ||
| Encodes profiles using the ProfilerEncoder and reports them using the CodeGuru profiler SDK. | ||
| """ | ||
|
|
||
| is_create_pg_called_during_submit_profile = False | ||
| def __init__(self, environment): | ||
| """ | ||
| :param environment: dependency container dictionary for the current profiler. | ||
|
|
@@ -51,6 +54,11 @@ def setup(self): | |
| def refresh_configuration(self): | ||
| """ | ||
| Refresh the agent configuration by calling the profiler backend service. | ||
|
|
||
| Note: | ||
| For an agent running on AWS Lambda, if the environment variables for Profiling using | ||
| Lambda layers are set, it tries to create a Profiling Group whenever a ResourceNotFoundException | ||
| is encountered. | ||
| """ | ||
| try: | ||
| fleet_instance_id = self.metadata.fleet_info.get_fleet_instance_id() | ||
|
|
@@ -67,9 +75,18 @@ def refresh_configuration(self): | |
| # whole process because the customer may fix this on their side by creating/changing the profiling group. | ||
| # We handle service exceptions like this in boto3 | ||
| # see https://boto3.amazonaws.com/v1/documentation/api/latest/guide/error-handling.html | ||
| if error.response['Error']['Code'] in ['ResourceNotFoundException', 'ValidationException']: | ||
| if error.response['Error']['Code'] == 'ValidationException': | ||
| self.agent_config_merger.disable_profiling() | ||
| self._log_request_failed(operation="configure_agent", exception=error) | ||
| self._log_request_failed(operation="configure_agent", exception=error) | ||
| if error.response['Error']['Code'] == 'ResourceNotFoundException': | ||
| if self.should_auto_create_profiling_group(): | ||
| logger.info( | ||
| "Profiling group not found. Will try to create a profiling group " | ||
| "with name = {} and compute platform = {} and retry calling configure agent after 5 minutes" | ||
| .format(self.profiling_group_name, 'AWSLambda')) | ||
| self.create_profiling_group() | ||
| else: | ||
| self.agent_config_merger.disable_profiling() | ||
| except Exception as e: | ||
| self._log_request_failed(operation="configure_agent", exception=e) | ||
|
|
||
|
|
@@ -80,6 +97,11 @@ def report(self, profile): | |
|
|
||
| :param profile: Profile to be encoded and reported to the profiler backend service. | ||
| :return: True if profile gets reported successfully; False otherwise. | ||
|
|
||
| Note: | ||
| For an agent running on AWS Lambda, if the environment variables for Profiling using | ||
| Lambda layers are set, it tries to create a Profiling Group whenever a ResourceNotFoundException | ||
| is encountered. | ||
| """ | ||
| try: | ||
| profile_stream = self._encode_profile(profile) | ||
|
|
@@ -90,11 +112,61 @@ def report(self, profile): | |
| ) | ||
| logger.info("Reported profile successfully") | ||
| return True | ||
| except ClientError as error: | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you please update the documentation of this functions that this creates a PG in the case of using Lamba layers if it throws ResourceNotFoundException? I would be clearer when reading the code.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done! |
||
| if error.response['Error']['Code'] == 'ResourceNotFoundException': | ||
| if self.should_auto_create_profiling_group(): | ||
| self.__class__.is_create_pg_called_during_submit_profile = True | ||
| logger.info( | ||
| "Profiling group not found. Will try to create a profiling group " | ||
| "with name = {} and compute platform = {}".format(self.profiling_group_name, 'AWSLambda')) | ||
| self.create_profiling_group() | ||
| return False | ||
| except Exception as e: | ||
| self._log_request_failed(operation="post_agent_profile", exception=e) | ||
| return False | ||
|
|
||
| @with_timer("createProfilingGroup", measurement="wall-clock-time") | ||
| def create_profiling_group(self): | ||
| """ | ||
| Create a Profiling Group for the AWS Lambda function. | ||
| """ | ||
| try: | ||
| self.codeguru_client_builder.codeguru_client.create_profiling_group( | ||
| profilingGroupName=self.profiling_group_name, | ||
| computePlatform='AWSLambda' | ||
| ) | ||
| logger.info("Created Lambda Profiling Group with name " + str(self.profiling_group_name)) | ||
| except ClientError as error: | ||
| if error.response['Error']['Code'] == 'ConflictException': | ||
| logger.info("Profiling Group with name {} already exists. Please use a different name." | ||
| .format(self.profiling_group_name)) | ||
| except Exception as e: | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Handle ConflictException too by logging an appropriate message and setting
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
| self._log_request_failed(operation="create_profiling_group", exception=e) | ||
|
|
||
| def should_auto_create_profiling_group(self): | ||
| """ | ||
| Currently the only condition we check is to verify that the Compute Platform is AWS Lambda. | ||
| In future, other checks could be places inside this method. | ||
| """ | ||
| return self.is_compute_platform_lambda() | ||
|
|
||
| def is_compute_platform_lambda(self): | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can you add a wrapper method
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
| """ | ||
| Check if the compute platform is AWS Lambda. | ||
| """ | ||
| does_lambda_task_root_exist = os.environ.get(LAMBDA_TASK_ROOT) | ||
| does_lambda_runtime_dir_exist = os.environ.get(LAMBDA_RUNTIME_DIR) | ||
| return bool(does_lambda_task_root_exist) and bool(does_lambda_runtime_dir_exist) | ||
|
|
||
| @staticmethod | ||
| def _log_request_failed(operation, exception): | ||
| log_exception(logger, "Failed to call the CodeGuru Profiler service for the {} operation: {}" | ||
| .format(operation, str(exception))) | ||
|
|
||
| @classmethod | ||
| def check_create_pg_called_during_submit_profile(cls): | ||
| return cls.is_create_pg_called_during_submit_profile | ||
|
|
||
| @classmethod | ||
| def reset_check_create_pg_called_during_submit_profile_flag(cls): | ||
| cls.is_create_pg_called_during_submit_profile = False | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Question here : What configuration will be used in case of
ResourceNotFoundExceptionandValidationException.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The default configuration defined here