Skip to content

"no active transaction found - cannot build new span" in wrapper function #1781

@janpio

Description

@janpio

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:

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 Customers.


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:

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?

Metadata

Metadata

Assignees

No one assigned

    Labels

    agent-nodejsMake available for APM Agents project planning.bug

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions