Skip to content

meta(changelog): Update changelog for v8.0.0-beta.1 #11613

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Apr 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

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

## 8.0.0-beta.0
## 8.0.0-beta.1

This is the first beta release of Sentry JavaScript SDK v8. With this release, there are no more planned breaking
changes for the v8 cycle.
Expand Down Expand Up @@ -144,6 +144,10 @@ disabled.
- ref(feedback): Configure font size (#11437)
- ref(feedback): Refactor Feedback types into @sentry/types and reduce the exported surface area (#11355)

## 8.0.0-beta.0

This release failed to publish correctly. Use 8.0.0-beta.1 instead.

## 8.0.0-alpha.9

This is the eighth alpha release of Sentry JavaScript SDK v8, which includes a variety of breaking changes.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,19 @@
import { expect } from '@playwright/test';
import { SDK_VERSION } from '@sentry/browser';

import { sentryTest } from '../../../../utils/fixtures';

sentryTest('it allows to lazy load an integration', async ({ getLocalTestUrl, page }) => {
const url = await getLocalTestUrl({ testDir: __dirname });

await page.route(`https://browser.sentry-cdn.com/${SDK_VERSION}/httpclient.min.js`, route => {
return route.fulfill({
status: 200,
contentType: 'application/javascript;',
body: "window.Sentry.httpClientIntegration = () => ({ name: 'HttpClient' })",
});
});

await page.goto(url);

const hasIntegration = await page.evaluate('!!window.Sentry.getClient()?.getIntegrationByName("HttpClient")');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,28 @@ sentryTest('should create a new trace on each navigation', async ({ getLocalTest
expect(navigation2TraceId).toMatch(/^[0-9a-f]{32}$/);
expect(navigation1TraceId).not.toEqual(navigation2TraceId);
});

sentryTest('error after navigation has navigation traceId', async ({ getLocalTestPath, page }) => {
if (shouldSkipTracingTest()) {
sentryTest.skip();
}

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

// ensure navigation transaction is finished
await getFirstSentryEnvelopeRequest<Event>(page, url);

const navigationEvent1 = await getFirstSentryEnvelopeRequest<Event>(page, `${url}#foo`);
expect(navigationEvent1.contexts?.trace?.op).toBe('navigation');

const navigationTraceId = navigationEvent1.contexts?.trace?.trace_id;
expect(navigationTraceId).toMatch(/^[0-9a-f]{32}$/);

const [, errorEvent] = await Promise.all([
page.locator('#errorBtn').click(),
getFirstSentryEnvelopeRequest<Event>(page),
]);

const errorTraceId = errorEvent.contexts?.trace?.trace_id;
expect(errorTraceId).toBe(navigationTraceId);
});
46 changes: 28 additions & 18 deletions packages/nextjs/src/common/wrapRouteHandlerWithSentry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
getRootSpan,
handleCallbackErrors,
setHttpStatus,
spanToJSON,
startSpan,
} from '@sentry/core';
import type { Span } from '@sentry/types';
Expand All @@ -24,32 +25,41 @@ function startOrUpdateSpan(spanName: string, cb: (rootSpan: Span) => Promise<Res
const activeSpan = getActiveSpan();
const rootSpan = activeSpan && getRootSpan(activeSpan);

if (rootSpan) {
rootSpan.updateName(spanName);
rootSpan.setAttributes({
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'route',
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'http.server',
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.nextjs',
});
// We have different possible scenarios here:
// 1. If we have no root span, we just create a new span
// 2. We have a root span that that we want to update here
// 3. We have a root span that was already updated (e.g. if this is a nested call)

return cb(rootSpan);
} else {
const attributes = {
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'route',
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'http.server',
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.nextjs',
} as const;

if (!rootSpan) {
return startSpan(
{
op: 'http.server',
name: spanName,
forceTransaction: true,
attributes: {
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'route',
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'http.server',
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.nextjs',
},
},
(span: Span) => {
return cb(span);
attributes,
},
cb,
);
}

// If `op` is set, we assume this was already processed before
// Probably this is a nested call, no need to update anything anymore
// OR, if we don't have next.span_type, we don't know where this comes from and don't want to mess with it
const existingAttributes = spanToJSON(rootSpan).data || {};
if (existingAttributes[SEMANTIC_ATTRIBUTE_SENTRY_OP] || !existingAttributes['next.span_type']) {
return cb(rootSpan);
}

// Finally, we want to update the root span, as the ones generated by next are often not good enough for us
rootSpan.updateName(spanName);
rootSpan.setAttributes(attributes);

return cb(rootSpan);
}

/**
Expand Down