Skip to content

Commit

Permalink
Merge pull request #10330 from getsentry/prepare-release/7.96.0
Browse files Browse the repository at this point in the history
meta(changelog): Update changelog for 7.96.0
  • Loading branch information
AbhiPrasad authored Jan 24, 2024
2 parents 72bde8d + bf84267 commit 29f6031
Show file tree
Hide file tree
Showing 49 changed files with 861 additions and 892 deletions.
29 changes: 29 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,35 @@

- "You miss 100 percent of the chances you don't take. — Wayne Gretzky" — Michael Scott

## 7.96.0

### Important Changes

#### Deprecations

This release includes some deprecations for integrations in `@sentry/browser` and frontend framework SDKs
(`@sentry/react`, `@sentry/vue`, etc.). Please take a look at our
[migration guide](https://github.com/getsentry/sentry-javascript/blob/develop/MIGRATION.md) for more details.

- feat(browser): Export functional integrations & deprecate classes (#10267)

#### Web Vitals Fix for LCP and CLS

This release fixes an issue with the Web Vitals integration where LCP and CLS were not being captured correctly,
increasing capture rate by 10-30% for some apps. LCP and CLS capturing issues were introduced with version `7.75.0`.

- fix(tracing): Ensure web vitals are correctly stopped/captured (#10323)

### Other Changes

- feat(react): Add `stripBasename` option for React Router 6. (#10314)
- fix(node): Fix `node-cron` types and add test (#10315)
- fix(node): Fix downleveled types entry point (#10321)
- fix(node): LocalVariables integration should use setupOnce (#10307)
- fix(replay): Fix type for options of replayIntegration (#10325)

Work in this release contributed by @Shubhdeep12. Thank you for your contribution!

## 7.95.0

### Important Changes
Expand Down
36 changes: 25 additions & 11 deletions MIGRATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,17 +34,31 @@ integrations from the `Integrations.XXX` hash, is deprecated in favor of using t

The following list shows how integrations should be migrated:

| Old | New | Packages |
| ------------------------ | ------------------------------- | ------------------------------------------------------------------------------------------------------- |
| `new InboundFilters()` | `inboundFiltersIntegration()` | `@sentry/core`, `@sentry/browser`, `@sentry/node`, `@sentry/deno`, `@sentry/bun`, `@sentry/vercel-edge` |
| `new FunctionToString()` | `functionToStringIntegration()` | `@sentry/core`, `@sentry/browser`, `@sentry/node`, `@sentry/deno`, `@sentry/bun`, `@sentry/vercel-edge` |
| `new LinkedErrors()` | `linkedErrorsIntegration()` | `@sentry/core`, `@sentry/browser`, `@sentry/node`, `@sentry/deno`, `@sentry/bun`, `@sentry/vercel-edge` |
| `new ModuleMetadata()` | `moduleMetadataIntegration()` | `@sentry/core`, `@sentry/browser` |
| `new RequestData()` | `requestDataIntegration()` | `@sentry/core`, `@sentry/node`, `@sentry/deno`, `@sentry/bun`, `@sentry/vercel-edge` |
| `new Wasm() ` | `wasmIntegration()` | `@sentry/wasm` |
| `new Replay()` | `replayIntegration()` | `@sentry/browser` |
| `new ReplayCanvas()` | `replayCanvasIntegration()` | `@sentry/browser` |
| `new Feedback()` | `feedbackIntegration()` | `@sentry/browser` |
| Old | New | Packages |
| ------------------------- | -------------------------------- | ------------------------------------------------------------------------------------------------------- |
| `new InboundFilters()` | `inboundFiltersIntegration()` | `@sentry/core`, `@sentry/browser`, `@sentry/node`, `@sentry/deno`, `@sentry/bun`, `@sentry/vercel-edge` |
| `new FunctionToString()` | `functionToStringIntegration()` | `@sentry/core`, `@sentry/browser`, `@sentry/node`, `@sentry/deno`, `@sentry/bun`, `@sentry/vercel-edge` |
| `new LinkedErrors()` | `linkedErrorsIntegration()` | `@sentry/core`, `@sentry/browser`, `@sentry/node`, `@sentry/deno`, `@sentry/bun`, `@sentry/vercel-edge` |
| `new ModuleMetadata()` | `moduleMetadataIntegration()` | `@sentry/core`, `@sentry/browser` |
| `new RequestData()` | `requestDataIntegration()` | `@sentry/core`, `@sentry/node`, `@sentry/deno`, `@sentry/bun`, `@sentry/vercel-edge` |
| `new Wasm() ` | `wasmIntegration()` | `@sentry/wasm` |
| `new Replay()` | `replayIntegration()` | `@sentry/browser` |
| `new ReplayCanvas()` | `replayCanvasIntegration()` | `@sentry/browser` |
| `new Feedback()` | `feedbackIntegration()` | `@sentry/browser` |
| `new CaptureConsole()` | `captureConsoleIntegration()` | `@sentry/integrations` |
| `new Debug()` | `debugIntegration()` | `@sentry/integrations` |
| `new Dedupe()` | `dedupeIntegration()` | `@sentry/browser`, `@sentry/integrations`, `@sentry/deno` |
| `new ExtraErrorData()` | `extraErrorDataIntegration()` | `@sentry/integrations` |
| `new ReportingObserver()` | `reportingObserverIntegration()` | `@sentry/integrations` |
| `new RewriteFrames()` | `rewriteFramesIntegration()` | `@sentry/integrations` |
| `new SessionTiming()` | `sessionTimingIntegration()` | `@sentry/integrations` |
| `new HttpClient()` | `httpClientIntegration()` | `@sentry/integrations` |
| `new ContextLines()` | `contextLinesIntegration()` | `@sentry/browser` |
| `new Breadcrumbs()` | `breadcrumbsIntegration()` | `@sentry/browser`, `@sentry/deno` |
| `new GlobalHandlers()` | `globalHandlersIntegration()` | `@sentry/browser` |
| `new HttpContext()` | `httpContextIntegration()` | `@sentry/browser` |
| `new TryCatch()` | `browserApiErrorsIntegration()` | `@sentry/browser`, `@sentry/deno` |
| `new VueIntegration()` | `vueIntegration()` | `@sentry/vue` |

## Deprecate `hub.bindClient()` and `makeMain()`

Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { addLcpInstrumentationHandler } from '@sentry-internal/tracing';

addLcpInstrumentationHandler(({ metric }) => {
const entry = metric.entries[metric.entries.length - 1];
window._LCP = entry.size;
});

addLcpInstrumentationHandler(({ metric }) => {
const entry = metric.entries[metric.entries.length - 1];
window._LCP2 = entry.size;
});

window.ADD_HANDLER = () => {
addLcpInstrumentationHandler(({ metric }) => {
const entry = metric.entries[metric.entries.length - 1];
window._LCP3 = entry.size;
});
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
</head>
<body>
<div id="content"></div>
<img src="https://example.com/path/to/image.png" />
<button type="button">Test button</button>
</body>
</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import type { Route } from '@playwright/test';
import { expect } from '@playwright/test';
import type { Event } from '@sentry/types';

import { sentryTest } from '../../../../utils/fixtures';
import { getFirstSentryEnvelopeRequest, shouldSkipTracingTest } from '../../../../utils/helpers';

const bundle = process.env.PW_BUNDLE || '';

sentryTest(
'should capture metrics for LCP instrumentation handlers',
async ({ browserName, getLocalTestPath, page }) => {
// This uses a utility that is not exported in CDN bundles
if (shouldSkipTracingTest() || browserName !== 'chromium' || bundle.startsWith('bundle')) {
sentryTest.skip();
}

await page.route('**/path/to/image.png', (route: Route) =>
route.fulfill({ path: `${__dirname}/assets/sentry-logo-600x179.png` }),
);

const url = await getLocalTestPath({ testDir: __dirname });
const [eventData] = await Promise.all([
getFirstSentryEnvelopeRequest<Event>(page),
page.goto(url),
page.click('button'),
]);

expect(eventData.measurements).toBeDefined();
expect(eventData.measurements?.lcp?.value).toBeDefined();

expect(eventData.tags?.['lcp.element']).toBe('body > img');
expect(eventData.tags?.['lcp.size']).toBe(107400);
expect(eventData.tags?.['lcp.url']).toBe('https://example.com/path/to/image.png');

const lcp = await (await page.waitForFunction('window._LCP')).jsonValue();
const lcp2 = await (await page.waitForFunction('window._LCP2')).jsonValue();
const lcp3 = await page.evaluate('window._LCP3');

expect(lcp).toEqual(107400);
expect(lcp2).toEqual(107400);
// this has not been triggered yet
expect(lcp3).toEqual(undefined);

// Adding a handler after LCP is completed still triggers the handler
await page.evaluate('window.ADD_HANDLER()');
const lcp3_2 = await (await page.waitForFunction('window._LCP3')).jsonValue();

expect(lcp3_2).toEqual(107400);
},
);
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,11 @@ export const ReplayRecordingData = [
description: 'largest-contentful-paint',
startTimestamp: expect.any(Number),
endTimestamp: expect.any(Number),
data: { value: expect.any(Number), size: expect.any(Number) },
data: {
value: expect.any(Number),
size: expect.any(Number),
nodeId: 16,
},
},
},
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,11 @@ export const ReplayRecordingData = [
description: 'largest-contentful-paint',
startTimestamp: expect.any(Number),
endTimestamp: expect.any(Number),
data: { value: expect.any(Number), size: expect.any(Number) },
data: {
value: expect.any(Number),
size: expect.any(Number),
nodeId: 16,
},
},
},
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,11 @@ export const ReplayRecordingData = [
description: 'largest-contentful-paint',
startTimestamp: expect.any(Number),
endTimestamp: expect.any(Number),
data: { value: expect.any(Number), size: expect.any(Number) },
data: {
value: expect.any(Number),
size: expect.any(Number),
nodeId: 16,
},
},
},
},
Expand Down
2 changes: 2 additions & 0 deletions dev-packages/node-integration-tests/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,12 @@
"apollo-server": "^3.11.1",
"axios": "^0.27.2",
"cors": "^2.8.5",
"cron": "^3.1.6",
"express": "^4.17.3",
"graphql": "^16.3.0",
"http-terminator": "^3.2.0",
"mongodb": "^3.7.3",
"mongoose": "^5.13.22",
"mongodb-memory-server-global": "^7.6.3",
"mysql": "^2.18.1",
"nock": "^13.1.0",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import * as Sentry from '@sentry/node';
import { CronJob } from 'cron';

// eslint-disable-next-line @typescript-eslint/no-unused-vars
const CronJobWithCheckIn = Sentry.cron.instrumentCron(CronJob, 'my-cron-job');

setTimeout(() => {
process.exit(0);
}, 1_000);
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { cleanupChildProcesses, createRunner } from '../../../utils/runner';

afterAll(() => {
cleanupChildProcesses();
});

test('node-cron types should match', done => {
createRunner(__dirname, 'scenario.ts').ensureNoErrorOutput().start(done);
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
const Sentry = require('@sentry/node-experimental');
const { loggingTransport } = require('@sentry-internal/node-integration-tests');

Sentry.init({
dsn: 'https://public@dsn.ingest.sentry.io/1337',
release: '1.0',
tracesSampleRate: 1.0,
transport: loggingTransport,
});

// Stop the process from exiting before the transaction is sent
setInterval(() => {}, 1000);

async function run() {
const { ApolloServer, gql } = require('apollo-server');

await Sentry.startSpan(
{
name: 'Test Transaction',
op: 'transaction',
},
async span => {
const typeDefs = gql`type Query { hello: String }`;

const resolvers = {
Query: {
hello: () => {
return 'Hello world!';
},
},
};

const server = new ApolloServer({
typeDefs,
resolvers,
});

// Ref: https://www.apollographql.com/docs/apollo-server/testing/testing/#testing-using-executeoperation
await server.executeOperation({
query: '{hello}',
});

setTimeout(() => {
span.end();
server.stop();
}, 500);
},
);
}

// eslint-disable-next-line @typescript-eslint/no-floating-promises
run();
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { conditionalTest } from '../../../utils';
import { createRunner } from '../../../utils/runner';

conditionalTest({ min: 14 })('GraphQL/Apollo Tests', () => {
const EXPECTED_TRANSACTION = {
transaction: 'Test Transaction',
spans: expect.arrayContaining([
expect.objectContaining({
data: {
'graphql.operation.type': 'query',
'graphql.source': '{hello}',
'otel.kind': 'INTERNAL',
'sentry.origin': 'auto.graphql.otel.graphql',
},
description: 'query',
status: 'ok',
origin: 'auto.graphql.otel.graphql',
}),
expect.objectContaining({
data: {
'graphql.field.name': 'hello',
'graphql.field.path': 'hello',
'graphql.field.type': 'String',
'graphql.source': 'hello',
'otel.kind': 'INTERNAL',
'sentry.origin': 'manual',
},
description: 'graphql.resolve',
status: 'ok',
origin: 'manual',
}),
]),
};

test('CJS - should instrument GraphQL queries used from Apollo Server.', done => {
createRunner(__dirname, 'scenario.js').expect({ transaction: EXPECTED_TRANSACTION }).start(done);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
const { loggingTransport } = require('@sentry-internal/node-integration-tests');
const Sentry = require('@sentry/node-experimental');

Sentry.init({
dsn: 'https://public@dsn.ingest.sentry.io/1337',
release: '1.0',
debug: true,
tracesSampleRate: 1.0,
transport: loggingTransport,
});

// Stop the process from exiting before the transaction is sent
setInterval(() => {}, 1000);

// Must be required after Sentry is initialized
const mongoose = require('mongoose');

async function run() {
await mongoose.connect(process.env.MONGO_URL || '');

const Schema = mongoose.Schema;

const BlogPostSchema = new Schema({
title: String,
body: String,
date: Date,
});

const BlogPost = mongoose.model('BlogPost', BlogPostSchema);

await Sentry.startSpan(
{
name: 'Test Transaction',
op: 'transaction',
},
async () => {
const post = new BlogPost();
post.title = 'Test';
post.body = 'Test body';
post.date = new Date();

await post.save();

await BlogPost.findOne({});
},
);
}

// eslint-disable-next-line @typescript-eslint/no-floating-promises
run();
Loading

0 comments on commit 29f6031

Please sign in to comment.