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

Mongoose spans are getting attached to wrong parent transaction #3161

Closed
1 of 3 tasks
sefiros1 opened this issue Feb 16, 2023 · 9 comments · Fixed by #3665
Closed
1 of 3 tasks

Mongoose spans are getting attached to wrong parent transaction #3161

sefiros1 opened this issue Feb 16, 2023 · 9 comments · Fixed by #3665
Assignees
Labels
agent-nodejs Make available for APM Agents project planning. bug community
Milestone

Comments

@sefiros1
Copy link
Contributor

Describe the bug

I'm using Koa with MongoDB via mongoose. With multiple simultaneous requests, mongoose spans begin to attach to the wrong parents. There is no such problem with one simultaneous request.

To Reproduce

Steps to reproduce the behavior:

  1. Start MongoDB server and run Koa server with mongoose (node index.js):
// index.js
/* eslint-disable import/order */
const elasticApmNode = require('elastic-apm-node');
elasticApmNode.start({
	serverUrl: 'http://localhost:8200',
});

const mongoose = require('mongoose');
const Koa = require('koa');
const app = new Koa();

const ip = 'localhost';
const port = 27017;
const username = 'root';
const password = 'password';
const database = 'database';

async function bootstrap() {
	await mongoose.connect(`mongodb://${ip}:${port}/admin`, {
		auth: {
			username,
			password,
		},
		dbName: database,
	}).catch(e => {
		console.error('Mongo connection error', e);
		// eslint-disable-next-line no-process-exit
		process.exit(1);
	});

	const Cat = mongoose.model('Cat', { name: String });

	// response
	app.use(async ctx => {
		const { pathname } = ctx.request.URL;
		if (pathname === '/create') {
			const kitty = new Cat({ name: 'Zildjian' });
			await kitty.save();
			ctx.body = 'Meow';
		} else if (pathname === '/getAll') {
			ctx.body = await Cat.find();
		}
	});

	app.listen(3000);
	console.log('listening on 3000');
}

bootstrap();
  1. Fill database with some data:
for i in `seq 1 500`; do curl http://localhost:3000/create; done
  1. Run first simple test:
ab -n 10 -c 1 http://localhost:3000/getAll
  1. Run second test with simultaneous requests:
ab -n 50 -c 50 http://localhost:3000/getAll

In kibana you should see normal traces for first test (step 3), but after second test (step 4) you will see
broken traces:

  • some with no mongo spans at all
    Screenshot from 2023-02-16 12-59-14

  • some with too many spans
    Screenshot from 2023-02-16 12-59-00

Expected behavior

Spans should be attached to their parents in test with simultaneous requests.

Environment (please complete the following information)

  • OS: Linux
  • Node.js version: v14.20.1
  • APM Server version: 7.17.2
  • Agent version: 3.42.0

How are you starting the agent? (please tick one of the boxes)

  • Calling agent.start() directly (e.g. require('elastic-apm-node').start(...))
  • Requiring elastic-apm-node/start from within the source code
  • Starting node with -r elastic-apm-node/start

Additional context

Agent config options:

Click to expand Tried with multiple configurations:
serverUrl: 'http://localhost:8200',
serverUrl: 'http://localhost:8200',
contextManager: "patch",
serverUrl: 'http://localhost:8200',
asyncHooks: false,

package.json dependencies:

Click to expand
"elastic-apm-node": "^3.42.0",
"koa": "^2.14.1",
"mongoose": "^6.9.1"
@github-actions github-actions bot added agent-nodejs Make available for APM Agents project planning. community triage labels Feb 16, 2023
@trentm
Copy link
Member

trentm commented Feb 24, 2023

@sefiros1 Thanks for the excellent report. I can repro. I hope to look into this next week.

I'm not a mongoose/mongodb user. Do you happen to know off hand if there is any built in debugging mode for mongoose that could log what it is doing internally? No worries if not.

One possibility is that mongoose is using some internal queue that is grouping up / batching multiple Mongo queries to be run under one asynchronous context. (The "background" section of #2498 describes what I mean.) If so, then I'll have to see if that is something we could instrument reasonably with the APM agent.

@trentm trentm added bug and removed triage labels Feb 24, 2023
@trentm trentm self-assigned this Feb 24, 2023
@trentm trentm added this to the 8.8 milestone Feb 24, 2023
@trentm
Copy link
Member

trentm commented Feb 24, 2023

Note to self: This might be the same issue that I was hitting when attempting to validate that we instrument mongoose >=5.7 correct in this PR: #2547

@sefiros1
Copy link
Contributor Author

@trentm Thanks for reply!

I'm not a mongoose/mongodb user. Do you happen to know off hand if there is any built in debugging mode for mongoose that could log what it is doing internally? No worries if not.

I have never used the mongoose/mongodb debug tools, but this might help:

// all executed methods log output to console
mongoose.set('debug', true)
    
// disable colors in debug mode
mongoose.set('debug', { color: false })

// get mongodb-shell friendly output (ISODate)
mongoose.set('debug', { shell: true })

@trentm trentm modified the milestones: 8.8, 8.9 May 4, 2023
@trentm trentm assigned david-luna and unassigned trentm Jun 6, 2023
@david-luna
Copy link
Member

Using the setup explained in this issue I did perform tests on several versions. Those tests confirm @trentm suspicions about internal optimisations #3161 (comment). MY guess is that commands may be sent in batches

The issue is on the driver level. The mongodb dependency is having same behaviour when running on a barebones http server with the same endpoints. The instrumentation relies on the command events to do the tracing & there is an internal change in 4.x which I assume changes when they're fired.

Code used for testing mongodb

require('elastic-apm-node').start({
  serviceName: 'example-trace-mongodb-concurrent',
  logUncaughtExceptions: true
})

const http = require('http')
const MongoClient = require('mongodb').MongoClient

const DB_NAME = 'example-trace-mongodb-concurrent'
const url = 'mongodb://localhost:27017'

async function bootstrap () {
  const client = new MongoClient(url)
  try {
    await client.connect()

    const database = client.db(DB_NAME)
    const catsCollection = database.collection('cats')

    const server = http.createServer(function onRequest (req, res) {
      console.log('incoming request: %s %s %s', req.method, req.url, req.headers)
      req.resume()
      req.on('end', async function () {
        const pathname = req.url
        let resBody = ''
        if (pathname === '/create') {
          catsCollection.insertOne({ name: 'kitty' })
          resBody = 'Meow'
        } else if (pathname === '/getAll') {
          resBody = JSON.stringify(await catsCollection.find().toArray())
        }
        // Then reply to the incoming request.
        res.writeHead(200, {
          server: 'example-trace-http',
          'content-type': 'text/plain',
          'content-length': Buffer.byteLength(resBody)
        })
        res.end(resBody)
      })
    })

    server.listen(3000, function () {
      console.log('listening on port 3000')
    })
    server.on('close', async function () {
      console.log('closing DB connection')
      await client.close()
    })
  } catch (err) {
    console.log('bootstrap error', err)
  }
}

bootstrap()

@david-luna
Copy link
Member

More tests reveal the change happens between v3 and v4 (when they removed instrumentation API)

with latest v3 we get the following

    req.waterfall:
    trace 37310b
    `- transaction d9a810 "GET unknown route" (16.839ms, GET http://localhost:3000/getAll -> 200)
       `- span d26568 "example-trace-mongodb-concurrent.cats.find" (4ms, mongodb)
    trace bc24e4
    `- transaction c5afe8 "GET unknown route" (48.751ms, GET http://localhost:3000/getAll -> 200)
       `- span f4ab20 "example-trace-mongodb-concurrent.cats.find" (17ms, mongodb)
       `- span dec5dc "example-trace-mongodb-concurrent.$cmd.getMore" (35ms, mongodb)
       `- span e8627e "example-trace-mongodb-concurrent.$cmd.getMore" (25.769ms, mongodb, compressed 3 exact_match spans sum 44ms)
       `- span e8627e "example-trace-mongodb-concurrent.$cmd.getMore" (25.769ms, mongodb, compressed 3 exact_match spans sum 44ms)
       `- span c083a1 "example-trace-mongodb-concurrent.$cmd.getMore" (37ms, mongodb)
       `- span 9667b6 "example-trace-mongodb-concurrent.$cmd.getMore" (27ms, mongodb)
       `- span c041e1 "example-trace-mongodb-concurrent.$cmd.getMore" (32ms, mongodb)
       `- span 6c40b7 "example-trace-mongodb-concurrent.$cmd.getMore" (23ms, mongodb)
       `- span 1c007c "example-trace-mongodb-concurrent.$cmd.getMore" (7ms, mongodb)
       `- span b2b577 "example-trace-mongodb-concurrent.$cmd.getMore" (13ms, mongodb)
       `- span 7416fd "example-trace-mongodb-concurrent.$cmd.getMore" (18ms, mongodb)
       `- span 36422e "example-trace-mongodb-concurrent.$cmd.getMore" (23ms, mongodb)
       `- span 990aea "example-trace-mongodb-concurrent.$cmd.getMore" (23ms, mongodb)
       `- span ce3e76 "example-trace-mongodb-concurrent.$cmd.getMore" (8ms, mongodb)
       `- span ad1c6f "example-trace-mongodb-concurrent.$cmd.getMore" (23ms, mongodb)
       `- span 1c6c2b "example-trace-mongodb-concurrent.$cmd.getMore" (13ms, mongodb)
       `- span 0aafff "example-trace-mongodb-concurrent.$cmd.getMore" (21ms, mongodb)
       `- span 3b5202 "example-trace-mongodb-concurrent.$cmd.getMore" (3ms, mongodb)
       `- span eb2ad8 "example-trace-mongodb-concurrent.$cmd.getMore" (2ms, mongodb)
       `- span 535e03 "example-trace-mongodb-concurrent.$cmd.getMore" (7ms, mongodb)
       `- span 81286a "example-trace-mongodb-concurrent.$cmd.getMore" (15ms, mongodb)
       `- span 4ef63b "example-trace-mongodb-concurrent.$cmd.getMore" (18ms, mongodb)
       `- span b59788 "example-trace-mongodb-concurrent.$cmd.getMore" (21ms, mongodb)
       `- span 47ad06 "example-trace-mongodb-concurrent.$cmd.getMore" (20ms, mongodb)
       `- span 739968 "example-trace-mongodb-concurrent.$cmd.getMore" (5ms, mongodb)
       `- span 82cceb "example-trace-mongodb-concurrent.$cmd.getMore" (16ms, mongodb)
       `- span 9fe067 "example-trace-mongodb-concurrent.$cmd.getMore" (10ms, mongodb)
       `- span 9916ce "example-trace-mongodb-concurrent.$cmd.getMore" (13ms, mongodb)
       `- span cd1587 "example-trace-mongodb-concurrent.$cmd.getMore" (15ms, mongodb)
       `- span 7dfdd8 "example-trace-mongodb-concurrent.$cmd.getMore" (16ms, mongodb)
    trace 01a214
    `- transaction d07fb8 "GET unknown route" (39.976ms, GET http://localhost:3000/getAll -> 200)
       `- span dd4eb0 "example-trace-mongodb-concurrent.cats.find" (15ms, mongodb)
    trace 4e6dca
    `- transaction 4bd28f "GET unknown route" (53.844ms, GET http://localhost:3000/getAll -> 200)
       `- span 56c211 "example-trace-mongodb-concurrent.cats.find" (18ms, mongodb)
    trace a62a18
    `- transaction 3d8329 "GET unknown route" (37.419ms, GET http://localhost:3000/getAll -> 200)
       `- span dd06ea "example-trace-mongodb-concurrent.cats.find" (20ms, mongodb)
    trace 9a9259
    `- transaction 786ab8 "GET unknown route" (42.436ms, GET http://localhost:3000/getAll -> 200)
       `- span daf842 "example-trace-mongodb-concurrent.cats.find" (20ms, mongodb)
    trace 2cd2f3
    `- transaction 076dcf "GET unknown route" (57.219ms, GET http://localhost:3000/getAll -> 200)
       `- span fe2f0e "example-trace-mongodb-concurrent.cats.find" (20ms, mongodb)
    trace cc9ef7
    `- transaction ac5755 "GET unknown route" (56.751ms, GET http://localhost:3000/getAll -> 200)
       `- span 30e07a "example-trace-mongodb-concurrent.cats.find" (24ms, mongodb)
    trace f41f0f
    `- transaction 9e8692 "GET unknown route" (40.266ms, GET http://localhost:3000/getAll -> 200)
       `- span 64db13 "example-trace-mongodb-concurrent.cats.find" (23ms, mongodb)
    trace b5e7b1
    `- transaction 76024f "GET unknown route" (50.03ms, GET http://localhost:3000/getAll -> 200)
       `- span 1285d0 "example-trace-mongodb-concurrent.cats.find" (22ms, mongodb)
    trace 78c00a
    `- transaction c51d50 "GET unknown route" (43.726ms, GET http://localhost:3000/getAll -> 200)
       `- span 3d0999 "example-trace-mongodb-concurrent.cats.find" (21ms, mongodb)
    trace f247fb
    `- transaction 14a701 "GET unknown route" (65.997ms, GET http://localhost:3000/getAll -> 200)
       `- span 12f4cb "example-trace-mongodb-concurrent.cats.find" (41ms, mongodb)
    trace 2d9ff2
    `- transaction 671277 "GET unknown route" (67.362ms, GET http://localhost:3000/getAll -> 200)
       `- span b535ad "example-trace-mongodb-concurrent.cats.find" (46ms, mongodb)
    trace 16138e
    `- transaction eb43b6 "GET unknown route" (60.781ms, GET http://localhost:3000/getAll -> 200)
       `- span 343a55 "example-trace-mongodb-concurrent.cats.find" (28ms, mongodb)
    trace 61be43
    `- transaction a05fd4 "GET unknown route" (60.283ms, GET http://localhost:3000/getAll -> 200)
       `- span e0e1f5 "example-trace-mongodb-concurrent.cats.find" (34ms, mongodb)
    trace 9d675c
    `- transaction 50c1d6 "GET unknown route" (67.578ms, GET http://localhost:3000/getAll -> 200)
       `- span 391931 "example-trace-mongodb-concurrent.cats.find" (51ms, mongodb)
    trace 94d29b
    `- transaction 6cd173 "GET unknown route" (42.678ms, GET http://localhost:3000/getAll -> 200)
       `- span dbc707 "example-trace-mongodb-concurrent.cats.find" (34ms, mongodb)
    trace b22a50
    `- transaction 8fe0dd "GET unknown route" (49.228ms, GET http://localhost:3000/getAll -> 200)
       `- span ac1773 "example-trace-mongodb-concurrent.cats.find" (39ms, mongodb)
    trace 2e00e8
    `- transaction 6956b8 "GET unknown route" (63.412ms, GET http://localhost:3000/getAll -> 200)
       `- span f65e7b "example-trace-mongodb-concurrent.cats.find" (44ms, mongodb)
    trace fe78b4
    `- transaction 6c8a88 "GET unknown route" (41.818ms, GET http://localhost:3000/getAll -> 200)
       `- span 38866c "example-trace-mongodb-concurrent.cats.find" (27ms, mongodb)
    trace 9fd9f5
    `- transaction 5e616f "GET unknown route" (55.151ms, GET http://localhost:3000/getAll -> 200)
       `- span 5a2b27 "example-trace-mongodb-concurrent.cats.find" (49ms, mongodb)
    trace 0751a4
    `- transaction c1b2e7 "GET unknown route" (62.026ms, GET http://localhost:3000/getAll -> 200)
       `- span d292c2 "example-trace-mongodb-concurrent.cats.find" (38ms, mongodb)
    trace 1c13b5
    `- transaction 2c2337 "GET unknown route" (46.217ms, GET http://localhost:3000/getAll -> 200)
       `- span f7ae3c "example-trace-mongodb-concurrent.cats.find" (26ms, mongodb)
    trace cb25ca
    `- transaction 1c509d "GET unknown route" (46.806ms, GET http://localhost:3000/getAll -> 200)
       `- span 3b7f9b "example-trace-mongodb-concurrent.cats.find" (32ms, mongodb)
    trace bfb23c
    `- transaction 6824c8 "GET unknown route" (53.58ms, GET http://localhost:3000/getAll -> 200)
       `- span c64db5 "example-trace-mongodb-concurrent.cats.find" (43ms, mongodb)
    trace 4f69c6
    `- transaction 3b233d "GET unknown route" (59.412ms, GET http://localhost:3000/getAll -> 200)
       `- span b90598 "example-trace-mongodb-concurrent.cats.find" (48ms, mongodb)
    trace 03fcf3
    `- transaction 0e6857 "GET unknown route" (33.894ms, GET http://localhost:3000/getAll -> 200)
       `- span f8d8cc "example-trace-mongodb-concurrent.cats.find" (25ms, mongodb)
    trace 616ff3
    `- transaction 8c6dad "GET unknown route" (34.462ms, GET http://localhost:3000/getAll -> 200)
       `- span 135859 "example-trace-mongodb-concurrent.cats.find" (31ms, mongodb)
    trace 947515
    `- transaction 3a618a "GET unknown route" (52.479ms, GET http://localhost:3000/getAll -> 200)
       `- span ee1b0e "example-trace-mongodb-concurrent.cats.find" (37ms, mongodb)
    trace ed9df0
    `- transaction 73ee20 "GET unknown route" (58.647ms, GET http://localhost:3000/getAll -> 200)
       `- span 449298 "example-trace-mongodb-concurrent.cats.find" (42ms, mongodb)
    trace b7c9f9
    `- transaction b46118 "GET unknown route" (62.512ms, GET http://localhost:3000/getAll -> 200)
       `- span 13fe70 "example-trace-mongodb-concurrent.cats.find" (47ms, mongodb)
    trace c8ad6e
    `- transaction ba7f5e "GET unknown route" (50.785ms, GET http://localhost:3000/getAll -> 200)
       `- span 15b6b7 "example-trace-mongodb-concurrent.cats.find" (30ms, mongodb)
    trace 1ed7cf
    `- transaction d1e60a "GET unknown route" (57.687ms, GET http://localhost:3000/getAll -> 200)
       `- span 1c740c "example-trace-mongodb-concurrent.cats.find" (35ms, mongodb)
    trace 66bab4
    `- transaction 7d38b6 "GET unknown route" (61.732ms, GET http://localhost:3000/getAll -> 200)
       `- span 30c258 "example-trace-mongodb-concurrent.cats.find" (41ms, mongodb)
    trace 7a3600
    `- transaction c5d78b "GET unknown route" (62.478ms, GET http://localhost:3000/getAll -> 200)
       `- span 6d919f "example-trace-mongodb-concurrent.cats.find" (46ms, mongodb)
    trace 3e0a44
    `- transaction 6fb91b "GET unknown route" (38.521ms, GET http://localhost:3000/getAll -> 200)
       `- span f581ae "example-trace-mongodb-concurrent.cats.find" (34ms, mongodb)
    trace f73a56
    `- transaction 262a3b "GET unknown route" (44.104ms, GET http://localhost:3000/getAll -> 200)
       `- span b728f3 "example-trace-mongodb-concurrent.cats.find" (40ms, mongodb)
    trace 00c7bc
    `- transaction 5e3ecc "GET unknown route" (50.358ms, GET http://localhost:3000/getAll -> 200)
       `- span 39565e "example-trace-mongodb-concurrent.cats.find" (24ms, mongodb)
    trace cf1804
    `- transaction 13abd0 "GET unknown route" (54.816ms, GET http://localhost:3000/getAll -> 200)
       `- span 83e560 "example-trace-mongodb-concurrent.cats.find" (29ms, mongodb)
    trace 226952
    `- transaction ea9a77 "GET unknown route" (58.856ms, GET http://localhost:3000/getAll -> 200)
       `- span 334ec4 "example-trace-mongodb-concurrent.cats.find" (45ms, mongodb)

We can see the find command is executed in the same context. Other commands like getMore get spans in the wrong context probably because they are queued & exec in an async way.

Version v4.0.0 seems to use the queue also for the find command (and probably other commands which map directly to the API). We can see some transactions without a find span related to it.

    req.waterfall:
    trace e0c801
    `- transaction 4d9c5a "GET unknown route" (24.605ms, GET http://localhost:3000/getAll -> 200)
       `- span c94c83 "example-trace-mongodb-concurrent.cats.find" (4ms, mongodb, sync)
       `- span 280b7e "example-trace-mongodb-concurrent.$cmd.getMore" (4ms, mongodb)
       `- span 280b7e "example-trace-mongodb-concurrent.$cmd.getMore" (4ms, mongodb)
       `- span 865114 "example-trace-mongodb-concurrent.cats.find" (12ms, mongodb)
       `- span fbeebe "example-trace-mongodb-concurrent.cats.find" (4ms, mongodb, sync)
       `- span 30de91 "example-trace-mongodb-concurrent.cats.find" (6ms, mongodb)
       `- span 365004 "example-trace-mongodb-concurrent.cats.find" (14ms, mongodb)
       `- span 3b2ce8 "example-trace-mongodb-concurrent.cats.find" (13ms, mongodb)
       `- span c590ac "example-trace-mongodb-concurrent.$cmd.getMore" (13ms, mongodb)
       `- span a64638 "example-trace-mongodb-concurrent.$cmd.getMore" (15ms, mongodb)
    trace 36fd41
    `- transaction 69cdb4 "GET unknown route" (75.658ms, GET http://localhost:3000/getAll -> 200)
       `- span a1024b "example-trace-mongodb-concurrent.cats.find" (19ms, mongodb)
    trace f5998d
    `- transaction f1f5a3 "GET unknown route" (75.528ms, GET http://localhost:3000/getAll -> 200)
       `- span 04397f "example-trace-mongodb-concurrent.cats.find" (17.21ms, mongodb, sync, compressed 2 exact_match spans sum 17ms)
       `- span 539a2a "example-trace-mongodb-concurrent.$cmd.getMore" (9ms, mongodb)
    trace 0fdf1e
    `- transaction b7512e "GET unknown route" (83.458ms, GET http://localhost:3000/getAll -> 200)
       `- span 7a5bd7 "example-trace-mongodb-concurrent.cats.find" (20.524ms, mongodb, sync, compressed 2 exact_match spans sum 21ms)
       `- span 620851 "example-trace-mongodb-concurrent.$cmd.getMore" (17ms, mongodb)
    trace 17058c
    `- transaction ef0a34 "GET unknown route" (85.016ms, GET http://localhost:3000/getAll -> 200)
       `- span 59d78a "example-trace-mongodb-concurrent.cats.find" (12ms, mongodb, sync)
       `- span 038cc0 "example-trace-mongodb-concurrent.$cmd.getMore" (45ms, mongodb)
    trace ec0a94
    `- transaction 91538e "GET unknown route" (78.305ms, GET http://localhost:3000/getAll -> 200)
       `- span fe73b5 "example-trace-mongodb-concurrent.cats.find" (21.109ms, mongodb, sync, compressed 2 exact_match spans sum 21ms)
       `- span 35fd86 "example-trace-mongodb-concurrent.$cmd.getMore" (18ms, mongodb)
    trace 5b7f75
    `- transaction 88a7e1 "GET unknown route" (73.65ms, GET http://localhost:3000/getAll -> 200)
       `- span 3120e2 "example-trace-mongodb-concurrent.cats.find" (9ms, mongodb, sync)
       `- span 3120e2 "example-trace-mongodb-concurrent.cats.find" (9ms, mongodb, sync)
       `- span c75431 "example-trace-mongodb-concurrent.$cmd.getMore" (39ms, mongodb)
    trace b84ce7
    `- transaction 3a9a95 "GET unknown route" (69.765ms, GET http://localhost:3000/getAll -> 200)
       `- span d088b4 "example-trace-mongodb-concurrent.$cmd.getMore" (36ms, mongodb, sync)
    trace dce95d
    `- transaction 8a183a "GET unknown route" (73.797ms, GET http://localhost:3000/getAll -> 200)
       `- span 57f294 "example-trace-mongodb-concurrent.cats.find" (12ms, mongodb, sync)
       `- span 7994c9 "example-trace-mongodb-concurrent.$cmd.getMore" (16ms, mongodb)
    trace 51ecf7
    `- transaction b00624 "GET unknown route" (47.883ms, GET http://localhost:3000/getAll -> 200)
       `- span 444faa "example-trace-mongodb-concurrent.cats.find" (18.939ms, mongodb, sync, compressed 2 exact_match spans sum 18ms)
       `- span 444faa "example-trace-mongodb-concurrent.cats.find" (18.939ms, mongodb, sync, compressed 2 exact_match spans sum 18ms)
       `- span b24f10 "example-trace-mongodb-concurrent.$cmd.getMore" (15ms, mongodb)
    trace 49822c
    `- transaction f57537 "GET unknown route" (69.738ms, GET http://localhost:3000/getAll -> 200)
       `- span bb2456 "example-trace-mongodb-concurrent.cats.find" (12ms, mongodb, sync)
       `- span 61b379 "example-trace-mongodb-concurrent.$cmd.getMore" (13ms, mongodb)
    trace 104ec7
    `- transaction 5d8992 "GET unknown route" (72.657ms, GET http://localhost:3000/getAll -> 200)
       `- span 5cdf50 "example-trace-mongodb-concurrent.cats.find" (35ms, mongodb, sync)
       `- span 5cdf50 "example-trace-mongodb-concurrent.cats.find" (35ms, mongodb, sync)
       `- span edeba4 "example-trace-mongodb-concurrent.$cmd.getMore" (20ms, mongodb)
    trace b8a513
    `- transaction 10314b "GET unknown route" (70.656ms, GET http://localhost:3000/getAll -> 200)
       `- span f5ffde "example-trace-mongodb-concurrent.$cmd.getMore" (38ms, mongodb, sync)
    trace 46e04d
    `- transaction 02c7ad "GET unknown route" (72.641ms, GET http://localhost:3000/getAll -> 200)
       `- span c1b3ee "example-trace-mongodb-concurrent.$cmd.getMore" (38ms, mongodb, sync)
    trace d0012a
    `- transaction c012b9 "GET unknown route" (73.996ms, GET http://localhost:3000/getAll -> 200)
       `- span 222767 "example-trace-mongodb-concurrent.cats.find" (11ms, mongodb, sync)
       `- span 50a42c "example-trace-mongodb-concurrent.$cmd.getMore" (37ms, mongodb)
    trace 5fdafc
    `- transaction bf947d "GET unknown route" (74.375ms, GET http://localhost:3000/getAll -> 200)
       `- span f21f2f "example-trace-mongodb-concurrent.cats.find" (13ms, mongodb, sync)
       `- span e5a093 "example-trace-mongodb-concurrent.$cmd.getMore" (20ms, mongodb)
    trace 75bfd8
    `- transaction 3a879a "GET unknown route" (75.911ms, GET http://localhost:3000/getAll -> 200)
       `- span c6c639 "example-trace-mongodb-concurrent.$cmd.getMore" (37ms, mongodb, sync)
    trace e48bec
    `- transaction 984b07 "GET unknown route" (75.234ms, GET http://localhost:3000/getAll -> 200)
       `- span 127046 "example-trace-mongodb-concurrent.cats.find" (12ms, mongodb, sync)
       `- span 600e8c "example-trace-mongodb-concurrent.$cmd.getMore" (19ms, mongodb)
    trace 955691
    `- transaction 36de90 "GET unknown route" (77.999ms, GET http://localhost:3000/getAll -> 200)
    trace cdee44
    `- transaction bc0457 "GET unknown route" (76.07ms, GET http://localhost:3000/getAll -> 200)
       `- span e7d75d "example-trace-mongodb-concurrent.$cmd.getMore" (12ms, mongodb, sync)
    trace 7dd31e
    `- transaction 37e45e "GET unknown route" (79.459ms, GET http://localhost:3000/getAll -> 200)
       `- span 9e6e96 "example-trace-mongodb-concurrent.$cmd.getMore" (45ms, mongodb, sync)
    trace 07e6e6
    `- transaction b2edfd "GET unknown route" (45.315ms, GET http://localhost:3000/getAll -> 200)
       `- span 01319c "example-trace-mongodb-concurrent.cats.find" (10ms, mongodb, sync)
       `- span 01319c "example-trace-mongodb-concurrent.cats.find" (10ms, mongodb, sync)
       `- span c694f8 "example-trace-mongodb-concurrent.$cmd.getMore" (36ms, mongodb)
    trace e4418f
    `- transaction 61598a "GET unknown route" (51.116ms, GET http://localhost:3000/getAll -> 200)
       `- span a13a77 "example-trace-mongodb-concurrent.cats.find" (10ms, mongodb, sync)
       `- span a13a77 "example-trace-mongodb-concurrent.cats.find" (10ms, mongodb, sync)
       `- span 57677e "example-trace-mongodb-concurrent.$cmd.getMore" (34ms, mongodb)
    trace 884669
    `- transaction 40d406 "GET unknown route" (57.269ms, GET http://localhost:3000/getAll -> 200)
       `- span ee856b "example-trace-mongodb-concurrent.cats.find" (8ms, mongodb, sync)
       `- span 45b26d "example-trace-mongodb-concurrent.$cmd.getMore" (8ms, mongodb)
    trace b41ca2
    `- transaction ea8b53 "GET unknown route" (45.163ms, GET http://localhost:3000/getAll -> 200)
       `- span afa0bd "example-trace-mongodb-concurrent.$cmd.getMore" (34ms, mongodb, sync)
    trace fa6d54
    `- transaction a77fdb "GET unknown route" (53ms, GET http://localhost:3000/getAll -> 200)
       `- span 6e67b0 "example-trace-mongodb-concurrent.cats.find" (13ms, mongodb, sync)
       `- span 6e67b0 "example-trace-mongodb-concurrent.cats.find" (13ms, mongodb, sync)
       `- span e3a895 "example-trace-mongodb-concurrent.$cmd.getMore" (43ms, mongodb)
    trace 88ebb7
    `- transaction f79861 "GET unknown route" (53.666ms, GET http://localhost:3000/getAll -> 200)
       `- span dd508f "example-trace-mongodb-concurrent.cats.find" (7ms, mongodb, sync)
       `- span dd508f "example-trace-mongodb-concurrent.cats.find" (7ms, mongodb, sync)
       `- span fdf1b8 "example-trace-mongodb-concurrent.$cmd.getMore" (44ms, mongodb)
    trace 22095d
    `- transaction 6102ae "GET unknown route" (56.195ms, GET http://localhost:3000/getAll -> 200)
       `- span 58a8e3 "example-trace-mongodb-concurrent.cats.find" (9ms, mongodb, sync)
       `- span e7fb61 "example-trace-mongodb-concurrent.$cmd.getMore" (12ms, mongodb)
    trace 1ead66
    `- transaction 05e329 "GET unknown route" (41.412ms, GET http://localhost:3000/getAll -> 200)
       `- span 684bf7 "example-trace-mongodb-concurrent.cats.find" (11ms, mongodb, sync)
       `- span 684bf7 "example-trace-mongodb-concurrent.cats.find" (11ms, mongodb, sync)
       `- span 2fe456 "example-trace-mongodb-concurrent.$cmd.getMore" (42ms, mongodb)
    trace 4e8af6
    `- transaction ba4c70 "GET unknown route" (47.976ms, GET http://localhost:3000/getAll -> 200)
       `- span 6b9304 "example-trace-mongodb-concurrent.$cmd.getMore" (40ms, mongodb, sync)
    trace bf9e8d
    `- transaction ce3556 "GET unknown route" (50.301ms, GET http://localhost:3000/getAll -> 200)
       `- span 1da563 "example-trace-mongodb-concurrent.cats.find" (15.674ms, mongodb, sync, compressed 2 exact_match spans sum 15ms)
       `- span 29d2ac "example-trace-mongodb-concurrent.$cmd.getMore" (11ms, mongodb)
    trace c5a749
    `- transaction 66f8ad "GET unknown route" (57.706ms, GET http://localhost:3000/getAll -> 200)
       `- span 4ffc33 "example-trace-mongodb-concurrent.$cmd.getMore" (35ms, mongodb, sync)
    trace 8ae54c
    `- transaction 003fcf "GET unknown route" (81.908ms, GET http://localhost:3000/getAll -> 200)
       `- span 79f951 "example-trace-mongodb-concurrent.cats.find" (10ms, mongodb, sync)
       `- span 7a2fd4 "example-trace-mongodb-concurrent.$cmd.getMore" (40ms, mongodb)
    trace 3c280b
    `- transaction c4de85 "GET unknown route" (57.327ms, GET http://localhost:3000/getAll -> 200)
       `- span dbd400 "example-trace-mongodb-concurrent.cats.find" (11ms, mongodb, sync)
       `- span 4feba3 "example-trace-mongodb-concurrent.$cmd.getMore" (14ms, mongodb)
    trace c91b7e
    `- transaction 6366e7 "GET unknown route" (52.975ms, GET http://localhost:3000/getAll -> 200)
       `- span 1cad87 "example-trace-mongodb-concurrent.cats.find" (9ms, mongodb, sync)
       `- span 3ee35b "example-trace-mongodb-concurrent.$cmd.getMore" (11ms, mongodb)
    trace 87a68c
    `- transaction 704a86 "GET unknown route" (43.444ms, GET http://localhost:3000/getAll -> 200)
       `- span 0b413d "example-trace-mongodb-concurrent.cats.find" (11ms, mongodb, sync)
       `- span 0b413d "example-trace-mongodb-concurrent.cats.find" (11ms, mongodb, sync)
       `- span 6e3d85 "example-trace-mongodb-concurrent.$cmd.getMore" (12ms, mongodb)
    trace 5df0d0
    `- transaction e6b874 "GET unknown route" (44.665ms, GET http://localhost:3000/getAll -> 200)
       `- span 8351b5 "example-trace-mongodb-concurrent.cats.find" (11ms, mongodb, sync)
       `- span 8351b5 "example-trace-mongodb-concurrent.cats.find" (11ms, mongodb, sync)
       `- span f88f77 "example-trace-mongodb-concurrent.$cmd.getMore" (40ms, mongodb)
    trace 55980a
    `- transaction 8d9da7 "GET unknown route" (49.354ms, GET http://localhost:3000/getAll -> 200)
       `- span 671e0f "example-trace-mongodb-concurrent.cats.find" (12ms, mongodb, sync)
       `- span 671e0f "example-trace-mongodb-concurrent.cats.find" (12ms, mongodb, sync)
       `- span 4ac6bb "example-trace-mongodb-concurrent.$cmd.getMore" (42ms, mongodb)
    trace 25bb5a
    `- transaction d60631 "GET unknown route" (54.181ms, GET http://localhost:3000/getAll -> 200)
       `- span 9f68f0 "example-trace-mongodb-concurrent.cats.find" (14ms, mongodb, sync)
       `- span 9f68f0 "example-trace-mongodb-concurrent.cats.find" (14ms, mongodb, sync)
       `- span 4b2a15 "example-trace-mongodb-concurrent.$cmd.getMore" (18ms, mongodb)
    trace eb9ab7
    `- transaction 693dbc "GET unknown route" (76.031ms, GET http://localhost:3000/getAll -> 200)
       `- span 4730ff "example-trace-mongodb-concurrent.cats.find" (11ms, mongodb, sync)
       `- span e08418 "example-trace-mongodb-concurrent.$cmd.getMore" (41ms, mongodb)

@david-luna
Copy link
Member

The async behaviour has been there for a while since the ConnectionPool Class is using process.nextTick to execute all operations once the connection is available to use.

Not sure if there is a way to make the connection available in a sync way through configuration but even if we achieve it I believe this will not cover all use cases for mongodb. We may have to check if possible to instrument the server layer of the client (probably more sensible to internal changes in the driver)

@david-luna
Copy link
Member

The previous comment was not complete. Cursors are also involved since they make use of async iterators for their operations. This methods are internal and there is not an easy way to ensure we got the right context when they execute. Elastic APM is not the only affected. I've used OpenTelemetry to check by creating this tracer

// File: otel-manual-instrumentation.js
// OpenTelemetry
const { Resource } = require('@opentelemetry/resources')
const { SemanticResourceAttributes } = require('@opentelemetry/semantic-conventions')
const { ConsoleSpanExporter } = require('@opentelemetry/sdk-trace-base')
const { SimpleSpanProcessor } = require('@opentelemetry/sdk-trace-base')
const { NodeTracerProvider } = require('@opentelemetry/sdk-trace-node')
const { trace } = require('@opentelemetry/api')
// instrumentations
const { MongoDBInstrumentation } = require('@opentelemetry/instrumentation-mongodb')
const { HttpInstrumentation } = require('@opentelemetry/instrumentation-http')
const { registerInstrumentations } = require('@opentelemetry/instrumentation')

// Exporter
module.exports = (serviceName) => {
  const exporter = new ConsoleSpanExporter()
  const provider = new NodeTracerProvider({
    resource: new Resource({
      [SemanticResourceAttributes.SERVICE_NAME]: serviceName
    })
  })
  provider.addSpanProcessor(new SimpleSpanProcessor(exporter))
  provider.register()
  registerInstrumentations({
    instrumentations: [
      new HttpInstrumentation(),
      new MongoDBInstrumentation({
        enhancedDatabaseReporting: true
      })
    ],
    tracerProvider: provider
  })
  return trace.getTracer(serviceName)
}

and replacing our instrumentation in the code above for

const tracer = require('./otel-manual-instrumentation')('example-trace-mongodb-http')

Sadly the results are similar to Elastic APM, we got some HTTP spans with no MongoDB child spans and others have several. This is the output from OTel

trace ab23c4787b2c746a543154507d
`- GET http://localhost:3000/getAll
   `- mongodb.find {"find":"cats","filter":{}}
   `- mongodb.getMore {"getMore":{"low":298897890,"high":950976215,"unsigned":false},"collection":"cats","batchSize":1000}
trace 8c19304c15e7f8bbbb291e31af
`- GET http://localhost:3000/getAll
   `- mongodb.find {"find":"cats","filter":{}}
   `- mongodb.find {"find":"cats","filter":{}}
   `- mongodb.find {"find":"cats","filter":{}}
   `- mongodb.find {"find":"cats","filter":{}}
   `- mongodb.find {"find":"cats","filter":{}}
   `- mongodb.find {"find":"cats","filter":{}}
   `- mongodb.find {"find":"cats","filter":{}}
   `- mongodb.find {"find":"cats","filter":{}}
   `- mongodb.find {"find":"cats","filter":{}}
   `- mongodb.find {"find":"cats","filter":{}}
   `- mongodb.getMore {"getMore":{"low":-113975727,"high":1274270182,"unsigned":false},"collection":"cats","batchSize":1000}
   `- mongodb.getMore {"getMore":{"low":2084331457,"high":1028891598,"unsigned":false},"collection":"cats","batchSize":1000}
   `- mongodb.getMore {"getMore":{"low":1378369893,"high":2031910884,"unsigned":false},"collection":"cats","batchSize":1000}
   `- mongodb.getMore {"getMore":{"low":1257407227,"high":818624404,"unsigned":false},"collection":"cats","batchSize":1000}
   `- mongodb.getMore {"getMore":{"low":810916200,"high":1671639240,"unsigned":false},"collection":"cats","batchSize":1000}
trace a0a100aaf67bdef72e756f395f
`- GET http://localhost:3000/getAll
trace f942a547801b480af51f4af88d
`- GET http://localhost:3000/getAll
trace 525bcaa5fa6787ec96ca47fbec
`- GET http://localhost:3000/getAll
   `- mongodb.find {"find":"cats","filter":{}}
   `- mongodb.find {"find":"cats","filter":{}}
   `- mongodb.find {"find":"cats","filter":{}}
   `- mongodb.find {"find":"cats","filter":{}}
   `- mongodb.find {"find":"cats","filter":{}}
   `- mongodb.find {"find":"cats","filter":{}}
   `- mongodb.find {"find":"cats","filter":{}}
   `- mongodb.find {"find":"cats","filter":{}}
   `- mongodb.getMore {"getMore":{"low":300323420,"high":127031576,"unsigned":false},"collection":"cats","batchSize":1000}
   `- mongodb.find {"find":"cats","filter":{}}
   `- mongodb.find {"find":"cats","filter":{}}
   `- mongodb.find {"find":"cats","filter":{}}
   `- mongodb.find {"find":"cats","filter":{}}
   `- mongodb.find {"find":"cats","filter":{}}
   `- mongodb.getMore {"getMore":{"low":-2074455098,"high":554401294,"unsigned":false},"collection":"cats","batchSize":1000}
   `- mongodb.getMore {"getMore":{"low":-67109169,"high":762137799,"unsigned":false},"collection":"cats","batchSize":1000}
   `- mongodb.getMore {"getMore":{"low":-989148754,"high":1090994491,"unsigned":false},"collection":"cats","batchSize":1000}
   `- mongodb.getMore {"getMore":{"low":1482972967,"high":1269868453,"unsigned":false},"collection":"cats","batchSize":1000}
   `- mongodb.getMore {"getMore":{"low":2013767455,"high":1717252540,"unsigned":false},"collection":"cats","batchSize":1000}
   `- mongodb.getMore {"getMore":{"low":969496423,"high":1797024114,"unsigned":false},"collection":"cats","batchSize":1000}
   `- mongodb.getMore {"getMore":{"low":-1803188800,"high":1049603875,"unsigned":false},"collection":"cats","batchSize":1000}
   `- mongodb.getMore {"getMore":{"low":1812370198,"high":270657678,"unsigned":false},"collection":"cats","batchSize":1000}
   `- mongodb.getMore {"getMore":{"low":1391838669,"high":1872051109,"unsigned":false},"collection":"cats","batchSize":1000}
   `- mongodb.getMore {"getMore":{"low":-229563661,"high":1193636256,"unsigned":false},"collection":"cats","batchSize":1000}
   `- mongodb.find {"find":"cats","filter":{}}
   `- mongodb.getMore {"getMore":{"low":2002568280,"high":1854177659,"unsigned":false},"collection":"cats","batchSize":1000}
   `- mongodb.getMore {"getMore":{"low":291000252,"high":12010881,"unsigned":false},"collection":"cats","batchSize":1000}
   `- mongodb.getMore {"getMore":{"low":-271658501,"high":351481635,"unsigned":false},"collection":"cats","batchSize":1000}
   `- mongodb.getMore {"getMore":{"low":1429551921,"high":1228367270,"unsigned":false},"collection":"cats","batchSize":1000}
   `- mongodb.getMore {"getMore":{"low":1010522064,"high":1076563895,"unsigned":false},"collection":"cats","batchSize":1000}
   `- mongodb.getMore {"getMore":{"low":96367583,"high":756720472,"unsigned":false},"collection":"cats","batchSize":1000}
   `- mongodb.getMore {"getMore":{"low":-2043313488,"high":1129313640,"unsigned":false},"collection":"cats","batchSize":1000}
trace 2127c8391dd9cd20b19493bcd5
`- GET http://localhost:3000/getAll
   `- mongodb.find {"find":"cats","filter":{}}
   `- mongodb.find {"find":"cats","filter":{}}
   `- mongodb.find {"find":"cats","filter":{}}
   `- mongodb.find {"find":"cats","filter":{}}
   `- mongodb.find {"find":"cats","filter":{}}
   `- mongodb.find {"find":"cats","filter":{}}
   `- mongodb.find {"find":"cats","filter":{}}
   `- mongodb.find {"find":"cats","filter":{}}
   `- mongodb.find {"find":"cats","filter":{}}
   `- mongodb.find {"find":"cats","filter":{}}
   `- mongodb.find {"find":"cats","filter":{}}
   `- mongodb.find {"find":"cats","filter":{}}
   `- mongodb.find {"find":"cats","filter":{}}
   `- mongodb.getMore {"getMore":{"low":1270567681,"high":1551095473,"unsigned":false},"collection":"cats","batchSize":1000}
   `- mongodb.find {"find":"cats","filter":{}}
   `- mongodb.getMore {"getMore":{"low":1466741546,"high":1189010522,"unsigned":false},"collection":"cats","batchSize":1000}
   `- mongodb.getMore {"getMore":{"low":-809841143,"high":270750708,"unsigned":false},"collection":"cats","batchSize":1000}
   `- mongodb.getMore {"getMore":{"low":-5917614,"high":88235706,"unsigned":false},"collection":"cats","batchSize":1000}
   `- mongodb.getMore {"getMore":{"low":47702364,"high":1240051794,"unsigned":false},"collection":"cats","batchSize":1000}
   `- mongodb.getMore {"getMore":{"low":-880720416,"high":1381113044,"unsigned":false},"collection":"cats","batchSize":1000}
   `- mongodb.getMore {"getMore":{"low":701516285,"high":297830911,"unsigned":false},"collection":"cats","batchSize":1000}
   `- mongodb.getMore {"getMore":{"low":-1612777661,"high":267238589,"unsigned":false},"collection":"cats","batchSize":1000}
   `- mongodb.getMore {"getMore":{"low":-2025316836,"high":1866762153,"unsigned":false},"collection":"cats","batchSize":1000}
   `- mongodb.find {"find":"cats","filter":{}}
   `- mongodb.getMore {"getMore":{"low":-1793848668,"high":1305652784,"unsigned":false},"collection":"cats","batchSize":1000}
   `- mongodb.getMore {"getMore":{"low":654116132,"high":2026288532,"unsigned":false},"collection":"cats","batchSize":1000}
   `- mongodb.getMore {"getMore":{"low":486328311,"high":1535351397,"unsigned":false},"collection":"cats","batchSize":1000}
   `- mongodb.getMore {"getMore":{"low":870856291,"high":2113070875,"unsigned":false},"collection":"cats","batchSize":1000}
   `- mongodb.getMore {"getMore":{"low":-1304213004,"high":1080703820,"unsigned":false},"collection":"cats","batchSize":1000}
   `- mongodb.getMore {"getMore":{"low":2064853800,"high":493914734,"unsigned":false},"collection":"cats","batchSize":1000}
   `- mongodb.getMore {"getMore":{"low":-56169879,"high":262661781,"unsigned":false},"collection":"cats","batchSize":1000}
trace 86a4e3ea4a6b9e8b4a3c194fe6
`- GET http://localhost:3000/getAll
trace 3c19d6b28e7586ffc80db2bcc3
`- GET http://localhost:3000/getAll
trace 1107b93b5ad05f9d1a8b3a40b9
`- GET http://localhost:3000/getAll
trace 0149313d3a22497470d3c45571
`- GET http://localhost:3000/getAll
trace a5f234dcef85d5405aa3fa7fa8
`- GET http://localhost:3000/getAll
trace f859895df951a86abef3706df6
`- GET http://localhost:3000/getAll
trace 32adb205a3b835c84f1746ea05
`- GET http://localhost:3000/getAll
trace 1dd05064c481fcee9912876286
`- GET http://localhost:3000/getAll
trace 8f75727fad516762ef9e092f74
`- GET http://localhost:3000/getAll
trace 19a7f2efde7f52a1db395ae3c3
`- GET http://localhost:3000/getAll
trace 0846c398cfe317cc78a0f12e0a
`- GET http://localhost:3000/getAll
trace 6a62a778b786c42cbdac9a7691
`- GET http://localhost:3000/getAll
trace c7abbe25d3f5e7d0925d507606
`- GET http://localhost:3000/getAll
trace fa4907ed874a36e8f2db544fb0
`- GET http://localhost:3000/getAll
trace 3734407bc8fa6de6e5d8bbd62d
`- GET http://localhost:3000/getAll
trace ea710695acb8a9b3e7146a3dbb
`- GET http://localhost:3000/getAll
trace ada5e6a80f3471902885da4428
`- GET http://localhost:3000/getAll
trace 639c41f211423f26d8cad51229
`- GET http://localhost:3000/getAll
trace bf3b189b794a941ee1e79bf72c
`- GET http://localhost:3000/getAll
trace d2110992e06207e429b0b60387
`- GET http://localhost:3000/getAll
trace db0e3bf8e357b85120b906a9c1
`- GET http://localhost:3000/getAll
trace 046b682fb52e5ac87c81509d88
`- GET http://localhost:3000/getAll
trace 00d27c885781bbe57d2dd882fc
`- GET http://localhost:3000/getAll
trace 28f5cdb0ca665c1f8cb1502445
`- GET http://localhost:3000/getAll
trace 71e048545163b8a387c5e7868c
`- GET http://localhost:3000/getAll
trace cb15258d935b21f388559bb437
`- GET http://localhost:3000/getAll
trace 750622f6b6fd076bcac77f4878
`- GET http://localhost:3000/getAll
trace de81011c67d73954b7bfe2ebd3
`- GET http://localhost:3000/getAll
trace a6f4e65c38bf848386c0498916
`- GET http://localhost:3000/getAll
trace 1a55f4126f1682c3da010ea084
`- GET http://localhost:3000/getAll
trace afe8edebae8a8eacdad5fd036f
`- GET http://localhost:3000/getAll
trace a8aba97c6b613318de09f86786
`- GET http://localhost:3000/getAll
trace 0f8d07040f4200e241034f4798
`- GET http://localhost:3000/getAll
trace 180dbc4abdef5c5b2debd48412
`- GET http://localhost:3000/getAll

Elastic APM is relying on MongoClient events API to do instrumentation but it has the same issue, the event is fired in a different context. In conclusion we need to change the instrumentation but without going too deep in internal implementations details since they may change in the near future.

@estolfo estolfo modified the milestones: 8.9, 8.11 Aug 21, 2023
@david-luna
Copy link
Member

Another test reveals the tracking works if the client is not shared across requests. Making a change to the original test code (moving client creation inside the request handler) produces the desired output.

the code

require('../').start({
  serviceName: 'example-trace-mongodb-concurrent',
  logUncaughtExceptions: true,
});

const http = require('http');
const MongoClient = require('mongodb').MongoClient;

const DB_NAME = 'example-trace-mongodb-concurrent';
const url = 'mongodb://localhost:27017';

async function bootstrap() {
  try {
    const server = http.createServer(async function onRequest(req, res) {
      // NOTE: a client is created on each request
      const client = await MongoClient.connect(url);
      const database = client.db(DB_NAME);
      const catsCollection = database.collection('cats');

      req.resume();
      req.on('end', async function () {
        const pathname = req.url;
        let resBody = '';
        if (pathname === '/create') {
          catsCollection.insertOne({ name: 'kitty' });
          resBody = 'Meow';
        } else if (pathname === '/getAll') {
          resBody = JSON.stringify(
            await catsCollection.find({ name: 'kitty' }).toArray(),
          );
        }
        // Then reply to the incoming request.
        res.writeHead(200, {
          server: 'example-trace-http',
          'content-type': 'text/plain',
          'content-length': Buffer.byteLength(resBody),
        });
        await client.close();
        res.end(resBody);
      });
    });

    server.listen(3000, function () {
      console.log('linstening on port 3000');
    });
    server.on('close', async function () {
      console.log('closing DB conneciton');
    });
  } catch (err) {
    console.log('bootstrap error', err);
  }
}

bootstrap();

When sending 30 concurrent requests

ab -n 30 -c 30 http://localhost:3000/getAll

Gives the following traces

--
req.waterfall:
trace b1abab
`- transaction 01dfa2 "GET unknown route" (31.322ms, GET http://localhost:3000/getAll -> 200)
   `- span 5db535 "example-trace-mongodb-concurrent.cats.find" (3ms, mongodb, sync)
   `- span 2b0c09 "example-trace-mongodb-concurrent.$cmd.getMore" (3ms, mongodb)
   `- span fba2b8 "admin.$cmd.endSessions" (0ms, mongodb, sync)
trace 04dda2
`- transaction 5bd108 "GET unknown route" (77.515ms, GET http://localhost:3000/getAll -> 200)
   `- span fed247 "example-trace-mongodb-concurrent.cats.find" (3ms, mongodb, sync)
   `- span 05eb67 "example-trace-mongodb-concurrent.$cmd.getMore" (8ms, mongodb)
   `- span fdfbf5 "admin.$cmd.endSessions" (0ms, mongodb, sync)
trace eaf83b
`- transaction 9e4115 "GET unknown route" (76.304ms, GET http://localhost:3000/getAll -> 200)
   `- span 9fc28e "example-trace-mongodb-concurrent.cats.find" (4ms, mongodb, sync)
   `- span 4b8ef2 "example-trace-mongodb-concurrent.$cmd.getMore" (10ms, mongodb)
   `- span 79ac2c "admin.$cmd.endSessions" (0ms, mongodb, sync)
trace c10b31
`- transaction 7e29a2 "GET unknown route" (75.906ms, GET http://localhost:3000/getAll -> 200)
   `- span 19671a "example-trace-mongodb-concurrent.cats.find" (4ms, mongodb, sync)
   `- span f7de5a "example-trace-mongodb-concurrent.$cmd.getMore" (11ms, mongodb)
   `- span 2bef1b "admin.$cmd.endSessions" (0ms, mongodb, sync)
trace 2fd8fd
`- transaction 398045 "GET unknown route" (75.379ms, GET http://localhost:3000/getAll -> 200)
   `- span 9aa950 "example-trace-mongodb-concurrent.cats.find" (5ms, mongodb, sync)
   `- span 914238 "example-trace-mongodb-concurrent.$cmd.getMore" (12ms, mongodb)
   `- span ce14c7 "admin.$cmd.endSessions" (0ms, mongodb, sync)
trace e42f35
`- transaction 6fc414 "GET unknown route" (75.293ms, GET http://localhost:3000/getAll -> 200)
   `- span 0aefee "example-trace-mongodb-concurrent.cats.find" (7ms, mongodb, sync)
   `- span a6ac7c "example-trace-mongodb-concurrent.$cmd.getMore" (14ms, mongodb)
   `- span 143506 "admin.$cmd.endSessions" (0ms, mongodb, sync)
trace f1f2ba
`- transaction c627b6 "GET unknown route" (135.151ms, GET http://localhost:3000/getAll -> 200)
   `- span b9264b "example-trace-mongodb-concurrent.cats.find" (31ms, mongodb, sync)
   `- span 41a6e2 "example-trace-mongodb-concurrent.$cmd.getMore" (49ms, mongodb)
   `- span b8441a "admin.$cmd.endSessions" (0ms, mongodb, sync)
trace 118e35
`- transaction 71ffa3 "GET unknown route" (133.708ms, GET http://localhost:3000/getAll -> 200)
   `- span 190f31 "example-trace-mongodb-concurrent.cats.find" (29ms, mongodb, sync)
   `- span 2b650e "example-trace-mongodb-concurrent.$cmd.getMore" (44ms, mongodb)
   `- span 8b309e "admin.$cmd.endSessions" (1ms, mongodb, sync)
trace 8fc501
`- transaction bd23b1 "GET unknown route" (133.185ms, GET http://localhost:3000/getAll -> 200)
   `- span 181548 "example-trace-mongodb-concurrent.cats.find" (30ms, mongodb, sync)
   `- span 92b6a5 "example-trace-mongodb-concurrent.$cmd.getMore" (46ms, mongodb)
   `- span 36f0a5 "admin.$cmd.endSessions" (0ms, mongodb, sync)
trace 9e9418
`- transaction fabfcb "GET unknown route" (132.478ms, GET http://localhost:3000/getAll -> 200)
   `- span daa8e2 "example-trace-mongodb-concurrent.cats.find" (31ms, mongodb, sync)
   `- span 02d559 "example-trace-mongodb-concurrent.$cmd.getMore" (51ms, mongodb)
   `- span 26e7b1 "admin.$cmd.endSessions" (0ms, mongodb, sync)
trace 8e97bc
`- transaction 52c78d "GET unknown route" (131.573ms, GET http://localhost:3000/getAll -> 200)
   `- span f00c28 "example-trace-mongodb-concurrent.cats.find" (31ms, mongodb, sync)
   `- span 04a6ca "example-trace-mongodb-concurrent.$cmd.getMore" (50ms, mongodb)
   `- span 0e314e "admin.$cmd.endSessions" (0ms, mongodb, sync)
trace bfc7a1
`- transaction fe1058 "GET unknown route" (126.206ms, GET http://localhost:3000/getAll -> 200)
   `- span e09655 "example-trace-mongodb-concurrent.cats.find" (16ms, mongodb, sync)
   `- span 20472f "example-trace-mongodb-concurrent.$cmd.getMore" (22ms, mongodb)
   `- span 97a546 "admin.$cmd.endSessions" (1ms, mongodb, sync)
trace 6a742a
`- transaction 8bf1f3 "GET unknown route" (124.851ms, GET http://localhost:3000/getAll -> 200)
   `- span 0051de "example-trace-mongodb-concurrent.cats.find" (15ms, mongodb, sync)
   `- span 7c18d5 "example-trace-mongodb-concurrent.$cmd.getMore" (16ms, mongodb)
   `- span 408b3b "admin.$cmd.endSessions" (0ms, mongodb, sync)
trace a277e9
`- transaction 8a1c59 "GET unknown route" (128.91ms, GET http://localhost:3000/getAll -> 200)
   `- span a97d30 "example-trace-mongodb-concurrent.cats.find" (32ms, mongodb, sync)
   `- span f21e22 "example-trace-mongodb-concurrent.$cmd.getMore" (54ms, mongodb)
   `- span ea6210 "admin.$cmd.endSessions" (0ms, mongodb, sync)
trace ab30ec
`- transaction fd8847 "GET unknown route" (123.492ms, GET http://localhost:3000/getAll -> 200)
   `- span 8d4f86 "example-trace-mongodb-concurrent.cats.find" (16ms, mongodb, sync)
   `- span e272a2 "example-trace-mongodb-concurrent.$cmd.getMore" (20ms, mongodb)
   `- span 2100e5 "admin.$cmd.endSessions" (0ms, mongodb, sync)
trace fb9cd6
`- transaction 237080 "GET unknown route" (123.517ms, GET http://localhost:3000/getAll -> 200)
   `- span 0b313c "example-trace-mongodb-concurrent.cats.find" (16ms, mongodb, sync)
   `- span b53743 "example-trace-mongodb-concurrent.$cmd.getMore" (23ms, mongodb)
   `- span 6a5f33 "admin.$cmd.endSessions" (0ms, mongodb, sync)
trace ef97af
`- transaction 88912b "GET unknown route" (122.396ms, GET http://localhost:3000/getAll -> 200)
   `- span 7254c8 "example-trace-mongodb-concurrent.cats.find" (17ms, mongodb, sync)
   `- span 7ab70d "example-trace-mongodb-concurrent.$cmd.getMore" (26ms, mongodb)
   `- span c93b07 "admin.$cmd.endSessions" (0ms, mongodb, sync)
trace 3fa4ca
`- transaction 15a528 "GET unknown route" (123.466ms, GET http://localhost:3000/getAll -> 200)
   `- span 31660a "example-trace-mongodb-concurrent.cats.find" (17ms, mongodb, sync)
   `- span e1aa00 "example-trace-mongodb-concurrent.$cmd.getMore" (29ms, mongodb)
   `- span f17a9a "admin.$cmd.endSessions" (0ms, mongodb, sync)
trace 6cd27c
`- transaction 25ae0d "GET unknown route" (123.222ms, GET http://localhost:3000/getAll -> 200)
   `- span 4624be "example-trace-mongodb-concurrent.cats.find" (18ms, mongodb, sync)
   `- span 76d683 "example-trace-mongodb-concurrent.$cmd.getMore" (31ms, mongodb)
   `- span fdaf3e "admin.$cmd.endSessions" (0ms, mongodb, sync)
trace 92f2ae
`- transaction c0bc48 "GET unknown route" (123.868ms, GET http://localhost:3000/getAll -> 200)
   `- span bc2fca "example-trace-mongodb-concurrent.cats.find" (18ms, mongodb, sync)
   `- span b5c555 "example-trace-mongodb-concurrent.$cmd.getMore" (33ms, mongodb)
   `- span ed23ce "admin.$cmd.endSessions" (0ms, mongodb, sync)
trace 15d0dc
`- transaction bebc8e "GET unknown route" (123.236ms, GET http://localhost:3000/getAll -> 200)
   `- span 53b789 "example-trace-mongodb-concurrent.cats.find" (18ms, mongodb, sync)
   `- span 31320c "example-trace-mongodb-concurrent.$cmd.getMore" (34ms, mongodb)
   `- span 450452 "admin.$cmd.endSessions" (0ms, mongodb, sync)
trace 3b65fd
`- transaction 1f1406 "GET unknown route" (122.965ms, GET http://localhost:3000/getAll -> 200)
   `- span 0cc14b "example-trace-mongodb-concurrent.cats.find" (19ms, mongodb, sync)
   `- span b8c77f "example-trace-mongodb-concurrent.$cmd.getMore" (36ms, mongodb)
   `- span 579637 "admin.$cmd.endSessions" (0ms, mongodb, sync)
trace 2c72bb
`- transaction 6a571a "GET unknown route" (122.802ms, GET http://localhost:3000/getAll -> 200)
   `- span 73a164 "example-trace-mongodb-concurrent.cats.find" (20ms, mongodb, sync)
   `- span 31eb38 "example-trace-mongodb-concurrent.$cmd.getMore" (38ms, mongodb)
   `- span ceda49 "admin.$cmd.endSessions" (0ms, mongodb, sync)
trace 838812
`- transaction 64dfd0 "GET unknown route" (122.461ms, GET http://localhost:3000/getAll -> 200)
   `- span fa6f3f "example-trace-mongodb-concurrent.cats.find" (20ms, mongodb, sync)
   `- span aa7862 "example-trace-mongodb-concurrent.$cmd.getMore" (41ms, mongodb)
   `- span 69ad43 "admin.$cmd.endSessions" (0ms, mongodb, sync)
trace 9f4ec6
`- transaction d1fbb9 "GET unknown route" (122.337ms, GET http://localhost:3000/getAll -> 200)
   `- span 8c3b67 "example-trace-mongodb-concurrent.cats.find" (21ms, mongodb, sync)
   `- span c4672e "example-trace-mongodb-concurrent.$cmd.getMore" (42ms, mongodb)
   `- span cdffe7 "admin.$cmd.endSessions" (1ms, mongodb, sync)
trace 6185d9
`- transaction a4901a "GET unknown route" (133.301ms, GET http://localhost:3000/getAll -> 200)
   `- span b98b31 "example-trace-mongodb-concurrent.cats.find" (82ms, mongodb, sync)
   `- span ca60db "example-trace-mongodb-concurrent.$cmd.getMore" (11ms, mongodb)
   `- span 0e4e4f "admin.$cmd.endSessions" (0ms, mongodb, sync)
trace 7d547a
`- transaction a122ca "GET unknown route" (133.011ms, GET http://localhost:3000/getAll -> 200)
   `- span c8a5a6 "example-trace-mongodb-concurrent.cats.find" (82ms, mongodb, sync)
   `- span 7c5b4d "example-trace-mongodb-concurrent.$cmd.getMore" (12ms, mongodb)
   `- span aaa95d "admin.$cmd.endSessions" (0ms, mongodb, sync)
trace 3c4f29
`- transaction 5c74d6 "GET unknown route" (132.784ms, GET http://localhost:3000/getAll -> 200)
   `- span 285084 "example-trace-mongodb-concurrent.cats.find" (83ms, mongodb, sync)
   `- span e9d801 "example-trace-mongodb-concurrent.$cmd.getMore" (14ms, mongodb)
   `- span 2335c1 "admin.$cmd.endSessions" (0ms, mongodb, sync)
trace 2d5c97
`- transaction e297f6 "GET unknown route" (132.29ms, GET http://localhost:3000/getAll -> 200)
   `- span f5b593 "example-trace-mongodb-concurrent.cats.find" (82ms, mongodb, sync)
   `- span d94b22 "example-trace-mongodb-concurrent.$cmd.getMore" (15ms, mongodb)
   `- span 225207 "admin.$cmd.endSessions" (0ms, mongodb, sync)
trace 799974
`- transaction 2d3286 "GET unknown route" (131.147ms, GET http://localhost:3000/getAll -> 200)
   `- span 908049 "example-trace-mongodb-concurrent.cats.find" (56ms, mongodb, sync)
   `- span b37449 "example-trace-mongodb-concurrent.$cmd.getMore" (9ms, mongodb)
   `- span b224e5 "admin.$cmd.endSessions" (0ms, mongodb, sync)

@david-luna
Copy link
Member

david-luna commented Sep 18, 2023

@sefiros1

Took a while to get to the root cause but we could confirm our assumptions about batching. We prepared a repo which reproduces the issue for our agent and Opentelemtry

https://github.com/david-luna/node-mongodb-native-async-resource

And I've created an issue in MongoDB's issue tracker with a fix proposal
https://jira.mongodb.org/browse/NODE-5639

and a PR (draft for now)
mongodb/node-mongodb-native#3871

For now I'd say let's wait for their response

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
agent-nodejs Make available for APM Agents project planning. bug community
Projects
Status: Done
4 participants