Skip to content

Commit

Permalink
Merge pull request #13110 from getsentry/prepare-release/8.21.0
Browse files Browse the repository at this point in the history
meta: Update CHANGELOG for 8.21.0
  • Loading branch information
Lms24 authored Jul 30, 2024
2 parents f609d05 + f3a4109 commit dd3b1aa
Show file tree
Hide file tree
Showing 43 changed files with 843 additions and 56 deletions.
8 changes: 6 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,15 @@ upcoming release.
- feat(feedback): Make cropped screenshot area draggable (#13071)
- feat(core): Adapt spans for client-side fetch to streaming responses (#12723)
- feat(core): Capture # of dropped spans through `beforeSendTransaction` (#13022)
- feat(deps): bump @opentelemetry/instrumentation-aws-sdk from 0.43.0 to 0.43.1 (#13089)
- feat(deps): bump @opentelemetry/instrumentation-express from 0.41.0 to 0.41.1 (#13090)
- feat(deps): bump `@opentelemetry/instrumentation-aws-sdk` from 0.43.0 to 0.43.1 (#13089)
- feat(deps): bump `@opentelemetry/instrumentation-express` from 0.41.0 to 0.41.1 (#13090)
- feat(nestjs): Automatic instrumentation of nestjs middleware (#13065)
- feat(node): Upgrade `import-in-the-middle` to 1.11.0 (#13107)
- feat(nuxt): Add connected tracing meta tags (#13098)
- feat(nuxt): Add vue-router instrumentation (#13054)
- feat(solidstart): Add server action instrumentation helper (#13035)
- fix(feedback): Ensure pluggable feedback CDN bundle is correctly built (#13081)
- fix(nextjs): Only delete clientside bundle source maps with `sourcemaps.deleteFilesAfterUpload` (#13102)
- fix(node): Improve OTEL validation logic (#13079)

## 8.20.0
Expand Down
10 changes: 8 additions & 2 deletions dev-packages/browser-integration-tests/utils/fixtures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,12 +68,18 @@ const sentryTest = base.extend<TestFixtures>({
// Ensure feedback can be lazy loaded
await page.route(`https://browser.sentry-cdn.com/${SDK_VERSION}/feedback-modal.min.js`, route => {
const filePath = path.resolve(testDir, './dist/feedback-modal.bundle.js');
return fs.existsSync(filePath) ? route.fulfill({ path: filePath }) : route.continue();
if (!fs.existsSync(filePath)) {
throw new Error(`Feedback modal bundle (${filePath}) not found`);
}
return route.fulfill({ path: filePath });
});

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

Expand Down
13 changes: 13 additions & 0 deletions dev-packages/browser-integration-tests/utils/generatePlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,19 @@ class SentryScenarioGenerationPlugin {
fileName,
);

if (integration === 'feedback') {
addStaticAssetSymlink(
this.localOutPath,
path.resolve(PACKAGES_DIR, 'feedback', 'build/bundles/feedback-modal.js'),
'feedback-modal.bundle.js',
);
addStaticAssetSymlink(
this.localOutPath,
path.resolve(PACKAGES_DIR, 'feedback', 'build/bundles/feedback-screenshot.js'),
'feedback-screenshot.bundle.js',
);
}

const integrationObject = createHtmlTagObject('script', {
src: fileName,
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ export class AppController {
return this.appService.testTransaction();
}

@Get('test-middleware-instrumentation')
testMiddlewareInstrumentation() {
return this.appService.testMiddleware();
}

@Get('test-exception/:id')
async testException(@Param('id') id: string) {
return this.appService.testException(id);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
import { Module } from '@nestjs/common';
import { MiddlewareConsumer, Module } from '@nestjs/common';
import { ScheduleModule } from '@nestjs/schedule';
import { SentryModule } from '@sentry/nestjs/setup';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { ExampleMiddleware } from './example.middleware';

@Module({
imports: [SentryModule.forRoot(), ScheduleModule.forRoot()],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
export class AppModule {
configure(consumer: MiddlewareConsumer): void {
consumer.apply(ExampleMiddleware).forRoutes('test-middleware-instrumentation');
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ export class AppService {
});
}

testMiddleware() {
// span that should not be a child span of the middleware span
Sentry.startSpan({ name: 'test-controller-span' }, () => {});
}

testException(id: string) {
throw new Error(`This is an exception with id ${id}`);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { Injectable, NestMiddleware } from '@nestjs/common';
import * as Sentry from '@sentry/nestjs';
import { NextFunction, Request, Response } from 'express';

@Injectable()
export class ExampleMiddleware implements NestMiddleware {
use(req: Request, res: Response, next: NextFunction) {
// span that should be a child span of the middleware span
Sentry.startSpan({ name: 'test-middleware-span' }, () => {});
next();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -121,3 +121,82 @@ test('Sends an API route transaction', async ({ baseURL }) => {
}),
);
});

test('API route transaction includes nest middleware span. Spans created in and after middleware are nested correctly', async ({
baseURL,
}) => {
const pageloadTransactionEventPromise = waitForTransaction('nestjs', transactionEvent => {
return (
transactionEvent?.contexts?.trace?.op === 'http.server' &&
transactionEvent?.transaction === 'GET /test-middleware-instrumentation'
);
});

await fetch(`${baseURL}/test-middleware-instrumentation`);

const transactionEvent = await pageloadTransactionEventPromise;

expect(transactionEvent).toEqual(
expect.objectContaining({
spans: expect.arrayContaining([
{
span_id: expect.any(String),
trace_id: expect.any(String),
data: {
'sentry.op': 'middleware.nestjs',
'sentry.origin': 'auto.middleware.nestjs',
},
description: 'ExampleMiddleware',
parent_span_id: expect.any(String),
start_timestamp: expect.any(Number),
timestamp: expect.any(Number),
status: 'ok',
op: 'middleware.nestjs',
origin: 'auto.middleware.nestjs',
},
]),
}),
);

const exampleMiddlewareSpan = transactionEvent.spans.find(span => span.description === 'ExampleMiddleware');
const exampleMiddlewareSpanId = exampleMiddlewareSpan?.span_id;

expect(transactionEvent).toEqual(
expect.objectContaining({
spans: expect.arrayContaining([
{
span_id: expect.any(String),
trace_id: expect.any(String),
data: expect.any(Object),
description: 'test-controller-span',
parent_span_id: expect.any(String),
start_timestamp: expect.any(Number),
timestamp: expect.any(Number),
status: 'ok',
origin: 'manual',
},
{
span_id: expect.any(String),
trace_id: expect.any(String),
data: expect.any(Object),
description: 'test-middleware-span',
parent_span_id: expect.any(String),
start_timestamp: expect.any(Number),
timestamp: expect.any(Number),
status: 'ok',
origin: 'manual',
},
]),
}),
);

// verify correct span parent-child relationships
const testMiddlewareSpan = transactionEvent.spans.find(span => span.description === 'test-middleware-span');
const testControllerSpan = transactionEvent.spans.find(span => span.description === 'test-controller-span');

// 'ExampleMiddleware' is the parent of 'test-middleware-span'
expect(testMiddlewareSpan.parent_span_id).toBe(exampleMiddlewareSpanId);

// 'ExampleMiddleware' is NOT the parent of 'test-controller-span'
expect(testControllerSpan.parent_span_id).not.toBe(exampleMiddlewareSpanId);
});
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ assert.match(buildStdout, /(λ|ƒ) \/server-component\/parameter\/\[\.\.\.parame
assert.match(buildStdout, /(λ|ƒ) \/server-component\/parameter\/\[parameter\]/);

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

export {};
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ export class AppController {
return this.appService.testTransaction();
}

@Get('test-middleware-instrumentation')
testMiddlewareInstrumentation() {
return this.appService.testMiddleware();
}

@Get('test-exception/:id')
async testException(@Param('id') id: string) {
return this.appService.testException(id);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import { Module } from '@nestjs/common';
import { MiddlewareConsumer, Module } from '@nestjs/common';
import { ScheduleModule } from '@nestjs/schedule';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { ExampleMiddleware } from './example.middleware';

@Module({
imports: [ScheduleModule.forRoot()],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
export class AppModule {
configure(consumer: MiddlewareConsumer): void {
consumer.apply(ExampleMiddleware).forRoutes('test-middleware-instrumentation');
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ export class AppService {
});
}

testMiddleware() {
// span that should not be a child span of the middleware span
Sentry.startSpan({ name: 'test-controller-span' }, () => {});
}

testException(id: string) {
throw new Error(`This is an exception with id ${id}`);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { Injectable, NestMiddleware } from '@nestjs/common';
import * as Sentry from '@sentry/nestjs';
import { NextFunction, Request, Response } from 'express';

@Injectable()
export class ExampleMiddleware implements NestMiddleware {
use(req: Request, res: Response, next: NextFunction) {
// span that should be a child span of the middleware span
Sentry.startSpan({ name: 'test-middleware-span' }, () => {});
next();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -121,3 +121,82 @@ test('Sends an API route transaction', async ({ baseURL }) => {
}),
);
});

test('API route transaction includes nest middleware span. Spans created in and after middleware are nested correctly', async ({
baseURL,
}) => {
const pageloadTransactionEventPromise = waitForTransaction('nestjs', transactionEvent => {
return (
transactionEvent?.contexts?.trace?.op === 'http.server' &&
transactionEvent?.transaction === 'GET /test-middleware-instrumentation'
);
});

await fetch(`${baseURL}/test-middleware-instrumentation`);

const transactionEvent = await pageloadTransactionEventPromise;

expect(transactionEvent).toEqual(
expect.objectContaining({
spans: expect.arrayContaining([
{
span_id: expect.any(String),
trace_id: expect.any(String),
data: {
'sentry.op': 'middleware.nestjs',
'sentry.origin': 'auto.middleware.nestjs',
},
description: 'ExampleMiddleware',
parent_span_id: expect.any(String),
start_timestamp: expect.any(Number),
timestamp: expect.any(Number),
status: 'ok',
op: 'middleware.nestjs',
origin: 'auto.middleware.nestjs',
},
]),
}),
);

const exampleMiddlewareSpan = transactionEvent.spans.find(span => span.description === 'ExampleMiddleware');
const exampleMiddlewareSpanId = exampleMiddlewareSpan?.span_id;

expect(transactionEvent).toEqual(
expect.objectContaining({
spans: expect.arrayContaining([
{
span_id: expect.any(String),
trace_id: expect.any(String),
data: expect.any(Object),
description: 'test-controller-span',
parent_span_id: expect.any(String),
start_timestamp: expect.any(Number),
timestamp: expect.any(Number),
status: 'ok',
origin: 'manual',
},
{
span_id: expect.any(String),
trace_id: expect.any(String),
data: expect.any(Object),
description: 'test-middleware-span',
parent_span_id: expect.any(String),
start_timestamp: expect.any(Number),
timestamp: expect.any(Number),
status: 'ok',
origin: 'manual',
},
]),
}),
);

// verify correct span parent-child relationships
const testMiddlewareSpan = transactionEvent.spans.find(span => span.description === 'test-middleware-span');
const testControllerSpan = transactionEvent.spans.find(span => span.description === 'test-controller-span');

// 'ExampleMiddleware' is the parent of 'test-middleware-span'
expect(testMiddlewareSpan.parent_span_id).toBe(exampleMiddlewareSpanId);

// 'ExampleMiddleware' is NOT the parent of 'test-controller-span'
expect(testControllerSpan.parent_span_id).not.toBe(exampleMiddlewareSpanId);
});
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"This is currently not an issue outside of our repo. See: https://github.com/nksaraf/vinxi/issues/177"
],
"preview": "HOST=localhost PORT=3030 NODE_OPTIONS='--import ./src/instrument.server.mjs' vinxi dev",
"start": "HOST=localhost PORT=3030 NODE_OPTIONS='--import ./src/instrument.server.mjs' vinxi start",
"test:prod": "TEST_ENV=production playwright test",
"test:build": "pnpm install && npx playwright install && pnpm build",
"test:assert": "pnpm test:prod"
Expand All @@ -31,7 +32,7 @@
"jsdom": "^24.0.0",
"solid-js": "1.8.17",
"typescript": "^5.4.5",
"vinxi": "^0.3.12",
"vinxi": "^0.4.0",
"vite": "^5.2.8",
"vite-plugin-solid": "^2.10.2",
"vitest": "^1.5.0"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Sentry.init({
tunnel: 'http://localhost:3031/', // proxy server
// Performance Monitoring
tracesSampleRate: 1.0, // Capture 100% of the transactions
debug: !!import.meta.env.DEBUG,
});

mount(() => <StartClient />, document.getElementById('app')!);
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ Sentry.init({
environment: 'qa', // dynamic sampling bias to keep transactions
tracesSampleRate: 1.0, // Capture 100% of the transactions
tunnel: 'http://localhost:3031/', // proxy server
debug: !!process.env.DEBUG,
});
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ export default function Home() {
<li>
<A href="/client-error">Client error</A>
</li>
<li>
<A href="/server-error">Server error</A>
</li>
<li>
<A id="navLink" href="/users/5">
User 5
Expand Down
Loading

0 comments on commit dd3b1aa

Please sign in to comment.