Skip to content
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

use vercel project name as service name #8291

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 50 additions & 44 deletions backend/vercel/vercel.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,23 +13,20 @@ import (
"strings"

"github.com/go-chi/chi"
"github.com/samber/lo"
log "github.com/sirupsen/logrus"
"go.opentelemetry.io/otel/trace"

model2 "github.com/highlight-run/highlight/backend/model"
highlightHttp "github.com/highlight-run/highlight/backend/http"
"github.com/highlight-run/highlight/backend/model"
privateModel "github.com/highlight-run/highlight/backend/private-graph/graph/model"
hlog "github.com/highlight/highlight/sdk/highlight-go/log"
highlightChi "github.com/highlight/highlight/sdk/highlight-go/middleware/chi"

"github.com/pkg/errors"

"github.com/highlight-run/highlight/backend/private-graph/graph/model"
"github.com/samber/lo"
log "github.com/sirupsen/logrus"
"go.opentelemetry.io/otel/trace"
)

const (
SourcemapEnvKey = "HIGHLIGHT_SOURCEMAP_UPLOAD_API_KEY"
ProjectIdEnvVar = "NEXT_PUBLIC_HIGHLIGHT_PROJECT_ID"
LogDrainProjectHeader = "x-highlight-project"
SourcemapEnvKey = "HIGHLIGHT_SOURCEMAP_UPLOAD_API_KEY"
ProjectIdEnvVar = "NEXT_PUBLIC_HIGHLIGHT_PROJECT_ID"
)

var (
Expand Down Expand Up @@ -204,10 +201,10 @@ func RemoveLogDrain(logDrainId string, accessToken string, teamId *string) error
return nil
}

func GetProjects(accessToken string, teamId *string) ([]*model.VercelProject, error) {
func GetProjects(accessToken string, teamId *string) ([]*privateModel.VercelProject, error) {
client := &http.Client{}

projects := []*model.VercelProject{}
projects := []*privateModel.VercelProject{}
next := 0
for {
data := url.Values{}
Expand Down Expand Up @@ -246,7 +243,7 @@ func GetProjects(accessToken string, teamId *string) ([]*model.VercelProject, er
}

var projectsResponse struct {
Projects []*model.VercelProject `json:"projects"`
Projects []*privateModel.VercelProject `json:"projects"`
Pagination struct {
Next int `json:"next"`
} `json:"pagination"`
Expand Down Expand Up @@ -315,40 +312,48 @@ func RemoveLogDrains(ctx context.Context, vercelTeamID *string, accessToken stri
}

func CreateLogDrain(ctx context.Context, vercelTeamID *string, vercelProjectIDs []string, projectVerboseID string, name string, accessToken string) error {
client := &http.Client{}

headers := fmt.Sprintf(`{"%s":"%s"}`, LogDrainProjectHeader, projectVerboseID)
projectIds := fmt.Sprintf(`[%s]`, strings.Join(lo.Map(vercelProjectIDs, func(t string, i int) string {
return fmt.Sprintf("\"%s\"", t)
}), ","))
body := fmt.Sprintf(`{"url":"https://pub.highlight.run/vercel/v1/logs", "name":"%s", "headers":%s, "projectIds":%s, "deliveryFormat":"ndjson", "secret": "%s", "sources": ["static", "lambda", "edge", "build", "external"]}`, name, headers, projectIds, projectVerboseID)
u := fmt.Sprintf("%s/v2/integrations/log-drains", ApiBaseUrl)
if vercelTeamID != nil {
u = fmt.Sprintf("%s?teamId=%s", u, *vercelTeamID)
}
req, err := http.NewRequest("POST", u, strings.NewReader(body))
projects, err := GetProjects(accessToken, vercelTeamID)
if err != nil {
return errors.Wrap(err, "error creating api request to Vercel")
return err
}
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", accessToken))
vercelProjectNames := lo.SliceToMap(projects, func(item *privateModel.VercelProject) (string, string) {
return item.ID, item.Name
})

res, err := client.Do(req)
client := &http.Client{}
for _, vercelProjectID := range vercelProjectIDs {
serviceName := vercelProjectNames[vercelProjectID]
headers := fmt.Sprintf(`{"%s":"%s","%s":"%s"}`, highlightHttp.LogDrainProjectHeader, projectVerboseID, highlightHttp.LogDrainServiceHeader, serviceName)
projectIds := fmt.Sprintf(`["%s"]`, vercelProjectID)
body := fmt.Sprintf(`{"url":"https://pub.highlight.run/vercel/v1/logs", "name":"%s", "headers":%s, "projectIds":%s, "deliveryFormat":"ndjson", "secret": "%s", "sources": ["static", "lambda", "edge", "build", "external"]}`, name, headers, projectIds, projectVerboseID)
u := fmt.Sprintf("%s/v2/integrations/log-drains", ApiBaseUrl)
if vercelTeamID != nil {
u = fmt.Sprintf("%s?teamId=%s", u, *vercelTeamID)
}
req, err := http.NewRequest("POST", u, strings.NewReader(body))
if err != nil {
return errors.Wrap(err, "error creating api request to Vercel")
}
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", accessToken))

if err != nil {
return errors.Wrap(err, "error getting response from Vercel log-drain endpoint")
}
res, err := client.Do(req)

b, err := io.ReadAll(res.Body)
if err != nil {
return errors.Wrap(err, "error getting response from Vercel log-drain endpoint")
}

if res.StatusCode != 200 {
log.WithContext(ctx).WithField("Body", string(b)).
WithField("Url", u).
Errorf("Vercel Log Drain API responded with error")
return errors.New("Vercel Log Drain API responded with error; status_code=" + res.Status + "; body=" + string(b))
}
b, err := io.ReadAll(res.Body)

if err != nil {
return errors.Wrap(err, "error reading response body from Vercel log-drain endpoint")
if res.StatusCode != 200 {
log.WithContext(ctx).WithField("Body", string(b)).
WithField("Url", u).
Errorf("Vercel Log Drain API responded with error")
return errors.New("Vercel Log Drain API responded with error; status_code=" + res.Status + "; body=" + string(b))
}

if err != nil {
return errors.Wrap(err, "error reading response body from Vercel log-drain endpoint")
}
}

return nil
Expand Down Expand Up @@ -380,14 +385,15 @@ func HandleLog(w http.ResponseWriter, r *http.Request) {
logs = append(logs, l)
}

projectVerboseID := r.Header.Get(LogDrainProjectHeader)
projectID, err := model2.FromVerboseID(projectVerboseID)
serviceName := r.Header.Get(highlightHttp.LogDrainServiceHeader)
projectVerboseID := r.Header.Get(highlightHttp.LogDrainProjectHeader)
projectID, err := model.FromVerboseID(projectVerboseID)
if err != nil {
log.WithContext(r.Context()).WithError(err).WithField("projectVerboseID", projectVerboseID).Error("failed to parse highlight project id from vercel request")
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
hlog.SubmitVercelLogs(r.Context(), tracer, projectID, logs)
hlog.SubmitVercelLogs(r.Context(), tracer, projectID, serviceName, logs)

w.WriteHeader(http.StatusOK)
}
Expand Down
78 changes: 56 additions & 22 deletions backend/vercel/vercel_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ package vercel
import (
"context"
"encoding/json"
"fmt"
http2 "github.com/highlight-run/highlight/backend/http"
privateModel "github.com/highlight-run/highlight/backend/private-graph/graph/model"
"io"
"net/http"
"net/http/httptest"
Expand All @@ -14,31 +17,62 @@ import (

func TestCreateLogDrain(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/v2/integrations/log-drains" {
t.Errorf("Expected to request '/fixedvalue', got: %s", r.URL.Path)
}
var resp struct {
Url string
Name string
Headers map[string]string
ProjectIds []string
DeliveryFormat string
Secret string
Sources []string
}
data, _ := io.ReadAll(r.Body)
if err := json.Unmarshal(data, &resp); err != nil {
if r.URL.Path == "/v2/integrations/log-drains" {
var resp struct {
Url string
Name string
Headers map[string]string
ProjectIds []string
DeliveryFormat string
Secret string
Sources []string
}
data, _ := io.ReadAll(r.Body)
if err := json.Unmarshal(data, &resp); err != nil {
t.Error(err)
}

assert.Equal(t, "https://pub.highlight.run/vercel/v1/logs", resp.Url)
assert.Equal(t, "Highlight Log Drain", resp.Name)
assert.Equal(t, "1", resp.Headers[http2.LogDrainProjectHeader])
assert.Equal(t, "vercel-project-name", resp.Headers[http2.LogDrainServiceHeader])
assert.Equal(t, []string{"prj_UYboDfJ3kTGcKmmqu4Ydryzy2KQC"}, resp.ProjectIds)
assert.Equal(t, "ndjson", resp.DeliveryFormat)
assert.Equal(t, "1", resp.Secret)
assert.Equal(t, []string{"static", "lambda", "edge", "build", "external"}, resp.Sources)
} else if r.URL.Path == "/v9/projects" {
projectsResponse := struct {
Projects []*privateModel.VercelProject `json:"projects"`
Pagination struct {
Next int `json:"next"`
} `json:"pagination"`
}{
Projects: []*privateModel.VercelProject{{
ID: "prj_UYboDfJ3kTGcKmmqu4Ydryzy2KQC",
Name: "vercel-project-name",
Env: []*privateModel.VercelEnv{{
ID: "abc",
Key: "def",
ConfigurationID: "456",
}},
}},
Pagination: struct {
Next int `json:"next"`
}(struct{ Next int }{
Next: 0,
}),
}
body, err := json.Marshal(&projectsResponse)
assert.NoError(t, err)
_, err = w.Write(body)
assert.NoError(t, err)
} else {
err := fmt.Sprintf("Expected to request '/fixedvalue', got: %s", r.URL.Path)
t.Error(err)
http.Error(w, err, http.StatusInternalServerError)
return
}

assert.Equal(t, "https://pub.highlight.run/vercel/v1/logs", resp.Url)
assert.Equal(t, "Highlight Log Drain", resp.Name)
assert.Equal(t, "1", resp.Headers[LogDrainProjectHeader])
assert.Equal(t, []string{"prj_UYboDfJ3kTGcKmmqu4Ydryzy2KQC"}, resp.ProjectIds)
assert.Equal(t, "ndjson", resp.DeliveryFormat)
assert.Equal(t, "1", resp.Secret)
assert.Equal(t, []string{"static", "lambda", "edge", "build", "external"}, resp.Sources)

w.WriteHeader(http.StatusOK)
}))
defer server.Close()
Expand Down
10 changes: 5 additions & 5 deletions sdk/highlight-go/log/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,10 @@ type VercelLog struct {
Proxy VercelProxy `json:"proxy"`
}

func submitVercelLog(ctx context.Context, tracer trace.Tracer, projectID int, log VercelLog) {
func submitVercelLog(ctx context.Context, tracer trace.Tracer, projectID int, serviceName string, log VercelLog) {
span, _ := highlight.StartTraceWithoutResourceAttributes(
ctx, tracer, highlight.UtilitySpanName, []trace.SpanStartOption{trace.WithSpanKind(trace.SpanKindClient)},
attribute.String(highlight.ProjectIDAttribute, strconv.Itoa(projectID)),
attribute.String(highlight.ProjectIDAttribute, strconv.Itoa(projectID)), semconv.ServiceNameKey.String(serviceName),
)
defer highlight.EndTrace(span)

Expand All @@ -95,7 +95,7 @@ func submitVercelLog(ctx context.Context, tracer trace.Tracer, projectID int, lo
attrs := []attribute.KeyValue{
LogSeverityKey.String(level),
LogMessageKey.String(log.Message),
semconv.ServiceNameKey.String("vercel-log-drain-" + log.ProjectId),
attribute.String("vercel.project", log.ProjectId),
semconv.ServiceVersionKey.String(log.DeploymentId),
semconv.CodeNamespaceKey.String(log.Source),
semconv.CodeFilepathKey.String(log.Path),
Expand All @@ -121,13 +121,13 @@ func submitVercelLog(ctx context.Context, tracer trace.Tracer, projectID int, lo
}
}

func SubmitVercelLogs(ctx context.Context, tracer trace.Tracer, projectID int, logs []VercelLog) {
func SubmitVercelLogs(ctx context.Context, tracer trace.Tracer, projectID int, serviceName string, logs []VercelLog) {
if len(logs) == 0 {
return
}

for _, log := range logs {
submitVercelLog(ctx, tracer, projectID, log)
submitVercelLog(ctx, tracer, projectID, serviceName, log)
}
}

Expand Down
Loading