Skip to content

Commit 7891473

Browse files
adonovangopherbot
authored andcommitted
gopls/internal/telemetry/cmd/stacks: fix two bugs
1. There were three early returns in the frame -> URL computation, though it was hard to see, and their formatting logic differed. This CL factors them, extracting the frameURL function. 2. When git clone fails (e.g. due to no SSO cert), we failed to clean up the empty dir, causing a persistently stuck failure state. Now we attempt to clean up the directory. (This won't help when the program is terminated from without.) Change-Id: I0f7e2dd26b95899ec85b3e4666def374dc8caadd Reviewed-on: https://go-review.googlesource.com/c/tools/+/613076 LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Robert Findley <[email protected]> Auto-Submit: Alan Donovan <[email protected]>
1 parent 91d4bdb commit 7891473

File tree

1 file changed

+72
-68
lines changed

1 file changed

+72
-68
lines changed

gopls/internal/telemetry/cmd/stacks/stacks.go

Lines changed: 72 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -316,75 +316,11 @@ func newIssue(stack, id string, info Info, jsonURL string, counts map[Info]int64
316316
}
317317

318318
// Parse the stack and get the symbol names out.
319-
for _, line := range strings.Split(stack, "\n") {
320-
// e.g. "golang.org/x/tools/gopls/foo.(*Type).Method.inlined.func3:+5"
321-
symbol, offset, ok := strings.Cut(line, ":")
322-
if !ok {
323-
// Not a symbol (perhaps stack counter title: "gopls/bug"?)
324-
fmt.Fprintf(body, "`%s`\n", line)
325-
continue
326-
}
327-
fileline, ok := pclntab[symbol]
328-
if !ok {
329-
// objdump reports ELF symbol names, which in
330-
// rare cases may be the Go symbols of
331-
// runtime.CallersFrames mangled by (e.g.) the
332-
// addition of .abi0 suffix; see
333-
// https://github.com/golang/go/issues/69390#issuecomment-2343795920
334-
// So this should not be a hard error.
335-
log.Printf("no pclntab info for symbol: %s", symbol)
336-
fmt.Fprintf(body, "`%s`\n", line)
337-
continue
338-
}
339-
if offset == "" {
340-
log.Fatalf("missing line offset: %s", line)
341-
}
342-
offsetNum, err := strconv.Atoi(offset[1:])
343-
if err != nil {
344-
log.Fatalf("invalid line offset: %s", line)
345-
}
346-
linenum := fileline.line
347-
switch offset[0] {
348-
case '-':
349-
linenum -= offsetNum
350-
case '+':
351-
linenum += offsetNum
352-
case '=':
353-
linenum = offsetNum
354-
}
355-
356-
// Construct CodeSearch URL.
357-
var url string
358-
if firstSegment, _, _ := strings.Cut(fileline.file, "/"); !strings.Contains(firstSegment, ".") {
359-
// std
360-
// (First segment is a dir beneath GOROOT/src, not a module domain name.)
361-
url = fmt.Sprintf("https://cs.opensource.google/go/go/+/%s:src/%s;l=%d",
362-
info.GoVersion, fileline.file, linenum)
363-
364-
} else if rest, ok := strings.CutPrefix(fileline.file, "golang.org/x/tools"); ok {
365-
// in x/tools repo (tools or gopls module)
366-
if rest[0] == '/' {
367-
// "golang.org/x/tools/gopls" -> "gopls"
368-
rest = rest[1:]
369-
} else if rest[0] == '@' {
370-
// "golang.org/x/tools@version/dir/file.go" -> "dir/file.go"
371-
rest = rest[strings.Index(rest, "/")+1:]
372-
}
373-
374-
url = fmt.Sprintf("https://cs.opensource.google/go/x/tools/+/%s:%s;l=%d",
375-
"gopls/"+info.Version, rest, linenum)
376-
377-
} else {
378-
// TODO(adonovan): support other module dependencies of gopls.
379-
log.Printf("no CodeSearch URL for %q (%s:%d)",
380-
symbol, fileline.file, linenum)
381-
}
382-
383-
// Emit stack frame.
384-
if url != "" {
385-
fmt.Fprintf(body, "- [`%s`](%s)\n", line, url)
319+
for _, frame := range strings.Split(stack, "\n") {
320+
if url := frameURL(pclntab, info, frame); url != "" {
321+
fmt.Fprintf(body, "- [`%s`](%s)\n", frame, url)
386322
} else {
387-
fmt.Fprintf(body, "- `%s`\n", line)
323+
fmt.Fprintf(body, "- `%s`\n", frame)
388324
}
389325
}
390326

@@ -411,6 +347,73 @@ func newIssue(stack, id string, info Info, jsonURL string, counts map[Info]int64
411347
return title
412348
}
413349

350+
// frameURL returns the CodeSearch URL for the stack frame, if known.
351+
func frameURL(pclntab map[string]FileLine, info Info, frame string) string {
352+
// e.g. "golang.org/x/tools/gopls/foo.(*Type).Method.inlined.func3:+5"
353+
symbol, offset, ok := strings.Cut(frame, ":")
354+
if !ok {
355+
// Not a symbol (perhaps stack counter title: "gopls/bug"?)
356+
return ""
357+
}
358+
359+
fileline, ok := pclntab[symbol]
360+
if !ok {
361+
// objdump reports ELF symbol names, which in
362+
// rare cases may be the Go symbols of
363+
// runtime.CallersFrames mangled by (e.g.) the
364+
// addition of .abi0 suffix; see
365+
// https://github.com/golang/go/issues/69390#issuecomment-2343795920
366+
// So this should not be a hard error.
367+
log.Printf("no pclntab info for symbol: %s", symbol)
368+
return ""
369+
}
370+
371+
if offset == "" {
372+
log.Fatalf("missing line offset: %s", frame)
373+
}
374+
offsetNum, err := strconv.Atoi(offset[1:])
375+
if err != nil {
376+
log.Fatalf("invalid line offset: %s", frame)
377+
}
378+
linenum := fileline.line
379+
switch offset[0] {
380+
case '-':
381+
linenum -= offsetNum
382+
case '+':
383+
linenum += offsetNum
384+
case '=':
385+
linenum = offsetNum
386+
}
387+
388+
// Construct CodeSearch URL.
389+
firstSegment, _, _ := strings.Cut(fileline.file, "/")
390+
if !strings.Contains(firstSegment, ".") {
391+
// std
392+
// (First segment is a dir beneath GOROOT/src, not a module domain name.)
393+
return fmt.Sprintf("https://cs.opensource.google/go/go/+/%s:src/%s;l=%d",
394+
info.GoVersion, fileline.file, linenum)
395+
}
396+
397+
if rest, ok := strings.CutPrefix(fileline.file, "golang.org/x/tools"); ok {
398+
// in x/tools repo (tools or gopls module)
399+
if rest[0] == '/' {
400+
// "golang.org/x/tools/gopls" -> "gopls"
401+
rest = rest[1:]
402+
} else if rest[0] == '@' {
403+
// "golang.org/x/tools@version/dir/file.go" -> "dir/file.go"
404+
rest = rest[strings.Index(rest, "/")+1:]
405+
}
406+
407+
return fmt.Sprintf("https://cs.opensource.google/go/x/tools/+/%s:%s;l=%d",
408+
"gopls/"+info.Version, rest, linenum)
409+
}
410+
411+
// TODO(adonovan): support other module dependencies of gopls.
412+
log.Printf("no CodeSearch URL for %q (%s:%d)",
413+
symbol, fileline.file, linenum)
414+
return ""
415+
}
416+
414417
// -- GitHub search --
415418

416419
// searchIssues queries the GitHub issue tracker.
@@ -504,6 +507,7 @@ func readPCLineTable(info Info) (map[string]FileLine, error) {
504507
if !fileExists(revDir) {
505508
log.Printf("cloning tools@gopls/%s", info.Version)
506509
if err := shallowClone(revDir, "https://go.googlesource.com/tools", "gopls/"+info.Version); err != nil {
510+
_ = os.RemoveAll(revDir) // ignore errors
507511
return nil, fmt.Errorf("clone: %v", err)
508512
}
509513
}

0 commit comments

Comments
 (0)