From 63fa3157b46ad7797c255d8157b86f81d70f128c Mon Sep 17 00:00:00 2001 From: Akshay Date: Wed, 07 May 2025 17:06:39 +0000 Subject: [PATCH] Revert "telemetry: init telemetry package" This reverts commit 44f2b1f562faf1f36be90385a699a60991db6b86. --- appview/config.go | 1 - appview/db/issues.go | 37 ++++++------------------------------- appview/db/profile.go | 32 +++----------------------------- appview/db/pulls.go | 136 +++++++++++++++++++++++++--------------------------------------------------------------------------------------------------------------- appview/db/repos.go | 126 ++++++++++++------------------------------------------------------------------------------------------------------------------ appview/db/star.go | 9 ++++----- appview/db/timeline.go | 31 +++---------------------------- appview/state/artifact.go | 2 +- appview/state/middleware.go | 44 +++++++++++++------------------------------- appview/state/profile.go | 38 +++++--------------------------------- appview/state/pull.go | 758 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- appview/state/repo.go | 794 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- appview/state/repo_util.go | 30 ++++++------------------------ appview/state/router.go | 7 +------ appview/state/state.go | 78 +++++++++--------------------------------------------------------------------- cmd/appview/main.go | 6 ++---- go.mod | 27 ++++++--------------------- go.sum | 66 ++++++++++++++++++------------------------------------------------ telemetry/middleware.go | 88 ---------------------------------------------------------------------------------------- telemetry/provider.go | 65 ----------------------------------------------------------------- telemetry/telemetry.go | 76 ---------------------------------------------------------------------------- 21 file(s) changed, 334 insertion(s)(+), 2117 deletion(s)(-) diff --git a/appview/config.go b/appview/config.go --- a/appview/config.go +++ b/appview/config.go @@ -17,7 +17,6 @@ CamoHost string `env:"TANGLED_CAMO_HOST, default=https://camo.tangled.sh"` CamoSharedSecret string `env:"TANGLED_CAMO_SHARED_SECRET"` AvatarSharedSecret string `env:"TANGLED_AVATAR_SHARED_SECRET"` AvatarHost string `env:"TANGLED_AVATAR_HOST, default=https://avatar.tangled.sh"` - EnableTelemetry bool `env:"TANGLED_TELEMETRY_ENABLED, default=false"` } func LoadConfig(ctx context.Context) (*Config, error) { diff --git a/appview/db/issues.go b/appview/db/issues.go --- a/appview/db/issues.go +++ b/appview/db/issues.go @@ -1,13 +1,10 @@ package db import ( - "context" "database/sql" "time" "github.com/bluesky-social/indigo/atproto/syntax" - "go.opentelemetry.io/otel" - "go.opentelemetry.io/otel/attribute" "tangled.sh/tangled.sh/core/appview/pagination" ) @@ -106,25 +103,14 @@ err := e.QueryRow(`select owner_did from issues where repo_at = ? and issue_id = ?`, repoAt, issueId).Scan(&ownerDid) return ownerDid, err } -func GetIssues(ctx context.Context, e Execer, repoAt syntax.ATURI, isOpen bool, page pagination.Page) ([]Issue, error) { - ctx, span := otel.Tracer("db").Start(ctx, "GetIssues") - defer span.End() - - span.SetAttributes( - attribute.String("repo_at", repoAt.String()), - attribute.Bool("is_open", isOpen), - attribute.Int("page.offset", page.Offset), - attribute.Int("page.limit", page.Limit), - ) - +func GetIssues(e Execer, repoAt syntax.ATURI, isOpen bool, page pagination.Page) ([]Issue, error) { var issues []Issue openValue := 0 if isOpen { openValue = 1 } - rows, err := e.QueryContext( - ctx, + rows, err := e.Query( ` with numbered_issue as ( select @@ -153,13 +139,12 @@ title, body, open, comment_count - from + from numbered_issue - where + where row_num between ? and ?`, repoAt, openValue, page.Offset+1, page.Offset+page.Limit) if err != nil { - span.RecordError(err) return nil, err } defer rows.Close() @@ -170,13 +155,11 @@ var createdAt string var metadata IssueMetadata err := rows.Scan(&issue.OwnerDid, &issue.IssueId, &createdAt, &issue.Title, &issue.Body, &issue.Open, &metadata.CommentCount) if err != nil { - span.RecordError(err) return nil, err } createdTime, err := time.Parse(time.RFC3339, createdAt) if err != nil { - span.RecordError(err) return nil, err } issue.Created = createdTime @@ -186,11 +169,9 @@ issues = append(issues, issue) } if err := rows.Err(); err != nil { - span.RecordError(err) return nil, err } - span.SetAttributes(attribute.Int("issues.count", len(issues))) return issues, nil } @@ -275,10 +256,7 @@ return issues, nil } -func GetIssue(ctx context.Context, e Execer, repoAt syntax.ATURI, issueId int) (*Issue, error) { - ctx, span := otel.Tracer("db").Start(ctx, "GetIssue") - defer span.End() - +func GetIssue(e Execer, repoAt syntax.ATURI, issueId int) (*Issue, error) { query := `select owner_did, created, title, body, open from issues where repo_at = ? and issue_id = ?` row := e.QueryRow(query, repoAt, issueId) @@ -298,10 +276,7 @@ return &issue, nil } -func GetIssueWithComments(ctx context.Context, e Execer, repoAt syntax.ATURI, issueId int) (*Issue, []Comment, error) { - ctx, span := otel.Tracer("db").Start(ctx, "GetIssueWithComments") - defer span.End() - +func GetIssueWithComments(e Execer, repoAt syntax.ATURI, issueId int) (*Issue, []Comment, error) { query := `select owner_did, issue_id, created, title, body, open from issues where repo_at = ? and issue_id = ?` row := e.QueryRow(query, repoAt, issueId) diff --git a/appview/db/profile.go b/appview/db/profile.go --- a/appview/db/profile.go +++ b/appview/db/profile.go @@ -1,13 +1,8 @@ package db import ( - "context" "fmt" "time" - - "go.opentelemetry.io/otel/attribute" - "go.opentelemetry.io/otel/codes" - "go.opentelemetry.io/otel/trace" ) type RepoEvent struct { @@ -88,14 +83,7 @@ } const TimeframeMonths = 7 -func MakeProfileTimeline(ctx context.Context, e Execer, forDid string) (*ProfileTimeline, error) { - span := trace.SpanFromContext(ctx) - defer span.End() - - span.SetAttributes( - attribute.String("forDid", forDid), - ) - +func MakeProfileTimeline(e Execer, forDid string) (*ProfileTimeline, error) { timeline := ProfileTimeline{ ByMonth: make([]ByMonth, TimeframeMonths), } @@ -104,13 +92,9 @@ timeframe := fmt.Sprintf("-%d months", TimeframeMonths) pulls, err := GetPullsByOwnerDid(e, forDid, timeframe) if err != nil { - span.RecordError(err) - span.SetStatus(codes.Error, "error getting pulls by owner did") return nil, fmt.Errorf("error getting pulls by owner did: %w", err) } - span.SetAttributes(attribute.Int("pulls.count", len(pulls))) - // group pulls by month for _, pull := range pulls { pullMonth := pull.Created.Month() @@ -128,13 +112,9 @@ } issues, err := GetIssuesByOwnerDid(e, forDid, timeframe) if err != nil { - span.RecordError(err) - span.SetStatus(codes.Error, "error getting issues by owner did") return nil, fmt.Errorf("error getting issues by owner did: %w", err) } - span.SetAttributes(attribute.Int("issues.count", len(issues))) - for _, issue := range issues { issueMonth := issue.Created.Month() @@ -149,23 +129,17 @@ *items = append(*items, &issue) } - repos, err := GetAllReposByDid(ctx, e, forDid) + repos, err := GetAllReposByDid(e, forDid) if err != nil { - span.RecordError(err) - span.SetStatus(codes.Error, "error getting all repos by did") return nil, fmt.Errorf("error getting all repos by did: %w", err) } - - span.SetAttributes(attribute.Int("repos.count", len(repos))) for _, repo := range repos { // TODO: get this in the original query; requires COALESCE because nullable var sourceRepo *Repo if repo.Source != "" { - sourceRepo, err = GetRepoByAtUri(ctx, e, repo.Source) + sourceRepo, err = GetRepoByAtUri(e, repo.Source) if err != nil { - span.RecordError(err) - span.SetStatus(codes.Error, "error getting repo by at uri") return nil, err } } diff --git a/appview/db/pulls.go b/appview/db/pulls.go --- a/appview/db/pulls.go +++ b/appview/db/pulls.go @@ -1,7 +1,6 @@ package db import ( - "context" "database/sql" "fmt" "log" @@ -11,8 +10,6 @@ "time" "github.com/bluekeyes/go-gitdiff/gitdiff" "github.com/bluesky-social/indigo/atproto/syntax" - "go.opentelemetry.io/otel/attribute" - "go.opentelemetry.io/otel/trace" "tangled.sh/tangled.sh/core/api/tangled" "tangled.sh/tangled.sh/core/patchutil" "tangled.sh/tangled.sh/core/types" @@ -237,18 +234,7 @@ return patches } -func NewPull(ctx context.Context, tx *sql.Tx, pull *Pull) error { - span := trace.SpanFromContext(ctx) - defer span.End() - - span.SetAttributes( - attribute.String("repo.at", pull.RepoAt.String()), - attribute.String("owner.did", pull.OwnerDid), - attribute.String("title", pull.Title), - attribute.String("target_branch", pull.TargetBranch), - ) - span.AddEvent("creating new pull request") - +func NewPull(tx *sql.Tx, pull *Pull) error { defer tx.Rollback() _, err := tx.Exec(` @@ -256,7 +242,6 @@ insert or ignore into repo_pull_seqs (repo_at, next_pull_id) values (?, 1) `, pull.RepoAt) if err != nil { - span.RecordError(err) return err } @@ -268,16 +253,12 @@ where repo_at = ? returning next_pull_id - 1 `, pull.RepoAt).Scan(&nextId) if err != nil { - span.RecordError(err) return err } pull.PullId = nextId pull.State = PullOpen - span.SetAttributes(attribute.Int("pull.id", pull.PullId)) - span.AddEvent("assigned pull ID") - var sourceBranch, sourceRepoAt *string if pull.PullSource != nil { sourceBranch = &pull.PullSource.Branch @@ -303,34 +284,26 @@ sourceBranch, sourceRepoAt, ) if err != nil { - span.RecordError(err) return err } - - span.AddEvent("inserted pull record") _, err = tx.Exec(` insert into pull_submissions (pull_id, repo_at, round_number, patch, source_rev) values (?, ?, ?, ?, ?) `, pull.PullId, pull.RepoAt, 0, pull.Submissions[0].Patch, pull.Submissions[0].SourceRev) if err != nil { - span.RecordError(err) return err } - - span.AddEvent("inserted initial pull submission") if err := tx.Commit(); err != nil { - span.RecordError(err) return err } - span.AddEvent("transaction committed successfully") return nil } -func GetPullAt(ctx context.Context, e Execer, repoAt syntax.ATURI, pullId int) (syntax.ATURI, error) { - pull, err := GetPull(ctx, e, repoAt, pullId) +func GetPullAt(e Execer, repoAt syntax.ATURI, pullId int) (syntax.ATURI, error) { + pull, err := GetPull(e, repoAt, pullId) if err != nil { return "", err } @@ -343,19 +316,10 @@ err := e.QueryRow(`select next_pull_id from repo_pull_seqs where repo_at = ?`, repoAt).Scan(&pullId) return pullId - 1, err } -func GetPulls(ctx context.Context, e Execer, repoAt syntax.ATURI, state PullState) ([]*Pull, error) { - span := trace.SpanFromContext(ctx) - defer span.End() - - span.SetAttributes( - attribute.String("repoAt", repoAt.String()), - attribute.String("state", state.String()), - ) - span.AddEvent("querying pulls") - +func GetPulls(e Execer, repoAt syntax.ATURI, state PullState) ([]*Pull, error) { pulls := make(map[int]*Pull) - rows, err := e.QueryContext(ctx, ` + rows, err := e.Query(` select owner_did, pull_id, @@ -372,7 +336,6 @@ pulls where repo_at = ? and state = ?`, repoAt, state) if err != nil { - span.RecordError(err) return nil, err } defer rows.Close() @@ -394,13 +357,11 @@ &sourceBranch, &sourceRepoAt, ) if err != nil { - span.RecordError(err) return nil, err } createdTime, err := time.Parse(time.RFC3339, createdAt) if err != nil { - span.RecordError(err) return nil, err } pull.Created = createdTime @@ -412,7 +373,6 @@ } if sourceRepoAt.Valid { sourceRepoAtParsed, err := syntax.ParseATURI(sourceRepoAt.String) if err != nil { - span.RecordError(err) return nil, err } pull.PullSource.RepoAt = &sourceRepoAtParsed @@ -422,9 +382,6 @@ pulls[pull.PullId] = &pull } - span.AddEvent("querying pull submissions") - span.SetAttributes(attribute.Int("pull_count", len(pulls))) - // get latest round no. for each pull inClause := strings.TrimSuffix(strings.Repeat("?, ", len(pulls)), ", ") submissionsQuery := fmt.Sprintf(` @@ -443,9 +400,8 @@ for _, p := range pulls { args[idx] = p.PullId idx += 1 } - submissionsRows, err := e.QueryContext(ctx, submissionsQuery, args...) + submissionsRows, err := e.Query(submissionsQuery, args...) if err != nil { - span.RecordError(err) return nil, err } defer submissionsRows.Close() @@ -458,7 +414,6 @@ &s.PullId, &s.RoundNumber, ) if err != nil { - span.RecordError(err) return nil, err } @@ -468,11 +423,8 @@ p.Submissions[s.RoundNumber] = &s } } if err := rows.Err(); err != nil { - span.RecordError(err) return nil, err } - - span.AddEvent("querying pull comments") // get comment count on latest submission on each pull inClause = strings.TrimSuffix(strings.Repeat("?, ", len(pulls)), ", ") @@ -491,9 +443,8 @@ args = []any{} for _, p := range pulls { args = append(args, p.Submissions[p.LastRoundNumber()].ID) } - commentsRows, err := e.QueryContext(ctx, commentsQuery, args...) + commentsRows, err := e.Query(commentsQuery, args...) if err != nil { - span.RecordError(err) return nil, err } defer commentsRows.Close() @@ -505,7 +456,6 @@ &commentCount, &pullId, ) if err != nil { - span.RecordError(err) return nil, err } if p, ok := pulls[pullId]; ok { @@ -513,11 +463,8 @@ p.Submissions[p.LastRoundNumber()].Comments = make([]PullComment, commentCount) } } if err := rows.Err(); err != nil { - span.RecordError(err) return nil, err } - - span.AddEvent("sorting pulls by date") orderedByDate := []*Pull{} for _, p := range pulls { @@ -527,17 +474,10 @@ sort.Slice(orderedByDate, func(i, j int) bool { return orderedByDate[i].Created.After(orderedByDate[j].Created) }) - span.SetAttributes(attribute.Int("result_count", len(orderedByDate))) return orderedByDate, nil } -func GetPull(ctx context.Context, e Execer, repoAt syntax.ATURI, pullId int) (*Pull, error) { - span := trace.SpanFromContext(ctx) - defer span.End() - - span.SetAttributes(attribute.String("repoAt", repoAt.String()), attribute.Int("pull.id", pullId)) - span.AddEvent("query pull metadata") - +func GetPull(e Execer, repoAt syntax.ATURI, pullId int) (*Pull, error) { query := ` select owner_did, @@ -556,7 +496,7 @@ pulls where repo_at = ? and pull_id = ? ` - row := e.QueryRowContext(ctx, query, repoAt, pullId) + row := e.QueryRow(query, repoAt, pullId) var pull Pull var createdAt string @@ -575,17 +515,16 @@ &sourceBranch, &sourceRepoAt, ) if err != nil { - span.RecordError(err) return nil, err } createdTime, err := time.Parse(time.RFC3339, createdAt) if err != nil { - span.RecordError(err) return nil, err } pull.Created = createdTime + // populate source if sourceBranch.Valid { pull.PullSource = &PullSource{ Branch: sourceBranch.String, @@ -593,14 +532,12 @@ } if sourceRepoAt.Valid { sourceRepoAtParsed, err := syntax.ParseATURI(sourceRepoAt.String) if err != nil { - span.RecordError(err) return nil, err } pull.PullSource.RepoAt = &sourceRepoAtParsed } } - span.AddEvent("query submissions") submissionsQuery := ` select id, pull_id, repo_at, round_number, patch, created, source_rev @@ -609,9 +546,8 @@ pull_submissions where repo_at = ? and pull_id = ? ` - submissionsRows, err := e.QueryContext(ctx, submissionsQuery, repoAt, pullId) + submissionsRows, err := e.Query(submissionsQuery, repoAt, pullId) if err != nil { - span.RecordError(err) return nil, err } defer submissionsRows.Close() @@ -632,13 +568,11 @@ &submissionCreatedStr, &submissionSourceRev, ) if err != nil { - span.RecordError(err) return nil, err } submissionCreatedTime, err := time.Parse(time.RFC3339, submissionCreatedStr) if err != nil { - span.RecordError(err) return nil, err } submission.Created = submissionCreatedTime @@ -650,7 +584,6 @@ submissionsMap[submission.ID] = &submission } if err = submissionsRows.Close(); err != nil { - span.RecordError(err) return nil, err } if len(submissionsMap) == 0 { @@ -662,8 +595,6 @@ for k := range submissionsMap { args = append(args, k) } inClause := strings.TrimSuffix(strings.Repeat("?, ", len(submissionsMap)), ", ") - - span.AddEvent("query comments") commentsQuery := fmt.Sprintf(` select id, @@ -681,9 +612,8 @@ submission_id IN (%s) order by created asc `, inClause) - commentsRows, err := e.QueryContext(ctx, commentsQuery, args...) + commentsRows, err := e.Query(commentsQuery, args...) if err != nil { - span.RecordError(err) return nil, err } defer commentsRows.Close() @@ -702,34 +632,34 @@ &comment.Body, &commentCreatedStr, ) if err != nil { - span.RecordError(err) return nil, err } commentCreatedTime, err := time.Parse(time.RFC3339, commentCreatedStr) if err != nil { - span.RecordError(err) return nil, err } comment.Created = commentCreatedTime + // Add the comment to its submission if submission, ok := submissionsMap[comment.SubmissionId]; ok { submission.Comments = append(submission.Comments, comment) } + } if err = commentsRows.Err(); err != nil { - span.RecordError(err) return nil, err } - if pull.PullSource != nil && pull.PullSource.RepoAt != nil { - span.AddEvent("query pull source repo") - pullSourceRepo, err := GetRepoByAtUri(ctx, e, pull.PullSource.RepoAt.String()) - if err != nil { - span.RecordError(err) - log.Printf("failed to get repo by at uri: %v", err) - } else { - pull.PullSource.Repo = pullSourceRepo + var pullSourceRepo *Repo + if pull.PullSource != nil { + if pull.PullSource.RepoAt != nil { + pullSourceRepo, err = GetRepoByAtUri(e, pull.PullSource.RepoAt.String()) + if err != nil { + log.Printf("failed to get repo by at uri: %v", err) + } else { + pull.PullSource.Repo = pullSourceRepo + } } } @@ -817,21 +747,9 @@ return pulls, nil } -func NewPullComment(ctx context.Context, e Execer, comment *PullComment) (int64, error) { - span := trace.SpanFromContext(ctx) - defer span.End() - - span.SetAttributes( - attribute.String("repo.at", comment.RepoAt), - attribute.Int("pull.id", comment.PullId), - attribute.Int("submission.id", comment.SubmissionId), - attribute.String("owner.did", comment.OwnerDid), - ) - span.AddEvent("inserting new pull comment") - +func NewPullComment(e Execer, comment *PullComment) (int64, error) { query := `insert into pull_comments (owner_did, repo_at, submission_id, comment_at, pull_id, body) values (?, ?, ?, ?, ?, ?)` - res, err := e.ExecContext( - ctx, + res, err := e.Exec( query, comment.OwnerDid, comment.RepoAt, @@ -841,18 +759,14 @@ comment.PullId, comment.Body, ) if err != nil { - span.RecordError(err) return 0, err } i, err := res.LastInsertId() if err != nil { - span.RecordError(err) return 0, err } - span.SetAttributes(attribute.Int64("comment.id", i)) - span.AddEvent("pull comment created successfully") return i, nil } diff --git a/appview/db/repos.go b/appview/db/repos.go --- a/appview/db/repos.go +++ b/appview/db/repos.go @@ -1,13 +1,10 @@ package db import ( - "context" "database/sql" "time" "github.com/bluesky-social/indigo/atproto/syntax" - "go.opentelemetry.io/otel" - "go.opentelemetry.io/otel/attribute" ) type Repo struct { @@ -26,11 +23,7 @@ // optional Source string } -func GetAllRepos(ctx context.Context, e Execer, limit int) ([]Repo, error) { - ctx, span := otel.Tracer("db").Start(ctx, "GetAllRepos") - defer span.End() - span.SetAttributes(attribute.Int("limit", limit)) - +func GetAllRepos(e Execer, limit int) ([]Repo, error) { var repos []Repo rows, err := e.Query( @@ -42,7 +35,6 @@ `, limit, ) if err != nil { - span.RecordError(err) return nil, err } defer rows.Close() @@ -53,26 +45,19 @@ err := scanRepo( rows, &repo.Did, &repo.Name, &repo.Knot, &repo.Rkey, &repo.Description, &repo.Created, &repo.Source, ) if err != nil { - span.RecordError(err) return nil, err } repos = append(repos, repo) } if err := rows.Err(); err != nil { - span.RecordError(err) return nil, err } - span.SetAttributes(attribute.Int("repos.count", len(repos))) return repos, nil } -func GetAllReposByDid(ctx context.Context, e Execer, did string) ([]Repo, error) { - ctx, span := otel.Tracer("db").Start(ctx, "GetAllReposByDid") - defer span.End() - span.SetAttributes(attribute.String("did", did)) - +func GetAllReposByDid(e Execer, did string) ([]Repo, error) { var repos []Repo rows, err := e.Query( @@ -96,7 +81,6 @@ r.at_uri order by r.created desc`, did) if err != nil { - span.RecordError(err) return nil, err } defer rows.Close() @@ -110,7 +94,6 @@ var nullableSource sql.NullString err := rows.Scan(&repo.Did, &repo.Name, &repo.Knot, &repo.Rkey, &nullableDescription, &createdAt, &repoStats.StarCount, &nullableSource) if err != nil { - span.RecordError(err) return nil, err } @@ -135,22 +118,13 @@ repos = append(repos, repo) } if err := rows.Err(); err != nil { - span.RecordError(err) return nil, err } - span.SetAttributes(attribute.Int("repos.count", len(repos))) return repos, nil } -func GetRepo(ctx context.Context, e Execer, did, name string) (*Repo, error) { - ctx, span := otel.Tracer("db").Start(ctx, "GetRepo") - defer span.End() - span.SetAttributes( - attribute.String("did", did), - attribute.String("name", name), - ) - +func GetRepo(e Execer, did, name string) (*Repo, error) { var repo Repo var nullableDescription sql.NullString @@ -158,7 +132,6 @@ row := e.QueryRow(`select did, name, knot, created, at_uri, description from repos where did = ? and name = ?`, did, name) var createdAt string if err := row.Scan(&repo.Did, &repo.Name, &repo.Knot, &createdAt, &repo.AtUri, &nullableDescription); err != nil { - span.RecordError(err) return nil, err } createdAtTime, _ := time.Parse(time.RFC3339, createdAt) @@ -173,11 +146,7 @@ return &repo, nil } -func GetRepoByAtUri(ctx context.Context, e Execer, atUri string) (*Repo, error) { - ctx, span := otel.Tracer("db").Start(ctx, "GetRepoByAtUri") - defer span.End() - span.SetAttributes(attribute.String("atUri", atUri)) - +func GetRepoByAtUri(e Execer, atUri string) (*Repo, error) { var repo Repo var nullableDescription sql.NullString @@ -185,7 +154,6 @@ row := e.QueryRow(`select did, name, knot, created, at_uri, description from repos where at_uri = ?`, atUri) var createdAt string if err := row.Scan(&repo.Did, &repo.Name, &repo.Knot, &createdAt, &repo.AtUri, &nullableDescription); err != nil { - span.RecordError(err) return nil, err } createdAtTime, _ := time.Parse(time.RFC3339, createdAt) @@ -200,60 +168,31 @@ return &repo, nil } -func AddRepo(ctx context.Context, e Execer, repo *Repo) error { - ctx, span := otel.Tracer("db").Start(ctx, "AddRepo") - defer span.End() - span.SetAttributes( - attribute.String("did", repo.Did), - attribute.String("name", repo.Name), - ) - +func AddRepo(e Execer, repo *Repo) error { _, err := e.Exec( `insert into repos (did, name, knot, rkey, at_uri, description, source) values (?, ?, ?, ?, ?, ?, ?)`, repo.Did, repo.Name, repo.Knot, repo.Rkey, repo.AtUri, repo.Description, repo.Source, ) - if err != nil { - span.RecordError(err) - } return err } -func RemoveRepo(ctx context.Context, e Execer, did, name string) error { - ctx, span := otel.Tracer("db").Start(ctx, "RemoveRepo") - defer span.End() - span.SetAttributes( - attribute.String("did", did), - attribute.String("name", name), - ) - +func RemoveRepo(e Execer, did, name string) error { _, err := e.Exec(`delete from repos where did = ? and name = ?`, did, name) - if err != nil { - span.RecordError(err) - } return err } -func GetRepoSource(ctx context.Context, e Execer, repoAt syntax.ATURI) (string, error) { - ctx, span := otel.Tracer("db").Start(ctx, "GetRepoSource") - defer span.End() - span.SetAttributes(attribute.String("repoAt", repoAt.String())) - +func GetRepoSource(e Execer, repoAt syntax.ATURI) (string, error) { var nullableSource sql.NullString err := e.QueryRow(`select source from repos where at_uri = ?`, repoAt).Scan(&nullableSource) if err != nil { - span.RecordError(err) return "", err } return nullableSource.String, nil } -func GetForksByDid(ctx context.Context, e Execer, did string) ([]Repo, error) { - ctx, span := otel.Tracer("db").Start(ctx, "GetForksByDid") - defer span.End() - span.SetAttributes(attribute.String("did", did)) - +func GetForksByDid(e Execer, did string) ([]Repo, error) { var repos []Repo rows, err := e.Query( @@ -264,7 +203,6 @@ order by created desc`, did, ) if err != nil { - span.RecordError(err) return nil, err } defer rows.Close() @@ -277,7 +215,6 @@ var nullableSource sql.NullString err := rows.Scan(&repo.Did, &repo.Name, &repo.Knot, &repo.Rkey, &nullableDescription, &createdAt, &repo.AtUri, &nullableSource) if err != nil { - span.RecordError(err) return nil, err } @@ -300,22 +237,13 @@ repos = append(repos, repo) } if err := rows.Err(); err != nil { - span.RecordError(err) return nil, err } - span.SetAttributes(attribute.Int("forks.count", len(repos))) return repos, nil } -func GetForkByDid(ctx context.Context, e Execer, did string, name string) (*Repo, error) { - ctx, span := otel.Tracer("db").Start(ctx, "GetForkByDid") - defer span.End() - span.SetAttributes( - attribute.String("did", did), - attribute.String("name", name), - ) - +func GetForkByDid(e Execer, did string, name string) (*Repo, error) { var repo Repo var createdAt string var nullableDescription sql.NullString @@ -330,7 +258,6 @@ ) err := row.Scan(&repo.Did, &repo.Name, &repo.Knot, &repo.Rkey, &nullableDescription, &createdAt, &repo.AtUri, &nullableSource) if err != nil { - span.RecordError(err) return nil, err } @@ -352,46 +279,21 @@ return &repo, nil } -func AddCollaborator(ctx context.Context, e Execer, collaborator, repoOwnerDid, repoName, repoKnot string) error { - ctx, span := otel.Tracer("db").Start(ctx, "AddCollaborator") - defer span.End() - span.SetAttributes( - attribute.String("collaborator", collaborator), - attribute.String("repoOwnerDid", repoOwnerDid), - attribute.String("repoName", repoName), - ) - +func AddCollaborator(e Execer, collaborator, repoOwnerDid, repoName, repoKnot string) error { _, err := e.Exec( `insert into collaborators (did, repo) values (?, (select id from repos where did = ? and name = ? and knot = ?));`, collaborator, repoOwnerDid, repoName, repoKnot) - if err != nil { - span.RecordError(err) - } return err } -func UpdateDescription(ctx context.Context, e Execer, repoAt, newDescription string) error { - ctx, span := otel.Tracer("db").Start(ctx, "UpdateDescription") - defer span.End() - span.SetAttributes( - attribute.String("repoAt", repoAt), - attribute.String("description", newDescription), - ) - +func UpdateDescription(e Execer, repoAt, newDescription string) error { _, err := e.Exec( `update repos set description = ? where at_uri = ?`, newDescription, repoAt) - if err != nil { - span.RecordError(err) - } return err } -func CollaboratingIn(ctx context.Context, e Execer, collaborator string) ([]Repo, error) { - ctx, span := otel.Tracer("db").Start(ctx, "CollaboratingIn") - defer span.End() - span.SetAttributes(attribute.String("collaborator", collaborator)) - +func CollaboratingIn(e Execer, collaborator string) ([]Repo, error) { var repos []Repo rows, err := e.Query( @@ -408,7 +310,6 @@ c.did = ? group by r.id;`, collaborator) if err != nil { - span.RecordError(err) return nil, err } defer rows.Close() @@ -421,7 +322,6 @@ var nullableDescription sql.NullString err := rows.Scan(&repo.Did, &repo.Name, &repo.Knot, &repo.Rkey, &nullableDescription, &createdAt, &repoStats.StarCount) if err != nil { - span.RecordError(err) return nil, err } @@ -444,11 +344,9 @@ repos = append(repos, repo) } if err := rows.Err(); err != nil { - span.RecordError(err) return nil, err } - span.SetAttributes(attribute.Int("repos.count", len(repos))) return repos, nil } diff --git a/appview/db/star.go b/appview/db/star.go --- a/appview/db/star.go +++ b/appview/db/star.go @@ -1,7 +1,6 @@ package db import ( - "context" "log" "time" @@ -18,12 +17,12 @@ // optionally, populate this when querying for reverse mappings Repo *Repo } -func (star *Star) ResolveRepo(ctx context.Context, e Execer) error { +func (star *Star) ResolveRepo(e Execer) error { if star.Repo != nil { return nil } - repo, err := GetRepoByAtUri(ctx, e, star.RepoAt.String()) + repo, err := GetRepoByAtUri(e, star.RepoAt.String()) if err != nil { return err } @@ -41,7 +40,7 @@ // Get a star record func GetStar(e Execer, starredByDid string, repoAt syntax.ATURI) (*Star, error) { query := ` - select starred_by_did, repo_at, created, rkey + select starred_by_did, repo_at, created, rkey from stars where starred_by_did = ? and repo_at = ?` row := e.QueryRow(query, starredByDid, repoAt) @@ -98,7 +97,7 @@ func GetAllStars(e Execer, limit int) ([]Star, error) { var stars []Star rows, err := e.Query(` - select + select s.starred_by_did, s.repo_at, s.rkey, diff --git a/appview/db/timeline.go b/appview/db/timeline.go --- a/appview/db/timeline.go +++ b/appview/db/timeline.go @@ -1,12 +1,8 @@ package db import ( - "context" "sort" "time" - - "go.opentelemetry.io/otel/attribute" - "go.opentelemetry.io/otel/trace" ) type TimelineEvent struct { @@ -22,49 +18,30 @@ } // TODO: this gathers heterogenous events from different sources and aggregates // them in code; if we did this entirely in sql, we could order and limit and paginate easily -func MakeTimeline(ctx context.Context, e Execer) ([]TimelineEvent, error) { - span := trace.SpanFromContext(ctx) - defer span.End() - +func MakeTimeline(e Execer) ([]TimelineEvent, error) { var events []TimelineEvent limit := 50 - span.SetAttributes(attribute.Int("timeline.limit", limit)) - - repos, err := GetAllRepos(ctx, e, limit) + repos, err := GetAllRepos(e, limit) if err != nil { - span.RecordError(err) - span.SetAttributes(attribute.String("error.from", "GetAllRepos")) return nil, err } - span.SetAttributes(attribute.Int("timeline.repos.count", len(repos))) follows, err := GetAllFollows(e, limit) if err != nil { - span.RecordError(err) - span.SetAttributes(attribute.String("error.from", "GetAllFollows")) return nil, err } - span.SetAttributes(attribute.Int("timeline.follows.count", len(follows))) stars, err := GetAllStars(e, limit) if err != nil { - span.RecordError(err) - span.SetAttributes(attribute.String("error.from", "GetAllStars")) return nil, err } - span.SetAttributes(attribute.Int("timeline.stars.count", len(stars))) for _, repo := range repos { var sourceRepo *Repo if repo.Source != "" { - sourceRepo, err = GetRepoByAtUri(ctx, e, repo.Source) + sourceRepo, err = GetRepoByAtUri(e, repo.Source) if err != nil { - span.RecordError(err) - span.SetAttributes( - attribute.String("error.from", "GetRepoByAtUri"), - attribute.String("repo.source", repo.Source), - ) return nil, err } } @@ -98,8 +75,6 @@ // Limit the slice to 100 events if len(events) > limit { events = events[:limit] } - - span.SetAttributes(attribute.Int("timeline.events.total", len(events))) return events, nil } diff --git a/appview/state/artifact.go b/appview/state/artifact.go --- a/appview/state/artifact.go +++ b/appview/state/artifact.go @@ -118,7 +118,7 @@ } s.pages.RepoArtifactFragment(w, pages.RepoArtifactParams{ LoggedInUser: user, - RepoInfo: f.RepoInfo(r.Context(), s, user), + RepoInfo: f.RepoInfo(s, user), Artifact: artifact, }) } diff --git a/appview/state/middleware.go b/appview/state/middleware.go --- a/appview/state/middleware.go +++ b/appview/state/middleware.go @@ -12,7 +12,6 @@ "slices" "github.com/bluesky-social/indigo/atproto/identity" "github.com/go-chi/chi/v5" - "go.opentelemetry.io/otel/attribute" "tangled.sh/tangled.sh/core/appview/db" "tangled.sh/tangled.sh/core/appview/middleware" ) @@ -20,11 +19,8 @@ func knotRoleMiddleware(s *State, group string) middleware.Middleware { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - ctx, span := s.t.TraceStart(r.Context(), "knotRoleMiddleware") - defer span.End() - // requires auth also - actor := s.auth.GetUser(r.WithContext(ctx)) + actor := s.auth.GetUser(r) if actor == nil { // we need a logged in user log.Printf("not logged in, redirecting") @@ -45,7 +41,7 @@ http.Error(w, "Forbiden", http.StatusUnauthorized) return } - next.ServeHTTP(w, r.WithContext(ctx)) + next.ServeHTTP(w, r) }) } } @@ -57,18 +53,15 @@ func RepoPermissionMiddleware(s *State, requiredPerm string) middleware.Middleware { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - ctx, span := s.t.TraceStart(r.Context(), "RepoPermissionMiddleware") - defer span.End() - // requires auth also - actor := s.auth.GetUser(r.WithContext(ctx)) + actor := s.auth.GetUser(r) if actor == nil { // we need a logged in user log.Printf("not logged in, redirecting") http.Error(w, "Forbiden", http.StatusUnauthorized) return } - f, err := s.fullyResolvedRepo(r.WithContext(ctx)) + f, err := s.fullyResolvedRepo(r) if err != nil { http.Error(w, "malformed url", http.StatusBadRequest) return @@ -82,7 +75,7 @@ http.Error(w, "Forbiden", http.StatusUnauthorized) return } - next.ServeHTTP(w, r.WithContext(ctx)) + next.ServeHTTP(w, r) }) } } @@ -108,10 +101,7 @@ next.ServeHTTP(w, req) return } - ctx, span := s.t.TraceStart(req.Context(), "ResolveIdent") - defer span.End() - - id, err := s.resolver.ResolveIdent(ctx, didOrHandle) + id, err := s.resolver.ResolveIdent(req.Context(), didOrHandle) if err != nil { // invalid did or handle log.Println("failed to resolve did/handle:", err) @@ -119,7 +109,7 @@ w.WriteHeader(http.StatusNotFound) return } - ctx = context.WithValue(ctx, "resolvedId", *id) + ctx := context.WithValue(req.Context(), "resolvedId", *id) next.ServeHTTP(w, req.WithContext(ctx)) }) @@ -129,18 +119,15 @@ func ResolveRepo(s *State) middleware.Middleware { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { - ctx, span := s.t.TraceStart(req.Context(), "ResolveRepo") - defer span.End() - repoName := chi.URLParam(req, "repo") - id, ok := ctx.Value("resolvedId").(identity.Identity) + id, ok := req.Context().Value("resolvedId").(identity.Identity) if !ok { log.Println("malformed middleware") w.WriteHeader(http.StatusInternalServerError) return } - repo, err := db.GetRepo(ctx, s.db, id.DID.String(), repoName) + repo, err := db.GetRepo(s.db, id.DID.String(), repoName) if err != nil { // invalid did or handle log.Println("failed to resolve repo") @@ -148,7 +135,7 @@ w.WriteHeader(http.StatusNotFound) return } - ctx = context.WithValue(ctx, "knot", repo.Knot) + ctx := context.WithValue(req.Context(), "knot", repo.Knot) ctx = context.WithValue(ctx, "repoAt", repo.AtUri) ctx = context.WithValue(ctx, "repoDescription", repo.Description) ctx = context.WithValue(ctx, "repoAddedAt", repo.Created.Format(time.RFC3339)) @@ -161,10 +148,7 @@ // middleware that is tacked on top of /{user}/{repo}/pulls/{pull} func ResolvePull(s *State) middleware.Middleware { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - ctx, span := s.t.TraceStart(r.Context(), "ResolvePull") - defer span.End() - - f, err := s.fullyResolvedRepo(r.WithContext(ctx)) + f, err := s.fullyResolvedRepo(r) if err != nil { log.Println("failed to fully resolve repo", err) http.Error(w, "invalid repo url", http.StatusNotFound) @@ -179,15 +163,13 @@ log.Println("failed to parse pr id", err) return } - pr, err := db.GetPull(ctx, s.db, f.RepoAt, prIdInt) + pr, err := db.GetPull(s.db, f.RepoAt, prIdInt) if err != nil { log.Println("failed to get pull and comments", err) return } - span.SetAttributes(attribute.Int("pull.id", prIdInt)) - - ctx = context.WithValue(ctx, "pull", pr) + ctx := context.WithValue(r.Context(), "pull", pr) next.ServeHTTP(w, r.WithContext(ctx)) }) diff --git a/appview/state/profile.go b/appview/state/profile.go --- a/appview/state/profile.go +++ b/appview/state/profile.go @@ -10,54 +10,36 @@ "net/http" "github.com/bluesky-social/indigo/atproto/identity" "github.com/go-chi/chi/v5" - "go.opentelemetry.io/otel/attribute" "tangled.sh/tangled.sh/core/appview/db" "tangled.sh/tangled.sh/core/appview/pages" ) func (s *State) ProfilePage(w http.ResponseWriter, r *http.Request) { - ctx, span := s.t.TraceStart(r.Context(), "ProfilePage") - defer span.End() - didOrHandle := chi.URLParam(r, "user") if didOrHandle == "" { http.Error(w, "Bad request", http.StatusBadRequest) return } - ident, ok := ctx.Value("resolvedId").(identity.Identity) + ident, ok := r.Context().Value("resolvedId").(identity.Identity) if !ok { s.pages.Error404(w) - span.RecordError(fmt.Errorf("failed to resolve identity")) return } - span.SetAttributes( - attribute.String("user.did", ident.DID.String()), - attribute.String("user.handle", ident.Handle.String()), - ) - - repos, err := db.GetAllReposByDid(ctx, s.db, ident.DID.String()) + repos, err := db.GetAllReposByDid(s.db, ident.DID.String()) if err != nil { log.Printf("getting repos for %s: %s", ident.DID.String(), err) - span.RecordError(err) - span.SetAttributes(attribute.String("error.repos", err.Error())) } - span.SetAttributes(attribute.Int("repos.count", len(repos))) - collaboratingRepos, err := db.CollaboratingIn(ctx, s.db, ident.DID.String()) + collaboratingRepos, err := db.CollaboratingIn(s.db, ident.DID.String()) if err != nil { log.Printf("getting collaborating repos for %s: %s", ident.DID.String(), err) - span.RecordError(err) - span.SetAttributes(attribute.String("error.collaborating_repos", err.Error())) } - span.SetAttributes(attribute.Int("collaborating_repos.count", len(collaboratingRepos))) - timeline, err := db.MakeProfileTimeline(ctx, s.db, ident.DID.String()) + timeline, err := db.MakeProfileTimeline(s.db, ident.DID.String()) if err != nil { log.Printf("failed to create profile timeline for %s: %s", ident.DID.String(), err) - span.RecordError(err) - span.SetAttributes(attribute.String("error.timeline", err.Error())) } var didsToResolve []string @@ -78,9 +60,8 @@ didsToResolve = append(didsToResolve, re.Source.Did) } } } - span.SetAttributes(attribute.Int("dids_to_resolve.count", len(didsToResolve))) - resolvedIds := s.resolver.ResolveIdents(ctx, didsToResolve) + resolvedIds := s.resolver.ResolveIdents(r.Context(), didsToResolve) didHandleMap := make(map[string]string) for _, identity := range resolvedIds { if !identity.Handle.IsInvalidHandle() { @@ -89,26 +70,17 @@ } else { didHandleMap[identity.DID.String()] = identity.DID.String() } } - span.SetAttributes(attribute.Int("resolved_ids.count", len(resolvedIds))) followers, following, err := db.GetFollowerFollowing(s.db, ident.DID.String()) if err != nil { log.Printf("getting follow stats repos for %s: %s", ident.DID.String(), err) - span.RecordError(err) - span.SetAttributes(attribute.String("error.follow_stats", err.Error())) } - span.SetAttributes( - attribute.Int("followers.count", followers), - attribute.Int("following.count", following), - ) loggedInUser := s.auth.GetUser(r) followStatus := db.IsNotFollowing if loggedInUser != nil { followStatus = db.GetFollowStatus(s.db, loggedInUser.Did, ident.DID.String()) - span.SetAttributes(attribute.String("logged_in_user.did", loggedInUser.Did)) } - span.SetAttributes(attribute.String("follow_status", string(db.FollowStatus(followStatus)))) profileAvatarUri := s.GetAvatarUri(ident.Handle.String()) s.pages.ProfilePage(w, pages.ProfilePageParams{ diff --git a/appview/state/pull.go b/appview/state/pull.go --- a/appview/state/pull.go +++ b/appview/state/pull.go @@ -1,7 +1,6 @@ package state import ( - "context" "database/sql" "encoding/json" "errors" @@ -12,14 +11,12 @@ "net/http" "strconv" "time" - "go.opentelemetry.io/otel/attribute" "tangled.sh/tangled.sh/core/api/tangled" "tangled.sh/tangled.sh/core/appview" "tangled.sh/tangled.sh/core/appview/auth" "tangled.sh/tangled.sh/core/appview/db" "tangled.sh/tangled.sh/core/appview/pages" "tangled.sh/tangled.sh/core/patchutil" - "tangled.sh/tangled.sh/core/telemetry" "tangled.sh/tangled.sh/core/types" comatproto "github.com/bluesky-social/indigo/api/atproto" @@ -30,19 +27,16 @@ ) // htmx fragment func (s *State) PullActions(w http.ResponseWriter, r *http.Request) { - ctx, span := s.t.TraceStart(r.Context(), "PullActions") - defer span.End() - switch r.Method { case http.MethodGet: user := s.auth.GetUser(r) - f, err := s.fullyResolvedRepo(r.WithContext(ctx)) + f, err := s.fullyResolvedRepo(r) if err != nil { log.Println("failed to get repo and knot", err) return } - pull, ok := ctx.Value("pull").(*db.Pull) + pull, ok := r.Context().Value("pull").(*db.Pull) if !ok { log.Println("failed to get pull") s.pages.Notice(w, "pull-error", "Failed to edit patch. Try again later.") @@ -60,59 +54,39 @@ log.Println("failed to parse round id", err) return } - _, mergeSpan := s.t.TraceStart(ctx, "mergeCheck") - mergeCheckResponse := s.mergeCheck(ctx, f, pull) - mergeSpan.End() - + mergeCheckResponse := s.mergeCheck(f, pull) resubmitResult := pages.Unknown if user.Did == pull.OwnerDid { - _, resubmitSpan := s.t.TraceStart(ctx, "resubmitCheck") - resubmitResult = s.resubmitCheck(ctx, f, pull) - resubmitSpan.End() + resubmitResult = s.resubmitCheck(f, pull) } - _, renderSpan := s.t.TraceStart(ctx, "renderPullActions") s.pages.PullActionsFragment(w, pages.PullActionsParams{ LoggedInUser: user, - RepoInfo: f.RepoInfo(ctx, s, user), + RepoInfo: f.RepoInfo(s, user), Pull: pull, RoundNumber: roundNumber, MergeCheck: mergeCheckResponse, ResubmitCheck: resubmitResult, }) - renderSpan.End() return } } func (s *State) RepoSinglePull(w http.ResponseWriter, r *http.Request) { - ctx, span := s.t.TraceStart(r.Context(), "RepoSinglePull") - defer span.End() - user := s.auth.GetUser(r) - f, err := s.fullyResolvedRepo(r.WithContext(ctx)) + f, err := s.fullyResolvedRepo(r) if err != nil { log.Println("failed to get repo and knot", err) - span.RecordError(err) return } - pull, ok := ctx.Value("pull").(*db.Pull) + pull, ok := r.Context().Value("pull").(*db.Pull) if !ok { - err := errors.New("failed to get pull from context") - log.Println(err) - span.RecordError(err) + log.Println("failed to get pull") s.pages.Notice(w, "pull-error", "Failed to edit patch. Try again later.") return } - attrs := telemetry.MapAttrs[string](map[string]string{ - "pull.id": fmt.Sprintf("%d", pull.PullId), - "pull.owner": pull.OwnerDid, - }) - - span.SetAttributes(attrs...) - totalIdents := 1 for _, submission := range pull.Submissions { totalIdents += len(submission.Comments) @@ -130,7 +104,7 @@ idx += 1 } } - resolvedIds := s.resolver.ResolveIdents(ctx, identsToResolve) + resolvedIds := s.resolver.ResolveIdents(r.Context(), identsToResolve) didHandleMap := make(map[string]string) for _, identity := range resolvedIds { if !identity.Handle.IsInvalidHandle() { @@ -139,18 +113,16 @@ } else { didHandleMap[identity.DID.String()] = identity.DID.String() } } - span.SetAttributes(attribute.Int("identities.resolved", len(resolvedIds))) - mergeCheckResponse := s.mergeCheck(ctx, f, pull) - + mergeCheckResponse := s.mergeCheck(f, pull) resubmitResult := pages.Unknown if user != nil && user.Did == pull.OwnerDid { - resubmitResult = s.resubmitCheck(ctx, f, pull) + resubmitResult = s.resubmitCheck(f, pull) } s.pages.RepoSinglePull(w, pages.RepoSinglePullParams{ LoggedInUser: user, - RepoInfo: f.RepoInfo(ctx, s, user), + RepoInfo: f.RepoInfo(s, user), DidHandleMap: didHandleMap, Pull: pull, MergeCheck: mergeCheckResponse, @@ -158,7 +130,7 @@ ResubmitCheck: resubmitResult, }) } -func (s *State) mergeCheck(ctx context.Context, f *FullyResolvedRepo, pull *db.Pull) types.MergeCheckResponse { +func (s *State) mergeCheck(f *FullyResolvedRepo, pull *db.Pull) types.MergeCheckResponse { if pull.State == db.PullMerged { return types.MergeCheckResponse{} } @@ -218,14 +190,8 @@ return mergeCheckResponse } -func (s *State) resubmitCheck(ctx context.Context, f *FullyResolvedRepo, pull *db.Pull) pages.ResubmitResult { - ctx, span := s.t.TraceStart(ctx, "resubmitCheck") - defer span.End() - - span.SetAttributes(attribute.Int("pull.id", pull.PullId)) - +func (s *State) resubmitCheck(f *FullyResolvedRepo, pull *db.Pull) pages.ResubmitResult { if pull.State == db.PullMerged || pull.PullSource == nil { - span.SetAttributes(attribute.String("result", "Unknown")) return pages.Unknown } @@ -233,13 +199,9 @@ var knot, ownerDid, repoName string if pull.PullSource.RepoAt != nil { // fork-based pulls - span.SetAttributes(attribute.Bool("isForkBased", true)) - sourceRepo, err := db.GetRepoByAtUri(ctx, s.db, pull.PullSource.RepoAt.String()) + sourceRepo, err := db.GetRepoByAtUri(s.db, pull.PullSource.RepoAt.String()) if err != nil { log.Println("failed to get source repo", err) - span.RecordError(err) - span.SetAttributes(attribute.String("error", "failed_to_get_source_repo")) - span.SetAttributes(attribute.String("result", "Unknown")) return pages.Unknown } @@ -248,43 +210,26 @@ ownerDid = sourceRepo.Did repoName = sourceRepo.Name } else { // pulls within the same repo - span.SetAttributes(attribute.Bool("isBranchBased", true)) knot = f.Knot ownerDid = f.OwnerDid() repoName = f.RepoName } - span.SetAttributes( - attribute.String("knot", knot), - attribute.String("ownerDid", ownerDid), - attribute.String("repoName", repoName), - attribute.String("sourceBranch", pull.PullSource.Branch), - ) - us, err := NewUnsignedClient(knot, s.config.Dev) if err != nil { log.Printf("failed to setup client for %s; ignoring: %v", knot, err) - span.RecordError(err) - span.SetAttributes(attribute.String("error", "failed_to_setup_client")) - span.SetAttributes(attribute.String("result", "Unknown")) return pages.Unknown } resp, err := us.Branch(ownerDid, repoName, pull.PullSource.Branch) if err != nil { log.Println("failed to reach knotserver", err) - span.RecordError(err) - span.SetAttributes(attribute.String("error", "failed_to_reach_knotserver")) - span.SetAttributes(attribute.String("result", "Unknown")) return pages.Unknown } body, err := io.ReadAll(resp.Body) if err != nil { log.Printf("error reading response body: %v", err) - span.RecordError(err) - span.SetAttributes(attribute.String("error", "failed_to_read_response")) - span.SetAttributes(attribute.String("result", "Unknown")) return pages.Unknown } defer resp.Body.Close() @@ -292,46 +237,29 @@ var result types.RepoBranchResponse if err := json.Unmarshal(body, &result); err != nil { log.Println("failed to parse response:", err) - span.RecordError(err) - span.SetAttributes(attribute.String("error", "failed_to_parse_response")) - span.SetAttributes(attribute.String("result", "Unknown")) return pages.Unknown } latestSubmission := pull.Submissions[pull.LastRoundNumber()] - - span.SetAttributes( - attribute.String("latestSubmission.SourceRev", latestSubmission.SourceRev), - attribute.String("branch.Hash", result.Branch.Hash), - ) - if latestSubmission.SourceRev != result.Branch.Hash { fmt.Println(latestSubmission.SourceRev, result.Branch.Hash) - span.SetAttributes(attribute.String("result", "ShouldResubmit")) return pages.ShouldResubmit } - span.SetAttributes(attribute.String("result", "ShouldNotResubmit")) return pages.ShouldNotResubmit } func (s *State) RepoPullPatch(w http.ResponseWriter, r *http.Request) { - ctx, span := s.t.TraceStart(r.Context(), "RepoPullPatch") - defer span.End() - - user := s.auth.GetUser(r.WithContext(ctx)) - f, err := s.fullyResolvedRepo(r.WithContext(ctx)) + user := s.auth.GetUser(r) + f, err := s.fullyResolvedRepo(r) if err != nil { log.Println("failed to get repo and knot", err) - span.RecordError(err) return } - pull, ok := ctx.Value("pull").(*db.Pull) + pull, ok := r.Context().Value("pull").(*db.Pull) if !ok { - err := errors.New("failed to get pull from context") - log.Println(err) - span.RecordError(err) + log.Println("failed to get pull") s.pages.Notice(w, "pull-error", "Failed to edit patch. Try again later.") return } @@ -341,19 +269,11 @@ roundIdInt, err := strconv.Atoi(roundId) if err != nil || roundIdInt >= len(pull.Submissions) { http.Error(w, "bad round id", http.StatusBadRequest) log.Println("failed to parse round id", err) - span.RecordError(err) - span.SetAttributes(attribute.String("error", "bad_round_id")) return } - span.SetAttributes( - attribute.Int("pull.id", pull.PullId), - attribute.Int("round", roundIdInt), - attribute.String("pull.owner", pull.OwnerDid), - ) - identsToResolve := []string{pull.OwnerDid} - resolvedIds := s.resolver.ResolveIdents(ctx, identsToResolve) + resolvedIds := s.resolver.ResolveIdents(r.Context(), identsToResolve) didHandleMap := make(map[string]string) for _, identity := range resolvedIds { if !identity.Handle.IsInvalidHandle() { @@ -362,61 +282,53 @@ } else { didHandleMap[identity.DID.String()] = identity.DID.String() } } - span.SetAttributes(attribute.Int("identities.resolved", len(resolvedIds))) diff := pull.Submissions[roundIdInt].AsNiceDiff(pull.TargetBranch) s.pages.RepoPullPatchPage(w, pages.RepoPullPatchParams{ LoggedInUser: user, DidHandleMap: didHandleMap, - RepoInfo: f.RepoInfo(ctx, s, user), + RepoInfo: f.RepoInfo(s, user), Pull: pull, Round: roundIdInt, Submission: pull.Submissions[roundIdInt], Diff: &diff, }) + } func (s *State) RepoPullInterdiff(w http.ResponseWriter, r *http.Request) { - ctx, span := s.t.TraceStart(r.Context(), "RepoPullInterdiff") - defer span.End() - user := s.auth.GetUser(r) - f, err := s.fullyResolvedRepo(r.WithContext(ctx)) + f, err := s.fullyResolvedRepo(r) if err != nil { log.Println("failed to get repo and knot", err) return } - pull, ok := ctx.Value("pull").(*db.Pull) + pull, ok := r.Context().Value("pull").(*db.Pull) if !ok { log.Println("failed to get pull") s.pages.Notice(w, "pull-error", "Failed to get pull.") return } - _, roundSpan := s.t.TraceStart(ctx, "parseRound") roundId := chi.URLParam(r, "round") roundIdInt, err := strconv.Atoi(roundId) if err != nil || roundIdInt >= len(pull.Submissions) { http.Error(w, "bad round id", http.StatusBadRequest) log.Println("failed to parse round id", err) - roundSpan.End() return } if roundIdInt == 0 { http.Error(w, "bad round id", http.StatusBadRequest) log.Println("cannot interdiff initial submission") - roundSpan.End() return } - roundSpan.End() - _, identSpan := s.t.TraceStart(ctx, "resolveIdentities") identsToResolve := []string{pull.OwnerDid} - resolvedIds := s.resolver.ResolveIdents(ctx, identsToResolve) + resolvedIds := s.resolver.ResolveIdents(r.Context(), identsToResolve) didHandleMap := make(map[string]string) for _, identity := range resolvedIds { if !identity.Handle.IsInvalidHandle() { @@ -425,14 +337,11 @@ } else { didHandleMap[identity.DID.String()] = identity.DID.String() } } - identSpan.End() - _, diffSpan := s.t.TraceStart(ctx, "calculateInterdiff") currentPatch, err := pull.Submissions[roundIdInt].AsDiff(pull.TargetBranch) if err != nil { log.Println("failed to interdiff; current patch malformed") s.pages.Notice(w, fmt.Sprintf("interdiff-error-%d", roundIdInt), "Failed to calculate interdiff; current patch is invalid.") - diffSpan.End() return } @@ -440,51 +349,40 @@ previousPatch, err := pull.Submissions[roundIdInt-1].AsDiff(pull.TargetBranch) if err != nil { log.Println("failed to interdiff; previous patch malformed") s.pages.Notice(w, fmt.Sprintf("interdiff-error-%d", roundIdInt), "Failed to calculate interdiff; previous patch is invalid.") - diffSpan.End() return } interdiff := patchutil.Interdiff(previousPatch, currentPatch) - diffSpan.End() - _, renderSpan := s.t.TraceStart(ctx, "renderInterdiffPage") s.pages.RepoPullInterdiffPage(w, pages.RepoPullInterdiffParams{ - LoggedInUser: s.auth.GetUser(r.WithContext(ctx)), - RepoInfo: f.RepoInfo(ctx, s, user), + LoggedInUser: s.auth.GetUser(r), + RepoInfo: f.RepoInfo(s, user), Pull: pull, Round: roundIdInt, DidHandleMap: didHandleMap, Interdiff: interdiff, }) - renderSpan.End() return } func (s *State) RepoPullPatchRaw(w http.ResponseWriter, r *http.Request) { - ctx, span := s.t.TraceStart(r.Context(), "RepoPullPatchRaw") - defer span.End() - - pull, ok := ctx.Value("pull").(*db.Pull) + pull, ok := r.Context().Value("pull").(*db.Pull) if !ok { log.Println("failed to get pull") s.pages.Notice(w, "pull-error", "Failed to edit patch. Try again later.") return } - _, roundSpan := s.t.TraceStart(ctx, "parseRound") roundId := chi.URLParam(r, "round") roundIdInt, err := strconv.Atoi(roundId) if err != nil || roundIdInt >= len(pull.Submissions) { http.Error(w, "bad round id", http.StatusBadRequest) log.Println("failed to parse round id", err) - roundSpan.End() return } - roundSpan.End() - _, identSpan := s.t.TraceStart(ctx, "resolveIdentities") identsToResolve := []string{pull.OwnerDid} - resolvedIds := s.resolver.ResolveIdents(ctx, identsToResolve) + resolvedIds := s.resolver.ResolveIdents(r.Context(), identsToResolve) didHandleMap := make(map[string]string) for _, identity := range resolvedIds { if !identity.Handle.IsInvalidHandle() { @@ -493,22 +391,15 @@ } else { didHandleMap[identity.DID.String()] = identity.DID.String() } } - identSpan.End() - _, writeSpan := s.t.TraceStart(ctx, "writePatch") w.Header().Set("Content-Type", "text/plain") w.Write([]byte(pull.Submissions[roundIdInt].Patch)) - writeSpan.End() } func (s *State) RepoPulls(w http.ResponseWriter, r *http.Request) { - ctx, span := s.t.TraceStart(r.Context(), "RepoPulls") - defer span.End() - user := s.auth.GetUser(r) params := r.URL.Query() - _, stateSpan := s.t.TraceStart(ctx, "determinePullState") state := db.PullOpen switch params.Get("state") { case "closed": @@ -516,33 +407,25 @@ state = db.PullClosed case "merged": state = db.PullMerged } - stateSpan.End() - _, repoSpan := s.t.TraceStart(ctx, "resolveRepo") - f, err := s.fullyResolvedRepo(r.WithContext(ctx)) + f, err := s.fullyResolvedRepo(r) if err != nil { log.Println("failed to get repo and knot", err) - repoSpan.End() return } - repoSpan.End() - _, pullsSpan := s.t.TraceStart(ctx, "getPulls") - pulls, err := db.GetPulls(ctx, s.db, f.RepoAt, state) + pulls, err := db.GetPulls(s.db, f.RepoAt, state) if err != nil { log.Println("failed to get pulls", err) s.pages.Notice(w, "pulls", "Failed to load pulls. Try again later.") - pullsSpan.End() return } - pullsSpan.End() - _, sourceRepoSpan := s.t.TraceStart(ctx, "resolvePullSources") for _, p := range pulls { var pullSourceRepo *db.Repo if p.PullSource != nil { if p.PullSource.RepoAt != nil { - pullSourceRepo, err = db.GetRepoByAtUri(ctx, s.db, p.PullSource.RepoAt.String()) + pullSourceRepo, err = db.GetRepoByAtUri(s.db, p.PullSource.RepoAt.String()) if err != nil { log.Printf("failed to get repo by at uri: %v", err) continue @@ -552,14 +435,12 @@ } } } } - sourceRepoSpan.End() - _, identSpan := s.t.TraceStart(ctx, "resolveIdentities") identsToResolve := make([]string, len(pulls)) for i, pull := range pulls { identsToResolve[i] = pull.OwnerDid } - resolvedIds := s.resolver.ResolveIdents(ctx, identsToResolve) + resolvedIds := s.resolver.ResolveIdents(r.Context(), identsToResolve) didHandleMap := make(map[string]string) for _, identity := range resolvedIds { if !identity.Handle.IsInvalidHandle() { @@ -568,102 +449,78 @@ } else { didHandleMap[identity.DID.String()] = identity.DID.String() } } - identSpan.End() - _, renderSpan := s.t.TraceStart(ctx, "renderPullsPage") s.pages.RepoPulls(w, pages.RepoPullsParams{ - LoggedInUser: s.auth.GetUser(r.WithContext(ctx)), - RepoInfo: f.RepoInfo(ctx, s, user), + LoggedInUser: s.auth.GetUser(r), + RepoInfo: f.RepoInfo(s, user), Pulls: pulls, DidHandleMap: didHandleMap, FilteringBy: state, }) - renderSpan.End() return } func (s *State) PullComment(w http.ResponseWriter, r *http.Request) { - ctx, span := s.t.TraceStart(r.Context(), "PullComment") - defer span.End() - - user := s.auth.GetUser(r.WithContext(ctx)) - f, err := s.fullyResolvedRepo(r.WithContext(ctx)) + user := s.auth.GetUser(r) + f, err := s.fullyResolvedRepo(r) if err != nil { log.Println("failed to get repo and knot", err) return } - pull, ok := ctx.Value("pull").(*db.Pull) + pull, ok := r.Context().Value("pull").(*db.Pull) if !ok { log.Println("failed to get pull") s.pages.Notice(w, "pull-error", "Failed to edit patch. Try again later.") return } - _, roundSpan := s.t.TraceStart(ctx, "parseRoundNumber") roundNumberStr := chi.URLParam(r, "round") roundNumber, err := strconv.Atoi(roundNumberStr) if err != nil || roundNumber >= len(pull.Submissions) { http.Error(w, "bad round id", http.StatusBadRequest) log.Println("failed to parse round id", err) - roundSpan.End() return } - roundSpan.End() switch r.Method { case http.MethodGet: - _, renderSpan := s.t.TraceStart(ctx, "renderCommentFragment") s.pages.PullNewCommentFragment(w, pages.PullNewCommentParams{ LoggedInUser: user, - RepoInfo: f.RepoInfo(ctx, s, user), + RepoInfo: f.RepoInfo(s, user), Pull: pull, RoundNumber: roundNumber, }) - renderSpan.End() return case http.MethodPost: - postCtx, postSpan := s.t.TraceStart(ctx, "CreateComment") - defer postSpan.End() - - _, validateSpan := s.t.TraceStart(postCtx, "validateComment") body := r.FormValue("body") if body == "" { s.pages.Notice(w, "pull", "Comment body is required") - validateSpan.End() return } - validateSpan.End() // Start a transaction - _, txSpan := s.t.TraceStart(postCtx, "startTransaction") - tx, err := s.db.BeginTx(postCtx, nil) + tx, err := s.db.BeginTx(r.Context(), nil) if err != nil { log.Println("failed to start transaction", err) s.pages.Notice(w, "pull-comment", "Failed to create comment.") - txSpan.End() return } defer tx.Rollback() - txSpan.End() createdAt := time.Now().Format(time.RFC3339) ownerDid := user.Did - _, pullAtSpan := s.t.TraceStart(postCtx, "getPullAt") - pullAt, err := db.GetPullAt(postCtx, s.db, f.RepoAt, pull.PullId) + pullAt, err := db.GetPullAt(s.db, f.RepoAt, pull.PullId) if err != nil { log.Println("failed to get pull at", err) s.pages.Notice(w, "pull-comment", "Failed to create comment.") - pullAtSpan.End() return } - pullAtSpan.End() - _, atProtoSpan := s.t.TraceStart(postCtx, "createAtProtoRecord") atUri := f.RepoAt.String() - client, _ := s.auth.AuthorizedClient(r.WithContext(postCtx)) - atResp, err := comatproto.RepoPutRecord(postCtx, client, &comatproto.RepoPutRecord_Input{ + client, _ := s.auth.AuthorizedClient(r) + atResp, err := comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{ Collection: tangled.RepoPullCommentNSID, Repo: user.Did, Rkey: appview.TID(), @@ -680,14 +537,11 @@ }) if err != nil { log.Println("failed to create pull comment", err) s.pages.Notice(w, "pull-comment", "Failed to create comment.") - atProtoSpan.End() return } - atProtoSpan.End() // Create the pull comment in the database with the commentAt field - _, dbSpan := s.t.TraceStart(postCtx, "createDbComment") - commentId, err := db.NewPullComment(postCtx, tx, &db.PullComment{ + commentId, err := db.NewPullComment(tx, &db.PullComment{ OwnerDid: user.Did, RepoAt: f.RepoAt.String(), PullId: pull.PullId, @@ -698,11 +552,10 @@ }) if err != nil { log.Println("failed to create pull comment", err) s.pages.Notice(w, "pull-comment", "Failed to create comment.") - dbSpan.End() return } - dbSpan.End() + // Commit the transaction if err = tx.Commit(); err != nil { log.Println("failed to commit transaction", err) s.pages.Notice(w, "pull-comment", "Failed to create comment.") @@ -715,25 +568,18 @@ } } func (s *State) NewPull(w http.ResponseWriter, r *http.Request) { - ctx, span := s.t.TraceStart(r.Context(), "NewPull") - defer span.End() - - user := s.auth.GetUser(r.WithContext(ctx)) - f, err := s.fullyResolvedRepo(r.WithContext(ctx)) + user := s.auth.GetUser(r) + f, err := s.fullyResolvedRepo(r) if err != nil { log.Println("failed to get repo and knot", err) - span.RecordError(err) return } switch r.Method { case http.MethodGet: - span.SetAttributes(attribute.String("method", "GET")) - us, err := NewUnsignedClient(f.Knot, s.config.Dev) if err != nil { log.Printf("failed to create unsigned client for %s", f.Knot) - span.RecordError(err) s.pages.Error503(w) return } @@ -741,14 +587,12 @@ resp, err := us.Branches(f.OwnerDid(), f.RepoName) if err != nil { log.Println("failed to reach knotserver", err) - span.RecordError(err) return } body, err := io.ReadAll(resp.Body) if err != nil { log.Printf("Error reading response body: %v", err) - span.RecordError(err) return } @@ -756,55 +600,36 @@ var result types.RepoBranchesResponse err = json.Unmarshal(body, &result) if err != nil { log.Println("failed to parse response:", err) - span.RecordError(err) return } s.pages.RepoNewPull(w, pages.RepoNewPullParams{ LoggedInUser: user, - RepoInfo: f.RepoInfo(ctx, s, user), + RepoInfo: f.RepoInfo(s, user), Branches: result.Branches, }) case http.MethodPost: - span.SetAttributes(attribute.String("method", "POST")) - title := r.FormValue("title") body := r.FormValue("body") targetBranch := r.FormValue("targetBranch") fromFork := r.FormValue("fork") sourceBranch := r.FormValue("sourceBranch") patch := r.FormValue("patch") - - span.SetAttributes( - attribute.String("targetBranch", targetBranch), - attribute.String("sourceBranch", sourceBranch), - attribute.Bool("hasFork", fromFork != ""), - attribute.Bool("hasPatch", patch != ""), - ) if targetBranch == "" { s.pages.Notice(w, "pull", "Target branch is required.") - span.SetAttributes(attribute.String("error", "missing_target_branch")) return } // Determine PR type based on input parameters - isPushAllowed := f.RepoInfo(ctx, s, user).Roles.IsPushAllowed() + isPushAllowed := f.RepoInfo(s, user).Roles.IsPushAllowed() isBranchBased := isPushAllowed && sourceBranch != "" && fromFork == "" isForkBased := fromFork != "" && sourceBranch != "" isPatchBased := patch != "" && !isBranchBased && !isForkBased - span.SetAttributes( - attribute.Bool("isPushAllowed", isPushAllowed), - attribute.Bool("isBranchBased", isBranchBased), - attribute.Bool("isForkBased", isForkBased), - attribute.Bool("isPatchBased", isPatchBased), - ) - if isPatchBased && !patchutil.IsFormatPatch(patch) { if title == "" { s.pages.Notice(w, "pull", "Title is required for git-diff patches.") - span.SetAttributes(attribute.String("error", "missing_title_for_git_diff")) return } } @@ -812,21 +637,18 @@ // Validate we have at least one valid PR creation method if !isBranchBased && !isPatchBased && !isForkBased { s.pages.Notice(w, "pull", "Neither source branch nor patch supplied.") - span.SetAttributes(attribute.String("error", "no_valid_pr_method")) return } // Can't mix branch-based and patch-based approaches if isBranchBased && patch != "" { s.pages.Notice(w, "pull", "Cannot select both patch and source branch.") - span.SetAttributes(attribute.String("error", "mixed_pr_methods")) return } us, err := NewUnsignedClient(f.Knot, s.config.Dev) if err != nil { log.Printf("failed to create unsigned client to %s: %v", f.Knot, err) - span.RecordError(err) s.pages.Notice(w, "pull", "Failed to create a pull request. Try again later.") return } @@ -834,21 +656,12 @@ caps, err := us.Capabilities() if err != nil { log.Println("error fetching knot caps", f.Knot, err) - span.RecordError(err) s.pages.Notice(w, "pull", "Failed to create a pull request. Try again later.") return } - span.SetAttributes( - attribute.Bool("caps.pullRequests.formatPatch", caps.PullRequests.FormatPatch), - attribute.Bool("caps.pullRequests.branchSubmissions", caps.PullRequests.BranchSubmissions), - attribute.Bool("caps.pullRequests.forkSubmissions", caps.PullRequests.ForkSubmissions), - attribute.Bool("caps.pullRequests.patchSubmissions", caps.PullRequests.PatchSubmissions), - ) - if !caps.PullRequests.FormatPatch { s.pages.Notice(w, "pull", "This knot doesn't support format-patch. Unfortunately, there is no fallback for now.") - span.SetAttributes(attribute.String("error", "formatpatch_not_supported")) return } @@ -856,38 +669,27 @@ // Handle the PR creation based on the type if isBranchBased { if !caps.PullRequests.BranchSubmissions { s.pages.Notice(w, "pull", "This knot doesn't support branch-based pull requests. Try another way?") - span.SetAttributes(attribute.String("error", "branch_submissions_not_supported")) return } - s.handleBranchBasedPull(w, r.WithContext(ctx), f, user, title, body, targetBranch, sourceBranch) + s.handleBranchBasedPull(w, r, f, user, title, body, targetBranch, sourceBranch) } else if isForkBased { if !caps.PullRequests.ForkSubmissions { s.pages.Notice(w, "pull", "This knot doesn't support fork-based pull requests. Try another way?") - span.SetAttributes(attribute.String("error", "fork_submissions_not_supported")) return } - s.handleForkBasedPull(w, r.WithContext(ctx), f, user, fromFork, title, body, targetBranch, sourceBranch) + s.handleForkBasedPull(w, r, f, user, fromFork, title, body, targetBranch, sourceBranch) } else if isPatchBased { if !caps.PullRequests.PatchSubmissions { s.pages.Notice(w, "pull", "This knot doesn't support patch-based pull requests. Send your patch over email.") - span.SetAttributes(attribute.String("error", "patch_submissions_not_supported")) return } - s.handlePatchBasedPull(w, r.WithContext(ctx), f, user, title, body, targetBranch, patch) + s.handlePatchBasedPull(w, r, f, user, title, body, targetBranch, patch) } return } } func (s *State) handleBranchBasedPull(w http.ResponseWriter, r *http.Request, f *FullyResolvedRepo, user *auth.User, title, body, targetBranch, sourceBranch string) { - ctx, span := s.t.TraceStart(r.Context(), "handleBranchBasedPull") - defer span.End() - - span.SetAttributes( - attribute.String("targetBranch", targetBranch), - attribute.String("sourceBranch", sourceBranch), - ) - pullSource := &db.PullSource{ Branch: sourceBranch, } @@ -899,8 +701,6 @@ // Generate a patch using /compare ksClient, err := NewUnsignedClient(f.Knot, s.config.Dev) if err != nil { log.Printf("failed to create signed client for %s: %s", f.Knot, err) - span.RecordError(err) - span.SetAttributes(attribute.String("error", "client_creation_failed")) s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.") return } @@ -908,8 +708,6 @@ comparison, err := ksClient.Compare(f.OwnerDid(), f.RepoName, targetBranch, sourceBranch) if err != nil { log.Println("failed to compare", err) - span.RecordError(err) - span.SetAttributes(attribute.String("error", "comparison_failed")) s.pages.Notice(w, "pull", err.Error()) return } @@ -917,51 +715,30 @@ sourceRev := comparison.Rev2 patch := comparison.Patch - span.SetAttributes(attribute.String("sourceRev", sourceRev)) - if !patchutil.IsPatchValid(patch) { - span.SetAttributes(attribute.String("error", "invalid_patch_format")) s.pages.Notice(w, "pull", "Invalid patch format. Please provide a valid diff.") return } - s.createPullRequest(w, r.WithContext(ctx), f, user, title, body, targetBranch, patch, sourceRev, pullSource, recordPullSource) + s.createPullRequest(w, r, f, user, title, body, targetBranch, patch, sourceRev, pullSource, recordPullSource) } func (s *State) handlePatchBasedPull(w http.ResponseWriter, r *http.Request, f *FullyResolvedRepo, user *auth.User, title, body, targetBranch, patch string) { - ctx, span := s.t.TraceStart(r.Context(), "handlePatchBasedPull") - defer span.End() - - span.SetAttributes(attribute.String("targetBranch", targetBranch)) - if !patchutil.IsPatchValid(patch) { - span.SetAttributes(attribute.String("error", "invalid_patch_format")) s.pages.Notice(w, "pull", "Invalid patch format. Please provide a valid diff.") return } - s.createPullRequest(w, r.WithContext(ctx), f, user, title, body, targetBranch, patch, "", nil, nil) + s.createPullRequest(w, r, f, user, title, body, targetBranch, patch, "", nil, nil) } func (s *State) handleForkBasedPull(w http.ResponseWriter, r *http.Request, f *FullyResolvedRepo, user *auth.User, forkRepo string, title, body, targetBranch, sourceBranch string) { - ctx, span := s.t.TraceStart(r.Context(), "handleForkBasedPull") - defer span.End() - - span.SetAttributes( - attribute.String("forkRepo", forkRepo), - attribute.String("targetBranch", targetBranch), - attribute.String("sourceBranch", sourceBranch), - ) - - fork, err := db.GetForkByDid(ctx, s.db, user.Did, forkRepo) + fork, err := db.GetForkByDid(s.db, user.Did, forkRepo) if errors.Is(err, sql.ErrNoRows) { - span.SetAttributes(attribute.String("error", "fork_not_found")) s.pages.Notice(w, "pull", "No such fork.") return } else if err != nil { log.Println("failed to fetch fork:", err) - span.RecordError(err) - span.SetAttributes(attribute.String("error", "fork_fetch_failed")) s.pages.Notice(w, "pull", "Failed to fetch fork.") return } @@ -969,8 +746,6 @@ secret, err := db.GetRegistrationKey(s.db, fork.Knot) if err != nil { log.Println("failed to fetch registration key:", err) - span.RecordError(err) - span.SetAttributes(attribute.String("error", "registration_key_fetch_failed")) s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.") return } @@ -978,8 +753,6 @@ sc, err := NewSignedClient(fork.Knot, secret, s.config.Dev) if err != nil { log.Println("failed to create signed client:", err) - span.RecordError(err) - span.SetAttributes(attribute.String("error", "signed_client_creation_failed")) s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.") return } @@ -987,8 +760,6 @@ us, err := NewUnsignedClient(fork.Knot, s.config.Dev) if err != nil { log.Println("failed to create unsigned client:", err) - span.RecordError(err) - span.SetAttributes(attribute.String("error", "unsigned_client_creation_failed")) s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.") return } @@ -996,24 +767,18 @@ resp, err := sc.NewHiddenRef(user.Did, fork.Name, sourceBranch, targetBranch) if err != nil { log.Println("failed to create hidden ref:", err, resp.StatusCode) - span.RecordError(err) - span.SetAttributes(attribute.String("error", "hidden_ref_creation_failed")) s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.") return } switch resp.StatusCode { case 404: - span.SetAttributes(attribute.String("error", "not_found_status")) case 400: - span.SetAttributes(attribute.String("error", "bad_request_status")) s.pages.Notice(w, "pull", "Branch based pull requests are not supported on this knot.") return } hiddenRef := fmt.Sprintf("hidden/%s/%s", sourceBranch, targetBranch) - span.SetAttributes(attribute.String("hiddenRef", hiddenRef)) - // We're now comparing the sourceBranch (on the fork) against the hiddenRef which is tracking // the targetBranch on the target repository. This code is a bit confusing, but here's an example: // hiddenRef: hidden/feature-1/main (on repo-fork) @@ -1022,18 +787,14 @@ // sourceBranch: feature-1 (on repo-fork) comparison, err := us.Compare(user.Did, fork.Name, hiddenRef, sourceBranch) if err != nil { log.Println("failed to compare across branches", err) - span.RecordError(err) - span.SetAttributes(attribute.String("error", "branch_comparison_failed")) s.pages.Notice(w, "pull", err.Error()) return } sourceRev := comparison.Rev2 patch := comparison.Patch - span.SetAttributes(attribute.String("sourceRev", sourceRev)) if !patchutil.IsPatchValid(patch) { - span.SetAttributes(attribute.String("error", "invalid_patch_format")) s.pages.Notice(w, "pull", "Invalid patch format. Please provide a valid diff.") return } @@ -1041,13 +802,11 @@ forkAtUri, err := syntax.ParseATURI(fork.AtUri) if err != nil { log.Println("failed to parse fork AT URI", err) - span.RecordError(err) - span.SetAttributes(attribute.String("error", "fork_aturi_parse_failed")) s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.") return } - s.createPullRequest(w, r.WithContext(ctx), f, user, title, body, targetBranch, patch, sourceRev, &db.PullSource{ + s.createPullRequest(w, r, f, user, title, body, targetBranch, patch, sourceRev, &db.PullSource{ Branch: sourceBranch, RepoAt: &forkAtUri, }, &tangled.RepoPull_Source{Branch: sourceBranch, Repo: &fork.AtUri}) @@ -1064,20 +823,9 @@ sourceRev string, pullSource *db.PullSource, recordPullSource *tangled.RepoPull_Source, ) { - ctx, span := s.t.TraceStart(r.Context(), "createPullRequest") - defer span.End() - - span.SetAttributes( - attribute.String("targetBranch", targetBranch), - attribute.String("sourceRev", sourceRev), - attribute.Bool("hasPullSource", pullSource != nil), - ) - - tx, err := s.db.BeginTx(ctx, nil) + tx, err := s.db.BeginTx(r.Context(), nil) if err != nil { log.Println("failed to start tx") - span.RecordError(err) - span.SetAttributes(attribute.String("error", "transaction_start_failed")) s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.") return } @@ -1088,23 +836,16 @@ // so if it's still empty now, it's intentionally skipped owing to format-patch. if title == "" { formatPatches, err := patchutil.ExtractPatches(patch) if err != nil { - span.RecordError(err) - span.SetAttributes(attribute.String("error", "extract_patches_failed")) s.pages.Notice(w, "pull", fmt.Sprintf("Failed to extract patches: %v", err)) return } if len(formatPatches) == 0 { - span.SetAttributes(attribute.String("error", "no_patches_found")) s.pages.Notice(w, "pull", "No patches found in the supplied format-patch.") return } title = formatPatches[0].Title body = formatPatches[0].Body - span.SetAttributes( - attribute.Bool("title_extracted", true), - attribute.Bool("body_extracted", formatPatches[0].Body != ""), - ) } rkey := appview.TID() @@ -1112,7 +853,7 @@ initialSubmission := db.PullSubmission{ Patch: patch, SourceRev: sourceRev, } - err = db.NewPull(ctx, tx, &db.Pull{ + err = db.NewPull(tx, &db.Pull{ Title: title, Body: body, TargetBranch: targetBranch, @@ -1126,24 +867,18 @@ PullSource: pullSource, }) if err != nil { log.Println("failed to create pull request", err) - span.RecordError(err) - span.SetAttributes(attribute.String("error", "db_create_pull_failed")) s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.") return } - - client, _ := s.auth.AuthorizedClient(r.WithContext(ctx)) + client, _ := s.auth.AuthorizedClient(r) pullId, err := db.NextPullId(s.db, f.RepoAt) if err != nil { log.Println("failed to get pull id", err) - span.RecordError(err) - span.SetAttributes(attribute.String("error", "get_pull_id_failed")) s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.") return } - span.SetAttributes(attribute.Int("pullId", pullId)) - _, err = comatproto.RepoPutRecord(ctx, client, &comatproto.RepoPutRecord_Input{ + _, err = comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{ Collection: tangled.RepoPullNSID, Repo: user.Did, Rkey: rkey, @@ -1161,16 +896,6 @@ }) if err != nil { log.Println("failed to create pull request", err) - span.RecordError(err) - span.SetAttributes(attribute.String("error", "atproto_create_record_failed")) - s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.") - return - } - - if err = tx.Commit(); err != nil { - log.Println("failed to commit transaction", err) - span.RecordError(err) - span.SetAttributes(attribute.String("error", "transaction_commit_failed")) s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.") return } @@ -1179,36 +904,24 @@ s.pages.HxLocation(w, fmt.Sprintf("/%s/pulls/%d", f.OwnerSlashRepo(), pullId)) } func (s *State) ValidatePatch(w http.ResponseWriter, r *http.Request) { - ctx, span := s.t.TraceStart(r.Context(), "ValidatePatch") - defer span.End() - - _, err := s.fullyResolvedRepo(r.WithContext(ctx)) + _, err := s.fullyResolvedRepo(r) if err != nil { log.Println("failed to get repo and knot", err) - span.RecordError(err) - span.SetAttributes(attribute.String("error", "resolve_repo_failed")) return } patch := r.FormValue("patch") - span.SetAttributes(attribute.Bool("hasPatch", patch != "")) - if patch == "" { - span.SetAttributes(attribute.String("error", "empty_patch")) s.pages.Notice(w, "patch-error", "Patch is required.") return } - if !patchutil.IsPatchValid(patch) { - span.SetAttributes(attribute.String("error", "invalid_patch_format")) + if patch == "" || !patchutil.IsPatchValid(patch) { s.pages.Notice(w, "patch-error", "Invalid patch format. Please provide a valid git diff or format-patch.") return } - isFormatPatch := patchutil.IsFormatPatch(patch) - span.SetAttributes(attribute.Bool("isFormatPatch", isFormatPatch)) - - if isFormatPatch { + if patchutil.IsFormatPatch(patch) { s.pages.Notice(w, "patch-preview", "git-format-patch detected. Title and description are optional; if left out, they will be extracted from the first commit.") } else { s.pages.Notice(w, "patch-preview", "Regular git-diff detected. Please provide a title and description.") @@ -1216,41 +929,29 @@ } } func (s *State) PatchUploadFragment(w http.ResponseWriter, r *http.Request) { - ctx, span := s.t.TraceStart(r.Context(), "PatchUploadFragment") - defer span.End() - - user := s.auth.GetUser(r.WithContext(ctx)) - f, err := s.fullyResolvedRepo(r.WithContext(ctx)) + user := s.auth.GetUser(r) + f, err := s.fullyResolvedRepo(r) if err != nil { log.Println("failed to get repo and knot", err) - span.RecordError(err) - span.SetAttributes(attribute.String("error", "resolve_repo_failed")) return } s.pages.PullPatchUploadFragment(w, pages.PullPatchUploadParams{ - RepoInfo: f.RepoInfo(ctx, s, user), + RepoInfo: f.RepoInfo(s, user), }) } func (s *State) CompareBranchesFragment(w http.ResponseWriter, r *http.Request) { - ctx, span := s.t.TraceStart(r.Context(), "CompareBranchesFragment") - defer span.End() - - user := s.auth.GetUser(r.WithContext(ctx)) - f, err := s.fullyResolvedRepo(r.WithContext(ctx)) + user := s.auth.GetUser(r) + f, err := s.fullyResolvedRepo(r) if err != nil { log.Println("failed to get repo and knot", err) - span.RecordError(err) - span.SetAttributes(attribute.String("error", "resolve_repo_failed")) return } us, err := NewUnsignedClient(f.Knot, s.config.Dev) if err != nil { log.Printf("failed to create unsigned client for %s", f.Knot) - span.RecordError(err) - span.SetAttributes(attribute.String("error", "client_creation_failed")) s.pages.Error503(w) return } @@ -1258,89 +959,69 @@ resp, err := us.Branches(f.OwnerDid(), f.RepoName) if err != nil { log.Println("failed to reach knotserver", err) - span.RecordError(err) - span.SetAttributes(attribute.String("error", "knotserver_connection_failed")) return } body, err := io.ReadAll(resp.Body) if err != nil { log.Printf("Error reading response body: %v", err) - span.RecordError(err) - span.SetAttributes(attribute.String("error", "response_read_failed")) return } - defer resp.Body.Close() var result types.RepoBranchesResponse err = json.Unmarshal(body, &result) if err != nil { log.Println("failed to parse response:", err) - span.RecordError(err) - span.SetAttributes(attribute.String("error", "response_parse_failed")) return } - span.SetAttributes(attribute.Int("branches.count", len(result.Branches))) s.pages.PullCompareBranchesFragment(w, pages.PullCompareBranchesParams{ - RepoInfo: f.RepoInfo(ctx, s, user), + RepoInfo: f.RepoInfo(s, user), Branches: result.Branches, }) } func (s *State) CompareForksFragment(w http.ResponseWriter, r *http.Request) { - ctx, span := s.t.TraceStart(r.Context(), "CompareForksFragment") - defer span.End() - - user := s.auth.GetUser(r.WithContext(ctx)) - f, err := s.fullyResolvedRepo(r.WithContext(ctx)) + user := s.auth.GetUser(r) + f, err := s.fullyResolvedRepo(r) if err != nil { log.Println("failed to get repo and knot", err) - span.RecordError(err) return } - forks, err := db.GetForksByDid(ctx, s.db, user.Did) + forks, err := db.GetForksByDid(s.db, user.Did) if err != nil { log.Println("failed to get forks", err) - span.RecordError(err) return } s.pages.PullCompareForkFragment(w, pages.PullCompareForkParams{ - RepoInfo: f.RepoInfo(ctx, s, user), + RepoInfo: f.RepoInfo(s, user), Forks: forks, }) } func (s *State) CompareForksBranchesFragment(w http.ResponseWriter, r *http.Request) { - ctx, span := s.t.TraceStart(r.Context(), "CompareForksBranchesFragment") - defer span.End() + user := s.auth.GetUser(r) - user := s.auth.GetUser(r.WithContext(ctx)) - - f, err := s.fullyResolvedRepo(r.WithContext(ctx)) + f, err := s.fullyResolvedRepo(r) if err != nil { log.Println("failed to get repo and knot", err) - span.RecordError(err) return } forkVal := r.URL.Query().Get("fork") - span.SetAttributes(attribute.String("fork", forkVal)) // fork repo - repo, err := db.GetRepo(ctx, s.db, user.Did, forkVal) + repo, err := db.GetRepo(s.db, user.Did, forkVal) if err != nil { log.Println("failed to get repo", user.Did, forkVal) - span.RecordError(err) return } sourceBranchesClient, err := NewUnsignedClient(repo.Knot, s.config.Dev) if err != nil { log.Printf("failed to create unsigned client for %s", repo.Knot) - span.RecordError(err) s.pages.Error503(w) return } @@ -1348,14 +1029,12 @@ sourceResp, err := sourceBranchesClient.Branches(user.Did, repo.Name) if err != nil { log.Println("failed to reach knotserver for source branches", err) - span.RecordError(err) return } sourceBody, err := io.ReadAll(sourceResp.Body) if err != nil { log.Println("failed to read source response body", err) - span.RecordError(err) return } defer sourceResp.Body.Close() @@ -1364,14 +1043,12 @@ var sourceResult types.RepoBranchesResponse err = json.Unmarshal(sourceBody, &sourceResult) if err != nil { log.Println("failed to parse source branches response:", err) - span.RecordError(err) return } targetBranchesClient, err := NewUnsignedClient(f.Knot, s.config.Dev) if err != nil { log.Printf("failed to create unsigned client for target knot %s", f.Knot) - span.RecordError(err) s.pages.Error503(w) return } @@ -1379,14 +1056,12 @@ targetResp, err := targetBranchesClient.Branches(f.OwnerDid(), f.RepoName) if err != nil { log.Println("failed to reach knotserver for target branches", err) - span.RecordError(err) return } targetBody, err := io.ReadAll(targetResp.Body) if err != nil { log.Println("failed to read target response body", err) - span.RecordError(err) return } defer targetResp.Body.Close() @@ -1395,114 +1070,84 @@ var targetResult types.RepoBranchesResponse err = json.Unmarshal(targetBody, &targetResult) if err != nil { log.Println("failed to parse target branches response:", err) - span.RecordError(err) return } s.pages.PullCompareForkBranchesFragment(w, pages.PullCompareForkBranchesParams{ - RepoInfo: f.RepoInfo(ctx, s, user), + RepoInfo: f.RepoInfo(s, user), SourceBranches: sourceResult.Branches, TargetBranches: targetResult.Branches, }) } func (s *State) ResubmitPull(w http.ResponseWriter, r *http.Request) { - ctx, span := s.t.TraceStart(r.Context(), "ResubmitPull") - defer span.End() - - user := s.auth.GetUser(r.WithContext(ctx)) - f, err := s.fullyResolvedRepo(r.WithContext(ctx)) + user := s.auth.GetUser(r) + f, err := s.fullyResolvedRepo(r) if err != nil { log.Println("failed to get repo and knot", err) - span.RecordError(err) return } - pull, ok := ctx.Value("pull").(*db.Pull) + pull, ok := r.Context().Value("pull").(*db.Pull) if !ok { log.Println("failed to get pull") - span.RecordError(errors.New("failed to get pull from context")) s.pages.Notice(w, "pull-error", "Failed to edit patch. Try again later.") return } - span.SetAttributes( - attribute.Int("pull.id", pull.PullId), - attribute.String("pull.owner", pull.OwnerDid), - attribute.String("method", r.Method), - ) - switch r.Method { case http.MethodGet: s.pages.PullResubmitFragment(w, pages.PullResubmitParams{ - RepoInfo: f.RepoInfo(ctx, s, user), + RepoInfo: f.RepoInfo(s, user), Pull: pull, }) return case http.MethodPost: if pull.IsPatchBased() { - span.SetAttributes(attribute.String("pull.type", "patch_based")) - s.resubmitPatch(w, r.WithContext(ctx)) + s.resubmitPatch(w, r) return } else if pull.IsBranchBased() { - span.SetAttributes(attribute.String("pull.type", "branch_based")) - s.resubmitBranch(w, r.WithContext(ctx)) + s.resubmitBranch(w, r) return } else if pull.IsForkBased() { - span.SetAttributes(attribute.String("pull.type", "fork_based")) - s.resubmitFork(w, r.WithContext(ctx)) + s.resubmitFork(w, r) return } - span.SetAttributes(attribute.String("pull.type", "unknown")) } } func (s *State) resubmitPatch(w http.ResponseWriter, r *http.Request) { - ctx, span := s.t.TraceStart(r.Context(), "resubmitPatch") - defer span.End() - - user := s.auth.GetUser(r.WithContext(ctx)) + user := s.auth.GetUser(r) - pull, ok := ctx.Value("pull").(*db.Pull) + pull, ok := r.Context().Value("pull").(*db.Pull) if !ok { log.Println("failed to get pull") - span.RecordError(errors.New("failed to get pull from context")) s.pages.Notice(w, "pull-error", "Failed to edit patch. Try again later.") return } - span.SetAttributes( - attribute.Int("pull.id", pull.PullId), - attribute.String("pull.owner", pull.OwnerDid), - ) - - f, err := s.fullyResolvedRepo(r.WithContext(ctx)) + f, err := s.fullyResolvedRepo(r) if err != nil { log.Println("failed to get repo and knot", err) - span.RecordError(err) return } if user.Did != pull.OwnerDid { log.Println("unauthorized user") - span.SetAttributes(attribute.String("error", "unauthorized_user")) w.WriteHeader(http.StatusUnauthorized) return } patch := r.FormValue("patch") - span.SetAttributes(attribute.Bool("has_patch", patch != "")) if err = validateResubmittedPatch(pull, patch); err != nil { - span.SetAttributes(attribute.String("error", "invalid_patch")) s.pages.Notice(w, "resubmit-error", err.Error()) return } - tx, err := s.db.BeginTx(ctx, nil) + tx, err := s.db.BeginTx(r.Context(), nil) if err != nil { log.Println("failed to start tx") - span.RecordError(err) s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.") return } @@ -1511,22 +1156,19 @@ err = db.ResubmitPull(tx, pull, patch, "") if err != nil { log.Println("failed to resubmit pull request", err) - span.RecordError(err) s.pages.Notice(w, "resubmit-error", "Failed to resubmit pull request. Try again later.") return } - client, _ := s.auth.AuthorizedClient(r.WithContext(ctx)) + client, _ := s.auth.AuthorizedClient(r) - ex, err := comatproto.RepoGetRecord(ctx, client, "", tangled.RepoPullNSID, user.Did, pull.Rkey) + ex, err := comatproto.RepoGetRecord(r.Context(), client, "", tangled.RepoPullNSID, user.Did, pull.Rkey) if err != nil { // failed to get record - span.RecordError(err) - span.SetAttributes(attribute.String("error", "record_not_found")) s.pages.Notice(w, "resubmit-error", "Failed to update pull, no record found on PDS.") return } - _, err = comatproto.RepoPutRecord(ctx, client, &comatproto.RepoPutRecord_Input{ + _, err = comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{ Collection: tangled.RepoPullNSID, Repo: user.Did, Rkey: pull.Rkey, @@ -1543,14 +1185,12 @@ }, }) if err != nil { log.Println("failed to update record", err) - span.RecordError(err) s.pages.Notice(w, "resubmit-error", "Failed to update pull request on the PDS. Try again later.") return } if err = tx.Commit(); err != nil { log.Println("failed to commit transaction", err) - span.RecordError(err) s.pages.Notice(w, "resubmit-error", "Failed to resubmit pull.") return } @@ -1560,43 +1200,29 @@ return } func (s *State) resubmitBranch(w http.ResponseWriter, r *http.Request) { - ctx, span := s.t.TraceStart(r.Context(), "resubmitBranch") - defer span.End() + user := s.auth.GetUser(r) - user := s.auth.GetUser(r.WithContext(ctx)) - - pull, ok := ctx.Value("pull").(*db.Pull) + pull, ok := r.Context().Value("pull").(*db.Pull) if !ok { log.Println("failed to get pull") - span.RecordError(errors.New("failed to get pull from context")) - s.pages.Notice(w, "pull-error", "Failed to edit patch. Try again later.") + s.pages.Notice(w, "resubmit-error", "Failed to edit patch. Try again later.") return } - span.SetAttributes( - attribute.Int("pull.id", pull.PullId), - attribute.String("pull.owner", pull.OwnerDid), - attribute.String("pull.source_branch", pull.PullSource.Branch), - attribute.String("pull.target_branch", pull.TargetBranch), - ) - - f, err := s.fullyResolvedRepo(r.WithContext(ctx)) + f, err := s.fullyResolvedRepo(r) if err != nil { log.Println("failed to get repo and knot", err) - span.RecordError(err) return } if user.Did != pull.OwnerDid { log.Println("unauthorized user") - span.SetAttributes(attribute.String("error", "unauthorized_user")) w.WriteHeader(http.StatusUnauthorized) return } - if !f.RepoInfo(ctx, s, user).Roles.IsPushAllowed() { + if !f.RepoInfo(s, user).Roles.IsPushAllowed() { log.Println("unauthorized user") - span.SetAttributes(attribute.String("error", "push_not_allowed")) w.WriteHeader(http.StatusUnauthorized) return } @@ -1604,8 +1230,6 @@ ksClient, err := NewUnsignedClient(f.Knot, s.config.Dev) if err != nil { log.Printf("failed to create client for %s: %s", f.Knot, err) - span.RecordError(err) - span.SetAttributes(attribute.String("error", "client_creation_failed")) s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.") return } @@ -1613,32 +1237,26 @@ comparison, err := ksClient.Compare(f.OwnerDid(), f.RepoName, pull.TargetBranch, pull.PullSource.Branch) if err != nil { log.Printf("compare request failed: %s", err) - span.RecordError(err) - span.SetAttributes(attribute.String("error", "compare_failed")) s.pages.Notice(w, "resubmit-error", err.Error()) return } sourceRev := comparison.Rev2 patch := comparison.Patch - span.SetAttributes(attribute.String("source_rev", sourceRev)) if err = validateResubmittedPatch(pull, patch); err != nil { - span.SetAttributes(attribute.String("error", "invalid_patch")) s.pages.Notice(w, "resubmit-error", err.Error()) return } if sourceRev == pull.Submissions[pull.LastRoundNumber()].SourceRev { - span.SetAttributes(attribute.String("error", "no_changes")) s.pages.Notice(w, "resubmit-error", "This branch has not changed since the last submission.") return } - tx, err := s.db.BeginTx(ctx, nil) + tx, err := s.db.BeginTx(r.Context(), nil) if err != nil { log.Println("failed to start tx") - span.RecordError(err) s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.") return } @@ -1647,17 +1265,14 @@ err = db.ResubmitPull(tx, pull, patch, sourceRev) if err != nil { log.Println("failed to create pull request", err) - span.RecordError(err) s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.") return } - client, _ := s.auth.AuthorizedClient(r.WithContext(ctx)) + client, _ := s.auth.AuthorizedClient(r) - ex, err := comatproto.RepoGetRecord(ctx, client, "", tangled.RepoPullNSID, user.Did, pull.Rkey) + ex, err := comatproto.RepoGetRecord(r.Context(), client, "", tangled.RepoPullNSID, user.Did, pull.Rkey) if err != nil { // failed to get record - span.RecordError(err) - span.SetAttributes(attribute.String("error", "record_not_found")) s.pages.Notice(w, "resubmit-error", "Failed to update pull, no record found on PDS.") return } @@ -1665,7 +1280,7 @@ recordPullSource := &tangled.RepoPull_Source{ Branch: pull.PullSource.Branch, } - _, err = comatproto.RepoPutRecord(ctx, client, &comatproto.RepoPutRecord_Input{ + _, err = comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{ Collection: tangled.RepoPullNSID, Repo: user.Did, Rkey: pull.Rkey, @@ -1683,14 +1298,12 @@ }, }) if err != nil { log.Println("failed to update record", err) - span.RecordError(err) s.pages.Notice(w, "resubmit-error", "Failed to update pull request on the PDS. Try again later.") return } if err = tx.Commit(); err != nil { log.Println("failed to commit transaction", err) - span.RecordError(err) s.pages.Notice(w, "resubmit-error", "Failed to resubmit pull.") return } @@ -1700,61 +1313,38 @@ return } func (s *State) resubmitFork(w http.ResponseWriter, r *http.Request) { - ctx, span := s.t.TraceStart(r.Context(), "resubmitFork") - defer span.End() - - user := s.auth.GetUser(r.WithContext(ctx)) + user := s.auth.GetUser(r) - pull, ok := ctx.Value("pull").(*db.Pull) + pull, ok := r.Context().Value("pull").(*db.Pull) if !ok { log.Println("failed to get pull") - span.RecordError(errors.New("failed to get pull from context")) - s.pages.Notice(w, "pull-error", "Failed to edit patch. Try again later.") + s.pages.Notice(w, "resubmit-error", "Failed to edit patch. Try again later.") return } - span.SetAttributes( - attribute.Int("pull.id", pull.PullId), - attribute.String("pull.owner", pull.OwnerDid), - attribute.String("pull.source_branch", pull.PullSource.Branch), - attribute.String("pull.target_branch", pull.TargetBranch), - ) - - f, err := s.fullyResolvedRepo(r.WithContext(ctx)) + f, err := s.fullyResolvedRepo(r) if err != nil { log.Println("failed to get repo and knot", err) - span.RecordError(err) return } if user.Did != pull.OwnerDid { log.Println("unauthorized user") - span.SetAttributes(attribute.String("error", "unauthorized_user")) w.WriteHeader(http.StatusUnauthorized) return } - forkRepo, err := db.GetRepoByAtUri(ctx, s.db, pull.PullSource.RepoAt.String()) + forkRepo, err := db.GetRepoByAtUri(s.db, pull.PullSource.RepoAt.String()) if err != nil { log.Println("failed to get source repo", err) - span.RecordError(err) - span.SetAttributes(attribute.String("error", "source_repo_not_found")) s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.") return } - span.SetAttributes( - attribute.String("fork.knot", forkRepo.Knot), - attribute.String("fork.did", forkRepo.Did), - attribute.String("fork.name", forkRepo.Name), - ) - // extract patch by performing compare ksClient, err := NewUnsignedClient(forkRepo.Knot, s.config.Dev) if err != nil { log.Printf("failed to create client for %s: %s", forkRepo.Knot, err) - span.RecordError(err) - span.SetAttributes(attribute.String("error", "client_creation_failed")) s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.") return } @@ -1762,8 +1352,6 @@ secret, err := db.GetRegistrationKey(s.db, forkRepo.Knot) if err != nil { log.Printf("failed to get registration key for %s: %s", forkRepo.Knot, err) - span.RecordError(err) - span.SetAttributes(attribute.String("error", "reg_key_not_found")) s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.") return } @@ -1772,8 +1360,6 @@ // update the hidden tracking branch to latest signedClient, err := NewSignedClient(forkRepo.Knot, secret, s.config.Dev) if err != nil { log.Printf("failed to create signed client for %s: %s", forkRepo.Knot, err) - span.RecordError(err) - span.SetAttributes(attribute.String("error", "signed_client_creation_failed")) s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.") return } @@ -1781,44 +1367,34 @@ resp, err := signedClient.NewHiddenRef(forkRepo.Did, forkRepo.Name, pull.PullSource.Branch, pull.TargetBranch) if err != nil || resp.StatusCode != http.StatusNoContent { log.Printf("failed to update tracking branch: %s", err) - span.RecordError(err) - span.SetAttributes(attribute.String("error", "hidden_ref_update_failed")) s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.") return } hiddenRef := fmt.Sprintf("hidden/%s/%s", pull.PullSource.Branch, pull.TargetBranch) - span.SetAttributes(attribute.String("hidden_ref", hiddenRef)) - comparison, err := ksClient.Compare(forkRepo.Did, forkRepo.Name, hiddenRef, pull.PullSource.Branch) if err != nil { log.Printf("failed to compare branches: %s", err) - span.RecordError(err) - span.SetAttributes(attribute.String("error", "compare_failed")) s.pages.Notice(w, "resubmit-error", err.Error()) return } sourceRev := comparison.Rev2 patch := comparison.Patch - span.SetAttributes(attribute.String("source_rev", sourceRev)) if err = validateResubmittedPatch(pull, patch); err != nil { - span.SetAttributes(attribute.String("error", "invalid_patch")) s.pages.Notice(w, "resubmit-error", err.Error()) return } if sourceRev == pull.Submissions[pull.LastRoundNumber()].SourceRev { - span.SetAttributes(attribute.String("error", "no_changes")) s.pages.Notice(w, "resubmit-error", "This branch has not changed since the last submission.") return } - tx, err := s.db.BeginTx(ctx, nil) + tx, err := s.db.BeginTx(r.Context(), nil) if err != nil { log.Println("failed to start tx") - span.RecordError(err) s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.") return } @@ -1827,17 +1403,14 @@ err = db.ResubmitPull(tx, pull, patch, sourceRev) if err != nil { log.Println("failed to create pull request", err) - span.RecordError(err) s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.") return } - client, _ := s.auth.AuthorizedClient(r.WithContext(ctx)) + client, _ := s.auth.AuthorizedClient(r) - ex, err := comatproto.RepoGetRecord(ctx, client, "", tangled.RepoPullNSID, user.Did, pull.Rkey) + ex, err := comatproto.RepoGetRecord(r.Context(), client, "", tangled.RepoPullNSID, user.Did, pull.Rkey) if err != nil { // failed to get record - span.RecordError(err) - span.SetAttributes(attribute.String("error", "record_not_found")) s.pages.Notice(w, "resubmit-error", "Failed to update pull, no record found on PDS.") return } @@ -1847,7 +1420,7 @@ recordPullSource := &tangled.RepoPull_Source{ Branch: pull.PullSource.Branch, Repo: &repoAt, } - _, err = comatproto.RepoPutRecord(ctx, client, &comatproto.RepoPutRecord_Input{ + _, err = comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{ Collection: tangled.RepoPullNSID, Repo: user.Did, Rkey: pull.Rkey, @@ -1865,14 +1438,12 @@ }, }) if err != nil { log.Println("failed to update record", err) - span.RecordError(err) s.pages.Notice(w, "resubmit-error", "Failed to update pull request on the PDS. Try again later.") return } if err = tx.Commit(); err != nil { log.Println("failed to commit transaction", err) - span.RecordError(err) s.pages.Notice(w, "resubmit-error", "Failed to resubmit pull.") return } @@ -1899,46 +1470,30 @@ return nil } func (s *State) MergePull(w http.ResponseWriter, r *http.Request) { - ctx, span := s.t.TraceStart(r.Context(), "MergePull") - defer span.End() - - f, err := s.fullyResolvedRepo(r.WithContext(ctx)) + f, err := s.fullyResolvedRepo(r) if err != nil { log.Println("failed to resolve repo:", err) - span.RecordError(err) - span.SetAttributes(attribute.String("error", "resolve_repo_failed")) s.pages.Notice(w, "pull-merge-error", "Failed to merge pull request. Try again later.") return } - pull, ok := ctx.Value("pull").(*db.Pull) + pull, ok := r.Context().Value("pull").(*db.Pull) if !ok { log.Println("failed to get pull") - span.SetAttributes(attribute.String("error", "pull_not_in_context")) s.pages.Notice(w, "pull-error", "Failed to edit patch. Try again later.") return } - span.SetAttributes( - attribute.Int("pull.id", pull.PullId), - attribute.String("pull.owner", pull.OwnerDid), - attribute.String("target_branch", pull.TargetBranch), - ) - secret, err := db.GetRegistrationKey(s.db, f.Knot) if err != nil { log.Printf("no registration key found for domain %s: %s\n", f.Knot, err) - span.RecordError(err) - span.SetAttributes(attribute.String("error", "reg_key_not_found")) s.pages.Notice(w, "pull-merge-error", "Failed to merge pull request. Try again later.") return } - ident, err := s.resolver.ResolveIdent(ctx, pull.OwnerDid) + ident, err := s.resolver.ResolveIdent(r.Context(), pull.OwnerDid) if err != nil { log.Printf("resolving identity: %s", err) - span.RecordError(err) - span.SetAttributes(attribute.String("error", "resolve_identity_failed")) w.WriteHeader(http.StatusNotFound) return } @@ -1946,15 +1501,11 @@ email, err := db.GetPrimaryEmail(s.db, pull.OwnerDid) if err != nil { log.Printf("failed to get primary email: %s", err) - span.RecordError(err) - span.SetAttributes(attribute.String("error", "get_email_failed")) } ksClient, err := NewSignedClient(f.Knot, secret, s.config.Dev) if err != nil { log.Printf("failed to create signed client for %s: %s", f.Knot, err) - span.RecordError(err) - span.SetAttributes(attribute.String("error", "client_creation_failed")) s.pages.Notice(w, "pull-merge-error", "Failed to merge pull request. Try again later.") return } @@ -1963,84 +1514,55 @@ // Merge the pull request resp, err := ksClient.Merge([]byte(pull.LatestPatch()), f.OwnerDid(), f.RepoName, pull.TargetBranch, pull.Title, pull.Body, ident.Handle.String(), email.Address) if err != nil { log.Printf("failed to merge pull request: %s", err) - span.RecordError(err) - span.SetAttributes(attribute.String("error", "merge_failed")) s.pages.Notice(w, "pull-merge-error", "Failed to merge pull request. Try again later.") return } - span.SetAttributes(attribute.Int("response.status", resp.StatusCode)) - if resp.StatusCode == http.StatusOK { err := db.MergePull(s.db, f.RepoAt, pull.PullId) if err != nil { log.Printf("failed to update pull request status in database: %s", err) - span.RecordError(err) - span.SetAttributes(attribute.String("error", "db_update_failed")) s.pages.Notice(w, "pull-merge-error", "Failed to merge pull request. Try again later.") return } s.pages.HxLocation(w, fmt.Sprintf("/@%s/%s/pulls/%d", f.OwnerHandle(), f.RepoName, pull.PullId)) } else { log.Printf("knotserver returned non-OK status code for merge: %d", resp.StatusCode) - span.SetAttributes(attribute.String("error", "non_ok_response")) s.pages.Notice(w, "pull-merge-error", "Failed to merge pull request. Try again later.") } } func (s *State) ClosePull(w http.ResponseWriter, r *http.Request) { - ctx, span := s.t.TraceStart(r.Context(), "ClosePull") - defer span.End() - - user := s.auth.GetUser(r.WithContext(ctx)) + user := s.auth.GetUser(r) - f, err := s.fullyResolvedRepo(r.WithContext(ctx)) + f, err := s.fullyResolvedRepo(r) if err != nil { log.Println("malformed middleware") - span.RecordError(err) - span.SetAttributes(attribute.String("error", "resolve_repo_failed")) return } - pull, ok := ctx.Value("pull").(*db.Pull) + pull, ok := r.Context().Value("pull").(*db.Pull) if !ok { log.Println("failed to get pull") - span.SetAttributes(attribute.String("error", "pull_not_in_context")) s.pages.Notice(w, "pull-error", "Failed to edit patch. Try again later.") return } - span.SetAttributes( - attribute.Int("pull.id", pull.PullId), - attribute.String("pull.owner", pull.OwnerDid), - attribute.String("user.did", user.Did), - ) - // auth filter: only owner or collaborators can close roles := RolesInRepo(s, user, f) isCollaborator := roles.IsCollaborator() isPullAuthor := user.Did == pull.OwnerDid isCloseAllowed := isCollaborator || isPullAuthor - - span.SetAttributes( - attribute.Bool("is_collaborator", isCollaborator), - attribute.Bool("is_pull_author", isPullAuthor), - attribute.Bool("is_close_allowed", isCloseAllowed), - ) - if !isCloseAllowed { log.Println("failed to close pull") - span.SetAttributes(attribute.String("error", "unauthorized")) s.pages.Notice(w, "pull-close", "You are unauthorized to close this pull.") return } // Start a transaction - tx, err := s.db.BeginTx(ctx, nil) + tx, err := s.db.BeginTx(r.Context(), nil) if err != nil { log.Println("failed to start transaction", err) - span.RecordError(err) - span.SetAttributes(attribute.String("error", "transaction_start_failed")) s.pages.Notice(w, "pull-close", "Failed to close pull.") return } @@ -2049,8 +1571,6 @@ // Close the pull in the database err = db.ClosePull(tx, f.RepoAt, pull.PullId) if err != nil { log.Println("failed to close pull", err) - span.RecordError(err) - span.SetAttributes(attribute.String("error", "db_close_failed")) s.pages.Notice(w, "pull-close", "Failed to close pull.") return } @@ -2058,8 +1578,6 @@ // Commit the transaction if err = tx.Commit(); err != nil { log.Println("failed to commit transaction", err) - span.RecordError(err) - span.SetAttributes(attribute.String("error", "transaction_commit_failed")) s.pages.Notice(w, "pull-close", "Failed to close pull.") return } @@ -2069,59 +1587,37 @@ return } func (s *State) ReopenPull(w http.ResponseWriter, r *http.Request) { - ctx, span := s.t.TraceStart(r.Context(), "ReopenPull") - defer span.End() - - user := s.auth.GetUser(r.WithContext(ctx)) + user := s.auth.GetUser(r) - f, err := s.fullyResolvedRepo(r.WithContext(ctx)) + f, err := s.fullyResolvedRepo(r) if err != nil { log.Println("failed to resolve repo", err) - span.RecordError(err) - span.SetAttributes(attribute.String("error", "resolve_repo_failed")) s.pages.Notice(w, "pull-reopen", "Failed to reopen pull.") return } - pull, ok := ctx.Value("pull").(*db.Pull) + pull, ok := r.Context().Value("pull").(*db.Pull) if !ok { log.Println("failed to get pull") - span.SetAttributes(attribute.String("error", "pull_not_in_context")) s.pages.Notice(w, "pull-error", "Failed to edit patch. Try again later.") return } - span.SetAttributes( - attribute.Int("pull.id", pull.PullId), - attribute.String("pull.owner", pull.OwnerDid), - attribute.String("user.did", user.Did), - ) - - // auth filter: only owner or collaborators can reopen + // auth filter: only owner or collaborators can close roles := RolesInRepo(s, user, f) isCollaborator := roles.IsCollaborator() isPullAuthor := user.Did == pull.OwnerDid - isReopenAllowed := isCollaborator || isPullAuthor - - span.SetAttributes( - attribute.Bool("is_collaborator", isCollaborator), - attribute.Bool("is_pull_author", isPullAuthor), - attribute.Bool("is_reopen_allowed", isReopenAllowed), - ) - - if !isReopenAllowed { - log.Println("failed to reopen pull") - span.SetAttributes(attribute.String("error", "unauthorized")) - s.pages.Notice(w, "pull-close", "You are unauthorized to reopen this pull.") + isCloseAllowed := isCollaborator || isPullAuthor + if !isCloseAllowed { + log.Println("failed to close pull") + s.pages.Notice(w, "pull-close", "You are unauthorized to close this pull.") return } // Start a transaction - tx, err := s.db.BeginTx(ctx, nil) + tx, err := s.db.BeginTx(r.Context(), nil) if err != nil { log.Println("failed to start transaction", err) - span.RecordError(err) - span.SetAttributes(attribute.String("error", "transaction_start_failed")) s.pages.Notice(w, "pull-reopen", "Failed to reopen pull.") return } @@ -2130,8 +1626,6 @@ // Reopen the pull in the database err = db.ReopenPull(tx, f.RepoAt, pull.PullId) if err != nil { log.Println("failed to reopen pull", err) - span.RecordError(err) - span.SetAttributes(attribute.String("error", "db_reopen_failed")) s.pages.Notice(w, "pull-reopen", "Failed to reopen pull.") return } @@ -2139,8 +1633,6 @@ // Commit the transaction if err = tx.Commit(); err != nil { log.Println("failed to commit transaction", err) - span.RecordError(err) - span.SetAttributes(attribute.String("error", "transaction_commit_failed")) s.pages.Notice(w, "pull-reopen", "Failed to reopen pull.") return } diff --git a/appview/state/repo.go b/appview/state/repo.go --- a/appview/state/repo.go +++ b/appview/state/repo.go @@ -16,8 +16,6 @@ "strconv" "strings" "time" - "go.opentelemetry.io/otel/attribute" - "go.opentelemetry.io/otel/codes" "tangled.sh/tangled.sh/core/api/tangled" "tangled.sh/tangled.sh/core/appview" "tangled.sh/tangled.sh/core/appview/auth" @@ -40,23 +38,16 @@ lexutil "github.com/bluesky-social/indigo/lex/util" ) func (s *State) RepoIndex(w http.ResponseWriter, r *http.Request) { - ctx, span := s.t.TraceStart(r.Context(), "RepoIndex") - defer span.End() - ref := chi.URLParam(r, "ref") - f, err := s.fullyResolvedRepo(r.WithContext(ctx)) + f, err := s.fullyResolvedRepo(r) if err != nil { log.Println("failed to fully resolve repo", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to fully resolve repo") return } us, err := NewUnsignedClient(f.Knot, s.config.Dev) if err != nil { log.Printf("failed to create unsigned client for %s", f.Knot) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to create unsigned client") s.pages.Error503(w) return } @@ -65,8 +56,6 @@ resp, err := us.Index(f.OwnerDid(), f.RepoName, ref) if err != nil { s.pages.Error503(w) log.Println("failed to reach knotserver", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to reach knotserver") return } defer resp.Body.Close() @@ -74,8 +63,6 @@ body, err := io.ReadAll(resp.Body) if err != nil { log.Printf("Error reading response body: %v", err) - span.RecordError(err) - span.SetStatus(codes.Error, "error reading response body") return } @@ -83,8 +70,6 @@ var result types.RepoIndexResponse err = json.Unmarshal(body, &result) if err != nil { log.Printf("Error unmarshalling response body: %v", err) - span.RecordError(err) - span.SetStatus(codes.Error, "error unmarshalling response body") return } @@ -127,13 +112,6 @@ branchCount := len(result.Branches) tagCount := len(result.Tags) fileCount := len(result.Files) - span.SetAttributes( - attribute.Int("commits.count", commitCount), - attribute.Int("branches.count", branchCount), - attribute.Int("tags.count", tagCount), - attribute.Int("files.count", fileCount), - ) - commitCount, branchCount, tagCount = balanceIndexItems(commitCount, branchCount, tagCount, fileCount) commitsTrunc := result.Commits[:min(commitCount, len(result.Commits))] tagsTrunc := result.Tags[:min(tagCount, len(result.Tags))] @@ -144,7 +122,7 @@ user := s.auth.GetUser(r) s.pages.RepoIndexPage(w, pages.RepoIndexParams{ LoggedInUser: user, - RepoInfo: f.RepoInfo(ctx, s, user), + RepoInfo: f.RepoInfo(s, user), TagMap: tagMap, RepoIndexResponse: result, CommitsTrunc: commitsTrunc, @@ -156,14 +134,9 @@ return } func (s *State) RepoLog(w http.ResponseWriter, r *http.Request) { - ctx, span := s.t.TraceStart(r.Context(), "RepoLog") - defer span.End() - - f, err := s.fullyResolvedRepo(r.WithContext(ctx)) + f, err := s.fullyResolvedRepo(r) if err != nil { log.Println("failed to fully resolve repo", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to fully resolve repo") return } @@ -176,29 +149,22 @@ } } ref := chi.URLParam(r, "ref") - span.SetAttributes(attribute.Int("page", page), attribute.String("ref", ref)) us, err := NewUnsignedClient(f.Knot, s.config.Dev) if err != nil { log.Println("failed to create unsigned client", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to create unsigned client") return } resp, err := us.Log(f.OwnerDid(), f.RepoName, ref, page) if err != nil { log.Println("failed to reach knotserver", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to reach knotserver") return } body, err := io.ReadAll(resp.Body) if err != nil { log.Printf("error reading response body: %v", err) - span.RecordError(err) - span.SetStatus(codes.Error, "error reading response body") return } @@ -206,18 +172,12 @@ var repolog types.RepoLogResponse err = json.Unmarshal(body, &repolog) if err != nil { log.Println("failed to parse json response", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to parse json response") return } - - span.SetAttributes(attribute.Int("commits.count", len(repolog.Commits))) result, err := us.Tags(f.OwnerDid(), f.RepoName) if err != nil { log.Println("failed to reach knotserver", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to reach knotserver for tags") return } @@ -230,13 +190,11 @@ } tagMap[hash] = append(tagMap[hash], tag.Name) } - span.SetAttributes(attribute.Int("tags.count", len(result.Tags))) - user := s.auth.GetUser(r) s.pages.RepoLog(w, pages.RepoLogParams{ LoggedInUser: user, TagMap: tagMap, - RepoInfo: f.RepoInfo(ctx, s, user), + RepoInfo: f.RepoInfo(s, user), RepoLogResponse: repolog, EmailToDidOrHandle: EmailToDidOrHandle(s, uniqueEmails(repolog.Commits)), }) @@ -244,10 +202,7 @@ return } func (s *State) RepoDescriptionEdit(w http.ResponseWriter, r *http.Request) { - ctx, span := s.t.TraceStart(r.Context(), "RepoDescriptionEdit") - defer span.End() - - f, err := s.fullyResolvedRepo(r.WithContext(ctx)) + f, err := s.fullyResolvedRepo(r) if err != nil { log.Println("failed to get repo and knot", err) w.WriteHeader(http.StatusBadRequest) @@ -256,20 +211,15 @@ } user := s.auth.GetUser(r) s.pages.EditRepoDescriptionFragment(w, pages.RepoDescriptionParams{ - RepoInfo: f.RepoInfo(ctx, s, user), + RepoInfo: f.RepoInfo(s, user), }) return } func (s *State) RepoDescription(w http.ResponseWriter, r *http.Request) { - ctx, span := s.t.TraceStart(r.Context(), "RepoDescription") - defer span.End() - - f, err := s.fullyResolvedRepo(r.WithContext(ctx)) + f, err := s.fullyResolvedRepo(r) if err != nil { log.Println("failed to get repo and knot", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to resolve repo") w.WriteHeader(http.StatusBadRequest) return } @@ -278,33 +228,27 @@ repoAt := f.RepoAt rkey := repoAt.RecordKey().String() if rkey == "" { log.Println("invalid aturi for repo", err) - span.RecordError(err) - span.SetStatus(codes.Error, "invalid aturi for repo") w.WriteHeader(http.StatusInternalServerError) return } user := s.auth.GetUser(r) - span.SetAttributes(attribute.String("method", r.Method)) switch r.Method { case http.MethodGet: s.pages.RepoDescriptionFragment(w, pages.RepoDescriptionParams{ - RepoInfo: f.RepoInfo(ctx, s, user), + RepoInfo: f.RepoInfo(s, user), }) return case http.MethodPut: user := s.auth.GetUser(r) newDescription := r.FormValue("description") - span.SetAttributes(attribute.String("description", newDescription)) client, _ := s.auth.AuthorizedClient(r) // optimistic update - err = db.UpdateDescription(ctx, s.db, string(repoAt), newDescription) + err = db.UpdateDescription(s.db, string(repoAt), newDescription) if err != nil { - log.Println("failed to perform update-description query", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to update description in database") + log.Println("failed to perferom update-description query", err) s.pages.Notice(w, "repo-notice", "Failed to update description, try again later.") return } @@ -312,16 +256,13 @@ // this is a bit of a pain because the golang atproto impl does not allow nil SwapRecord field // // SwapRecord is optional and should happen automagically, but given that it does not, we have to perform two requests - ex, err := comatproto.RepoGetRecord(ctx, client, "", tangled.RepoNSID, user.Did, rkey) + ex, err := comatproto.RepoGetRecord(r.Context(), client, "", tangled.RepoNSID, user.Did, rkey) if err != nil { // failed to get record - span.RecordError(err) - span.SetStatus(codes.Error, "failed to get record from PDS") s.pages.Notice(w, "repo-notice", "Failed to update description, no record found on PDS.") return } - - _, err = comatproto.RepoPutRecord(ctx, client, &comatproto.RepoPutRecord_Input{ + _, err = comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{ Collection: tangled.RepoNSID, Repo: user.Did, Rkey: rkey, @@ -338,15 +279,13 @@ }, }) if err != nil { - log.Println("failed to perform update-description query", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to put record to PDS") + log.Println("failed to perferom update-description query", err) // failed to get record s.pages.Notice(w, "repo-notice", "Failed to update description, unable to save to PDS.") return } - newRepoInfo := f.RepoInfo(ctx, s, user) + newRepoInfo := f.RepoInfo(s, user) newRepoInfo.Description = newDescription s.pages.RepoDescriptionFragment(w, pages.RepoDescriptionParams{ @@ -357,14 +296,9 @@ } } func (s *State) RepoCommit(w http.ResponseWriter, r *http.Request) { - ctx, span := s.t.TraceStart(r.Context(), "RepoCommit") - defer span.End() - - f, err := s.fullyResolvedRepo(r.WithContext(ctx)) + f, err := s.fullyResolvedRepo(r) if err != nil { log.Println("failed to fully resolve repo", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to fully resolve repo") return } ref := chi.URLParam(r, "ref") @@ -373,30 +307,20 @@ if !s.config.Dev { protocol = "https" } - span.SetAttributes(attribute.String("ref", ref), attribute.String("protocol", protocol)) - if !plumbing.IsHash(ref) { - span.SetAttributes(attribute.Bool("invalid_hash", true)) s.pages.Error404(w) return } - requestURL := fmt.Sprintf("%s://%s/%s/%s/commit/%s", protocol, f.Knot, f.OwnerDid(), f.RepoName, ref) - span.SetAttributes(attribute.String("request_url", requestURL)) - - resp, err := http.Get(requestURL) + resp, err := http.Get(fmt.Sprintf("%s://%s/%s/%s/commit/%s", protocol, f.Knot, f.OwnerDid(), f.RepoName, ref)) if err != nil { log.Println("failed to reach knotserver", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to reach knotserver") return } body, err := io.ReadAll(resp.Body) if err != nil { log.Printf("Error reading response body: %v", err) - span.RecordError(err) - span.SetStatus(codes.Error, "error reading response body") return } @@ -404,15 +328,13 @@ var result types.RepoCommitResponse err = json.Unmarshal(body, &result) if err != nil { log.Println("failed to parse response:", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to parse response") return } user := s.auth.GetUser(r) s.pages.RepoCommit(w, pages.RepoCommitParams{ LoggedInUser: user, - RepoInfo: f.RepoInfo(ctx, s, user), + RepoInfo: f.RepoInfo(s, user), RepoCommitResponse: result, EmailToDidOrHandle: EmailToDidOrHandle(s, []string{result.Diff.Commit.Author.Email}), }) @@ -420,14 +342,9 @@ return } func (s *State) RepoTree(w http.ResponseWriter, r *http.Request) { - ctx, span := s.t.TraceStart(r.Context(), "RepoTree") - defer span.End() - - f, err := s.fullyResolvedRepo(r.WithContext(ctx)) + f, err := s.fullyResolvedRepo(r) if err != nil { log.Println("failed to fully resolve repo", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to fully resolve repo") return } @@ -437,29 +354,15 @@ protocol := "http" if !s.config.Dev { protocol = "https" } - - span.SetAttributes( - attribute.String("ref", ref), - attribute.String("tree_path", treePath), - attribute.String("protocol", protocol), - ) - - requestURL := fmt.Sprintf("%s://%s/%s/%s/tree/%s/%s", protocol, f.Knot, f.OwnerDid(), f.RepoName, ref, treePath) - span.SetAttributes(attribute.String("request_url", requestURL)) - - resp, err := http.Get(requestURL) + resp, err := http.Get(fmt.Sprintf("%s://%s/%s/%s/tree/%s/%s", protocol, f.Knot, f.OwnerDid(), f.RepoName, ref, treePath)) if err != nil { log.Println("failed to reach knotserver", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to reach knotserver") return } body, err := io.ReadAll(resp.Body) if err != nil { log.Printf("Error reading response body: %v", err) - span.RecordError(err) - span.SetStatus(codes.Error, "error reading response body") return } @@ -467,17 +370,13 @@ var result types.RepoTreeResponse err = json.Unmarshal(body, &result) if err != nil { log.Println("failed to parse response:", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to parse response") return } // redirects tree paths trying to access a blob; in this case the result.Files is unpopulated, // so we can safely redirect to the "parent" (which is the same file). if len(result.Files) == 0 && result.Parent == treePath { - redirectURL := fmt.Sprintf("/%s/blob/%s/%s", f.OwnerSlashRepo(), ref, result.Parent) - span.SetAttributes(attribute.String("redirect_url", redirectURL)) - http.Redirect(w, r, redirectURL, http.StatusFound) + http.Redirect(w, r, fmt.Sprintf("/%s/blob/%s/%s", f.OwnerSlashRepo(), ref, result.Parent), http.StatusFound) return } @@ -499,51 +398,36 @@ LoggedInUser: user, BreadCrumbs: breadcrumbs, BaseTreeLink: baseTreeLink, BaseBlobLink: baseBlobLink, - RepoInfo: f.RepoInfo(ctx, s, user), + RepoInfo: f.RepoInfo(s, user), RepoTreeResponse: result, }) return } func (s *State) RepoTags(w http.ResponseWriter, r *http.Request) { - ctx, span := s.t.TraceStart(r.Context(), "RepoTags") - defer span.End() - - f, err := s.fullyResolvedRepo(r.WithContext(ctx)) + f, err := s.fullyResolvedRepo(r) if err != nil { log.Println("failed to get repo and knot", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to get repo and knot") return } us, err := NewUnsignedClient(f.Knot, s.config.Dev) if err != nil { log.Println("failed to create unsigned client", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to create unsigned client") return } result, err := us.Tags(f.OwnerDid(), f.RepoName) if err != nil { log.Println("failed to reach knotserver", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to reach knotserver") return } - span.SetAttributes(attribute.Int("tags.count", len(result.Tags))) - artifacts, err := db.GetArtifact(s.db, db.Filter("repo_at", f.RepoAt)) if err != nil { log.Println("failed grab artifacts", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to grab artifacts") return } - - span.SetAttributes(attribute.Int("artifacts.count", len(artifacts))) // convert artifacts to map for easy UI building artifactMap := make(map[plumbing.Hash][]db.Artifact) @@ -567,12 +451,10 @@ danglingArtifacts = append(danglingArtifacts, a) } } - span.SetAttributes(attribute.Int("dangling_artifacts.count", len(danglingArtifacts))) - user := s.auth.GetUser(r) s.pages.RepoTags(w, pages.RepoTagsParams{ LoggedInUser: user, - RepoInfo: f.RepoInfo(ctx, s, user), + RepoInfo: f.RepoInfo(s, user), RepoTagsResponse: *result, ArtifactMap: artifactMap, DanglingArtifacts: danglingArtifacts, @@ -581,38 +463,27 @@ return } func (s *State) RepoBranches(w http.ResponseWriter, r *http.Request) { - ctx, span := s.t.TraceStart(r.Context(), "RepoBranches") - defer span.End() - - f, err := s.fullyResolvedRepo(r.WithContext(ctx)) + f, err := s.fullyResolvedRepo(r) if err != nil { log.Println("failed to get repo and knot", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to get repo and knot") return } us, err := NewUnsignedClient(f.Knot, s.config.Dev) if err != nil { log.Println("failed to create unsigned client", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to create unsigned client") return } resp, err := us.Branches(f.OwnerDid(), f.RepoName) if err != nil { log.Println("failed to reach knotserver", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to reach knotserver") return } body, err := io.ReadAll(resp.Body) if err != nil { log.Printf("Error reading response body: %v", err) - span.RecordError(err) - span.SetStatus(codes.Error, "error reading response body") return } @@ -620,12 +491,8 @@ var result types.RepoBranchesResponse err = json.Unmarshal(body, &result) if err != nil { log.Println("failed to parse response:", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to parse response") return } - - span.SetAttributes(attribute.Int("branches.count", len(result.Branches))) slices.SortFunc(result.Branches, func(a, b types.Branch) int { if a.IsDefault { @@ -647,21 +514,16 @@ user := s.auth.GetUser(r) s.pages.RepoBranches(w, pages.RepoBranchesParams{ LoggedInUser: user, - RepoInfo: f.RepoInfo(ctx, s, user), + RepoInfo: f.RepoInfo(s, user), RepoBranchesResponse: result, }) return } func (s *State) RepoBlob(w http.ResponseWriter, r *http.Request) { - ctx, span := s.t.TraceStart(r.Context(), "RepoBlob") - defer span.End() - - f, err := s.fullyResolvedRepo(r.WithContext(ctx)) + f, err := s.fullyResolvedRepo(r) if err != nil { log.Println("failed to get repo and knot", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to get repo and knot") return } @@ -671,29 +533,15 @@ protocol := "http" if !s.config.Dev { protocol = "https" } - - span.SetAttributes( - attribute.String("ref", ref), - attribute.String("file_path", filePath), - attribute.String("protocol", protocol), - ) - - requestURL := fmt.Sprintf("%s://%s/%s/%s/blob/%s/%s", protocol, f.Knot, f.OwnerDid(), f.RepoName, ref, filePath) - span.SetAttributes(attribute.String("request_url", requestURL)) - - resp, err := http.Get(requestURL) + resp, err := http.Get(fmt.Sprintf("%s://%s/%s/%s/blob/%s/%s", protocol, f.Knot, f.OwnerDid(), f.RepoName, ref, filePath)) if err != nil { log.Println("failed to reach knotserver", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to reach knotserver") return } body, err := io.ReadAll(resp.Body) if err != nil { log.Printf("Error reading response body: %v", err) - span.RecordError(err) - span.SetStatus(codes.Error, "error reading response body") return } @@ -701,8 +549,6 @@ var result types.RepoBlobResponse err = json.Unmarshal(body, &result) if err != nil { log.Println("failed to parse response:", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to parse response") return } @@ -722,16 +568,10 @@ renderToggle = true showRendered = r.URL.Query().Get("code") != "true" } - span.SetAttributes( - attribute.Bool("is_binary", result.IsBinary), - attribute.Bool("show_rendered", showRendered), - attribute.Bool("render_toggle", renderToggle), - ) - user := s.auth.GetUser(r) s.pages.RepoBlob(w, pages.RepoBlobParams{ LoggedInUser: user, - RepoInfo: f.RepoInfo(ctx, s, user), + RepoInfo: f.RepoInfo(s, user), RepoBlobResponse: result, BreadCrumbs: breadcrumbs, ShowRendered: showRendered, @@ -741,14 +581,9 @@ return } func (s *State) RepoBlobRaw(w http.ResponseWriter, r *http.Request) { - ctx, span := s.t.TraceStart(r.Context(), "RepoBlobRaw") - defer span.End() - - f, err := s.fullyResolvedRepo(r.WithContext(ctx)) + f, err := s.fullyResolvedRepo(r) if err != nil { log.Println("failed to get repo and knot", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to get repo and knot") return } @@ -759,29 +594,15 @@ protocol := "http" if !s.config.Dev { protocol = "https" } - - span.SetAttributes( - attribute.String("ref", ref), - attribute.String("file_path", filePath), - attribute.String("protocol", protocol), - ) - - requestURL := fmt.Sprintf("%s://%s/%s/%s/blob/%s/%s", protocol, f.Knot, f.OwnerDid(), f.RepoName, ref, filePath) - span.SetAttributes(attribute.String("request_url", requestURL)) - - resp, err := http.Get(requestURL) + resp, err := http.Get(fmt.Sprintf("%s://%s/%s/%s/blob/%s/%s", protocol, f.Knot, f.OwnerDid(), f.RepoName, ref, filePath)) if err != nil { log.Println("failed to reach knotserver", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to reach knotserver") return } body, err := io.ReadAll(resp.Body) if err != nil { log.Printf("Error reading response body: %v", err) - span.RecordError(err) - span.SetStatus(codes.Error, "error reading response body") return } @@ -789,12 +610,8 @@ var result types.RepoBlobResponse err = json.Unmarshal(body, &result) if err != nil { log.Println("failed to parse response:", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to parse response") return } - - span.SetAttributes(attribute.Bool("is_binary", result.IsBinary)) if result.IsBinary { w.Header().Set("Content-Type", "application/octet-stream") @@ -808,76 +625,53 @@ return } func (s *State) AddCollaborator(w http.ResponseWriter, r *http.Request) { - ctx, span := s.t.TraceStart(r.Context(), "AddCollaborator") - defer span.End() - - f, err := s.fullyResolvedRepo(r.WithContext(ctx)) + f, err := s.fullyResolvedRepo(r) if err != nil { log.Println("failed to get repo and knot", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to get repo and knot") return } collaborator := r.FormValue("collaborator") if collaborator == "" { - span.SetAttributes(attribute.String("error", "malformed_form")) http.Error(w, "malformed form", http.StatusBadRequest) return } - span.SetAttributes(attribute.String("collaborator", collaborator)) - - collaboratorIdent, err := s.resolver.ResolveIdent(ctx, collaborator) + collaboratorIdent, err := s.resolver.ResolveIdent(r.Context(), collaborator) if err != nil { - span.RecordError(err) - span.SetStatus(codes.Error, "failed to resolve collaborator") w.Write([]byte("failed to resolve collaborator did to a handle")) return } log.Printf("adding %s to %s\n", collaboratorIdent.Handle.String(), f.Knot) - span.SetAttributes( - attribute.String("collaborator_did", collaboratorIdent.DID.String()), - attribute.String("collaborator_handle", collaboratorIdent.Handle.String()), - ) // TODO: create an atproto record for this secret, err := db.GetRegistrationKey(s.db, f.Knot) if err != nil { log.Printf("no key found for domain %s: %s\n", f.Knot, err) - span.RecordError(err) - span.SetStatus(codes.Error, "no key found for domain") return } ksClient, err := NewSignedClient(f.Knot, secret, s.config.Dev) if err != nil { log.Println("failed to create client to ", f.Knot) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to create signed client") return } ksResp, err := ksClient.AddCollaborator(f.OwnerDid(), f.RepoName, collaboratorIdent.DID.String()) if err != nil { log.Printf("failed to make request to %s: %s", f.Knot, err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to make request to knotserver") return } if ksResp.StatusCode != http.StatusNoContent { - span.SetAttributes(attribute.Int("status_code", ksResp.StatusCode)) w.Write([]byte(fmt.Sprint("knotserver failed to add collaborator: ", err))) return } - tx, err := s.db.BeginTx(ctx, nil) + tx, err := s.db.BeginTx(r.Context(), nil) if err != nil { log.Println("failed to start tx") - span.RecordError(err) - span.SetStatus(codes.Error, "failed to start transaction") w.Write([]byte(fmt.Sprint("failed to add collaborator: ", err))) return } @@ -891,16 +685,12 @@ }() err = s.enforcer.AddCollaborator(collaboratorIdent.DID.String(), f.Knot, f.DidSlashRepo()) if err != nil { - span.RecordError(err) - span.SetStatus(codes.Error, "failed to add collaborator to enforcer") w.Write([]byte(fmt.Sprint("failed to add collaborator: ", err))) return } - err = db.AddCollaborator(ctx, s.db, collaboratorIdent.DID.String(), f.OwnerDid(), f.RepoName, f.Knot) + err = db.AddCollaborator(s.db, collaboratorIdent.DID.String(), f.OwnerDid(), f.RepoName, f.Knot) if err != nil { - span.RecordError(err) - span.SetStatus(codes.Error, "failed to add collaborator to database") w.Write([]byte(fmt.Sprint("failed to add collaborator: ", err))) return } @@ -908,8 +698,6 @@ err = tx.Commit() if err != nil { log.Println("failed to commit changes", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to commit transaction") http.Error(w, err.Error(), http.StatusInternalServerError) return } @@ -917,91 +705,65 @@ err = s.enforcer.E.SavePolicy() if err != nil { log.Println("failed to update ACLs", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to save enforcer policy") http.Error(w, err.Error(), http.StatusInternalServerError) return } w.Write([]byte(fmt.Sprint("added collaborator: ", collaboratorIdent.Handle.String()))) + } func (s *State) DeleteRepo(w http.ResponseWriter, r *http.Request) { - ctx, span := s.t.TraceStart(r.Context(), "DeleteRepo") - defer span.End() - user := s.auth.GetUser(r) - f, err := s.fullyResolvedRepo(r.WithContext(ctx)) + f, err := s.fullyResolvedRepo(r) if err != nil { log.Println("failed to get repo and knot", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to get repo and knot") return } - span.SetAttributes( - attribute.String("repo_name", f.RepoName), - attribute.String("knot", f.Knot), - attribute.String("owner_did", f.OwnerDid()), - ) - // remove record from pds xrpcClient, _ := s.auth.AuthorizedClient(r) repoRkey := f.RepoAt.RecordKey().String() - _, err = comatproto.RepoDeleteRecord(ctx, xrpcClient, &comatproto.RepoDeleteRecord_Input{ + _, err = comatproto.RepoDeleteRecord(r.Context(), xrpcClient, &comatproto.RepoDeleteRecord_Input{ Collection: tangled.RepoNSID, Repo: user.Did, Rkey: repoRkey, }) if err != nil { log.Printf("failed to delete record: %s", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to delete record from PDS") s.pages.Notice(w, "settings-delete", "Failed to delete repository from PDS.") return } log.Println("removed repo record ", f.RepoAt.String()) - span.SetAttributes(attribute.String("repo_at", f.RepoAt.String())) secret, err := db.GetRegistrationKey(s.db, f.Knot) if err != nil { log.Printf("no key found for domain %s: %s\n", f.Knot, err) - span.RecordError(err) - span.SetStatus(codes.Error, "no key found for domain") return } ksClient, err := NewSignedClient(f.Knot, secret, s.config.Dev) if err != nil { log.Println("failed to create client to ", f.Knot) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to create client") return } ksResp, err := ksClient.RemoveRepo(f.OwnerDid(), f.RepoName) if err != nil { log.Printf("failed to make request to %s: %s", f.Knot, err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to make request to knotserver") return } - span.SetAttributes(attribute.Int("ks_status_code", ksResp.StatusCode)) if ksResp.StatusCode != http.StatusNoContent { log.Println("failed to remove repo from knot, continuing anyway ", f.Knot) - span.SetAttributes(attribute.Bool("knot_remove_failed", true)) } else { log.Println("removed repo from knot ", f.Knot) - span.SetAttributes(attribute.Bool("knot_remove_success", true)) } - tx, err := s.db.BeginTx(ctx, nil) + tx, err := s.db.BeginTx(r.Context(), nil) if err != nil { log.Println("failed to start tx") - span.RecordError(err) - span.SetStatus(codes.Error, "failed to start transaction") w.Write([]byte(fmt.Sprint("failed to add collaborator: ", err))) return } @@ -1010,20 +772,15 @@ tx.Rollback() err = s.enforcer.E.LoadPolicy() if err != nil { log.Println("failed to rollback policies") - span.RecordError(err) } }() // remove collaborator RBAC repoCollaborators, err := s.enforcer.E.GetImplicitUsersForResourceByDomain(f.DidSlashRepo(), f.Knot) if err != nil { - span.RecordError(err) - span.SetStatus(codes.Error, "failed to get collaborators") s.pages.Notice(w, "settings-delete", "Failed to remove collaborators") return } - span.SetAttributes(attribute.Int("collaborators.count", len(repoCollaborators))) - for _, c := range repoCollaborators { did := c[0] s.enforcer.RemoveCollaborator(did, f.Knot, f.DidSlashRepo()) @@ -1033,17 +790,13 @@ // remove repo RBAC err = s.enforcer.RemoveRepo(f.OwnerDid(), f.Knot, f.DidSlashRepo()) if err != nil { - span.RecordError(err) - span.SetStatus(codes.Error, "failed to remove repo RBAC") s.pages.Notice(w, "settings-delete", "Failed to update RBAC rules") return } // remove repo from db - err = db.RemoveRepo(ctx, tx, f.OwnerDid(), f.RepoName) + err = db.RemoveRepo(tx, f.OwnerDid(), f.RepoName) if err != nil { - span.RecordError(err) - span.SetStatus(codes.Error, "failed to remove repo from db") s.pages.Notice(w, "settings-delete", "Failed to update appview") return } @@ -1052,8 +805,6 @@ err = tx.Commit() if err != nil { log.Println("failed to commit changes", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to commit transaction") http.Error(w, err.Error(), http.StatusInternalServerError) return } @@ -1061,8 +812,6 @@ err = s.enforcer.E.SavePolicy() if err != nil { log.Println("failed to update ACLs", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to save policy") http.Error(w, err.Error(), http.StatusInternalServerError) return } @@ -1071,59 +820,37 @@ s.pages.HxRedirect(w, fmt.Sprintf("/%s", f.OwnerDid())) } func (s *State) SetDefaultBranch(w http.ResponseWriter, r *http.Request) { - ctx, span := s.t.TraceStart(r.Context(), "SetDefaultBranch") - defer span.End() - - f, err := s.fullyResolvedRepo(r.WithContext(ctx)) + f, err := s.fullyResolvedRepo(r) if err != nil { log.Println("failed to get repo and knot", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to get repo and knot") return } branch := r.FormValue("branch") if branch == "" { - span.SetAttributes(attribute.Bool("malformed_form", true)) - span.SetStatus(codes.Error, "malformed form") http.Error(w, "malformed form", http.StatusBadRequest) return } - span.SetAttributes( - attribute.String("branch", branch), - attribute.String("repo_name", f.RepoName), - attribute.String("knot", f.Knot), - attribute.String("owner_did", f.OwnerDid()), - ) - secret, err := db.GetRegistrationKey(s.db, f.Knot) if err != nil { log.Printf("no key found for domain %s: %s\n", f.Knot, err) - span.RecordError(err) - span.SetStatus(codes.Error, "no key found for domain") return } ksClient, err := NewSignedClient(f.Knot, secret, s.config.Dev) if err != nil { log.Println("failed to create client to ", f.Knot) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to create client") return } ksResp, err := ksClient.SetDefaultBranch(f.OwnerDid(), f.RepoName, branch) if err != nil { log.Printf("failed to make request to %s: %s", f.Knot, err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to make request to knotserver") return } - span.SetAttributes(attribute.Int("ks_status_code", ksResp.StatusCode)) if ksResp.StatusCode != http.StatusNoContent { - span.SetStatus(codes.Error, "failed to set default branch") s.pages.Notice(w, "repo-settings", "Failed to set default branch. Try again later.") return } @@ -1132,35 +859,20 @@ w.Write([]byte(fmt.Sprint("default branch set to: ", branch))) } func (s *State) RepoSettings(w http.ResponseWriter, r *http.Request) { - ctx, span := s.t.TraceStart(r.Context(), "RepoSettings") - defer span.End() - - f, err := s.fullyResolvedRepo(r.WithContext(ctx)) + f, err := s.fullyResolvedRepo(r) if err != nil { log.Println("failed to get repo and knot", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to get repo and knot") return } - span.SetAttributes( - attribute.String("repo_name", f.RepoName), - attribute.String("knot", f.Knot), - attribute.String("owner_did", f.OwnerDid()), - attribute.String("method", r.Method), - ) - switch r.Method { case http.MethodGet: // for now, this is just pubkeys user := s.auth.GetUser(r) - repoCollaborators, err := f.Collaborators(ctx, s) + repoCollaborators, err := f.Collaborators(r.Context(), s) if err != nil { log.Println("failed to get collaborators", err) - span.RecordError(err) - span.SetAttributes(attribute.String("error", "failed_to_get_collaborators")) } - span.SetAttributes(attribute.Int("collaborators.count", len(repoCollaborators))) isCollaboratorInviteAllowed := false if user != nil { @@ -1169,41 +881,31 @@ if err == nil && ok { isCollaboratorInviteAllowed = true } } - span.SetAttributes(attribute.Bool("invite_allowed", isCollaboratorInviteAllowed)) var branchNames []string var defaultBranch string us, err := NewUnsignedClient(f.Knot, s.config.Dev) if err != nil { log.Println("failed to create unsigned client", err) - span.RecordError(err) - span.SetAttributes(attribute.String("error", "failed_to_create_unsigned_client")) } else { resp, err := us.Branches(f.OwnerDid(), f.RepoName) if err != nil { log.Println("failed to reach knotserver", err) - span.RecordError(err) - span.SetAttributes(attribute.String("error", "failed_to_reach_knotserver_for_branches")) } else { defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { log.Printf("Error reading response body: %v", err) - span.RecordError(err) - span.SetAttributes(attribute.String("error", "failed_to_read_branches_response")) } else { var result types.RepoBranchesResponse err = json.Unmarshal(body, &result) if err != nil { log.Println("failed to parse response:", err) - span.RecordError(err) - span.SetAttributes(attribute.String("error", "failed_to_parse_branches_response")) } else { for _, branch := range result.Branches { branchNames = append(branchNames, branch.Name) } - span.SetAttributes(attribute.Int("branches.count", len(branchNames))) } } } @@ -1211,16 +913,13 @@ defaultBranchResp, err := us.DefaultBranch(f.OwnerDid(), f.RepoName) if err != nil { log.Println("failed to reach knotserver", err) - span.RecordError(err) - span.SetAttributes(attribute.String("error", "failed_to_reach_knotserver_for_default_branch")) } else { defaultBranch = defaultBranchResp.Branch - span.SetAttributes(attribute.String("default_branch", defaultBranch)) } } s.pages.RepoSettings(w, pages.RepoSettingsParams{ LoggedInUser: user, - RepoInfo: f.RepoInfo(ctx, s, user), + RepoInfo: f.RepoInfo(s, user), Collaborators: repoCollaborators, IsCollaboratorInviteAllowed: isCollaboratorInviteAllowed, Branches: branchNames, @@ -1309,96 +1008,65 @@ return collaborators, nil } -func (f *FullyResolvedRepo) RepoInfo(ctx context.Context, s *State, u *auth.User) repoinfo.RepoInfo { - ctx, span := s.t.TraceStart(ctx, "RepoInfo") - defer span.End() - +func (f *FullyResolvedRepo) RepoInfo(s *State, u *auth.User) repoinfo.RepoInfo { isStarred := false if u != nil { isStarred = db.GetStarStatus(s.db, u.Did, syntax.ATURI(f.RepoAt)) - span.SetAttributes(attribute.Bool("is_starred", isStarred)) } starCount, err := db.GetStarCount(s.db, f.RepoAt) if err != nil { log.Println("failed to get star count for ", f.RepoAt) - span.RecordError(err) } - issueCount, err := db.GetIssueCount(s.db, f.RepoAt) if err != nil { log.Println("failed to get issue count for ", f.RepoAt) - span.RecordError(err) } - pullCount, err := db.GetPullCount(s.db, f.RepoAt) if err != nil { log.Println("failed to get issue count for ", f.RepoAt) - span.RecordError(err) } - - span.SetAttributes( - attribute.Int("stats.stars", starCount), - attribute.Int("stats.issues.open", issueCount.Open), - attribute.Int("stats.issues.closed", issueCount.Closed), - attribute.Int("stats.pulls.open", pullCount.Open), - attribute.Int("stats.pulls.closed", pullCount.Closed), - attribute.Int("stats.pulls.merged", pullCount.Merged), - ) - - source, err := db.GetRepoSource(ctx, s.db, f.RepoAt) + source, err := db.GetRepoSource(s.db, f.RepoAt) if errors.Is(err, sql.ErrNoRows) { source = "" } else if err != nil { log.Println("failed to get repo source for ", f.RepoAt, err) - span.RecordError(err) } var sourceRepo *db.Repo if source != "" { - span.SetAttributes(attribute.String("source", source)) - sourceRepo, err = db.GetRepoByAtUri(ctx, s.db, source) + sourceRepo, err = db.GetRepoByAtUri(s.db, source) if err != nil { log.Println("failed to get repo by at uri", err) - span.RecordError(err) } } var sourceHandle *identity.Identity if sourceRepo != nil { - sourceHandle, err = s.resolver.ResolveIdent(ctx, sourceRepo.Did) + sourceHandle, err = s.resolver.ResolveIdent(context.Background(), sourceRepo.Did) if err != nil { log.Println("failed to resolve source repo", err) - span.RecordError(err) - } else if sourceHandle != nil { - span.SetAttributes(attribute.String("source_handle", sourceHandle.Handle.String())) } } knot := f.Knot - span.SetAttributes(attribute.String("knot", knot)) - var disableFork bool us, err := NewUnsignedClient(knot, s.config.Dev) if err != nil { log.Printf("failed to create unsigned client for %s: %v", knot, err) - span.RecordError(err) } else { resp, err := us.Branches(f.OwnerDid(), f.RepoName) if err != nil { log.Printf("failed to get branches for %s/%s: %v", f.OwnerDid(), f.RepoName, err) - span.RecordError(err) } else { defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { log.Printf("error reading branch response body: %v", err) - span.RecordError(err) } else { var branchesResp types.RepoBranchesResponse if err := json.Unmarshal(body, &branchesResp); err != nil { log.Printf("error parsing branch response: %v", err) - span.RecordError(err) } else { disableFork = false } @@ -1406,10 +1074,6 @@ if len(branchesResp.Branches) == 0 { disableFork = true } - span.SetAttributes( - attribute.Int("branches.count", len(branchesResp.Branches)), - attribute.Bool("disable_fork", disableFork), - ) } } } @@ -1441,15 +1105,10 @@ return repoInfo } func (s *State) RepoSingleIssue(w http.ResponseWriter, r *http.Request) { - ctx, span := s.t.TraceStart(r.Context(), "RepoSingleIssue") - defer span.End() - user := s.auth.GetUser(r) - f, err := s.fullyResolvedRepo(r.WithContext(ctx)) + f, err := s.fullyResolvedRepo(r) if err != nil { log.Println("failed to get repo and knot", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to resolve repo") return } @@ -1458,40 +1117,26 @@ issueIdInt, err := strconv.Atoi(issueId) if err != nil { http.Error(w, "bad issue id", http.StatusBadRequest) log.Println("failed to parse issue id", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to parse issue id") return } - span.SetAttributes(attribute.Int("issue_id", issueIdInt)) - - issue, comments, err := db.GetIssueWithComments(ctx, s.db, f.RepoAt, issueIdInt) + issue, comments, err := db.GetIssueWithComments(s.db, f.RepoAt, issueIdInt) if err != nil { log.Println("failed to get issue and comments", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to get issue and comments") s.pages.Notice(w, "issues", "Failed to load issue. Try again later.") return } - span.SetAttributes( - attribute.Int("comments.count", len(comments)), - attribute.String("issue.title", issue.Title), - attribute.String("issue.owner_did", issue.OwnerDid), - ) - - issueOwnerIdent, err := s.resolver.ResolveIdent(ctx, issue.OwnerDid) + issueOwnerIdent, err := s.resolver.ResolveIdent(r.Context(), issue.OwnerDid) if err != nil { log.Println("failed to resolve issue owner", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to resolve issue owner") } identsToResolve := make([]string, len(comments)) for i, comment := range comments { identsToResolve[i] = comment.OwnerDid } - resolvedIds := s.resolver.ResolveIdents(ctx, identsToResolve) + resolvedIds := s.resolver.ResolveIdents(r.Context(), identsToResolve) didHandleMap := make(map[string]string) for _, identity := range resolvedIds { if !identity.Handle.IsInvalidHandle() { @@ -1503,25 +1148,21 @@ } s.pages.RepoSingleIssue(w, pages.RepoSingleIssueParams{ LoggedInUser: user, - RepoInfo: f.RepoInfo(ctx, s, user), + RepoInfo: f.RepoInfo(s, user), Issue: *issue, Comments: comments, IssueOwnerHandle: issueOwnerIdent.Handle.String(), DidHandleMap: didHandleMap, }) + } func (s *State) CloseIssue(w http.ResponseWriter, r *http.Request) { - ctx, span := s.t.TraceStart(r.Context(), "CloseIssue") - defer span.End() - user := s.auth.GetUser(r) - f, err := s.fullyResolvedRepo(r.WithContext(ctx)) + f, err := s.fullyResolvedRepo(r) if err != nil { log.Println("failed to get repo and knot", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to resolve repo") return } @@ -1530,44 +1171,32 @@ issueIdInt, err := strconv.Atoi(issueId) if err != nil { http.Error(w, "bad issue id", http.StatusBadRequest) log.Println("failed to parse issue id", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to parse issue id") return } - span.SetAttributes(attribute.Int("issue_id", issueIdInt)) - - issue, err := db.GetIssue(ctx, s.db, f.RepoAt, issueIdInt) + issue, err := db.GetIssue(s.db, f.RepoAt, issueIdInt) if err != nil { log.Println("failed to get issue", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to get issue") s.pages.Notice(w, "issue-action", "Failed to close issue. Try again later.") return } - collaborators, err := f.Collaborators(ctx, s) + collaborators, err := f.Collaborators(r.Context(), s) if err != nil { log.Println("failed to fetch repo collaborators: %w", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to fetch repo collaborators") } isCollaborator := slices.ContainsFunc(collaborators, func(collab pages.Collaborator) bool { return user.Did == collab.Did }) isIssueOwner := user.Did == issue.OwnerDid - span.SetAttributes( - attribute.Bool("is_collaborator", isCollaborator), - attribute.Bool("is_issue_owner", isIssueOwner), - ) - // TODO: make this more granular if isIssueOwner || isCollaborator { + closed := tangled.RepoIssueStateClosed client, _ := s.auth.AuthorizedClient(r) - _, err = comatproto.RepoPutRecord(ctx, client, &comatproto.RepoPutRecord_Input{ + _, err = comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{ Collection: tangled.RepoIssueStateNSID, Repo: user.Did, Rkey: appview.TID(), @@ -1581,8 +1210,6 @@ }) if err != nil { log.Println("failed to update issue state", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to update issue state in PDS") s.pages.Notice(w, "issue-action", "Failed to close issue. Try again later.") return } @@ -1590,8 +1217,6 @@ err := db.CloseIssue(s.db, f.RepoAt, issueIdInt) if err != nil { log.Println("failed to close issue", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to close issue in database") s.pages.Notice(w, "issue-action", "Failed to close issue. Try again later.") return } @@ -1600,22 +1225,16 @@ s.pages.HxLocation(w, fmt.Sprintf("/%s/issues/%d", f.OwnerSlashRepo(), issueIdInt)) return } else { log.Println("user is not permitted to close issue") - span.SetAttributes(attribute.Bool("permission_denied", true)) http.Error(w, "for biden", http.StatusUnauthorized) return } } func (s *State) ReopenIssue(w http.ResponseWriter, r *http.Request) { - ctx, span := s.t.TraceStart(r.Context(), "ReopenIssue") - defer span.End() - user := s.auth.GetUser(r) - f, err := s.fullyResolvedRepo(r.WithContext(ctx)) + f, err := s.fullyResolvedRepo(r) if err != nil { log.Println("failed to get repo and knot", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to resolve repo") return } @@ -1624,44 +1243,29 @@ issueIdInt, err := strconv.Atoi(issueId) if err != nil { http.Error(w, "bad issue id", http.StatusBadRequest) log.Println("failed to parse issue id", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to parse issue id") return } - span.SetAttributes(attribute.Int("issue_id", issueIdInt)) - - issue, err := db.GetIssue(ctx, s.db, f.RepoAt, issueIdInt) + issue, err := db.GetIssue(s.db, f.RepoAt, issueIdInt) if err != nil { log.Println("failed to get issue", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to get issue") s.pages.Notice(w, "issue-action", "Failed to close issue. Try again later.") return } - collaborators, err := f.Collaborators(ctx, s) + collaborators, err := f.Collaborators(r.Context(), s) if err != nil { log.Println("failed to fetch repo collaborators: %w", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to fetch repo collaborators") } isCollaborator := slices.ContainsFunc(collaborators, func(collab pages.Collaborator) bool { return user.Did == collab.Did }) isIssueOwner := user.Did == issue.OwnerDid - - span.SetAttributes( - attribute.Bool("is_collaborator", isCollaborator), - attribute.Bool("is_issue_owner", isIssueOwner), - ) if isCollaborator || isIssueOwner { err := db.ReopenIssue(s.db, f.RepoAt, issueIdInt) if err != nil { log.Println("failed to reopen issue", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to reopen issue") s.pages.Notice(w, "issue-action", "Failed to reopen issue. Try again later.") return } @@ -1669,22 +1273,16 @@ s.pages.HxLocation(w, fmt.Sprintf("/%s/issues/%d", f.OwnerSlashRepo(), issueIdInt)) return } else { log.Println("user is not the owner of the repo") - span.SetAttributes(attribute.Bool("permission_denied", true)) http.Error(w, "forbidden", http.StatusUnauthorized) return } } func (s *State) NewIssueComment(w http.ResponseWriter, r *http.Request) { - ctx, span := s.t.TraceStart(r.Context(), "NewIssueComment") - defer span.End() - user := s.auth.GetUser(r) - f, err := s.fullyResolvedRepo(r.WithContext(ctx)) + f, err := s.fullyResolvedRepo(r) if err != nil { log.Println("failed to get repo and knot", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to resolve repo") return } @@ -1693,21 +1291,13 @@ issueIdInt, err := strconv.Atoi(issueId) if err != nil { http.Error(w, "bad issue id", http.StatusBadRequest) log.Println("failed to parse issue id", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to parse issue id") return } - span.SetAttributes( - attribute.Int("issue_id", issueIdInt), - attribute.String("method", r.Method), - ) - switch r.Method { case http.MethodPost: body := r.FormValue("body") if body == "" { - span.SetAttributes(attribute.Bool("missing_body", true)) s.pages.Notice(w, "issue", "Body is required") return } @@ -1715,11 +1305,6 @@ commentId := mathrand.IntN(1000000) rkey := appview.TID() - span.SetAttributes( - attribute.Int("comment_id", commentId), - attribute.String("rkey", rkey), - ) - err := db.NewIssueComment(s.db, &db.Comment{ OwnerDid: user.Did, RepoAt: f.RepoAt, @@ -1730,8 +1315,6 @@ Rkey: rkey, }) if err != nil { log.Println("failed to create comment", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to create comment in database") s.pages.Notice(w, "issue-comment", "Failed to create comment.") return } @@ -1742,17 +1325,13 @@ ownerDid := user.Did issueAt, err := db.GetIssueAt(s.db, f.RepoAt, issueIdInt) if err != nil { log.Println("failed to get issue at", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to get issue at") s.pages.Notice(w, "issue-comment", "Failed to create comment.") return } - span.SetAttributes(attribute.String("issue_at", issueAt)) - atUri := f.RepoAt.String() client, _ := s.auth.AuthorizedClient(r) - _, err = comatproto.RepoPutRecord(ctx, client, &comatproto.RepoPutRecord_Input{ + _, err = comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{ Collection: tangled.RepoIssueCommentNSID, Repo: user.Did, Rkey: rkey, @@ -1769,8 +1348,6 @@ }, }) if err != nil { log.Println("failed to create comment", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to create comment in PDS") s.pages.Notice(w, "issue-comment", "Failed to create comment.") return } @@ -1781,15 +1358,10 @@ } } func (s *State) IssueComment(w http.ResponseWriter, r *http.Request) { - ctx, span := s.t.TraceStart(r.Context(), "IssueComment") - defer span.End() - user := s.auth.GetUser(r) - f, err := s.fullyResolvedRepo(r.WithContext(ctx)) + f, err := s.fullyResolvedRepo(r) if err != nil { log.Println("failed to get repo and knot", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to resolve repo") return } @@ -1798,8 +1370,6 @@ issueIdInt, err := strconv.Atoi(issueId) if err != nil { http.Error(w, "bad issue id", http.StatusBadRequest) log.Println("failed to parse issue id", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to parse issue id") return } @@ -1808,21 +1378,12 @@ commentIdInt, err := strconv.Atoi(commentId) if err != nil { http.Error(w, "bad comment id", http.StatusBadRequest) log.Println("failed to parse issue id", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to parse comment id") return } - span.SetAttributes( - attribute.Int("issue_id", issueIdInt), - attribute.Int("comment_id", commentIdInt), - ) - - issue, err := db.GetIssue(ctx, s.db, f.RepoAt, issueIdInt) + issue, err := db.GetIssue(s.db, f.RepoAt, issueIdInt) if err != nil { log.Println("failed to get issue", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to get issue") s.pages.Notice(w, "issues", "Failed to load issue. Try again later.") return } @@ -1830,16 +1391,12 @@ comment, err := db.GetComment(s.db, f.RepoAt, issueIdInt, commentIdInt) if err != nil { http.Error(w, "bad comment id", http.StatusBadRequest) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to get comment") return } - identity, err := s.resolver.ResolveIdent(ctx, comment.OwnerDid) + identity, err := s.resolver.ResolveIdent(r.Context(), comment.OwnerDid) if err != nil { log.Println("failed to resolve did") - span.RecordError(err) - span.SetStatus(codes.Error, "failed to resolve did") return } @@ -1852,7 +1409,7 @@ } s.pages.SingleIssueCommentFragment(w, pages.SingleIssueCommentParams{ LoggedInUser: user, - RepoInfo: f.RepoInfo(ctx, s, user), + RepoInfo: f.RepoInfo(s, user), DidHandleMap: didHandleMap, Issue: issue, Comment: comment, @@ -1860,15 +1417,10 @@ }) } func (s *State) EditIssueComment(w http.ResponseWriter, r *http.Request) { - ctx, span := s.t.TraceStart(r.Context(), "EditIssueComment") - defer span.End() - user := s.auth.GetUser(r) - f, err := s.fullyResolvedRepo(r.WithContext(ctx)) + f, err := s.fullyResolvedRepo(r) if err != nil { log.Println("failed to get repo and knot", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to resolve repo") return } @@ -1877,8 +1429,6 @@ issueIdInt, err := strconv.Atoi(issueId) if err != nil { http.Error(w, "bad issue id", http.StatusBadRequest) log.Println("failed to parse issue id", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to parse issue id") return } @@ -1887,22 +1437,12 @@ commentIdInt, err := strconv.Atoi(commentId) if err != nil { http.Error(w, "bad comment id", http.StatusBadRequest) log.Println("failed to parse issue id", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to parse comment id") return } - span.SetAttributes( - attribute.Int("issue_id", issueIdInt), - attribute.Int("comment_id", commentIdInt), - attribute.String("method", r.Method), - ) - - issue, err := db.GetIssue(ctx, s.db, f.RepoAt, issueIdInt) + issue, err := db.GetIssue(s.db, f.RepoAt, issueIdInt) if err != nil { log.Println("failed to get issue", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to get issue") s.pages.Notice(w, "issues", "Failed to load issue. Try again later.") return } @@ -1910,14 +1450,11 @@ comment, err := db.GetComment(s.db, f.RepoAt, issueIdInt, commentIdInt) if err != nil { http.Error(w, "bad comment id", http.StatusBadRequest) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to get comment") return } if comment.OwnerDid != user.Did { http.Error(w, "you are not the author of this comment", http.StatusUnauthorized) - span.SetAttributes(attribute.Bool("permission_denied", true)) return } @@ -1925,7 +1462,7 @@ switch r.Method { case http.MethodGet: s.pages.EditIssueCommentFragment(w, pages.EditIssueCommentParams{ LoggedInUser: user, - RepoInfo: f.RepoInfo(ctx, s, user), + RepoInfo: f.RepoInfo(s, user), Issue: issue, Comment: comment, }) @@ -1935,18 +1472,11 @@ newBody := r.FormValue("body") client, _ := s.auth.AuthorizedClient(r) rkey := comment.Rkey - span.SetAttributes( - attribute.String("new_body", newBody), - attribute.String("rkey", rkey), - ) - // optimistic update edited := time.Now() err = db.EditComment(s.db, comment.RepoAt, comment.Issue, comment.CommentId, newBody) if err != nil { log.Println("failed to perferom update-description query", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to edit comment in database") s.pages.Notice(w, "repo-notice", "Failed to update description, try again later.") return } @@ -1954,12 +1484,10 @@ // rkey is optional, it was introduced later if comment.Rkey != "" { // update the record on pds - ex, err := comatproto.RepoGetRecord(ctx, client, "", tangled.RepoIssueCommentNSID, user.Did, rkey) + ex, err := comatproto.RepoGetRecord(r.Context(), client, "", tangled.RepoIssueCommentNSID, user.Did, rkey) if err != nil { // failed to get record log.Println(err, rkey) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to get record from PDS") s.pages.Notice(w, fmt.Sprintf("comment-%s-status", commentId), "Failed to update description, no record found on PDS.") return } @@ -1971,7 +1499,7 @@ issueAt := record["issue"].(string) createdAt := record["createdAt"].(string) commentIdInt64 := int64(commentIdInt) - _, err = comatproto.RepoPutRecord(ctx, client, &comatproto.RepoPutRecord_Input{ + _, err = comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{ Collection: tangled.RepoIssueCommentNSID, Repo: user.Did, Rkey: rkey, @@ -1989,8 +1517,6 @@ }, }) if err != nil { log.Println(err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to put record to PDS") } } @@ -2004,25 +1530,22 @@ // return new comment body with htmx s.pages.SingleIssueCommentFragment(w, pages.SingleIssueCommentParams{ LoggedInUser: user, - RepoInfo: f.RepoInfo(ctx, s, user), + RepoInfo: f.RepoInfo(s, user), DidHandleMap: didHandleMap, Issue: issue, Comment: comment, }) return + } + } func (s *State) DeleteIssueComment(w http.ResponseWriter, r *http.Request) { - ctx, span := s.t.TraceStart(r.Context(), "DeleteIssueComment") - defer span.End() - user := s.auth.GetUser(r) - f, err := s.fullyResolvedRepo(r.WithContext(ctx)) + f, err := s.fullyResolvedRepo(r) if err != nil { log.Println("failed to get repo and knot", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to resolve repo") return } @@ -2031,16 +1554,12 @@ issueIdInt, err := strconv.Atoi(issueId) if err != nil { http.Error(w, "bad issue id", http.StatusBadRequest) log.Println("failed to parse issue id", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to parse issue id") return } - issue, err := db.GetIssue(ctx, s.db, f.RepoAt, issueIdInt) + issue, err := db.GetIssue(s.db, f.RepoAt, issueIdInt) if err != nil { log.Println("failed to get issue", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to get issue") s.pages.Notice(w, "issues", "Failed to load issue. Try again later.") return } @@ -2050,33 +1569,22 @@ commentIdInt, err := strconv.Atoi(commentId) if err != nil { http.Error(w, "bad comment id", http.StatusBadRequest) log.Println("failed to parse issue id", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to parse comment id") return } - span.SetAttributes( - attribute.Int("issue_id", issueIdInt), - attribute.Int("comment_id", commentIdInt), - ) - comment, err := db.GetComment(s.db, f.RepoAt, issueIdInt, commentIdInt) if err != nil { http.Error(w, "bad comment id", http.StatusBadRequest) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to get comment") return } if comment.OwnerDid != user.Did { http.Error(w, "you are not the author of this comment", http.StatusUnauthorized) - span.SetAttributes(attribute.Bool("permission_denied", true)) return } if comment.Deleted != nil { http.Error(w, "comment already deleted", http.StatusBadRequest) - span.SetAttributes(attribute.Bool("already_deleted", true)) return } @@ -2085,8 +1593,6 @@ deleted := time.Now() err = db.DeleteComment(s.db, f.RepoAt, issueIdInt, commentIdInt) if err != nil { log.Println("failed to delete comment") - span.RecordError(err) - span.SetStatus(codes.Error, "failed to delete comment in database") s.pages.Notice(w, fmt.Sprintf("comment-%s-status", commentId), "failed to delete comment") return } @@ -2094,15 +1600,13 @@ // delete from pds if comment.Rkey != "" { client, _ := s.auth.AuthorizedClient(r) - _, err = comatproto.RepoDeleteRecord(ctx, client, &comatproto.RepoDeleteRecord_Input{ + _, err = comatproto.RepoDeleteRecord(r.Context(), client, &comatproto.RepoDeleteRecord_Input{ Collection: tangled.GraphFollowNSID, Repo: user.Did, Rkey: comment.Rkey, }) if err != nil { log.Println(err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to delete record from PDS") } } @@ -2116,7 +1620,7 @@ // htmx fragment of comment after deletion s.pages.SingleIssueCommentFragment(w, pages.SingleIssueCommentParams{ LoggedInUser: user, - RepoInfo: f.RepoInfo(ctx, s, user), + RepoInfo: f.RepoInfo(s, user), DidHandleMap: didHandleMap, Issue: issue, Comment: comment, @@ -2125,9 +1629,6 @@ return } func (s *State) RepoIssues(w http.ResponseWriter, r *http.Request) { - ctx, span := s.t.TraceStart(r.Context(), "RepoIssues") - defer span.End() - params := r.URL.Query() state := params.Get("state") isOpen := true @@ -2140,43 +1641,31 @@ default: isOpen = true } - span.SetAttributes( - attribute.Bool("is_open", isOpen), - attribute.String("state_param", state), - ) - page, ok := r.Context().Value("page").(pagination.Page) if !ok { log.Println("failed to get page") - span.SetAttributes(attribute.Bool("page_not_found", true)) page = pagination.FirstPage() } user := s.auth.GetUser(r) - f, err := s.fullyResolvedRepo(r.WithContext(ctx)) + f, err := s.fullyResolvedRepo(r) if err != nil { log.Println("failed to get repo and knot", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to resolve repo") return } - issues, err := db.GetIssues(ctx, s.db, f.RepoAt, isOpen, page) + issues, err := db.GetIssues(s.db, f.RepoAt, isOpen, page) if err != nil { log.Println("failed to get issues", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to get issues") s.pages.Notice(w, "issues", "Failed to load issues. Try again later.") return } - span.SetAttributes(attribute.Int("issues.count", len(issues))) - identsToResolve := make([]string, len(issues)) for i, issue := range issues { identsToResolve[i] = issue.OwnerDid } - resolvedIds := s.resolver.ResolveIdents(ctx, identsToResolve) + resolvedIds := s.resolver.ResolveIdents(r.Context(), identsToResolve) didHandleMap := make(map[string]string) for _, identity := range resolvedIds { if !identity.Handle.IsInvalidHandle() { @@ -2188,7 +1677,7 @@ } s.pages.RepoIssues(w, pages.RepoIssuesParams{ LoggedInUser: s.auth.GetUser(r), - RepoInfo: f.RepoInfo(ctx, s, user), + RepoInfo: f.RepoInfo(s, user), Issues: issues, DidHandleMap: didHandleMap, FilteringByOpen: isOpen, @@ -2198,46 +1687,31 @@ return } func (s *State) NewIssue(w http.ResponseWriter, r *http.Request) { - ctx, span := s.t.TraceStart(r.Context(), "NewIssue") - defer span.End() - user := s.auth.GetUser(r) - f, err := s.fullyResolvedRepo(r.WithContext(ctx)) + f, err := s.fullyResolvedRepo(r) if err != nil { log.Println("failed to get repo and knot", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to resolve repo") return } - - span.SetAttributes(attribute.String("method", r.Method)) switch r.Method { case http.MethodGet: s.pages.RepoNewIssue(w, pages.RepoNewIssueParams{ LoggedInUser: user, - RepoInfo: f.RepoInfo(ctx, s, user), + RepoInfo: f.RepoInfo(s, user), }) case http.MethodPost: title := r.FormValue("title") body := r.FormValue("body") - span.SetAttributes( - attribute.String("title", title), - attribute.String("body_length", fmt.Sprintf("%d", len(body))), - ) - if title == "" || body == "" { - span.SetAttributes(attribute.Bool("form_validation_failed", true)) s.pages.Notice(w, "issues", "Title and body are required") return } - tx, err := s.db.BeginTx(ctx, nil) + tx, err := s.db.BeginTx(r.Context(), nil) if err != nil { - span.RecordError(err) - span.SetStatus(codes.Error, "failed to begin transaction") s.pages.Notice(w, "issues", "Failed to create issue, try again later") return } @@ -2250,8 +1724,6 @@ OwnerDid: user.Did, }) if err != nil { log.Println("failed to create issue", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to create issue in database") s.pages.Notice(w, "issues", "Failed to create issue.") return } @@ -2259,23 +1731,16 @@ issueId, err := db.GetIssueId(s.db, f.RepoAt) if err != nil { log.Println("failed to get issue id", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to get issue id") s.pages.Notice(w, "issues", "Failed to create issue.") return } - span.SetAttributes(attribute.Int("issue_id", issueId)) - client, _ := s.auth.AuthorizedClient(r) atUri := f.RepoAt.String() - rkey := appview.TID() - span.SetAttributes(attribute.String("rkey", rkey)) - - resp, err := comatproto.RepoPutRecord(ctx, client, &comatproto.RepoPutRecord_Input{ + resp, err := comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{ Collection: tangled.RepoIssueNSID, Repo: user.Did, - Rkey: rkey, + Rkey: appview.TID(), Record: &lexutil.LexiconTypeDecoder{ Val: &tangled.RepoIssue{ Repo: atUri, @@ -2288,19 +1753,13 @@ }, }) if err != nil { log.Println("failed to create issue", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to create issue in PDS") s.pages.Notice(w, "issues", "Failed to create issue.") return } - span.SetAttributes(attribute.String("issue_uri", resp.Uri)) - err = db.SetIssueAt(s.db, f.RepoAt, issueId, resp.Uri) if err != nil { log.Println("failed to set issue at", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to set issue URI in database") s.pages.Notice(w, "issues", "Failed to create issue.") return } @@ -2311,102 +1770,67 @@ } } func (s *State) ForkRepo(w http.ResponseWriter, r *http.Request) { - ctx, span := s.t.TraceStart(r.Context(), "ForkRepo") - defer span.End() - user := s.auth.GetUser(r) - f, err := s.fullyResolvedRepo(r.WithContext(ctx)) + f, err := s.fullyResolvedRepo(r) if err != nil { log.Printf("failed to resolve source repo: %v", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to resolve source repo") return } - span.SetAttributes( - attribute.String("method", r.Method), - attribute.String("repo_name", f.RepoName), - attribute.String("owner_did", f.OwnerDid()), - attribute.String("knot", f.Knot), - ) - switch r.Method { case http.MethodGet: user := s.auth.GetUser(r) knots, err := s.enforcer.GetDomainsForUser(user.Did) if err != nil { - span.RecordError(err) - span.SetStatus(codes.Error, "failed to get domains for user") s.pages.Notice(w, "repo", "Invalid user account.") return } - span.SetAttributes(attribute.Int("knots.count", len(knots))) - s.pages.ForkRepo(w, pages.ForkRepoParams{ LoggedInUser: user, Knots: knots, - RepoInfo: f.RepoInfo(ctx, s, user), + RepoInfo: f.RepoInfo(s, user), }) case http.MethodPost: + knot := r.FormValue("knot") if knot == "" { - span.SetAttributes(attribute.Bool("missing_knot", true)) s.pages.Notice(w, "repo", "Invalid form submission—missing knot domain.") return } - span.SetAttributes(attribute.String("target_knot", knot)) - ok, err := s.enforcer.E.Enforce(user.Did, knot, knot, "repo:create") if err != nil || !ok { - span.SetAttributes( - attribute.Bool("permission_denied", true), - attribute.Bool("enforce_error", err != nil), - ) s.pages.Notice(w, "repo", "You do not have permission to create a repo in this knot.") return } forkName := fmt.Sprintf("%s", f.RepoName) - span.SetAttributes(attribute.String("fork_name", forkName)) // this check is *only* to see if the forked repo name already exists // in the user's account. - existingRepo, err := db.GetRepo(ctx, s.db, user.Did, f.RepoName) + existingRepo, err := db.GetRepo(s.db, user.Did, f.RepoName) if err != nil { if errors.Is(err, sql.ErrNoRows) { // no existing repo with this name found, we can use the name as is - span.SetAttributes(attribute.Bool("repo_name_available", true)) } else { log.Println("error fetching existing repo from db", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to check for existing repo") s.pages.Notice(w, "repo", "Failed to fork this repository. Try again later.") return } } else if existingRepo != nil { // repo with this name already exists, append random string forkName = fmt.Sprintf("%s-%s", forkName, randomString(3)) - span.SetAttributes( - attribute.Bool("repo_name_conflict", true), - attribute.String("adjusted_fork_name", forkName), - ) } - secret, err := db.GetRegistrationKey(s.db, knot) if err != nil { - span.RecordError(err) - span.SetStatus(codes.Error, "failed to get registration key") s.pages.Notice(w, "repo", fmt.Sprintf("No registration key found for knot %s.", knot)) return } client, err := NewSignedClient(knot, secret, s.config.Dev) if err != nil { - span.RecordError(err) - span.SetStatus(codes.Error, "failed to create signed client") s.pages.Notice(w, "repo", "Failed to reach knot server.") return } @@ -2420,11 +1844,6 @@ } forkSourceUrl := fmt.Sprintf("%s://%s/%s/%s", uri, f.Knot, f.OwnerDid(), f.RepoName) sourceAt := f.RepoAt.String() - span.SetAttributes( - attribute.String("fork_source_url", forkSourceUrl), - attribute.String("source_at", sourceAt), - ) - rkey := appview.TID() repo := &db.Repo{ Did: user.Did, @@ -2434,13 +1853,9 @@ Rkey: rkey, Source: sourceAt, } - span.SetAttributes(attribute.String("rkey", rkey)) - - tx, err := s.db.BeginTx(ctx, nil) + tx, err := s.db.BeginTx(r.Context(), nil) if err != nil { log.Println(err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to begin transaction") s.pages.Notice(w, "repo", "Failed to save repository information.") return } @@ -2449,29 +1864,21 @@ tx.Rollback() err = s.enforcer.E.LoadPolicy() if err != nil { log.Println("failed to rollback policies") - span.RecordError(err) } }() resp, err := client.ForkRepo(user.Did, forkSourceUrl, forkName) if err != nil { - span.RecordError(err) - span.SetStatus(codes.Error, "failed to fork repo on knot server") s.pages.Notice(w, "repo", "Failed to create repository on knot server.") return } - - span.SetAttributes(attribute.Int("fork_response_status", resp.StatusCode)) switch resp.StatusCode { case http.StatusConflict: - span.SetAttributes(attribute.Bool("name_conflict", true)) s.pages.Notice(w, "repo", "A repository with that name already exists.") return case http.StatusInternalServerError: - span.SetAttributes(attribute.Bool("server_error", true)) s.pages.Notice(w, "repo", "Failed to create repository on knot. Try again later.") - return case http.StatusNoContent: // continue } @@ -2479,7 +1886,7 @@ xrpcClient, _ := s.auth.AuthorizedClient(r) createdAt := time.Now().Format(time.RFC3339) - atresp, err := comatproto.RepoPutRecord(ctx, xrpcClient, &comatproto.RepoPutRecord_Input{ + atresp, err := comatproto.RepoPutRecord(r.Context(), xrpcClient, &comatproto.RepoPutRecord_Input{ Collection: tangled.RepoNSID, Repo: user.Did, Rkey: rkey, @@ -2494,20 +1901,15 @@ }}, }) if err != nil { log.Printf("failed to create record: %s", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to create record in PDS") s.pages.Notice(w, "repo", "Failed to announce repository creation.") return } log.Println("created repo record: ", atresp.Uri) - span.SetAttributes(attribute.String("repo_uri", atresp.Uri)) repo.AtUri = atresp.Uri - err = db.AddRepo(ctx, tx, repo) + err = db.AddRepo(tx, repo) if err != nil { log.Println(err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to add repo to database") s.pages.Notice(w, "repo", "Failed to save repository information.") return } @@ -2517,8 +1919,6 @@ p, _ := securejoin.SecureJoin(user.Did, forkName) err = s.enforcer.AddRepo(user.Did, knot, p) if err != nil { log.Println(err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to set up repository permissions") s.pages.Notice(w, "repo", "Failed to set up repository permissions.") return } @@ -2526,8 +1926,6 @@ err = tx.Commit() if err != nil { log.Println("failed to commit changes", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to commit transaction") http.Error(w, err.Error(), http.StatusInternalServerError) return } @@ -2535,8 +1933,6 @@ err = s.enforcer.E.SavePolicy() if err != nil { log.Println("failed to update ACLs", err) - span.RecordError(err) - span.SetStatus(codes.Error, "failed to save policy") http.Error(w, err.Error(), http.StatusInternalServerError) return } diff --git a/appview/state/repo_util.go b/appview/state/repo_util.go --- a/appview/state/repo_util.go +++ b/appview/state/repo_util.go @@ -12,42 +12,25 @@ "github.com/bluesky-social/indigo/atproto/identity" "github.com/bluesky-social/indigo/atproto/syntax" "github.com/go-chi/chi/v5" "github.com/go-git/go-git/v5/plumbing/object" - "go.opentelemetry.io/otel/attribute" "tangled.sh/tangled.sh/core/appview/auth" "tangled.sh/tangled.sh/core/appview/db" "tangled.sh/tangled.sh/core/appview/pages/repoinfo" - "tangled.sh/tangled.sh/core/telemetry" ) func (s *State) fullyResolvedRepo(r *http.Request) (*FullyResolvedRepo, error) { - ctx := r.Context() - - attrs := telemetry.MapAttrs(map[string]string{ - "repo": chi.URLParam(r, "repo"), - "ref": chi.URLParam(r, "ref"), - }) - - ctx, span := s.t.TraceStart(ctx, "fullyResolvedRepo", attrs...) - defer span.End() - repoName := chi.URLParam(r, "repo") - knot, ok := ctx.Value("knot").(string) + knot, ok := r.Context().Value("knot").(string) if !ok { log.Println("malformed middleware") return nil, fmt.Errorf("malformed middleware") } - - span.SetAttributes(attribute.String("knot", knot)) - - id, ok := ctx.Value("resolvedId").(identity.Identity) + id, ok := r.Context().Value("resolvedId").(identity.Identity) if !ok { log.Println("malformed middleware") return nil, fmt.Errorf("malformed middleware") } - span.SetAttributes(attribute.String("did", id.DID.String())) - - repoAt, ok := ctx.Value("repoAt").(string) + repoAt, ok := r.Context().Value("repoAt").(string) if !ok { log.Println("malformed middleware") return nil, fmt.Errorf("malformed middleware") @@ -73,12 +56,11 @@ return nil, err } ref = defaultBranch.Branch - - span.SetAttributes(attribute.String("default_branch", ref)) } - description, ok := ctx.Value("repoDescription").(string) - addedAt, ok := ctx.Value("repoAddedAt").(string) + // pass through values from the middleware + description, ok := r.Context().Value("repoDescription").(string) + addedAt, ok := r.Context().Value("repoAddedAt").(string) return &FullyResolvedRepo{ Knot: knot, diff --git a/appview/state/router.go b/appview/state/router.go --- a/appview/state/router.go +++ b/appview/state/router.go @@ -13,12 +13,6 @@ func (s *State) Router() http.Handler { router := chi.NewRouter() - if s.t != nil { - // top-level telemetry middleware - // router.Use(s.t.RequestDuration()) - // router.Use(s.t.RequestInFlight()) - } - router.HandleFunc("/*", func(w http.ResponseWriter, r *http.Request) { pat := chi.URLParam(r, "*") if strings.HasPrefix(pat, "did:") || strings.HasPrefix(pat, "@") { @@ -54,6 +48,7 @@ } func (s *State) UserRouter() http.Handler { r := chi.NewRouter() + // strip @ from user r.Use(StripLeadingAt) diff --git a/appview/state/state.go b/appview/state/state.go --- a/appview/state/state.go +++ b/appview/state/state.go @@ -9,7 +9,6 @@ "fmt" "log" "log/slog" "net/http" - "runtime/debug" "strings" "time" @@ -18,7 +17,6 @@ "github.com/bluesky-social/indigo/atproto/syntax" lexutil "github.com/bluesky-social/indigo/lex/util" securejoin "github.com/cyphar/filepath-securejoin" "github.com/go-chi/chi/v5" - "go.opentelemetry.io/otel/attribute" "tangled.sh/tangled.sh/core/api/tangled" "tangled.sh/tangled.sh/core/appview" "tangled.sh/tangled.sh/core/appview/auth" @@ -26,7 +24,6 @@ "tangled.sh/tangled.sh/core/appview/db" "tangled.sh/tangled.sh/core/appview/pages" "tangled.sh/tangled.sh/core/jetstream" "tangled.sh/tangled.sh/core/rbac" - "tangled.sh/tangled.sh/core/telemetry" ) type State struct { @@ -37,11 +34,10 @@ tidClock *syntax.TIDClock pages *pages.Pages resolver *appview.Resolver jc *jetstream.JetstreamClient - t *telemetry.Telemetry config *appview.Config } -func Make(ctx context.Context, config *appview.Config) (*State, error) { +func Make(config *appview.Config) (*State, error) { d, err := db.Make(config.DbPath) if err != nil { return nil, err @@ -63,14 +59,6 @@ pgs := pages.NewPages(config) resolver := appview.NewResolver() - bi, ok := debug.ReadBuildInfo() - var version string - if ok { - version = bi.Main.Version - } else { - version = "v0.0.0-unknown" - } - wrapper := db.DbWrapper{d} jc, err := jetstream.NewJetstreamClient( config.JetstreamEndpoint, @@ -84,19 +72,11 @@ ) if err != nil { return nil, fmt.Errorf("failed to create jetstream client: %w", err) } - err = jc.StartJetstream(ctx, appview.Ingest(wrapper)) + err = jc.StartJetstream(context.Background(), appview.Ingest(wrapper)) if err != nil { return nil, fmt.Errorf("failed to start jetstream watcher: %w", err) } - var tele *telemetry.Telemetry - if config.EnableTelemetry { - tele, err = telemetry.NewTelemetry(ctx, "appview", version, config.Dev) - if err != nil { - return nil, fmt.Errorf("failed to setup telemetry: %w", err) - } - } - state := &State{ d, auth, @@ -105,7 +85,6 @@ clock, pgs, resolver, jc, - tele, config, } @@ -199,16 +178,11 @@ w.WriteHeader(http.StatusSeeOther) } func (s *State) Timeline(w http.ResponseWriter, r *http.Request) { - ctx, span := s.t.TraceStart(r.Context(), "Timeline") - defer span.End() - user := s.auth.GetUser(r) - span.SetAttributes(attribute.String("user.did", user.Did)) - timeline, err := db.MakeTimeline(ctx, s.db) + timeline, err := db.MakeTimeline(s.db) if err != nil { log.Println(err) - span.RecordError(err) s.pages.Notice(w, "timeline", "Uh oh! Failed to load timeline.") } @@ -227,9 +201,8 @@ if ev.Star != nil { didsToResolve = append(didsToResolve, ev.Star.StarredByDid, ev.Star.Repo.Did) } } - span.SetAttributes(attribute.Int("dids.to_resolve.count", len(didsToResolve))) - resolvedIds := s.resolver.ResolveIdents(ctx, didsToResolve) + resolvedIds := s.resolver.ResolveIdents(r.Context(), didsToResolve) didHandleMap := make(map[string]string) for _, identity := range resolvedIds { if !identity.Handle.IsInvalidHandle() { @@ -238,7 +211,6 @@ } else { didHandleMap[identity.DID.String()] = identity.DID.String() } } - span.SetAttributes(attribute.Int("dids.resolved.count", len(resolvedIds))) s.pages.Timeline(w, pages.TimelineParams{ LoggedInUser: user, @@ -634,22 +606,14 @@ return nil } func (s *State) NewRepo(w http.ResponseWriter, r *http.Request) { - ctx, span := s.t.TraceStart(r.Context(), "NewRepo") - defer span.End() - switch r.Method { case http.MethodGet: user := s.auth.GetUser(r) - span.SetAttributes(attribute.String("user.did", user.Did)) - span.SetAttributes(attribute.String("request.method", "GET")) - knots, err := s.enforcer.GetDomainsForUser(user.Did) if err != nil { - span.RecordError(err) s.pages.Notice(w, "repo", "Invalid user account.") return } - span.SetAttributes(attribute.Int("knots.count", len(knots))) s.pages.NewRepo(w, pages.NewRepoParams{ LoggedInUser: user, @@ -658,22 +622,18 @@ }) case http.MethodPost: user := s.auth.GetUser(r) - span.SetAttributes(attribute.String("user.did", user.Did)) - span.SetAttributes(attribute.String("request.method", "POST")) domain := r.FormValue("domain") if domain == "" { s.pages.Notice(w, "repo", "Invalid form submission—missing knot domain.") return } - span.SetAttributes(attribute.String("domain", domain)) repoName := r.FormValue("name") if repoName == "" { s.pages.Notice(w, "repo", "Repository name cannot be empty.") return } - span.SetAttributes(attribute.String("repo.name", repoName)) if err := validateRepoName(repoName); err != nil { s.pages.Notice(w, "repo", err.Error()) @@ -684,39 +644,29 @@ defaultBranch := r.FormValue("branch") if defaultBranch == "" { defaultBranch = "main" } - span.SetAttributes(attribute.String("repo.default_branch", defaultBranch)) description := r.FormValue("description") ok, err := s.enforcer.E.Enforce(user.Did, domain, domain, "repo:create") if err != nil || !ok { - if err != nil { - span.RecordError(err) - } - span.SetAttributes(attribute.Bool("permission.granted", false)) s.pages.Notice(w, "repo", "You do not have permission to create a repo in this knot.") return } - span.SetAttributes(attribute.Bool("permission.granted", true)) - existingRepo, err := db.GetRepo(ctx, s.db, user.Did, repoName) + existingRepo, err := db.GetRepo(s.db, user.Did, repoName) if err == nil && existingRepo != nil { - span.SetAttributes(attribute.Bool("repo.exists", true)) s.pages.Notice(w, "repo", fmt.Sprintf("A repo by this name already exists on %s", existingRepo.Knot)) return } - span.SetAttributes(attribute.Bool("repo.exists", false)) secret, err := db.GetRegistrationKey(s.db, domain) if err != nil { - span.RecordError(err) s.pages.Notice(w, "repo", fmt.Sprintf("No registration key found for knot %s.", domain)) return } client, err := NewSignedClient(domain, secret, s.config.Dev) if err != nil { - span.RecordError(err) s.pages.Notice(w, "repo", "Failed to connect to knot server.") return } @@ -730,11 +680,10 @@ Rkey: rkey, Description: description, } - rWithCtx := r.WithContext(ctx) - xrpcClient, _ := s.auth.AuthorizedClient(rWithCtx) + xrpcClient, _ := s.auth.AuthorizedClient(r) createdAt := time.Now().Format(time.RFC3339) - atresp, err := comatproto.RepoPutRecord(ctx, xrpcClient, &comatproto.RepoPutRecord_Input{ + atresp, err := comatproto.RepoPutRecord(r.Context(), xrpcClient, &comatproto.RepoPutRecord_Input{ Collection: tangled.RepoNSID, Repo: user.Did, Rkey: rkey, @@ -747,17 +696,14 @@ Owner: user.Did, }}, }) if err != nil { - span.RecordError(err) log.Printf("failed to create record: %s", err) s.pages.Notice(w, "repo", "Failed to announce repository creation.") return } log.Println("created repo record: ", atresp.Uri) - span.SetAttributes(attribute.String("repo.uri", atresp.Uri)) - tx, err := s.db.BeginTx(ctx, nil) + tx, err := s.db.BeginTx(r.Context(), nil) if err != nil { - span.RecordError(err) log.Println(err) s.pages.Notice(w, "repo", "Failed to save repository information.") return @@ -772,11 +718,9 @@ }() resp, err := client.NewRepo(user.Did, repoName, defaultBranch) if err != nil { - span.RecordError(err) s.pages.Notice(w, "repo", "Failed to create repository on knot server.") return } - span.SetAttributes(attribute.Int("knot_response.status", resp.StatusCode)) switch resp.StatusCode { case http.StatusConflict: @@ -789,9 +733,8 @@ // continue } repo.AtUri = atresp.Uri - err = db.AddRepo(ctx, tx, repo) + err = db.AddRepo(tx, repo) if err != nil { - span.RecordError(err) log.Println(err) s.pages.Notice(w, "repo", "Failed to save repository information.") return @@ -801,7 +744,6 @@ // acls p, _ := securejoin.SecureJoin(user.Did, repoName) err = s.enforcer.AddRepo(user.Did, domain, p) if err != nil { - span.RecordError(err) log.Println(err) s.pages.Notice(w, "repo", "Failed to set up repository permissions.") return @@ -809,7 +751,6 @@ } err = tx.Commit() if err != nil { - span.RecordError(err) log.Println("failed to commit changes", err) http.Error(w, err.Error(), http.StatusInternalServerError) return @@ -817,7 +758,6 @@ } err = s.enforcer.E.SavePolicy() if err != nil { - span.RecordError(err) log.Println("failed to update ACLs", err) http.Error(w, err.Error(), http.StatusInternalServerError) return diff --git a/cmd/appview/main.go b/cmd/appview/main.go --- a/cmd/appview/main.go +++ b/cmd/appview/main.go @@ -14,15 +14,13 @@ func main() { slog.SetDefault(slog.New(slog.NewTextHandler(os.Stdout, nil))) - ctx := context.Background() - - c, err := appview.LoadConfig(ctx) + c, err := appview.LoadConfig(context.Background()) if err != nil { log.Println("failed to load config", "error", err) return } - state, err := state.Make(ctx, c) + state, err := state.Make(c) if err != nil { log.Fatal(err) diff --git a/go.mod b/go.mod --- a/go.mod +++ b/go.mod @@ -26,15 +26,6 @@ github.com/resend/resend-go/v2 v2.15.0 github.com/sethvargo/go-envconfig v1.1.0 github.com/whyrusleeping/cbor-gen v0.2.1-0.20241030202151-b7a6831be65e github.com/yuin/goldmark v1.4.13 - go.opentelemetry.io/otel v1.35.0 - go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.35.0 - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.35.0 - go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.35.0 - go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.35.0 - go.opentelemetry.io/otel/metric v1.35.0 - go.opentelemetry.io/otel/sdk v1.35.0 - go.opentelemetry.io/otel/sdk/metric v1.35.0 - go.opentelemetry.io/otel/trace v1.35.0 golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 ) @@ -48,7 +39,6 @@ github.com/beorn7/perks v1.0.1 // indirect github.com/bmatcuk/doublestar/v4 v4.7.1 // indirect github.com/carlmjohnson/versioninfo v0.22.5 // indirect github.com/casbin/govaluate v1.3.0 // indirect - github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/cloudflare/circl v1.6.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect @@ -57,14 +47,13 @@ github.com/emirpasic/gods v1.18.1 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect github.com/go-git/go-billy/v5 v5.6.2 // indirect - github.com/go-logr/logr v1.4.2 // indirect + github.com/go-logr/logr v1.4.1 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/goccy/go-json v0.10.2 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/gorilla/css v1.0.1 // indirect github.com/gorilla/securecookie v1.1.2 // indirect github.com/gorilla/websocket v1.5.1 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-retryablehttp v0.7.5 // indirect github.com/hashicorp/golang-lru v1.0.2 // indirect @@ -110,22 +99,18 @@ github.com/stretchr/testify v1.10.0 // indirect github.com/xanzy/ssh-agent v0.3.3 // indirect gitlab.com/yawning/secp256k1-voi v0.0.0-20230925100816-f2616030848b // indirect gitlab.com/yawning/tuplehash v0.0.0-20230713102510-df83abbf9a02 // indirect - go.opentelemetry.io/auto/sdk v1.1.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0 // indirect - go.opentelemetry.io/proto/otlp v1.5.0 // indirect + go.opentelemetry.io/otel v1.21.0 // indirect + go.opentelemetry.io/otel/metric v1.21.0 // indirect + go.opentelemetry.io/otel/trace v1.21.0 // indirect go.uber.org/atomic v1.11.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.26.0 // indirect golang.org/x/crypto v0.37.0 // indirect golang.org/x/net v0.39.0 // indirect - golang.org/x/sys v0.33.0 // indirect - golang.org/x/text v0.24.0 // indirect + golang.org/x/sys v0.32.0 // indirect golang.org/x/time v0.5.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20250218202821-56aae31c358a // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a // indirect - google.golang.org/grpc v1.71.0 // indirect - google.golang.org/protobuf v1.36.5 // indirect + google.golang.org/protobuf v1.34.2 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect lukechampine.com/blake3 v1.2.1 // indirect diff --git a/go.sum b/go.sum --- a/go.sum +++ b/go.sum @@ -42,8 +42,6 @@ github.com/casbin/casbin/v2 v2.103.0/go.mod h1:Ee33aqGrmES+GNL17L0h9X28wXuo829wnNUnS0edAco= github.com/casbin/govaluate v1.2.0/go.mod h1:G/UnbIjZk/0uMNaLwZZmFQrR72tYRZWQkO70si/iR7A= github.com/casbin/govaluate v1.3.0 h1:VA0eSY0M2lA86dYd5kPPuNZMUD9QkWnOCnavGrw9myc= github.com/casbin/govaluate v1.3.0/go.mod h1:G/UnbIjZk/0uMNaLwZZmFQrR72tYRZWQkO70si/iR7A= -github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= -github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cloudflare/circl v1.1.0/go.mod h1:prBCrKB9DV4poKZY1l9zBXg2QJY7mvgRvtMxxK7fi4I= @@ -84,8 +82,8 @@ github.com/go-git/go-git-fixtures/v4 v4.3.1/go.mod h1:8LHG1a3SRW71ettAD/jW13h8c6AqjVSeL11RAdgaqpo= github.com/go-git/go-git/v5 v5.6.1 h1:q4ZRqQl4pR/ZJHc1L5CFjGA1a10u76aV1iC+nh+bHsk= github.com/go-git/go-git/v5 v5.6.1/go.mod h1:mvyoL6Unz0PiTQrGQfSfiLFhBH1c1e84ylC2MDs4ee8= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= -github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= +github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0= @@ -95,11 +93,9 @@ github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= -github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= -github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= -github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= @@ -115,8 +111,6 @@ github.com/gorilla/sessions v1.4.0 h1:kpIYOp/oi6MG/p5PgxApU8srsSw9tuFbt46Lt7auzqQ= github.com/gorilla/sessions v1.4.0/go.mod h1:FLWm50oby91+hl7p/wRxDth9bWSuk0qVL2emc7lT5ik= github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1 h1:e9Rjr40Z98/clHv5Yg79Is0NtosR5LXRvdr7o/6NwbA= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1/go.mod h1:tIxuGz/9mpox++sgp9fJjHO0+q1X9/UOWd798aAm22M= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxCsHI= @@ -233,8 +227,8 @@ github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= github.com/resend/resend-go/v2 v2.15.0 h1:B6oMEPf8IEQwn2Ovx/9yymkESLDSeNfLFaNMw+mzHhE= github.com/resend/resend-go/v2 v2.15.0/go.mod h1:3YCb8c8+pLiqhtRFXTyFwlLvfjQtluxOr9HEh2BwCkQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= -github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= +github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= +github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= @@ -274,39 +268,21 @@ gitlab.com/yawning/secp256k1-voi v0.0.0-20230925100816-f2616030848b h1:CzigHMRySiX3drau9C6Q5CAbNIApmLdat5jPMqChvDA= gitlab.com/yawning/secp256k1-voi v0.0.0-20230925100816-f2616030848b/go.mod h1:/y/V339mxv2sZmYYR64O07VuCpdNZqCTwO8ZcouTMI8= gitlab.com/yawning/tuplehash v0.0.0-20230713102510-df83abbf9a02 h1:qwDnMxjkyLmAFgcfgTnfJrmYKWhHnci3GjDqcZp1M3Q= gitlab.com/yawning/tuplehash v0.0.0-20230713102510-df83abbf9a02/go.mod h1:JTnUj0mpYiAsuZLmKjTx/ex3AtMowcCgnE7YNyCEP0I= -go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= -go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1 h1:aFJWCqJMNjENlcleuuOkGAPH82y0yULBScfXcIEdS24= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1/go.mod h1:sEGXWArGqc3tVa+ekntsN65DmVbVeW+7lTKTjZF3/Fo= -go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ= -go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.35.0 h1:QcFwRrZLc82r8wODjvyCbP7Ifp3UANaBSmhDSFjnqSc= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.35.0/go.mod h1:CXIWhUomyWBG/oY2/r/kLp6K/cmx9e/7DLpBuuGdLCA= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0 h1:1fTNlAIJZGWLP5FVu0fikVry1IsiUnXjf7QFvoNN3Xw= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0/go.mod h1:zjPK58DtkqQFn+YUMbx0M2XV3QgKU0gS9LeGohREyK4= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.35.0 h1:m639+BofXTvcY1q8CGs4ItwQarYtJPOWmVobfM1HpVI= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.35.0/go.mod h1:LjReUci/F4BUyv+y4dwnq3h/26iNOeC3wAIqgvTIZVo= -go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.35.0 h1:PB3Zrjs1sG1GBX51SXyTSoOTqcDglmsk7nT6tkKPb/k= -go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.35.0/go.mod h1:U2R3XyVPzn0WX7wOIypPuptulsMcPDPs/oiSVOMVnHY= -go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.35.0 h1:T0Ec2E+3YZf5bgTNQVet8iTDW7oIk03tXHq+wkwIDnE= -go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.35.0/go.mod h1:30v2gqH+vYGJsesLWFov8u47EpYTcIQcBjKpI6pJThg= -go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M= -go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE= -go.opentelemetry.io/otel/sdk v1.35.0 h1:iPctf8iprVySXSKJffSS79eOjl9pvxV9ZqOWT0QejKY= -go.opentelemetry.io/otel/sdk v1.35.0/go.mod h1:+ga1bZliga3DxJ3CQGg3updiaAJoNECOgJREo9KHGQg= -go.opentelemetry.io/otel/sdk/metric v1.35.0 h1:1RriWBmCKgkeHEhM7a2uMjMUfP7MsOF5JpUCaEqEI9o= -go.opentelemetry.io/otel/sdk/metric v1.35.0/go.mod h1:is6XYCUMpcKi+ZsOvfluY5YstFnhW0BidkR+gL+qN+w= -go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs= -go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc= -go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4= -go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4= +go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc= +go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo= +go.opentelemetry.io/otel/metric v1.21.0 h1:tlYWfeo+Bocx5kLEloTjbcDwBuELRrIFxwdQ36PlJu4= +go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM= +go.opentelemetry.io/otel/trace v1.21.0 h1:WD9i5gzvoUPuXIXH24ZNBudiarZDKuekPqi/E8fpfLc= +go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= -go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= -go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk= +go.uber.org/goleak v1.2.0/go.mod h1:XJYK+MuIchqpmGmUSAzotztawfKvYLUIgg7guXrwVUo= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= @@ -381,8 +357,8 @@ golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= -golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20= +golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20220722155259-a9ba230a4035/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -419,14 +395,8 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU= golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= -google.golang.org/genproto/googleapis/api v0.0.0-20250218202821-56aae31c358a h1:nwKuGPlUAt+aR+pcrkfFRrTU1BVrSmYyYMxYbUIVHr0= -google.golang.org/genproto/googleapis/api v0.0.0-20250218202821-56aae31c358a/go.mod h1:3kWAYMk1I75K4vykHtKt2ycnOgpA6974V7bREqbsenU= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a h1:51aaUVRocpvUOSQKM6Q7VuoaktNIaMCLuhZB6DKksq4= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a/go.mod h1:uRxBH1mhmO8PGhU89cMcHaXKZqO+OfakD8QQO0oYwlQ= -google.golang.org/grpc v1.71.0 h1:kF77BGdPTQ4/JZWMlb9VpJ5pa25aqvVqogsxNHHdeBg= -google.golang.org/grpc v1.71.0/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec= -google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM= -google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/telemetry/middleware.go b/telemetry/middleware.go deleted file mode 100644 --- a/telemetry/middleware.go +++ /dev/null @@ -1,88 +0,0 @@ -package telemetry - -import ( - "fmt" - "net/http" - "time" - - "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" - otelmetric "go.opentelemetry.io/otel/metric" - "go.opentelemetry.io/otel/semconv/v1.13.0/httpconv" -) - -func (t *Telemetry) RequestDuration() func(next http.Handler) http.Handler { - const ( - metricNameRequestDurationMs = "request_duration_millis" - metricUnitRequestDurationMs = "ms" - metricDescRequestDurationMs = "Measures the latency of HTTP requests processed by the server, in milliseconds." - ) - histogram, err := t.meter.Int64Histogram( - metricNameRequestDurationMs, - otelmetric.WithDescription(metricDescRequestDurationMs), - otelmetric.WithUnit(metricUnitRequestDurationMs), - ) - if err != nil { - panic(fmt.Sprintf("unable to create %s histogram: %v", metricNameRequestDurationMs, err)) - } - - return func(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - // capture the start time of the request - startTime := time.Now() - - // execute next http handler - next.ServeHTTP(w, r) - - // record the request duration - duration := time.Since(startTime) - histogram.Record( - r.Context(), - int64(duration.Milliseconds()), - otelmetric.WithAttributes( - httpconv.ServerRequest(t.serviceName, r)..., - ), - ) - }) - } -} - -func (t *Telemetry) RequestInFlight() func(next http.Handler) http.Handler { - const ( - metricNameRequestInFlight = "request_in_flight" - metricDescRequestInFlight = "Measures the number of concurrent HTTP requests being processed by the server." - metricUnitRequestInFlight = "1" - ) - - // counter to capture requests in flight - counter, err := t.meter.Int64UpDownCounter( - metricNameRequestInFlight, - otelmetric.WithDescription(metricDescRequestInFlight), - otelmetric.WithUnit(metricUnitRequestInFlight), - ) - if err != nil { - panic(fmt.Sprintf("unable to create %s counter: %v", metricNameRequestInFlight, err)) - } - - return func(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - attrs := otelmetric.WithAttributes(httpconv.ServerRequest(t.serviceName, r)...) - - // increase the number of requests in flight - counter.Add(r.Context(), 1, attrs) - - // execute next http handler - next.ServeHTTP(w, r) - - // decrease the number of requests in flight - counter.Add(r.Context(), -1, attrs) - }) - } -} - -func (t *Telemetry) WithRouteTag() func(next http.Handler) http.Handler { - return func(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - otelhttp.WithRouteTag(r.URL.Path, next) - }) - } -} diff --git a/telemetry/provider.go b/telemetry/provider.go deleted file mode 100644 --- a/telemetry/provider.go +++ /dev/null @@ -1,65 +0,0 @@ -package telemetry - -import ( - "context" - "fmt" - "time" - - "go.opentelemetry.io/otel" - "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc" - "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc" - "go.opentelemetry.io/otel/exporters/stdout/stdoutmetric" - "go.opentelemetry.io/otel/exporters/stdout/stdouttrace" - "go.opentelemetry.io/otel/sdk/metric" - "go.opentelemetry.io/otel/sdk/resource" - "go.opentelemetry.io/otel/sdk/trace" -) - -func NewTracerProvider(ctx context.Context, res *resource.Resource, isDev bool) (*trace.TracerProvider, error) { - var exporter trace.SpanExporter - var err error - - if isDev { - exporter, err = stdouttrace.New() - if err != nil { - return nil, fmt.Errorf("failed to create stdout trace exporter: %w", err) - } - } else { - exporter, err = otlptracegrpc.New(ctx) - if err != nil { - return nil, fmt.Errorf("failed to create OTLP trace exporter: %w", err) - } - } - - tp := trace.NewTracerProvider( - trace.WithBatcher(exporter, trace.WithBatchTimeout(1*time.Second)), - trace.WithResource(res), - ) - otel.SetTracerProvider(tp) - - return tp, nil -} - -func NewMeterProvider(ctx context.Context, res *resource.Resource, isDev bool) (*metric.MeterProvider, error) { - var exporter metric.Exporter - var err error - - if isDev { - exporter, err = stdoutmetric.New() - if err != nil { - return nil, fmt.Errorf("failed to create stdout metric exporter: %w", err) - } - } else { - exporter, err = otlpmetricgrpc.New(ctx) - if err != nil { - return nil, fmt.Errorf("failed to create OTLP metric exporter: %w", err) - } - } - - mp := metric.NewMeterProvider( - metric.WithReader(metric.NewPeriodicReader(exporter, metric.WithInterval(10*time.Second))), - metric.WithResource(res), - ) - otel.SetMeterProvider(mp) - return mp, nil -} diff --git a/telemetry/telemetry.go b/telemetry/telemetry.go deleted file mode 100644 --- a/telemetry/telemetry.go +++ /dev/null @@ -1,76 +0,0 @@ -package telemetry - -import ( - "context" - "fmt" - - "go.opentelemetry.io/otel/attribute" - otelmetric "go.opentelemetry.io/otel/metric" - "go.opentelemetry.io/otel/sdk/metric" - "go.opentelemetry.io/otel/sdk/resource" - "go.opentelemetry.io/otel/sdk/trace" - semconv "go.opentelemetry.io/otel/semconv/v1.17.0" - oteltrace "go.opentelemetry.io/otel/trace" -) - -type Telemetry struct { - tp *trace.TracerProvider - mp *metric.MeterProvider - - meter otelmetric.Meter - tracer oteltrace.Tracer - - serviceName string - serviceVersion string -} - -func NewTelemetry(ctx context.Context, serviceName, serviceVersion string, isDev bool) (*Telemetry, error) { - res := resource.NewWithAttributes( - semconv.SchemaURL, - semconv.ServiceName(serviceName), - semconv.ServiceVersion(serviceVersion), - ) - - tp, err := NewTracerProvider(ctx, res, isDev) - if err != nil { - return nil, err - } - - // mp, err := NewMeterProvider(ctx, res, isDev) - // if err != nil { - // return nil, err - // } - - return &Telemetry{ - tp: tp, - //mp: mp, - - //meter: mp.Meter(serviceName), - tracer: tp.Tracer(serviceVersion), - - serviceName: serviceName, - serviceVersion: serviceVersion, - }, nil -} - -func (t *Telemetry) Meter() otelmetric.Meter { - return t.meter -} - -func (t *Telemetry) Tracer() oteltrace.Tracer { - return t.tracer -} - -func (t *Telemetry) TraceStart(ctx context.Context, name string, attrs ...attribute.KeyValue) (context.Context, oteltrace.Span) { - ctx, span := t.tracer.Start(ctx, name) - span.SetAttributes(attrs...) - return ctx, span -} - -func MapAttrs[T any](attrs map[string]T) []attribute.KeyValue { - var result []attribute.KeyValue - for k, v := range attrs { - result = append(result, attribute.Key(k).String(fmt.Sprintf("%v", v))) - } - return result -} -- tangled.sh