func (wrapper *GenericWrapper) Call(args ...interface{}) (results []reflect.Value) {
	inputs := wrapper.transformArguments(args...)
	defer func() {
		wrapper.thrownError = recover()
		if wrapper.thrownError != nil {
			exception := &protocol.Exception{
				Type:      "Runtime Error",
				Message:   fmt.Sprintf("%v", wrapper.thrownError),
				Traceback: string(debug.Stack()),
				Time:      tracer.GetTimestamp(),
			}
			if wrapper.invoking {
				wrapper.runner.Exception = exception
				wrapper.runner.ErrorCode = protocol.ErrorCode_EXCEPTION
				wrapper.safeAddRunnerEvent()
				panic(userError{
					exception: wrapper.thrownError,
					stack:     exception.Traceback,
				})
			} else {
				exception.Type = "GenericEpsagonWrapper"
				wrapper.tracer.AddException(exception)
				if !wrapper.invoked {  
					results = wrapper.handler.Call(inputs)
				}
			}
		}
	}()
	wrapper.createRunner()
	wrapper.invoking = true
	wrapper.invoked = true
	results = wrapper.handler.Call(inputs)
	wrapper.invoking = false
	wrapper.addRunnerEvent()
	return results
}
Call the wrapped function
package epsagon
import (
	"fmt"
	"reflect"
	"runtime"
	"runtime/debug"
	"github.com/epsagon/epsagon-go/protocol"
	"github.com/epsagon/epsagon-go/tracer"
	"github.com/google/uuid"
)
type userError struct {
	exception interface{}
	stack     string
}
type GenericWrapper struct {
	handler       reflect.Value
	config        *Config
	tracer        tracer.Tracer
	runner        *protocol.Event
	thrownError   interface{}
	resourceName  string
	invoked       bool
	invoking      bool
	dontAddRunner bool
	injectContext bool
}
func WrapGenericFunction(
	handler interface{}, config *Config, tracer tracer.Tracer, injectContext bool, resourceName string) *GenericWrapper {
	return &GenericWrapper{
		config:        config,
		handler:       reflect.ValueOf(handler),
		tracer:        tracer,
		injectContext: injectContext,
		resourceName:  resourceName,
	}
}
func (wrapper *GenericWrapper) GetRunnerEvent() *protocol.Event {
	return wrapper.runner
}
func (wrapper *GenericWrapper) createRunner() {
	resourceName := wrapper.resourceName
	if len(resourceName) == 0 {
		resourceName = runtime.FuncForPC(wrapper.handler.Pointer()).Name()
	}
	wrapper.runner = &protocol.Event{
		Id:        uuid.New().String(),
		Origin:    "runner",
		StartTime: tracer.GetTimestamp(),
		Resource: &protocol.Resource{
			Name:      resourceName,
			Type:      "go-function",
			Operation: "invoke",
			Metadata:  make(map[string]string),
		},
		ErrorCode: protocol.ErrorCode_OK,
	}
}
func (wrapper *GenericWrapper) safeAddRunnerEvent() {
	defer func() {
		recover()
	}()
	wrapper.addRunnerEvent()
}
func (wrapper *GenericWrapper) addRunnerEvent() {
	if wrapper.dontAddRunner {
		return
	}
	endTime := tracer.GetTimestamp()
	wrapper.runner.Duration = endTime - wrapper.runner.StartTime
	wrapper.tracer.AddEvent(wrapper.runner)
}
func (wrapper *GenericWrapper) transformArguments(args ...interface{}) []reflect.Value {
	actualLength := len(args)
	if wrapper.injectContext {
		actualLength += 1
	}
	if wrapper.handler.Type().NumIn() != actualLength {
		msg := fmt.Sprintf(
			"Wrong number of args: %d, expected: %d",
			actualLength, wrapper.handler.Type().NumIn())
		wrapper.createRunner()
		wrapper.runner.Exception = &protocol.Exception{
			Type:    "Runtime Error",
			Message: fmt.Sprintf("%v", msg),
			Time:    tracer.GetTimestamp(),
		}
		wrapper.safeAddRunnerEvent()
		panic(msg)
	}
	inputs := make([]reflect.Value, actualLength)
	argsInputs := inputs
	if wrapper.injectContext {
		inputs[0] = reflect.ValueOf(ContextWithTracer(wrapper.tracer))
		argsInputs = argsInputs[1:]
	}
	for k, in := range args {
		argsInputs[k] = reflect.ValueOf(in)
	}
	return inputs
}