elastic / elastic/apm-agent-nodejs
Previosly ended exit span stays in run context and breaks next spans
- Dominant language
- JavaScript
- Stars
- 594
- Forks
- 244
- Avg merge
- 1d 8h
- Merged PRs (30d)
- 16
Description
**Describe the bug**
If one create an exit span and finish it with `span.end()` it still presents in the run context and is visible as currentSpan. Therefore all further spans are not started inside the same transaction.
**To Reproduce**
Run the following example code:
```javascript
const apm = require('elastic-apm-node');
const tracer = apm.start({
serverUrl: '...', // replace with your url
serviceName: 'testSpans',
environment: 'dev',
logUncaughtExceptions: false,
transactionSampleRate: 1
});
const runAsyncCode = async () => new Promise((resolve) => setImmediate(resolve));
const executeDbSpan = async (apmTransaction) => {
const span = apmTransaction?.startSpan('SQL query', 'db', 'mssql', 'query', { exitSpan: true });
try {
span?.setServiceTarget('mssql', 'someDB');
await runAsyncCode();
span?.setOutcome('success');
}
catch (err) {
tracer?.captureError(err, { parent: span });
span?.setOutcome('failure');
} finally {
span?.end();
}
}
const executeCustomSpan = async (apmTransaction) => {
// this span will be null since previosly ended db span
// is present as currentSpan
const span = apmTransaction?.startSpan(`MyCustomSpan`);
try {
await runAsyncCode();
span?.setOutcome('success');
}
catch (err) {
tracer?.captureError(err, { parent: span });
span?.setOutcome('failure');
} finally {
span?.end();
}
}
const run = async () => {
const transaction = tracer.startTransaction('test');
try {
await executeDbSpan(transaction);
await executeCustomSpan(transaction);
} finally {
transaction?.end();
}
}
run();
```
**Expected behavior**
in executeCustomSpan newly started span with `MyCustomSpan` name should not be `null`
**Environment (please complete the following information)**
- OS: Windows, Linux
- Node.js version: 16.18.0
- APM Server version: 7.14.4 (but does not matter)
- Agent version: 3.43.0
**How are you starting the agent? (please tick one of the boxes)**
- [x] 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 is using `AsyncLocalStorageRunContextManager` and as far as I can see `supersedeRunContext` removes the span from the context but then in `active` method it is still there.
Agent config options:
Click to expand
```
see the source code I pasted here
```
`package.json` dependencies:
Click to expand
```
"dependencies": {
"elastic-apm-node": "^3.43.0"
}
```
Contributor guide
Assessment
This issue has not been assessed yet.