Skip to content

Commit

Permalink
Merge pull request #9596 from getsentry/prepare-release/7.81.0
Browse files Browse the repository at this point in the history
  • Loading branch information
lforst committed Nov 20, 2023
2 parents 3d8f692 + 4ff96ec commit feeb70a
Show file tree
Hide file tree
Showing 76 changed files with 1,518 additions and 411 deletions.
3 changes: 2 additions & 1 deletion .github/workflows/codeql-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ concurrency:
jobs:
analyze:
name: Analyze
runs-on: ubuntu-20.04
runs-on: ubuntu-latest

strategy:
fail-fast: false
Expand All @@ -51,6 +51,7 @@ jobs:
uses: github/codeql-action/init@v2
with:
config-file: ./.github/codeql/codeql-config.yml
queries: security-extended
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
Expand Down
53 changes: 53 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,59 @@

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

## 7.81.0

### Important Changes

**- feat(nextjs): Add instrumentation utility for server actions (#9553)**

This release adds a utility function `withServerActionInstrumentation` to the `@sentry/nextjs` SDK for instrumenting your Next.js server actions with error and performance monitoring.

You can optionally pass form data and headers to record them, and configure the wrapper to record the Server Action responses:

```tsx
import * as Sentry from "@sentry/nextjs";
import { headers } from "next/headers";

export default function ServerComponent() {
async function myServerAction(formData: FormData) {
"use server";
return await Sentry.withServerActionInstrumentation(
"myServerAction", // The name you want to associate this Server Action with in Sentry
{
formData, // Optionally pass in the form data
headers: headers(), // Optionally pass in headers
recordResponse: true, // Optionally record the server action response
},
async () => {
// ... Your Server Action code

return { name: "John Doe" };
}
);
}

return (
<form action={myServerAction}>
<input type="text" name="some-input-value" />
<button type="submit">Run Action</button>
</form>
);
}
```

### Other Changes

- docs(feedback): Example docs on `sendFeedback` (#9560)
- feat(feedback): Add `level` and remove breadcrumbs from feedback event (#9533)
- feat(vercel-edge): Add fetch instrumentation (#9504)
- feat(vue): Support Vue 3 lifecycle hooks in mixin options (#9578)
- fix(nextjs): Download CLI binary if it can't be found (#9584)
- ref: Deprecate `extractTraceParentData` from `@sentry/core` & downstream packages (#9158)
- ref(replay): Add further logging to network body parsing (#9566)

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

## 7.80.1

- fix(astro): Adjust Vite plugin config to upload server source maps (#9541)
Expand Down
6 changes: 6 additions & 0 deletions MIGRATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ npx @sentry/migr8@latest

This will let you select which updates to run, and automatically update your code. Make sure to still review all code changes!

## Deprecate `extractTraceParentData` export from `@sentry/core` & downstream packages

Instead, import this directly from `@sentry/utils`.

Generally, in most cases you should probably use `continueTrace` instead, which abstracts this away from you and handles scope propagation for you.

## Deprecate `timestampWithMs` export - #7878

The `timestampWithMs` util is deprecated in favor of using `timestampInSeconds`.
Expand Down
1 change: 1 addition & 0 deletions packages/astro/src/index.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export {
withMonitor,
configureScope,
createTransport,
// eslint-disable-next-line deprecation/deprecation
extractTraceparentData,
getActiveTransaction,
getHubFromCarrier,
Expand Down
2 changes: 1 addition & 1 deletion packages/browser-integration-tests/fixtures/loader.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
new Promise(function (resolve, reject) {
reject('this is unhandled');
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { expect } from '@playwright/test';

import { sentryTest } from '../../../../utils/fixtures';
import { envelopeRequestParser, waitForErrorRequestOnUrl } from '../../../../utils/helpers';

sentryTest('unhandled promise rejection handler works', async ({ getLocalTestUrl, page }) => {
const url = await getLocalTestUrl({ testDir: __dirname });
const req = await waitForErrorRequestOnUrl(page, url);

const eventData = envelopeRequestParser(req);
expect(eventData.exception?.values?.length).toBe(1);
expect(eventData.exception?.values?.[0]?.value).toBe(
'Non-Error promise rejection captured with value: this is unhandled',
);
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import * as Sentry from '@sentry/browser';
import { Feedback } from '@sentry-internal/feedback';

window.Sentry = Sentry;

Sentry.init({
dsn: 'https://public@dsn.ingest.sentry.io/1337',
integrations: [new Feedback()],
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
</head>
<body></body>
</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { expect } from '@playwright/test';

import { sentryTest } from '../../../utils/fixtures';
import { envelopeRequestParser, getEnvelopeType } from '../../../utils/helpers';

sentryTest('should capture feedback (@sentry-internal/feedback import)', async ({ getLocalTestPath, page }) => {
if (process.env.PW_BUNDLE) {
sentryTest.skip();
}

const feedbackRequestPromise = page.waitForResponse(res => {
const req = res.request();

const postData = req.postData();
if (!postData) {
return false;
}

try {
return getEnvelopeType(req) === 'feedback';
} catch (err) {
return false;
}
});

await page.route('https://dsn.ingest.sentry.io/**/*', route => {
return route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify({ id: 'test-id' }),
});
});

const url = await getLocalTestPath({ testDir: __dirname });

await page.goto(url);
await page.getByText('Report a Bug').click();
expect(await page.locator(':visible:text-is("Report a Bug")').count()).toEqual(1);
await page.locator('[name="name"]').fill('Jane Doe');
await page.locator('[name="email"]').fill('janedoe@example.org');
await page.locator('[name="message"]').fill('my example feedback');
await page.getByLabel('Send Bug Report').click();

const feedbackEvent = envelopeRequestParser((await feedbackRequestPromise).request());
expect(feedbackEvent).toEqual({
type: 'feedback',
contexts: {
feedback: {
contact_email: 'janedoe@example.org',
message: 'my example feedback',
name: 'Jane Doe',
source: 'widget',
url: expect.stringContaining('/dist/index.html'),
},
},
level: 'info',
timestamp: expect.any(Number),
event_id: expect.stringMatching(/\w{32}/),
environment: 'production',
sdk: {
integrations: expect.arrayContaining(['Feedback']),
version: expect.any(String),
name: 'sentry.javascript.browser',
packages: expect.anything(),
},
request: {
url: expect.stringContaining('/dist/index.html'),
headers: {
'User-Agent': expect.stringContaining(''),
},
},
platform: 'javascript',
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import * as Sentry from '@sentry/browser';
import { Feedback } from '@sentry-internal/feedback';

window.Sentry = Sentry;

Sentry.init({
dsn: 'https://public@dsn.ingest.sentry.io/1337',
replaysOnErrorSampleRate: 1.0,
replaysSessionSampleRate: 0,
integrations: [
new Sentry.Replay({
flushMinDelay: 200,
flushMaxDelay: 200,
minReplayDuration: 0,
}),
new Feedback(),
],
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
</head>
<body></body>
</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import { expect } from '@playwright/test';

import { sentryTest } from '../../../utils/fixtures';
import { envelopeRequestParser, getEnvelopeType } from '../../../utils/helpers';
import { getCustomRecordingEvents, getReplayEvent, waitForReplayRequest } from '../../../utils/replayHelpers';

sentryTest('should capture feedback (@sentry-internal/feedback import)', async ({ getLocalTestPath, page }) => {
if (process.env.PW_BUNDLE) {
sentryTest.skip();
}

const reqPromise0 = waitForReplayRequest(page, 0);
const feedbackRequestPromise = page.waitForResponse(res => {
const req = res.request();

const postData = req.postData();
if (!postData) {
return false;
}

try {
return getEnvelopeType(req) === 'feedback';
} catch (err) {
return false;
}
});

await page.route('https://dsn.ingest.sentry.io/**/*', route => {
return route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify({ id: 'test-id' }),
});
});

const url = await getLocalTestPath({ testDir: __dirname });

await page.goto(url);
await page.getByText('Report a Bug').click();
await page.locator('[name="name"]').fill('Jane Doe');
await page.locator('[name="email"]').fill('janedoe@example.org');
await page.locator('[name="message"]').fill('my example feedback');
await page.getByLabel('Send Bug Report').click();

const [feedbackResp, replayReq] = await Promise.all([feedbackRequestPromise, reqPromise0]);

const feedbackEvent = envelopeRequestParser(feedbackResp.request());
const replayEvent = getReplayEvent(replayReq);
const { breadcrumbs } = getCustomRecordingEvents(replayReq);

expect(breadcrumbs).toEqual(
expect.arrayContaining([
{
category: 'sentry.feedback',
data: { feedbackId: expect.any(String) },
},
]),
);

expect(feedbackEvent).toEqual({
type: 'feedback',
contexts: {
feedback: {
contact_email: 'janedoe@example.org',
message: 'my example feedback',
name: 'Jane Doe',
replay_id: replayEvent.event_id,
source: 'widget',
url: expect.stringContaining('/dist/index.html'),
},
},
level: 'info',
timestamp: expect.any(Number),
event_id: expect.stringMatching(/\w{32}/),
environment: 'production',
sdk: {
integrations: expect.arrayContaining(['Feedback']),
version: expect.any(String),
name: 'sentry.javascript.browser',
packages: expect.anything(),
},
request: {
url: expect.stringContaining('/dist/index.html'),
headers: {
'User-Agent': expect.stringContaining(''),
},
},
platform: 'javascript',
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import {
BrowserClient,
Breadcrumbs,
Dedupe,
FunctionToString,
HttpContext,
InboundFilters,
LinkedErrors,
defaultStackParser,
makeFetchTransport,
Hub,
} from '@sentry/browser';

const integrations = [
new Breadcrumbs(),
new FunctionToString(),
new Dedupe(),
new HttpContext(),
new InboundFilters(),
new LinkedErrors(),
];

const client = new BrowserClient({
dsn: 'https://public@dsn.ingest.sentry.io/1337',
release: '0.0.1',
environment: 'local',
sampleRate: 1.0,
tracesSampleRate: 0.0,
transport: makeFetchTransport,
stackParser: defaultStackParser,
integrations,
debug: true,
});

const hub = new Hub(client);

hub.captureException(new Error('test client'));

0 comments on commit feeb70a

Please sign in to comment.