Hey @nicolaigj, welcome to the forum!
This changes just about every function signature and therefore screws up our testing and would require a fair amount of refactoring. is there a way to access the transaction without having to pass it around in function parameters?
Manual propagation is just the way things need to be done in Go, since it lacks anything like thread-local storage.
Rather than passing transactions or spans explicitly, I would recommend you use context
. These docs need a bit of love, but demonstrate how you can pass context between functions and start spans using it: Set up the Agent | APM Go Agent Reference [2.x] | Elastic
So rather than
func doSomething(tx *apm.Transaction) {
span := tx.StartSpan("name", "type")
defer span.End()
}
do this instead:
func doSomething(ctx context.Context) {
span, ctx := apm.StartSpan(ctx, "name", "type")
defer span.End()
}
Passing context around may have additional benefits, such as being able to propagate other request-scoped data, and request cancellation.
If you specifically want to extract the current transaction from a context object, you can use apm.TransactionFromContext.
And another question, if I implement passing transaction as function parameters, is there a correct way to fake a transaction in testing that don't send anything to the server?
This might be moot if you pass context around instead, since apm.StartSpan
will return a no-op span if the context doesn't contain a transaction. Thus if you pass context.Background()
into your functions, no spans will be generated.
If you want to test your instrumentation, you could initialise a Tracer a fake transport. The agent has a testing package, go.elastic.co/apm/apmtest, with various things that you could use, such as apmtest.NewRecordingTracer, which can be used for recording events in memory.