diff --git a/.github/workflows/auto-release.yml b/.github/workflows/auto-release.yml index dd41d7d50e5e..39e73722dfa5 100644 --- a/.github/workflows/auto-release.yml +++ b/.github/workflows/auto-release.yml @@ -9,7 +9,7 @@ on: # This workflow tirggers a release when merging a branch with the pattern `prepare-release/VERSION` into master. jobs: release: - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 name: 'Prepare a new version' steps: diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c58d8606d4de..5972af74bb89 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -62,7 +62,7 @@ env: jobs: job_get_metadata: name: Get Metadata - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 permissions: pull-requests: read steps: @@ -118,7 +118,7 @@ jobs: job_build: name: Build needs: job_get_metadata - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 timeout-minutes: 15 if: | needs.job_get_metadata.outputs.changed_any_code == 'true' || @@ -196,7 +196,7 @@ jobs: job_check_branches: name: Check PR branches needs: job_get_metadata - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 if: github.event_name == 'pull_request' permissions: pull-requests: write @@ -212,7 +212,7 @@ jobs: name: Size Check needs: [job_get_metadata, job_build] timeout-minutes: 15 - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 if: github.event_name == 'pull_request' || needs.job_get_metadata.outputs.is_base_branch == 'true' || needs.job_get_metadata.outputs.is_release == 'true' @@ -242,7 +242,7 @@ jobs: # inter-package dependencies resolve cleanly. needs: [job_get_metadata, job_build] timeout-minutes: 10 - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 steps: - name: Check out current commit (${{ needs.job_get_metadata.outputs.commit_label }}) uses: actions/checkout@v4 @@ -267,7 +267,7 @@ jobs: name: Check file formatting needs: [job_get_metadata] timeout-minutes: 10 - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 steps: - name: Check out current commit (${{ needs.job_get_metadata.outputs.commit_label }}) uses: actions/checkout@v4 @@ -290,7 +290,7 @@ jobs: name: Circular Dependency Check needs: [job_get_metadata, job_build] timeout-minutes: 10 - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 steps: - name: Check out current commit (${{ needs.job_get_metadata.outputs.commit_label }}) uses: actions/checkout@v4 @@ -310,7 +310,7 @@ jobs: job_artifacts: name: Upload Artifacts needs: [job_get_metadata, job_build] - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 # Build artifacts are only needed for releasing workflow. if: needs.job_get_metadata.outputs.is_release == 'true' steps: @@ -347,7 +347,7 @@ jobs: name: Browser Unit Tests needs: [job_get_metadata, job_build] timeout-minutes: 10 - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 steps: - name: Check out base commit (${{ github.event.pull_request.base.sha }}) uses: actions/checkout@v4 @@ -386,7 +386,7 @@ jobs: needs: [job_get_metadata, job_build] if: needs.job_build.outputs.changed_bun == 'true' || github.event_name != 'pull_request' timeout-minutes: 10 - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 strategy: fail-fast: false steps: @@ -413,7 +413,7 @@ jobs: needs: [job_get_metadata, job_build] if: needs.job_build.outputs.changed_deno == 'true' || github.event_name != 'pull_request' timeout-minutes: 10 - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 strategy: fail-fast: false steps: @@ -443,7 +443,7 @@ jobs: name: Node (${{ matrix.node }}) Unit Tests needs: [job_get_metadata, job_build] timeout-minutes: 10 - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 strategy: fail-fast: false matrix: @@ -578,7 +578,7 @@ jobs: name: PW ${{ matrix.bundle }} Tests needs: [job_get_metadata, job_build] if: needs.job_build.outputs.changed_browser_integration == 'true' || github.event_name != 'pull_request' - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 timeout-minutes: 15 strategy: fail-fast: false @@ -638,7 +638,7 @@ jobs: job_check_for_faulty_dts: name: Check for faulty .d.ts files needs: [job_get_metadata, job_build] - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 timeout-minutes: 5 steps: - name: Check out current commit (${{ needs.job_get_metadata.outputs.commit_label }}) @@ -666,12 +666,12 @@ jobs: Tests needs: [job_get_metadata, job_build] if: needs.job_build.outputs.changed_node_integration == 'true' || github.event_name != 'pull_request' - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 timeout-minutes: 15 strategy: fail-fast: false matrix: - node: [18, 20, 22] + node: ['18.20.5', 20, 22] typescript: - false include: @@ -705,7 +705,7 @@ jobs: name: Remix (Node ${{ matrix.node }}) Tests needs: [job_get_metadata, job_build] if: needs.job_build.outputs.changed_remix == 'true' || github.event_name != 'pull_request' - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 timeout-minutes: 10 strategy: fail-fast: false @@ -801,7 +801,7 @@ jobs: # See: https://github.com/actions/runner/issues/2205 if: always() && needs.job_e2e_prepare.result == 'success' && needs.job_e2e_prepare.outputs.matrix != '{"include":[]}' needs: [job_get_metadata, job_build, job_e2e_prepare] - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 timeout-minutes: 15 env: # We just use a dummy DSN here, only send to the tunnel anyhow @@ -923,7 +923,7 @@ jobs: (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) && github.actor != 'dependabot[bot]' needs: [job_get_metadata, job_build, job_e2e_prepare] - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 timeout-minutes: 15 env: E2E_TEST_AUTH_TOKEN: ${{ secrets.E2E_TEST_AUTH_TOKEN }} @@ -1043,7 +1043,7 @@ jobs: ] # Always run this, even if a dependent job failed if: always() - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 steps: - name: Check for failures if: contains(needs.*.result, 'failure') diff --git a/.github/workflows/canary.yml b/.github/workflows/canary.yml index 24f25fd1ea9a..614a971623b3 100644 --- a/.github/workflows/canary.yml +++ b/.github/workflows/canary.yml @@ -27,7 +27,7 @@ permissions: jobs: job_e2e_prepare: name: Prepare E2E Canary tests - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 timeout-minutes: 30 steps: - name: Check out current commit @@ -54,7 +54,7 @@ jobs: job_e2e_tests: name: E2E ${{ matrix.label }} Test needs: [job_e2e_prepare] - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 timeout-minutes: 20 env: # We just use a dummy DSN here, only send to the tunnel anyhow diff --git a/.github/workflows/clear-cache.yml b/.github/workflows/clear-cache.yml index 5c327553e3b8..78f1e3f66586 100644 --- a/.github/workflows/clear-cache.yml +++ b/.github/workflows/clear-cache.yml @@ -21,7 +21,7 @@ on: jobs: clear-caches: name: Delete all caches - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/enforce-license-compliance.yml b/.github/workflows/enforce-license-compliance.yml index 776f8135178d..f83a03a51b42 100644 --- a/.github/workflows/enforce-license-compliance.yml +++ b/.github/workflows/enforce-license-compliance.yml @@ -17,7 +17,7 @@ on: jobs: enforce-license-compliance: - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 steps: - name: 'Enforce License Compliance' uses: getsentry/action-enforce-license-compliance@main diff --git a/.github/workflows/external-contributors.yml b/.github/workflows/external-contributors.yml index e9b1e05a2c92..cc2cbdb72774 100644 --- a/.github/workflows/external-contributors.yml +++ b/.github/workflows/external-contributors.yml @@ -12,7 +12,7 @@ jobs: permissions: pull-requests: write contents: write - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 if: | github.event.pull_request.merged == true && github.event.pull_request.author_association != 'COLLABORATOR' diff --git a/.github/workflows/flaky-test-detector.yml b/.github/workflows/flaky-test-detector.yml index 5d0d5af5d247..a232e1e735b1 100644 --- a/.github/workflows/flaky-test-detector.yml +++ b/.github/workflows/flaky-test-detector.yml @@ -23,7 +23,7 @@ concurrency: jobs: flaky-detector: - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 timeout-minutes: 60 name: 'Check tests for flakiness' # Also skip if PR is from master -> develop diff --git a/.github/workflows/gitflow-sync-develop.yml b/.github/workflows/gitflow-sync-develop.yml index 893dbbbf56fb..9bf8b6a556d6 100644 --- a/.github/workflows/gitflow-sync-develop.yml +++ b/.github/workflows/gitflow-sync-develop.yml @@ -17,7 +17,7 @@ env: jobs: main: name: Create PR master->develop - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 permissions: pull-requests: write contents: write diff --git a/.github/workflows/release-comment-issues.yml b/.github/workflows/release-comment-issues.yml index 4bbcb29aba21..ab4c45fc8f17 100644 --- a/.github/workflows/release-comment-issues.yml +++ b/.github/workflows/release-comment-issues.yml @@ -12,7 +12,7 @@ on: # This workflow is triggered when a release is published jobs: release-comment-issues: - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 name: 'Notify issues' steps: - name: Get version diff --git a/.github/workflows/release-size-info.yml b/.github/workflows/release-size-info.yml index 04e51e5ae14e..ea0cef636b8e 100644 --- a/.github/workflows/release-size-info.yml +++ b/.github/workflows/release-size-info.yml @@ -13,7 +13,7 @@ on: # It fetches the size-limit info from the release branch and adds it to the release jobs: release-size-info: - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 name: 'Add size-limit info to release' steps: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2768f18a5bc8..99569fd7f1aa 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -14,7 +14,7 @@ on: default: master jobs: release: - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 name: 'Release a new version' steps: - name: Get auth token diff --git a/CHANGELOG.md b/CHANGELOG.md index ad2232acfbb1..c7b41f50b30b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,7 @@ - "You miss 100 percent of the chances you don't take. — Wayne Gretzky" — Michael Scott -Work in this release was contributed by @tjhiggins, @chris-basebone, @GrizliK1988, @davidturissini, @nwalters512, @aloisklink, @arturovt, @benjick, @maximepvrt, @mstrokin, @kunal-511, @jahands, @jrandolf and @nathankleyn. Thank you for your contributions! +Work in this release was contributed by @tjhiggins, @chris-basebone, @GrizliK1988, @davidturissini, @nwalters512, @aloisklink, @arturovt, @benjick, @maximepvrt, @mstrokin, @kunal-511, @jahands, @jrandolf, @Zen-cronic and @nathankleyn. Thank you for your contributions! ## 9.0.0-alpha.0 diff --git a/dev-packages/browser-integration-tests/suites/tracing/metrics/pageload-resource-spans/test.ts b/dev-packages/browser-integration-tests/suites/tracing/metrics/pageload-resource-spans/test.ts index 2343d77f55c7..9478b8f833f7 100644 --- a/dev-packages/browser-integration-tests/suites/tracing/metrics/pageload-resource-spans/test.ts +++ b/dev-packages/browser-integration-tests/suites/tracing/metrics/pageload-resource-spans/test.ts @@ -1,24 +1,44 @@ import type { Route } from '@playwright/test'; import { expect } from '@playwright/test'; -import type { Event } from '@sentry/core'; +import { type Event, SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '@sentry/core'; import { sentryTest } from '../../../../utils/fixtures'; import { getFirstSentryEnvelopeRequest, shouldSkipTracingTest } from '../../../../utils/helpers'; -sentryTest('should add resource spans to pageload transaction', async ({ getLocalTestUrl, page }) => { +sentryTest('should add resource spans to pageload transaction', async ({ getLocalTestUrl, page, browserName }) => { if (shouldSkipTracingTest()) { sentryTest.skip(); } + const isWebkitRun = browserName === 'webkit'; + // Intercepting asset requests to avoid network-related flakiness and random retries (on Firefox). await page.route('https://example.com/path/to/image.svg', (route: Route) => - route.fulfill({ path: `${__dirname}/assets/image.svg` }), + route.fulfill({ + path: `${__dirname}/assets/image.svg`, + headers: { + 'Timing-Allow-Origin': '*', + 'Content-Type': 'image/svg+xml', + }, + }), ); await page.route('https://example.com/path/to/script.js', (route: Route) => - route.fulfill({ path: `${__dirname}/assets/script.js` }), + route.fulfill({ + path: `${__dirname}/assets/script.js`, + headers: { + 'Timing-Allow-Origin': '*', + 'Content-Type': 'application/javascript', + }, + }), ); await page.route('https://example.com/path/to/style.css', (route: Route) => - route.fulfill({ path: `${__dirname}/assets/style.css` }), + route.fulfill({ + path: `${__dirname}/assets/style.css`, + headers: { + 'Timing-Allow-Origin': '*', + 'Content-Type': 'text/css', + }, + }), ); const url = await getLocalTestUrl({ testDir: __dirname }); @@ -27,11 +47,14 @@ sentryTest('should add resource spans to pageload transaction', async ({ getLoca const resourceSpans = eventData.spans?.filter(({ op }) => op?.startsWith('resource')); const scriptSpans = resourceSpans?.filter(({ op }) => op === 'resource.script'); - const linkSpans = resourceSpans?.filter(({ op }) => op === 'resource.link'); - const imgSpans = resourceSpans?.filter(({ op }) => op === 'resource.img'); + const linkSpan = resourceSpans?.filter(({ op }) => op === 'resource.link')[0]; + const imgSpan = resourceSpans?.filter(({ op }) => op === 'resource.img')[0]; + + const spanId = eventData.contexts?.trace?.span_id; + const traceId = eventData.contexts?.trace?.trace_id; - expect(imgSpans).toHaveLength(1); - expect(linkSpans).toHaveLength(1); + expect(spanId).toBeDefined(); + expect(traceId).toBeDefined(); const hasCdnBundle = (process.env.PW_BUNDLE || '').startsWith('bundle'); @@ -41,11 +64,90 @@ sentryTest('should add resource spans to pageload transaction', async ({ getLoca } expect(scriptSpans?.map(({ description }) => description).sort()).toEqual(expectedScripts); + expect(scriptSpans?.map(({ parent_span_id }) => parent_span_id)).toEqual(expectedScripts.map(() => spanId)); - const spanId = eventData.contexts?.trace?.span_id; + const customScriptSpan = scriptSpans?.find( + ({ description }) => description === 'https://example.com/path/to/script.js', + ); - expect(spanId).toBeDefined(); - expect(imgSpans?.[0].parent_span_id).toBe(spanId); - expect(linkSpans?.[0].parent_span_id).toBe(spanId); - expect(scriptSpans?.map(({ parent_span_id }) => parent_span_id)).toEqual(expectedScripts.map(() => spanId)); + expect(imgSpan).toEqual({ + data: { + 'http.decoded_response_content_length': expect.any(Number), + 'http.response_content_length': expect.any(Number), + 'http.response_transfer_size': expect.any(Number), + 'network.protocol.name': '', + 'network.protocol.version': 'unknown', + [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'resource.img', + [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.resource.browser.metrics', + 'server.address': 'example.com', + 'url.same_origin': false, + 'url.scheme': 'https', + ...(!isWebkitRun && { + 'resource.render_blocking_status': 'non-blocking', + 'http.response_delivery_type': '', + }), + }, + description: 'https://example.com/path/to/image.svg', + op: 'resource.img', + origin: 'auto.resource.browser.metrics', + parent_span_id: spanId, + span_id: expect.stringMatching(/^[a-f0-9]{16}$/), + start_timestamp: expect.any(Number), + timestamp: expect.any(Number), + trace_id: traceId, + }); + + expect(linkSpan).toEqual({ + data: { + 'http.decoded_response_content_length': expect.any(Number), + 'http.response_content_length': expect.any(Number), + 'http.response_transfer_size': expect.any(Number), + 'network.protocol.name': '', + 'network.protocol.version': 'unknown', + [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'resource.link', + [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.resource.browser.metrics', + 'server.address': 'example.com', + 'url.same_origin': false, + 'url.scheme': 'https', + ...(!isWebkitRun && { + 'resource.render_blocking_status': 'non-blocking', + 'http.response_delivery_type': '', + }), + }, + description: 'https://example.com/path/to/style.css', + op: 'resource.link', + origin: 'auto.resource.browser.metrics', + parent_span_id: spanId, + span_id: expect.stringMatching(/^[a-f0-9]{16}$/), + start_timestamp: expect.any(Number), + timestamp: expect.any(Number), + trace_id: traceId, + }); + + expect(customScriptSpan).toEqual({ + data: { + 'http.decoded_response_content_length': expect.any(Number), + 'http.response_content_length': expect.any(Number), + 'http.response_transfer_size': expect.any(Number), + 'network.protocol.name': '', + 'network.protocol.version': 'unknown', + 'sentry.op': 'resource.script', + 'sentry.origin': 'auto.resource.browser.metrics', + 'server.address': 'example.com', + 'url.same_origin': false, + 'url.scheme': 'https', + ...(!isWebkitRun && { + 'resource.render_blocking_status': 'non-blocking', + 'http.response_delivery_type': '', + }), + }, + description: 'https://example.com/path/to/script.js', + op: 'resource.script', + origin: 'auto.resource.browser.metrics', + parent_span_id: spanId, + span_id: expect.stringMatching(/^[a-f0-9]{16}$/), + start_timestamp: expect.any(Number), + timestamp: expect.any(Number), + trace_id: traceId, + }); }); diff --git a/docs/migration/v8-to-v9.md b/docs/migration/v8-to-v9.md index e279fb0ebc86..538826a0cde5 100644 --- a/docs/migration/v8-to-v9.md +++ b/docs/migration/v8-to-v9.md @@ -1,7 +1,5 @@ # Upgrading from 8.x to 9.x -**DISCLAIMER: THIS MIGRATION GUIDE IS WORK IN PROGRESS** - Version 9 of the Sentry SDK concerns API cleanup and compatibility updates. This update contains behavioral changes that will not be caught by TypeScript or linters, so we recommend carefully reading the section on [Behavioral Changes](#2-behavior-changes). @@ -24,7 +22,7 @@ This includes features like Nullish Coalescing (`??`), Optional Chaining (`?.`), If you observe failures due to syntax or features listed above, it may indicate that your current runtime does not support ES2020. If your runtime does not support ES2020, we recommend transpiling the SDK using Babel or similar tooling. -**Node.js:** The minimum supported Node.js version is **18.0.0**, except for ESM-only SDKs (nuxt, solidstart, astro) which require Node **18.19.1** or up. +**Node.js:** The minimum supported Node.js version is **18.0.0**, except for ESM-only SDKs (`@sentry/astro`, `@sentry/nuxt`, `@sentry/sveltekit`) which require Node.js version **18.19.1** or higher. We no longer test against Node 14 and Node 16 and cannot guarantee that the SDK will work as expected on these versions. **Browsers:** Due to SDK code now including ES2020 features, the minimum supported browser list now looks as follows: @@ -52,7 +50,7 @@ Support for the following frameworks and library versions are dropped: ### TypeScript Version Policy -In preparation for the OpenTelemetry SDK v2, which will raise the minimum required TypeScript version, the minimum required TypeScript version is increased to version `5.0.4` (TBD https://github.com/open-telemetry/opentelemetry-js/pull/5145). +In preparation for the OpenTelemetry SDK v2, which will raise the minimum required TypeScript version, the minimum required TypeScript version is increased to version `5.0.4`. Additionally, like the OpenTelemetry SDK, the Sentry JavaScript SDK will follow [DefinitelyType's version support policy](https://github.com/DefinitelyTyped/DefinitelyTyped#support-window) which has a support time frame of 2 years for any released version of TypeScript. @@ -71,7 +69,7 @@ Older Typescript versions _may_ still work, but we will not test them anymore an }); ``` -- Dropping spans in the `beforeSendSpan` hook is no longer possible. +- Dropping spans in the `beforeSendSpan` hook is no longer possible. This means you cannot return `null` from the `beforeSendSpan` hook anymore. - The `beforeSendSpan` hook now receives the root span as well as the child spans. - In previous versions, we determined if tracing is enabled (for Tracing Without Performance) by checking if either `tracesSampleRate` or `traceSampler` are _defined_ at all, in `Sentry.init()`. This means that e.g. the following config would lead to tracing without performance (=tracing being enabled, even if no spans would be started): @@ -154,7 +152,7 @@ Older Typescript versions _may_ still work, but we will not test them anymore an - The `sentry` property on the Next.js config object has officially been discontinued. Pass options to `withSentryConfig` directly. -### All Meta-Framework SDKs (`@sentry/astro`, `@sentry/nuxt`, `@sentry/solidstart`) +### All Meta-Framework SDKs (`@sentry/astro`, `@sentry/nextjs`, `@sentry/nuxt`, `@sentry/sveltekit`, `@sentry/solidstart`) - Updated source map generation to respect the user-provided value of your build config, such as `vite.build.sourcemap`: @@ -170,10 +168,6 @@ The `componentStack` field in the `ErrorBoundary` component is now typed as `str In the `onUnmount` lifecycle method, the `componentStack` field is now typed as `string | null`. The `componentStack` is `null` when no error has been thrown at time of unmount. -### Uncategorized (TODO) - -TODO - ## 3. Package Removals As part of an architectural cleanup, we deprecated the following packages: @@ -190,27 +184,34 @@ You may experience slight compatibility issues in the future by using it. We decided to keep this package around to temporarily lessen the upgrade burden. It will be removed in a future major version. -## 4. Removal of Deprecated APIs (TODO) +## 4. Removal of Deprecated APIs ### `@sentry/core` / All SDKs +- **The metrics API has been removed from the SDK.** + + The Sentry metrics beta has ended and the metrics API has been removed from the SDK. Learn more in the Sentry [help center docs](https://sentry.zendesk.com/hc/en-us/articles/26369339769883-Metrics-Beta-Ended-on-October-7th). + - The `debugIntegration` has been removed. To log outgoing events, use [Hook Options](https://docs.sentry.io/platforms/javascript/configuration/options/#hooks) (`beforeSend`, `beforeSendTransaction`, ...). + - The `sessionTimingIntegration` has been removed. To capture session durations alongside events, use [Context](https://docs.sentry.io/platforms/javascript/enriching-events/context/) (`Sentry.setContext()`). + - The `addOpenTelemetryInstrumentation` method has been removed. Use the `openTelemetryInstrumentations` option in `Sentry.init()` or your custom Sentry Client instead. -```js -import * as Sentry from '@sentry/node'; + ```js + import * as Sentry from '@sentry/node'; -// before -Sentry.addOpenTelemetryInstrumentation(new GenericPoolInstrumentation()); + // before + Sentry.addOpenTelemetryInstrumentation(new GenericPoolInstrumentation()); -// after -Sentry.init({ - openTelemetryInstrumentations: [new GenericPoolInstrumentation()], -}); -``` + // after + Sentry.init({ + openTelemetryInstrumentations: [new GenericPoolInstrumentation()], + }); + ``` - The `DEFAULT_USER_INCLUDES` constant has been removed. + - The `getCurrentHub()`, `Hub` and `getCurrentHubShim()` APIs have been removed. They were on compatibility life support since the release of v8 and have now been fully removed from the SDK. ### `@sentry/browser` @@ -239,24 +240,23 @@ Sentry.init({ - The `sentrySolidStartVite` plugin is no longer exported. Instead, wrap the SolidStart config with `withSentry` and provide Sentry options as the second parameter. - ``` + ```ts // app.config.ts import { defineConfig } from '@solidjs/start/config'; import { withSentry } from '@sentry/solidstart'; - export default defineConfig(withSentry( - { /* SolidStart config */ }, - { /* Sentry build-time config (like project and org) */ }) + export default defineConfig( + withSentry( + { + /* SolidStart config */ + }, + { + /* Sentry build-time config (like project and org) */ + }, + ), ); ``` -#### 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 -- `client.recordDroppedEvent()` no longer accepts an `event` as third argument. The event was no longer used for some time, instead you can (optionally) pass a count of dropped events as third argument. - ### `@sentry/nestjs` - Removed `WithSentry` decorator. Use the `SentryExceptionCaptured` decorator instead. @@ -278,7 +278,7 @@ The following changes are unlikely to affect users of the SDK. They are listed h - The `wrapUseRoutes` method has been removed. Use the `wrapUseRoutesV6` or `wrapUseRoutesV7` methods instead depending on what version of react router you are using. - The `wrapCreateBrowserRouter` method has been removed. Use the `wrapCreateBrowserRouterV6` or `wrapCreateBrowserRouterV7` methods depending on what version of react router you are using. -## `@sentry/vue` +### `@sentry/vue` - The options `tracingOptions`, `trackComponents`, `timeout`, `hooks` have been removed everywhere except in the `tracingOptions` option of `vueIntegration()`. @@ -313,6 +313,13 @@ The following changes are unlikely to affect users of the SDK. They are listed h - The `fetchProxyScriptNonce` option in `sentryHandle()` was removed due to security concerns. If you previously specified this option for your CSP policy, specify a [script hash](https://docs.sentry.io/platforms/javascript/guides/sveltekit/manual-setup/#configure-csp-for-client-side-fetch-instrumentation) in your CSP config or [disable](https://docs.sentry.io/platforms/javascript/guides/sveltekit/manual-setup/#disable-client-side-fetch-proxy-script) the injection of the script entirely. +#### 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 +- `client.recordDroppedEvent()` no longer accepts an `event` as third argument. The event was no longer used for some time, instead you can (optionally) pass a count of dropped events as third argument. + ## 5. Build Changes Previously the CJS versions of the SDK code (wrongfully) contained compatibility statements for default exports in ESM: @@ -326,19 +333,18 @@ Let us know if this is causing issues in your setup by opening an issue on GitHu ### `@sentry/deno` -The minimum supported Deno version is now **2.0.0**. +- The minimum supported Deno version for the Deno SDK (`@sentry/deno`) is now **2.0.0**. -- `@sentry/deno` is no longer published on `deno.land` so you'll need to import - from npm: +- `@sentry/deno` is no longer published on the `deno.land` registry so you'll need to import the SDK from npm: -```javascript -import * as Sentry from 'npm:@sentry/deno'; + ```javascript + import * as Sentry from 'npm:@sentry/deno'; -Sentry.init({ - dsn: '__DSN__', - // ... -}); -``` + Sentry.init({ + dsn: '__DSN__', + // ... + }); + ``` ## 6. Type Changes @@ -383,49 +389,49 @@ The following outlines deprecations that were introduced in version 8 of the SDK - **Passing `undefined` to `tracesSampleRate` / `tracesSampler` / `enableTracing` will be handled differently in v9** -In v8, explicitly setting `tracesSampleRate` (even if it is set to `undefined`) resulted in tracing being _enabled_, although no spans were generated. + In v8, explicitly setting `tracesSampleRate` (even if it is set to `undefined`) resulted in tracing being _enabled_, although no spans were generated. -```ts -Sentry.init({ - tracesSampleRate: undefined, -}); -``` + ```ts + Sentry.init({ + tracesSampleRate: undefined, + }); + ``` -In v9, we will streamline this behavior so that passing `undefined` will result in tracing being disabled, the same as not passing the option at all. + In v9, we will streamline this behavior so that passing `undefined` will result in tracing being disabled, the same as not passing the option at all. -If you are relying on `undefined` being passed in and having tracing enabled because of this, you should update your config to set e.g. `tracesSampleRate: 0` instead, which will also enable tracing in v9. + If you are relying on `undefined` being passed in and having tracing enabled because of this, you should update your config to set e.g. `tracesSampleRate: 0` instead, which will also enable tracing in v9. -The `enableTracing` option was removed. In v9, to emulate `enableTracing: true`, set `tracesSampleRate: 1`. To emulate `enableTracing: false`, remove the `tracesSampleRate` and `tracesSampler` options (if configured). + The `enableTracing` option was removed. In v9, to emulate `enableTracing: true`, set `tracesSampleRate: 1`. To emulate `enableTracing: false`, remove the `tracesSampleRate` and `tracesSampler` options (if configured). - **The `autoSessionTracking` option is deprecated.** -To enable session tracking, it is recommended to unset `autoSessionTracking` and ensure that either, in browser environments the `browserSessionIntegration` is added, or in server environments the `httpIntegration` is added. + To enable session tracking, it is recommended to unset `autoSessionTracking` and ensure that either, in browser environments the `browserSessionIntegration` is added, or in server environments the `httpIntegration` is added. -To disable session tracking, it is recommended unset `autoSessionTracking` and to remove the `browserSessionIntegration` in browser environments, or in server environments configure the `httpIntegration` with the `trackIncomingRequestsAsSessions` option set to `false`. -Additionally, in Node.js environments, a session was automatically created for every node process when `autoSessionTracking` was set to `true`. This behavior has been replaced by the `processSessionIntegration` which is configured by default. + To disable session tracking, it is recommended unset `autoSessionTracking` and to remove the `browserSessionIntegration` in browser environments, or in server environments configure the `httpIntegration` with the `trackIncomingRequestsAsSessions` option set to `false`. + Additionally, in Node.js environments, a session was automatically created for every node process when `autoSessionTracking` was set to `true`. This behavior has been replaced by the `processSessionIntegration` which is configured by default. -- **The metrics API has been removed from the SDK.** +- **The metrics API is deprecated.** -The Sentry metrics beta has ended and the metrics API has been removed from the SDK. Learn more in [help center docs](https://sentry.zendesk.com/hc/en-us/articles/26369339769883-Metrics-Beta-Ended-on-October-7th). + The Sentry metrics beta has ended and the metrics API has been deprecated in `8.x`. The entire API will be removed in `9.x` of the SDK. Learn more in the Sentry [help center docs](https://sentry.zendesk.com/hc/en-us/articles/26369339769883-Metrics-Beta-Ended-on-October-7th). ## `@sentry/utils` - **The `@sentry/utils` package has been deprecated. Import everything from `@sentry/core` instead.** -- Deprecated `AddRequestDataToEventOptions.transaction`. This option effectively doesn't do anything anymore, and will be removed in v9. -- Deprecated `TransactionNamingScheme` type. -- Deprecated `validSeverityLevels`. Will not be replaced. -- Deprecated `urlEncode`. No replacements. -- Deprecated `addRequestDataToEvent`. Use `httpRequestToRequestData` instead and put the resulting object directly on `event.request`. -- Deprecated `extractRequestData`. Instead manually extract relevant data off request. -- Deprecated `arrayify`. No replacements. -- Deprecated `memoBuilder`. No replacements. -- Deprecated `getNumberOfUrlSegments`. No replacements. -- Deprecated `BAGGAGE_HEADER_NAME`. Use the `"baggage"` string constant directly instead. -- Deprecated `makeFifoCache`. No replacements. -- Deprecated `dynamicRequire`. No replacements. -- Deprecated `flatten`. No replacements. -- Deprecated `_browserPerformanceTimeOriginMode`. No replacements. + - Deprecated `AddRequestDataToEventOptions.transaction`. This option effectively doesn't do anything anymore, and will be removed in v9. + - Deprecated `TransactionNamingScheme` type. + - Deprecated `validSeverityLevels`. Will not be replaced. + - Deprecated `urlEncode`. No replacements. + - Deprecated `addRequestDataToEvent`. Use `httpRequestToRequestData` instead and put the resulting object directly on `event.request`. + - Deprecated `extractRequestData`. Instead manually extract relevant data off request. + - Deprecated `arrayify`. No replacements. + - Deprecated `memoBuilder`. No replacements. + - Deprecated `getNumberOfUrlSegments`. No replacements. + - Deprecated `BAGGAGE_HEADER_NAME`. Use the `"baggage"` string constant directly instead. + - Deprecated `makeFifoCache`. No replacements. + - Deprecated `dynamicRequire`. No replacements. + - Deprecated `flatten`. No replacements. + - Deprecated `_browserPerformanceTimeOriginMode`. No replacements. ## `@sentry/core` @@ -461,10 +467,10 @@ The Sentry metrics beta has ended and the metrics API has been removed from the - **The `@sentry/types` package has been deprecated. Import everything from `@sentry/core` instead.** -- Deprecated `Request` in favor of `RequestEventData`. -- Deprecated `RequestSession`. No replacements. -- Deprecated `RequestSessionStatus`. No replacements. -- Deprecated `SessionFlusherLike`. No replacements. + - Deprecated `Request` in favor of `RequestEventData`. + - Deprecated `RequestSession`. No replacements. + - Deprecated `RequestSessionStatus`. No replacements. + - Deprecated `SessionFlusherLike`. No replacements. ## `@sentry/nuxt` @@ -474,23 +480,23 @@ The Sentry metrics beta has ended and the metrics API has been removed from the - Deprecated `tracingOptions`, `trackComponents`, `timeout`, `hooks` options everywhere other than in the `tracingOptions` option of the `vueIntegration()`. -These options should now be set as follows: + These options should now be set as follows: -```ts -import * as Sentry from '@sentry/vue'; + ```ts + import * as Sentry from '@sentry/vue'; -Sentry.init({ - integrations: [ - Sentry.vueIntegration({ - tracingOptions: { - trackComponents: true, - timeout: 1000, - hooks: ['mount', 'update', 'unmount'], - }, - }), - ], -}); -``` + Sentry.init({ + integrations: [ + Sentry.vueIntegration({ + tracingOptions: { + trackComponents: true, + timeout: 1000, + hooks: ['mount', 'update', 'unmount'], + }, + }), + ], + }); + ``` - Deprecated `logErrors` in the `vueIntegration`. The Sentry Vue error handler will propagate the error to a user-defined error handler or just re-throw the error (which will log the error without modifying). @@ -499,24 +505,24 @@ Sentry.init({ - When component tracking is enabled, "update" spans are no longer created by default. -Add an `"update"` item to the `tracingOptions.hooks` option via the `vueIntegration()` to restore this behavior. - -```ts -Sentry.init({ - integrations: [ - Sentry.vueIntegration({ - tracingOptions: { - trackComponents: true, - hooks: [ - 'mount', - 'update', // <-- - 'unmount', - ], - }, - }), - ], -}); -``` + Add an `"update"` item to the `tracingOptions.hooks` option via the `vueIntegration()` to restore this behavior. + + ```ts + Sentry.init({ + integrations: [ + Sentry.vueIntegration({ + tracingOptions: { + trackComponents: true, + hooks: [ + 'mount', + 'update', // add this line to re-enable update spans + 'unmount', + ], + }, + }), + ], + }); + ``` ## `@sentry/astro` diff --git a/packages/browser-utils/src/index.ts b/packages/browser-utils/src/index.ts index 4737a2b47342..fad5772d1b96 100644 --- a/packages/browser-utils/src/index.ts +++ b/packages/browser-utils/src/index.ts @@ -17,6 +17,8 @@ export { registerInpInteractionListener, } from './metrics/browserMetrics'; +export { extractNetworkProtocol } from './metrics/utils'; + export { addClickKeypressInstrumentationHandler } from './instrument/dom'; export { addHistoryInstrumentationHandler } from './instrument/history'; diff --git a/packages/browser-utils/src/metrics/browserMetrics.ts b/packages/browser-utils/src/metrics/browserMetrics.ts index 1d2b6b47c87e..794faa197ad5 100644 --- a/packages/browser-utils/src/metrics/browserMetrics.ts +++ b/packages/browser-utils/src/metrics/browserMetrics.ts @@ -20,7 +20,13 @@ import { addPerformanceInstrumentationHandler, addTtfbInstrumentationHandler, } from './instrument'; -import { getBrowserPerformanceAPI, isMeasurementValue, msToSec, startAndEndSpan } from './utils'; +import { + extractNetworkProtocol, + getBrowserPerformanceAPI, + isMeasurementValue, + msToSec, + startAndEndSpan, +} from './utils'; import { getActivationStart } from './web-vitals/lib/getActivationStart'; import { getNavigationEntry } from './web-vitals/lib/getNavigationEntry'; import { getVisibilityWatcher } from './web-vitals/lib/getVisibilityWatcher'; @@ -596,6 +602,10 @@ export function _addResourceSpans( attributes['url.same_origin'] = resourceUrl.includes(WINDOW.location.origin); + const { name, version } = extractNetworkProtocol(entry.nextHopProtocol); + attributes['network.protocol.name'] = name; + attributes['network.protocol.version'] = version; + const startTimestamp = timeOrigin + startTime; const endTimestamp = startTimestamp + duration; diff --git a/packages/browser-utils/src/metrics/utils.ts b/packages/browser-utils/src/metrics/utils.ts index 91aefa8a8918..aef40d4cf613 100644 --- a/packages/browser-utils/src/metrics/utils.ts +++ b/packages/browser-utils/src/metrics/utils.ts @@ -137,3 +137,34 @@ export function getBrowserPerformanceAPI(): Performance | undefined { export function msToSec(time: number): number { return time / 1000; } + +/** + * Converts ALPN protocol ids to name and version. + * + * (https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids) + * @param nextHopProtocol PerformanceResourceTiming.nextHopProtocol + */ +export function extractNetworkProtocol(nextHopProtocol: string): { name: string; version: string } { + let name = 'unknown'; + let version = 'unknown'; + let _name = ''; + for (const char of nextHopProtocol) { + // http/1.1 etc. + if (char === '/') { + [name, version] = nextHopProtocol.split('/') as [string, string]; + break; + } + // h2, h3 etc. + if (!isNaN(Number(char))) { + name = _name === 'h' ? 'http' : _name; + version = nextHopProtocol.split(_name)[1] as string; + break; + } + _name += char; + } + if (_name === nextHopProtocol) { + // webrtc, ftp, etc. + name = _name; + } + return { name, version }; +} diff --git a/packages/browser-utils/test/browser/browserMetrics.test.ts b/packages/browser-utils/test/browser/browserMetrics.test.ts index 2ff1c2df209a..98a3bb375c00 100644 --- a/packages/browser-utils/test/browser/browserMetrics.test.ts +++ b/packages/browser-utils/test/browser/browserMetrics.test.ts @@ -131,6 +131,7 @@ describe('_addResourceSpans', () => { encodedBodySize: 256, decodedBodySize: 256, renderBlockingStatus: 'non-blocking', + nextHopProtocol: 'http/1.1', }); _addResourceSpans(span, entry, resourceEntryName, 123, 456, 100); @@ -150,6 +151,7 @@ describe('_addResourceSpans', () => { encodedBodySize: 256, decodedBodySize: 256, renderBlockingStatus: 'non-blocking', + nextHopProtocol: 'http/1.1', }); _addResourceSpans(span, entry, 'https://example.com/assets/to/me', 123, 456, 100); @@ -169,6 +171,7 @@ describe('_addResourceSpans', () => { encodedBodySize: 456, decodedBodySize: 593, renderBlockingStatus: 'non-blocking', + nextHopProtocol: 'http/1.1', }); const timeOrigin = 100; @@ -195,6 +198,8 @@ describe('_addResourceSpans', () => { ['url.scheme']: 'https', ['server.address']: 'example.com', ['url.same_origin']: true, + ['network.protocol.name']: 'http', + ['network.protocol.version']: '1.1', }, }), ); @@ -233,6 +238,7 @@ describe('_addResourceSpans', () => { const { initiatorType, op } = table[i]!; const entry = mockPerformanceResourceTiming({ initiatorType, + nextHopProtocol: 'http/1.1', }); _addResourceSpans(span, entry, 'https://example.com/assets/to/me', 123, 234, 465); @@ -254,6 +260,7 @@ describe('_addResourceSpans', () => { encodedBodySize: 0, decodedBodySize: 0, renderBlockingStatus: 'non-blocking', + nextHopProtocol: 'h2', }); _addResourceSpans(span, entry, resourceEntryName, 100, 23, 345); @@ -271,6 +278,8 @@ describe('_addResourceSpans', () => { ['url.scheme']: 'https', ['server.address']: 'example.com', ['url.same_origin']: true, + ['network.protocol.name']: 'http', + ['network.protocol.version']: '2', }, }), ); @@ -288,6 +297,7 @@ describe('_addResourceSpans', () => { transferSize: 2147483647, encodedBodySize: 2147483647, decodedBodySize: 2147483647, + nextHopProtocol: 'h3', }); _addResourceSpans(span, entry, resourceEntryName, 100, 23, 345); @@ -301,6 +311,8 @@ describe('_addResourceSpans', () => { 'server.address': 'example.com', 'url.same_origin': true, 'url.scheme': 'https', + ['network.protocol.name']: 'http', + ['network.protocol.version']: '3', }, description: '/assets/to/css', timestamp: 468, @@ -325,6 +337,7 @@ describe('_addResourceSpans', () => { transferSize: null, encodedBodySize: null, decodedBodySize: null, + nextHopProtocol: 'h3', } as unknown as PerformanceResourceTiming; _addResourceSpans(span, entry, resourceEntryName, 100, 23, 345); @@ -338,6 +351,8 @@ describe('_addResourceSpans', () => { 'server.address': 'example.com', 'url.same_origin': true, 'url.scheme': 'https', + ['network.protocol.name']: 'http', + ['network.protocol.version']: '3', }, description: '/assets/to/css', timestamp: 468, @@ -365,6 +380,7 @@ describe('_addResourceSpans', () => { encodedBodySize: 0, decodedBodySize: 0, deliveryType, + nextHopProtocol: 'h3', }); _addResourceSpans(span, entry, resourceEntryName, 100, 23, 345); diff --git a/packages/browser-utils/test/browser/utils.test.ts b/packages/browser-utils/test/browser/utils.test.ts index bb7a757e4b6a..01fb5da605c4 100644 --- a/packages/browser-utils/test/browser/utils.test.ts +++ b/packages/browser-utils/test/browser/utils.test.ts @@ -1,5 +1,5 @@ import { SentrySpan, getCurrentScope, getIsolationScope, setCurrentClient, spanToJSON } from '@sentry/core'; -import { startAndEndSpan } from '../../src/metrics/utils'; +import { extractNetworkProtocol, startAndEndSpan } from '../../src/metrics/utils'; import { TestClient, getDefaultClientOptions } from '../utils/TestClient'; describe('startAndEndSpan()', () => { @@ -54,3 +54,44 @@ describe('startAndEndSpan()', () => { expect(spanToJSON(parentSpan).start_timestamp).toEqual(123); }); }); + +describe('HTTPTimings', () => { + test.each([ + ['http/0.9', { name: 'http', version: '0.9' }], + ['http/1.0', { name: 'http', version: '1.0' }], + ['http/1.1', { name: 'http', version: '1.1' }], + ['spdy/1', { name: 'spdy', version: '1' }], + ['spdy/2', { name: 'spdy', version: '2' }], + ['spdy/3', { name: 'spdy', version: '3' }], + ['stun.turn', { name: 'stun.turn', version: 'unknown' }], + ['stun.nat-discovery', { name: 'stun.nat-discovery', version: 'unknown' }], + ['h2', { name: 'http', version: '2' }], + ['h2c', { name: 'http', version: '2c' }], + ['webrtc', { name: 'webrtc', version: 'unknown' }], + ['c-webrtc', { name: 'c-webrtc', version: 'unknown' }], + ['ftp', { name: 'ftp', version: 'unknown' }], + ['imap', { name: 'imap', version: 'unknown' }], + ['pop3', { name: 'pop', version: '3' }], + ['managesieve', { name: 'managesieve', version: 'unknown' }], + ['coap', { name: 'coap', version: 'unknown' }], + ['xmpp-client', { name: 'xmpp-client', version: 'unknown' }], + ['xmpp-server', { name: 'xmpp-server', version: 'unknown' }], + ['acme-tls/1', { name: 'acme-tls', version: '1' }], + ['mqtt', { name: 'mqtt', version: 'unknown' }], + ['dot', { name: 'dot', version: 'unknown' }], + ['ntske/1', { name: 'ntske', version: '1' }], + ['sunrpc', { name: 'sunrpc', version: 'unknown' }], + ['h3', { name: 'http', version: '3' }], + ['smb', { name: 'smb', version: 'unknown' }], + ['irc', { name: 'irc', version: 'unknown' }], + ['nntp', { name: 'nntp', version: 'unknown' }], + ['nnsp', { name: 'nnsp', version: 'unknown' }], + ['doq', { name: 'doq', version: 'unknown' }], + ['sip/2', { name: 'sip', version: '2' }], + ['tds/8.0', { name: 'tds', version: '8.0' }], + ['dicom', { name: 'dicom', version: 'unknown' }], + ['', { name: '', version: 'unknown' }], + ])('Extracting version from ALPN protocol %s', (protocol, expected) => { + expect(extractNetworkProtocol(protocol)).toMatchObject(expected); + }); +}); diff --git a/packages/browser/src/sdk.ts b/packages/browser/src/sdk.ts index d6fedeba769b..36dcade62859 100644 --- a/packages/browser/src/sdk.ts +++ b/packages/browser/src/sdk.ts @@ -53,9 +53,7 @@ export function applyDefaultOptions(optionsArg: BrowserOptions = {}): BrowserOpt release: typeof __SENTRY_RELEASE__ === 'string' // This allows build tooling to find-and-replace __SENTRY_RELEASE__ to inject a release value ? __SENTRY_RELEASE__ - : WINDOW.SENTRY_RELEASE?.id // This supports the variable that sentry-webpack-plugin injects - ? WINDOW.SENTRY_RELEASE.id - : undefined, + : WINDOW.SENTRY_RELEASE?.id, // This supports the variable that sentry-webpack-plugin injects sendClientReports: true, }; diff --git a/packages/browser/src/tracing/request.ts b/packages/browser/src/tracing/request.ts index f249d04a53ec..da7ebea712a1 100644 --- a/packages/browser/src/tracing/request.ts +++ b/packages/browser/src/tracing/request.ts @@ -2,6 +2,7 @@ import { SENTRY_XHR_DATA_KEY, addPerformanceInstrumentationHandler, addXhrInstrumentationHandler, + extractNetworkProtocol, } from '@sentry-internal/browser-utils'; import type { XhrHint } from '@sentry-internal/browser-utils'; import type { Client, HandlerDataXhr, SentryWrappedXMLHttpRequest, Span } from '@sentry/core'; @@ -230,37 +231,6 @@ function addHTTPTimings(span: Span): void { }); } -/** - * Converts ALPN protocol ids to name and version. - * - * (https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids) - * @param nextHopProtocol PerformanceResourceTiming.nextHopProtocol - */ -export function extractNetworkProtocol(nextHopProtocol: string): { name: string; version: string } { - let name = 'unknown'; - let version = 'unknown'; - let _name = ''; - for (const char of nextHopProtocol) { - // http/1.1 etc. - if (char === '/') { - [name, version] = nextHopProtocol.split('/') as [string, string]; - break; - } - // h2, h3 etc. - if (!isNaN(Number(char))) { - name = _name === 'h' ? 'http' : _name; - version = nextHopProtocol.split(_name)[1] as string; - break; - } - _name += char; - } - if (_name === nextHopProtocol) { - // webrtc, ftp, etc. - name = _name; - } - return { name, version }; -} - function getAbsoluteTime(time: number = 0): number { return ((browserPerformanceTimeOrigin() || performance.timeOrigin) + time) / 1000; } diff --git a/packages/browser/test/tracing/request.test.ts b/packages/browser/test/tracing/request.test.ts index b262053190eb..67cd96ee6717 100644 --- a/packages/browser/test/tracing/request.test.ts +++ b/packages/browser/test/tracing/request.test.ts @@ -5,7 +5,7 @@ import * as browserUtils from '@sentry-internal/browser-utils'; import * as utils from '@sentry/core'; import type { Client } from '@sentry/core'; -import { extractNetworkProtocol, instrumentOutgoingRequests, shouldAttachHeaders } from '../../src/tracing/request'; +import { instrumentOutgoingRequests, shouldAttachHeaders } from '../../src/tracing/request'; beforeAll(() => { // @ts-expect-error need to override global Request because it's not in the vi environment (even with an @@ -64,57 +64,6 @@ describe('instrumentOutgoingRequests', () => { }); }); -interface ProtocolInfo { - name: string; - version: string; -} - -describe('HTTPTimings', () => { - test('Extracting version from ALPN protocol', () => { - const nextHopToNetworkVersion: Record = { - 'http/0.9': { name: 'http', version: '0.9' }, - 'http/1.0': { name: 'http', version: '1.0' }, - 'http/1.1': { name: 'http', version: '1.1' }, - 'spdy/1': { name: 'spdy', version: '1' }, - 'spdy/2': { name: 'spdy', version: '2' }, - 'spdy/3': { name: 'spdy', version: '3' }, - 'stun.turn': { name: 'stun.turn', version: 'unknown' }, - 'stun.nat-discovery': { name: 'stun.nat-discovery', version: 'unknown' }, - h2: { name: 'http', version: '2' }, - h2c: { name: 'http', version: '2c' }, - webrtc: { name: 'webrtc', version: 'unknown' }, - 'c-webrtc': { name: 'c-webrtc', version: 'unknown' }, - ftp: { name: 'ftp', version: 'unknown' }, - imap: { name: 'imap', version: 'unknown' }, - pop3: { name: 'pop', version: '3' }, - managesieve: { name: 'managesieve', version: 'unknown' }, - coap: { name: 'coap', version: 'unknown' }, - 'xmpp-client': { name: 'xmpp-client', version: 'unknown' }, - 'xmpp-server': { name: 'xmpp-server', version: 'unknown' }, - 'acme-tls/1': { name: 'acme-tls', version: '1' }, - mqtt: { name: 'mqtt', version: 'unknown' }, - dot: { name: 'dot', version: 'unknown' }, - 'ntske/1': { name: 'ntske', version: '1' }, - sunrpc: { name: 'sunrpc', version: 'unknown' }, - h3: { name: 'http', version: '3' }, - smb: { name: 'smb', version: 'unknown' }, - irc: { name: 'irc', version: 'unknown' }, - nntp: { name: 'nntp', version: 'unknown' }, - nnsp: { name: 'nnsp', version: 'unknown' }, - doq: { name: 'doq', version: 'unknown' }, - 'sip/2': { name: 'sip', version: '2' }, - 'tds/8.0': { name: 'tds', version: '8.0' }, - dicom: { name: 'dicom', version: 'unknown' }, - }; - - const protocols = Object.keys(nextHopToNetworkVersion); - for (const protocol of protocols) { - const expected = nextHopToNetworkVersion[protocol]!; - expect(extractNetworkProtocol(protocol)).toMatchObject(expected); - } - }); -}); - describe('shouldAttachHeaders', () => { describe('should prefer `tracePropagationTargets` over defaults', () => { it('should return `true` if the url matches the new tracePropagationTargets', () => { diff --git a/packages/core/src/client.ts b/packages/core/src/client.ts index 5dfb28d76c01..14d419858529 100644 --- a/packages/core/src/client.ts +++ b/packages/core/src/client.ts @@ -937,11 +937,10 @@ export abstract class Client { if (DEBUG_BUILD) { // If something's gone wrong, log the error as a warning. If it's just us having used a `SentryError` for // control flow, log just the message (no stack) as a log-level log. - const sentryError = reason as SentryError; - if (sentryError.logLevel === 'log') { - logger.log(sentryError.message); + if (reason instanceof SentryError && reason.logLevel === 'log') { + logger.log(reason.message); } else { - logger.warn(sentryError); + logger.warn(reason); } } return undefined; diff --git a/packages/core/src/types-hoist/options.ts b/packages/core/src/types-hoist/options.ts index 49f3daa93b8e..58634930c993 100644 --- a/packages/core/src/types-hoist/options.ts +++ b/packages/core/src/types-hoist/options.ts @@ -138,15 +138,6 @@ export interface ClientOptions