Skip to content

Commit dd3b1aa

Browse files
authored
Merge pull request #13110 from getsentry/prepare-release/8.21.0
meta: Update CHANGELOG for 8.21.0
2 parents f609d05 + f3a4109 commit dd3b1aa

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+843
-56
lines changed

CHANGELOG.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,15 @@ upcoming release.
3131
- feat(feedback): Make cropped screenshot area draggable (#13071)
3232
- feat(core): Adapt spans for client-side fetch to streaming responses (#12723)
3333
- feat(core): Capture # of dropped spans through `beforeSendTransaction` (#13022)
34-
- feat(deps): bump @opentelemetry/instrumentation-aws-sdk from 0.43.0 to 0.43.1 (#13089)
35-
- feat(deps): bump @opentelemetry/instrumentation-express from 0.41.0 to 0.41.1 (#13090)
34+
- feat(deps): bump `@opentelemetry/instrumentation-aws-sdk` from 0.43.0 to 0.43.1 (#13089)
35+
- feat(deps): bump `@opentelemetry/instrumentation-express` from 0.41.0 to 0.41.1 (#13090)
36+
- feat(nestjs): Automatic instrumentation of nestjs middleware (#13065)
37+
- feat(node): Upgrade `import-in-the-middle` to 1.11.0 (#13107)
3638
- feat(nuxt): Add connected tracing meta tags (#13098)
3739
- feat(nuxt): Add vue-router instrumentation (#13054)
40+
- feat(solidstart): Add server action instrumentation helper (#13035)
3841
- fix(feedback): Ensure pluggable feedback CDN bundle is correctly built (#13081)
42+
- fix(nextjs): Only delete clientside bundle source maps with `sourcemaps.deleteFilesAfterUpload` (#13102)
3943
- fix(node): Improve OTEL validation logic (#13079)
4044

4145
## 8.20.0

dev-packages/browser-integration-tests/utils/fixtures.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,12 +68,18 @@ const sentryTest = base.extend<TestFixtures>({
6868
// Ensure feedback can be lazy loaded
6969
await page.route(`https://browser.sentry-cdn.com/${SDK_VERSION}/feedback-modal.min.js`, route => {
7070
const filePath = path.resolve(testDir, './dist/feedback-modal.bundle.js');
71-
return fs.existsSync(filePath) ? route.fulfill({ path: filePath }) : route.continue();
71+
if (!fs.existsSync(filePath)) {
72+
throw new Error(`Feedback modal bundle (${filePath}) not found`);
73+
}
74+
return route.fulfill({ path: filePath });
7275
});
7376

7477
await page.route(`https://browser.sentry-cdn.com/${SDK_VERSION}/feedback-screenshot.min.js`, route => {
7578
const filePath = path.resolve(testDir, './dist/feedback-screenshot.bundle.js');
76-
return fs.existsSync(filePath) ? route.fulfill({ path: filePath }) : route.continue();
79+
if (!fs.existsSync(filePath)) {
80+
throw new Error(`Feedback screenshot bundle (${filePath}) not found`);
81+
}
82+
return route.fulfill({ path: filePath });
7783
});
7884
}
7985

dev-packages/browser-integration-tests/utils/generatePlugin.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,19 @@ class SentryScenarioGenerationPlugin {
272272
fileName,
273273
);
274274

275+
if (integration === 'feedback') {
276+
addStaticAssetSymlink(
277+
this.localOutPath,
278+
path.resolve(PACKAGES_DIR, 'feedback', 'build/bundles/feedback-modal.js'),
279+
'feedback-modal.bundle.js',
280+
);
281+
addStaticAssetSymlink(
282+
this.localOutPath,
283+
path.resolve(PACKAGES_DIR, 'feedback', 'build/bundles/feedback-screenshot.js'),
284+
'feedback-screenshot.bundle.js',
285+
);
286+
}
287+
275288
const integrationObject = createHtmlTagObject('script', {
276289
src: fileName,
277290
});

dev-packages/e2e-tests/test-applications/nestjs-basic/src/app.controller.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ export class AppController {
1010
return this.appService.testTransaction();
1111
}
1212

13+
@Get('test-middleware-instrumentation')
14+
testMiddlewareInstrumentation() {
15+
return this.appService.testMiddleware();
16+
}
17+
1318
@Get('test-exception/:id')
1419
async testException(@Param('id') id: string) {
1520
return this.appService.testException(id);
Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,17 @@
1-
import { Module } from '@nestjs/common';
1+
import { MiddlewareConsumer, Module } from '@nestjs/common';
22
import { ScheduleModule } from '@nestjs/schedule';
33
import { SentryModule } from '@sentry/nestjs/setup';
44
import { AppController } from './app.controller';
55
import { AppService } from './app.service';
6+
import { ExampleMiddleware } from './example.middleware';
67

78
@Module({
89
imports: [SentryModule.forRoot(), ScheduleModule.forRoot()],
910
controllers: [AppController],
1011
providers: [AppService],
1112
})
12-
export class AppModule {}
13+
export class AppModule {
14+
configure(consumer: MiddlewareConsumer): void {
15+
consumer.apply(ExampleMiddleware).forRoutes('test-middleware-instrumentation');
16+
}
17+
}

dev-packages/e2e-tests/test-applications/nestjs-basic/src/app.service.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@ export class AppService {
2121
});
2222
}
2323

24+
testMiddleware() {
25+
// span that should not be a child span of the middleware span
26+
Sentry.startSpan({ name: 'test-controller-span' }, () => {});
27+
}
28+
2429
testException(id: string) {
2530
throw new Error(`This is an exception with id ${id}`);
2631
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { Injectable, NestMiddleware } from '@nestjs/common';
2+
import * as Sentry from '@sentry/nestjs';
3+
import { NextFunction, Request, Response } from 'express';
4+
5+
@Injectable()
6+
export class ExampleMiddleware implements NestMiddleware {
7+
use(req: Request, res: Response, next: NextFunction) {
8+
// span that should be a child span of the middleware span
9+
Sentry.startSpan({ name: 'test-middleware-span' }, () => {});
10+
next();
11+
}
12+
}

dev-packages/e2e-tests/test-applications/nestjs-basic/tests/transactions.test.ts

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,3 +121,82 @@ test('Sends an API route transaction', async ({ baseURL }) => {
121121
}),
122122
);
123123
});
124+
125+
test('API route transaction includes nest middleware span. Spans created in and after middleware are nested correctly', async ({
126+
baseURL,
127+
}) => {
128+
const pageloadTransactionEventPromise = waitForTransaction('nestjs', transactionEvent => {
129+
return (
130+
transactionEvent?.contexts?.trace?.op === 'http.server' &&
131+
transactionEvent?.transaction === 'GET /test-middleware-instrumentation'
132+
);
133+
});
134+
135+
await fetch(`${baseURL}/test-middleware-instrumentation`);
136+
137+
const transactionEvent = await pageloadTransactionEventPromise;
138+
139+
expect(transactionEvent).toEqual(
140+
expect.objectContaining({
141+
spans: expect.arrayContaining([
142+
{
143+
span_id: expect.any(String),
144+
trace_id: expect.any(String),
145+
data: {
146+
'sentry.op': 'middleware.nestjs',
147+
'sentry.origin': 'auto.middleware.nestjs',
148+
},
149+
description: 'ExampleMiddleware',
150+
parent_span_id: expect.any(String),
151+
start_timestamp: expect.any(Number),
152+
timestamp: expect.any(Number),
153+
status: 'ok',
154+
op: 'middleware.nestjs',
155+
origin: 'auto.middleware.nestjs',
156+
},
157+
]),
158+
}),
159+
);
160+
161+
const exampleMiddlewareSpan = transactionEvent.spans.find(span => span.description === 'ExampleMiddleware');
162+
const exampleMiddlewareSpanId = exampleMiddlewareSpan?.span_id;
163+
164+
expect(transactionEvent).toEqual(
165+
expect.objectContaining({
166+
spans: expect.arrayContaining([
167+
{
168+
span_id: expect.any(String),
169+
trace_id: expect.any(String),
170+
data: expect.any(Object),
171+
description: 'test-controller-span',
172+
parent_span_id: expect.any(String),
173+
start_timestamp: expect.any(Number),
174+
timestamp: expect.any(Number),
175+
status: 'ok',
176+
origin: 'manual',
177+
},
178+
{
179+
span_id: expect.any(String),
180+
trace_id: expect.any(String),
181+
data: expect.any(Object),
182+
description: 'test-middleware-span',
183+
parent_span_id: expect.any(String),
184+
start_timestamp: expect.any(Number),
185+
timestamp: expect.any(Number),
186+
status: 'ok',
187+
origin: 'manual',
188+
},
189+
]),
190+
}),
191+
);
192+
193+
// verify correct span parent-child relationships
194+
const testMiddlewareSpan = transactionEvent.spans.find(span => span.description === 'test-middleware-span');
195+
const testControllerSpan = transactionEvent.spans.find(span => span.description === 'test-controller-span');
196+
197+
// 'ExampleMiddleware' is the parent of 'test-middleware-span'
198+
expect(testMiddlewareSpan.parent_span_id).toBe(exampleMiddlewareSpanId);
199+
200+
// 'ExampleMiddleware' is NOT the parent of 'test-controller-span'
201+
expect(testControllerSpan.parent_span_id).not.toBe(exampleMiddlewareSpanId);
202+
});

dev-packages/e2e-tests/test-applications/nextjs-app-dir/assert-build.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,10 @@ assert.match(buildStdout, /(λ|ƒ) \/server-component\/parameter\/\[\.\.\.parame
2222
assert.match(buildStdout, /(λ|ƒ) \/server-component\/parameter\/\[parameter\]/);
2323

2424
// Read the contents of the directory
25-
const files = fs.readdirSync(path.join(process.cwd(), '.next', 'server'));
25+
const files = fs.readdirSync(path.join(process.cwd(), '.next', 'static'));
2626
const mapFiles = files.filter(file => path.extname(file) === '.map');
2727
if (mapFiles.length > 0) {
28-
throw new Error('.map files found even though `sourcemaps.deleteSourcemapsAfterUpload` option is set!');
28+
throw new Error('Client bundle .map files found even though `sourcemaps.deleteSourcemapsAfterUpload` option is set!');
2929
}
3030

3131
export {};

dev-packages/e2e-tests/test-applications/node-nestjs-basic/src/app.controller.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ export class AppController {
1010
return this.appService.testTransaction();
1111
}
1212

13+
@Get('test-middleware-instrumentation')
14+
testMiddlewareInstrumentation() {
15+
return this.appService.testMiddleware();
16+
}
17+
1318
@Get('test-exception/:id')
1419
async testException(@Param('id') id: string) {
1520
return this.appService.testException(id);
Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
1-
import { Module } from '@nestjs/common';
1+
import { MiddlewareConsumer, Module } from '@nestjs/common';
22
import { ScheduleModule } from '@nestjs/schedule';
33
import { AppController } from './app.controller';
44
import { AppService } from './app.service';
5+
import { ExampleMiddleware } from './example.middleware';
56

67
@Module({
78
imports: [ScheduleModule.forRoot()],
89
controllers: [AppController],
910
providers: [AppService],
1011
})
11-
export class AppModule {}
12+
export class AppModule {
13+
configure(consumer: MiddlewareConsumer): void {
14+
consumer.apply(ExampleMiddleware).forRoutes('test-middleware-instrumentation');
15+
}
16+
}

dev-packages/e2e-tests/test-applications/node-nestjs-basic/src/app.service.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@ export class AppService {
2121
});
2222
}
2323

24+
testMiddleware() {
25+
// span that should not be a child span of the middleware span
26+
Sentry.startSpan({ name: 'test-controller-span' }, () => {});
27+
}
28+
2429
testException(id: string) {
2530
throw new Error(`This is an exception with id ${id}`);
2631
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { Injectable, NestMiddleware } from '@nestjs/common';
2+
import * as Sentry from '@sentry/nestjs';
3+
import { NextFunction, Request, Response } from 'express';
4+
5+
@Injectable()
6+
export class ExampleMiddleware implements NestMiddleware {
7+
use(req: Request, res: Response, next: NextFunction) {
8+
// span that should be a child span of the middleware span
9+
Sentry.startSpan({ name: 'test-middleware-span' }, () => {});
10+
next();
11+
}
12+
}

dev-packages/e2e-tests/test-applications/node-nestjs-basic/tests/transactions.test.ts

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,3 +121,82 @@ test('Sends an API route transaction', async ({ baseURL }) => {
121121
}),
122122
);
123123
});
124+
125+
test('API route transaction includes nest middleware span. Spans created in and after middleware are nested correctly', async ({
126+
baseURL,
127+
}) => {
128+
const pageloadTransactionEventPromise = waitForTransaction('nestjs', transactionEvent => {
129+
return (
130+
transactionEvent?.contexts?.trace?.op === 'http.server' &&
131+
transactionEvent?.transaction === 'GET /test-middleware-instrumentation'
132+
);
133+
});
134+
135+
await fetch(`${baseURL}/test-middleware-instrumentation`);
136+
137+
const transactionEvent = await pageloadTransactionEventPromise;
138+
139+
expect(transactionEvent).toEqual(
140+
expect.objectContaining({
141+
spans: expect.arrayContaining([
142+
{
143+
span_id: expect.any(String),
144+
trace_id: expect.any(String),
145+
data: {
146+
'sentry.op': 'middleware.nestjs',
147+
'sentry.origin': 'auto.middleware.nestjs',
148+
},
149+
description: 'ExampleMiddleware',
150+
parent_span_id: expect.any(String),
151+
start_timestamp: expect.any(Number),
152+
timestamp: expect.any(Number),
153+
status: 'ok',
154+
op: 'middleware.nestjs',
155+
origin: 'auto.middleware.nestjs',
156+
},
157+
]),
158+
}),
159+
);
160+
161+
const exampleMiddlewareSpan = transactionEvent.spans.find(span => span.description === 'ExampleMiddleware');
162+
const exampleMiddlewareSpanId = exampleMiddlewareSpan?.span_id;
163+
164+
expect(transactionEvent).toEqual(
165+
expect.objectContaining({
166+
spans: expect.arrayContaining([
167+
{
168+
span_id: expect.any(String),
169+
trace_id: expect.any(String),
170+
data: expect.any(Object),
171+
description: 'test-controller-span',
172+
parent_span_id: expect.any(String),
173+
start_timestamp: expect.any(Number),
174+
timestamp: expect.any(Number),
175+
status: 'ok',
176+
origin: 'manual',
177+
},
178+
{
179+
span_id: expect.any(String),
180+
trace_id: expect.any(String),
181+
data: expect.any(Object),
182+
description: 'test-middleware-span',
183+
parent_span_id: expect.any(String),
184+
start_timestamp: expect.any(Number),
185+
timestamp: expect.any(Number),
186+
status: 'ok',
187+
origin: 'manual',
188+
},
189+
]),
190+
}),
191+
);
192+
193+
// verify correct span parent-child relationships
194+
const testMiddlewareSpan = transactionEvent.spans.find(span => span.description === 'test-middleware-span');
195+
const testControllerSpan = transactionEvent.spans.find(span => span.description === 'test-controller-span');
196+
197+
// 'ExampleMiddleware' is the parent of 'test-middleware-span'
198+
expect(testMiddlewareSpan.parent_span_id).toBe(exampleMiddlewareSpanId);
199+
200+
// 'ExampleMiddleware' is NOT the parent of 'test-controller-span'
201+
expect(testControllerSpan.parent_span_id).not.toBe(exampleMiddlewareSpanId);
202+
});

dev-packages/e2e-tests/test-applications/solidstart/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
"This is currently not an issue outside of our repo. See: https://github.com/nksaraf/vinxi/issues/177"
1212
],
1313
"preview": "HOST=localhost PORT=3030 NODE_OPTIONS='--import ./src/instrument.server.mjs' vinxi dev",
14+
"start": "HOST=localhost PORT=3030 NODE_OPTIONS='--import ./src/instrument.server.mjs' vinxi start",
1415
"test:prod": "TEST_ENV=production playwright test",
1516
"test:build": "pnpm install && npx playwright install && pnpm build",
1617
"test:assert": "pnpm test:prod"
@@ -31,7 +32,7 @@
3132
"jsdom": "^24.0.0",
3233
"solid-js": "1.8.17",
3334
"typescript": "^5.4.5",
34-
"vinxi": "^0.3.12",
35+
"vinxi": "^0.4.0",
3536
"vite": "^5.2.8",
3637
"vite-plugin-solid": "^2.10.2",
3738
"vitest": "^1.5.0"

dev-packages/e2e-tests/test-applications/solidstart/src/entry-client.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ Sentry.init({
1212
tunnel: 'http://localhost:3031/', // proxy server
1313
// Performance Monitoring
1414
tracesSampleRate: 1.0, // Capture 100% of the transactions
15+
debug: !!import.meta.env.DEBUG,
1516
});
1617

1718
mount(() => <StartClient />, document.getElementById('app')!);

dev-packages/e2e-tests/test-applications/solidstart/src/instrument.server.mjs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,5 @@ Sentry.init({
55
environment: 'qa', // dynamic sampling bias to keep transactions
66
tracesSampleRate: 1.0, // Capture 100% of the transactions
77
tunnel: 'http://localhost:3031/', // proxy server
8+
debug: !!process.env.DEBUG,
89
});

dev-packages/e2e-tests/test-applications/solidstart/src/routes/index.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ export default function Home() {
1111
<li>
1212
<A href="/client-error">Client error</A>
1313
</li>
14+
<li>
15+
<A href="/server-error">Server error</A>
16+
</li>
1417
<li>
1518
<A id="navLink" href="/users/5">
1619
User 5

0 commit comments

Comments
 (0)