Переглянути джерело

[POR-1625] analytics on cluster deletion (#3469)

Feroze Mohideen 2 роки тому
батько
коміт
5d2501eda2

+ 70 - 15
api/server/handlers/project/update_onboarding_step.go

@@ -9,6 +9,7 @@ import (
 	"github.com/porter-dev/porter/api/types"
 	"github.com/porter-dev/porter/internal/analytics"
 	"github.com/porter-dev/porter/internal/models"
+	"github.com/porter-dev/porter/internal/telemetry"
 )
 
 type UpdateOnboardingStepHandler struct {
@@ -26,26 +27,47 @@ func NewUpdateOnboardingStepHandler(
 }
 
 func (v *UpdateOnboardingStepHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
-	user, _ := r.Context().Value(types.UserScope).(*models.User)
-	project, _ := r.Context().Value(types.ProjectScope).(*models.Project)
+	ctx, span := telemetry.NewSpan(r.Context(), "serve-update-onboarding-step")
+	defer span.End()
+
+	user, _ := ctx.Value(types.UserScope).(*models.User)
+	project, _ := ctx.Value(types.ProjectScope).(*models.Project)
 
 	request := &types.UpdateOnboardingStepRequest{}
+
+	// intentionally do not return error so as not to block post-reporting steps
 	if ok := v.DecodeAndValidate(w, r, request); !ok {
-		return
+		_ = telemetry.Error(ctx, span, nil, "error decoding request")
 	}
 
 	if request.Step == "project-delete" {
-		v.Config().AnalyticsClient.Track(analytics.ProjectDeleteTrack(&analytics.ProjectCreateDeleteTrackOpts{
+		err := v.Config().AnalyticsClient.Track(analytics.ProjectDeleteTrack(&analytics.ProjectCreateDeleteTrackOpts{
+			ProjectScopedTrackOpts: analytics.GetProjectScopedTrackOpts(user.ID, project.ID),
+			Email:                  user.Email,
+			FirstName:              user.FirstName,
+			LastName:               user.LastName,
+			CompanyName:            user.CompanyName,
+		}))
+		if err != nil {
+			_ = telemetry.Error(ctx, span, err, "error tracking project delete")
+		}
+	}
+
+	if request.Step == "cluster-delete" {
+		err := v.Config().AnalyticsClient.Track(analytics.ClusterDeleteTrack(&analytics.ClusterDeleteTrackOpts{
 			ProjectScopedTrackOpts: analytics.GetProjectScopedTrackOpts(user.ID, project.ID),
 			Email:                  user.Email,
 			FirstName:              user.FirstName,
 			LastName:               user.LastName,
 			CompanyName:            user.CompanyName,
 		}))
+		if err != nil {
+			_ = telemetry.Error(ctx, span, err, "error tracking cluster delete")
+		}
 	}
 
 	if request.Step == "cost-consent-opened" {
-		v.Config().AnalyticsClient.Track(analytics.CostConsentOpenedTrack(&analytics.CostConsentOpenedTrackOpts{
+		err := v.Config().AnalyticsClient.Track(analytics.CostConsentOpenedTrack(&analytics.CostConsentOpenedTrackOpts{
 			UserScopedTrackOpts: analytics.GetUserScopedTrackOpts(user.ID),
 			Provider:            request.Provider,
 			Email:               user.Email,
@@ -53,10 +75,13 @@ func (v *UpdateOnboardingStepHandler) ServeHTTP(w http.ResponseWriter, r *http.R
 			LastName:            user.LastName,
 			CompanyName:         user.CompanyName,
 		}))
+		if err != nil {
+			_ = telemetry.Error(ctx, span, err, "error tracking cost consent opened")
+		}
 	}
 
 	if request.Step == "cost-consent-complete" {
-		v.Config().AnalyticsClient.Track(analytics.CostConsentCompletedTrack(&analytics.CostConsentCompletedTrackOpts{
+		err := v.Config().AnalyticsClient.Track(analytics.CostConsentCompletedTrack(&analytics.CostConsentCompletedTrackOpts{
 			UserScopedTrackOpts: analytics.GetUserScopedTrackOpts(user.ID),
 			Provider:            request.Provider,
 			Email:               user.Email,
@@ -64,10 +89,13 @@ func (v *UpdateOnboardingStepHandler) ServeHTTP(w http.ResponseWriter, r *http.R
 			LastName:            user.LastName,
 			CompanyName:         user.CompanyName,
 		}))
+		if err != nil {
+			_ = telemetry.Error(ctx, span, err, "error tracking cost consent completed")
+		}
 	}
 
 	if request.Step == "aws-account-id-complete" {
-		v.Config().AnalyticsClient.Track(analytics.AWSInputTrack(&analytics.AWSInputTrackOpts{
+		err := v.Config().AnalyticsClient.Track(analytics.AWSInputTrack(&analytics.AWSInputTrackOpts{
 			ProjectScopedTrackOpts: analytics.GetProjectScopedTrackOpts(user.ID, project.ID),
 			Email:                  user.Email,
 			FirstName:              user.FirstName,
@@ -75,10 +103,13 @@ func (v *UpdateOnboardingStepHandler) ServeHTTP(w http.ResponseWriter, r *http.R
 			CompanyName:            user.CompanyName,
 			AccountId:              request.AccountId,
 		}))
+		if err != nil {
+			_ = telemetry.Error(ctx, span, err, "error tracking aws input")
+		}
 	}
 
 	if request.Step == "aws-login-redirect-success" {
-		v.Config().AnalyticsClient.Track(analytics.AWSLoginRedirectSuccess(&analytics.AWSRedirectOpts{
+		err := v.Config().AnalyticsClient.Track(analytics.AWSLoginRedirectSuccess(&analytics.AWSRedirectOpts{
 			ProjectScopedTrackOpts: analytics.GetProjectScopedTrackOpts(user.ID, project.ID),
 			Email:                  user.Email,
 			FirstName:              user.FirstName,
@@ -87,10 +118,13 @@ func (v *UpdateOnboardingStepHandler) ServeHTTP(w http.ResponseWriter, r *http.R
 			AccountId:              request.AccountId,
 			LoginURL:               request.LoginURL,
 		}))
+		if err != nil {
+			_ = telemetry.Error(ctx, span, err, "error tracking aws login redirect")
+		}
 	}
 
 	if request.Step == "aws-cloudformation-redirect-success" {
-		v.Config().AnalyticsClient.Track(analytics.AWSCloudformationRedirectSuccess(&analytics.AWSRedirectOpts{
+		err := v.Config().AnalyticsClient.Track(analytics.AWSCloudformationRedirectSuccess(&analytics.AWSRedirectOpts{
 			ProjectScopedTrackOpts: analytics.GetProjectScopedTrackOpts(user.ID, project.ID),
 			Email:                  user.Email,
 			FirstName:              user.FirstName,
@@ -100,10 +134,13 @@ func (v *UpdateOnboardingStepHandler) ServeHTTP(w http.ResponseWriter, r *http.R
 			CloudformationURL:      request.CloudformationURL,
 			ExternalId:             request.ExternalId,
 		}))
+		if err != nil {
+			_ = telemetry.Error(ctx, span, err, "error tracking aws cloudformation redirect")
+		}
 	}
 
 	if request.Step == "aws-create-integration-success" {
-		v.Config().AnalyticsClient.Track(analytics.AWSCreateIntegrationSucceeded(&analytics.AWSCreateIntegrationOpts{
+		err := v.Config().AnalyticsClient.Track(analytics.AWSCreateIntegrationSucceeded(&analytics.AWSCreateIntegrationOpts{
 			ProjectScopedTrackOpts: analytics.GetProjectScopedTrackOpts(user.ID, project.ID),
 			Email:                  user.Email,
 			FirstName:              user.FirstName,
@@ -111,10 +148,13 @@ func (v *UpdateOnboardingStepHandler) ServeHTTP(w http.ResponseWriter, r *http.R
 			CompanyName:            user.CompanyName,
 			AccountId:              request.AccountId,
 		}))
+		if err != nil {
+			_ = telemetry.Error(ctx, span, err, "error tracking aws create integration")
+		}
 	}
 
 	if request.Step == "aws-create-integration-failure" {
-		v.Config().AnalyticsClient.Track(analytics.AWSCreateIntegrationFailed(&analytics.AWSCreateIntegrationOpts{
+		err := v.Config().AnalyticsClient.Track(analytics.AWSCreateIntegrationFailed(&analytics.AWSCreateIntegrationOpts{
 			ProjectScopedTrackOpts: analytics.GetProjectScopedTrackOpts(user.ID, project.ID),
 			Email:                  user.Email,
 			FirstName:              user.FirstName,
@@ -124,26 +164,35 @@ func (v *UpdateOnboardingStepHandler) ServeHTTP(w http.ResponseWriter, r *http.R
 			ErrorMessage:           request.ErrorMessage,
 			ExternalId:             request.ExternalId,
 		}))
+		if err != nil {
+			_ = telemetry.Error(ctx, span, err, "error tracking aws create integration failure")
+		}
 	}
 
 	if request.Step == "credential-step-complete" {
-		v.Config().AnalyticsClient.Track(analytics.CredentialStepTrack(&analytics.CredentialStepTrackOpts{
+		err := v.Config().AnalyticsClient.Track(analytics.CredentialStepTrack(&analytics.CredentialStepTrackOpts{
 			UserScopedTrackOpts: analytics.GetUserScopedTrackOpts(user.ID),
 		}))
+		if err != nil {
+			_ = telemetry.Error(ctx, span, err, "error tracking credential step complete")
+		}
 	}
 
 	if request.Step == "pre-provisioning-check-started" {
-		v.Config().AnalyticsClient.Track(analytics.PreProvisionCheckTrack(&analytics.PreProvisionCheckTrackOpts{
+		err := v.Config().AnalyticsClient.Track(analytics.PreProvisionCheckTrack(&analytics.PreProvisionCheckTrackOpts{
 			ProjectScopedTrackOpts: analytics.GetProjectScopedTrackOpts(user.ID, project.ID),
 			Email:                  user.Email,
 			FirstName:              user.FirstName,
 			LastName:               user.LastName,
 			CompanyName:            user.CompanyName,
 		}))
+		if err != nil {
+			_ = telemetry.Error(ctx, span, err, "error tracking pre-provisioning check started")
+		}
 	}
 
 	if request.Step == "provisioning-started" {
-		v.Config().AnalyticsClient.Track(analytics.ProvisioningAttemptTrack(&analytics.ProvisioningAttemptTrackOpts{
+		err := v.Config().AnalyticsClient.Track(analytics.ProvisioningAttemptTrack(&analytics.ProvisioningAttemptTrackOpts{
 			ProjectScopedTrackOpts: analytics.GetProjectScopedTrackOpts(user.ID, project.ID),
 			Email:                  user.Email,
 			FirstName:              user.FirstName,
@@ -151,10 +200,13 @@ func (v *UpdateOnboardingStepHandler) ServeHTTP(w http.ResponseWriter, r *http.R
 			CompanyName:            user.CompanyName,
 			Region:                 request.Region,
 		}))
+		if err != nil {
+			_ = telemetry.Error(ctx, span, err, "error tracking provisioning started")
+		}
 	}
 
 	if request.Step == "provisioning-failed" {
-		v.Config().AnalyticsClient.Track(analytics.ProvisionFailureTrack(&analytics.ProvisioningAttemptTrackOpts{
+		err := v.Config().AnalyticsClient.Track(analytics.ProvisionFailureTrack(&analytics.ProvisioningAttemptTrackOpts{
 			ProjectScopedTrackOpts: analytics.GetProjectScopedTrackOpts(user.ID, project.ID),
 			Email:                  user.Email,
 			FirstName:              user.FirstName,
@@ -163,6 +215,9 @@ func (v *UpdateOnboardingStepHandler) ServeHTTP(w http.ResponseWriter, r *http.R
 			ErrorMessage:           request.ErrorMessage,
 			Region:                 request.Region,
 		}))
+		if err != nil {
+			_ = telemetry.Error(ctx, span, err, "error tracking provisioning failure")
+		}
 	}
 
 	v.WriteResult(w, r, user.ToUserType())

+ 7 - 1
dashboard/src/main/home/modals/UpdateClusterModal.tsx

@@ -33,10 +33,16 @@ class UpdateClusterModal extends Component<PropsType, StateType> {
     console.log(err);
   };
 
-  handleDelete = () => {
+  handleDelete = async () => {
     let { currentProject, currentCluster } = this.context;
     this.setState({ status: "loading" });
 
+    await api.updateOnboardingStep(
+      "<token>",
+      { step: "cluster-delete" },
+      { project_id: currentProject.id }
+    );
+
     api
       .deleteCluster(
         "<token>",

+ 1 - 0
internal/analytics/track_events.go

@@ -8,6 +8,7 @@ const (
 	UserVerifyEmail SegmentEvent = "User Verified Email"
 	ProjectCreate   SegmentEvent = "New Project Event"
 	ProjectDelete   SegmentEvent = "Project Deleted"
+	ClusterDelete   SegmentEvent = "Cluster Deleted"
 
 	CostConsentOpened           SegmentEvent = "Cost Consent Opened"
 	CostConsentComplete         SegmentEvent = "Cost Consent Complete"

+ 23 - 0
internal/analytics/tracks.go

@@ -156,6 +156,29 @@ func ProjectDeleteTrack(opts *ProjectCreateDeleteTrackOpts) segmentTrack {
 	)
 }
 
+// ClusterDeleteTrackOpts are the options for creating a track when a cluster is deleted
+type ClusterDeleteTrackOpts struct {
+	*ProjectScopedTrackOpts
+
+	Email       string
+	FirstName   string
+	LastName    string
+	CompanyName string
+}
+
+// ClusterDeleteTrack returns a track for when a cluster is deleted
+func ClusterDeleteTrack(opts *ClusterDeleteTrackOpts) segmentTrack {
+	additionalProps := make(map[string]interface{})
+	additionalProps["email"] = opts.Email
+	additionalProps["name"] = opts.FirstName + " " + opts.LastName
+	additionalProps["company"] = opts.CompanyName
+
+	return getSegmentProjectTrack(
+		opts.ProjectScopedTrackOpts,
+		getDefaultSegmentTrack(additionalProps, ClusterDelete),
+	)
+}
+
 // CostConsentOpenedTrackOpts are the options for creating a track when a user opens the cost consent
 type CostConsentOpenedTrackOpts struct {
 	*UserScopedTrackOpts