Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wrapper helpers using reflection #970

Open
ktsivkov opened this issue Oct 9, 2024 · 3 comments
Open

Wrapper helpers using reflection #970

ktsivkov opened this issue Oct 9, 2024 · 3 comments

Comments

@ktsivkov
Copy link

ktsivkov commented Oct 9, 2024

Provide helper functions to enable easier and cleaner way to start transactions and segments.

Summary

By my experience most of the time the applications that require transactions they are quite straight forward.

  • Starting a transaction
  • Starting Segments
  • Ending segments
  • Ending transactions

Desired Behaviour

Optimally will be nice to have a way to wrap application specific functions that when invoked will start transactions and segments without coupling the application code to the agent's behavior, and without changing their underlying type.

To achieve the wrapping behavior we can use reflections, and to avoid changing the underlying type of the "wrapees" we can use generics.

Possible Solution

I can think of two solutions, the easiest one could be the addition of helper functions WrapTransactionFunc and WrapSegmentFunc, and they can be implemented like this:

func WrapTransactionFunc[V any](app *Application, wrapee V, transactionName string, traceOptions ...TraceOption) V {
	typ := reflect.TypeOf(wrapee)
	if typ.Kind() != reflect.Func {
		panic("wrapee must be a func")
	}

	wrappedFunc := func(args []reflect.Value) []reflect.Value {
		tx := app.StartTransaction(transactionName, traceOptions...)
		defer tx.End()

		return reflect.ValueOf(wrapee).Call(args)
	}

	fn := reflect.MakeFunc(typ, wrappedFunc)
	return fn.Interface().(V)
}


func WrapSegmentFunc[V any](tx *Transaction, wrapee V, segmentName string) V {
	typ := reflect.TypeOf(wrapee)
	if typ.Kind() != reflect.Func {
		panic("wrapee must be a func")
	}

	wrappedFunc := func(args []reflect.Value) []reflect.Value {
		sg := tx.StartSegment(segmentName)
		defer sg.End()

		return reflect.ValueOf(wrapee).Call(args)
	}

	fn := reflect.MakeFunc(typ, wrappedFunc)
	return fn.Interface().(V)
}
@iamemilio
Copy link
Contributor

iamemilio commented Oct 9, 2024

This would rack up quite a bit of overhead. Have you played with easy-instrumentation at all?

@ktsivkov
Copy link
Author

ktsivkov commented Oct 9, 2024

@iamemilio No, but just checked the readme file. It looks quite interesting, I will definitely have a look!

@iamemilio
Copy link
Contributor

iamemilio commented Oct 9, 2024

Don't hesitate to leave us some feedback! We don't have the ability to exclude functions at the moment, but can track that as a possible feature.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants