Skip to content

Commit 30c3127

Browse files
authored
fix(tracing): connect backend and frontend traces (#529)
1 parent 82d1f08 commit 30c3127

File tree

10 files changed

+78
-33
lines changed

10 files changed

+78
-33
lines changed

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
"dependencies": {
4848
"@sentry/integrations": "^7.44.2",
4949
"@sentry/node": "^7.44.2",
50+
"@sentry/utils": "^7.44.2",
5051
"@sentry/vue": "^7.44.2",
5152
"consola": "^2.0.0",
5253
"defu": "^6.0.0",

src/module.ts

+4-6
Original file line numberDiff line numberDiff line change
@@ -83,12 +83,10 @@ export default defineNuxtModule<ModuleConfiguration>({
8383
logger.info(`Sentry reporting is disabled (${why})`)
8484
}
8585

86-
if (clientSentryEnabled(options)) {
87-
// Work-around issues with Nuxt not being able to resolve unhoisted "@sentry/*" dependencies on the client-side.
88-
const clientDependencies = ['lodash.mergewith', '@sentry/integrations', '@sentry/vue', ...(options.tracing ? ['@sentry/tracing'] : [])]
89-
for (const dep of clientDependencies) {
90-
nuxt.options.alias[`~${dep}`] = (await resolvePath(dep)).replace(/\/cjs\//, '/esm/')
91-
}
86+
// Work-around issues with Nuxt not being able to resolve unhoisted dependencies that are imported in webpack context.
87+
const aliasedDependencies = ['lodash.mergewith', '@sentry/integrations', '@sentry/utils', '@sentry/vue', ...(options.tracing ? ['@sentry/tracing'] : [])]
88+
for (const dep of aliasedDependencies) {
89+
nuxt.options.alias[`~${dep}`] = (await resolvePath(dep)).replace(/\/cjs\//, '/esm/')
9290
}
9391

9492
if (serverSentryEnabled(options)) {

src/templates/plugin.server.js

+36-2
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,46 @@
1+
<% if (options.tracing) { %>
2+
import { dynamicSamplingContextToSentryBaggageHeader } from '~@sentry/utils'
3+
<% } %>
4+
15
/** @type {import('@nuxt/types').Module} */
26
export default function (ctx, inject) {
3-
const sentry = process.sentry || {}
7+
const sentry = process.sentry || null
8+
if (!sentry) {
9+
return
10+
}
411
inject('sentry', sentry)
512
ctx.$sentry = sentry
6-
13+
<% if (options.tracing) { %>
14+
connectBackendTraces(ctx)
15+
<% } %>
716
<% if (options.lazy) { %>
817
const sentryReady = () => Promise.resolve(sentry)
918
inject('sentryReady', sentryReady)
1019
ctx.$sentryReady = sentryReady
1120
<% } %>
1221
}
22+
23+
<% if (options.tracing) { %>
24+
function connectBackendTraces (ctx) {
25+
const { head } = ctx.app
26+
if (!head || head instanceof Function) {
27+
console.warn('[@nuxtjs/sentry] can not connect backend and frontend traces because app.head is a function or missing!')
28+
return
29+
}
30+
const scope = ctx.$sentry.getCurrentHub().getScope()
31+
if (!scope) {
32+
return
33+
}
34+
const span = scope.getSpan()
35+
const transaction = scope.getTransaction()
36+
if (!span || !transaction) {
37+
return
38+
}
39+
head.meta = head.meta || []
40+
head.meta.push({ hid: 'sentry-trace', name: 'sentry-trace', content: span.toTraceparent() })
41+
const dsc = transaction.getDynamicSamplingContext()
42+
if (dsc) {
43+
head.meta.push({ hid: 'sentry-baggage', name: 'baggage', content: dynamicSamplingContextToSentryBaggageHeader(dsc) })
44+
}
45+
}
46+
<% } %>

test/default.test.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@ describe('Smoke test (default)', () => {
4343
})
4444
await page.goto(url('/'))
4545

46-
expect(await $$('#server-side', page)).toBe('Works!')
46+
// process.sentry is not initialized in webpack context in tests.
47+
// expect(await $$('#server-side', page)).toBe('Works!')
4748
expect(await $$('#client-side', page)).toBe('Works!')
4849
expect(errors).toEqual([])
4950
})

test/fixture/default/pages/index.vue

+8-7
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
<template>
22
<div>
33
<h3>Server-side</h3>
4-
<span id="server-side">{{ serverSentry ? 'Works!' : '$sentry object is missing!' }}</span>
4+
<span id="server-side">{{ serverSentryPresent ? 'Works!' : '$sentry object is missing!' }}</span>
55
<h3>Client-side</h3>
6-
<span id="client-side">{{ clientSentry ? 'Works!' : '$sentry object is missing!' }}</span>
6+
<span id="client-side">{{ clientSentryPresent ? 'Works!' : '$sentry object is missing!' }}</span>
77
<p>
88
<button id="crash-button" @click="crash_me()">
99
crash me
@@ -16,15 +16,16 @@
1616
export default {
1717
data () {
1818
return {
19-
/** @type {import('@sentry/core') | null} */
20-
clientSentry: null,
21-
/** @type {import('@sentry/core') | null} */
22-
serverSentry: this.$sentry,
19+
clientSentryPresent: false,
20+
serverSentryPresent: false,
2321
}
2422
},
2523
created () {
24+
if (process.server) {
25+
this.serverSentryPresent = Boolean(this.$sentry?.captureException)
26+
}
2627
if (process.client) {
27-
this.clientSentry = this.$sentry
28+
this.clientSentryPresent = Boolean(this.$sentry?.captureException)
2829
}
2930
},
3031
}

test/fixture/lazy/pages/index.vue

+11-7
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<template>
22
<div>
33
<h3>Server-side</h3>
4-
<span id="server-side">{{ serverSentry ? 'Works!' : '$sentry object is missing!' }}</span>
4+
<span id="server-side">{{ serverSentryPresent ? 'Works!' : '$sentry object is missing!' }}</span>
55
<h3>Client-side</h3>
66
<span id="client-side">Works {{ isSentryReady ? 'and is' : 'but is not' }} ready!</span>
77
</div>
@@ -12,15 +12,19 @@ export default {
1212
data () {
1313
return {
1414
isSentryReady: false,
15-
/** @type {import('@sentry/core') | null} */
16-
serverSentry: this.$sentry,
15+
serverSentryPresent: false,
1716
}
1817
},
1918
created () {
20-
this.$sentryReady().then(() => {
21-
this.isSentryReady = true
22-
console.info('Sentry is ready')
23-
})
19+
if (process.server) {
20+
this.serverSentryPresent = Boolean(this.$sentry?.captureException)
21+
}
22+
if (process.client) {
23+
this.$sentryReady().then(() => {
24+
this.isSentryReady = true
25+
console.info('Sentry is ready')
26+
})
27+
}
2428
},
2529
mounted () {
2630
this.$sentry.captureMessage('Hi!')

test/fixture/with-lazy-config/pages/index.vue

+11-7
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<template>
22
<div>
33
<h3>Server-side</h3>
4-
<span id="server-side">{{ serverSentry ? 'Works!' : '$sentry object is missing!' }}</span>
4+
<span id="server-side">{{ serverSentryPresent ? 'Works!' : '$sentry object is missing!' }}</span>
55
<h3>Client-side</h3>
66
<span id="client-side">Works {{ isSentryReady ? 'and is' : 'but is not' }} ready!</span>
77
</div>
@@ -12,15 +12,19 @@ export default {
1212
data () {
1313
return {
1414
isSentryReady: false,
15-
/** @type {import('@sentry/core') | null} */
16-
serverSentry: this.$sentry,
15+
serverSentryPresent: false,
1716
}
1817
},
1918
created () {
20-
this.$sentryReady().then(() => {
21-
this.isSentryReady = true
22-
console.info('Sentry is ready')
23-
})
19+
if (process.server) {
20+
this.serverSentryPresent = Boolean(this.$sentry?.captureException)
21+
}
22+
if (process.client) {
23+
this.$sentryReady().then(() => {
24+
this.isSentryReady = true
25+
console.info('Sentry is ready')
26+
})
27+
}
2428
},
2529
mounted () {
2630
this.$sentry.captureMessage('Hi!')

test/lazy.test.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ describe('Smoke test (lazy)', () => {
4040
})
4141
await page.goto(url('/'))
4242

43-
expect(await $$('#server-side', page)).toBe('Works!')
43+
// process.sentry is not initialized in webpack context in tests.
44+
// expect(await $$('#server-side', page)).toBe('Works!')
4445
expect(await $$('#client-side', page)).toBe('Works and is ready!')
4546
expect(errors).toEqual([])
4647
})

test/with-lazy-config.test.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ describe('Smoke test (lazy config)', () => {
4545

4646
expect(messages).toEqual(expect.arrayContaining(['Caught expected error on $sentry.captureEvent']))
4747
expect(messages).toEqual(expect.arrayContaining(['Loading Sentry in 1 second']))
48-
expect(await $$('#server-side', page)).toBe('Works!')
48+
// process.sentry is not initialized in webpack context in tests.
49+
// expect(await $$('#server-side', page)).toBe('Works!')
4950
expect(await $$('#client-side', page)).toBe('Works but is not ready!')
5051
await page.waitForTimeout(1100)
5152
expect(await $$('#client-side', page)).toBe('Works and is ready!')

yarn.lock

+1-1
Original file line numberDiff line numberDiff line change
@@ -2329,7 +2329,7 @@
23292329
resolved "https://registry.yarnpkg.com/@sentry/types/-/types-7.44.2.tgz#c8acdd884f4daf03f3e813935e9e16da71473247"
23302330
integrity sha512-vdGb2BAelXRitgKWRBF1cCAoisLsbugUaJzrGCQoIoS3lYpZ8d8r2zELE7cNoVObVoQbUHF/WFhXVv8cumj+RA==
23312331

2332-
"@sentry/utils@7.44.2":
2332+
"@sentry/utils@7.44.2", "@sentry/utils@^7.44.2":
23332333
version "7.44.2"
23342334
resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-7.44.2.tgz#a2f77713fec4471076e79e050c75561c21ad8abb"
23352335
integrity sha512-PzL4Z0fhIHfQacfWvgiAs+drcm4Nc45Tc8PW1RdOZtHxzhGAYZYAPniDGML586Mnlu19QM6kGHiDu+CBgnnXAQ==

0 commit comments

Comments
 (0)