Log slow API requests with server spans and client timing
This commit is contained in:
+70
-68
@@ -14,6 +14,7 @@ import (
|
||||
"time"
|
||||
|
||||
"g.fc.run/ai/byre/internal/procgroup"
|
||||
"g.fc.run/ai/byre/internal/trace"
|
||||
)
|
||||
|
||||
type RepoInfo struct {
|
||||
@@ -22,13 +23,13 @@ type RepoInfo struct {
|
||||
Remote string
|
||||
}
|
||||
|
||||
func Inspect(path string) (RepoInfo, error) {
|
||||
func Inspect(ctx context.Context, path string) (RepoInfo, error) {
|
||||
abs, err := filepath.Abs(path)
|
||||
if err != nil {
|
||||
return RepoInfo{}, err
|
||||
}
|
||||
|
||||
root, err := run(abs, "rev-parse", "--show-toplevel")
|
||||
root, err := run(ctx, abs, "rev-parse", "--show-toplevel")
|
||||
if err != nil {
|
||||
return RepoInfo{}, err
|
||||
}
|
||||
@@ -47,12 +48,12 @@ func Inspect(path string) (RepoInfo, error) {
|
||||
return RepoInfo{}, fmt.Errorf("%s is inside the repo at %s; register the repo root", abs, root)
|
||||
}
|
||||
|
||||
branch, err := run(root, "symbolic-ref", "--short", "HEAD")
|
||||
branch, err := run(ctx, root, "symbolic-ref", "--short", "HEAD")
|
||||
if err != nil {
|
||||
return RepoInfo{}, err
|
||||
}
|
||||
|
||||
remote, err := run(root, "remote", "get-url", "origin")
|
||||
remote, err := run(ctx, root, "remote", "get-url", "origin")
|
||||
if err != nil {
|
||||
return RepoInfo{}, err
|
||||
}
|
||||
@@ -60,13 +61,13 @@ func Inspect(path string) (RepoInfo, error) {
|
||||
return RepoInfo{Root: root, DefaultBranch: branch, Remote: remote}, nil
|
||||
}
|
||||
|
||||
func AddWorktree(repo, path, branch, base string) (string, error) {
|
||||
sha, err := run(repo, "rev-parse", "--verify", base+"^{commit}")
|
||||
func AddWorktree(ctx context.Context, repo, path, branch, base string) (string, error) {
|
||||
sha, err := run(ctx, repo, "rev-parse", "--verify", base+"^{commit}")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
_, err = run(repo, "worktree", "add", "-b", branch, path, sha)
|
||||
_, err = run(ctx, repo, "worktree", "add", "-b", branch, path, sha)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -74,38 +75,38 @@ func AddWorktree(repo, path, branch, base string) (string, error) {
|
||||
return sha, nil
|
||||
}
|
||||
|
||||
func AddDetachedWorktree(repo, path, commit string) error {
|
||||
_, err := run(repo, "worktree", "add", "--detach", path, commit)
|
||||
func AddDetachedWorktree(ctx context.Context, repo, path, commit string) error {
|
||||
_, err := run(ctx, repo, "worktree", "add", "--detach", path, commit)
|
||||
return err
|
||||
}
|
||||
|
||||
func RemoveDetachedWorktree(repo, path string) error {
|
||||
func RemoveDetachedWorktree(ctx context.Context, repo, path string) error {
|
||||
_, err := os.Stat(path)
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
return nil
|
||||
}
|
||||
_, err = run(repo, "worktree", "remove", "--force", path)
|
||||
_, err = run(ctx, repo, "worktree", "remove", "--force", path)
|
||||
return err
|
||||
}
|
||||
|
||||
func RemoveWorktree(repo, path, branch string) error {
|
||||
list, err := run(repo, "worktree", "list", "--porcelain")
|
||||
func RemoveWorktree(ctx context.Context, repo, path, branch string) error {
|
||||
list, err := run(ctx, repo, "worktree", "list", "--porcelain")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, statErr := os.Stat(path)
|
||||
if statErr == nil || slices.Contains(strings.Split(list, "\n"), "worktree "+path) {
|
||||
_, err = run(repo, "worktree", "remove", "--force", path)
|
||||
_, err = run(ctx, repo, "worktree", "remove", "--force", path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
_, _, code, err := runCode(repo, nil, "rev-parse", "--verify", "--quiet", "refs/heads/"+branch)
|
||||
_, _, code, err := runCode(ctx, repo, nil, "rev-parse", "--verify", "--quiet", "refs/heads/"+branch)
|
||||
if err != nil || code != 0 {
|
||||
return err
|
||||
}
|
||||
_, err = run(repo, "branch", "-D", branch)
|
||||
_, err = run(ctx, repo, "branch", "-D", branch)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -117,24 +118,24 @@ func (e *ConflictError) Error() string {
|
||||
return "merge conflicts in " + strings.Join(e.Files, ", ")
|
||||
}
|
||||
|
||||
func Ahead(worktree, target string) (int, error) {
|
||||
count, err := run(worktree, "rev-list", "--count", target+"..HEAD")
|
||||
func Ahead(ctx context.Context, worktree, target string) (int, error) {
|
||||
count, err := run(ctx, worktree, "rev-list", "--count", target+"..HEAD")
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return strconv.Atoi(count)
|
||||
}
|
||||
|
||||
func Behind(worktree, target string) (int, error) {
|
||||
count, err := run(worktree, "rev-list", "--count", "HEAD.."+target)
|
||||
func Behind(ctx context.Context, worktree, target string) (int, error) {
|
||||
count, err := run(ctx, worktree, "rev-list", "--count", "HEAD.."+target)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return strconv.Atoi(count)
|
||||
}
|
||||
|
||||
func SquashCommit(repo, worktree, target, message string, env []string, sign func(payload []byte) ([]byte, error)) (string, error) {
|
||||
checkedOut, err := run(repo, "symbolic-ref", "--short", "HEAD")
|
||||
func SquashCommit(ctx context.Context, repo, worktree, target, message string, env []string, sign func(payload []byte) ([]byte, error)) (string, error) {
|
||||
checkedOut, err := run(ctx, repo, "symbolic-ref", "--short", "HEAD")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -142,20 +143,20 @@ func SquashCommit(repo, worktree, target, message string, env []string, sign fun
|
||||
return "", fmt.Errorf("%s has %s checked out, not %s", repo, checkedOut, target)
|
||||
}
|
||||
|
||||
tree, err := Snapshot(worktree)
|
||||
tree, err := Snapshot(ctx, worktree)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
base, err := run(worktree, "merge-base", target, "HEAD")
|
||||
base, err := run(ctx, worktree, "merge-base", target, "HEAD")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
head, err := run(repo, "rev-parse", target)
|
||||
head, err := run(ctx, repo, "rev-parse", target)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
out, stderr, code, err := runCode(repo, nil, "merge-tree", "--write-tree", "--name-only", "--merge-base="+base, head, tree)
|
||||
out, stderr, code, err := runCode(ctx, repo, nil, "merge-tree", "--write-tree", "--name-only", "--merge-base="+base, head, tree)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -174,7 +175,7 @@ func SquashCommit(repo, worktree, target, message string, env []string, sign fun
|
||||
return "", fmt.Errorf("git merge-tree exited %d: %s", code, stderr)
|
||||
}
|
||||
|
||||
headTree, err := run(repo, "rev-parse", head+"^{tree}")
|
||||
headTree, err := run(ctx, repo, "rev-parse", head+"^{tree}")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -182,11 +183,11 @@ func SquashCommit(repo, worktree, target, message string, env []string, sign fun
|
||||
return "", nil
|
||||
}
|
||||
|
||||
commit, err := runEnv(repo, env, "commit-tree", lines[0], "-p", head, "-m", message)
|
||||
commit, err := runEnv(ctx, repo, env, "commit-tree", lines[0], "-p", head, "-m", message)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
signing, stderr, code, err := runCode(repo, nil, "config", "--type=bool", "--get", "commit.gpgsign")
|
||||
signing, stderr, code, err := runCode(ctx, repo, nil, "config", "--type=bool", "--get", "commit.gpgsign")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -196,11 +197,11 @@ func SquashCommit(repo, worktree, target, message string, env []string, sign fun
|
||||
if signing != "true" {
|
||||
return commit, nil
|
||||
}
|
||||
return signCommit(repo, commit, sign)
|
||||
return signCommit(ctx, repo, commit, sign)
|
||||
}
|
||||
|
||||
func signCommit(repo, commit string, sign func(payload []byte) ([]byte, error)) (string, error) {
|
||||
payload, err := runRaw(repo, nil, "", "cat-file", "commit", commit)
|
||||
func signCommit(ctx context.Context, repo, commit string, sign func(payload []byte) ([]byte, error)) (string, error) {
|
||||
payload, err := runRaw(ctx, repo, nil, "", "cat-file", "commit", commit)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -214,7 +215,7 @@ func signCommit(repo, commit string, sign func(payload []byte) ([]byte, error))
|
||||
}
|
||||
header := "gpgsig " + strings.ReplaceAll(strings.TrimSuffix(string(sig), "\n"), "\n", "\n ") + "\n"
|
||||
signed := payload[:eoh+1] + header + payload[eoh+1:]
|
||||
return runInput(repo, nil, signed, "hash-object", "-t", "commit", "-w", "--stdin")
|
||||
return runInput(ctx, repo, nil, signed, "hash-object", "-t", "commit", "-w", "--stdin")
|
||||
}
|
||||
|
||||
const Remote = "origin"
|
||||
@@ -244,8 +245,8 @@ func Push(ctx context.Context, repo, commit, branch, notes string) error {
|
||||
return fmt.Errorf("pushing %s to %s: exit status %d: %s", branch, Remote, code, strings.TrimSpace(out+"\n"+stderr))
|
||||
}
|
||||
|
||||
func FastForward(repo, rev string) error {
|
||||
_, err := run(repo, "merge", "--ff-only", rev)
|
||||
func FastForward(ctx context.Context, repo, rev string) error {
|
||||
_, err := run(ctx, repo, "merge", "--ff-only", rev)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -265,19 +266,19 @@ func FetchFastForward(ctx context.Context, repo, branch string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return FastForward(repo, Remote+"/"+branch)
|
||||
return FastForward(ctx, repo, Remote+"/"+branch)
|
||||
}
|
||||
|
||||
func Head(dir string) (string, error) {
|
||||
return run(dir, "rev-parse", "HEAD")
|
||||
func Head(ctx context.Context, dir string) (string, error) {
|
||||
return run(ctx, dir, "rev-parse", "HEAD")
|
||||
}
|
||||
|
||||
func BranchHead(repo, branch string) (string, error) {
|
||||
return run(repo, "rev-parse", "--verify", "refs/heads/"+branch+"^{commit}")
|
||||
func BranchHead(ctx context.Context, repo, branch string) (string, error) {
|
||||
return run(ctx, repo, "rev-parse", "--verify", "refs/heads/"+branch+"^{commit}")
|
||||
}
|
||||
|
||||
func IsAncestor(dir, ancestor, descendant string) (bool, error) {
|
||||
_, stderr, code, err := runCode(dir, nil, "merge-base", "--is-ancestor", ancestor, descendant)
|
||||
func IsAncestor(ctx context.Context, dir, ancestor, descendant string) (bool, error) {
|
||||
_, stderr, code, err := runCode(ctx, dir, nil, "merge-base", "--is-ancestor", ancestor, descendant)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
@@ -290,38 +291,38 @@ func IsAncestor(dir, ancestor, descendant string) (bool, error) {
|
||||
return false, fmt.Errorf("git merge-base --is-ancestor %s %s: exit status %d: %s", ancestor, descendant, code, stderr)
|
||||
}
|
||||
|
||||
func MergeInProgress(dir string) (bool, error) {
|
||||
_, _, code, err := runCode(dir, nil, "rev-parse", "--quiet", "--verify", "MERGE_HEAD")
|
||||
func MergeInProgress(ctx context.Context, dir string) (bool, error) {
|
||||
_, _, code, err := runCode(ctx, dir, nil, "rev-parse", "--quiet", "--verify", "MERGE_HEAD")
|
||||
return err == nil && code == 0, err
|
||||
}
|
||||
|
||||
func AbortMerge(dir string) error {
|
||||
merging, err := MergeInProgress(dir)
|
||||
func AbortMerge(ctx context.Context, dir string) error {
|
||||
merging, err := MergeInProgress(ctx, dir)
|
||||
if err != nil || !merging {
|
||||
return err
|
||||
}
|
||||
_, err = run(dir, "merge", "--abort")
|
||||
_, err = run(ctx, dir, "merge", "--abort")
|
||||
return err
|
||||
}
|
||||
|
||||
func ReadFile(repo, rev, path string) (string, bool, error) {
|
||||
_, _, code, err := runCode(repo, nil, "cat-file", "-e", rev+":"+path)
|
||||
func ReadFile(ctx context.Context, repo, rev, path string) (string, bool, error) {
|
||||
_, _, code, err := runCode(ctx, repo, nil, "cat-file", "-e", rev+":"+path)
|
||||
if err != nil {
|
||||
return "", false, err
|
||||
}
|
||||
if code != 0 {
|
||||
return "", false, nil
|
||||
}
|
||||
out, err := run(repo, "cat-file", "blob", rev+":"+path)
|
||||
out, err := run(ctx, repo, "cat-file", "blob", rev+":"+path)
|
||||
return out, true, err
|
||||
}
|
||||
|
||||
func CommitAll(dir, message, name, email string) (string, error) {
|
||||
status, err := run(dir, "status", "--porcelain", "--untracked-files=all")
|
||||
func CommitAll(ctx context.Context, dir, message, name, email string) (string, error) {
|
||||
status, err := run(ctx, dir, "status", "--porcelain", "--untracked-files=all")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
merging, err := MergeInProgress(dir)
|
||||
merging, err := MergeInProgress(ctx, dir)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -330,38 +331,38 @@ func CommitAll(dir, message, name, email string) (string, error) {
|
||||
}
|
||||
|
||||
env := IdentityEnv(name, email)
|
||||
_, err = runEnv(dir, env, "add", "--all")
|
||||
_, err = runEnv(ctx, dir, env, "add", "--all")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
_, err = runEnv(dir, env, "commit", "--quiet", "--message", message)
|
||||
_, err = runEnv(ctx, dir, env, "commit", "--quiet", "--message", message)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return Head(dir)
|
||||
return Head(ctx, dir)
|
||||
}
|
||||
|
||||
func Merge(dir, rev, message, name, email string) error {
|
||||
func Merge(ctx context.Context, dir, rev, message, name, email string) error {
|
||||
env := IdentityEnv(name, email)
|
||||
_, err := runEnv(dir, env, "merge", "--no-ff", "--quiet", "--message", message, rev)
|
||||
_, err := runEnv(ctx, dir, env, "merge", "--no-ff", "--quiet", "--message", message, rev)
|
||||
return err
|
||||
}
|
||||
|
||||
func run(dir string, args ...string) (string, error) {
|
||||
return runEnv(dir, nil, args...)
|
||||
func run(ctx context.Context, dir string, args ...string) (string, error) {
|
||||
return runEnv(ctx, dir, nil, args...)
|
||||
}
|
||||
|
||||
func runEnv(dir string, env []string, args ...string) (string, error) {
|
||||
return runInput(dir, env, "", args...)
|
||||
func runEnv(ctx context.Context, dir string, env []string, args ...string) (string, error) {
|
||||
return runInput(ctx, dir, env, "", args...)
|
||||
}
|
||||
|
||||
func runInput(dir string, env []string, input string, args ...string) (string, error) {
|
||||
out, err := runRaw(dir, env, input, args...)
|
||||
func runInput(ctx context.Context, dir string, env []string, input string, args ...string) (string, error) {
|
||||
out, err := runRaw(ctx, dir, env, input, args...)
|
||||
return strings.TrimSpace(out), err
|
||||
}
|
||||
|
||||
func runRaw(dir string, env []string, input string, args ...string) (string, error) {
|
||||
out, stderr, code, err := runCodeInput(context.Background(), dir, env, strings.NewReader(input), args...)
|
||||
func runRaw(ctx context.Context, dir string, env []string, input string, args ...string) (string, error) {
|
||||
out, stderr, code, err := runCodeInput(context.WithoutCancel(ctx), dir, env, strings.NewReader(input), args...)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -371,8 +372,8 @@ func runRaw(dir string, env []string, input string, args ...string) (string, err
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func runCode(dir string, env []string, args ...string) (string, string, int, error) {
|
||||
out, stderr, code, err := runCodeInput(context.Background(), dir, env, nil, args...)
|
||||
func runCode(ctx context.Context, dir string, env []string, args ...string) (string, string, int, error) {
|
||||
out, stderr, code, err := runCodeInput(context.WithoutCancel(ctx), dir, env, nil, args...)
|
||||
return strings.TrimSpace(out), stderr, code, err
|
||||
}
|
||||
|
||||
@@ -384,6 +385,7 @@ func runNetwork(ctx context.Context, dir string, args ...string) (string, string
|
||||
}
|
||||
|
||||
func runCodeInput(ctx context.Context, dir string, env []string, stdin io.Reader, args ...string) (string, string, int, error) {
|
||||
defer trace.Start(ctx, "git "+args[0])()
|
||||
argv := args
|
||||
if args[0] != "config" {
|
||||
argv = append([]string{"-c", "commit.gpgsign=false"}, args...)
|
||||
|
||||
Reference in New Issue
Block a user