Skip to content

Commit

Permalink
Merge back CLI tools from v2.1.0.
Browse files Browse the repository at this point in the history
Confirms that it makes v1 work with go1.16. With this:

  go get github.com/maruel/panicparse/cmd/pp

does the right thing! It leverages an updated version of cmd/ and
internal/, and then uses stack@v2 instead of stack/ here.

Found a way to hack my way through:
- Copied .github/workflows/test.yaml from v2.1.0.
- Deleted all of vendor/. It was breaking the CI tests.
- Updated stack/context_test.go to make it work with go1.16.
- Updated stack/context_test.go to make it work with all of vendor/
  removed.
- Use v2.1.0 version of the executables in cmd/ and //main.go.
- Use v2.1.0 version of the internal/.
- Copied stack@v2.1.0 back into
  vendor/github.com/maruel/panicparse/v2/stack. Since older Go versions still
  look into it, they are able to load v2 even if go modules are disabled.
  • Loading branch information
maruel committed Dec 19, 2020
1 parent 025ad72 commit 0b45582
Show file tree
Hide file tree
Showing 47 changed files with 8,613 additions and 270 deletions.
File renamed without changes.
48 changes: 27 additions & 21 deletions cmd/panic/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,26 +37,19 @@ import (

"github.com/maruel/panicparse/cmd/panic/internal"
correct "github.com/maruel/panicparse/cmd/panic/internal/incorrect"
"github.com/maruel/panicparse/cmd/panic/internal/ùtf8"
ùtf8 "github.com/maruel/panicparse/cmd/panic/internal/utf8"
)

func main() {
if len(os.Args) == 2 {
n := os.Args[1]
if f, ok := types[n]; ok {
fmt.Printf("GOTRACEBACK=%s\n", os.Getenv("GOTRACEBACK"))
if n == "simple" {
// Since the map lookup creates another call stack entry, add a one-off
// "simple" panic style to test the very minimal case.
// types["simple"].f is never called.
panic("simple")
}
f.f()
os.Exit(3)
}
// Undocumented command to do a raw dump of the supported commands. This is
// used by unit tests in ../../stack.
if n == "dump_commands" {
switch n := os.Args[1]; n {
case "-h", "-help", "--help", "help":
usage()
os.Exit(0)

case "dump_commands":
// Undocumented command to do a raw dump of the supported commands. This
// is used by unit tests in ../../stack.
items := make([]string, 0, len(types))
for n := range types {
items = append(items, n)
Expand All @@ -66,11 +59,25 @@ func main() {
fmt.Printf("%s\n", n)
}
os.Exit(0)

default:
if f, ok := types[n]; ok {
fmt.Printf("GOTRACEBACK=%s\n", os.Getenv("GOTRACEBACK"))
if n == "simple" {
// Since the map lookup creates another call stack entry, add a
// one-off "simple" panic style to test the very minimal case.
// types["simple"].f is never called.
panic("simple")
}
f.f()
os.Exit(3)
}
fmt.Fprintf(stdErr, "unknown panic style %q\n", n)
os.Exit(1)
}
fmt.Fprintf(stdErr, "unknown panic style %q\n", n)
os.Exit(1)
}
usage()
os.Exit(1)
}

// Mocked in test.
Expand Down Expand Up @@ -111,7 +118,7 @@ func panicRaceDisabled(name string) {

func rerunWithFastCrash() {
if os.Getenv("GORACE") != "log_path=stderr halt_on_error=1" {
os.Setenv("GORACE", "log_path=stderr halt_on_error=1")
_ = os.Setenv("GORACE", "log_path=stderr halt_on_error=1")
c := exec.Command(os.Args[0], os.Args[1:]...)
c.Stderr = os.Stderr
if err, ok := c.Run().(*exec.ExitError); ok {
Expand Down Expand Up @@ -413,7 +420,7 @@ Set GOTRACEBACK before running this tool to see how it affects the panic output.
Select the way to panic:
`
io.WriteString(stdErr, t)
_, _ = io.WriteString(stdErr, t)
names := make([]string, 0, len(types))
m := 0
for n := range types {
Expand All @@ -426,7 +433,6 @@ Select the way to panic:
for _, n := range names {
fmt.Fprintf(stdErr, "- %-*s %s\n", m, n, types[n].desc)
}
os.Exit(2)
}

//
Expand Down
6 changes: 3 additions & 3 deletions cmd/panicweb/internal/internal.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ func GetAsync(url string) {
if err != nil {
log.Fatalf("failed to read: %v", err)
}
resp.Body.Close()
_ = resp.Body.Close()
log.Fatal("the goal is to not complete this request")
}()
}
Expand All @@ -39,7 +39,7 @@ func URL1Handler(w http.ResponseWriter, req *http.Request) {
w.Header().Set("Content-Length", "100000")
w.WriteHeader(200)
b := [4096]byte{}
w.Write(b[:])
_, _ = w.Write(b[:])
<-Unblock
}

Expand All @@ -50,6 +50,6 @@ func URL2Handler(w http.ResponseWriter, req *http.Request) {
w.Header().Set("Content-Length", "100000")
w.WriteHeader(200)
b := [4096]byte{}
w.Write(b[:])
_, _ = w.Write(b[:])
<-Unblock
}
26 changes: 24 additions & 2 deletions cmd/panicweb/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,26 @@ import (
"net"
"net/http"
_ "net/http/pprof"
"os"
"runtime"
"strings"
"sync"
"time"

"github.com/maruel/panicparse/cmd/panicweb/internal"
"github.com/maruel/panicparse/stack/webstack"
"github.com/maruel/panicparse/v2/stack/webstack"
"github.com/mattn/go-colorable"
)

var rootPage = []byte(`<!DOCTYPE html>
<ul>
<li><a href="/panicparse">/panicparse</a></li>
<li><a href="/debug/pprof/goroutine?debug=2">/debug/pprof/goroutine?debug=2</a></li>
<li><a href="/url1">/url1</a></li>
<li><a href="/url2">/url2</a></li>
</ul>
`)

func main() {
allowremote := flag.Bool("allowremote", false, "allows access from non-localhost; implies -wait")
sleep := flag.Bool("wait", false, "sleep instead of crashing")
Expand Down Expand Up @@ -91,10 +101,22 @@ func main() {
} else {
http.HandleFunc("/panicparse", webstack.SnapshotHandler)
}
http.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
w.Header().Set("Content-Type", "text/html; charset=utf-8")
_, _ = w.Write(rootPage)
})
go http.Serve(ln, http.DefaultServeMux)

// Start many clients.
url := "http://" + ln.Addr().String() + "/"
a := ln.Addr()
url := fmt.Sprintf("http://%s/", a)
if *allowremote {
if h, err := os.Hostname(); err == nil {
if t, ok := a.(*net.TCPAddr); ok {
url = fmt.Sprintf("http://%s:%d/", h, t.Port)
}
}
}
for i := 0; i < 10; i++ {
internal.GetAsync(url + "url1")
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/panicweb/main_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ package main
import "golang.org/x/sys/unix"

func sysHang() {
unix.Nanosleep(&unix.Timespec{Sec: 366 * 24 * 60 * 60}, &unix.Timespec{})
_ = unix.Nanosleep(&unix.Timespec{Sec: 366 * 24 * 60 * 60}, &unix.Timespec{})
}
12 changes: 2 additions & 10 deletions cmd/pp/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,10 @@
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.

// panicparse: analyzes stack dump of Go processes and simplifies it.
// pp: analyzes stack dump of Go processes and simplifies it.
//
// It is mostly useful on servers will large number of identical goroutines,
// making the crash dump harder to read than strictly necessary.
//
// Colors:
// - Magenta: first goroutine to be listed.
// - Yellow: main package.
// - Green: standard library.
// - Red: other packages.
//
// Bright colors are used for exported symbols.
package main

import (
Expand All @@ -24,7 +16,7 @@ import (
)

func main() {
if err := internal.Main("/cmd/pp"); err != nil {
if err := internal.Main(); err != nil {
fmt.Fprintf(os.Stderr, "Failed: %s\n", err)
os.Exit(1)
}
Expand Down
9 changes: 5 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ module github.com/maruel/panicparse
go 1.11

require (
github.com/google/go-cmp v0.4.0
github.com/mattn/go-colorable v0.1.6
github.com/google/go-cmp v0.5.1
github.com/maruel/panicparse/v2 v2.1.0
github.com/mattn/go-colorable v0.1.7
github.com/mattn/go-isatty v0.0.12
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d
golang.org/x/sys v0.0.0-20200724161237-0e2f3a69832c
)
16 changes: 10 additions & 6 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/mattn/go-colorable v0.1.6 h1:6Su7aK7lXmJ/U79bYtBjLNaha4Fs1Rg9plHpcH+vvnE=
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/google/go-cmp v0.5.1 h1:JFrFEBb2xKufg6XkJsJr+WbKb4FQlURi5RUcBveYu9k=
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/maruel/panicparse/v2 v2.1.0 h1:Ml+NucJWyfNVA7YVXavI3EAwqGcPEY1epYjs4CSMwy0=
github.com/maruel/panicparse/v2 v2.1.0/go.mod h1:AeTWdCE4lcq8OKsLb6cHSj1RWHVSnV9HBCk7sKLF4Jg=
github.com/mattn/go-colorable v0.1.7 h1:bQGKb3vps/j0E9GfJQ03JyhRuxsvdAanXlT9BTw3mdw=
github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4=
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI=
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae h1:/WDfKMnPU+m5M4xB+6x4kaepxRw6jWvR5iDRdvjHgy8=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200724161237-0e2f3a69832c h1:UIcGWL6/wpCfyGuJnRFJRurA+yj8RrW7Q6x2YMCXt6c=
golang.org/x/sys v0.0.0-20200724161237-0e2f3a69832c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
9 changes: 9 additions & 0 deletions internal/internaltest/go1.13.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// Copyright 2020 Marc-Antoine Ruel. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.

// +build go1.13

package internaltest

const wrap = "%w"
10 changes: 10 additions & 0 deletions internal/internaltest/gopre1.13.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Copyright 2020 Marc-Antoine Ruel. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.

// +build go1.1
// +build !go1.13

package internaltest

const wrap = "%v"
60 changes: 34 additions & 26 deletions internal/internaltest/internaltest.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
package internaltest

import (
"bytes"
"errors"
"fmt"
"os"
"os/exec"
Expand Down Expand Up @@ -121,7 +121,7 @@ func StaticPanicRaceOutput() []byte {
func IsUsingModules() bool {
// Calculate the default. We assume developer builds are recent (go1.14 and
// later).
ver := getGoMinorVersion()
ver := GetGoMinorVersion()
if ver > 0 && ver < 11 {
// go1.9.7+ and go1.10.3+ were fixed to tolerate semantic versioning import
// but they do not support the environment variable.
Expand All @@ -141,14 +141,14 @@ var (
panicOutputs map[string][]byte
)

// getGoMinorVersion returns the Go1 minor version.
// GetGoMinorVersion returns the Go1 minor version.
//
// Returns 0 for a developper build, panics if can't parse the version.
// Returns 0 for a developer build, panics if can't parse the version.
//
// Ignores the revision (go1.<minor>.<revision>).
func getGoMinorVersion() int {
func GetGoMinorVersion() int {
ver := runtime.Version()
if strings.HasPrefix(ver, "devel ") {
if strings.HasPrefix(ver, "devel +") {
return 0
}
if !strings.HasPrefix(ver, "go1.") {
Expand All @@ -159,7 +159,12 @@ func getGoMinorVersion() int {
v := ver[4:]
if i := strings.IndexByte(v, '.'); i != -1 {
v = v[:i]
} else if i := strings.Index(v, "beta"); i != -1 {
v = v[:i]
} else if i := strings.Index(v, "rc"); i != -1 {
v = v[:i]
}

m, err := strconv.Atoi(v)
if err != nil {
panic(fmt.Sprintf("failed to parse %q: %v", ver, err))
Expand All @@ -180,34 +185,37 @@ func build(tool string, race bool) string {
if runtime.GOOS == "windows" {
p += ".exe"
}
path := "github.com/maruel/panicparse/cmd/"
if err := Compile(path+tool, p, "", true, race); err != nil {
_, _ = os.Stderr.WriteString(err.Error())
return ""
}
return p
}

var errNoRace = errors.New("platform does not support -race")

// Compile compiles sources into an executable.
func Compile(in, exe, cwd string, disableInlining, race bool) error {
// Disable inlining otherwise the inlining varies between local execution and
// remote execution. This can be observed as Elided being true without any
// argument.
args := []string{"build", "-gcflags", "-l", "-o", p}
if race {
args = append(args, "-race")
args := []string{"build", "-o", exe}
if disableInlining {
args = append(args, "-gcflags", "-l")
}
path := "github.com/maruel/panicparse/cmd/"
c := exec.Command("go", append(args, path+tool)...)
b := bytes.Buffer{}
c.Stdout = os.Stdout
if race {
c.Stderr = &b
} else {
c.Stderr = os.Stderr
args = append(args, "-race")
}
if err := c.Run(); err != nil {
if race {
if strings.HasPrefix(b.String(), "go test: -race is only supported on ") {
// Race detector is not supported. Calling code with handle.
return ""
}
os.Stderr.Write(b.Bytes())
return ""
c := exec.Command("go", append(args, in)...)
c.Dir = cwd
if out, err := c.CombinedOutput(); err != nil {
if race && strings.HasPrefix(string(out), "go test: -race is only supported on ") {
return errNoRace
}
return ""
return fmt.Errorf("compile failure: "+wrap+"\n%s", err, out)
}
return p
return nil
}

// execRun runs a command and returns the combined output.
Expand Down
Loading

0 comments on commit 0b45582

Please sign in to comment.