AspectGo is an AOP framework for Go. You can write an aspect in a simple Go-compatible grammar.
I'm hoping to propose merging AspectGo to the upstream of golang.org/x/exp if possible, but no concret plan yet.
Recipe:
- Logging
- Assertion
- Fault injection
- Mocking
- Coverage-guided genetic fuzzing (as in AFL)
- Fuzzed(randomized) scheduling
The interface is not fixed yet. Your suggestion and PR are welcome.
$ go install github.com/AkihiroSuda/aspectgo/cmd/aspectgo $ go build github.com/AkihiroSuda/aspectgo/example/hello && ./hello hello $ aspectgo \ -w /tmp/wovengopath \ # output gopath -t github.com/AkihiroSuda/aspectgo/example/hello \ # target package example/hello/main_aspect.go # aspect file $ GOPATH=/tmp/wovengopath go build github.com/AkihiroSuda/aspectgo/example/hello && ./hello BEFORE hello hello AFTER hello The aspect is located on example/hello/main_aspect.go:
package main import ( "fmt" "regexp" asp "github.com/AkihiroSuda/aspectgo/aspect" ) // ExampleAspect implements interface asp.Aspect type ExampleAspect struct { } // Executed on compilation-time func (a *ExampleAspect) Pointcut() asp.Pointcut { pkg := regexp.QuoteMeta("github.com/AkihiroSuda/aspectgo/example/hello") s := pkg + ".*" return asp.NewCallPointcutFromRegexp(s) } // Executed ONLY on runtime func (a *ExampleAspect) Advice(ctx asp.Context) []interface{} { args := ctx.Args() fmt.Println("BEFORE hello") res := ctx.Call(args) fmt.Println("AFTER hello") return res }The target is example/hello/main.go:
package main import ( "fmt" ) func sayHello(s string) { fmt.Println("hello " + s) } func main() { sayHello("world") }You can also execute other examples as follows:
$ go test -v github.com/AkihiroSuda/aspectgo/example If the output is hard to read, please add the -parallel 1 flag to go test.
- Clean
/tmp/wovengopathbefore runningaspectgoevery time. - Clean GOPATH before running
aspectgofor faster compilation.
- Only single aspect file is supported (But you can define multiple aspects in a single file)
- Only regexp for function name (excluding
mainandinit) and method name can be a pointcut - Only "call" pointcut is supported. No support for "execution" pointcut yet:
- Suppose that
*S,*TimplementsI, and there is a call toI.Foo()in the target package. You can make a pointcut forI.Foo(), but you can't make a pointcut for*Snor*T. - Aspect cannot be woven to Go-builtin packages. i.e., You can't hook a call from a Go-builtin pacakge. (But you can hook a call to a Go-builtin package by just making a "call" pointcut for it)
- Suppose that
- Only "around" advice is supported. No support for "before" and "after" pointcut.
- If an object hits multiple pointcuts, only the last one is effective.
- github.com/deferpanic/goweave
- github.com/gogap/aop
- golang.org/x/tools/refactor/eg (Not AOP, but has some similarity)
- github.com/coreos/gofail (ditto)