Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions packages/datadog-plugin-next/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ const errorPages = new Set(['/404', '/500', '/_error', '/_not-found', '/_not-fou

class NextPlugin extends ServerPlugin {
static id = 'next'
#requestsBySpanId = new WeakMap()

constructor (...args) {
super(...args)
this._requests = new WeakMap()
this.addSub('apm:next:page:load', message => this.pageLoad(message))
}

Expand All @@ -35,7 +35,9 @@ class NextPlugin extends ServerPlugin {

analyticsSampler.sample(span, this.config.measured, true)

this._requests.set(span, req)
// Store request by span ID to handle cases where child spans are activated
const spanId = span.context()._spanId
this.#requestsBySpanId.set(spanId, req)

return { ...store, span }
}
Expand Down Expand Up @@ -89,7 +91,13 @@ class NextPlugin extends ServerPlugin {
if (!store) return

const span = store.span
const req = this._requests.get(span)

const spanId = span.context()._spanId
const parentSpanId = span.context()._parentId

// Try current span first, then parent span.
// This handles cases where pageLoad runs in a child span context
const req = this.#requestsBySpanId.get(spanId) ?? this.#requestsBySpanId.get(parentSpanId)

// safeguard against missing req in complicated timeout scenarios
if (!req) return
Expand Down
29 changes: 29 additions & 0 deletions packages/datadog-plugin-next/test/index.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,35 @@ describe('Plugin', function () {
.get(`http://127.0.0.1:${port}/api/hello/world`)
.catch(done)
})

it('should handle child spans and still find the request object', done => {
agent
.assertSomeTraces(traces => {
const spans = traces[0]

const nextRequestSpan = spans.find(span => span.name === 'next.request')
assert.ok(nextRequestSpan, 'next.request span should exist')

assert.strictEqual(nextRequestSpan.resource, 'GET /api/hello/[name]')
assert.strictEqual(nextRequestSpan.meta['next.page'], '/api/hello/[name]')
assert.strictEqual(nextRequestSpan.meta['http.method'], 'GET')
assert.strictEqual(nextRequestSpan.meta['http.status_code'], '200')

const webRequestSpan = spans.find(span => span.name === 'web.request')
assert.ok(webRequestSpan, 'web.request span should exist')
assert.strictEqual(webRequestSpan.resource, 'GET /api/hello/[name]')

const childSpan = spans.find(span => span.name === 'child.operation')
assert.ok(childSpan, 'child span should exist')
assert.strictEqual(childSpan.parent_id.toString(), nextRequestSpan.span_id.toString())
})
.then(done)
.catch(done)

axios
.get(`http://127.0.0.1:${port}/api/hello/world?createChildSpan=true`)
.catch(done)
})
})

describe('for pages', () => {
Expand Down
11 changes: 11 additions & 0 deletions packages/datadog-plugin-next/test/pages/api/hello/[name].js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,17 @@

export default (req, res) => {
const tracer = require('../../../../../dd-trace')

if (req.query.createChildSpan === 'true') {
const childSpan = tracer.startSpan('child.operation', {
childOf: tracer.scope().active()
})

tracer.scope().activate(childSpan, () => {
childSpan.finish()
})
}

const span = tracer.scope().active()
const name = span && span.context()._name

Expand Down
Loading