diff --git a/CHANGELOG.md b/CHANGELOG.md index 4769478ae150..33795925ca00 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,23 @@ - "You miss 100 percent of the chances you don't take. — Wayne Gretzky" — Michael Scott +## 8.0.0-rc.3 + +### Important Changes + +- **feat(bun): Add Bun Global Unhandled Handlers (#11960)** + +The Bun SDK will now capture global unhandled errors. + +### Other Changes + +- feat(node): Log process and thread info on initialisation (#11972) +- fix(aws-serverless): Include ESM artifacts in package (#11973) +- fix(browser): Only start `http.client` spans if there is an active parent span (#11974) +- fix(feedback): Improve CSS theme variable names and layout (#11964) +- fix(node): Ensure `execArgv` are not sent to worker threads (#11963) +- ref(feedback): Simplify feedback function params (#11957) + ## 8.0.0-rc.2 ### Important Changes diff --git a/dev-packages/node-integration-tests/suites/public-api/LocalVariables/local-variables-instrument.js b/dev-packages/node-integration-tests/suites/public-api/LocalVariables/local-variables-instrument.js new file mode 100644 index 000000000000..0b39efcfd8db --- /dev/null +++ b/dev-packages/node-integration-tests/suites/public-api/LocalVariables/local-variables-instrument.js @@ -0,0 +1,8 @@ +const Sentry = require('@sentry/node'); +const { loggingTransport } = require('@sentry-internal/node-integration-tests'); + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + includeLocalVariables: true, + transport: loggingTransport, +}); diff --git a/dev-packages/node-integration-tests/suites/public-api/LocalVariables/local-variables-no-sentry.js b/dev-packages/node-integration-tests/suites/public-api/LocalVariables/local-variables-no-sentry.js new file mode 100644 index 000000000000..08636175fa7b --- /dev/null +++ b/dev-packages/node-integration-tests/suites/public-api/LocalVariables/local-variables-no-sentry.js @@ -0,0 +1,31 @@ +/* eslint-disable no-unused-vars */ +process.on('uncaughtException', () => { + // do nothing - this will prevent the Error below from closing this process +}); + +class Some { + two(name) { + throw new Error('Enough!'); + } +} + +function one(name) { + const arr = [1, '2', null]; + const obj = { + name, + num: 5, + }; + const bool = false; + const num = 0; + const str = ''; + const something = undefined; + const somethingElse = null; + + const ty = new Some(); + + ty.two(name); +} + +setTimeout(() => { + one('some name'); +}, 1000); diff --git a/dev-packages/node-integration-tests/suites/public-api/LocalVariables/test.ts b/dev-packages/node-integration-tests/suites/public-api/LocalVariables/test.ts index e2aa6c405773..61b9fc3064a4 100644 --- a/dev-packages/node-integration-tests/suites/public-api/LocalVariables/test.ts +++ b/dev-packages/node-integration-tests/suites/public-api/LocalVariables/test.ts @@ -59,6 +59,16 @@ conditionalTest({ min: 18 })('LocalVariables integration', () => { .start(done); }); + test('Should include local variables when instrumenting via --require', done => { + const requirePath = path.resolve(__dirname, 'local-variables-instrument.js'); + + createRunner(__dirname, 'local-variables-no-sentry.js') + .withFlags(`--require=${requirePath}`) + .ignore('session') + .expect({ event: EXPECTED_LOCAL_VARIABLES_EVENT }) + .start(done); + }); + test('Should include local variables with ESM', done => { createRunner(__dirname, 'local-variables-caught.mjs') .ignore('session') diff --git a/packages/aws-serverless/package.json b/packages/aws-serverless/package.json index b3214c0c3d75..ad4b2163df3f 100644 --- a/packages/aws-serverless/package.json +++ b/packages/aws-serverless/package.json @@ -11,6 +11,7 @@ }, "files": [ "cjs", + "esm", "types", "types-ts3.8", "import-hook.mjs", diff --git a/packages/browser/src/tracing/request.ts b/packages/browser/src/tracing/request.ts index 673cff9e5474..89b87ba6b757 100644 --- a/packages/browser/src/tracing/request.ts +++ b/packages/browser/src/tracing/request.ts @@ -7,6 +7,7 @@ import { SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SentryNonRecordingSpan, + getActiveSpan, getClient, getCurrentScope, getDynamicSamplingContextFromClient, @@ -324,20 +325,23 @@ export function xhrCallback( const fullUrl = getFullURL(sentryXhrData.url); const host = fullUrl ? parseUrl(fullUrl).host : undefined; - const span = shouldCreateSpanResult - ? startInactiveSpan({ - name: `${sentryXhrData.method} ${sentryXhrData.url}`, - attributes: { - type: 'xhr', - 'http.method': sentryXhrData.method, - 'http.url': fullUrl, - url: sentryXhrData.url, - 'server.address': host, - [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.browser', - [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'http.client', - }, - }) - : new SentryNonRecordingSpan(); + const hasParent = !!getActiveSpan(); + + const span = + shouldCreateSpanResult && hasParent + ? startInactiveSpan({ + name: `${sentryXhrData.method} ${sentryXhrData.url}`, + attributes: { + type: 'xhr', + 'http.method': sentryXhrData.method, + 'http.url': fullUrl, + url: sentryXhrData.url, + 'server.address': host, + [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.browser', + [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'http.client', + }, + }) + : new SentryNonRecordingSpan(); xhr.__sentry_xhr_span_id__ = span.spanContext().spanId; spans[xhr.__sentry_xhr_span_id__] = span; @@ -348,9 +352,10 @@ export function xhrCallback( addTracingHeadersToXhrRequest( xhr, client, - // If performance is disabled (TWP), we do not want to use the span as base for the trace headers, + // If performance is disabled (TWP) or there's no active root span (pageload/navigation/interaction), + // we do not want to use the span as base for the trace headers, // which means that the headers will be generated from the scope and the sampling decision is deferred - hasTracingEnabled() ? span : undefined, + hasTracingEnabled() && hasParent ? span : undefined, ); } diff --git a/packages/bun/src/sdk.ts b/packages/bun/src/sdk.ts index e9aabf5dae79..f299c8119985 100644 --- a/packages/bun/src/sdk.ts +++ b/packages/bun/src/sdk.ts @@ -12,6 +12,8 @@ import { modulesIntegration, nativeNodeFetchIntegration, nodeContextIntegration, + onUncaughtExceptionIntegration, + onUnhandledRejectionIntegration, } from '@sentry/node'; import type { Integration, Options } from '@sentry/types'; @@ -33,9 +35,9 @@ export function getDefaultIntegrations(_options: Options): Integration[] { consoleIntegration(), httpIntegration(), nativeNodeFetchIntegration(), - // Global Handlers # TODO (waiting for https://github.com/oven-sh/bun/issues/5091) - // new NodeIntegrations.OnUncaughtException(), - // new NodeIntegrations.OnUnhandledRejection(), + // Global Handlers + onUncaughtExceptionIntegration(), + onUnhandledRejectionIntegration(), // Event Info contextLinesIntegration(), nodeContextIntegration(), diff --git a/packages/core/src/fetch.ts b/packages/core/src/fetch.ts index 9a8ff09f1f50..9b9d2ece836b 100644 --- a/packages/core/src/fetch.ts +++ b/packages/core/src/fetch.ts @@ -17,7 +17,7 @@ import { } from './tracing'; import { SentryNonRecordingSpan } from './tracing/sentryNonRecordingSpan'; import { hasTracingEnabled } from './utils/hasTracingEnabled'; -import { spanToTraceHeader } from './utils/spanUtils'; +import { getActiveSpan, spanToTraceHeader } from './utils/spanUtils'; type PolymorphicRequestHeaders = | Record @@ -70,20 +70,23 @@ export function instrumentFetchRequest( const fullUrl = getFullURL(url); const host = fullUrl ? parseUrl(fullUrl).host : undefined; - const span = shouldCreateSpanResult - ? startInactiveSpan({ - name: `${method} ${url}`, - attributes: { - url, - type: 'fetch', - 'http.method': method, - 'http.url': fullUrl, - 'server.address': host, - [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: spanOrigin, - [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'http.client', - }, - }) - : new SentryNonRecordingSpan(); + const hasParent = !!getActiveSpan(); + + const span = + shouldCreateSpanResult && hasParent + ? startInactiveSpan({ + name: `${method} ${url}`, + attributes: { + url, + type: 'fetch', + 'http.method': method, + 'http.url': fullUrl, + 'server.address': host, + [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: spanOrigin, + [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'http.client', + }, + }) + : new SentryNonRecordingSpan(); handlerData.fetchData.__span = span.spanContext().spanId; spans[span.spanContext().spanId] = span; @@ -102,9 +105,10 @@ export function instrumentFetchRequest( client, scope, options, - // If performance is disabled (TWP), we do not want to use the span as base for the trace headers, + // If performance is disabled (TWP) or there's no active root span (pageload/navigation/interaction), + // we do not want to use the span as base for the trace headers, // which means that the headers will be generated from the scope and the sampling decision is deferred - hasTracingEnabled() ? span : undefined, + hasTracingEnabled() && hasParent ? span : undefined, ); } diff --git a/packages/feedback/src/constants/index.ts b/packages/feedback/src/constants/index.ts index fe4683b5ee17..a8794ed663b0 100644 --- a/packages/feedback/src/constants/index.ts +++ b/packages/feedback/src/constants/index.ts @@ -9,9 +9,10 @@ export const WINDOW = GLOBAL_OBJ as typeof GLOBAL_OBJ & Window; export const DOCUMENT = WINDOW.document; export const NAVIGATOR = WINDOW.navigator; -export const ACTOR_LABEL = 'Report a Bug'; +export const TRIGGER_LABEL = 'Report a Bug'; export const CANCEL_BUTTON_LABEL = 'Cancel'; export const SUBMIT_BUTTON_LABEL = 'Send Bug Report'; +export const CONFIRM_BUTTON_LABEL = 'Confirm'; export const FORM_TITLE = 'Report a Bug'; export const EMAIL_PLACEHOLDER = 'your.email@example.org'; export const EMAIL_LABEL = 'Email'; @@ -20,7 +21,9 @@ export const MESSAGE_LABEL = 'Description'; export const NAME_PLACEHOLDER = 'Your Name'; export const NAME_LABEL = 'Name'; export const SUCCESS_MESSAGE_TEXT = 'Thank you for your report!'; -export const IS_REQUIRED_TEXT = '(required)'; +export const IS_REQUIRED_LABEL = '(required)'; +export const ADD_SCREENSHOT_LABEL = 'Add a screenshot'; +export const REMOVE_SCREENSHOT_LABEL = 'Remove screenshot'; export const FEEDBACK_WIDGET_SOURCE = 'widget'; export const FEEDBACK_API_SOURCE = 'api'; diff --git a/packages/feedback/src/constants/theme.ts b/packages/feedback/src/constants/theme.ts index 26398b74d1b2..ba8193afd9d0 100644 --- a/packages/feedback/src/constants/theme.ts +++ b/packages/feedback/src/constants/theme.ts @@ -1,44 +1,44 @@ -const LIGHT_BACKGROUND = '#ffffff'; const INHERIT = 'inherit'; -const SUBMIT_COLOR = 'rgba(108, 95, 199, 1)'; +const PURPLE = 'rgba(88, 74, 192, 1)'; +const PURPLE_HOVER = 'rgba(108, 95, 199, 1)'; export const LIGHT_THEME = { - fontFamily: "system-ui, 'Helvetica Neue', Arial, sans-serif", - fontSize: '14px', - foreground: '#2b2233', - background: LIGHT_BACKGROUND, - success: '#268d75', - error: '#df3338', - - zIndex: 100000, + successForeground: '#268d75', + errorForeground: '#df3338', + background: '#ffffff', border: '1.5px solid rgba(41, 35, 47, 0.13)', boxShadow: '0px 4px 24px 0px rgba(43, 34, 51, 0.12)', - backgroundHover: '#f6f6f7', - borderRadius: '25px', - - formBorderRadius: '20px', - formContentBorderRadius: '6px', - - submitForeground: LIGHT_BACKGROUND, - submitBackground: 'rgba(88, 74, 192, 1)', - submitForegroundHover: LIGHT_BACKGROUND, - submitBackgroundHover: SUBMIT_COLOR, - submitBorder: SUBMIT_COLOR, + inputForeground: INHERIT, + inputBackground: INHERIT, + inputBackgroundHover: INHERIT, + inputBackgroundFocus: INHERIT, + inputBorder: 'var(--border)', + inputBorderRadius: '6px', + inputOutlineFocus: PURPLE_HOVER, + + buttonForeground: INHERIT, + buttonForegroundHover: INHERIT, + buttonBackground: 'var(--background)', + buttonBackgroundHover: '#f6f6f7', + buttonBorder: 'var(--border)', + buttonOutlineFocus: 'var(--input-outline-focus)', + + submitForeground: '#ffffff', + submitForegroundHover: '#ffffff', + submitBackground: PURPLE, + submitBackgroundHover: PURPLE_HOVER, + submitBorder: PURPLE_HOVER, + submitBorderRadius: 'var(--button-border-radius)', submitOutlineFocus: '#29232f', - cancelForeground: 'var(--foreground)', - cancelBackground: 'transparent', - cancelForegroundHover: 'var(--foreground)', - cancelBackgroundHover: 'var(--background-hover)', - cancelBorder: 'var(--border)', - cancelOutlineFocus: 'var(--input-outline-focus)', + triggerBackground: 'var(--background)', + triggerBackgroundHover: 'var(--button-background-hover)', + triggerBorderRadius: '1.7em/50%', - inputBackground: INHERIT, - inputForeground: INHERIT, - inputBorder: 'var(--border)', - inputOutlineFocus: SUBMIT_COLOR, + dialogBackground: 'var(--background)', + dialogBorderRadius: '20px', }; export const DEFAULT_THEME = { @@ -46,12 +46,13 @@ export const DEFAULT_THEME = { dark: { ...LIGHT_THEME, - background: '#29232f', - backgroundHover: '#352f3b', foreground: '#ebe6ef', - border: '1.5px solid rgba(235, 230, 239, 0.15)', + successForeground: '#2da98c', + errorForeground: '#f55459', + background: '#29232f', + border: '1.5px solid rgba(235, 230, 239, 0.5)', + boxShadow: '0px 4px 24px 0px rgba(43, 34, 51, 0.12)', - success: '#2da98c', - error: '#f55459', + buttonBackgroundHover: '#352f3b', }, }; diff --git a/packages/feedback/src/core/components/Actor.css.ts b/packages/feedback/src/core/components/Actor.css.ts index ea80921b3744..3daa58d09a99 100644 --- a/packages/feedback/src/core/components/Actor.css.ts +++ b/packages/feedback/src/core/components/Actor.css.ts @@ -9,7 +9,7 @@ export function createActorStyles(): HTMLStyleElement { .widget__actor { position: fixed; z-index: var(--z-index); - margin: 0; + margin: var(--page-margin); inset: var(--actor-inset); display: flex; @@ -20,14 +20,15 @@ export function createActorStyles(): HTMLStyleElement { font-family: inherit; font-size: var(--font-size); font-weight: 600; - line-height: 16px; + line-height: 1.14em; text-decoration: none; - background-color: var(--background); - border-radius: var(--border-radius); + background-color: var(--trigger-background); + border-radius: var(--trigger-border-radius); border: var(--border); box-shadow: var(--box-shadow); color: var(--foreground); + fill: var(--foreground); cursor: pointer; opacity: 1; transition: transform 0.2s ease-in-out; @@ -41,12 +42,12 @@ export function createActorStyles(): HTMLStyleElement { } .widget__actor:hover { - background-color: var(--background-hover); + background-color: var(--trigger-background-hover); } .widget__actor svg { - width: 16px; - height: 16px; + width: 1.14em; + height: 1.14em; } @media (max-width: 600px) { diff --git a/packages/feedback/src/core/components/Actor.ts b/packages/feedback/src/core/components/Actor.ts index ac62fad4957e..6b2469e0313c 100644 --- a/packages/feedback/src/core/components/Actor.ts +++ b/packages/feedback/src/core/components/Actor.ts @@ -3,7 +3,7 @@ import { createActorStyles } from './Actor.css'; import { FeedbackIcon } from './FeedbackIcon'; export interface ActorProps { - buttonLabel: string; + triggerLabel: string; shadow: ShadowRoot; } @@ -22,16 +22,16 @@ export interface ActorComponent { /** * The sentry-provided button to open the feedback modal */ -export function Actor({ buttonLabel, shadow }: ActorProps): ActorComponent { +export function Actor({ triggerLabel, shadow }: ActorProps): ActorComponent { const el = DOCUMENT.createElement('button'); el.type = 'button'; el.className = 'widget__actor'; el.ariaHidden = 'false'; - el.ariaLabel = buttonLabel; + el.ariaLabel = triggerLabel; el.appendChild(FeedbackIcon()); - if (buttonLabel) { + if (triggerLabel) { const label = DOCUMENT.createElement('span'); - label.appendChild(DOCUMENT.createTextNode(buttonLabel)); + label.appendChild(DOCUMENT.createTextNode(triggerLabel)); el.appendChild(label); } diff --git a/packages/feedback/src/core/createMainStyles.ts b/packages/feedback/src/core/createMainStyles.ts index 92763cacdd93..b60bba37b6e3 100644 --- a/packages/feedback/src/core/createMainStyles.ts +++ b/packages/feedback/src/core/createMainStyles.ts @@ -3,73 +3,45 @@ import { DOCUMENT } from '../constants'; function getThemedCssVariables(theme: FeedbackInternalOptions['themeLight']): string { return ` - --background: ${theme.background}; - --background-hover: ${theme.backgroundHover}; --foreground: ${theme.foreground}; - --error: ${theme.error}; - --success: ${theme.success}; + --success-foreground: ${theme.successForeground}; + --error-foreground: ${theme.errorForeground}; + --background: ${theme.background}; --border: ${theme.border}; - --border-radius: ${theme.borderRadius}; --box-shadow: ${theme.boxShadow}; - --submit-background: ${theme.submitBackground}; - --submit-background-hover: ${theme.submitBackgroundHover}; - --submit-border: ${theme.submitBorder}; - --submit-outline-focus: ${theme.submitOutlineFocus}; - --submit-foreground: ${theme.submitForeground}; - --submit-foreground-hover: ${theme.submitForegroundHover}; - - --cancel-background: ${theme.cancelBackground}; - --cancel-background-hover: ${theme.cancelBackgroundHover}; - --cancel-border: ${theme.cancelBorder}; - --cancel-outline-focus: ${theme.cancelOutlineFocus}; - --cancel-foreground: ${theme.cancelForeground}; - --cancel-foreground-hover: ${theme.cancelForegroundHover}; - - --input-background: ${theme.inputBackground}; - --input-foreground: ${theme.inputForeground}; - --input-border: ${theme.inputBorder}; - --input-outline-focus: ${theme.inputOutlineFocus}; + --button-foreground: ${theme.buttonForeground}; + --button-foreground-hover: ${theme.buttonForegroundHover}; + --button-background: ${theme.buttonBackground}; + --button-background-hover: ${theme.buttonBackgroundHover}; + --button-border: ${theme.buttonBorder}; + --button-outline-focus: ${theme.buttonOutlineFocus}; - --form-border-radius: ${theme.formBorderRadius}; - --form-content-border-radius: ${theme.formContentBorderRadius}; + --trigger-background: ${theme.triggerBackground}; + --trigger-background-hover: ${theme.triggerBackgroundHover}; + --trigger-border-radius: ${theme.triggerBorderRadius}; `; } /** * Creates