elastic / elastic/apm-agent-nodejs
"no active transaction found - cannot build new span" in wrapper function
- Dominant language
- JavaScript
- Stars
- 594
- Forks
- 244
- Avg merge
- 1d 8h
- Merged PRs (30d)
- 16
Description
Hi, working with the Node Instrumentation of Elastic APM has been nice this weekend!
But now I hit a problem that took me quite a bit of time to solve. And although I found a workaround, I wonder if I was doing something wrong:
---
I want to instrument a function _inside_ of `@prisma/client`, a database client.
You start Prisma Client like this:
```js
const { PrismaClient } = require('@prisma/client')
const prisma = new PrismaClient()
```
Then you can do e.g. `await prisma.customer.findMany()` to get a list of all your `Customer`s.
---
The function I am interested in is `prisma.fetcher.request`, as it sends the job to a binary (Query Engine). Knowing how long that binary is busy would be interesting to me.
Unfortunately this `request` is not a straight from `@prisma/client` - you see above that we have to "dance" a bit first to have an thing where the function I want is present. (I do not even know how the `const { PrismaClient }` thing is called, and afterwards we have to instantiate the Client first. [The reason for this btw is that the Client is generated custom to my database schema on build time, not on run time.])
---
I tried to use `apm.addPatch`, but to be able to get an `request` function I had to `new PrismaClient()` first, and then modify that client and overwrite the one in the export - and in the end it did not work because of the error message from the title. The different "contextes" of the patching function, then the object inside etc confused me too much to be able to fix this.
---
So I dumped `apm.addPatch` and decided just to try to simply wrap `prisma.fetcher.request`. Less elegant code, but easier to achieve as I can just do that on my real `prisma` object:
```js
var originalRequest = prisma.fetcher.request
var newRequest = async function(object) {
var span = apm.startSpan('Query Engine (prisma.fetcher.request)')
var result = await originalRequest.call(this, object)
span.end()
return result
}
prisma.fetcher.request = newRequest
```
This unfortunately led to the same `no active transaction found - cannot build new span` message in the debug output of Elastic APM Node.
I found a workaround: Inside my express route where I have a working `startSpan` I "export" the current transaction into a variable `currentTransaction = apm.currentTransaction` and then use `currentTransaction.startSpan` in the code above instead of `apm.startSpan`. This works.
- (A small side effect stays: I get the following debug log message each time:
```
recovering from wrong currentTransaction {
wrong: undefined,
correct: '231f0f9de2f88e5c',
trace: '4e9075a7c4af5cfe15783a5b3bbeca32'
}
```
Seems using `startSpan` on `currentTransaction` fixes the problem, but at the same time is unexpected enough for this log message.)
Is there a way to avoid this workaround?
How should I have done this in the first place?
Contributor guide
Assessment
This issue has not been assessed yet.