Skip to content

Commit

Permalink
Add telemetry to all metronome methods and endpoints (#4503)
Browse files Browse the repository at this point in the history
  • Loading branch information
MauAraujo authored Apr 4, 2024
1 parent d743b5a commit 11bf64b
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 20 deletions.
2 changes: 1 addition & 1 deletion api/server/handlers/billing/credits.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ func (c *GetCreditsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
return
}

credits, err := c.Config().BillingManager.MetronomeClient.GetCustomerCredits(proj.UsageID)
credits, err := c.Config().BillingManager.MetronomeClient.GetCustomerCredits(ctx, proj.UsageID)
if err != nil {
err := telemetry.Error(ctx, span, err, "error getting credits")
c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
Expand Down
2 changes: 1 addition & 1 deletion api/server/handlers/billing/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ func (c *CheckPaymentEnabledHandler) ServeHTTP(w http.ResponseWriter, r *http.Re

if c.Config().ServerConf.MetronomeAPIKey != "" && c.Config().ServerConf.PorterCloudPlanID != "" &&
proj.GetFeatureFlag(models.MetronomeEnabled, c.Config().LaunchDarklyClient) && proj.UsageID == uuid.Nil {
customerID, customerPlanID, err := c.Config().BillingManager.MetronomeClient.CreateCustomerWithPlan(user.CompanyName, proj.Name, proj.ID, proj.BillingID, c.Config().ServerConf.PorterCloudPlanID)
customerID, customerPlanID, err := c.Config().BillingManager.MetronomeClient.CreateCustomerWithPlan(ctx, user.CompanyName, proj.Name, proj.ID, proj.BillingID, c.Config().ServerConf.PorterCloudPlanID)
if err != nil {
err = telemetry.Error(ctx, span, err, "error creating Metronome customer")
c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
Expand Down
2 changes: 1 addition & 1 deletion api/server/handlers/project/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ func (p *ProjectCreateHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)

// Create Metronome customer and add to starter plan
if p.Config().ServerConf.MetronomeAPIKey != "" && p.Config().ServerConf.PorterCloudPlanID != "" && proj.GetFeatureFlag(models.MetronomeEnabled, p.Config().LaunchDarklyClient) {
customerID, customerPlanID, err := p.Config().BillingManager.MetronomeClient.CreateCustomerWithPlan(user.CompanyName, proj.Name, proj.ID, proj.BillingID, p.Config().ServerConf.PorterCloudPlanID)
customerID, customerPlanID, err := p.Config().BillingManager.MetronomeClient.CreateCustomerWithPlan(ctx, user.CompanyName, proj.Name, proj.ID, proj.BillingID, p.Config().ServerConf.PorterCloudPlanID)
if err != nil {
err = telemetry.Error(ctx, span, err, "error creating Metronome customer")
p.HandleAPIError(w, r, apierrors.NewErrInternal(err))
Expand Down
7 changes: 6 additions & 1 deletion api/server/handlers/project/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,13 +94,18 @@ func (p *ProjectDeleteHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)

if p.Config().ServerConf.MetronomeAPIKey != "" && p.Config().ServerConf.PorterCloudPlanID != "" &&
proj.GetFeatureFlag(models.MetronomeEnabled, p.Config().LaunchDarklyClient) {
err = p.Config().BillingManager.MetronomeClient.EndCustomerPlan(proj.UsageID, proj.UsagePlanID)
err = p.Config().BillingManager.MetronomeClient.EndCustomerPlan(ctx, proj.UsageID, proj.UsagePlanID)
if err != nil {
e := "error ending billing plan"
err = telemetry.Error(ctx, span, err, e)
p.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusInternalServerError))
return
}
telemetry.WithAttributes(span,
telemetry.AttributeKV{Key: "project-id", Value: proj.ID},
telemetry.AttributeKV{Key: "usage-id", Value: proj.UsageID},
telemetry.AttributeKV{Key: "usage-plan-id", Value: proj.UsagePlanID},
)
}

deletedProject, err := p.Repo().Project().DeleteProject(proj)
Expand Down
49 changes: 33 additions & 16 deletions internal/billing/metronome.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package billing

import (
"bytes"
"context"
"encoding/json"
"fmt"
"net/http"
Expand All @@ -11,6 +12,7 @@ import (

"github.com/google/uuid"
"github.com/porter-dev/porter/api/types"
"github.com/porter-dev/porter/internal/telemetry"
)

const (
Expand All @@ -34,7 +36,10 @@ func NewMetronomeClient(metronomeApiKey string) MetronomeClient {
}

// createCustomer will create the customer in Metronome
func (m MetronomeClient) createCustomer(orgName string, projectName string, projectID uint, billingID string) (customerID uuid.UUID, err error) {
func (m MetronomeClient) createCustomer(ctx context.Context, orgName string, projectName string, projectID uint, billingID string) (customerID uuid.UUID, err error) {
ctx, span := telemetry.NewSpan(ctx, "create-metronome-customer")
defer span.End()

path := "customers"
projIDStr := strconv.FormatUint(uint64(projectID), 10)

Expand All @@ -56,15 +61,18 @@ func (m MetronomeClient) createCustomer(orgName string, projectName string, proj

err = post(path, m.ApiKey, customer, &result)
if err != nil {
return customerID, err
return customerID, telemetry.Error(ctx, span, err, "error creating customer")
}
return result.Data.ID, nil
}

// addCustomerPlan will start the customer on the given plan
func (m MetronomeClient) addCustomerPlan(customerID uuid.UUID, planID uuid.UUID) (customerPlanID uuid.UUID, err error) {
func (m MetronomeClient) addCustomerPlan(ctx context.Context, customerID uuid.UUID, planID uuid.UUID) (customerPlanID uuid.UUID, err error) {
ctx, span := telemetry.NewSpan(ctx, "add-metronome-customer-plan")
defer span.End()

if customerID == uuid.Nil || planID == uuid.Nil {
return customerPlanID, fmt.Errorf("customer or plan id empty")
return customerPlanID, telemetry.Error(ctx, span, err, "customer or plan id empty")
}

path := fmt.Sprintf("/customers/%s/plans/add", customerID)
Expand All @@ -87,33 +95,39 @@ func (m MetronomeClient) addCustomerPlan(customerID uuid.UUID, planID uuid.UUID)

err = post(path, m.ApiKey, req, &result)
if err != nil {
return customerPlanID, err
return customerPlanID, telemetry.Error(ctx, span, err, "failed to add customer to plan")
}

return result.Data.CustomerPlanID, nil
}

// CreateCustomerWithPlan will create the customer in Metronome and immediately add it to the plan
func (m MetronomeClient) CreateCustomerWithPlan(orgName string, projectName string, projectID uint, billingID string, planID string) (customerID uuid.UUID, customerPlanID uuid.UUID, err error) {
func (m MetronomeClient) CreateCustomerWithPlan(ctx context.Context, orgName string, projectName string, projectID uint, billingID string, planID string) (customerID uuid.UUID, customerPlanID uuid.UUID, err error) {
ctx, span := telemetry.NewSpan(ctx, "add-metronome-customer-plan")
defer span.End()

porterCloudPlanID, err := uuid.Parse(planID)
if err != nil {
return customerID, customerPlanID, fmt.Errorf("error parsing starter plan id: %w", err)
return customerID, customerPlanID, telemetry.Error(ctx, span, err, "error parsing starter plan id")
}

customerID, err = m.createCustomer(orgName, projectName, projectID, billingID)
customerID, err = m.createCustomer(ctx, orgName, projectName, projectID, billingID)
if err != nil {
return customerID, customerPlanID, err
return customerID, customerPlanID, telemetry.Error(ctx, span, err, "error while creatinc customer with plan")
}

customerPlanID, err = m.addCustomerPlan(customerID, porterCloudPlanID)
customerPlanID, err = m.addCustomerPlan(ctx, customerID, porterCloudPlanID)

return customerID, customerPlanID, err
}

// EndCustomerPlan will immediately end the plan for the given customer
func (m MetronomeClient) EndCustomerPlan(customerID uuid.UUID, customerPlanID uuid.UUID) (err error) {
func (m MetronomeClient) EndCustomerPlan(ctx context.Context, customerID uuid.UUID, customerPlanID uuid.UUID) (err error) {
ctx, span := telemetry.NewSpan(ctx, "end-metronome-customer-plan")
defer span.End()

if customerID == uuid.Nil || customerPlanID == uuid.Nil {
return fmt.Errorf("customer or customer plan id empty")
return telemetry.Error(ctx, span, err, "customer or customer plan id empty")
}

path := fmt.Sprintf("/customers/%s/plans/%s/end", customerID, customerPlanID)
Expand All @@ -129,16 +143,19 @@ func (m MetronomeClient) EndCustomerPlan(customerID uuid.UUID, customerPlanID uu

err = post(path, m.ApiKey, req, nil)
if err != nil {
return err
return telemetry.Error(ctx, span, err, "failed to end customer plan")
}

return nil
}

// GetCustomerCredits will return the first credit grant for the customer
func (m MetronomeClient) GetCustomerCredits(customerID uuid.UUID) (credits int64, err error) {
func (m MetronomeClient) GetCustomerCredits(ctx context.Context, customerID uuid.UUID) (credits int64, err error) {
ctx, span := telemetry.NewSpan(ctx, "get-customer-credits")
defer span.End()

if customerID == uuid.Nil {
return credits, fmt.Errorf("customer id empty")
return credits, telemetry.Error(ctx, span, err, "customer id empty")
}

path := "credits/listGrants"
Expand All @@ -155,7 +172,7 @@ func (m MetronomeClient) GetCustomerCredits(customerID uuid.UUID) (credits int64

err = post(path, m.ApiKey, req, &result)
if err != nil {
return credits, err
return credits, telemetry.Error(ctx, span, err, "failed to get customer credits")
}

return result.Data[0].Balance.IncludingPending, nil
Expand Down

0 comments on commit 11bf64b

Please sign in to comment.