Explorar o código

add initial telemetry to legacy create release (#3035)

dt3-5 %!s(int64=3) %!d(string=hai) anos
pai
achega
475e65e01f

+ 17 - 4
api/server/authz/cluster.go

@@ -6,6 +6,8 @@ import (
 	"net/http"
 	"strings"
 
+	"github.com/porter-dev/porter/internal/telemetry"
+
 	"github.com/porter-dev/porter/api/server/shared/apierrors"
 	"github.com/porter-dev/porter/api/server/shared/config"
 	"github.com/porter-dev/porter/api/types"
@@ -74,7 +76,7 @@ type KubernetesAgentGetter interface {
 	GetOutOfClusterConfig(cluster *models.Cluster) *kubernetes.OutOfClusterConfig
 	GetDynamicClient(r *http.Request, cluster *models.Cluster) (dynamic.Interface, error)
 	GetAgent(r *http.Request, cluster *models.Cluster, namespace string) (*kubernetes.Agent, error)
-	GetHelmAgent(r *http.Request, cluster *models.Cluster, namespace string) (*helm.Agent, error)
+	GetHelmAgent(ctx context.Context, r *http.Request, cluster *models.Cluster, namespace string) (*helm.Agent, error)
 }
 
 type OutOfClusterAgentGetter struct {
@@ -128,11 +130,20 @@ func (d *OutOfClusterAgentGetter) GetAgent(r *http.Request, cluster *models.Clus
 	return agent, nil
 }
 
-func (d *OutOfClusterAgentGetter) GetHelmAgent(r *http.Request, cluster *models.Cluster, namespace string) (*helm.Agent, error) {
+func (d *OutOfClusterAgentGetter) GetHelmAgent(ctx context.Context, r *http.Request, cluster *models.Cluster, namespace string) (*helm.Agent, error) {
+	ctx, span := telemetry.NewSpan(ctx, "get-helm-agent")
+	defer span.End()
+
+	telemetry.WithAttributes(span,
+		telemetry.AttributeKV{Key: "cluster-id", Value: cluster.ID},
+		telemetry.AttributeKV{Key: "project-id", Value: cluster.ProjectID},
+	)
+
 	// look for the agent in context
 	ctxAgentVal := r.Context().Value(HelmAgentCtxKey)
 
 	if ctxAgentVal != nil {
+		telemetry.WithAttributes(span, telemetry.AttributeKV{Key: "agent-from-context", Value: true})
 		if agent, ok := ctxAgentVal.(*helm.Agent); ok {
 			return agent, nil
 		}
@@ -141,16 +152,18 @@ func (d *OutOfClusterAgentGetter) GetHelmAgent(r *http.Request, cluster *models.
 	// if helm agent not found in context, construct it from k8s agent
 	k8sAgent, err := d.GetAgent(r, cluster, namespace)
 	if err != nil {
-		return nil, err
+		return nil, telemetry.Error(ctx, span, err, "error getting k8s agent")
 	}
 
 	if namespace == "" {
 		namespace = getNamespaceFromRequest(r)
 	}
 
+	telemetry.WithAttributes(span, telemetry.AttributeKV{Key: "namespace", Value: namespace})
+
 	helmAgent, err := helm.GetAgentFromK8sAgent("secret", namespace, d.config.Logger, k8sAgent)
 	if err != nil {
-		return nil, fmt.Errorf("failed to get Helm agent: %s", err.Error())
+		return nil, telemetry.Error(ctx, span, err, "failed to get Helm agent")
 	}
 
 	newCtx := context.WithValue(r.Context(), HelmAgentCtxKey, helmAgent)

+ 1 - 1
api/server/authz/release.go

@@ -37,7 +37,7 @@ type ReleaseScopedMiddleware struct {
 func (p *ReleaseScopedMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 	cluster, _ := r.Context().Value(types.ClusterScope).(*models.Cluster)
 
-	helmAgent, err := p.agentGetter.GetHelmAgent(r, cluster, "")
+	helmAgent, err := p.agentGetter.GetHelmAgent(r.Context(), r, cluster, "")
 	if err != nil {
 		apierrors.HandleAPIError(p.config.Logger, p.config.Alerter, w, r, apierrors.NewErrInternal(err), true)
 		return

+ 1 - 1
api/server/handlers/cluster/install_agent.go

@@ -52,7 +52,7 @@ func (c *InstallAgentHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)
 		return
 	}
 
-	helmAgent, err := c.GetHelmAgent(r, cluster, "porter-agent-system")
+	helmAgent, err := c.GetHelmAgent(r.Context(), r, cluster, "porter-agent-system")
 	if err != nil {
 		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
 		return

+ 1 - 1
api/server/handlers/cluster/upgrade_agent.go

@@ -33,7 +33,7 @@ func NewUpgradeAgentHandler(
 
 func (c *UpgradeAgentHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 	cluster, _ := r.Context().Value(types.ClusterScope).(*models.Cluster)
-	helmAgent, err := c.GetHelmAgent(r, cluster, "porter-agent-system")
+	helmAgent, err := c.GetHelmAgent(r.Context(), r, cluster, "porter-agent-system")
 	if err != nil {
 		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
 		return

+ 1 - 1
api/server/handlers/namespace/create_env_group.go

@@ -67,7 +67,7 @@ func (c *CreateEnvGroupHandler) ServeHTTP(w http.ResponseWriter, r *http.Request
 		return
 	}
 
-	helmAgent, err := c.GetHelmAgent(r, cluster, namespace)
+	helmAgent, err := c.GetHelmAgent(r.Context(), r, cluster, namespace)
 	if err != nil {
 		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
 		return

+ 1 - 1
api/server/handlers/namespace/list_releases.go

@@ -42,7 +42,7 @@ func (c *ListReleasesHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)
 	namespace := r.Context().Value(types.NamespaceScope).(string)
 	cluster, _ := r.Context().Value(types.ClusterScope).(*models.Cluster)
 
-	helmAgent, err := c.GetHelmAgent(r, cluster, "")
+	helmAgent, err := c.GetHelmAgent(r.Context(), r, cluster, "")
 	if err != nil {
 		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
 		return

+ 107 - 45
api/server/handlers/release/create.go

@@ -9,6 +9,8 @@ import (
 	"strings"
 	"time"
 
+	"github.com/porter-dev/porter/internal/telemetry"
+
 	"github.com/porter-dev/porter/api/server/authz"
 	"github.com/porter-dev/porter/api/server/handlers"
 	"github.com/porter-dev/porter/api/server/shared"
@@ -49,12 +51,24 @@ func NewCreateReleaseHandler(
 }
 
 func (c *CreateReleaseHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
-	ctx := r.Context()
-	user, _ := ctx.Value(types.UserScope).(*models.User)
-	cluster, _ := ctx.Value(types.ClusterScope).(*models.Cluster)
-	namespace := ctx.Value(types.NamespaceScope).(string)
+	tracer, _ := telemetry.InitTracer(r.Context(), c.Config().TelemetryConfig)
+	defer tracer.Shutdown()
+
+	user, _ := r.Context().Value(types.UserScope).(*models.User)
+	cluster, _ := r.Context().Value(types.ClusterScope).(*models.Cluster)
+	namespace := r.Context().Value(types.NamespaceScope).(string)
 	operationID := oauth.CreateRandomState()
 
+	ctx, span := telemetry.NewSpan(r.Context(), "serve-create-release")
+	defer span.End()
+
+	telemetry.WithAttributes(span,
+		telemetry.AttributeKV{Key: "project-id", Value: cluster.ProjectID},
+		telemetry.AttributeKV{Key: "cluster-id", Value: cluster.ID},
+		telemetry.AttributeKV{Key: "user-email", Value: user.Email},
+		telemetry.AttributeKV{Key: "namespace", Value: namespace},
+	)
+
 	c.Config().AnalyticsClient.Track(analytics.ApplicationLaunchStartTrack(
 		&analytics.ApplicationLaunchStartTrackOpts{
 			ClusterScopedTrackOpts: analytics.GetClusterScopedTrackOpts(user.ID, cluster.ProjectID, cluster.ID),
@@ -62,9 +76,9 @@ func (c *CreateReleaseHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)
 		},
 	))
 
-	helmAgent, err := c.GetHelmAgent(r, cluster, "")
+	helmAgent, err := c.GetHelmAgent(ctx, r, cluster, "")
 	if err != nil {
-		c.HandleAPIError(w, r, apierrors.NewErrInternal(fmt.Errorf("error getting helm agent: %w", err)))
+		c.HandleAPIError(w, r, apierrors.NewErrInternal(telemetry.Error(ctx, span, err, "error getting helm agent")))
 		return
 	}
 
@@ -78,12 +92,14 @@ func (c *CreateReleaseHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)
 		request.RepoURL = c.Config().ServerConf.DefaultApplicationHelmRepoURL
 	}
 
+	telemetry.WithAttributes(span, telemetry.AttributeKV{Key: "repo-url", Value: request.RepoURL})
+
 	// if the repo url is not an addon or application url, validate against the helm repos
 	if request.RepoURL != c.Config().ServerConf.DefaultAddonHelmRepoURL && request.RepoURL != c.Config().ServerConf.DefaultApplicationHelmRepoURL {
 		// load the helm repos in the project
 		hrs, err := c.Repo().HelmRepo().ListHelmReposByProjectID(cluster.ProjectID)
 		if err != nil {
-			c.HandleAPIError(w, r, apierrors.NewErrInternal(fmt.Errorf("error listing helm repos for project : %w", err)))
+			c.HandleAPIError(w, r, apierrors.NewErrInternal(telemetry.Error(ctx, span, err, "error listing helm repos for project")))
 			return
 		}
 
@@ -91,7 +107,7 @@ func (c *CreateReleaseHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)
 
 		if !isValid {
 			c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(
-				fmt.Errorf("invalid repo_url parameter"),
+				telemetry.Error(ctx, span, err, "invalid repo_url parameter"),
 				http.StatusBadRequest,
 			))
 
@@ -105,26 +121,26 @@ func (c *CreateReleaseHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)
 
 	chart, err := loader.LoadChartPublic(request.RepoURL, request.TemplateName, request.TemplateVersion)
 	if err != nil {
-		c.HandleAPIError(w, r, apierrors.NewErrInternal(fmt.Errorf("error loading public chart: %w", err)))
+		c.HandleAPIError(w, r, apierrors.NewErrInternal(telemetry.Error(ctx, span, err, "error loading public chart")))
 		return
 	}
 
 	registries, err := c.Repo().Registry().ListRegistriesByProjectID(cluster.ProjectID)
 	if err != nil {
-		c.HandleAPIError(w, r, apierrors.NewErrInternal(fmt.Errorf("error listing registries: %w", err)))
+		c.HandleAPIError(w, r, apierrors.NewErrInternal(telemetry.Error(ctx, span, err, "error listing registries")))
 		return
 	}
 
 	k8sAgent, err := c.GetAgent(r, cluster, "")
 	if err != nil {
-		c.HandleAPIError(w, r, apierrors.NewErrInternal(fmt.Errorf("error getting k8s agent: %w", err)))
+		c.HandleAPIError(w, r, apierrors.NewErrInternal(telemetry.Error(ctx, span, err, "error getting k8s agent")))
 		return
 	}
 
 	// create the namespace if it does not exist already
 	_, err = k8sAgent.CreateNamespace(namespace, nil)
 	if err != nil {
-		c.HandleAPIError(w, r, apierrors.NewErrInternal(fmt.Errorf("error creating namespace: %w", err)))
+		c.HandleAPIError(w, r, apierrors.NewErrInternal(telemetry.Error(ctx, span, err, "error creating namespace")))
 		return
 	}
 
@@ -141,7 +157,7 @@ func (c *CreateReleaseHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)
 	helmRelease, err := helmAgent.InstallChart(conf, c.Config().DOConf, c.Config().ServerConf.DisablePullSecretsInjection)
 	if err != nil {
 		c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(
-			fmt.Errorf("error installing a new chart: %s", err.Error()),
+			telemetry.Error(ctx, span, err, "error installing a new chart"),
 			http.StatusBadRequest,
 		))
 
@@ -155,7 +171,7 @@ func (c *CreateReleaseHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)
 			// read the attached configmap
 			cm, _, err := k8sAgent.GetLatestVersionedConfigMap(envGroupName, namespace)
 			if err != nil {
-				c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(fmt.Errorf("Couldn't find the env group"), http.StatusNotFound))
+				c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(telemetry.Error(ctx, span, err, "Couldn't find the env group"), http.StatusNotFound))
 				return
 			}
 
@@ -163,9 +179,9 @@ func (c *CreateReleaseHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)
 		}
 	}
 
-	release, err := CreateAppReleaseFromHelmRelease(c.Config(), cluster.ProjectID, cluster.ID, 0, helmRelease)
+	release, err := CreateAppReleaseFromHelmRelease(ctx, c.Config(), cluster.ProjectID, cluster.ID, 0, helmRelease)
 	if err != nil {
-		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+		c.HandleAPIError(w, r, apierrors.NewErrInternal(telemetry.Error(ctx, span, err, "error creating app release from helm release")))
 		return
 	}
 
@@ -175,7 +191,9 @@ func (c *CreateReleaseHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)
 			_, err = k8sAgent.AddApplicationToVersionedConfigMap(cm, release.Name)
 
 			if err != nil {
-				c.HandleAPIErrorNoWrite(w, r, apierrors.NewErrInternal(fmt.Errorf("Couldn't add %s to the config map %s", release.Name, cm.Name)))
+				telemetry.WithAttributes(span, telemetry.AttributeKV{Key: "release-name", Value: release.Name})
+				telemetry.WithAttributes(span, telemetry.AttributeKV{Key: "config-map-name", Value: cm.Name})
+				c.HandleAPIErrorNoWrite(w, r, apierrors.NewErrInternal(telemetry.Error(ctx, span, err, "Couldn't add release to the config map")))
 			}
 		}
 	}
@@ -189,11 +207,11 @@ func (c *CreateReleaseHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)
 	}
 
 	if request.BuildConfig != nil {
-		_, err = createBuildConfig(c.Config(), release, request.BuildConfig)
+		_, err = createBuildConfig(ctx, c.Config(), release, request.BuildConfig)
 	}
 
 	if err != nil {
-		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+		c.HandleAPIError(w, r, apierrors.NewErrInternal(telemetry.Error(ctx, span, err, "error building config")))
 		return
 	}
 
@@ -214,12 +232,12 @@ func (c *CreateReleaseHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)
 
 			if unwrappedErr != nil {
 				if errors.Is(unwrappedErr, actions.ErrProtectedBranch) {
-					c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusConflict))
+					c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(telemetry.Error(ctx, span, err, "error creating git action on protected branch"), http.StatusConflict))
 				} else if errors.Is(unwrappedErr, actions.ErrCreatePRForProtectedBranch) {
-					c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusPreconditionFailed))
+					c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(telemetry.Error(ctx, span, err, "error creating PR on protected branch"), http.StatusPreconditionFailed))
 				}
 			} else {
-				c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+				c.HandleAPIError(w, r, apierrors.NewErrInternal(telemetry.Error(ctx, span, err, "error creating git action")))
 				return
 			}
 		}
@@ -243,10 +261,21 @@ func (c *CreateReleaseHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)
 }
 
 func CreateAppReleaseFromHelmRelease(
+	ctx context.Context,
 	config *config.Config,
 	projectID, clusterID, stackResourceID uint,
 	helmRelease *release.Release,
 ) (*models.Release, error) {
+	ctx, span := telemetry.NewSpan(ctx, "create-app-release-from-helm-release")
+	defer span.End()
+
+	telemetry.WithAttributes(span,
+		telemetry.AttributeKV{Key: "project-id", Value: projectID},
+		telemetry.AttributeKV{Key: "cluster-id", Value: clusterID},
+		telemetry.AttributeKV{Key: "stack-resource-id", Value: stackResourceID},
+		telemetry.AttributeKV{Key: "helm-release-name", Value: helmRelease.Name},
+	)
+
 	token, err := encryption.GenerateRandomBytes(16)
 	if err != nil {
 		return nil, err
@@ -256,16 +285,18 @@ func CreateAppReleaseFromHelmRelease(
 	image, ok := helmRelease.Config["image"].(map[string]interface{})
 
 	if !ok {
-		return nil, fmt.Errorf("Could not find field image in config")
+		return nil, telemetry.Error(ctx, span, nil, "Could not find field image in config")
 	}
 
 	repository := image["repository"]
 	repoStr, ok := repository.(string)
 
 	if !ok {
-		return nil, fmt.Errorf("Could not find field repository in config")
+		return nil, telemetry.Error(ctx, span, nil, "Could not find field repository in config")
 	}
 
+	telemetry.WithAttributes(span, telemetry.AttributeKV{Key: "repo-uri", Value: repoStr})
+
 	release := &models.Release{
 		ClusterID:       clusterID,
 		ProjectID:       projectID,
@@ -303,12 +334,23 @@ func createGitAction(
 	name, namespace string,
 	release *models.Release,
 ) (*types.GitActionConfig, []byte, error) {
+	ctx, span := telemetry.NewSpan(ctx, "create-git-action")
+	defer span.End()
+
+	telemetry.WithAttributes(span,
+		telemetry.AttributeKV{Key: "project-id", Value: projectID},
+		telemetry.AttributeKV{Key: "cluster-id", Value: clusterID},
+		telemetry.AttributeKV{Key: "user-id", Value: userID},
+		telemetry.AttributeKV{Key: "name", Value: name},
+		telemetry.AttributeKV{Key: "namespace", Value: namespace},
+	)
+
 	// if the registry was provisioned through Porter, create a repository if necessary
 	if release != nil && request.RegistryID != 0 {
 		// read the registry
 		reg, err := config.Repo.Registry().ReadRegistry(projectID, request.RegistryID)
 		if err != nil {
-			return nil, nil, err
+			return nil, nil, telemetry.Error(ctx, span, err, "could not read repo registry")
 		}
 
 		_reg := registry.Registry(*reg)
@@ -318,15 +360,19 @@ func createGitAction(
 		nameSpl := strings.Split(request.ImageRepoURI, "/")
 		repoName := nameSpl[len(nameSpl)-1]
 
+		telemetry.WithAttributes(span, telemetry.AttributeKV{Key: "repo-name", Value: repoName})
+
 		err = regAPI.CreateRepository(ctx, config, repoName)
 
 		if err != nil {
-			return nil, nil, err
+			return nil, nil, telemetry.Error(ctx, span, err, "could not create repo")
 		}
 	}
 
 	isDryRun := release == nil
 
+	telemetry.WithAttributes(span, telemetry.AttributeKV{Key: "is-dry-run", Value: isDryRun})
+
 	repoSplit := strings.Split(request.GitRepo, "/")
 
 	if len(repoSplit) != 2 {
@@ -338,10 +384,10 @@ func createGitAction(
 
 	// if this isn't a dry run, generate the token
 	if !isDryRun {
-		encoded, err = getToken(config, userID, projectID, clusterID, request)
+		encoded, err = getToken(ctx, config, userID, projectID, clusterID, request)
 
 		if err != nil {
-			return nil, nil, err
+			return nil, nil, telemetry.Error(ctx, span, err, "error getting token")
 		}
 	}
 
@@ -401,7 +447,7 @@ func createGitAction(
 
 		if gaRunner.DryRun {
 			if gitErr != nil {
-				return nil, nil, gitErr
+				return nil, nil, telemetry.Error(ctx, span, gitErr, "error setting up git")
 			}
 
 			return nil, workflowYAML, nil
@@ -422,26 +468,35 @@ func createGitAction(
 		Version:             "v0.1.0",
 	})
 	if err != nil {
-		return nil, nil, err
+		return nil, nil, telemetry.Error(ctx, span, err, "error creating git action config")
 	}
 
 	// update the release in the db with the image repo uri
 	release.ImageRepoURI = ga.ImageRepoURI
 
 	_, err = config.Repo.Release().UpdateRelease(release)
-
 	if err != nil {
-		return nil, nil, err
+		return nil, nil, telemetry.Error(ctx, span, err, "error updating release")
 	}
 
 	return ga.ToGitActionConfigType(), workflowYAML, gitErr
 }
 
 func getToken(
+	ctx context.Context,
 	config *config.Config,
 	userID, projectID, clusterID uint,
 	request *types.CreateGitActionConfigRequest,
 ) (string, error) {
+	ctx, span := telemetry.NewSpan(ctx, "get-git-action-token")
+	defer span.End()
+
+	telemetry.WithAttributes(span,
+		telemetry.AttributeKV{Key: "project-id", Value: projectID},
+		telemetry.AttributeKV{Key: "cluster-id", Value: clusterID},
+		telemetry.AttributeKV{Key: "user-id", Value: userID},
+	)
+
 	// create a policy for the token
 	policy := []*types.PolicyDocument{
 		{
@@ -466,12 +521,12 @@ func getToken(
 
 	uid, err := encryption.GenerateRandomBytes(16)
 	if err != nil {
-		return "", err
+		return "", telemetry.Error(ctx, span, err, "error generating uid")
 	}
 
 	policyBytes, err := json.Marshal(policy)
 	if err != nil {
-		return "", err
+		return "", telemetry.Error(ctx, span, err, "error marshalling policy into json")
 	}
 
 	policyModel := &models.Policy{
@@ -485,24 +540,24 @@ func getToken(
 	policyModel, err = config.Repo.Policy().CreatePolicy(policyModel)
 
 	if err != nil {
-		return "", err
+		return "", telemetry.Error(ctx, span, err, "error creating policy")
 	}
 
 	// create the token in the database
 	tokenUID, err := encryption.GenerateRandomBytes(16)
 	if err != nil {
-		return "", err
+		return "", telemetry.Error(ctx, span, err, "error generating tokenUID")
 	}
 
 	secretKey, err := encryption.GenerateRandomBytes(16)
 	if err != nil {
-		return "", err
+		return "", telemetry.Error(ctx, span, err, "error generating secret key")
 	}
 
 	// hash the secret key for storage in the db
 	hashedToken, err := bcrypt.GenerateFromPassword([]byte(secretKey), 8)
 	if err != nil {
-		return "", err
+		return "", telemetry.Error(ctx, span, err, "error generating hashedToken")
 	}
 
 	expiresAt := time.Now().Add(time.Hour * 24 * 365)
@@ -522,26 +577,30 @@ func getToken(
 	apiToken, err = config.Repo.APIToken().CreateAPIToken(apiToken)
 
 	if err != nil {
-		return "", err
+		return "", telemetry.Error(ctx, span, err, "error creating api token")
 	}
 
 	// generate porter jwt token
 	jwt, err := token.GetStoredTokenForAPI(userID, projectID, apiToken.UniqueID, secretKey)
 	if err != nil {
-		return "", err
+		return "", telemetry.Error(ctx, span, err, "error getting stored token for api")
 	}
 
 	return jwt.EncodeToken(config.TokenConf)
 }
 
 func createBuildConfig(
+	ctx context.Context,
 	config *config.Config,
 	release *models.Release,
 	bcRequest *types.CreateBuildConfigRequest,
 ) (*types.BuildConfig, error) {
+	ctx, span := telemetry.NewSpan(ctx, "create-build-config")
+	defer span.End()
+
 	data, err := json.Marshal(bcRequest.Config)
 	if err != nil {
-		return nil, err
+		return nil, telemetry.Error(ctx, span, err, "error marshalling build config request")
 	}
 
 	// handle write to the database
@@ -551,14 +610,14 @@ func createBuildConfig(
 		Config:     data,
 	})
 	if err != nil {
-		return nil, err
+		return nil, telemetry.Error(ctx, span, err, "error creating build config")
 	}
 
 	release.BuildConfig = bc.ID
 
 	_, err = config.Repo.Release().UpdateRelease(release)
 	if err != nil {
-		return nil, err
+		return nil, telemetry.Error(ctx, span, err, "error updating release")
 	}
 
 	return bc.ToBuildConfigType(), nil
@@ -573,6 +632,7 @@ type containerEnvConfig struct {
 }
 
 func GetGARunner(
+	ctx context.Context,
 	config *config.Config,
 	userID, projectID, clusterID uint,
 	ga *models.GitActionConfig,
@@ -580,10 +640,12 @@ func GetGARunner(
 	release *models.Release,
 	helmRelease *release.Release,
 ) (*actions.GithubActions, error) {
+	ctx, span := telemetry.NewSpan(ctx, "get-ga-runner")
+	defer span.End()
+
 	cEnv := &containerEnvConfig{}
 
 	rawValues, err := yaml.Marshal(helmRelease.Config)
-
 	if err == nil {
 		err = yaml.Unmarshal(rawValues, cEnv)
 
@@ -596,7 +658,7 @@ func GetGARunner(
 	repoSplit := strings.Split(ga.GitRepo, "/")
 
 	if len(repoSplit) != 2 {
-		return nil, fmt.Errorf("invalid formatting of repo name")
+		return nil, telemetry.Error(ctx, span, nil, "invalid formatting of repo name")
 	}
 
 	// create the commit in the git repo

+ 1 - 1
api/server/handlers/release/create_addon.go

@@ -48,7 +48,7 @@ func (c *CreateAddonHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 		},
 	))
 
-	helmAgent, err := c.GetHelmAgent(r, cluster, "")
+	helmAgent, err := c.GetHelmAgent(r.Context(), r, cluster, "")
 	if err != nil {
 		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
 		return

+ 1 - 1
api/server/handlers/release/create_webhook.go

@@ -29,7 +29,7 @@ func (c *CreateWebhookHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)
 	helmRelease, _ := r.Context().Value(types.ReleaseScope).(*release.Release)
 	cluster, _ := r.Context().Value(types.ClusterScope).(*models.Cluster)
 
-	release, err := CreateAppReleaseFromHelmRelease(c.Config(), cluster.ProjectID, cluster.ID, 0, helmRelease)
+	release, err := CreateAppReleaseFromHelmRelease(r.Context(), c.Config(), cluster.ProjectID, cluster.ID, 0, helmRelease)
 	if err != nil {
 		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
 		return

+ 2 - 1
api/server/handlers/release/delete.go

@@ -37,7 +37,7 @@ func (c *DeleteReleaseHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)
 	cluster, _ := r.Context().Value(types.ClusterScope).(*models.Cluster)
 	helmRelease, _ := r.Context().Value(types.ReleaseScope).(*release.Release)
 
-	helmAgent, err := c.GetHelmAgent(r, cluster, "")
+	helmAgent, err := c.GetHelmAgent(r.Context(), r, cluster, "")
 	if err != nil {
 		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
 		return
@@ -88,6 +88,7 @@ func (c *DeleteReleaseHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)
 					}
 				} else {
 					gaRunner, err := GetGARunner(
+						r.Context(),
 						c.Config(),
 						user.ID,
 						cluster.ProjectID,

+ 1 - 1
api/server/handlers/release/get_history.go

@@ -32,7 +32,7 @@ func NewGetReleaseHistoryHandler(
 func (c *GetReleaseHistoryHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 	cluster, _ := r.Context().Value(types.ClusterScope).(*models.Cluster)
 
-	helmAgent, err := c.GetHelmAgent(r, cluster, "")
+	helmAgent, err := c.GetHelmAgent(r.Context(), r, cluster, "")
 	if err != nil {
 		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
 		return

+ 1 - 1
api/server/handlers/release/update_image_batch.go

@@ -35,7 +35,7 @@ func NewUpdateImageBatchHandler(
 func (c *UpdateImageBatchHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 	cluster, _ := r.Context().Value(types.ClusterScope).(*models.Cluster)
 
-	helmAgent, err := c.GetHelmAgent(r, cluster, "")
+	helmAgent, err := c.GetHelmAgent(r.Context(), r, cluster, "")
 	if err != nil {
 		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
 		return

+ 2 - 1
api/server/handlers/release/update_rollback.go

@@ -36,7 +36,7 @@ func (c *RollbackReleaseHandler) ServeHTTP(w http.ResponseWriter, r *http.Reques
 	cluster, _ := r.Context().Value(types.ClusterScope).(*models.Cluster)
 	helmRelease, _ := r.Context().Value(types.ReleaseScope).(*release.Release)
 
-	helmAgent, err := c.GetHelmAgent(r, cluster, "")
+	helmAgent, err := c.GetHelmAgent(r.Context(), r, cluster, "")
 	if err != nil {
 		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
 		return
@@ -75,6 +75,7 @@ func (c *RollbackReleaseHandler) ServeHTTP(w http.ResponseWriter, r *http.Reques
 
 			if gitAction != nil && gitAction.ID != 0 && gitAction.GitlabIntegrationID == 0 {
 				gaRunner, err := GetGARunner(
+					r.Context(),
 					c.Config(),
 					user.ID,
 					cluster.ProjectID,

+ 2 - 1
api/server/handlers/release/upgrade.go

@@ -44,7 +44,7 @@ func (c *UpgradeReleaseHandler) ServeHTTP(w http.ResponseWriter, r *http.Request
 	cluster, _ := r.Context().Value(types.ClusterScope).(*models.Cluster)
 	helmRelease, _ := r.Context().Value(types.ReleaseScope).(*release.Release)
 
-	helmAgent, err := c.GetHelmAgent(r, cluster, "")
+	helmAgent, err := c.GetHelmAgent(r.Context(), r, cluster, "")
 	if err != nil {
 		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
 		return
@@ -233,6 +233,7 @@ func (c *UpgradeReleaseHandler) ServeHTTP(w http.ResponseWriter, r *http.Request
 
 			if gitAction != nil && gitAction.ID != 0 && gitAction.GitlabIntegrationID == 0 {
 				gaRunner, err := GetGARunner(
+					r.Context(),
 					c.Config(),
 					user.ID,
 					cluster.ProjectID,

+ 1 - 1
api/server/handlers/release/upgrade_webhook.go

@@ -72,7 +72,7 @@ func (c *WebhookHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 
 	// in this case, we retrieve the agent by passing in the namespace field directly, since
 	// it cannot be detected from the URL
-	helmAgent, err := c.GetHelmAgent(r, cluster, release.Namespace)
+	helmAgent, err := c.GetHelmAgent(r.Context(), r, cluster, release.Namespace)
 	if err != nil {
 		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
 		return

+ 2 - 2
api/server/handlers/stack/add_application.go

@@ -125,7 +125,7 @@ func (p *StackAddApplicationHandler) ServeHTTP(w http.ResponseWriter, r *http.Re
 		return
 	}
 
-	helmAgent, err := p.GetHelmAgent(r, cluster, "")
+	helmAgent, err := p.GetHelmAgent(r.Context(), r, cluster, "")
 	if err != nil {
 		p.HandleAPIError(w, r, apierrors.NewErrInternal(err))
 		return
@@ -175,7 +175,7 @@ func (p *StackAddApplicationHandler) ServeHTTP(w http.ResponseWriter, r *http.Re
 
 	for _, resource := range revision.Resources {
 		if rel, exists := helmReleaseMap[fmt.Sprintf("%s/%s", namespace, resource.Name)]; exists {
-			_, err = release.CreateAppReleaseFromHelmRelease(p.Config(), proj.ID, cluster.ID, resource.ID, rel)
+			_, err = release.CreateAppReleaseFromHelmRelease(r.Context(), p.Config(), proj.ID, cluster.ID, resource.ID, rel)
 
 			if err != nil {
 				saveErrs = append(saveErrs, fmt.Sprintf("the resource %s/%s could not be saved right now", namespace, resource.Name))

+ 2 - 2
api/server/handlers/stack/create.go

@@ -171,7 +171,7 @@ func (p *StackCreateHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 			return
 		}
 
-		helmAgent, err := p.GetHelmAgent(r, cluster, "")
+		helmAgent, err := p.GetHelmAgent(r.Context(), r, cluster, "")
 		if err != nil {
 			p.HandleAPIError(w, r, apierrors.NewErrInternal(err))
 			return
@@ -221,7 +221,7 @@ func (p *StackCreateHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 
 		for _, resource := range revision.Resources {
 			if rel, exists := helmReleaseMap[fmt.Sprintf("%s/%s", namespace, resource.Name)]; exists {
-				_, err = release.CreateAppReleaseFromHelmRelease(p.Config(), proj.ID, cluster.ID, resource.ID, rel)
+				_, err = release.CreateAppReleaseFromHelmRelease(r.Context(), p.Config(), proj.ID, cluster.ID, resource.ID, rel)
 
 				if err != nil {
 					saveErrs = append(saveErrs, fmt.Sprintf("the resource %s/%s could not be saved right now", namespace, resource.Name))

+ 1 - 1
api/server/handlers/stack/delete.go

@@ -46,7 +46,7 @@ func (p *StackDeleteHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 			return
 		}
 
-		helmAgent, err := p.GetHelmAgent(r, cluster, namespace)
+		helmAgent, err := p.GetHelmAgent(r.Context(), r, cluster, namespace)
 		if err != nil {
 			p.HandleAPIError(w, r, apierrors.NewErrInternal(err))
 			return

+ 1 - 1
api/server/handlers/stack/remove_application.go

@@ -97,7 +97,7 @@ func (p *StackRemoveApplicationHandler) ServeHTTP(w http.ResponseWriter, r *http
 		return
 	}
 
-	helmAgent, err := p.GetHelmAgent(r, cluster, namespace)
+	helmAgent, err := p.GetHelmAgent(r.Context(), r, cluster, namespace)
 	if err != nil {
 		p.HandleAPIError(w, r, apierrors.NewErrInternal(err))
 		return

+ 1 - 1
api/server/handlers/stack/rollback.go

@@ -35,7 +35,7 @@ func NewStackRollbackHandler(
 func (p *StackRollbackHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 	proj, _ := r.Context().Value(types.ProjectScope).(*models.Project)
 	cluster, _ := r.Context().Value(types.ClusterScope).(*models.Cluster)
-	helmAgent, err := p.GetHelmAgent(r, cluster, "")
+	helmAgent, err := p.GetHelmAgent(r.Context(), r, cluster, "")
 	if err != nil {
 		p.HandleAPIError(w, r, apierrors.NewErrInternal(err))
 		return

+ 1 - 1
api/server/handlers/stack/update_source_put.go

@@ -38,7 +38,7 @@ func (p *StackPutSourceConfigHandler) ServeHTTP(w http.ResponseWriter, r *http.R
 	namespace, _ := r.Context().Value(types.NamespaceScope).(string)
 	stack, _ := r.Context().Value(types.StackScope).(*models.Stack)
 
-	helmAgent, err := p.GetHelmAgent(r, cluster, "")
+	helmAgent, err := p.GetHelmAgent(r.Context(), r, cluster, "")
 	if err != nil {
 		p.HandleAPIError(w, r, apierrors.NewErrInternal(err))
 		return

+ 9 - 1
api/server/handlers/stacks/create_porter_app.go

@@ -6,6 +6,8 @@ import (
 	"net/http"
 	"strings"
 
+	"github.com/porter-dev/porter/internal/telemetry"
+
 	"github.com/porter-dev/porter/api/server/authz"
 	"github.com/porter-dev/porter/api/server/handlers"
 	"github.com/porter-dev/porter/api/server/shared"
@@ -37,10 +39,16 @@ func NewCreatePorterAppHandler(
 }
 
 func (c *CreatePorterAppHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+	tracer, _ := telemetry.InitTracer(r.Context(), c.Config().TelemetryConfig)
+	defer tracer.Shutdown()
+
 	ctx := r.Context()
 	project, _ := ctx.Value(types.ProjectScope).(*models.Project)
 	cluster, _ := ctx.Value(types.ClusterScope).(*models.Cluster)
 
+	ctx, span := telemetry.NewSpan(r.Context(), "serve-create-porter-app")
+	defer span.End()
+
 	request := &types.CreatePorterAppRequest{}
 	if ok := c.DecodeAndValidate(w, r, request); !ok {
 		c.HandleAPIError(w, r, apierrors.NewErrInternal(fmt.Errorf("error decoding request")))
@@ -54,7 +62,7 @@ func (c *CreatePorterAppHandler) ServeHTTP(w http.ResponseWriter, r *http.Reques
 	}
 	namespace := fmt.Sprintf("porter-stack-%s", stackName)
 
-	helmAgent, err := c.GetHelmAgent(r, cluster, namespace)
+	helmAgent, err := c.GetHelmAgent(ctx, r, cluster, namespace)
 	if err != nil {
 		c.HandleAPIError(w, r, apierrors.NewErrInternal(fmt.Errorf("error getting helm agent: %w", err)))
 		return

+ 1 - 1
api/server/handlers/user/create.go

@@ -34,7 +34,7 @@ func NewUserCreateHandler(
 }
 
 func (u *UserCreateHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
-	tracer, err := telemetry.InitTracer(context.Background(), u.Config().TelemetryConfig)
+	tracer, _ := telemetry.InitTracer(context.Background(), u.Config().TelemetryConfig)
 	defer tracer.Shutdown()
 
 	// just for demonstration purposes

+ 1 - 1
api/server/handlers/v1/env_group/create.go

@@ -69,7 +69,7 @@ func (c *CreateEnvGroupHandler) ServeHTTP(w http.ResponseWriter, r *http.Request
 		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
 	}
 
-	helmAgent, err := c.GetHelmAgent(r, cluster, namespace)
+	helmAgent, err := c.GetHelmAgent(r.Context(), r, cluster, namespace)
 	if err != nil {
 		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
 		return

+ 2 - 1
api/server/handlers/v1/release/upgrade.go

@@ -44,7 +44,7 @@ func (c *UpgradeReleaseHandler) ServeHTTP(w http.ResponseWriter, r *http.Request
 	cluster, _ := r.Context().Value(types.ClusterScope).(*models.Cluster)
 	helmRelease, _ := r.Context().Value(types.ReleaseScope).(*release.Release)
 
-	helmAgent, err := c.GetHelmAgent(r, cluster, "")
+	helmAgent, err := c.GetHelmAgent(r.Context(), r, cluster, "")
 	if err != nil {
 		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
 		return
@@ -217,6 +217,7 @@ func (c *UpgradeReleaseHandler) ServeHTTP(w http.ResponseWriter, r *http.Request
 
 			if gitAction != nil && gitAction.ID != 0 && gitAction.GitlabIntegrationID == 0 {
 				gaRunner, err := baseReleaseHandler.GetGARunner(
+					r.Context(),
 					c.Config(),
 					user.ID,
 					cluster.ProjectID,