Skip to content

Commit

Permalink
Merge branch 'develop' into sig/sveltekit-sourcemaps-enabled
Browse files Browse the repository at this point in the history
  • Loading branch information
s1gr1d authored Jan 7, 2025
2 parents f896f36 + c347dae commit 28884c0
Show file tree
Hide file tree
Showing 47 changed files with 374 additions and 1,394 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,16 @@ import { expect } from '@playwright/test';
import type { SessionContext } from '@sentry/core';

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

sentryTest('should update session when an error is thrown.', async ({ getLocalTestUrl, page }) => {
const url = await getLocalTestUrl({ testDir: __dirname });

const pageloadSession = await getFirstSentryEnvelopeRequest<SessionContext>(page, url);
const updatedSession = (
await Promise.all([page.locator('#throw-error').click(), getFirstSentryEnvelopeRequest<SessionContext>(page)])
)[1];

const updatedSessionPromise = waitForSession(page);
await page.locator('#throw-error').click();
const updatedSession = await updatedSessionPromise;

expect(pageloadSession).toBeDefined();
expect(pageloadSession.init).toBe(true);
Expand All @@ -25,9 +27,10 @@ sentryTest('should update session when an exception is captured.', async ({ getL
const url = await getLocalTestUrl({ testDir: __dirname });

const pageloadSession = await getFirstSentryEnvelopeRequest<SessionContext>(page, url);
const updatedSession = (
await Promise.all([page.locator('#capture-exception').click(), getFirstSentryEnvelopeRequest<SessionContext>(page)])
)[1];

const updatedSessionPromise = waitForSession(page);
await page.locator('#capture-exception').click();
const updatedSession = await updatedSessionPromise;

expect(pageloadSession).toBeDefined();
expect(pageloadSession.init).toBe(true);
Expand Down
30 changes: 24 additions & 6 deletions dev-packages/browser-integration-tests/utils/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import type {
Event,
EventEnvelope,
EventEnvelopeHeaders,
SessionContext,
TransactionEvent,
} from '@sentry/core';

Expand Down Expand Up @@ -157,7 +158,7 @@ export const countEnvelopes = async (
* @param {{ path?: string; content?: string }} impl
* @return {*} {Promise<void>}
*/
async function runScriptInSandbox(
export async function runScriptInSandbox(
page: Page,
impl: {
path?: string;
Expand All @@ -178,7 +179,7 @@ async function runScriptInSandbox(
* @param {string} [url]
* @return {*} {Promise<Array<Event>>}
*/
async function getSentryEvents(page: Page, url?: string): Promise<Array<Event>> {
export async function getSentryEvents(page: Page, url?: string): Promise<Array<Event>> {
if (url) {
await page.goto(url);
}
Expand Down Expand Up @@ -250,6 +251,25 @@ export function waitForTransactionRequest(
});
}

export async function waitForSession(page: Page): Promise<SessionContext> {
const req = await page.waitForRequest(req => {
const postData = req.postData();
if (!postData) {
return false;
}

try {
const event = envelopeRequestParser<SessionContext>(req);

return typeof event.init === 'boolean' && event.started !== undefined;
} catch {
return false;
}
});

return envelopeRequestParser<SessionContext>(req);
}

/**
* We can only test tracing tests in certain bundles/packages:
* - NPM (ESM, CJS)
Expand Down Expand Up @@ -353,7 +373,7 @@ async function getMultipleRequests<T>(
/**
* Wait and get multiple envelope requests at the given URL, or the current page
*/
async function getMultipleSentryEnvelopeRequests<T>(
export async function getMultipleSentryEnvelopeRequests<T>(
page: Page,
count: number,
options?: {
Expand All @@ -374,7 +394,7 @@ async function getMultipleSentryEnvelopeRequests<T>(
* @param {string} [url]
* @return {*} {Promise<T>}
*/
async function getFirstSentryEnvelopeRequest<T>(
export async function getFirstSentryEnvelopeRequest<T>(
page: Page,
url?: string,
requestParser: (req: Request) => T = envelopeRequestParser as (req: Request) => T,
Expand All @@ -388,5 +408,3 @@ async function getFirstSentryEnvelopeRequest<T>(

return req;
}

export { runScriptInSandbox, getMultipleSentryEnvelopeRequests, getFirstSentryEnvelopeRequest, getSentryEvents };
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
const { loggingTransport } = require('@sentry-internal/node-integration-tests');
const Sentry = require('@sentry/node');

Sentry.init({
dsn: 'https://[email protected]/1337',
release: '1.0',
transport: loggingTransport,
tracesSampler: samplingContext => {
// The sampling decision is based on whether the data in `normalizedRequest` is available --> this is what we want to test for
return (
samplingContext.normalizedRequest.url.includes('/test-normalized-request?query=123') &&
samplingContext.normalizedRequest.method &&
samplingContext.normalizedRequest.query_string === 'query=123' &&
!!samplingContext.normalizedRequest.headers
);
},
});

// express must be required after Sentry is initialized
const express = require('express');
const cors = require('cors');
const { startExpressServerAndSendPortToRunner } = require('@sentry-internal/node-integration-tests');

const app = express();

app.use(cors());

app.get('/test-normalized-request', (_req, res) => {
res.send('Success');
});

Sentry.setupExpressErrorHandler(app);

startExpressServerAndSendPortToRunner(app);
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ Sentry.init({
samplingContext.attributes['http.method'] === 'GET'
);
},
debug: true,
});

// express must be required after Sentry is initialized
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,23 @@ describe('express tracesSampler', () => {
});
});
});

describe('express tracesSampler includes normalizedRequest data', () => {
afterAll(() => {
cleanupChildProcesses();
});

describe('CJS', () => {
test('correctly samples & passes data to tracesSampler', done => {
const runner = createRunner(__dirname, 'scenario-normalizedRequest.js')
.expect({
transaction: {
transaction: 'GET /test-normalized-request',
},
})
.start(done);

runner.makeRequest('get', '/test-normalized-request?query=123');
});
});
});
16 changes: 15 additions & 1 deletion docs/migration/v8-to-v9.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ Sentry.init({

In v9, an `undefined` value will be treated the same as if the value is not defined at all. You'll need to set `tracesSampleRate: 0` if you want to enable tracing without performance.

- The `getCurrentHub().getIntegration(IntegrationClass)` method will always return `null` in v9. This has already stopped working mostly in v8, because we stopped exposing integration classes. In v9, the fallback behavior has been removed. Note that this does not change the type signature and is thus not technically breaking, but still worth pointing out.

### `@sentry/node`

- When `skipOpenTelemetrySetup: true` is configured, `httpIntegration({ spans: false })` will be configured by default. This means that you no longer have to specify this yourself in this scenario. With this change, no spans are emitted once `skipOpenTelemetrySetup: true` is configured, without any further configuration being needed.
Expand Down Expand Up @@ -141,8 +143,16 @@ Sentry.init({
- The `flatten` export has been removed. There is no replacement.
- The `urlEncode` method has been removed. There is no replacement.
- The `getDomElement` method has been removed. There is no replacement.
- The `Request` type has been removed. Use `RequestEventData` type instead.
- The `memoBuilder` method has been removed. There is no replacement.
- The `extractRequestData` method has been removed. Manually extract relevant data off request instead.
- The `addRequestDataToEvent` method has been removed. Use `addNormalizedRequestDataToEvent` instead.
- The `extractPathForTransaction` method has been removed. There is no replacement.

#### Other/Internal Changes

The following changes are unlikely to affect users of the SDK. They are listed here only for completion sake, and to alert users that may be relying on internal behavior.

- `client._prepareEvent()` now requires a currentScope & isolationScope to be passed as last arugments

### `@sentry/browser`

Expand Down Expand Up @@ -207,6 +217,10 @@ This led to some duplication, where we had to keep an interface in `@sentry/type
Since v9, the types have been merged into `@sentry/core`, which removed some of this duplication. This means that certain things that used to be a separate interface, will not expect an actual instance of the class/concrete implementation. This should not affect most users, unless you relied on passing things with a similar shape to internal methods. The following types are affected:

- `Scope` now always expects the `Scope` class
- The `TransactionNamingScheme` type has been removed. There is no replacement.
- The `Request` type has been removed. Use `RequestEventData` type instead.
- The `IntegrationClass` type is no longer exported - it was not used anymore. Instead, use `Integration` or `IntegrationFn`.
- The `samplingContext.request` attribute in the `tracesSampler` has been removed. Use `samplingContext.normalizedRequest` instead. Note that the type of `normalizedRequest` differs from `request`.

# No Version Support Timeline

Expand Down
4 changes: 4 additions & 0 deletions packages/angular/.eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,8 @@ module.exports = {
},
extends: ['../../.eslintrc.js'],
ignorePatterns: ['setup-test.ts', 'patch-vitest.ts'],
rules: {
// Angular transpiles this correctly/relies on this
'@sentry-internal/sdk/no-class-field-initializers': 'off',
},
};
4 changes: 0 additions & 4 deletions packages/astro/src/index.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ export {
addBreadcrumb,
addEventProcessor,
addIntegration,
// eslint-disable-next-line deprecation/deprecation
addRequestDataToEvent,
amqplibIntegration,
anrIntegration,
disableAnrDetectionForCallback,
Expand All @@ -38,8 +36,6 @@ export {
endSession,
expressErrorHandler,
expressIntegration,
// eslint-disable-next-line deprecation/deprecation
extractRequestData,
extraErrorDataIntegration,
fastifyIntegration,
flush,
Expand Down
4 changes: 0 additions & 4 deletions packages/aws-serverless/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,7 @@ export {
flush,
close,
getSentryRelease,
// eslint-disable-next-line deprecation/deprecation
addRequestDataToEvent,
DEFAULT_USER_INCLUDES,
// eslint-disable-next-line deprecation/deprecation
extractRequestData,
createGetModuleFromFilename,
anrIntegration,
disableAnrDetectionForCallback,
Expand Down
2 changes: 1 addition & 1 deletion packages/aws-serverless/src/sdk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export interface WrapperOptions {
captureAllSettledReasons: boolean;
/**
* Automatically trace all handler invocations.
* You may want to disable this if you use express within Lambda (use tracingHandler instead).
* You may want to disable this if you use express within Lambda.
* @default true
*/
startTrace: boolean;
Expand Down
9 changes: 7 additions & 2 deletions packages/browser/src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,13 @@ export class BrowserClient extends BaseClient<BrowserClientOptions> {
/**
* @inheritDoc
*/
protected _prepareEvent(event: Event, hint: EventHint, scope?: Scope): PromiseLike<Event | null> {
protected _prepareEvent(
event: Event,
hint: EventHint,
currentScope: Scope,
isolationScope: Scope,
): PromiseLike<Event | null> {
event.platform = event.platform || 'javascript';
return super._prepareEvent(event, hint, scope);
return super._prepareEvent(event, hint, currentScope, isolationScope);
}
}
2 changes: 0 additions & 2 deletions packages/browser/src/feedbackSync.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,9 @@ import {
feedbackModalIntegration,
feedbackScreenshotIntegration,
} from '@sentry-internal/feedback';
import { lazyLoadIntegration } from './utils/lazyLoadIntegration';

/** Add a widget to capture user feedback to your application. */
export const feedbackSyncIntegration = buildFeedbackIntegration({
lazyLoadIntegration,
getModalIntegration: () => feedbackModalIntegration,
getScreenshotIntegration: () => feedbackScreenshotIntegration,
});
4 changes: 0 additions & 4 deletions packages/bun/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,7 @@ export {
flush,
close,
getSentryRelease,
// eslint-disable-next-line deprecation/deprecation
addRequestDataToEvent,
DEFAULT_USER_INCLUDES,
// eslint-disable-next-line deprecation/deprecation
extractRequestData,
createGetModuleFromFilename,
anrIntegration,
disableAnrDetectionForCallback,
Expand Down
36 changes: 23 additions & 13 deletions packages/core/src/baseclient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -216,8 +216,11 @@ export abstract class BaseClient<O extends ClientOptions> implements Client<O> {

const sdkProcessingMetadata = event.sdkProcessingMetadata || {};
const capturedSpanScope: Scope | undefined = sdkProcessingMetadata.capturedSpanScope;
const capturedSpanIsolationScope: Scope | undefined = sdkProcessingMetadata.capturedSpanIsolationScope;

this._process(this._captureEvent(event, hintWithEventId, capturedSpanScope || currentScope));
this._process(
this._captureEvent(event, hintWithEventId, capturedSpanScope || currentScope, capturedSpanIsolationScope),
);

return hintWithEventId.event_id;
}
Expand Down Expand Up @@ -676,8 +679,8 @@ export abstract class BaseClient<O extends ClientOptions> implements Client<O> {
protected _prepareEvent(
event: Event,
hint: EventHint,
currentScope = getCurrentScope(),
isolationScope = getIsolationScope(),
currentScope: Scope,
isolationScope: Scope,
): PromiseLike<Event | null> {
const options = this.getOptions();
const integrations = Object.keys(this._integrations);
Expand Down Expand Up @@ -718,12 +721,17 @@ export abstract class BaseClient<O extends ClientOptions> implements Client<O> {
* @param hint
* @param scope
*/
protected _captureEvent(event: Event, hint: EventHint = {}, scope?: Scope): PromiseLike<string | undefined> {
protected _captureEvent(
event: Event,
hint: EventHint = {},
currentScope = getCurrentScope(),
isolationScope = getIsolationScope(),
): PromiseLike<string | undefined> {
if (DEBUG_BUILD && isErrorEvent(event)) {
logger.log(`Captured error event \`${getPossibleEventMessages(event)[0] || '<unknown>'}\``);
}

return this._processEvent(event, hint, scope).then(
return this._processEvent(event, hint, currentScope, isolationScope).then(
finalEvent => {
return finalEvent.event_id;
},
Expand Down Expand Up @@ -756,7 +764,12 @@ export abstract class BaseClient<O extends ClientOptions> implements Client<O> {
* @param currentScope A scope containing event metadata.
* @returns A SyncPromise that resolves with the event or rejects in case event was/will not be send.
*/
protected _processEvent(event: Event, hint: EventHint, currentScope?: Scope): PromiseLike<Event> {
protected _processEvent(
event: Event,
hint: EventHint,
currentScope: Scope,
isolationScope: Scope,
): PromiseLike<Event> {
const options = this.getOptions();
const { sampleRate } = options;

Expand All @@ -779,12 +792,9 @@ export abstract class BaseClient<O extends ClientOptions> implements Client<O> {
);
}

const dataCategory: DataCategory = eventType === 'replay_event' ? 'replay' : eventType;

const sdkProcessingMetadata = event.sdkProcessingMetadata || {};
const capturedSpanIsolationScope: Scope | undefined = sdkProcessingMetadata.capturedSpanIsolationScope;
const dataCategory = (eventType === 'replay_event' ? 'replay' : eventType) satisfies DataCategory;

return this._prepareEvent(event, hint, currentScope, capturedSpanIsolationScope)
return this._prepareEvent(event, hint, currentScope, isolationScope)
.then(prepared => {
if (prepared === null) {
this.recordDroppedEvent('event_processor', dataCategory, event);
Expand All @@ -811,8 +821,8 @@ export abstract class BaseClient<O extends ClientOptions> implements Client<O> {
throw new SentryError(`${beforeSendLabel} returned \`null\`, will not send event.`, 'log');
}

const session = currentScope && currentScope.getSession();
if (!isTransaction && session) {
const session = currentScope.getSession() || isolationScope.getSession();
if (isError && session) {
this._updateSessionFromEvent(session, processedEvent);
}

Expand Down
Loading

0 comments on commit 28884c0

Please sign in to comment.