Link

Around Advice

The one that takes the full control of your functions.


About

We will go though a real Around advice. This advice prints the taken time by the function.

Prerequisites

Let’s check that our environment is ready to follow the tutorial!

  • Install beyond tool & clone the beyond-examples repository
    >> go get github.com/wesovilabs/beyond
    >> git clone https://github.com/wesovilabs/beyond-examples.git
    >> cd around
    

Let’s do it!

> Define the advice

Around advices must implement the interface Around (github.com/wesovilabs/beyond/api.Around).

type Around interface {
  Before(ctx *context.BeyondContext)
  Returning(ctx *context.BeyondContext)
}

Open file advice/timer.go.

const timeStartKey = "time.start"

type TimerMode int32

const (
  Nanoseconds TimerMode = iota
  Microseconds
)

type TimerAdvice struct {
  mode TimerMode
}

func (a *TimerAdvice) Before(ctx *context.BeyondContext) {
  ctx.Set(timeStartKey, time.Now())
}

func (a *TimerAdvice) Returning(ctx *context.BeyondContext) {
  start := ctx.Get(timeStartKey).(time.Time)
  timeDuration:="?"
  switch a.mode {
  case Nanoseconds:
    timeDuration = fmt.Sprintf("%v nanoseconds\n", time.Since(start).Nanoseconds())
  case Microseconds:
    timeDuration = fmt.Sprintf("%v microseconds\n", time.Since(start).Microseconds())
  }
  params := make([]string, ctx.Params().Count())
  ctx.Params().ForEach(func(index int, arg *context.Arg) {
    params[index] = fmt.Sprintf("%s:%v", arg.Name(), arg.Value())
  })
  fmt.Printf("%s.%s(%s) took %s", ctx.Pkg(), ctx.Function(), strings.Join(params, ","),timeDuration)
}

Type TimerAdvice

This is our advice. It implements Around interface.

Method Before:

It contains the code to be executed before intercepted functions are executed.

Method Returning:

It contains the code to be executed after intercepted functions are executed.

> Register the advice

  • Write a function (or many) that returns the Returning advice

The function signature must be:

func() Around

Check the following functions, in file advice/timer.go,

func NewTimerAdvice(mode TimerMode) func() api.Around {
	return func() api.Around{
		return &TimerAdvice{mode}
	}
}

Keep in mind that Beyond ignores non-exported functions.

  • Register the above function

Open file cmd/main.go and have a look at function Beyond().

func Beyond() *api.Beyond {
  return api.New().
    WithAround(advice.NewTimerAdvice(advice.Microseconds), "greeting.Hello(string)...").
    WithAround(advice.NewTimerAdvice(advice.Nanoseconds), "greeting.Bye(string)...")
}

func main() {
  greeting.Greetings("Hello", "John")
  greeting.Greetings("Bye", "John")
}

Two functions will be intercepted:

We will learn more about how to register advices in section JoinPoint Expressions

> Beyond in action

This would be the normal behavior

>> go run cmd/main.go
Hey John
Bye John

but when we execute beyond command … (time won’t be exactly the same)

>> beyond run cmd/main.go
Hey John
greeting.Hello(firstName:John) took 37 microseconds
Bye John
greeting.Bye(firstName:John) took 4102 nanoseconds

Challenge

This time, the challenge must be decided by yourself!!! Extend the TimerAdvice or build a new one that you think it could be useful for other developers too.

When you complete this challenge, why dont you post an article sharing your experience with Beyond! I would be very grateful!


If you enjoyed this article, I would really appreciate if you shared it with your networks