Skip to content

Commit e28f713

Browse files
authored
internal: support optional filter expression for debug.stacks (#23605)
* internal: support optional filter expression for debug.stacks * internal/debug: fix string regexp * internal/debug: support searching for line numbers too
1 parent 62e3b83 commit e28f713

File tree

4 files changed

+47
-3
lines changed

4 files changed

+47
-3
lines changed

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ require (
3535
github.com/google/uuid v1.1.5
3636
github.com/gorilla/websocket v1.4.2
3737
github.com/graph-gophers/graphql-go v0.0.0-20201113091052-beb923fada29
38+
github.com/hashicorp/go-bexpr v0.1.10 // indirect
3839
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d
3940
github.com/holiman/bloomfilter/v2 v2.0.3
4041
github.com/holiman/uint256 v1.2.0

go.sum

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,8 @@ github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0U
216216
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
217217
github.com/graph-gophers/graphql-go v0.0.0-20201113091052-beb923fada29 h1:sezaKhEfPFg8W0Enm61B9Gs911H8iesGY5R8NDPtd1M=
218218
github.com/graph-gophers/graphql-go v0.0.0-20201113091052-beb923fada29/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc=
219+
github.com/hashicorp/go-bexpr v0.1.10 h1:9kuI5PFotCboP3dkDYFr/wi0gg0QVbSNz5oFRpxn4uE=
220+
github.com/hashicorp/go-bexpr v0.1.10/go.mod h1:oxlubA2vC/gFVfX1A6JGp7ls7uCDlfJn732ehYYg+g0=
219221
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
220222
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
221223
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d h1:dg1dEPuWpEqDnvIw251EVy4zlP8gWbsGj4BsUKCRpYs=
@@ -307,6 +309,10 @@ github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m
307309
github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
308310
github.com/mattn/go-tty v0.0.0-20180907095812-13ff1204f104/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE=
309311
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
312+
github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag=
313+
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
314+
github.com/mitchellh/pointerstructure v1.2.0 h1:O+i9nHnXS3l/9Wu7r4NrEdwA2VFTicjUEN1uBnDo34A=
315+
github.com/mitchellh/pointerstructure v1.2.0/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4=
310316
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
311317
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
312318
github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg=

internal/debug/api.go

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import (
2727
"os"
2828
"os/user"
2929
"path/filepath"
30+
"regexp"
3031
"runtime"
3132
"runtime/debug"
3233
"runtime/pprof"
@@ -35,6 +36,7 @@ import (
3536
"time"
3637

3738
"github.com/ethereum/go-ethereum/log"
39+
"github.com/hashicorp/go-bexpr"
3840
)
3941

4042
// Handler is the global debugging handler.
@@ -189,10 +191,44 @@ func (*HandlerT) WriteMemProfile(file string) error {
189191
return writeProfile("heap", file)
190192
}
191193

192-
// Stacks returns a printed representation of the stacks of all goroutines.
193-
func (*HandlerT) Stacks() string {
194+
// Stacks returns a printed representation of the stacks of all goroutines. It
195+
// also permits the following optional filters to be used:
196+
// - filter: boolean expression of packages to filter for
197+
func (*HandlerT) Stacks(filter *string) string {
194198
buf := new(bytes.Buffer)
195199
pprof.Lookup("goroutine").WriteTo(buf, 2)
200+
201+
// If any filtering was requested, execute them now
202+
if filter != nil && len(*filter) > 0 {
203+
expanded := *filter
204+
205+
// The input filter is a logical expression of package names. Transform
206+
// it into a proper boolean expression that can be fed into a parser and
207+
// interpreter:
208+
//
209+
// E.g. (eth || snap) && !p2p -> (eth in Value || snap in Value) && p2p not in Value
210+
expanded = regexp.MustCompile("[:/\\.A-Za-z0-9_-]+").ReplaceAllString(expanded, "`$0` in Value")
211+
expanded = regexp.MustCompile("!(`[:/\\.A-Za-z0-9_-]+`)").ReplaceAllString(expanded, "$1 not")
212+
expanded = strings.Replace(expanded, "||", "or", -1)
213+
expanded = strings.Replace(expanded, "&&", "and", -1)
214+
log.Info("Expanded filter expression", "filter", *filter, "expanded", expanded)
215+
216+
expr, err := bexpr.CreateEvaluator(expanded)
217+
if err != nil {
218+
log.Error("Failed to parse filter expression", "expanded", expanded, "err", err)
219+
return ""
220+
}
221+
// Split the goroutine dump into segments and filter each
222+
dump := buf.String()
223+
buf.Reset()
224+
225+
for _, trace := range strings.Split(dump, "\n\n") {
226+
if ok, _ := expr.Evaluate(map[string]string{"Value": trace}); ok {
227+
buf.WriteString(trace)
228+
buf.WriteString("\n\n")
229+
}
230+
}
231+
}
196232
return buf.String()
197233
}
198234

internal/web3ext/web3ext.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,8 @@ web3._extend({
278278
new web3._extend.Method({
279279
name: 'stacks',
280280
call: 'debug_stacks',
281-
params: 0,
281+
params: 1,
282+
inputFormatter: [null],
282283
outputFormatter: console.log
283284
}),
284285
new web3._extend.Method({

0 commit comments

Comments
 (0)