From 7a4a29132bf2ded0f8df40d6aa29be1c3f0cfba2 Mon Sep 17 00:00:00 2001 From: Lucas <12496191+lucashuy@users.noreply.github.com> Date: Tue, 12 Sep 2023 13:10:16 -0700 Subject: [PATCH] feat: Added event tracking for feature (#5872) * Added event tracking for feature * Correctly pass event value and fix typing --- samcli/commands/build/build_context.py | 20 +++++++++--- samcli/lib/telemetry/event.py | 1 + .../commands/buildcmd/test_build_context.py | 32 +++++++++++++++++++ 3 files changed, 49 insertions(+), 4 deletions(-) diff --git a/samcli/commands/build/build_context.py b/samcli/commands/build/build_context.py index a6d6b69102..7e2450a155 100644 --- a/samcli/commands/build/build_context.py +++ b/samcli/commands/build/build_context.py @@ -33,12 +33,12 @@ ) from samcli.lib.build.workflow_config import UnsupportedRuntimeException from samcli.lib.intrinsic_resolver.intrinsics_symbol_table import IntrinsicsSymbolTable -from samcli.lib.providers.provider import ResourcesToBuildCollector, Stack, Function, LayerVersion +from samcli.lib.providers.provider import ResourcesToBuildCollector, Stack, LayerVersion from samcli.lib.providers.sam_api_provider import SamApiProvider from samcli.lib.providers.sam_function_provider import SamFunctionProvider from samcli.lib.providers.sam_layer_provider import SamLayerProvider from samcli.lib.providers.sam_stack_provider import SamLocalStackProvider -from samcli.lib.telemetry.event import EventTracker +from samcli.lib.telemetry.event import EventTracker, UsedFeature, EventName from samcli.lib.utils.osutils import BUILD_DIR_PERMISSIONS from samcli.local.docker.manager import ContainerManager from samcli.local.lambdafn.exceptions import ( @@ -232,13 +232,15 @@ def __exit__(self, *args): def get_resources_to_build(self): return self.resources_to_build - def run(self): + def run(self) -> None: """Runs the building process by creating an ApplicationBuilder.""" if self._is_sam_template(): SamApiProvider.check_implicit_api_resource_ids(self.stacks) self._stacks = self._handle_build_pre_processing() + caught_exception: Optional[Exception] = None + try: # boolean value indicates if mount with write or not, defaults to READ ONLY mount_with_write = False @@ -276,7 +278,7 @@ def run(self): self._check_rust_cargo_experimental_flag() for f in self.get_resources_to_build().functions: - EventTracker.track_event("BuildFunctionRuntime", f.runtime) + EventTracker.track_event(EventName.BUILD_FUNCTION_RUNTIME.value, f.runtime) self._build_result = builder.build() @@ -306,6 +308,8 @@ def run(self): click.secho(msg, fg="yellow") except FunctionNotFound as function_not_found_ex: + caught_exception = function_not_found_ex + raise UserException( str(function_not_found_ex), wrapped_from=function_not_found_ex.__class__.__name__ ) from function_not_found_ex @@ -317,6 +321,8 @@ def run(self): InvalidBuildGraphException, ResourceNotFound, ) as ex: + caught_exception = ex + click.secho("\nBuild Failed", fg="red") # Some Exceptions have a deeper wrapped exception that needs to be surfaced @@ -324,6 +330,12 @@ def run(self): deep_wrap = getattr(ex, "wrapped_from", None) wrapped_from = deep_wrap if deep_wrap else ex.__class__.__name__ raise UserException(str(ex), wrapped_from=wrapped_from) from ex + finally: + if self.build_in_source: + exception_name = type(caught_exception).__name__ if caught_exception else None + EventTracker.track_event( + EventName.USED_FEATURE.value, UsedFeature.BUILD_IN_SOURCE.value, exception_name + ) def _is_sam_template(self) -> bool: """Check if a given template is a SAM template""" diff --git a/samcli/lib/telemetry/event.py b/samcli/lib/telemetry/event.py index 96e5fe45cb..398e8eeb5c 100644 --- a/samcli/lib/telemetry/event.py +++ b/samcli/lib/telemetry/event.py @@ -39,6 +39,7 @@ class UsedFeature(Enum): INIT_WITH_APPLICATION_INSIGHTS = "InitWithApplicationInsights" CFNLint = "CFNLint" INVOKED_CUSTOM_LAMBDA_AUTHORIZERS = "InvokedLambdaAuthorizers" + BUILD_IN_SOURCE = "BuildInSource" class EventType: diff --git a/tests/unit/commands/buildcmd/test_build_context.py b/tests/unit/commands/buildcmd/test_build_context.py index 417ce473e3..5d48139d4b 100644 --- a/tests/unit/commands/buildcmd/test_build_context.py +++ b/tests/unit/commands/buildcmd/test_build_context.py @@ -18,6 +18,7 @@ from samcli.lib.build.bundler import EsbuildBundlerManager from samcli.lib.build.workflow_config import UnsupportedRuntimeException from samcli.lib.providers.provider import Function, get_function_build_info +from samcli.lib.telemetry.event import EventName, UsedFeature from samcli.lib.utils.osutils import BUILD_DIR_PERMISSIONS from samcli.lib.utils.packagetype import ZIP, IMAGE from samcli.local.lambdafn.exceptions import FunctionNotFound @@ -1245,6 +1246,37 @@ def test_must_catch_function_not_found_exception( self.assertEqual(str(ctx.exception), "Function Not Found") + @patch("samcli.commands.build.build_context.BuildContext._is_sam_template") + @patch("samcli.commands.build.build_context.BuildContext.get_resources_to_build") + @patch("samcli.commands.build.build_context.BuildContext._check_exclude_warning") + @patch("samcli.commands.build.build_context.BuildContext._check_rust_cargo_experimental_flag") + @patch("samcli.lib.build.app_builder.ApplicationBuilder.build") + @patch("samcli.lib.telemetry.event.EventTracker.track_event") + def test_build_in_source_event_sent( + self, mock_track_event, mock_builder, mock_rust, mock_warning, mock_get_resources, mock_is_sam_template + ): + mock_builder.side_effect = [FunctionNotFound()] + + context = BuildContext( + resource_identifier="", + template_file="template_file", + base_dir="base_dir", + build_dir="build_dir", + cache_dir="cache_dir", + cached=False, + clean=False, + parallel=False, + mode="mode", + build_in_source=True, + ) + + with self.assertRaises(UserException): + context.run() + + mock_track_event.assert_called_with( + EventName.USED_FEATURE.value, UsedFeature.BUILD_IN_SOURCE.value, "FunctionNotFound" + ) + class TestBuildContext_is_sam_template(TestCase): @parameterized.expand(