├── test-fixtures ├── empty_input.txt ├── empty_stack.txt ├── empty_input.golden.json ├── partial_stack.txt ├── windows.txt ├── empty_stack.golden.json ├── partial_stack.golden.json ├── partial_createdby.golden.json ├── partial_createdby.txt ├── errorhandling.txt ├── go121_createdby.go ├── windows.golden.json ├── frameselided.go ├── frameselided_goroutine.go ├── go121_createdby.txt ├── lockedm.txt ├── errorhandling.golden.json ├── cgo.go ├── lockedm.golden.json ├── go121_createdby.golden.json ├── ancestors.go ├── cgo.txt ├── cgo.golden.json ├── ancestors.txt ├── waitsince.txt ├── waitsince.golden.json ├── frameselided.txt ├── frameselided_goroutine.txt ├── ancestors.golden.json ├── frameselided.golden.json └── frameselided_goroutine.golden.json ├── LICENSE-3rdparty.csv ├── go.mod ├── .github └── workflows │ └── go.yml ├── example └── main.go ├── fuzz.go ├── cmd └── gostack2json │ └── main.go ├── go.sum ├── CONTRIBUTING.md ├── panicparse_test.go.disabled ├── LICENSE-BSD3 ├── README.md ├── gostackparse.go ├── LICENSE-APACHE ├── LICENSE └── gostackparse_test.go /test-fixtures/empty_input.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /LICENSE-3rdparty.csv: -------------------------------------------------------------------------------- 1 | Component,Origin,License,Copyright 2 | -------------------------------------------------------------------------------- /test-fixtures/empty_stack.txt: -------------------------------------------------------------------------------- 1 | goroutine 1 [running]: 2 | 3 | goroutine 2 [running]: 4 | -------------------------------------------------------------------------------- /test-fixtures/empty_input.golden.json: -------------------------------------------------------------------------------- 1 | { 2 | "Errors": null, 3 | "Goroutines": null 4 | } 5 | -------------------------------------------------------------------------------- /test-fixtures/partial_stack.txt: -------------------------------------------------------------------------------- 1 | goroutine 1 [running]: 2 | main.main() 3 | 4 | goroutine 2 [running]: 5 | main.main() 6 | -------------------------------------------------------------------------------- /test-fixtures/windows.txt: -------------------------------------------------------------------------------- 1 | goroutine 1 [running]: 2 | runtime/pprof.writeGoroutineStacks(0x14e5940, 0xc0000abc50, 0x101b8a5, 0xc000333d20) 3 | C:/Users/felixge/pprof.go:693 +0x9f 4 | -------------------------------------------------------------------------------- /test-fixtures/empty_stack.golden.json: -------------------------------------------------------------------------------- 1 | { 2 | "Errors": [ 3 | "invalid function call on line 2: \"\"", 4 | "invalid function call on line 4: \"\"" 5 | ], 6 | "Goroutines": [] 7 | } 8 | -------------------------------------------------------------------------------- /test-fixtures/partial_stack.golden.json: -------------------------------------------------------------------------------- 1 | { 2 | "Errors": [ 3 | "invalid file:line ref on line 3: \"\"", 4 | "invalid file:line ref on line 6: \"\"" 5 | ], 6 | "Goroutines": [] 7 | } 8 | -------------------------------------------------------------------------------- /test-fixtures/partial_createdby.golden.json: -------------------------------------------------------------------------------- 1 | { 2 | "Errors": [ 3 | "invalid file:line ref on line 5: \"\"", 4 | "invalid file:line ref on line 10: \"\"" 5 | ], 6 | "Goroutines": [] 7 | } 8 | -------------------------------------------------------------------------------- /test-fixtures/partial_createdby.txt: -------------------------------------------------------------------------------- 1 | goroutine 1 [running]: 2 | main.foo() 3 | /example/main.go:182 +0x123 4 | created by main.main 5 | 6 | goroutine 2 [running]: 7 | main.foo() 8 | /example/main.go:183 +0x123 9 | created by main.foo 10 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/DataDog/gostackparse 2 | 3 | go 1.18 4 | 5 | require github.com/stretchr/testify v1.7.0 6 | 7 | require ( 8 | github.com/davecgh/go-spew v1.1.0 // indirect 9 | github.com/pmezard/go-difflib v1.0.0 // indirect 10 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect 11 | ) 12 | -------------------------------------------------------------------------------- /test-fixtures/errorhandling.txt: -------------------------------------------------------------------------------- 1 | goroutine 1 [running]: 2 | main.main() 3 | /example/main.go:152 +0x3d2 4 | 5 | goroutine 2 [running]: 6 | main.main)( 7 | /example/main.go:152 +0x3d2 8 | 9 | goroutine 3 [running]: 10 | main.foo() 11 | /example/main.go:182 +0x123 12 | created by main.main 13 | /example/main.go:110 +0x456 14 | -------------------------------------------------------------------------------- /test-fixtures/go121_createdby.go: -------------------------------------------------------------------------------- 1 | //go:build ignore 2 | // +build ignore 3 | 4 | package main 5 | 6 | import ( 7 | "fmt" 8 | "runtime" 9 | "sync" 10 | ) 11 | 12 | func main() { 13 | var wg sync.WaitGroup 14 | wg.Add(1) 15 | go func() { 16 | defer wg.Done() 17 | printStack() 18 | }() 19 | wg.Wait() 20 | } 21 | 22 | func printStack() { 23 | buf := make([]byte, 1<<20) 24 | n := runtime.Stack(buf, true) 25 | fmt.Printf("%s\n", buf[:n]) 26 | } 27 | -------------------------------------------------------------------------------- /test-fixtures/windows.golden.json: -------------------------------------------------------------------------------- 1 | { 2 | "Errors": null, 3 | "Goroutines": [ 4 | { 5 | "ID": 1, 6 | "State": "running", 7 | "Wait": 0, 8 | "LockedToThread": false, 9 | "Stack": [ 10 | { 11 | "Func": "runtime/pprof.writeGoroutineStacks", 12 | "File": "C:/Users/felixge/pprof.go", 13 | "Line": 693 14 | } 15 | ], 16 | "FramesElided": false, 17 | "CreatedBy": null 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /.github/workflows/go.yml: -------------------------------------------------------------------------------- 1 | name: Go 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | pull_request: 7 | branches: [main] 8 | 9 | jobs: 10 | test: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v2 14 | 15 | - name: Set up Go 16 | uses: actions/setup-go@v2 17 | with: 18 | go-version: 1.24 19 | 20 | - name: Build 21 | run: go build -v ./... 22 | 23 | - name: Test 24 | run: go test -v ./... 25 | -------------------------------------------------------------------------------- /example/main.go: -------------------------------------------------------------------------------- 1 | // Unless explicitly stated otherwise all files in this repository are licensed 2 | // under the Apache License Version 2.0. 3 | // This product includes software developed at Datadog (https://www.datadoghq.com/). 4 | // Copyright 2021 Datadog, Inc. 5 | 6 | package main 7 | 8 | import ( 9 | "bytes" 10 | "encoding/json" 11 | "os" 12 | "runtime/debug" 13 | 14 | "github.com/DataDog/gostackparse" 15 | ) 16 | 17 | func main() { 18 | stack := debug.Stack() 19 | goroutines, _ := gostackparse.Parse(bytes.NewReader(stack)) 20 | json.NewEncoder(os.Stdout).Encode(goroutines) 21 | } 22 | -------------------------------------------------------------------------------- /test-fixtures/frameselided.go: -------------------------------------------------------------------------------- 1 | //+build ignore 2 | 3 | // Unless explicitly stated otherwise all files in this repository are licensed 4 | // under the Apache License Version 2.0. 5 | // This product includes software developed at Datadog (https://www.datadoghq.com/). 6 | // Copyright 2016 Datadog, Inc. 7 | 8 | package main 9 | 10 | import ( 11 | "os" 12 | "runtime/pprof" 13 | ) 14 | 15 | func main() { 16 | stackDump(100) 17 | } 18 | 19 | func stackDump(remaining int) { 20 | if remaining > 0 { 21 | stackDump(remaining - 1) 22 | } else { 23 | pprof.Lookup("goroutine").WriteTo(os.Stdout, 2) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /fuzz.go: -------------------------------------------------------------------------------- 1 | // Unless explicitly stated otherwise all files in this repository are licensed 2 | // under the Apache License Version 2.0. 3 | // This product includes software developed at Datadog (https://www.datadoghq.com/). 4 | // Copyright 2016 Datadog, Inc. 5 | 6 | //+build gofuzz 7 | 8 | package gostackparse 9 | 10 | import "bytes" 11 | 12 | // Fuzz implements fuzzing using https://github.com/dvyukov/go-fuzz. See 13 | // TestFuzzCorupus for generating an initial test corpus. 14 | func Fuzz(data []byte) int { 15 | goroutines, _ := Parse(bytes.NewReader(data)) 16 | if len(goroutines) > 0 { 17 | return 1 18 | } 19 | return 0 20 | } 21 | -------------------------------------------------------------------------------- /test-fixtures/frameselided_goroutine.go: -------------------------------------------------------------------------------- 1 | //+build ignore 2 | 3 | // Unless explicitly stated otherwise all files in this repository are licensed 4 | // under the Apache License Version 2.0. 5 | // This product includes software developed at Datadog (https://www.datadoghq.com/). 6 | // Copyright 2016 Datadog, Inc. 7 | 8 | package main 9 | 10 | import ( 11 | "os" 12 | "runtime/pprof" 13 | ) 14 | 15 | func main() { 16 | wait := make(chan struct{}) 17 | go stackDump(100, wait) 18 | <-wait 19 | } 20 | 21 | func stackDump(remaining int, done chan struct{}) { 22 | if remaining > 0 { 23 | stackDump(remaining-1, done) 24 | } else { 25 | pprof.Lookup("goroutine").WriteTo(os.Stdout, 2) 26 | done <- struct{}{} 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /test-fixtures/go121_createdby.txt: -------------------------------------------------------------------------------- 1 | goroutine 18 [running]: 2 | main.printStack() 3 | /Users/nick.ripley/repos/gostackparse/test-fixtures/go121_createdby.go:23 +0x40 4 | main.main.func1() 5 | /Users/nick.ripley/repos/gostackparse/test-fixtures/go121_createdby.go:16 +0x4c 6 | created by main.main in goroutine 1 7 | /Users/nick.ripley/repos/gostackparse/test-fixtures/go121_createdby.go:14 +0x70 8 | 9 | goroutine 1 [semacquire]: 10 | sync.runtime_Semacquire(0x140000021a0?) 11 | /Users/nick.ripley/repos/go/src/runtime/sema.go:62 +0x2c 12 | sync.(*WaitGroup).Wait(0x1400011a010) 13 | /Users/nick.ripley/repos/go/src/sync/waitgroup.go:116 +0x74 14 | main.main() 15 | /Users/nick.ripley/repos/gostackparse/test-fixtures/go121_createdby.go:18 +0x78 -------------------------------------------------------------------------------- /test-fixtures/lockedm.txt: -------------------------------------------------------------------------------- 1 | goroutine 7 [running, locked to thread]: 2 | testing.tRunner.func1.1(0x12081c0, 0x1290cd0) 3 | /usr/local/Cellar/go/1.15.6/libexec/src/testing/testing.go:1072 +0x30d 4 | testing.tRunner.func1(0xc000001b00) 5 | /usr/local/Cellar/go/1.15.6/libexec/src/testing/testing.go:1075 +0x41a 6 | panic(0x12081c0, 0x1290cd0) 7 | /usr/local/Cellar/go/1.15.6/libexec/src/runtime/panic.go:969 +0x1b9 8 | gopkg.in/DataDog/dd-trace-go.v1/profiler/internal/stackparse.TestParse_Example(0xc000001b00) 9 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/stackparse_test.go:21 +0x45 10 | testing.tRunner(0xc000001b00, 0x1263488) 11 | /usr/local/Cellar/go/1.15.6/libexec/src/testing/testing.go:1123 +0xef 12 | created by testing.(*T).Run 13 | /usr/local/Cellar/go/1.15.6/libexec/src/testing/testing.go:1168 +0x2b3 14 | -------------------------------------------------------------------------------- /test-fixtures/errorhandling.golden.json: -------------------------------------------------------------------------------- 1 | { 2 | "Errors": [ 3 | "invalid function call on line 6: \"main.main)(\"" 4 | ], 5 | "Goroutines": [ 6 | { 7 | "ID": 1, 8 | "State": "running", 9 | "Wait": 0, 10 | "LockedToThread": false, 11 | "Stack": [ 12 | { 13 | "Func": "main.main", 14 | "File": "/example/main.go", 15 | "Line": 152 16 | } 17 | ], 18 | "FramesElided": false, 19 | "CreatedBy": null 20 | }, 21 | { 22 | "ID": 3, 23 | "State": "running", 24 | "Wait": 0, 25 | "LockedToThread": false, 26 | "Stack": [ 27 | { 28 | "Func": "main.foo", 29 | "File": "/example/main.go", 30 | "Line": 182 31 | } 32 | ], 33 | "FramesElided": false, 34 | "CreatedBy": { 35 | "Func": "main.main", 36 | "File": "/example/main.go", 37 | "Line": 110 38 | } 39 | } 40 | ] 41 | } 42 | -------------------------------------------------------------------------------- /cmd/gostack2json/main.go: -------------------------------------------------------------------------------- 1 | // Unless explicitly stated otherwise all files in this repository are licensed 2 | // under the Apache License Version 2.0. 3 | // This product includes software developed at Datadog (https://www.datadoghq.com/). 4 | // Copyright 2021 Datadog, Inc. 5 | 6 | package main 7 | 8 | import ( 9 | "encoding/json" 10 | "fmt" 11 | "os" 12 | 13 | stackparse "github.com/DataDog/gostackparse" 14 | ) 15 | 16 | // usage: go run stack2json.go < example.txt 17 | func main() { 18 | if err := run(); err != nil { 19 | fmt.Fprintln(os.Stderr, err) 20 | os.Exit(1) 21 | } 22 | } 23 | 24 | func run() error { 25 | gs, errs := stackparse.Parse(os.Stdin) 26 | out, err := json.MarshalIndent(gs, "", " ") 27 | if err != nil { 28 | return err 29 | } 30 | fmt.Printf("%s\n", out) 31 | 32 | if len(errs) > 0 { 33 | for i, e := range errs { 34 | fmt.Printf("error %d: %s\n", i+1, e) 35 | } 36 | return fmt.Errorf("%d errors occured", len(errs)) 37 | } 38 | return nil 39 | } 40 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= 2 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 3 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 4 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 5 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 6 | github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= 7 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 8 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 9 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 10 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= 11 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 12 | -------------------------------------------------------------------------------- /test-fixtures/cgo.go: -------------------------------------------------------------------------------- 1 | //+build ignore 2 | 3 | // Unless explicitly stated otherwise all files in this repository are licensed 4 | // under the Apache License Version 2.0. 5 | // This product includes software developed at Datadog (https://www.datadoghq.com/). 6 | // Copyright 2016 Datadog, Inc. 7 | 8 | package main 9 | 10 | import ( 11 | "runtime/pprof" 12 | /* 13 | #include 14 | 15 | extern int goSleep(int usec); 16 | 17 | static void __attribute__ ((noinline)) c_sleep(int usec) { 18 | usleep(usec); 19 | } 20 | 21 | static void c_sleep_loop(int usec) { 22 | while (1) { 23 | c_sleep(usec); 24 | } 25 | } 26 | 27 | static void c_go_sleep_loop(int usec) { 28 | while (1) { 29 | goSleep(usec); 30 | } 31 | } 32 | */ 33 | "C" 34 | ) 35 | import ( 36 | "os" 37 | "time" 38 | ) 39 | 40 | func main() { 41 | go cSleepLoop(time.Second) 42 | go cGoSleepLoop(time.Second) 43 | 44 | time.Sleep(time.Second / 10) 45 | pprof.Lookup("goroutine").WriteTo(os.Stdout, 2) 46 | } 47 | 48 | func cSleepLoop(d time.Duration) { 49 | C.c_sleep_loop(C.int(d.Microseconds())) 50 | } 51 | 52 | func cGoSleepLoop(d time.Duration) { 53 | C.c_go_sleep_loop(C.int(d.Microseconds())) 54 | } 55 | 56 | //export goSleep 57 | func goSleep(usec C.int) C.int { 58 | time.Sleep(time.Duration(usec) * time.Microsecond) 59 | return 0 60 | } 61 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Contributions are welcome. For smaller changes feel free to send a PR directly, but for big stuff it probably makes sense to open an issue first to discuss it. 4 | 5 | Please always try to clearly describe what problem you are trying to solve (intend) rather then just describing the change your are trying to make. 6 | 7 | ## Runbook 8 | 9 | Below are various commands and procedures that might be useful for people trying to contribute to this package. 10 | 11 | ``` 12 | # run all tests 13 | go test -v 14 | 15 | # run all benchmarks 16 | cp panicparse_test.go.disabled panicparse_test.go && go get -t . && go test -bench . 17 | 18 | ### FUZZING ### 19 | # generate fuzz-corpus directory (takes > 10s, generated 434MiB of data) 20 | FUZZ_CORPUS=true go test 21 | # alternative to the above corpus generation (doesn't seem to work as well) 22 | mkdir -p corpus && cp test-fixtures/*.txt corpus 23 | # install/update go-fuzz 24 | go get -u github.com/dvyukov/go-fuzz/go-fuzz github.com/dvyukov/go-fuzz/go-fuzz-build 25 | # build the test program with necessary instrumentation 26 | go-fuzz-build 27 | # start fuzzing, then wait for a while to see if it finds any issues 28 | go-fuzz 29 | # cleanup 30 | rm -rf gostackparse-fuzz.zip corpus 31 | 32 | # refresh go.dev cache by visiting this URL with latest version 33 | https://pkg.go.dev/github.com/DataDog/gostackparse@v0.4.0 34 | ``` 35 | -------------------------------------------------------------------------------- /panicparse_test.go.disabled: -------------------------------------------------------------------------------- 1 | // Unless explicitly stated otherwise all files in this repository are licensed 2 | // under the Apache License Version 2.0. 3 | // This product includes software developed at Datadog (https://www.datadoghq.com/). 4 | // Copyright 2021 Datadog, Inc. 5 | 6 | // NOTE(fg): To run this benchmark you have to drop the ".disabled" suffix from 7 | // the filename. This is done to avoid the panicparse library ending up in the 8 | // go.mod file of this package. If anybody has better ideas, please let me know 9 | // : ). 10 | 11 | package gostackparse 12 | 13 | import ( 14 | "bytes" 15 | "io" 16 | "io/ioutil" 17 | "path/filepath" 18 | "testing" 19 | "time" 20 | 21 | "github.com/maruel/panicparse/v2/stack" 22 | "github.com/stretchr/testify/require" 23 | ) 24 | 25 | func BenchmarkPanicparse(b *testing.B) { 26 | data, err := ioutil.ReadFile(filepath.Join("test-fixtures", "waitsince.txt")) 27 | require.NoError(b, err) 28 | 29 | b.ResetTimer() 30 | b.ReportAllocs() 31 | 32 | start := time.Now() 33 | parsedBytes := 0 34 | for i := 0; i < b.N; i++ { 35 | parsedBytes += len(data) 36 | s, _, err := stack.ScanSnapshot(bytes.NewReader(data), io.Discard, stack.DefaultOpts()) 37 | if err != nil && err != io.EOF { 38 | b.Fatal(err) 39 | } else if l := len(s.Goroutines); l != 9 { 40 | b.Fatal(l) 41 | } 42 | } 43 | 44 | mbPerSec := float64(parsedBytes) / time.Since(start).Seconds() / 1024 / 1024 45 | b.ReportMetric(mbPerSec, "MiB/s") 46 | } 47 | -------------------------------------------------------------------------------- /test-fixtures/lockedm.golden.json: -------------------------------------------------------------------------------- 1 | { 2 | "Errors": null, 3 | "Goroutines": [ 4 | { 5 | "ID": 7, 6 | "State": "running", 7 | "Wait": 0, 8 | "LockedToThread": true, 9 | "Stack": [ 10 | { 11 | "Func": "testing.tRunner.func1.1", 12 | "File": "/usr/local/Cellar/go/1.15.6/libexec/src/testing/testing.go", 13 | "Line": 1072 14 | }, 15 | { 16 | "Func": "testing.tRunner.func1", 17 | "File": "/usr/local/Cellar/go/1.15.6/libexec/src/testing/testing.go", 18 | "Line": 1075 19 | }, 20 | { 21 | "Func": "panic", 22 | "File": "/usr/local/Cellar/go/1.15.6/libexec/src/runtime/panic.go", 23 | "Line": 969 24 | }, 25 | { 26 | "Func": "gopkg.in/DataDog/dd-trace-go.v1/profiler/internal/stackparse.TestParse_Example", 27 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/stackparse_test.go", 28 | "Line": 21 29 | }, 30 | { 31 | "Func": "testing.tRunner", 32 | "File": "/usr/local/Cellar/go/1.15.6/libexec/src/testing/testing.go", 33 | "Line": 1123 34 | } 35 | ], 36 | "FramesElided": false, 37 | "CreatedBy": { 38 | "Func": "testing.(*T).Run", 39 | "File": "/usr/local/Cellar/go/1.15.6/libexec/src/testing/testing.go", 40 | "Line": 1168 41 | } 42 | } 43 | ] 44 | } 45 | -------------------------------------------------------------------------------- /LICENSE-BSD3: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016-Present, Datadog 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | * Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | * Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | * Neither the name of Datadog nor the 12 | names of its contributors may be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 19 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | -------------------------------------------------------------------------------- /test-fixtures/go121_createdby.golden.json: -------------------------------------------------------------------------------- 1 | { 2 | "Errors": null, 3 | "Goroutines": [ 4 | { 5 | "ID": 18, 6 | "State": "running", 7 | "Wait": 0, 8 | "LockedToThread": false, 9 | "Stack": [ 10 | { 11 | "Func": "main.printStack", 12 | "File": "/Users/nick.ripley/repos/gostackparse/test-fixtures/go121_createdby.go", 13 | "Line": 23 14 | }, 15 | { 16 | "Func": "main.main.func1", 17 | "File": "/Users/nick.ripley/repos/gostackparse/test-fixtures/go121_createdby.go", 18 | "Line": 16 19 | } 20 | ], 21 | "FramesElided": false, 22 | "CreatedBy": { 23 | "Func": "main.main", 24 | "File": "/Users/nick.ripley/repos/gostackparse/test-fixtures/go121_createdby.go", 25 | "Line": 14 26 | } 27 | }, 28 | { 29 | "ID": 1, 30 | "State": "semacquire", 31 | "Wait": 0, 32 | "LockedToThread": false, 33 | "Stack": [ 34 | { 35 | "Func": "sync.runtime_Semacquire", 36 | "File": "/Users/nick.ripley/repos/go/src/runtime/sema.go", 37 | "Line": 62 38 | }, 39 | { 40 | "Func": "sync.(*WaitGroup).Wait", 41 | "File": "/Users/nick.ripley/repos/go/src/sync/waitgroup.go", 42 | "Line": 116 43 | }, 44 | { 45 | "Func": "main.main", 46 | "File": "/Users/nick.ripley/repos/gostackparse/test-fixtures/go121_createdby.go", 47 | "Line": 18 48 | } 49 | ], 50 | "FramesElided": false, 51 | "CreatedBy": null 52 | } 53 | ] 54 | } 55 | -------------------------------------------------------------------------------- /test-fixtures/ancestors.go: -------------------------------------------------------------------------------- 1 | //+build ignore 2 | 3 | // Unless explicitly stated otherwise all files in this repository are licensed 4 | // under the Apache License Version 2.0. 5 | // This product includes software developed at Datadog (https://www.datadoghq.com/). 6 | // Copyright 2016 Datadog, Inc. 7 | 8 | package main 9 | 10 | import ( 11 | "fmt" 12 | "runtime" 13 | ) 14 | 15 | // adapted from https://github.com/golang/go/issues/22289 16 | // run with GODEBUG=tracebackancestors=10 go run ancestors.go 17 | func main() { 18 | w := make(chan struct{}) 19 | go foo(w, 5) 20 | <-w 21 | x := make(chan struct{}) 22 | go foo(x, 3) 23 | <-x 24 | fmt.Print(string(stackAll())) 25 | close(w) 26 | } 27 | 28 | func stackAll() []byte { 29 | buf := make([]byte, 1024) 30 | for { 31 | n := runtime.Stack(buf, true) 32 | if n < len(buf) { 33 | return buf[:n] 34 | } 35 | buf = make([]byte, 2*len(buf)) 36 | } 37 | } 38 | 39 | const maxStackDepth = 5 40 | 41 | func foo(w chan struct{}, timesToCallGo int) { 42 | if timesToCallGo == 0 { 43 | w <- struct{}{} 44 | <-w 45 | return 46 | } 47 | if timesToCallGo%2 == 0 { 48 | d1(func() { foo(w, timesToCallGo-1) }, maxStackDepth) 49 | } else { 50 | d1(func() { bar(w, timesToCallGo-1) }, maxStackDepth) 51 | } 52 | } 53 | 54 | func bar(w chan struct{}, timesToCallGo int) { 55 | if timesToCallGo == 0 { 56 | w <- struct{}{} 57 | <-w 58 | return 59 | } 60 | if timesToCallGo%2 == 0 { 61 | d1(func() { foo(w, timesToCallGo-1) }, maxStackDepth) 62 | } else { 63 | d1(func() { bar(w, timesToCallGo-1) }, maxStackDepth) 64 | } 65 | } 66 | 67 | func d1(fn func(), timesToRecurse int) { 68 | if timesToRecurse == 0 { 69 | go fn() 70 | return 71 | } 72 | d1(fn, timesToRecurse-1) 73 | } 74 | -------------------------------------------------------------------------------- /test-fixtures/cgo.txt: -------------------------------------------------------------------------------- 1 | goroutine 1 [running]: 2 | runtime/pprof.writeGoroutineStacks(0x4124060, 0xc000010018, 0x1000000000030, 0x4713e40) 3 | /usr/local/Cellar/go/1.15.6/libexec/src/runtime/pprof/pprof.go:693 +0x9f 4 | runtime/pprof.writeGoroutine(0x4124060, 0xc000010018, 0x2, 0x0, 0x50) 5 | /usr/local/Cellar/go/1.15.6/libexec/src/runtime/pprof/pprof.go:682 +0x45 6 | runtime/pprof.(*Profile).WriteTo(0x41b45a0, 0x4124060, 0xc000010018, 0x2, 0xffffffff, 0xc00007a058) 7 | /usr/local/Cellar/go/1.15.6/libexec/src/runtime/pprof/pprof.go:331 +0x3f2 8 | main.main() 9 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/cgo.go:40 +0xbb 10 | 11 | goroutine 6 [syscall]: 12 | main._Cfunc_c_sleep_loop(0xf4240) 13 | _cgo_gotypes.go:56 +0x45 14 | main.cSleepLoop(0x3b9aca00) 15 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/cgo.go:44 +0x45 16 | created by main.main 17 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/cgo.go:36 +0x45 18 | 19 | goroutine 7 [sleep, locked to thread]: 20 | time.Sleep(0x3b9aca00) 21 | /usr/local/Cellar/go/1.15.6/libexec/src/runtime/time.go:188 +0xbf 22 | main.goSleep(...) 23 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/cgo.go:53 24 | main._cgoexpwrap_65ad5df3a112_goSleep(0xf4240, 0xc000001b00) 25 | _cgo_gotypes.go:73 +0x34 26 | main._Cfunc_c_go_sleep_loop(0xf4240) 27 | _cgo_gotypes.go:43 +0x45 28 | main.cGoSleepLoop(0x3b9aca00) 29 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/cgo.go:48 +0x45 30 | created by main.main 31 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/cgo.go:37 +0x66 32 | -------------------------------------------------------------------------------- /test-fixtures/cgo.golden.json: -------------------------------------------------------------------------------- 1 | { 2 | "Errors": null, 3 | "Goroutines": [ 4 | { 5 | "ID": 1, 6 | "State": "running", 7 | "Wait": 0, 8 | "LockedToThread": false, 9 | "Stack": [ 10 | { 11 | "Func": "runtime/pprof.writeGoroutineStacks", 12 | "File": "/usr/local/Cellar/go/1.15.6/libexec/src/runtime/pprof/pprof.go", 13 | "Line": 693 14 | }, 15 | { 16 | "Func": "runtime/pprof.writeGoroutine", 17 | "File": "/usr/local/Cellar/go/1.15.6/libexec/src/runtime/pprof/pprof.go", 18 | "Line": 682 19 | }, 20 | { 21 | "Func": "runtime/pprof.(*Profile).WriteTo", 22 | "File": "/usr/local/Cellar/go/1.15.6/libexec/src/runtime/pprof/pprof.go", 23 | "Line": 331 24 | }, 25 | { 26 | "Func": "main.main", 27 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/cgo.go", 28 | "Line": 40 29 | } 30 | ], 31 | "FramesElided": false, 32 | "CreatedBy": null 33 | }, 34 | { 35 | "ID": 6, 36 | "State": "syscall", 37 | "Wait": 0, 38 | "LockedToThread": false, 39 | "Stack": [ 40 | { 41 | "Func": "main._Cfunc_c_sleep_loop", 42 | "File": "_cgo_gotypes.go", 43 | "Line": 56 44 | }, 45 | { 46 | "Func": "main.cSleepLoop", 47 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/cgo.go", 48 | "Line": 44 49 | } 50 | ], 51 | "FramesElided": false, 52 | "CreatedBy": { 53 | "Func": "main.main", 54 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/cgo.go", 55 | "Line": 36 56 | } 57 | }, 58 | { 59 | "ID": 7, 60 | "State": "sleep", 61 | "Wait": 0, 62 | "LockedToThread": true, 63 | "Stack": [ 64 | { 65 | "Func": "time.Sleep", 66 | "File": "/usr/local/Cellar/go/1.15.6/libexec/src/runtime/time.go", 67 | "Line": 188 68 | }, 69 | { 70 | "Func": "main.goSleep", 71 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/cgo.go", 72 | "Line": 53 73 | }, 74 | { 75 | "Func": "main._cgoexpwrap_65ad5df3a112_goSleep", 76 | "File": "_cgo_gotypes.go", 77 | "Line": 73 78 | }, 79 | { 80 | "Func": "main._Cfunc_c_go_sleep_loop", 81 | "File": "_cgo_gotypes.go", 82 | "Line": 43 83 | }, 84 | { 85 | "Func": "main.cGoSleepLoop", 86 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/cgo.go", 87 | "Line": 48 88 | } 89 | ], 90 | "FramesElided": false, 91 | "CreatedBy": { 92 | "Func": "main.main", 93 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/cgo.go", 94 | "Line": 37 95 | } 96 | } 97 | ] 98 | } 99 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![ci test status](https://img.shields.io/github/workflow/status/DataDog/gostackparse/Go?label=tests)](https://github.com/DataDog/gostackparse/actions/workflows/go.yml?query=branch%3Amain) 2 | [![documentation](http://img.shields.io/badge/godoc-reference-blue.svg)](https://pkg.go.dev/github.com/DataDog/gostackparse) 3 | 4 | # gostackparse 5 | 6 | Package gostackparse parses goroutines stack traces as produced by [`panic()`](https://golang.org/pkg/builtin/#panic) or [`debug.Stack()`](https://golang.org/pkg/runtime/debug/#Stack) at ~300 MiB/s. 7 | 8 | Parsing this data can be useful for [Goroutine Profiling](https://github.com/DataDog/go-profiler-notes/blob/main/goroutine.md#feature-matrix) or analyzing crashes from log files. 9 | 10 | ## Usage 11 | 12 | The package provides a simple [Parse()](https://pkg.go.dev/github.com/DataDog/gostackparse#Parse) API. You can use it like [this](./example): 13 | 14 | ```go 15 | import "github.com/DataDog/gostackparse" 16 | 17 | func main() { 18 | // Get a text-based stack trace 19 | stack := debug.Stack() 20 | // Parse it 21 | goroutines, _ := gostackparse.Parse(bytes.NewReader(stack)) 22 | // Ouptut the results 23 | json.NewEncoder(os.Stdout).Encode(goroutines) 24 | } 25 | ``` 26 | 27 | The result is a simple list of [Goroutine](https://pkg.go.dev/github.com/DataDog/gostackparse#Goroutine) structs: 28 | 29 | ``` 30 | [ 31 | { 32 | "ID": 1, 33 | "State": "running", 34 | "Wait": 0, 35 | "LockedToThread": false, 36 | "Stack": [ 37 | { 38 | "Func": "runtime/debug.Stack", 39 | "File": "/usr/local/Cellar/go/1.16/libexec/src/runtime/debug/stack.go", 40 | "Line": 24 41 | }, 42 | { 43 | "Func": "main.main", 44 | "File": "/home/go/src/github.com/DataDog/gostackparse/example/main.go", 45 | "Line": 18 46 | } 47 | ], 48 | "FramesElided": false, 49 | "CreatedBy": null 50 | } 51 | ] 52 | ``` 53 | 54 | ## Design Goals 55 | 56 | 1. Safe: No panics should be thrown. 57 | 2. Simple: Keep this pkg small and easy to modify. 58 | 3. Forgiving: Favor producing partial results over no results, even if the input data is different than expected. 59 | 4. Efficient: Parse several hundred MiB/s. 60 | 61 | ## Testing 62 | 63 | gostackparse has been tested using a combination of hand picked [test-fixtures](./test-fixtures), [property based testing](https://github.com/DataDog/gostackparse/search?q=TestParse_PropertyBased), and [fuzzing](https://github.com/DataDog/gostackparse/search?q=Fuzz). 64 | 65 | ## Comparsion to panicparse 66 | 67 | [panicparse](https://github.com/maruel/panicparse) is a popular library implementing similar functionality. 68 | 69 | gostackparse was created to provide a subset of the functionality (only the parsing) using ~10x less code while achieving > 100x faster performance. If you like fast minimalistic code, you might prefer it. If you're looking for more features and a larger community, use panicparse. 70 | 71 | ## Benchmarks 72 | 73 | gostackparse includes a small benchmark that shows that it can parse [test-fixtures/waitsince.txt](./test-fixtures/waitsince.txt) at ~300 MiB/s and how that compares to panicparse. 74 | 75 | ``` 76 | $ cp panicparse_test.go.disabled panicparse_test.go 77 | $ go get -t . 78 | $ go test -bench . 79 | goos: darwin 80 | goarch: amd64 81 | pkg: github.com/DataDog/gostackparse 82 | cpu: Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz 83 | BenchmarkGostackparse-12 45456 26275 ns/op 302.34 MiB/s 17243 B/op 306 allocs/op 84 | BenchmarkPanicparse-12 76 15943320 ns/op 0.50 MiB/s 5274247 B/op 116049 allocs/op 85 | PASS 86 | ok github.com/DataDog/gostackparse 3.634s 87 | ``` 88 | 89 | ## License 90 | 91 | This work is dual-licensed under Apache 2.0 or BSD3. See [LICENSE](./LICENSE). 92 | -------------------------------------------------------------------------------- /test-fixtures/ancestors.txt: -------------------------------------------------------------------------------- 1 | goroutine 1 [running]: 2 | main.stackAll() 3 | /Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go:31 +0x8c 4 | main.main() 5 | /Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go:24 +0xb8 6 | 7 | goroutine 25 [chan receive]: 8 | main.bar(0x140000a4060, 0x0) 9 | /Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go:57 +0x11c 10 | main.foo.func2() 11 | /Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go:50 +0x34 12 | created by main.d1 13 | /Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go:69 +0x34 14 | [originating from goroutine 24]: 15 | main.d1(...) 16 | /Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go:70 +0x34 17 | main.d1(...) 18 | /Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go:73 +0x54 19 | main.d1(...) 20 | /Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go:73 +0x54 21 | main.d1(...) 22 | /Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go:73 +0x54 23 | main.d1(...) 24 | /Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go:73 +0x54 25 | main.d1(...) 26 | /Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go:73 +0x54 27 | main.foo(...) 28 | /Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go:52 +0xec 29 | main.bar.func1(...) 30 | /Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go:61 +0x34 31 | created by main.d1 32 | /Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go:69 +0x34 33 | [originating from goroutine 23]: 34 | main.d1(...) 35 | /Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go:70 +0x34 36 | main.d1(...) 37 | /Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go:73 +0x54 38 | main.d1(...) 39 | /Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go:73 +0x54 40 | main.d1(...) 41 | /Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go:73 +0x54 42 | main.d1(...) 43 | /Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go:73 +0x54 44 | main.d1(...) 45 | /Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go:73 +0x54 46 | main.bar(...) 47 | /Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go:61 +0x88 48 | main.foo.func2(...) 49 | /Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go:50 +0x34 50 | created by main.d1 51 | /Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go:69 +0x34 52 | [originating from goroutine 22]: 53 | main.d1(...) 54 | /Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go:70 +0x34 55 | main.d1(...) 56 | /Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go:73 +0x54 57 | main.d1(...) 58 | /Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go:73 +0x54 59 | main.d1(...) 60 | /Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go:73 +0x54 61 | main.d1(...) 62 | /Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go:73 +0x54 63 | main.d1(...) 64 | /Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go:73 +0x54 65 | main.foo(...) 66 | /Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go:52 +0xec 67 | main.bar.func1(...) 68 | /Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go:61 +0x34 69 | created by main.d1 70 | /Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go:69 +0x34 71 | [originating from goroutine 21]: 72 | main.d1(...) 73 | /Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go:70 +0x34 74 | main.d1(...) 75 | /Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go:73 +0x54 76 | main.d1(...) 77 | /Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go:73 +0x54 78 | main.d1(...) 79 | /Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go:73 +0x54 80 | main.d1(...) 81 | /Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go:73 +0x54 82 | main.d1(...) 83 | /Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go:73 +0x54 84 | main.bar(...) 85 | /Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go:61 +0x88 86 | main.foo.func2(...) 87 | /Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go:50 +0x34 88 | created by main.d1 89 | /Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go:69 +0x34 90 | [originating from goroutine 20]: 91 | main.d1(...) 92 | /Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go:70 +0x34 93 | main.d1(...) 94 | /Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go:73 +0x54 95 | main.d1(...) 96 | /Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go:73 +0x54 97 | main.d1(...) 98 | /Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go:73 +0x54 99 | main.d1(...) 100 | /Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go:73 +0x54 101 | main.d1(...) 102 | /Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go:73 +0x54 103 | main.foo(...) 104 | /Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go:52 +0xec 105 | created by main.main 106 | /Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go:19 +0x58 107 | [originating from goroutine 1]: 108 | main.main(...) 109 | /Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go:20 +0x58 110 | 111 | goroutine 29 [chan receive]: 112 | main.bar(0x140000a4240, 0x0) 113 | /Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go:57 +0x11c 114 | main.foo.func2() 115 | /Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go:50 +0x34 116 | created by main.d1 117 | /Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go:69 +0x34 118 | [originating from goroutine 28]: 119 | main.d1(...) 120 | /Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go:70 +0x34 121 | main.d1(...) 122 | /Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go:73 +0x54 123 | main.d1(...) 124 | /Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go:73 +0x54 125 | main.d1(...) 126 | /Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go:73 +0x54 127 | main.d1(...) 128 | /Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go:73 +0x54 129 | main.d1(...) 130 | /Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go:73 +0x54 131 | main.foo(...) 132 | /Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go:52 +0xec 133 | main.bar.func1(...) 134 | /Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go:61 +0x34 135 | created by main.d1 136 | /Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go:69 +0x34 137 | [originating from goroutine 27]: 138 | main.d1(...) 139 | /Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go:70 +0x34 140 | main.d1(...) 141 | /Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go:73 +0x54 142 | main.d1(...) 143 | /Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go:73 +0x54 144 | main.d1(...) 145 | /Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go:73 +0x54 146 | main.d1(...) 147 | /Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go:73 +0x54 148 | main.d1(...) 149 | /Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go:73 +0x54 150 | main.bar(...) 151 | /Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go:61 +0x88 152 | main.foo.func2(...) 153 | /Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go:50 +0x34 154 | created by main.d1 155 | /Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go:69 +0x34 156 | [originating from goroutine 26]: 157 | main.d1(...) 158 | /Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go:70 +0x34 159 | main.d1(...) 160 | /Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go:73 +0x54 161 | main.d1(...) 162 | /Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go:73 +0x54 163 | main.d1(...) 164 | /Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go:73 +0x54 165 | main.d1(...) 166 | /Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go:73 +0x54 167 | main.d1(...) 168 | /Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go:73 +0x54 169 | main.foo(...) 170 | /Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go:52 +0xec 171 | created by main.main 172 | /Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go:22 +0xa4 173 | [originating from goroutine 1]: 174 | main.main(...) 175 | /Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go:23 +0xa4 176 | -------------------------------------------------------------------------------- /test-fixtures/waitsince.txt: -------------------------------------------------------------------------------- 1 | goroutine 1 [running]: 2 | runtime/pprof.writeGoroutineStacks(0x14e5940, 0xc0000abc50, 0x101b8a5, 0xc000333d20) 3 | /usr/local/Cellar/go/1.15.6/libexec/src/runtime/pprof/pprof.go:693 +0x9f 4 | runtime/pprof.writeGoroutine(0x14e5940, 0xc0000abc50, 0x2, 0xc000333dc0, 0x10ee5c8) 5 | /usr/local/Cellar/go/1.15.6/libexec/src/runtime/pprof/pprof.go:682 +0x45 6 | runtime/pprof.(*Profile).WriteTo(0x17179e0, 0x14e5940, 0xc0000abc50, 0x2, 0xc00002c210, 0xc0000ac4e0) 7 | /usr/local/Cellar/go/1.15.6/libexec/src/runtime/pprof/pprof.go:331 +0x3f2 8 | main.glob..func5(0x14e5940, 0xc0000abc50, 0xc000333eb0, 0x2) 9 | /Users/felix.geisendoerfer/go/src/github.com/felixge/go-profiler-notes/examples/goroutine/main.go:67 +0x65 10 | main.writeProfiles(0x2, 0xc0000c4008, 0x1466424) 11 | /Users/felix.geisendoerfer/go/src/github.com/felixge/go-profiler-notes/examples/goroutine/main.go:106 +0x187 12 | main.main() 13 | /Users/felix.geisendoerfer/go/src/github.com/felixge/go-profiler-notes/examples/goroutine/main.go:152 +0x3d2 14 | 15 | goroutine 22 [sleep, 1 minutes]: 16 | time.Sleep(0x3b9aca00) 17 | /usr/local/Cellar/go/1.15.6/libexec/src/runtime/time.go:188 +0xbf 18 | main.shortSleepLoop() 19 | /Users/felix.geisendoerfer/go/src/github.com/felixge/go-profiler-notes/examples/goroutine/main.go:165 +0x2a 20 | created by main.indirectShortSleepLoop2 21 | /Users/felix.geisendoerfer/go/src/github.com/felixge/go-profiler-notes/examples/goroutine/main.go:185 +0x35 22 | 23 | goroutine 3 [IO wait, 1 minutes]: 24 | internal/poll.runtime_pollWait(0x1e91e88, 0x72, 0x0) 25 | /usr/local/Cellar/go/1.15.6/libexec/src/runtime/netpoll.go:222 +0x55 26 | internal/poll.(*pollDesc).wait(0xc00019e018, 0x72, 0x0, 0x0, 0x1465786) 27 | /usr/local/Cellar/go/1.15.6/libexec/src/internal/poll/fd_poll_runtime.go:87 +0x45 28 | internal/poll.(*pollDesc).waitRead(...) 29 | /usr/local/Cellar/go/1.15.6/libexec/src/internal/poll/fd_poll_runtime.go:92 30 | internal/poll.(*FD).Accept(0xc00019e000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0) 31 | /usr/local/Cellar/go/1.15.6/libexec/src/internal/poll/fd_unix.go:394 +0x1fc 32 | net.(*netFD).accept(0xc00019e000, 0x7d667d63cbbded3e, 0x1789ccbbded3e, 0x100000001) 33 | /usr/local/Cellar/go/1.15.6/libexec/src/net/fd_unix.go:172 +0x45 34 | net.(*TCPListener).accept(0xc000188060, 0x60006709, 0xc000196da8, 0x109abe6) 35 | /usr/local/Cellar/go/1.15.6/libexec/src/net/tcpsock_posix.go:139 +0x32 36 | net.(*TCPListener).Accept(0xc000188060, 0xc000196df8, 0x18, 0xc000001200, 0x12e9eec) 37 | /usr/local/Cellar/go/1.15.6/libexec/src/net/tcpsock.go:261 +0x65 38 | net/http.(*Server).Serve(0xc00019c000, 0x14ec6e0, 0xc000188060, 0x0, 0x0) 39 | /usr/local/Cellar/go/1.15.6/libexec/src/net/http/server.go:2937 +0x266 40 | net/http.(*Server).ListenAndServe(0xc00019c000, 0xc00019c000, 0x1475536) 41 | /usr/local/Cellar/go/1.15.6/libexec/src/net/http/server.go:2866 +0xb7 42 | net/http.ListenAndServe(...) 43 | /usr/local/Cellar/go/1.15.6/libexec/src/net/http/server.go:3120 44 | main.main.func1(0xc000032120) 45 | /Users/felix.geisendoerfer/go/src/github.com/felixge/go-profiler-notes/examples/goroutine/main.go:123 +0x126 46 | created by main.main 47 | /Users/felix.geisendoerfer/go/src/github.com/felixge/go-profiler-notes/examples/goroutine/main.go:121 +0xc5 48 | 49 | goroutine 4 [sleep, 1 minutes]: 50 | time.Sleep(0x3b9aca00) 51 | /usr/local/Cellar/go/1.15.6/libexec/src/runtime/time.go:188 +0xbf 52 | main.shortSleepLoop() 53 | /Users/felix.geisendoerfer/go/src/github.com/felixge/go-profiler-notes/examples/goroutine/main.go:165 +0x2a 54 | created by main.main 55 | /Users/felix.geisendoerfer/go/src/github.com/felixge/go-profiler-notes/examples/goroutine/main.go:130 +0x195 56 | 57 | goroutine 5 [sleep, 1 minutes]: 58 | time.Sleep(0x34630b8a000) 59 | /usr/local/Cellar/go/1.15.6/libexec/src/runtime/time.go:188 +0xbf 60 | main.sleepLoop(0x34630b8a000) 61 | /Users/felix.geisendoerfer/go/src/github.com/felixge/go-profiler-notes/examples/goroutine/main.go:171 +0x2b 62 | created by main.main 63 | /Users/felix.geisendoerfer/go/src/github.com/felixge/go-profiler-notes/examples/goroutine/main.go:131 +0x1bc 64 | 65 | goroutine 6 [chan receive, 1 minutes]: 66 | main.chanReceiveForever() 67 | /Users/felix.geisendoerfer/go/src/github.com/felixge/go-profiler-notes/examples/goroutine/main.go:177 +0x4d 68 | created by main.main 69 | /Users/felix.geisendoerfer/go/src/github.com/felixge/go-profiler-notes/examples/goroutine/main.go:132 +0x1d4 70 | 71 | goroutine 24 [select, 1 minutes]: 72 | net/http.(*persistConn).writeLoop(0xc0000cea20) 73 | /usr/local/Cellar/go/1.15.6/libexec/src/net/http/transport.go:2340 +0x11c 74 | created by net/http.(*Transport).dialConn 75 | /usr/local/Cellar/go/1.15.6/libexec/src/net/http/transport.go:1709 +0xcdc 76 | 77 | goroutine 23 [IO wait, 1 minutes]: 78 | internal/poll.runtime_pollWait(0x1e91da0, 0x72, 0x14e6ca0) 79 | /usr/local/Cellar/go/1.15.6/libexec/src/runtime/netpoll.go:222 +0x55 80 | internal/poll.(*pollDesc).wait(0xc00010e198, 0x72, 0x14e6c00, 0x16db878, 0x0) 81 | /usr/local/Cellar/go/1.15.6/libexec/src/internal/poll/fd_poll_runtime.go:87 +0x45 82 | internal/poll.(*pollDesc).waitRead(...) 83 | /usr/local/Cellar/go/1.15.6/libexec/src/internal/poll/fd_poll_runtime.go:92 84 | internal/poll.(*FD).Read(0xc00010e180, 0xc000256000, 0x1000, 0x1000, 0x0, 0x0, 0x0) 85 | /usr/local/Cellar/go/1.15.6/libexec/src/internal/poll/fd_unix.go:159 +0x1a5 86 | net.(*netFD).Read(0xc00010e180, 0xc000256000, 0x1000, 0x1000, 0x103b1dc, 0xc000199b58, 0x10680e0) 87 | /usr/local/Cellar/go/1.15.6/libexec/src/net/fd_posix.go:55 +0x4f 88 | net.(*conn).Read(0xc000010008, 0xc000256000, 0x1000, 0x1000, 0x0, 0x0, 0x0) 89 | /usr/local/Cellar/go/1.15.6/libexec/src/net/net.go:182 +0x8e 90 | net/http.(*persistConn).Read(0xc0000cea20, 0xc000256000, 0x1000, 0x1000, 0xc00009e300, 0xc000199c58, 0x10074b5) 91 | /usr/local/Cellar/go/1.15.6/libexec/src/net/http/transport.go:1887 +0x77 92 | bufio.(*Reader).fill(0xc0001801e0) 93 | /usr/local/Cellar/go/1.15.6/libexec/src/bufio/bufio.go:101 +0x105 94 | bufio.(*Reader).Peek(0xc0001801e0, 0x1, 0x0, 0x0, 0x1, 0x0, 0xc0001d0060) 95 | /usr/local/Cellar/go/1.15.6/libexec/src/bufio/bufio.go:139 +0x4f 96 | net/http.(*persistConn).readLoop(0xc0000cea20) 97 | /usr/local/Cellar/go/1.15.6/libexec/src/net/http/transport.go:2040 +0x1a8 98 | created by net/http.(*Transport).dialConn 99 | /usr/local/Cellar/go/1.15.6/libexec/src/net/http/transport.go:1708 +0xcb7 100 | 101 | goroutine 41 [IO wait, 1 minutes]: 102 | internal/poll.runtime_pollWait(0x1e91cb8, 0x72, 0x14e6ca0) 103 | /usr/local/Cellar/go/1.15.6/libexec/src/runtime/netpoll.go:222 +0x55 104 | internal/poll.(*pollDesc).wait(0xc00019e098, 0x72, 0x14e6c00, 0x16db878, 0x0) 105 | /usr/local/Cellar/go/1.15.6/libexec/src/internal/poll/fd_poll_runtime.go:87 +0x45 106 | internal/poll.(*pollDesc).waitRead(...) 107 | /usr/local/Cellar/go/1.15.6/libexec/src/internal/poll/fd_poll_runtime.go:92 108 | internal/poll.(*FD).Read(0xc00019e080, 0xc000326000, 0x1000, 0x1000, 0x0, 0x0, 0x0) 109 | /usr/local/Cellar/go/1.15.6/libexec/src/internal/poll/fd_unix.go:159 +0x1a5 110 | net.(*netFD).Read(0xc00019e080, 0xc000326000, 0x1000, 0x1000, 0x203000, 0x203000, 0x203000) 111 | /usr/local/Cellar/go/1.15.6/libexec/src/net/fd_posix.go:55 +0x4f 112 | net.(*conn).Read(0xc000186028, 0xc000326000, 0x1000, 0x1000, 0x0, 0x0, 0x0) 113 | /usr/local/Cellar/go/1.15.6/libexec/src/net/net.go:182 +0x8e 114 | net/http.(*connReader).Read(0xc00007c300, 0xc000326000, 0x1000, 0x1000, 0x100000006, 0x10, 0x1819408) 115 | /usr/local/Cellar/go/1.15.6/libexec/src/net/http/server.go:798 +0x1ad 116 | bufio.(*Reader).fill(0xc000290060) 117 | /usr/local/Cellar/go/1.15.6/libexec/src/bufio/bufio.go:101 +0x105 118 | bufio.(*Reader).ReadSlice(0xc000290060, 0xa, 0x1819408, 0xc000337988, 0x100f6d0, 0xc000110000, 0x100) 119 | /usr/local/Cellar/go/1.15.6/libexec/src/bufio/bufio.go:360 +0x3d 120 | bufio.(*Reader).ReadLine(0xc000290060, 0xc000110000, 0x1079694, 0xc0001a4000, 0x0, 0x1010038, 0x30) 121 | /usr/local/Cellar/go/1.15.6/libexec/src/bufio/bufio.go:389 +0x34 122 | net/textproto.(*Reader).readLineSlice(0xc000182300, 0xc000110000, 0x10d7c4d, 0xc00019e080, 0x1068000, 0xc000282900) 123 | /usr/local/Cellar/go/1.15.6/libexec/src/net/textproto/reader.go:58 +0x6c 124 | net/textproto.(*Reader).ReadLine(...) 125 | /usr/local/Cellar/go/1.15.6/libexec/src/net/textproto/reader.go:39 126 | net/http.readRequest(0xc000290060, 0x0, 0xc000110000, 0x0, 0x0) 127 | /usr/local/Cellar/go/1.15.6/libexec/src/net/http/request.go:1012 +0xaa 128 | net/http.(*conn).readRequest(0xc0000c6320, 0x14ed4a0, 0xc000322000, 0x0, 0x0, 0x0) 129 | /usr/local/Cellar/go/1.15.6/libexec/src/net/http/server.go:984 +0x19a 130 | net/http.(*conn).serve(0xc0000c6320, 0x14ed4a0, 0xc000322000) 131 | /usr/local/Cellar/go/1.15.6/libexec/src/net/http/server.go:1851 +0x705 132 | created by net/http.(*Server).Serve 133 | /usr/local/Cellar/go/1.15.6/libexec/src/net/http/server.go:2969 +0x36c 134 | -------------------------------------------------------------------------------- /gostackparse.go: -------------------------------------------------------------------------------- 1 | // Unless explicitly stated otherwise all files in this repository are licensed 2 | // under the Apache License Version 2.0. 3 | // This product includes software developed at Datadog (https://www.datadoghq.com/). 4 | // Copyright 2021 Datadog, Inc. 5 | 6 | // Package gostackparse parses goroutines stack traces as produced by panic() 7 | // or debug.Stack() at ~300 MiB/s. 8 | package gostackparse 9 | 10 | import ( 11 | "bufio" 12 | "bytes" 13 | "fmt" 14 | "io" 15 | "regexp" 16 | "strconv" 17 | "strings" 18 | "time" 19 | ) 20 | 21 | type parserState int 22 | 23 | const ( 24 | stateHeader = iota 25 | stateStackFunc 26 | stateStackFile 27 | stateCreatedBy 28 | stateCreatedByFunc 29 | stateCreatedByFile 30 | stateOriginatingFrom 31 | ) 32 | 33 | // Parse parses a goroutines stack trace dump as produced by runtime.Stack(). 34 | // The parser is forgiving and will continue parsing even when encountering 35 | // unexpected data. When this happens it will try to discard the entire 36 | // goroutine that encountered the problem and continue with the next one. It 37 | // will also return an error for every goroutine that couldn't be parsed. If 38 | // all goroutines were parsed successfully, the []error slice is empty. 39 | func Parse(r io.Reader) ([]*Goroutine, []error) { 40 | var ( 41 | sc = bufio.NewScanner(r) 42 | state parserState 43 | lineNum int 44 | line []byte 45 | 46 | goroutines []*Goroutine 47 | errs []error 48 | g *Goroutine 49 | f *Frame 50 | 51 | abortGoroutine = func(msg string) { 52 | err := fmt.Errorf( 53 | "%s on line %d: %q", 54 | msg, 55 | lineNum, 56 | line, 57 | ) 58 | errs = append(errs, err) 59 | goroutines = goroutines[0 : len(goroutines)-1] 60 | state = stateHeader 61 | } 62 | ) 63 | 64 | // This for loop implements a simple line based state machine for parsing 65 | // the goroutines dump. The state != stateHeader makes sure we handle an 66 | // unexpected EOF the same way we'd handle an empty line. 67 | for sc.Scan() || state != stateHeader { 68 | line = sc.Bytes() 69 | lineNum++ 70 | 71 | statemachine: 72 | switch state { 73 | case stateHeader, stateOriginatingFrom: 74 | // Ignore lines that don't look like goroutine headers. This helps with 75 | // leading/trailing whitespace but also in case we encountered an error 76 | // during the previous goroutine and need to seek to the beginning of the 77 | // next one. 78 | if state == stateHeader { 79 | if !bytes.HasPrefix(line, goroutinePrefix) { 80 | continue 81 | } 82 | g = parseGoroutineHeader(line[len(goroutinePrefix):]) 83 | goroutines = append(goroutines, g) 84 | } 85 | if state == stateOriginatingFrom { 86 | // Make sure we capture only the ID that we need. If it's truncated, 87 | // it'll be handled by the error check below 88 | ancestorIDStr := bytes.TrimSuffix( 89 | bytes.TrimPrefix(line, originatingFromPrefix), 90 | []byte("]:"), 91 | ) 92 | ancestorID, err := strconv.Atoi(string(ancestorIDStr)) 93 | if err != nil { 94 | abortGoroutine(err.Error()) 95 | continue 96 | } 97 | ancestorG := &Goroutine{ID: ancestorID} 98 | g.Ancestor = ancestorG 99 | g = ancestorG 100 | } 101 | 102 | state = stateStackFunc 103 | if g == nil { 104 | abortGoroutine("invalid goroutine header") 105 | } 106 | case stateStackFunc, stateCreatedByFunc: 107 | f = parseFunc(line, state) 108 | if f == nil { 109 | if bytes.Equal(line, framesElided) { 110 | g.FramesElided = true 111 | state = stateCreatedBy 112 | continue 113 | } 114 | if bytes.HasPrefix(line, originatingFromPrefix) { 115 | state = stateOriginatingFrom 116 | goto statemachine 117 | } 118 | abortGoroutine("invalid function call") 119 | continue 120 | } 121 | if state == stateStackFunc { 122 | g.Stack = append(g.Stack, f) 123 | state = stateStackFile 124 | } else { 125 | g.CreatedBy = f 126 | state = stateCreatedByFile 127 | } 128 | case stateStackFile, stateCreatedByFile: 129 | if !parseFile(line, f) { 130 | abortGoroutine("invalid file:line ref") 131 | continue 132 | } 133 | state = stateCreatedBy 134 | case stateCreatedBy: 135 | if bytes.HasPrefix(line, createdByPrefix) { 136 | line = line[len(createdByPrefix):] 137 | state = stateCreatedByFunc 138 | goto statemachine 139 | } else if len(line) == 0 { 140 | state = stateHeader 141 | } else { 142 | state = stateStackFunc 143 | goto statemachine 144 | } 145 | } 146 | } 147 | 148 | if err := sc.Err(); err != nil { 149 | errs = append(errs, err) 150 | } 151 | return goroutines, errs 152 | } 153 | 154 | var ( 155 | goroutinePrefix = []byte("goroutine ") 156 | createdByPrefix = []byte("created by ") 157 | originatingFromPrefix = []byte("[originating from goroutine ") 158 | framesElided = []byte("...additional frames elided...") 159 | ) 160 | 161 | var goroutineHeader = regexp.MustCompile( 162 | `^(\d+) \[([^,]+)(?:, (\d+) minutes)?(, locked to thread)?\]:$`, 163 | ) 164 | 165 | // parseGoroutineHeader parses a goroutine header line and returns a new 166 | // Goroutine on success or nil on error. It expects the `goroutinePrefix` to 167 | // be trimmed from the beginning of the line. 168 | // 169 | // Example Input: 170 | // 1 [chan receive, 6883 minutes]: 171 | // 172 | // Example Output: 173 | // &Goroutine{ID: 1, State "chan receive", Waitduration: 6883*time.Minute} 174 | func parseGoroutineHeader(line []byte) *Goroutine { 175 | // TODO(fg) would probably be faster if we didn't use a regexp for this, but 176 | // might be more hassle than its worth. 177 | m := goroutineHeader.FindSubmatch(line) 178 | if len(m) != 5 { 179 | return nil 180 | } 181 | var ( 182 | id = m[1] 183 | state = m[2] 184 | waitminutes = m[3] 185 | locked = m[4] 186 | 187 | g = &Goroutine{State: string(state), LockedToThread: len(locked) > 0} 188 | err error 189 | ) 190 | 191 | // regex currently sucks `abc minutes` into the state string if abc is 192 | // non-numeric, let's not consider this a valid goroutine. 193 | if strings.HasSuffix(g.State, " minutes") { 194 | return nil 195 | } 196 | if g.ID, err = strconv.Atoi(string(id)); err != nil { 197 | // should be impossible to end up here 198 | return nil 199 | } 200 | if len(waitminutes) > 0 { 201 | min, err := strconv.Atoi(string(waitminutes)) 202 | if err != nil { 203 | // should be impossible to end up here 204 | return nil 205 | } 206 | g.Wait = time.Duration(min) * time.Minute 207 | } 208 | return g 209 | } 210 | 211 | // parseFunc parse a func call with potential argument addresses and returns a 212 | // new Frame for it on success or nil on error. 213 | // 214 | // Example Input: 215 | // runtime/pprof.writeGoroutineStacks(0x2b016e0, 0xc0995cafc0, 0xc00468e150, 0x0) 216 | // 217 | // Example Output: 218 | // &Frame{Func: "runtime/pprof.writeGoroutineStacks"} 219 | func parseFunc(line []byte, state parserState) *Frame { 220 | // createdBy func calls don't have trailing parens, just return them as-is. 221 | if state == stateCreatedByFunc { 222 | // go 1.21 changes the "created by" line to include the 223 | // goroutine which created the one whose stack is being printed, 224 | // e.g. 225 | // created by main.main in goroutine 1 226 | // We are at the beginning of the function name, so we should 227 | // just show up to the first space which follows the end of the 228 | // function name. 229 | i := bytes.Index(line, []byte(" ")) 230 | if i > 0 { 231 | return &Frame{Func: string(line[:i])} 232 | } 233 | return &Frame{Func: string(line)} 234 | } 235 | 236 | // A valid func call is supposed to have at least one matched pair of parens. 237 | // Multiple matched pairs are allowed, but nesting is not. 238 | var ( 239 | openIndex = -1 240 | closeIndex = -1 241 | ) 242 | for i, r := range line { 243 | switch r { 244 | case '(': 245 | if openIndex != -1 && closeIndex == -1 { 246 | return nil 247 | } 248 | openIndex = i 249 | closeIndex = -1 250 | case ')': 251 | if openIndex == -1 || closeIndex != -1 { 252 | return nil 253 | } 254 | closeIndex = i 255 | } 256 | } 257 | 258 | if openIndex == -1 || closeIndex == -1 || openIndex == 0 { 259 | return nil 260 | } 261 | return &Frame{Func: string(line[0:openIndex])} 262 | } 263 | 264 | // parseFile parses a file line and updates f accordingly or returns false on 265 | // error. 266 | // 267 | // Example Input: 268 | // \t/root/go1.15.6.linux.amd64/src/net/http/server.go:2969 +0x36c 269 | // 270 | // Example Update: 271 | // &Frame{File: "/root/go1.15.6.linux.amd64/src/net/http/server.go", Line: 2969} 272 | // 273 | // Note: The +0x36c is the relative pc offset from the function entry pc. It's 274 | // omitted if it's 0. 275 | func parseFile(line []byte, f *Frame) (ret bool) { 276 | if len(line) < 2 || line[0] != '\t' { 277 | return false 278 | } 279 | line = line[1:] 280 | 281 | const ( 282 | stateFilename = iota 283 | stateColon 284 | stateLine 285 | ) 286 | 287 | var state = stateFilename 288 | for i, c := range line { 289 | switch state { 290 | case stateFilename: 291 | if c == ':' { 292 | state = stateColon 293 | } 294 | case stateColon: 295 | if isDigit(c) { 296 | f.File = string(line[0 : i-1]) 297 | f.Line = int(c - '0') 298 | state = stateLine 299 | ret = true 300 | } else { 301 | state = stateFilename 302 | } 303 | case stateLine: 304 | if c == ' ' { 305 | return true 306 | } else if !isDigit(c) { 307 | return false 308 | } 309 | f.Line = f.Line*10 + int(c-'0') 310 | } 311 | 312 | } 313 | return 314 | } 315 | 316 | func isDigit(c byte) bool { 317 | return c >= '0' && c <= '9' 318 | } 319 | 320 | // Goroutine represents a single goroutine and its stack after extracting it 321 | // from the runtime.Stack() text format. See [1] for more info. 322 | // [1] https://github.com/felixge/go-profiler-notes/blob/main/goroutine.md 323 | type Goroutine struct { 324 | // ID is the goroutine id (aka `goid`). 325 | ID int 326 | // State is the `atomicstatus` of the goroutine, or if "waiting" the 327 | // `waitreason`. 328 | State string 329 | // Wait is the approximate duration a goroutine has been waiting or in a 330 | // syscall as determined by the first gc after the wait started. Aka 331 | // `waitsince`. 332 | Wait time.Duration 333 | // LockedToThread is true if the goroutine is locked by a thread, aka 334 | // `lockedm`. 335 | LockedToThread bool 336 | // Stack is the stack trace of the goroutine. 337 | Stack []*Frame 338 | // FramesElided is true if the stack trace contains a message indicating that 339 | // additional frames were elided. This happens when the stack depth exceeds 340 | // 100. 341 | FramesElided bool 342 | // CreatedBy is the frame that created this goroutine, nil for main(). 343 | CreatedBy *Frame 344 | // Ancestors are the Goroutines that created this goroutine. 345 | // See GODEBUG=tracebackancestors=n in https://pkg.go.dev/runtime. 346 | Ancestor *Goroutine `json:"Ancestor,omitempty"` 347 | } 348 | 349 | // Frame is a single call frame on the stack. 350 | type Frame struct { 351 | // Func is the name of the function, including package name, e.g. "main.main" 352 | // or "net/http.(*Server).Serve". 353 | Func string 354 | // File is the absolute path of source file e.g. 355 | // "/go/src/example.org/example/main.go". 356 | File string 357 | // Line is the line number of inside of the source file that was active when 358 | // the sample was taken. 359 | Line int 360 | } 361 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2016 Datadog, Inc. 190 | Licensed under the Apache License, Version 2.0 (the "License"); 191 | you may not use this file except in compliance with the License. 192 | You may obtain a copy of the License at 193 | 194 | http://www.apache.org/licenses/LICENSE-2.0 195 | 196 | Unless required by applicable law or agreed to in writing, software 197 | distributed under the License is distributed on an "AS IS" BASIS, 198 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 199 | See the License for the specific language governing permissions and 200 | limitations under the License. 201 | -------------------------------------------------------------------------------- /test-fixtures/waitsince.golden.json: -------------------------------------------------------------------------------- 1 | { 2 | "Errors": null, 3 | "Goroutines": [ 4 | { 5 | "ID": 1, 6 | "State": "running", 7 | "Wait": 0, 8 | "LockedToThread": false, 9 | "Stack": [ 10 | { 11 | "Func": "runtime/pprof.writeGoroutineStacks", 12 | "File": "/usr/local/Cellar/go/1.15.6/libexec/src/runtime/pprof/pprof.go", 13 | "Line": 693 14 | }, 15 | { 16 | "Func": "runtime/pprof.writeGoroutine", 17 | "File": "/usr/local/Cellar/go/1.15.6/libexec/src/runtime/pprof/pprof.go", 18 | "Line": 682 19 | }, 20 | { 21 | "Func": "runtime/pprof.(*Profile).WriteTo", 22 | "File": "/usr/local/Cellar/go/1.15.6/libexec/src/runtime/pprof/pprof.go", 23 | "Line": 331 24 | }, 25 | { 26 | "Func": "main.glob..func5", 27 | "File": "/Users/felix.geisendoerfer/go/src/github.com/felixge/go-profiler-notes/examples/goroutine/main.go", 28 | "Line": 67 29 | }, 30 | { 31 | "Func": "main.writeProfiles", 32 | "File": "/Users/felix.geisendoerfer/go/src/github.com/felixge/go-profiler-notes/examples/goroutine/main.go", 33 | "Line": 106 34 | }, 35 | { 36 | "Func": "main.main", 37 | "File": "/Users/felix.geisendoerfer/go/src/github.com/felixge/go-profiler-notes/examples/goroutine/main.go", 38 | "Line": 152 39 | } 40 | ], 41 | "FramesElided": false, 42 | "CreatedBy": null 43 | }, 44 | { 45 | "ID": 22, 46 | "State": "sleep", 47 | "Wait": 60000000000, 48 | "LockedToThread": false, 49 | "Stack": [ 50 | { 51 | "Func": "time.Sleep", 52 | "File": "/usr/local/Cellar/go/1.15.6/libexec/src/runtime/time.go", 53 | "Line": 188 54 | }, 55 | { 56 | "Func": "main.shortSleepLoop", 57 | "File": "/Users/felix.geisendoerfer/go/src/github.com/felixge/go-profiler-notes/examples/goroutine/main.go", 58 | "Line": 165 59 | } 60 | ], 61 | "FramesElided": false, 62 | "CreatedBy": { 63 | "Func": "main.indirectShortSleepLoop2", 64 | "File": "/Users/felix.geisendoerfer/go/src/github.com/felixge/go-profiler-notes/examples/goroutine/main.go", 65 | "Line": 185 66 | } 67 | }, 68 | { 69 | "ID": 3, 70 | "State": "IO wait", 71 | "Wait": 60000000000, 72 | "LockedToThread": false, 73 | "Stack": [ 74 | { 75 | "Func": "internal/poll.runtime_pollWait", 76 | "File": "/usr/local/Cellar/go/1.15.6/libexec/src/runtime/netpoll.go", 77 | "Line": 222 78 | }, 79 | { 80 | "Func": "internal/poll.(*pollDesc).wait", 81 | "File": "/usr/local/Cellar/go/1.15.6/libexec/src/internal/poll/fd_poll_runtime.go", 82 | "Line": 87 83 | }, 84 | { 85 | "Func": "internal/poll.(*pollDesc).waitRead", 86 | "File": "/usr/local/Cellar/go/1.15.6/libexec/src/internal/poll/fd_poll_runtime.go", 87 | "Line": 92 88 | }, 89 | { 90 | "Func": "internal/poll.(*FD).Accept", 91 | "File": "/usr/local/Cellar/go/1.15.6/libexec/src/internal/poll/fd_unix.go", 92 | "Line": 394 93 | }, 94 | { 95 | "Func": "net.(*netFD).accept", 96 | "File": "/usr/local/Cellar/go/1.15.6/libexec/src/net/fd_unix.go", 97 | "Line": 172 98 | }, 99 | { 100 | "Func": "net.(*TCPListener).accept", 101 | "File": "/usr/local/Cellar/go/1.15.6/libexec/src/net/tcpsock_posix.go", 102 | "Line": 139 103 | }, 104 | { 105 | "Func": "net.(*TCPListener).Accept", 106 | "File": "/usr/local/Cellar/go/1.15.6/libexec/src/net/tcpsock.go", 107 | "Line": 261 108 | }, 109 | { 110 | "Func": "net/http.(*Server).Serve", 111 | "File": "/usr/local/Cellar/go/1.15.6/libexec/src/net/http/server.go", 112 | "Line": 2937 113 | }, 114 | { 115 | "Func": "net/http.(*Server).ListenAndServe", 116 | "File": "/usr/local/Cellar/go/1.15.6/libexec/src/net/http/server.go", 117 | "Line": 2866 118 | }, 119 | { 120 | "Func": "net/http.ListenAndServe", 121 | "File": "/usr/local/Cellar/go/1.15.6/libexec/src/net/http/server.go", 122 | "Line": 3120 123 | }, 124 | { 125 | "Func": "main.main.func1", 126 | "File": "/Users/felix.geisendoerfer/go/src/github.com/felixge/go-profiler-notes/examples/goroutine/main.go", 127 | "Line": 123 128 | } 129 | ], 130 | "FramesElided": false, 131 | "CreatedBy": { 132 | "Func": "main.main", 133 | "File": "/Users/felix.geisendoerfer/go/src/github.com/felixge/go-profiler-notes/examples/goroutine/main.go", 134 | "Line": 121 135 | } 136 | }, 137 | { 138 | "ID": 4, 139 | "State": "sleep", 140 | "Wait": 60000000000, 141 | "LockedToThread": false, 142 | "Stack": [ 143 | { 144 | "Func": "time.Sleep", 145 | "File": "/usr/local/Cellar/go/1.15.6/libexec/src/runtime/time.go", 146 | "Line": 188 147 | }, 148 | { 149 | "Func": "main.shortSleepLoop", 150 | "File": "/Users/felix.geisendoerfer/go/src/github.com/felixge/go-profiler-notes/examples/goroutine/main.go", 151 | "Line": 165 152 | } 153 | ], 154 | "FramesElided": false, 155 | "CreatedBy": { 156 | "Func": "main.main", 157 | "File": "/Users/felix.geisendoerfer/go/src/github.com/felixge/go-profiler-notes/examples/goroutine/main.go", 158 | "Line": 130 159 | } 160 | }, 161 | { 162 | "ID": 5, 163 | "State": "sleep", 164 | "Wait": 60000000000, 165 | "LockedToThread": false, 166 | "Stack": [ 167 | { 168 | "Func": "time.Sleep", 169 | "File": "/usr/local/Cellar/go/1.15.6/libexec/src/runtime/time.go", 170 | "Line": 188 171 | }, 172 | { 173 | "Func": "main.sleepLoop", 174 | "File": "/Users/felix.geisendoerfer/go/src/github.com/felixge/go-profiler-notes/examples/goroutine/main.go", 175 | "Line": 171 176 | } 177 | ], 178 | "FramesElided": false, 179 | "CreatedBy": { 180 | "Func": "main.main", 181 | "File": "/Users/felix.geisendoerfer/go/src/github.com/felixge/go-profiler-notes/examples/goroutine/main.go", 182 | "Line": 131 183 | } 184 | }, 185 | { 186 | "ID": 6, 187 | "State": "chan receive", 188 | "Wait": 60000000000, 189 | "LockedToThread": false, 190 | "Stack": [ 191 | { 192 | "Func": "main.chanReceiveForever", 193 | "File": "/Users/felix.geisendoerfer/go/src/github.com/felixge/go-profiler-notes/examples/goroutine/main.go", 194 | "Line": 177 195 | } 196 | ], 197 | "FramesElided": false, 198 | "CreatedBy": { 199 | "Func": "main.main", 200 | "File": "/Users/felix.geisendoerfer/go/src/github.com/felixge/go-profiler-notes/examples/goroutine/main.go", 201 | "Line": 132 202 | } 203 | }, 204 | { 205 | "ID": 24, 206 | "State": "select", 207 | "Wait": 60000000000, 208 | "LockedToThread": false, 209 | "Stack": [ 210 | { 211 | "Func": "net/http.(*persistConn).writeLoop", 212 | "File": "/usr/local/Cellar/go/1.15.6/libexec/src/net/http/transport.go", 213 | "Line": 2340 214 | } 215 | ], 216 | "FramesElided": false, 217 | "CreatedBy": { 218 | "Func": "net/http.(*Transport).dialConn", 219 | "File": "/usr/local/Cellar/go/1.15.6/libexec/src/net/http/transport.go", 220 | "Line": 1709 221 | } 222 | }, 223 | { 224 | "ID": 23, 225 | "State": "IO wait", 226 | "Wait": 60000000000, 227 | "LockedToThread": false, 228 | "Stack": [ 229 | { 230 | "Func": "internal/poll.runtime_pollWait", 231 | "File": "/usr/local/Cellar/go/1.15.6/libexec/src/runtime/netpoll.go", 232 | "Line": 222 233 | }, 234 | { 235 | "Func": "internal/poll.(*pollDesc).wait", 236 | "File": "/usr/local/Cellar/go/1.15.6/libexec/src/internal/poll/fd_poll_runtime.go", 237 | "Line": 87 238 | }, 239 | { 240 | "Func": "internal/poll.(*pollDesc).waitRead", 241 | "File": "/usr/local/Cellar/go/1.15.6/libexec/src/internal/poll/fd_poll_runtime.go", 242 | "Line": 92 243 | }, 244 | { 245 | "Func": "internal/poll.(*FD).Read", 246 | "File": "/usr/local/Cellar/go/1.15.6/libexec/src/internal/poll/fd_unix.go", 247 | "Line": 159 248 | }, 249 | { 250 | "Func": "net.(*netFD).Read", 251 | "File": "/usr/local/Cellar/go/1.15.6/libexec/src/net/fd_posix.go", 252 | "Line": 55 253 | }, 254 | { 255 | "Func": "net.(*conn).Read", 256 | "File": "/usr/local/Cellar/go/1.15.6/libexec/src/net/net.go", 257 | "Line": 182 258 | }, 259 | { 260 | "Func": "net/http.(*persistConn).Read", 261 | "File": "/usr/local/Cellar/go/1.15.6/libexec/src/net/http/transport.go", 262 | "Line": 1887 263 | }, 264 | { 265 | "Func": "bufio.(*Reader).fill", 266 | "File": "/usr/local/Cellar/go/1.15.6/libexec/src/bufio/bufio.go", 267 | "Line": 101 268 | }, 269 | { 270 | "Func": "bufio.(*Reader).Peek", 271 | "File": "/usr/local/Cellar/go/1.15.6/libexec/src/bufio/bufio.go", 272 | "Line": 139 273 | }, 274 | { 275 | "Func": "net/http.(*persistConn).readLoop", 276 | "File": "/usr/local/Cellar/go/1.15.6/libexec/src/net/http/transport.go", 277 | "Line": 2040 278 | } 279 | ], 280 | "FramesElided": false, 281 | "CreatedBy": { 282 | "Func": "net/http.(*Transport).dialConn", 283 | "File": "/usr/local/Cellar/go/1.15.6/libexec/src/net/http/transport.go", 284 | "Line": 1708 285 | } 286 | }, 287 | { 288 | "ID": 41, 289 | "State": "IO wait", 290 | "Wait": 60000000000, 291 | "LockedToThread": false, 292 | "Stack": [ 293 | { 294 | "Func": "internal/poll.runtime_pollWait", 295 | "File": "/usr/local/Cellar/go/1.15.6/libexec/src/runtime/netpoll.go", 296 | "Line": 222 297 | }, 298 | { 299 | "Func": "internal/poll.(*pollDesc).wait", 300 | "File": "/usr/local/Cellar/go/1.15.6/libexec/src/internal/poll/fd_poll_runtime.go", 301 | "Line": 87 302 | }, 303 | { 304 | "Func": "internal/poll.(*pollDesc).waitRead", 305 | "File": "/usr/local/Cellar/go/1.15.6/libexec/src/internal/poll/fd_poll_runtime.go", 306 | "Line": 92 307 | }, 308 | { 309 | "Func": "internal/poll.(*FD).Read", 310 | "File": "/usr/local/Cellar/go/1.15.6/libexec/src/internal/poll/fd_unix.go", 311 | "Line": 159 312 | }, 313 | { 314 | "Func": "net.(*netFD).Read", 315 | "File": "/usr/local/Cellar/go/1.15.6/libexec/src/net/fd_posix.go", 316 | "Line": 55 317 | }, 318 | { 319 | "Func": "net.(*conn).Read", 320 | "File": "/usr/local/Cellar/go/1.15.6/libexec/src/net/net.go", 321 | "Line": 182 322 | }, 323 | { 324 | "Func": "net/http.(*connReader).Read", 325 | "File": "/usr/local/Cellar/go/1.15.6/libexec/src/net/http/server.go", 326 | "Line": 798 327 | }, 328 | { 329 | "Func": "bufio.(*Reader).fill", 330 | "File": "/usr/local/Cellar/go/1.15.6/libexec/src/bufio/bufio.go", 331 | "Line": 101 332 | }, 333 | { 334 | "Func": "bufio.(*Reader).ReadSlice", 335 | "File": "/usr/local/Cellar/go/1.15.6/libexec/src/bufio/bufio.go", 336 | "Line": 360 337 | }, 338 | { 339 | "Func": "bufio.(*Reader).ReadLine", 340 | "File": "/usr/local/Cellar/go/1.15.6/libexec/src/bufio/bufio.go", 341 | "Line": 389 342 | }, 343 | { 344 | "Func": "net/textproto.(*Reader).readLineSlice", 345 | "File": "/usr/local/Cellar/go/1.15.6/libexec/src/net/textproto/reader.go", 346 | "Line": 58 347 | }, 348 | { 349 | "Func": "net/textproto.(*Reader).ReadLine", 350 | "File": "/usr/local/Cellar/go/1.15.6/libexec/src/net/textproto/reader.go", 351 | "Line": 39 352 | }, 353 | { 354 | "Func": "net/http.readRequest", 355 | "File": "/usr/local/Cellar/go/1.15.6/libexec/src/net/http/request.go", 356 | "Line": 1012 357 | }, 358 | { 359 | "Func": "net/http.(*conn).readRequest", 360 | "File": "/usr/local/Cellar/go/1.15.6/libexec/src/net/http/server.go", 361 | "Line": 984 362 | }, 363 | { 364 | "Func": "net/http.(*conn).serve", 365 | "File": "/usr/local/Cellar/go/1.15.6/libexec/src/net/http/server.go", 366 | "Line": 1851 367 | } 368 | ], 369 | "FramesElided": false, 370 | "CreatedBy": { 371 | "Func": "net/http.(*Server).Serve", 372 | "File": "/usr/local/Cellar/go/1.15.6/libexec/src/net/http/server.go", 373 | "Line": 2969 374 | } 375 | } 376 | ] 377 | } 378 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This work is dual-licensed under Apache 2.0 or BSD3. 2 | You may select, at your option, one of the above-listed licenses. 3 | 4 | `SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause` 5 | 6 | Apache License 7 | Version 2.0, January 2004 8 | http://www.apache.org/licenses/ 9 | 10 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 11 | 12 | 1. Definitions. 13 | 14 | "License" shall mean the terms and conditions for use, reproduction, 15 | and distribution as defined by Sections 1 through 9 of this document. 16 | 17 | "Licensor" shall mean the copyright owner or entity authorized by 18 | the copyright owner that is granting the License. 19 | 20 | "Legal Entity" shall mean the union of the acting entity and all 21 | other entities that control, are controlled by, or are under common 22 | control with that entity. For the purposes of this definition, 23 | "control" means (i) the power, direct or indirect, to cause the 24 | direction or management of such entity, whether by contract or 25 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 26 | outstanding shares, or (iii) beneficial ownership of such entity. 27 | 28 | "You" (or "Your") shall mean an individual or Legal Entity 29 | exercising permissions granted by this License. 30 | 31 | "Source" form shall mean the preferred form for making modifications, 32 | including but not limited to software source code, documentation 33 | source, and configuration files. 34 | 35 | "Object" form shall mean any form resulting from mechanical 36 | transformation or translation of a Source form, including but 37 | not limited to compiled object code, generated documentation, 38 | and conversions to other media types. 39 | 40 | "Work" shall mean the work of authorship, whether in Source or 41 | Object form, made available under the License, as indicated by a 42 | copyright notice that is included in or attached to the work 43 | (an example is provided in the Appendix below). 44 | 45 | "Derivative Works" shall mean any work, whether in Source or Object 46 | form, that is based on (or derived from) the Work and for which the 47 | editorial revisions, annotations, elaborations, or other modifications 48 | represent, as a whole, an original work of authorship. For the purposes 49 | of this License, Derivative Works shall not include works that remain 50 | separable from, or merely link (or bind by name) to the interfaces of, 51 | the Work and Derivative Works thereof. 52 | 53 | "Contribution" shall mean any work of authorship, including 54 | the original version of the Work and any modifications or additions 55 | to that Work or Derivative Works thereof, that is intentionally 56 | submitted to Licensor for inclusion in the Work by the copyright owner 57 | or by an individual or Legal Entity authorized to submit on behalf of 58 | the copyright owner. For the purposes of this definition, "submitted" 59 | means any form of electronic, verbal, or written communication sent 60 | to the Licensor or its representatives, including but not limited to 61 | communication on electronic mailing lists, source code control systems, 62 | and issue tracking systems that are managed by, or on behalf of, the 63 | Licensor for the purpose of discussing and improving the Work, but 64 | excluding communication that is conspicuously marked or otherwise 65 | designated in writing by the copyright owner as "Not a Contribution." 66 | 67 | "Contributor" shall mean Licensor and any individual or Legal Entity 68 | on behalf of whom a Contribution has been received by Licensor and 69 | subsequently incorporated within the Work. 70 | 71 | 2. Grant of Copyright License. Subject to the terms and conditions of 72 | this License, each Contributor hereby grants to You a perpetual, 73 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 74 | copyright license to reproduce, prepare Derivative Works of, 75 | publicly display, publicly perform, sublicense, and distribute the 76 | Work and such Derivative Works in Source or Object form. 77 | 78 | 3. Grant of Patent License. Subject to the terms and conditions of 79 | this License, each Contributor hereby grants to You a perpetual, 80 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 81 | (except as stated in this section) patent license to make, have made, 82 | use, offer to sell, sell, import, and otherwise transfer the Work, 83 | where such license applies only to those patent claims licensable 84 | by such Contributor that are necessarily infringed by their 85 | Contribution(s) alone or by combination of their Contribution(s) 86 | with the Work to which such Contribution(s) was submitted. If You 87 | institute patent litigation against any entity (including a 88 | cross-claim or counterclaim in a lawsuit) alleging that the Work 89 | or a Contribution incorporated within the Work constitutes direct 90 | or contributory patent infringement, then any patent licenses 91 | granted to You under this License for that Work shall terminate 92 | as of the date such litigation is filed. 93 | 94 | 4. Redistribution. You may reproduce and distribute copies of the 95 | Work or Derivative Works thereof in any medium, with or without 96 | modifications, and in Source or Object form, provided that You 97 | meet the following conditions: 98 | 99 | (a) You must give any other recipients of the Work or 100 | Derivative Works a copy of this License; and 101 | 102 | (b) You must cause any modified files to carry prominent notices 103 | stating that You changed the files; and 104 | 105 | (c) You must retain, in the Source form of any Derivative Works 106 | that You distribute, all copyright, patent, trademark, and 107 | attribution notices from the Source form of the Work, 108 | excluding those notices that do not pertain to any part of 109 | the Derivative Works; and 110 | 111 | (d) If the Work includes a "NOTICE" text file as part of its 112 | distribution, then any Derivative Works that You distribute must 113 | include a readable copy of the attribution notices contained 114 | within such NOTICE file, excluding those notices that do not 115 | pertain to any part of the Derivative Works, in at least one 116 | of the following places: within a NOTICE text file distributed 117 | as part of the Derivative Works; within the Source form or 118 | documentation, if provided along with the Derivative Works; or, 119 | within a display generated by the Derivative Works, if and 120 | wherever such third-party notices normally appear. The contents 121 | of the NOTICE file are for informational purposes only and 122 | do not modify the License. You may add Your own attribution 123 | notices within Derivative Works that You distribute, alongside 124 | or as an addendum to the NOTICE text from the Work, provided 125 | that such additional attribution notices cannot be construed 126 | as modifying the License. 127 | 128 | You may add Your own copyright statement to Your modifications and 129 | may provide additional or different license terms and conditions 130 | for use, reproduction, or distribution of Your modifications, or 131 | for any such Derivative Works as a whole, provided Your use, 132 | reproduction, and distribution of the Work otherwise complies with 133 | the conditions stated in this License. 134 | 135 | 5. Submission of Contributions. Unless You explicitly state otherwise, 136 | any Contribution intentionally submitted for inclusion in the Work 137 | by You to the Licensor shall be under the terms and conditions of 138 | this License, without any additional terms or conditions. 139 | Notwithstanding the above, nothing herein shall supersede or modify 140 | the terms of any separate license agreement you may have executed 141 | with Licensor regarding such Contributions. 142 | 143 | 6. Trademarks. This License does not grant permission to use the trade 144 | names, trademarks, service marks, or product names of the Licensor, 145 | except as required for reasonable and customary use in describing the 146 | origin of the Work and reproducing the content of the NOTICE file. 147 | 148 | 7. Disclaimer of Warranty. Unless required by applicable law or 149 | agreed to in writing, Licensor provides the Work (and each 150 | Contributor provides its Contributions) on an "AS IS" BASIS, 151 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 152 | implied, including, without limitation, any warranties or conditions 153 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 154 | PARTICULAR PURPOSE. You are solely responsible for determining the 155 | appropriateness of using or redistributing the Work and assume any 156 | risks associated with Your exercise of permissions under this License. 157 | 158 | 8. Limitation of Liability. In no event and under no legal theory, 159 | whether in tort (including negligence), contract, or otherwise, 160 | unless required by applicable law (such as deliberate and grossly 161 | negligent acts) or agreed to in writing, shall any Contributor be 162 | liable to You for damages, including any direct, indirect, special, 163 | incidental, or consequential damages of any character arising as a 164 | result of this License or out of the use or inability to use the 165 | Work (including but not limited to damages for loss of goodwill, 166 | work stoppage, computer failure or malfunction, or any and all 167 | other commercial damages or losses), even if such Contributor 168 | has been advised of the possibility of such damages. 169 | 170 | 9. Accepting Warranty or Additional Liability. While redistributing 171 | the Work or Derivative Works thereof, You may choose to offer, 172 | and charge a fee for, acceptance of support, warranty, indemnity, 173 | or other liability obligations and/or rights consistent with this 174 | License. However, in accepting such obligations, You may act only 175 | on Your own behalf and on Your sole responsibility, not on behalf 176 | of any other Contributor, and only if You agree to indemnify, 177 | defend, and hold each Contributor harmless for any liability 178 | incurred by, or claims asserted against, such Contributor by reason 179 | of your accepting any such warranty or additional liability. 180 | 181 | END OF TERMS AND CONDITIONS 182 | 183 | APPENDIX: How to apply the Apache License to your work. 184 | 185 | To apply the Apache License to your work, attach the following 186 | boilerplate notice, with the fields enclosed by brackets "{}" 187 | replaced with your own identifying information. (Don't include 188 | the brackets!) The text should be enclosed in the appropriate 189 | comment syntax for the file format. We also recommend that a 190 | file or class name and description of purpose be included on the 191 | same "printed page" as the copyright notice for easier 192 | identification within third-party archives. 193 | 194 | Copyright 2021 Datadog, Inc. 195 | Licensed under the Apache License, Version 2.0 (the "License"); 196 | you may not use this file except in compliance with the License. 197 | You may obtain a copy of the License at 198 | 199 | http://www.apache.org/licenses/LICENSE-2.0 200 | 201 | Unless required by applicable law or agreed to in writing, software 202 | distributed under the License is distributed on an "AS IS" BASIS, 203 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 204 | See the License for the specific language governing permissions and 205 | limitations under the License. 206 | 207 | --- 208 | 209 | Copyright (c) 2021-Present, Datadog 210 | All rights reserved. 211 | 212 | Redistribution and use in source and binary forms, with or without 213 | modification, are permitted provided that the following conditions are met: 214 | * Redistributions of source code must retain the above copyright 215 | notice, this list of conditions and the following disclaimer. 216 | * Redistributions in binary form must reproduce the above copyright 217 | notice, this list of conditions and the following disclaimer in the 218 | documentation and/or other materials provided with the distribution. 219 | * Neither the name of Datadog nor the 220 | names of its contributors may be used to endorse or promote products 221 | derived from this software without specific prior written permission. 222 | 223 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 224 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 225 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 226 | DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 227 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 228 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 229 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 230 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 231 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 232 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 233 | -------------------------------------------------------------------------------- /gostackparse_test.go: -------------------------------------------------------------------------------- 1 | // Unless explicitly stated otherwise all files in this repository are licensed 2 | // under the Apache License Version 2.0. 3 | // This product includes software developed at Datadog (https://www.datadoghq.com/). 4 | // Copyright 2021 Datadog, Inc. 5 | 6 | package gostackparse 7 | 8 | import ( 9 | "bytes" 10 | "embed" 11 | "encoding/json" 12 | "flag" 13 | "fmt" 14 | "io/ioutil" 15 | "os" 16 | "path/filepath" 17 | "strings" 18 | "testing" 19 | "time" 20 | 21 | "github.com/stretchr/testify/require" 22 | ) 23 | 24 | var update = flag.Bool("update", false, "update golden files") 25 | 26 | // TestParse_GoldenFiles verifies the output of the parser for a set of input 27 | // files in the test-fixtures. If you want to test a new behavior or bug fix, 28 | // this is the best place to do it. 29 | func TestParse_GoldenFiles(t *testing.T) { 30 | inputs, err := filepath.Glob(filepath.Join("test-fixtures", "*.txt")) 31 | require.NoError(t, err) 32 | for _, input := range inputs { 33 | inputData, err := ioutil.ReadFile(input) 34 | require.NoError(t, err) 35 | 36 | golden := strings.TrimSuffix(input, filepath.Ext(input)) + ".golden.json" 37 | goroutines, errs := Parse(bytes.NewReader(inputData)) 38 | var errS []string 39 | for _, err := range errs { 40 | errS = append(errS, err.Error()) 41 | } 42 | actual, err := json.MarshalIndent(struct { 43 | Errors []string 44 | Goroutines []*Goroutine 45 | }{errS, goroutines}, "", " ") 46 | actual = append(actual, '\n') 47 | require.NoError(t, err) 48 | 49 | if *update { 50 | ioutil.WriteFile(golden, actual, 0644) 51 | } 52 | expected, _ := ioutil.ReadFile(golden) 53 | require.JSONEq(t, string(expected), string(actual)) 54 | } 55 | } 56 | 57 | // TestParse_PropertyBased does an exhaustive property based test against all 58 | // possible permutations of a few interesting line fragements defined below, 59 | // making sure the parser always does the right thing and never panics. This 60 | // test is complex and shouldn't be extended unless there is a good reason for 61 | // doing so. It's essentially just a very agressive smoke test. 62 | func TestParse_PropertyBased(t *testing.T) { 63 | seen := map[string]bool{} 64 | tests := fixtures.Permutations() 65 | for i := 0; i < tests; i++ { 66 | dump := fixtures.Generate(i) 67 | dumpS := dump.String() 68 | msg := fmt.Sprintf("permutation %d:\n%s", i, dumpS) 69 | 70 | require.False(t, seen[dumpS], msg) 71 | seen[dumpS] = true 72 | 73 | goroutines, errs := Parse(strings.NewReader(dumpS)) 74 | 75 | wantErr := dump.header.WantErr 76 | for _, f := range dump.stack { 77 | if wantErr != "" { 78 | break 79 | } else if f.fn.WantErr != "" { 80 | wantErr = f.fn.WantErr 81 | } else if f.file.WantErr != "" { 82 | wantErr = f.file.WantErr 83 | } 84 | } 85 | if wantErr == "" { 86 | wantErr = dump.createdBy.fn.WantErr 87 | } 88 | if wantErr == "" && dump.createdBy.fn.WantFrame != nil { 89 | wantErr = dump.createdBy.file.WantErr 90 | } 91 | 92 | if wantErr != "" { 93 | require.NotNil(t, errs, msg) 94 | require.Contains(t, errs[0].Error(), wantErr, msg) 95 | require.Equal(t, 0, len(goroutines), msg) 96 | continue 97 | } 98 | 99 | require.Nil(t, errs, msg) 100 | 101 | require.Equal(t, 1, len(goroutines), msg) 102 | g := goroutines[0] 103 | require.Equal(t, dump.header.WantG.ID, g.ID, msg) 104 | require.Equal(t, dump.header.WantG.State, g.State, msg) 105 | require.Equal(t, dump.header.WantG.Wait, g.Wait, msg) 106 | require.Equal(t, dump.header.WantG.LockedToThread, g.LockedToThread, msg) 107 | 108 | require.Equal(t, len(dump.stack), len(g.Stack), msg) 109 | for i, dumpFrame := range dump.stack { 110 | gFrame := g.Stack[i] 111 | require.Equal(t, dumpFrame.fn.WantFrame.Func, gFrame.Func, msg) 112 | require.Equal(t, dumpFrame.file.WantFrame.File, gFrame.File, msg) 113 | require.Equal(t, dumpFrame.file.WantFrame.Line, gFrame.Line, msg) 114 | } 115 | 116 | if dump.createdBy.fn.WantFrame == nil { 117 | require.Nil(t, g.CreatedBy, msg) 118 | } else { 119 | require.Equal(t, dump.createdBy.fn.WantFrame.Func, g.CreatedBy.Func, msg) 120 | require.Equal(t, dump.createdBy.file.WantFrame.File, g.CreatedBy.File, msg) 121 | require.Equal(t, dump.createdBy.file.WantFrame.Line, g.CreatedBy.Line, msg) 122 | } 123 | } 124 | t.Logf("executed %d tests", tests) 125 | } 126 | 127 | type dump struct { 128 | header headerLine 129 | stack []frameLines 130 | createdBy frameLines 131 | } 132 | 133 | func (d *dump) String() string { 134 | s := d.header.String() 135 | for _, f := range d.stack { 136 | s += f.String() 137 | } 138 | s += d.createdBy.String() 139 | return s 140 | } 141 | 142 | type headerLine struct { 143 | Line string 144 | WantG *Goroutine 145 | WantErr string 146 | } 147 | 148 | func (h *headerLine) String() string { 149 | return h.Line + "\n" 150 | } 151 | 152 | type frameLines struct { 153 | fn frameLine 154 | file frameLine 155 | } 156 | 157 | func (f *frameLines) String() string { 158 | return f.fn.Line + "\n" + f.file.Line + "\n" 159 | } 160 | 161 | type frameLine struct { 162 | Line string 163 | WantFrame *Frame 164 | WantErr string 165 | } 166 | 167 | // generator generates all possible goroutine stack trace permutations based on 168 | // the given stack depths and line fragements. 169 | type generator struct { 170 | minStack int 171 | maxStack int 172 | headers []headerLine 173 | funcs []frameLine 174 | files []frameLine 175 | createdBy []frameLine 176 | } 177 | 178 | func (g *generator) Generate(n int) *dump { 179 | // keep going around in circles 180 | n = n % g.Permutations() 181 | 182 | header := n % len(g.headers) 183 | n = n / len(g.headers) 184 | 185 | cFn := n % len(g.createdBy) 186 | n = n / len(g.createdBy) 187 | cFile := n % len(g.files) 188 | n = n / len(g.files) 189 | 190 | var stack []frameLines 191 | for d := 0; d < g.maxStack && (n > 0 || d < g.minStack); d++ { 192 | fn := n % len(g.funcs) 193 | n = n / len(g.funcs) 194 | file := n % len(g.files) 195 | n = n / len(g.files) 196 | frame := frameLines{ 197 | fn: g.funcs[fn], 198 | file: g.files[file], 199 | } 200 | stack = append(stack, frame) 201 | } 202 | 203 | d := &dump{ 204 | header: g.headers[header], 205 | stack: stack, 206 | createdBy: frameLines{ 207 | fn: g.createdBy[cFn], 208 | file: g.files[cFile], 209 | }, 210 | } 211 | return d 212 | } 213 | 214 | func (g *generator) Permutations() int { 215 | p := 0 216 | for d := g.minStack; d <= g.maxStack; d++ { 217 | pp := 1 218 | for frame := 0; frame < d; frame++ { 219 | pp = pp * len(g.files) * len(g.funcs) 220 | } 221 | p += len(g.headers) * pp * len(g.createdBy) * len(g.files) 222 | } 223 | return p 224 | } 225 | 226 | var fixtures = generator{ 227 | // Testing larger stack depths greatly increases the number of permutations 228 | // but is unlikely to shake out more bugs, so a depth of 1 to 2 seems like 229 | // the sweet spot. 230 | minStack: 1, 231 | maxStack: 2, 232 | 233 | headers: []headerLine{ 234 | { 235 | Line: "goroutine 1 [chan receive]:", 236 | WantG: &Goroutine{ID: 1, State: "chan receive", Wait: 0}, 237 | }, 238 | { 239 | Line: "goroutine 2 [IO Wait, locked to thread]:", 240 | WantG: &Goroutine{ID: 2, State: "IO Wait", Wait: 0, LockedToThread: true}, 241 | }, 242 | { 243 | Line: "goroutine 23 [select, 5 minutes]:", 244 | WantG: &Goroutine{ID: 23, State: "select", Wait: 5 * time.Minute}, 245 | }, 246 | { 247 | Line: "goroutine 42 [select, 5 minutes, locked to thread]:", 248 | WantG: &Goroutine{ID: 42, State: "select", Wait: 5 * time.Minute, LockedToThread: true}, 249 | }, 250 | { 251 | Line: "goroutine 23 []:", 252 | WantErr: "invalid goroutine header", 253 | }, 254 | { 255 | Line: "goroutine ", 256 | WantErr: "invalid goroutine header", 257 | }, 258 | { 259 | Line: "goroutine 1 [chan receive]:\n", 260 | WantErr: "invalid function call", 261 | }, 262 | }, 263 | 264 | funcs: []frameLine{ 265 | { 266 | Line: "main.main()", 267 | WantFrame: &Frame{Func: "main.main"}, 268 | }, 269 | { 270 | Line: "runtime.goparkunlock(...)", 271 | WantFrame: &Frame{Func: "runtime.goparkunlock"}, 272 | }, 273 | { 274 | Line: "net/http.(*persistConn).writeLoop(0xc0001a5c20)", 275 | WantFrame: &Frame{Func: "net/http.(*persistConn).writeLoop"}, 276 | }, 277 | { 278 | Line: "foo.bar", 279 | WantErr: "invalid function call", 280 | }, 281 | { 282 | Line: "foo.bar(", 283 | WantErr: "invalid function call", 284 | }, 285 | { 286 | Line: "net/http.(*persistConn).writeLoop(0xc0", 287 | WantErr: "invalid function call", 288 | }, 289 | { 290 | Line: "net/http.(*persist", 291 | WantErr: "invalid function call", 292 | }, 293 | { 294 | Line: "net/http.*persist)(", 295 | WantErr: "invalid function call", 296 | }, 297 | { 298 | Line: "net/http.(*persist))", 299 | WantErr: "invalid function call", 300 | }, 301 | { 302 | Line: "net/http.((*persist)", 303 | WantErr: "invalid function call", 304 | }, 305 | { 306 | Line: "()", 307 | WantErr: "invalid function call", 308 | }, 309 | }, 310 | 311 | files: []frameLine{ 312 | { 313 | Line: "\t/go/src/example.org/example/main.go:231 +0x1187", 314 | WantFrame: &Frame{File: "/go/src/example.org/example/main.go", Line: 231}, 315 | }, 316 | { 317 | Line: "\t/root/go1.15.6.linux.amd64/src/runtime/proc.go:312", 318 | WantFrame: &Frame{File: "/root/go1.15.6.linux.amd64/src/runtime/proc.go", Line: 312}, 319 | }, 320 | { 321 | Line: "/root/go1.15.6.linux.amd64/src/runtime/proc.go:312", 322 | WantErr: "invalid file:line ref", 323 | }, 324 | { 325 | Line: "", 326 | WantErr: "invalid file:line ref", 327 | }, 328 | }, 329 | 330 | createdBy: []frameLine{ 331 | { 332 | Line: "created by net/http.(*Server).Serve", 333 | WantFrame: &Frame{Func: "net/http.(*Server).Serve"}, 334 | }, 335 | { 336 | Line: "created by github.com/example.org/example/k8s.io/klog.init.0", 337 | WantFrame: &Frame{Func: "github.com/example.org/example/k8s.io/klog.init.0"}, 338 | }, 339 | }, 340 | } 341 | 342 | func BenchmarkGostackparse(b *testing.B) { 343 | data, err := ioutil.ReadFile(filepath.Join("test-fixtures", "waitsince.txt")) 344 | require.NoError(b, err) 345 | 346 | b.ResetTimer() 347 | b.ReportAllocs() 348 | 349 | start := time.Now() 350 | parsedBytes := 0 351 | for i := 0; i < b.N; i++ { 352 | parsedBytes += len(data) 353 | gs, err := Parse(bytes.NewReader(data)) 354 | if err != nil { 355 | b.Fatal(err) 356 | } else if l := len(gs); l != 9 { 357 | b.Fatal(l) 358 | } 359 | } 360 | 361 | mbPerSec := float64(parsedBytes) / time.Since(start).Seconds() / 1024 / 1024 362 | b.ReportMetric(mbPerSec, "MiB/s") 363 | } 364 | 365 | // Using go:embed to load test fixtures into memory, so the internal fuzzing infra doesn't need to handle individual files 366 | // along with the fuzzer binary. 367 | // 368 | //go:embed test-fixtures/*.txt 369 | var testFixtures embed.FS 370 | 371 | func FuzzParse(f *testing.F) { 372 | files, err := testFixtures.ReadDir("test-fixtures") 373 | require.NoError(f, err) 374 | 375 | for _, file := range files { 376 | if strings.HasSuffix(file.Name(), ".txt") { 377 | body, err := testFixtures.ReadFile(filepath.Join("test-fixtures", file.Name())) 378 | require.NoError(f, err) 379 | f.Add(body) 380 | } 381 | } 382 | // Regression tests 383 | // panic: runtime error: slice bounds out of range [28:26] 384 | f.Add([]byte("goroutine 0 [0]:\n0()\n\t:0\n[originating from goroutine ")) 385 | 386 | f.Fuzz(func(t *testing.T, data []byte) { 387 | gs, err := Parse(bytes.NewReader(data)) 388 | if err != nil { 389 | t.Skip() 390 | } 391 | // Invariant checks 392 | for _, g := range gs { 393 | for _, f := range g.Stack { 394 | if f.Func == "" { 395 | t.Errorf("func is empty: %+v", f) 396 | } 397 | } 398 | } 399 | }) 400 | } 401 | 402 | // This is a regression test for a panic on a truncated line with an [originating from goroutine prefix. 403 | func TestCrashRegression(t *testing.T) { 404 | crashPayload := []byte("goroutine 0 [0]:\n0()\n\t:0\n[originating from goroutine ") 405 | _, _ = Parse(bytes.NewReader(crashPayload)) 406 | } 407 | 408 | func TestFuzzCorupus(t *testing.T) { 409 | if os.Getenv("FUZZ_CORPUS") == "" { 410 | t.Skip("set FUZZ_CORPUS=true to generate fuzz corpus") 411 | } 412 | dir := "corpus" 413 | tests := fixtures.Permutations() 414 | require.NoError(t, os.MkdirAll(dir, 0755)) 415 | for i := 0; i < tests; i++ { 416 | dump := fixtures.Generate(i) 417 | name := filepath.Join(dir, fmt.Sprintf("%d.txt", i)) 418 | require.NoError(t, ioutil.WriteFile(name, []byte(dump.String()), 0666)) 419 | } 420 | } 421 | 422 | func Test_parseFile(t *testing.T) { 423 | tests := []struct { 424 | name string 425 | line string 426 | wantFrame Frame 427 | wantReturn bool 428 | }{ 429 | { 430 | name: "empty", 431 | line: "", 432 | wantFrame: Frame{}, 433 | wantReturn: false, 434 | }, 435 | { 436 | name: "simple", 437 | line: "\t/root/go1.15.6.linux.amd64/src/net/http/server.go:2969 +0x36c", 438 | wantFrame: Frame{ 439 | File: "/root/go1.15.6.linux.amd64/src/net/http/server.go", 440 | Line: 2969, 441 | }, 442 | wantReturn: true, 443 | }, 444 | { 445 | name: "simple+space", 446 | line: "\t/root/go1.15.6.linux.amd64/src/net/http/cool server.go:2969 +0x36c", 447 | wantFrame: Frame{ 448 | File: "/root/go1.15.6.linux.amd64/src/net/http/cool server.go", 449 | Line: 2969, 450 | }, 451 | wantReturn: true, 452 | }, 453 | { 454 | name: "no-relative-pc", 455 | line: "\t/root/go1.15.6.linux.amd64/src/net/http/server.go:2969", 456 | wantFrame: Frame{ 457 | File: "/root/go1.15.6.linux.amd64/src/net/http/server.go", 458 | Line: 2969, 459 | }, 460 | wantReturn: true, 461 | }, 462 | { 463 | name: "no-relative-pc+space", 464 | line: "\t/root/go1.15.6.linux.amd64/src/net/http/cool server.go:2969", 465 | wantFrame: Frame{ 466 | File: "/root/go1.15.6.linux.amd64/src/net/http/cool server.go", 467 | Line: 2969, 468 | }, 469 | wantReturn: true, 470 | }, 471 | } 472 | for _, tt := range tests { 473 | if len(tt.line) > 1 { 474 | tt.name = "windows+" + tt.name 475 | tt.line = "\tC:" + tt.line[1:] 476 | tt.wantFrame.File = "C:" + tt.wantFrame.File 477 | tests = append(tests, tt) 478 | } 479 | } 480 | 481 | for _, tt := range tests { 482 | t.Run(tt.name, func(t *testing.T) { 483 | var f Frame 484 | got := parseFile([]byte(tt.line), &f) 485 | if got != tt.wantReturn { 486 | t.Fatalf("got=%v want=%v", got, tt.wantReturn) 487 | } else if f != tt.wantFrame { 488 | t.Fatalf("got=%+v want=%+v", f, tt.wantFrame) 489 | } 490 | }) 491 | } 492 | } 493 | -------------------------------------------------------------------------------- /test-fixtures/frameselided.txt: -------------------------------------------------------------------------------- 1 | goroutine 1 [running]: 2 | runtime/pprof.writeGoroutineStacks(0x111e540, 0xc0000a0008, 0x30, 0x12b3998) 3 | /usr/local/Cellar/go/1.15.6/libexec/src/runtime/pprof/pprof.go:693 +0x9f 4 | runtime/pprof.writeGoroutine(0x111e540, 0xc0000a0008, 0x2, 0x0, 0x0) 5 | /usr/local/Cellar/go/1.15.6/libexec/src/runtime/pprof/pprof.go:682 +0x45 6 | runtime/pprof.(*Profile).WriteTo(0x11ae4e0, 0x111e540, 0xc0000a0008, 0x2, 0x0, 0x0) 7 | /usr/local/Cellar/go/1.15.6/libexec/src/runtime/pprof/pprof.go:331 +0x3f2 8 | main.stackDump(0x0) 9 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:16 +0x85 10 | main.stackDump(0x1) 11 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 12 | main.stackDump(0x2) 13 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 14 | main.stackDump(0x3) 15 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 16 | main.stackDump(0x4) 17 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 18 | main.stackDump(0x5) 19 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 20 | main.stackDump(0x6) 21 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 22 | main.stackDump(0x7) 23 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 24 | main.stackDump(0x8) 25 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 26 | main.stackDump(0x9) 27 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 28 | main.stackDump(0xa) 29 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 30 | main.stackDump(0xb) 31 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 32 | main.stackDump(0xc) 33 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 34 | main.stackDump(0xd) 35 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 36 | main.stackDump(0xe) 37 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 38 | main.stackDump(0xf) 39 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 40 | main.stackDump(0x10) 41 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 42 | main.stackDump(0x11) 43 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 44 | main.stackDump(0x12) 45 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 46 | main.stackDump(0x13) 47 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 48 | main.stackDump(0x14) 49 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 50 | main.stackDump(0x15) 51 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 52 | main.stackDump(0x16) 53 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 54 | main.stackDump(0x17) 55 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 56 | main.stackDump(0x18) 57 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 58 | main.stackDump(0x19) 59 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 60 | main.stackDump(0x1a) 61 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 62 | main.stackDump(0x1b) 63 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 64 | main.stackDump(0x1c) 65 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 66 | main.stackDump(0x1d) 67 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 68 | main.stackDump(0x1e) 69 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 70 | main.stackDump(0x1f) 71 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 72 | main.stackDump(0x20) 73 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 74 | main.stackDump(0x21) 75 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 76 | main.stackDump(0x22) 77 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 78 | main.stackDump(0x23) 79 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 80 | main.stackDump(0x24) 81 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 82 | main.stackDump(0x25) 83 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 84 | main.stackDump(0x26) 85 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 86 | main.stackDump(0x27) 87 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 88 | main.stackDump(0x28) 89 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 90 | main.stackDump(0x29) 91 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 92 | main.stackDump(0x2a) 93 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 94 | main.stackDump(0x2b) 95 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 96 | main.stackDump(0x2c) 97 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 98 | main.stackDump(0x2d) 99 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 100 | main.stackDump(0x2e) 101 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 102 | main.stackDump(0x2f) 103 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 104 | main.stackDump(0x30) 105 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 106 | main.stackDump(0x31) 107 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 108 | main.stackDump(0x32) 109 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 110 | main.stackDump(0x33) 111 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 112 | main.stackDump(0x34) 113 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 114 | main.stackDump(0x35) 115 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 116 | main.stackDump(0x36) 117 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 118 | main.stackDump(0x37) 119 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 120 | main.stackDump(0x38) 121 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 122 | main.stackDump(0x39) 123 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 124 | main.stackDump(0x3a) 125 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 126 | main.stackDump(0x3b) 127 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 128 | main.stackDump(0x3c) 129 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 130 | main.stackDump(0x3d) 131 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 132 | main.stackDump(0x3e) 133 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 134 | main.stackDump(0x3f) 135 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 136 | main.stackDump(0x40) 137 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 138 | main.stackDump(0x41) 139 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 140 | main.stackDump(0x42) 141 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 142 | main.stackDump(0x43) 143 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 144 | main.stackDump(0x44) 145 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 146 | main.stackDump(0x45) 147 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 148 | main.stackDump(0x46) 149 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 150 | main.stackDump(0x47) 151 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 152 | main.stackDump(0x48) 153 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 154 | main.stackDump(0x49) 155 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 156 | main.stackDump(0x4a) 157 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 158 | main.stackDump(0x4b) 159 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 160 | main.stackDump(0x4c) 161 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 162 | main.stackDump(0x4d) 163 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 164 | main.stackDump(0x4e) 165 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 166 | main.stackDump(0x4f) 167 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 168 | main.stackDump(0x50) 169 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 170 | main.stackDump(0x51) 171 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 172 | main.stackDump(0x52) 173 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 174 | main.stackDump(0x53) 175 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 176 | main.stackDump(0x54) 177 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 178 | main.stackDump(0x55) 179 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 180 | main.stackDump(0x56) 181 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 182 | main.stackDump(0x57) 183 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 184 | main.stackDump(0x58) 185 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 186 | main.stackDump(0x59) 187 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 188 | main.stackDump(0x5a) 189 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 190 | main.stackDump(0x5b) 191 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 192 | main.stackDump(0x5c) 193 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 194 | main.stackDump(0x5d) 195 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 196 | main.stackDump(0x5e) 197 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 198 | main.stackDump(0x5f) 199 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 200 | main.stackDump(0x60) 201 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go:14 +0x33 202 | ...additional frames elided... 203 | -------------------------------------------------------------------------------- /test-fixtures/frameselided_goroutine.txt: -------------------------------------------------------------------------------- 1 | goroutine 18 [running]: 2 | runtime/pprof.writeGoroutineStacks(0x111e5c0, 0xc000100008, 0x30, 0x12b5c20) 3 | /usr/local/Cellar/go/1.15.6/libexec/src/runtime/pprof/pprof.go:693 +0x9f 4 | runtime/pprof.writeGoroutine(0x111e5c0, 0xc000100008, 0x2, 0x0, 0x0) 5 | /usr/local/Cellar/go/1.15.6/libexec/src/runtime/pprof/pprof.go:682 +0x45 6 | runtime/pprof.(*Profile).WriteTo(0x11ae4e0, 0x111e5c0, 0xc000100008, 0x2, 0x0, 0x0) 7 | /usr/local/Cellar/go/1.15.6/libexec/src/runtime/pprof/pprof.go:331 +0x3f2 8 | main.stackDump(0x0, 0xc000128060) 9 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:24 +0x97 10 | main.stackDump(0x1, 0xc000128060) 11 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 12 | main.stackDump(0x2, 0xc000128060) 13 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 14 | main.stackDump(0x3, 0xc000128060) 15 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 16 | main.stackDump(0x4, 0xc000128060) 17 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 18 | main.stackDump(0x5, 0xc000128060) 19 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 20 | main.stackDump(0x6, 0xc000128060) 21 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 22 | main.stackDump(0x7, 0xc000128060) 23 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 24 | main.stackDump(0x8, 0xc000128060) 25 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 26 | main.stackDump(0x9, 0xc000128060) 27 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 28 | main.stackDump(0xa, 0xc000128060) 29 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 30 | main.stackDump(0xb, 0xc000128060) 31 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 32 | main.stackDump(0xc, 0xc000128060) 33 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 34 | main.stackDump(0xd, 0xc000128060) 35 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 36 | main.stackDump(0xe, 0xc000128060) 37 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 38 | main.stackDump(0xf, 0xc000128060) 39 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 40 | main.stackDump(0x10, 0xc000128060) 41 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 42 | main.stackDump(0x11, 0xc000128060) 43 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 44 | main.stackDump(0x12, 0xc000128060) 45 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 46 | main.stackDump(0x13, 0xc000128060) 47 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 48 | main.stackDump(0x14, 0xc000128060) 49 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 50 | main.stackDump(0x15, 0xc000128060) 51 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 52 | main.stackDump(0x16, 0xc000128060) 53 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 54 | main.stackDump(0x17, 0xc000128060) 55 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 56 | main.stackDump(0x18, 0xc000128060) 57 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 58 | main.stackDump(0x19, 0xc000128060) 59 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 60 | main.stackDump(0x1a, 0xc000128060) 61 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 62 | main.stackDump(0x1b, 0xc000128060) 63 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 64 | main.stackDump(0x1c, 0xc000128060) 65 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 66 | main.stackDump(0x1d, 0xc000128060) 67 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 68 | main.stackDump(0x1e, 0xc000128060) 69 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 70 | main.stackDump(0x1f, 0xc000128060) 71 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 72 | main.stackDump(0x20, 0xc000128060) 73 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 74 | main.stackDump(0x21, 0xc000128060) 75 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 76 | main.stackDump(0x22, 0xc000128060) 77 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 78 | main.stackDump(0x23, 0xc000128060) 79 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 80 | main.stackDump(0x24, 0xc000128060) 81 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 82 | main.stackDump(0x25, 0xc000128060) 83 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 84 | main.stackDump(0x26, 0xc000128060) 85 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 86 | main.stackDump(0x27, 0xc000128060) 87 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 88 | main.stackDump(0x28, 0xc000128060) 89 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 90 | main.stackDump(0x29, 0xc000128060) 91 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 92 | main.stackDump(0x2a, 0xc000128060) 93 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 94 | main.stackDump(0x2b, 0xc000128060) 95 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 96 | main.stackDump(0x2c, 0xc000128060) 97 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 98 | main.stackDump(0x2d, 0xc000128060) 99 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 100 | main.stackDump(0x2e, 0xc000128060) 101 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 102 | main.stackDump(0x2f, 0xc000128060) 103 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 104 | main.stackDump(0x30, 0xc000128060) 105 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 106 | main.stackDump(0x31, 0xc000128060) 107 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 108 | main.stackDump(0x32, 0xc000128060) 109 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 110 | main.stackDump(0x33, 0xc000128060) 111 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 112 | main.stackDump(0x34, 0xc000128060) 113 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 114 | main.stackDump(0x35, 0xc000128060) 115 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 116 | main.stackDump(0x36, 0xc000128060) 117 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 118 | main.stackDump(0x37, 0xc000128060) 119 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 120 | main.stackDump(0x38, 0xc000128060) 121 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 122 | main.stackDump(0x39, 0xc000128060) 123 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 124 | main.stackDump(0x3a, 0xc000128060) 125 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 126 | main.stackDump(0x3b, 0xc000128060) 127 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 128 | main.stackDump(0x3c, 0xc000128060) 129 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 130 | main.stackDump(0x3d, 0xc000128060) 131 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 132 | main.stackDump(0x3e, 0xc000128060) 133 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 134 | main.stackDump(0x3f, 0xc000128060) 135 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 136 | main.stackDump(0x40, 0xc000128060) 137 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 138 | main.stackDump(0x41, 0xc000128060) 139 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 140 | main.stackDump(0x42, 0xc000128060) 141 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 142 | main.stackDump(0x43, 0xc000128060) 143 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 144 | main.stackDump(0x44, 0xc000128060) 145 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 146 | main.stackDump(0x45, 0xc000128060) 147 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 148 | main.stackDump(0x46, 0xc000128060) 149 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 150 | main.stackDump(0x47, 0xc000128060) 151 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 152 | main.stackDump(0x48, 0xc000128060) 153 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 154 | main.stackDump(0x49, 0xc000128060) 155 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 156 | main.stackDump(0x4a, 0xc000128060) 157 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 158 | main.stackDump(0x4b, 0xc000128060) 159 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 160 | main.stackDump(0x4c, 0xc000128060) 161 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 162 | main.stackDump(0x4d, 0xc000128060) 163 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 164 | main.stackDump(0x4e, 0xc000128060) 165 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 166 | main.stackDump(0x4f, 0xc000128060) 167 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 168 | main.stackDump(0x50, 0xc000128060) 169 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 170 | main.stackDump(0x51, 0xc000128060) 171 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 172 | main.stackDump(0x52, 0xc000128060) 173 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 174 | main.stackDump(0x53, 0xc000128060) 175 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 176 | main.stackDump(0x54, 0xc000128060) 177 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 178 | main.stackDump(0x55, 0xc000128060) 179 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 180 | main.stackDump(0x56, 0xc000128060) 181 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 182 | main.stackDump(0x57, 0xc000128060) 183 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 184 | main.stackDump(0x58, 0xc000128060) 185 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 186 | main.stackDump(0x59, 0xc000128060) 187 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 188 | main.stackDump(0x5a, 0xc000128060) 189 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 190 | main.stackDump(0x5b, 0xc000128060) 191 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 192 | main.stackDump(0x5c, 0xc000128060) 193 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 194 | main.stackDump(0x5d, 0xc000128060) 195 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 196 | main.stackDump(0x5e, 0xc000128060) 197 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 198 | main.stackDump(0x5f, 0xc000128060) 199 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 200 | main.stackDump(0x60, 0xc000128060) 201 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:22 +0x45 202 | ...additional frames elided... 203 | created by main.main 204 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:16 +0x66 205 | 206 | goroutine 1 [chan receive]: 207 | main.main() 208 | /Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go:17 +0x7d 209 | -------------------------------------------------------------------------------- /test-fixtures/ancestors.golden.json: -------------------------------------------------------------------------------- 1 | { 2 | "Errors": null, 3 | "Goroutines": [ 4 | { 5 | "ID": 1, 6 | "State": "running", 7 | "Wait": 0, 8 | "LockedToThread": false, 9 | "Stack": [ 10 | { 11 | "Func": "main.stackAll", 12 | "File": "/Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go", 13 | "Line": 31 14 | }, 15 | { 16 | "Func": "main.main", 17 | "File": "/Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go", 18 | "Line": 24 19 | } 20 | ], 21 | "FramesElided": false, 22 | "CreatedBy": null 23 | }, 24 | { 25 | "ID": 25, 26 | "State": "chan receive", 27 | "Wait": 0, 28 | "LockedToThread": false, 29 | "Stack": [ 30 | { 31 | "Func": "main.bar", 32 | "File": "/Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go", 33 | "Line": 57 34 | }, 35 | { 36 | "Func": "main.foo.func2", 37 | "File": "/Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go", 38 | "Line": 50 39 | } 40 | ], 41 | "FramesElided": false, 42 | "CreatedBy": { 43 | "Func": "main.d1", 44 | "File": "/Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go", 45 | "Line": 69 46 | }, 47 | "Ancestor": { 48 | "ID": 24, 49 | "State": "", 50 | "Wait": 0, 51 | "LockedToThread": false, 52 | "Stack": [ 53 | { 54 | "Func": "main.d1", 55 | "File": "/Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go", 56 | "Line": 70 57 | }, 58 | { 59 | "Func": "main.d1", 60 | "File": "/Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go", 61 | "Line": 73 62 | }, 63 | { 64 | "Func": "main.d1", 65 | "File": "/Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go", 66 | "Line": 73 67 | }, 68 | { 69 | "Func": "main.d1", 70 | "File": "/Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go", 71 | "Line": 73 72 | }, 73 | { 74 | "Func": "main.d1", 75 | "File": "/Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go", 76 | "Line": 73 77 | }, 78 | { 79 | "Func": "main.d1", 80 | "File": "/Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go", 81 | "Line": 73 82 | }, 83 | { 84 | "Func": "main.foo", 85 | "File": "/Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go", 86 | "Line": 52 87 | }, 88 | { 89 | "Func": "main.bar.func1", 90 | "File": "/Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go", 91 | "Line": 61 92 | } 93 | ], 94 | "FramesElided": false, 95 | "CreatedBy": { 96 | "Func": "main.d1", 97 | "File": "/Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go", 98 | "Line": 69 99 | }, 100 | "Ancestor": { 101 | "ID": 23, 102 | "State": "", 103 | "Wait": 0, 104 | "LockedToThread": false, 105 | "Stack": [ 106 | { 107 | "Func": "main.d1", 108 | "File": "/Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go", 109 | "Line": 70 110 | }, 111 | { 112 | "Func": "main.d1", 113 | "File": "/Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go", 114 | "Line": 73 115 | }, 116 | { 117 | "Func": "main.d1", 118 | "File": "/Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go", 119 | "Line": 73 120 | }, 121 | { 122 | "Func": "main.d1", 123 | "File": "/Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go", 124 | "Line": 73 125 | }, 126 | { 127 | "Func": "main.d1", 128 | "File": "/Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go", 129 | "Line": 73 130 | }, 131 | { 132 | "Func": "main.d1", 133 | "File": "/Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go", 134 | "Line": 73 135 | }, 136 | { 137 | "Func": "main.bar", 138 | "File": "/Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go", 139 | "Line": 61 140 | }, 141 | { 142 | "Func": "main.foo.func2", 143 | "File": "/Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go", 144 | "Line": 50 145 | } 146 | ], 147 | "FramesElided": false, 148 | "CreatedBy": { 149 | "Func": "main.d1", 150 | "File": "/Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go", 151 | "Line": 69 152 | }, 153 | "Ancestor": { 154 | "ID": 22, 155 | "State": "", 156 | "Wait": 0, 157 | "LockedToThread": false, 158 | "Stack": [ 159 | { 160 | "Func": "main.d1", 161 | "File": "/Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go", 162 | "Line": 70 163 | }, 164 | { 165 | "Func": "main.d1", 166 | "File": "/Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go", 167 | "Line": 73 168 | }, 169 | { 170 | "Func": "main.d1", 171 | "File": "/Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go", 172 | "Line": 73 173 | }, 174 | { 175 | "Func": "main.d1", 176 | "File": "/Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go", 177 | "Line": 73 178 | }, 179 | { 180 | "Func": "main.d1", 181 | "File": "/Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go", 182 | "Line": 73 183 | }, 184 | { 185 | "Func": "main.d1", 186 | "File": "/Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go", 187 | "Line": 73 188 | }, 189 | { 190 | "Func": "main.foo", 191 | "File": "/Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go", 192 | "Line": 52 193 | }, 194 | { 195 | "Func": "main.bar.func1", 196 | "File": "/Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go", 197 | "Line": 61 198 | } 199 | ], 200 | "FramesElided": false, 201 | "CreatedBy": { 202 | "Func": "main.d1", 203 | "File": "/Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go", 204 | "Line": 69 205 | }, 206 | "Ancestor": { 207 | "ID": 21, 208 | "State": "", 209 | "Wait": 0, 210 | "LockedToThread": false, 211 | "Stack": [ 212 | { 213 | "Func": "main.d1", 214 | "File": "/Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go", 215 | "Line": 70 216 | }, 217 | { 218 | "Func": "main.d1", 219 | "File": "/Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go", 220 | "Line": 73 221 | }, 222 | { 223 | "Func": "main.d1", 224 | "File": "/Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go", 225 | "Line": 73 226 | }, 227 | { 228 | "Func": "main.d1", 229 | "File": "/Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go", 230 | "Line": 73 231 | }, 232 | { 233 | "Func": "main.d1", 234 | "File": "/Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go", 235 | "Line": 73 236 | }, 237 | { 238 | "Func": "main.d1", 239 | "File": "/Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go", 240 | "Line": 73 241 | }, 242 | { 243 | "Func": "main.bar", 244 | "File": "/Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go", 245 | "Line": 61 246 | }, 247 | { 248 | "Func": "main.foo.func2", 249 | "File": "/Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go", 250 | "Line": 50 251 | } 252 | ], 253 | "FramesElided": false, 254 | "CreatedBy": { 255 | "Func": "main.d1", 256 | "File": "/Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go", 257 | "Line": 69 258 | }, 259 | "Ancestor": { 260 | "ID": 20, 261 | "State": "", 262 | "Wait": 0, 263 | "LockedToThread": false, 264 | "Stack": [ 265 | { 266 | "Func": "main.d1", 267 | "File": "/Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go", 268 | "Line": 70 269 | }, 270 | { 271 | "Func": "main.d1", 272 | "File": "/Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go", 273 | "Line": 73 274 | }, 275 | { 276 | "Func": "main.d1", 277 | "File": "/Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go", 278 | "Line": 73 279 | }, 280 | { 281 | "Func": "main.d1", 282 | "File": "/Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go", 283 | "Line": 73 284 | }, 285 | { 286 | "Func": "main.d1", 287 | "File": "/Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go", 288 | "Line": 73 289 | }, 290 | { 291 | "Func": "main.d1", 292 | "File": "/Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go", 293 | "Line": 73 294 | }, 295 | { 296 | "Func": "main.foo", 297 | "File": "/Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go", 298 | "Line": 52 299 | } 300 | ], 301 | "FramesElided": false, 302 | "CreatedBy": { 303 | "Func": "main.main", 304 | "File": "/Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go", 305 | "Line": 19 306 | }, 307 | "Ancestor": { 308 | "ID": 1, 309 | "State": "", 310 | "Wait": 0, 311 | "LockedToThread": false, 312 | "Stack": [ 313 | { 314 | "Func": "main.main", 315 | "File": "/Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go", 316 | "Line": 20 317 | } 318 | ], 319 | "FramesElided": false, 320 | "CreatedBy": null 321 | } 322 | } 323 | } 324 | } 325 | } 326 | } 327 | }, 328 | { 329 | "ID": 29, 330 | "State": "chan receive", 331 | "Wait": 0, 332 | "LockedToThread": false, 333 | "Stack": [ 334 | { 335 | "Func": "main.bar", 336 | "File": "/Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go", 337 | "Line": 57 338 | }, 339 | { 340 | "Func": "main.foo.func2", 341 | "File": "/Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go", 342 | "Line": 50 343 | } 344 | ], 345 | "FramesElided": false, 346 | "CreatedBy": { 347 | "Func": "main.d1", 348 | "File": "/Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go", 349 | "Line": 69 350 | }, 351 | "Ancestor": { 352 | "ID": 28, 353 | "State": "", 354 | "Wait": 0, 355 | "LockedToThread": false, 356 | "Stack": [ 357 | { 358 | "Func": "main.d1", 359 | "File": "/Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go", 360 | "Line": 70 361 | }, 362 | { 363 | "Func": "main.d1", 364 | "File": "/Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go", 365 | "Line": 73 366 | }, 367 | { 368 | "Func": "main.d1", 369 | "File": "/Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go", 370 | "Line": 73 371 | }, 372 | { 373 | "Func": "main.d1", 374 | "File": "/Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go", 375 | "Line": 73 376 | }, 377 | { 378 | "Func": "main.d1", 379 | "File": "/Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go", 380 | "Line": 73 381 | }, 382 | { 383 | "Func": "main.d1", 384 | "File": "/Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go", 385 | "Line": 73 386 | }, 387 | { 388 | "Func": "main.foo", 389 | "File": "/Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go", 390 | "Line": 52 391 | }, 392 | { 393 | "Func": "main.bar.func1", 394 | "File": "/Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go", 395 | "Line": 61 396 | } 397 | ], 398 | "FramesElided": false, 399 | "CreatedBy": { 400 | "Func": "main.d1", 401 | "File": "/Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go", 402 | "Line": 69 403 | }, 404 | "Ancestor": { 405 | "ID": 27, 406 | "State": "", 407 | "Wait": 0, 408 | "LockedToThread": false, 409 | "Stack": [ 410 | { 411 | "Func": "main.d1", 412 | "File": "/Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go", 413 | "Line": 70 414 | }, 415 | { 416 | "Func": "main.d1", 417 | "File": "/Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go", 418 | "Line": 73 419 | }, 420 | { 421 | "Func": "main.d1", 422 | "File": "/Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go", 423 | "Line": 73 424 | }, 425 | { 426 | "Func": "main.d1", 427 | "File": "/Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go", 428 | "Line": 73 429 | }, 430 | { 431 | "Func": "main.d1", 432 | "File": "/Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go", 433 | "Line": 73 434 | }, 435 | { 436 | "Func": "main.d1", 437 | "File": "/Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go", 438 | "Line": 73 439 | }, 440 | { 441 | "Func": "main.bar", 442 | "File": "/Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go", 443 | "Line": 61 444 | }, 445 | { 446 | "Func": "main.foo.func2", 447 | "File": "/Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go", 448 | "Line": 50 449 | } 450 | ], 451 | "FramesElided": false, 452 | "CreatedBy": { 453 | "Func": "main.d1", 454 | "File": "/Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go", 455 | "Line": 69 456 | }, 457 | "Ancestor": { 458 | "ID": 26, 459 | "State": "", 460 | "Wait": 0, 461 | "LockedToThread": false, 462 | "Stack": [ 463 | { 464 | "Func": "main.d1", 465 | "File": "/Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go", 466 | "Line": 70 467 | }, 468 | { 469 | "Func": "main.d1", 470 | "File": "/Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go", 471 | "Line": 73 472 | }, 473 | { 474 | "Func": "main.d1", 475 | "File": "/Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go", 476 | "Line": 73 477 | }, 478 | { 479 | "Func": "main.d1", 480 | "File": "/Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go", 481 | "Line": 73 482 | }, 483 | { 484 | "Func": "main.d1", 485 | "File": "/Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go", 486 | "Line": 73 487 | }, 488 | { 489 | "Func": "main.d1", 490 | "File": "/Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go", 491 | "Line": 73 492 | }, 493 | { 494 | "Func": "main.foo", 495 | "File": "/Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go", 496 | "Line": 52 497 | } 498 | ], 499 | "FramesElided": false, 500 | "CreatedBy": { 501 | "Func": "main.main", 502 | "File": "/Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go", 503 | "Line": 22 504 | }, 505 | "Ancestor": { 506 | "ID": 1, 507 | "State": "", 508 | "Wait": 0, 509 | "LockedToThread": false, 510 | "Stack": [ 511 | { 512 | "Func": "main.main", 513 | "File": "/Users/eric/Downloads/gostackparse/test-fixtures/ancestors.go", 514 | "Line": 23 515 | } 516 | ], 517 | "FramesElided": false, 518 | "CreatedBy": null 519 | } 520 | } 521 | } 522 | } 523 | } 524 | ] 525 | } 526 | -------------------------------------------------------------------------------- /test-fixtures/frameselided.golden.json: -------------------------------------------------------------------------------- 1 | { 2 | "Errors": null, 3 | "Goroutines": [ 4 | { 5 | "ID": 1, 6 | "State": "running", 7 | "Wait": 0, 8 | "LockedToThread": false, 9 | "Stack": [ 10 | { 11 | "Func": "runtime/pprof.writeGoroutineStacks", 12 | "File": "/usr/local/Cellar/go/1.15.6/libexec/src/runtime/pprof/pprof.go", 13 | "Line": 693 14 | }, 15 | { 16 | "Func": "runtime/pprof.writeGoroutine", 17 | "File": "/usr/local/Cellar/go/1.15.6/libexec/src/runtime/pprof/pprof.go", 18 | "Line": 682 19 | }, 20 | { 21 | "Func": "runtime/pprof.(*Profile).WriteTo", 22 | "File": "/usr/local/Cellar/go/1.15.6/libexec/src/runtime/pprof/pprof.go", 23 | "Line": 331 24 | }, 25 | { 26 | "Func": "main.stackDump", 27 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 28 | "Line": 16 29 | }, 30 | { 31 | "Func": "main.stackDump", 32 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 33 | "Line": 14 34 | }, 35 | { 36 | "Func": "main.stackDump", 37 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 38 | "Line": 14 39 | }, 40 | { 41 | "Func": "main.stackDump", 42 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 43 | "Line": 14 44 | }, 45 | { 46 | "Func": "main.stackDump", 47 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 48 | "Line": 14 49 | }, 50 | { 51 | "Func": "main.stackDump", 52 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 53 | "Line": 14 54 | }, 55 | { 56 | "Func": "main.stackDump", 57 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 58 | "Line": 14 59 | }, 60 | { 61 | "Func": "main.stackDump", 62 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 63 | "Line": 14 64 | }, 65 | { 66 | "Func": "main.stackDump", 67 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 68 | "Line": 14 69 | }, 70 | { 71 | "Func": "main.stackDump", 72 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 73 | "Line": 14 74 | }, 75 | { 76 | "Func": "main.stackDump", 77 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 78 | "Line": 14 79 | }, 80 | { 81 | "Func": "main.stackDump", 82 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 83 | "Line": 14 84 | }, 85 | { 86 | "Func": "main.stackDump", 87 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 88 | "Line": 14 89 | }, 90 | { 91 | "Func": "main.stackDump", 92 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 93 | "Line": 14 94 | }, 95 | { 96 | "Func": "main.stackDump", 97 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 98 | "Line": 14 99 | }, 100 | { 101 | "Func": "main.stackDump", 102 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 103 | "Line": 14 104 | }, 105 | { 106 | "Func": "main.stackDump", 107 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 108 | "Line": 14 109 | }, 110 | { 111 | "Func": "main.stackDump", 112 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 113 | "Line": 14 114 | }, 115 | { 116 | "Func": "main.stackDump", 117 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 118 | "Line": 14 119 | }, 120 | { 121 | "Func": "main.stackDump", 122 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 123 | "Line": 14 124 | }, 125 | { 126 | "Func": "main.stackDump", 127 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 128 | "Line": 14 129 | }, 130 | { 131 | "Func": "main.stackDump", 132 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 133 | "Line": 14 134 | }, 135 | { 136 | "Func": "main.stackDump", 137 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 138 | "Line": 14 139 | }, 140 | { 141 | "Func": "main.stackDump", 142 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 143 | "Line": 14 144 | }, 145 | { 146 | "Func": "main.stackDump", 147 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 148 | "Line": 14 149 | }, 150 | { 151 | "Func": "main.stackDump", 152 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 153 | "Line": 14 154 | }, 155 | { 156 | "Func": "main.stackDump", 157 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 158 | "Line": 14 159 | }, 160 | { 161 | "Func": "main.stackDump", 162 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 163 | "Line": 14 164 | }, 165 | { 166 | "Func": "main.stackDump", 167 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 168 | "Line": 14 169 | }, 170 | { 171 | "Func": "main.stackDump", 172 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 173 | "Line": 14 174 | }, 175 | { 176 | "Func": "main.stackDump", 177 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 178 | "Line": 14 179 | }, 180 | { 181 | "Func": "main.stackDump", 182 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 183 | "Line": 14 184 | }, 185 | { 186 | "Func": "main.stackDump", 187 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 188 | "Line": 14 189 | }, 190 | { 191 | "Func": "main.stackDump", 192 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 193 | "Line": 14 194 | }, 195 | { 196 | "Func": "main.stackDump", 197 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 198 | "Line": 14 199 | }, 200 | { 201 | "Func": "main.stackDump", 202 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 203 | "Line": 14 204 | }, 205 | { 206 | "Func": "main.stackDump", 207 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 208 | "Line": 14 209 | }, 210 | { 211 | "Func": "main.stackDump", 212 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 213 | "Line": 14 214 | }, 215 | { 216 | "Func": "main.stackDump", 217 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 218 | "Line": 14 219 | }, 220 | { 221 | "Func": "main.stackDump", 222 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 223 | "Line": 14 224 | }, 225 | { 226 | "Func": "main.stackDump", 227 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 228 | "Line": 14 229 | }, 230 | { 231 | "Func": "main.stackDump", 232 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 233 | "Line": 14 234 | }, 235 | { 236 | "Func": "main.stackDump", 237 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 238 | "Line": 14 239 | }, 240 | { 241 | "Func": "main.stackDump", 242 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 243 | "Line": 14 244 | }, 245 | { 246 | "Func": "main.stackDump", 247 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 248 | "Line": 14 249 | }, 250 | { 251 | "Func": "main.stackDump", 252 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 253 | "Line": 14 254 | }, 255 | { 256 | "Func": "main.stackDump", 257 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 258 | "Line": 14 259 | }, 260 | { 261 | "Func": "main.stackDump", 262 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 263 | "Line": 14 264 | }, 265 | { 266 | "Func": "main.stackDump", 267 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 268 | "Line": 14 269 | }, 270 | { 271 | "Func": "main.stackDump", 272 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 273 | "Line": 14 274 | }, 275 | { 276 | "Func": "main.stackDump", 277 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 278 | "Line": 14 279 | }, 280 | { 281 | "Func": "main.stackDump", 282 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 283 | "Line": 14 284 | }, 285 | { 286 | "Func": "main.stackDump", 287 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 288 | "Line": 14 289 | }, 290 | { 291 | "Func": "main.stackDump", 292 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 293 | "Line": 14 294 | }, 295 | { 296 | "Func": "main.stackDump", 297 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 298 | "Line": 14 299 | }, 300 | { 301 | "Func": "main.stackDump", 302 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 303 | "Line": 14 304 | }, 305 | { 306 | "Func": "main.stackDump", 307 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 308 | "Line": 14 309 | }, 310 | { 311 | "Func": "main.stackDump", 312 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 313 | "Line": 14 314 | }, 315 | { 316 | "Func": "main.stackDump", 317 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 318 | "Line": 14 319 | }, 320 | { 321 | "Func": "main.stackDump", 322 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 323 | "Line": 14 324 | }, 325 | { 326 | "Func": "main.stackDump", 327 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 328 | "Line": 14 329 | }, 330 | { 331 | "Func": "main.stackDump", 332 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 333 | "Line": 14 334 | }, 335 | { 336 | "Func": "main.stackDump", 337 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 338 | "Line": 14 339 | }, 340 | { 341 | "Func": "main.stackDump", 342 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 343 | "Line": 14 344 | }, 345 | { 346 | "Func": "main.stackDump", 347 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 348 | "Line": 14 349 | }, 350 | { 351 | "Func": "main.stackDump", 352 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 353 | "Line": 14 354 | }, 355 | { 356 | "Func": "main.stackDump", 357 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 358 | "Line": 14 359 | }, 360 | { 361 | "Func": "main.stackDump", 362 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 363 | "Line": 14 364 | }, 365 | { 366 | "Func": "main.stackDump", 367 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 368 | "Line": 14 369 | }, 370 | { 371 | "Func": "main.stackDump", 372 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 373 | "Line": 14 374 | }, 375 | { 376 | "Func": "main.stackDump", 377 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 378 | "Line": 14 379 | }, 380 | { 381 | "Func": "main.stackDump", 382 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 383 | "Line": 14 384 | }, 385 | { 386 | "Func": "main.stackDump", 387 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 388 | "Line": 14 389 | }, 390 | { 391 | "Func": "main.stackDump", 392 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 393 | "Line": 14 394 | }, 395 | { 396 | "Func": "main.stackDump", 397 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 398 | "Line": 14 399 | }, 400 | { 401 | "Func": "main.stackDump", 402 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 403 | "Line": 14 404 | }, 405 | { 406 | "Func": "main.stackDump", 407 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 408 | "Line": 14 409 | }, 410 | { 411 | "Func": "main.stackDump", 412 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 413 | "Line": 14 414 | }, 415 | { 416 | "Func": "main.stackDump", 417 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 418 | "Line": 14 419 | }, 420 | { 421 | "Func": "main.stackDump", 422 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 423 | "Line": 14 424 | }, 425 | { 426 | "Func": "main.stackDump", 427 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 428 | "Line": 14 429 | }, 430 | { 431 | "Func": "main.stackDump", 432 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 433 | "Line": 14 434 | }, 435 | { 436 | "Func": "main.stackDump", 437 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 438 | "Line": 14 439 | }, 440 | { 441 | "Func": "main.stackDump", 442 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 443 | "Line": 14 444 | }, 445 | { 446 | "Func": "main.stackDump", 447 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 448 | "Line": 14 449 | }, 450 | { 451 | "Func": "main.stackDump", 452 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 453 | "Line": 14 454 | }, 455 | { 456 | "Func": "main.stackDump", 457 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 458 | "Line": 14 459 | }, 460 | { 461 | "Func": "main.stackDump", 462 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 463 | "Line": 14 464 | }, 465 | { 466 | "Func": "main.stackDump", 467 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 468 | "Line": 14 469 | }, 470 | { 471 | "Func": "main.stackDump", 472 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 473 | "Line": 14 474 | }, 475 | { 476 | "Func": "main.stackDump", 477 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 478 | "Line": 14 479 | }, 480 | { 481 | "Func": "main.stackDump", 482 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 483 | "Line": 14 484 | }, 485 | { 486 | "Func": "main.stackDump", 487 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 488 | "Line": 14 489 | }, 490 | { 491 | "Func": "main.stackDump", 492 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 493 | "Line": 14 494 | }, 495 | { 496 | "Func": "main.stackDump", 497 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 498 | "Line": 14 499 | }, 500 | { 501 | "Func": "main.stackDump", 502 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 503 | "Line": 14 504 | }, 505 | { 506 | "Func": "main.stackDump", 507 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided.go", 508 | "Line": 14 509 | } 510 | ], 511 | "FramesElided": true, 512 | "CreatedBy": null 513 | } 514 | ] 515 | } 516 | -------------------------------------------------------------------------------- /test-fixtures/frameselided_goroutine.golden.json: -------------------------------------------------------------------------------- 1 | { 2 | "Errors": null, 3 | "Goroutines": [ 4 | { 5 | "ID": 18, 6 | "State": "running", 7 | "Wait": 0, 8 | "LockedToThread": false, 9 | "Stack": [ 10 | { 11 | "Func": "runtime/pprof.writeGoroutineStacks", 12 | "File": "/usr/local/Cellar/go/1.15.6/libexec/src/runtime/pprof/pprof.go", 13 | "Line": 693 14 | }, 15 | { 16 | "Func": "runtime/pprof.writeGoroutine", 17 | "File": "/usr/local/Cellar/go/1.15.6/libexec/src/runtime/pprof/pprof.go", 18 | "Line": 682 19 | }, 20 | { 21 | "Func": "runtime/pprof.(*Profile).WriteTo", 22 | "File": "/usr/local/Cellar/go/1.15.6/libexec/src/runtime/pprof/pprof.go", 23 | "Line": 331 24 | }, 25 | { 26 | "Func": "main.stackDump", 27 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 28 | "Line": 24 29 | }, 30 | { 31 | "Func": "main.stackDump", 32 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 33 | "Line": 22 34 | }, 35 | { 36 | "Func": "main.stackDump", 37 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 38 | "Line": 22 39 | }, 40 | { 41 | "Func": "main.stackDump", 42 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 43 | "Line": 22 44 | }, 45 | { 46 | "Func": "main.stackDump", 47 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 48 | "Line": 22 49 | }, 50 | { 51 | "Func": "main.stackDump", 52 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 53 | "Line": 22 54 | }, 55 | { 56 | "Func": "main.stackDump", 57 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 58 | "Line": 22 59 | }, 60 | { 61 | "Func": "main.stackDump", 62 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 63 | "Line": 22 64 | }, 65 | { 66 | "Func": "main.stackDump", 67 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 68 | "Line": 22 69 | }, 70 | { 71 | "Func": "main.stackDump", 72 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 73 | "Line": 22 74 | }, 75 | { 76 | "Func": "main.stackDump", 77 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 78 | "Line": 22 79 | }, 80 | { 81 | "Func": "main.stackDump", 82 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 83 | "Line": 22 84 | }, 85 | { 86 | "Func": "main.stackDump", 87 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 88 | "Line": 22 89 | }, 90 | { 91 | "Func": "main.stackDump", 92 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 93 | "Line": 22 94 | }, 95 | { 96 | "Func": "main.stackDump", 97 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 98 | "Line": 22 99 | }, 100 | { 101 | "Func": "main.stackDump", 102 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 103 | "Line": 22 104 | }, 105 | { 106 | "Func": "main.stackDump", 107 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 108 | "Line": 22 109 | }, 110 | { 111 | "Func": "main.stackDump", 112 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 113 | "Line": 22 114 | }, 115 | { 116 | "Func": "main.stackDump", 117 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 118 | "Line": 22 119 | }, 120 | { 121 | "Func": "main.stackDump", 122 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 123 | "Line": 22 124 | }, 125 | { 126 | "Func": "main.stackDump", 127 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 128 | "Line": 22 129 | }, 130 | { 131 | "Func": "main.stackDump", 132 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 133 | "Line": 22 134 | }, 135 | { 136 | "Func": "main.stackDump", 137 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 138 | "Line": 22 139 | }, 140 | { 141 | "Func": "main.stackDump", 142 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 143 | "Line": 22 144 | }, 145 | { 146 | "Func": "main.stackDump", 147 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 148 | "Line": 22 149 | }, 150 | { 151 | "Func": "main.stackDump", 152 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 153 | "Line": 22 154 | }, 155 | { 156 | "Func": "main.stackDump", 157 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 158 | "Line": 22 159 | }, 160 | { 161 | "Func": "main.stackDump", 162 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 163 | "Line": 22 164 | }, 165 | { 166 | "Func": "main.stackDump", 167 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 168 | "Line": 22 169 | }, 170 | { 171 | "Func": "main.stackDump", 172 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 173 | "Line": 22 174 | }, 175 | { 176 | "Func": "main.stackDump", 177 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 178 | "Line": 22 179 | }, 180 | { 181 | "Func": "main.stackDump", 182 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 183 | "Line": 22 184 | }, 185 | { 186 | "Func": "main.stackDump", 187 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 188 | "Line": 22 189 | }, 190 | { 191 | "Func": "main.stackDump", 192 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 193 | "Line": 22 194 | }, 195 | { 196 | "Func": "main.stackDump", 197 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 198 | "Line": 22 199 | }, 200 | { 201 | "Func": "main.stackDump", 202 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 203 | "Line": 22 204 | }, 205 | { 206 | "Func": "main.stackDump", 207 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 208 | "Line": 22 209 | }, 210 | { 211 | "Func": "main.stackDump", 212 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 213 | "Line": 22 214 | }, 215 | { 216 | "Func": "main.stackDump", 217 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 218 | "Line": 22 219 | }, 220 | { 221 | "Func": "main.stackDump", 222 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 223 | "Line": 22 224 | }, 225 | { 226 | "Func": "main.stackDump", 227 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 228 | "Line": 22 229 | }, 230 | { 231 | "Func": "main.stackDump", 232 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 233 | "Line": 22 234 | }, 235 | { 236 | "Func": "main.stackDump", 237 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 238 | "Line": 22 239 | }, 240 | { 241 | "Func": "main.stackDump", 242 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 243 | "Line": 22 244 | }, 245 | { 246 | "Func": "main.stackDump", 247 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 248 | "Line": 22 249 | }, 250 | { 251 | "Func": "main.stackDump", 252 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 253 | "Line": 22 254 | }, 255 | { 256 | "Func": "main.stackDump", 257 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 258 | "Line": 22 259 | }, 260 | { 261 | "Func": "main.stackDump", 262 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 263 | "Line": 22 264 | }, 265 | { 266 | "Func": "main.stackDump", 267 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 268 | "Line": 22 269 | }, 270 | { 271 | "Func": "main.stackDump", 272 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 273 | "Line": 22 274 | }, 275 | { 276 | "Func": "main.stackDump", 277 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 278 | "Line": 22 279 | }, 280 | { 281 | "Func": "main.stackDump", 282 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 283 | "Line": 22 284 | }, 285 | { 286 | "Func": "main.stackDump", 287 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 288 | "Line": 22 289 | }, 290 | { 291 | "Func": "main.stackDump", 292 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 293 | "Line": 22 294 | }, 295 | { 296 | "Func": "main.stackDump", 297 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 298 | "Line": 22 299 | }, 300 | { 301 | "Func": "main.stackDump", 302 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 303 | "Line": 22 304 | }, 305 | { 306 | "Func": "main.stackDump", 307 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 308 | "Line": 22 309 | }, 310 | { 311 | "Func": "main.stackDump", 312 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 313 | "Line": 22 314 | }, 315 | { 316 | "Func": "main.stackDump", 317 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 318 | "Line": 22 319 | }, 320 | { 321 | "Func": "main.stackDump", 322 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 323 | "Line": 22 324 | }, 325 | { 326 | "Func": "main.stackDump", 327 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 328 | "Line": 22 329 | }, 330 | { 331 | "Func": "main.stackDump", 332 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 333 | "Line": 22 334 | }, 335 | { 336 | "Func": "main.stackDump", 337 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 338 | "Line": 22 339 | }, 340 | { 341 | "Func": "main.stackDump", 342 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 343 | "Line": 22 344 | }, 345 | { 346 | "Func": "main.stackDump", 347 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 348 | "Line": 22 349 | }, 350 | { 351 | "Func": "main.stackDump", 352 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 353 | "Line": 22 354 | }, 355 | { 356 | "Func": "main.stackDump", 357 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 358 | "Line": 22 359 | }, 360 | { 361 | "Func": "main.stackDump", 362 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 363 | "Line": 22 364 | }, 365 | { 366 | "Func": "main.stackDump", 367 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 368 | "Line": 22 369 | }, 370 | { 371 | "Func": "main.stackDump", 372 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 373 | "Line": 22 374 | }, 375 | { 376 | "Func": "main.stackDump", 377 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 378 | "Line": 22 379 | }, 380 | { 381 | "Func": "main.stackDump", 382 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 383 | "Line": 22 384 | }, 385 | { 386 | "Func": "main.stackDump", 387 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 388 | "Line": 22 389 | }, 390 | { 391 | "Func": "main.stackDump", 392 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 393 | "Line": 22 394 | }, 395 | { 396 | "Func": "main.stackDump", 397 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 398 | "Line": 22 399 | }, 400 | { 401 | "Func": "main.stackDump", 402 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 403 | "Line": 22 404 | }, 405 | { 406 | "Func": "main.stackDump", 407 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 408 | "Line": 22 409 | }, 410 | { 411 | "Func": "main.stackDump", 412 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 413 | "Line": 22 414 | }, 415 | { 416 | "Func": "main.stackDump", 417 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 418 | "Line": 22 419 | }, 420 | { 421 | "Func": "main.stackDump", 422 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 423 | "Line": 22 424 | }, 425 | { 426 | "Func": "main.stackDump", 427 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 428 | "Line": 22 429 | }, 430 | { 431 | "Func": "main.stackDump", 432 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 433 | "Line": 22 434 | }, 435 | { 436 | "Func": "main.stackDump", 437 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 438 | "Line": 22 439 | }, 440 | { 441 | "Func": "main.stackDump", 442 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 443 | "Line": 22 444 | }, 445 | { 446 | "Func": "main.stackDump", 447 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 448 | "Line": 22 449 | }, 450 | { 451 | "Func": "main.stackDump", 452 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 453 | "Line": 22 454 | }, 455 | { 456 | "Func": "main.stackDump", 457 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 458 | "Line": 22 459 | }, 460 | { 461 | "Func": "main.stackDump", 462 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 463 | "Line": 22 464 | }, 465 | { 466 | "Func": "main.stackDump", 467 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 468 | "Line": 22 469 | }, 470 | { 471 | "Func": "main.stackDump", 472 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 473 | "Line": 22 474 | }, 475 | { 476 | "Func": "main.stackDump", 477 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 478 | "Line": 22 479 | }, 480 | { 481 | "Func": "main.stackDump", 482 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 483 | "Line": 22 484 | }, 485 | { 486 | "Func": "main.stackDump", 487 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 488 | "Line": 22 489 | }, 490 | { 491 | "Func": "main.stackDump", 492 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 493 | "Line": 22 494 | }, 495 | { 496 | "Func": "main.stackDump", 497 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 498 | "Line": 22 499 | }, 500 | { 501 | "Func": "main.stackDump", 502 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 503 | "Line": 22 504 | }, 505 | { 506 | "Func": "main.stackDump", 507 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 508 | "Line": 22 509 | } 510 | ], 511 | "FramesElided": true, 512 | "CreatedBy": { 513 | "Func": "main.main", 514 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 515 | "Line": 16 516 | } 517 | }, 518 | { 519 | "ID": 1, 520 | "State": "chan receive", 521 | "Wait": 0, 522 | "LockedToThread": false, 523 | "Stack": [ 524 | { 525 | "Func": "main.main", 526 | "File": "/Users/felix.geisendoerfer/go/src/github.com/DataDog/dd-trace-go/profiler/internal/stackparse/test-fixtures/frameselided_goroutine.go", 527 | "Line": 17 528 | } 529 | ], 530 | "FramesElided": false, 531 | "CreatedBy": null 532 | } 533 | ] 534 | } 535 | --------------------------------------------------------------------------------