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
This commit is contained in:
		
							
								
								
									
										1
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								go.mod
									
									
									
									
									
								
							| @@ -35,6 +35,7 @@ require ( | |||||||
| 	github.com/google/uuid v1.1.5 | 	github.com/google/uuid v1.1.5 | ||||||
| 	github.com/gorilla/websocket v1.4.2 | 	github.com/gorilla/websocket v1.4.2 | ||||||
| 	github.com/graph-gophers/graphql-go v0.0.0-20201113091052-beb923fada29 | 	github.com/graph-gophers/graphql-go v0.0.0-20201113091052-beb923fada29 | ||||||
|  | 	github.com/hashicorp/go-bexpr v0.1.10 // indirect | ||||||
| 	github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d | 	github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d | ||||||
| 	github.com/holiman/bloomfilter/v2 v2.0.3 | 	github.com/holiman/bloomfilter/v2 v2.0.3 | ||||||
| 	github.com/holiman/uint256 v1.2.0 | 	github.com/holiman/uint256 v1.2.0 | ||||||
|   | |||||||
							
								
								
									
										6
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								go.sum
									
									
									
									
									
								
							| @@ -216,6 +216,8 @@ github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0U | |||||||
| github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= | github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= | ||||||
| github.com/graph-gophers/graphql-go v0.0.0-20201113091052-beb923fada29 h1:sezaKhEfPFg8W0Enm61B9Gs911H8iesGY5R8NDPtd1M= | github.com/graph-gophers/graphql-go v0.0.0-20201113091052-beb923fada29 h1:sezaKhEfPFg8W0Enm61B9Gs911H8iesGY5R8NDPtd1M= | ||||||
| github.com/graph-gophers/graphql-go v0.0.0-20201113091052-beb923fada29/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc= | github.com/graph-gophers/graphql-go v0.0.0-20201113091052-beb923fada29/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc= | ||||||
|  | github.com/hashicorp/go-bexpr v0.1.10 h1:9kuI5PFotCboP3dkDYFr/wi0gg0QVbSNz5oFRpxn4uE= | ||||||
|  | github.com/hashicorp/go-bexpr v0.1.10/go.mod h1:oxlubA2vC/gFVfX1A6JGp7ls7uCDlfJn732ehYYg+g0= | ||||||
| github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= | github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= | ||||||
| github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= | github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= | ||||||
| github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d h1:dg1dEPuWpEqDnvIw251EVy4zlP8gWbsGj4BsUKCRpYs= | 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 | |||||||
| github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= | github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= | ||||||
| github.com/mattn/go-tty v0.0.0-20180907095812-13ff1204f104/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE= | github.com/mattn/go-tty v0.0.0-20180907095812-13ff1204f104/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE= | ||||||
| github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= | github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= | ||||||
|  | github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= | ||||||
|  | github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= | ||||||
|  | github.com/mitchellh/pointerstructure v1.2.0 h1:O+i9nHnXS3l/9Wu7r4NrEdwA2VFTicjUEN1uBnDo34A= | ||||||
|  | github.com/mitchellh/pointerstructure v1.2.0/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4= | ||||||
| github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= | ||||||
| github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= | github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= | ||||||
| github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg= | github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg= | ||||||
|   | |||||||
| @@ -27,6 +27,7 @@ import ( | |||||||
| 	"os" | 	"os" | ||||||
| 	"os/user" | 	"os/user" | ||||||
| 	"path/filepath" | 	"path/filepath" | ||||||
|  | 	"regexp" | ||||||
| 	"runtime" | 	"runtime" | ||||||
| 	"runtime/debug" | 	"runtime/debug" | ||||||
| 	"runtime/pprof" | 	"runtime/pprof" | ||||||
| @@ -35,6 +36,7 @@ import ( | |||||||
| 	"time" | 	"time" | ||||||
|  |  | ||||||
| 	"github.com/ethereum/go-ethereum/log" | 	"github.com/ethereum/go-ethereum/log" | ||||||
|  | 	"github.com/hashicorp/go-bexpr" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // Handler is the global debugging handler. | // Handler is the global debugging handler. | ||||||
| @@ -189,10 +191,44 @@ func (*HandlerT) WriteMemProfile(file string) error { | |||||||
| 	return writeProfile("heap", file) | 	return writeProfile("heap", file) | ||||||
| } | } | ||||||
|  |  | ||||||
| // Stacks returns a printed representation of the stacks of all goroutines. | // Stacks returns a printed representation of the stacks of all goroutines. It | ||||||
| func (*HandlerT) Stacks() string { | // also permits the following optional filters to be used: | ||||||
|  | //   - filter: boolean expression of packages to filter for | ||||||
|  | func (*HandlerT) Stacks(filter *string) string { | ||||||
| 	buf := new(bytes.Buffer) | 	buf := new(bytes.Buffer) | ||||||
| 	pprof.Lookup("goroutine").WriteTo(buf, 2) | 	pprof.Lookup("goroutine").WriteTo(buf, 2) | ||||||
|  |  | ||||||
|  | 	// If any filtering was requested, execute them now | ||||||
|  | 	if filter != nil && len(*filter) > 0 { | ||||||
|  | 		expanded := *filter | ||||||
|  |  | ||||||
|  | 		// The input filter is a logical expression of package names. Transform | ||||||
|  | 		// it into a proper boolean expression that can be fed into a parser and | ||||||
|  | 		// interpreter: | ||||||
|  | 		// | ||||||
|  | 		// E.g. (eth || snap) && !p2p -> (eth in Value || snap in Value) && p2p not in Value | ||||||
|  | 		expanded = regexp.MustCompile("[:/\\.A-Za-z0-9_-]+").ReplaceAllString(expanded, "`$0` in Value") | ||||||
|  | 		expanded = regexp.MustCompile("!(`[:/\\.A-Za-z0-9_-]+`)").ReplaceAllString(expanded, "$1 not") | ||||||
|  | 		expanded = strings.Replace(expanded, "||", "or", -1) | ||||||
|  | 		expanded = strings.Replace(expanded, "&&", "and", -1) | ||||||
|  | 		log.Info("Expanded filter expression", "filter", *filter, "expanded", expanded) | ||||||
|  |  | ||||||
|  | 		expr, err := bexpr.CreateEvaluator(expanded) | ||||||
|  | 		if err != nil { | ||||||
|  | 			log.Error("Failed to parse filter expression", "expanded", expanded, "err", err) | ||||||
|  | 			return "" | ||||||
|  | 		} | ||||||
|  | 		// Split the goroutine dump into segments and filter each | ||||||
|  | 		dump := buf.String() | ||||||
|  | 		buf.Reset() | ||||||
|  |  | ||||||
|  | 		for _, trace := range strings.Split(dump, "\n\n") { | ||||||
|  | 			if ok, _ := expr.Evaluate(map[string]string{"Value": trace}); ok { | ||||||
|  | 				buf.WriteString(trace) | ||||||
|  | 				buf.WriteString("\n\n") | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
| 	return buf.String() | 	return buf.String() | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -278,7 +278,8 @@ web3._extend({ | |||||||
| 		new web3._extend.Method({ | 		new web3._extend.Method({ | ||||||
| 			name: 'stacks', | 			name: 'stacks', | ||||||
| 			call: 'debug_stacks', | 			call: 'debug_stacks', | ||||||
| 			params: 0, | 			params: 1, | ||||||
|  | 			inputFormatter: [null], | ||||||
| 			outputFormatter: console.log | 			outputFormatter: console.log | ||||||
| 		}), | 		}), | ||||||
| 		new web3._extend.Method({ | 		new web3._extend.Method({ | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user