diff --git a/packages/angular/src/sdk.ts b/packages/angular/src/sdk.ts index 09267d1f2082..072ae51f6bbe 100644 --- a/packages/angular/src/sdk.ts +++ b/packages/angular/src/sdk.ts @@ -1,19 +1,11 @@ -import { BrowserOptions, init as browserInit, SDK_VERSION } from '@sentry/browser'; +import { BrowserOptions, buildMetadata, init as browserInit } from '@sentry/browser'; + +const PACKAGE_NAME = 'angular'; /** * Inits the Angular SDK */ export function init(options: BrowserOptions): void { - options._metadata = options._metadata || {}; - options._metadata.sdk = { - name: 'sentry.javascript.angular', - packages: [ - { - name: 'npm:@sentry/angular', - version: SDK_VERSION, - }, - ], - version: SDK_VERSION, - }; + buildMetadata(options, PACKAGE_NAME); browserInit(options); } diff --git a/packages/browser/src/client.ts b/packages/browser/src/client.ts index aeb1539e2a7d..9d454ac00cc8 100644 --- a/packages/browser/src/client.ts +++ b/packages/browser/src/client.ts @@ -1,8 +1,9 @@ -import { BaseClient, Scope, SDK_VERSION } from '@sentry/core'; +import { BaseClient, buildMetadata, Scope } from '@sentry/core'; import { Event, EventHint } from '@sentry/types'; import { getGlobalObject, logger } from '@sentry/utils'; import { BrowserBackend, BrowserOptions } from './backend'; +import { PACKAGE_NAME } from './constants'; import { injectReportDialog, ReportDialogOptions } from './helpers'; import { Breadcrumbs } from './integrations'; @@ -19,17 +20,7 @@ export class BrowserClient extends BaseClient { * @param options Configuration options for this SDK. */ public constructor(options: BrowserOptions = {}) { - options._metadata = options._metadata || {}; - options._metadata.sdk = options._metadata.sdk || { - name: 'sentry.javascript.browser', - packages: [ - { - name: 'npm:@sentry/browser', - version: SDK_VERSION, - }, - ], - version: SDK_VERSION, - }; + buildMetadata(options, PACKAGE_NAME); super(BrowserBackend, options); } diff --git a/packages/browser/src/constants.ts b/packages/browser/src/constants.ts new file mode 100644 index 000000000000..4a78a81d9de4 --- /dev/null +++ b/packages/browser/src/constants.ts @@ -0,0 +1 @@ +export const PACKAGE_NAME = 'browser'; diff --git a/packages/browser/src/exports.ts b/packages/browser/src/exports.ts index cbe5c0c4f262..313553e9a588 100644 --- a/packages/browser/src/exports.ts +++ b/packages/browser/src/exports.ts @@ -18,6 +18,7 @@ export { export { addGlobalEventProcessor, addBreadcrumb, + buildMetadata, captureException, captureEvent, captureMessage, diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 5fe8450de3ed..6ed2f4ef6811 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -21,6 +21,7 @@ export { eventToSentryRequest, sessionToSentryRequest } from './request'; export { initAndBind, ClientClass } from './sdk'; export { NoopTransport } from './transports/noop'; export { SDK_VERSION } from './version'; +export { buildMetadata } from './metadata'; import * as Integrations from './integrations'; diff --git a/packages/core/src/metadata.ts b/packages/core/src/metadata.ts new file mode 100644 index 000000000000..199f72735966 --- /dev/null +++ b/packages/core/src/metadata.ts @@ -0,0 +1,28 @@ +import { Options, SdkInfo } from '@sentry/types'; + +import { SDK_VERSION } from './version'; + +const SDK_NAME_PREFIX = 'sentry.javascript'; +const PACKAGE_NAME_PREFIX = 'npm:@sentry/'; + +/** */ +export function buildMetadata( + options: Options, + name: string, + extraPackageNames: string[] = [], + integrations?: SdkInfo['integrations'], +): void { + const packageNames = [name, ...extraPackageNames]; + options._metadata = options._metadata || {}; + options._metadata.sdk = + options._metadata.sdk || + ({ + name: `${SDK_NAME_PREFIX}.${name}`, + packages: packageNames.map(name => ({ + name: `${PACKAGE_NAME_PREFIX}/${name}`, + version: SDK_VERSION, + })), + integrations, + version: SDK_VERSION, + } as SdkInfo); +} diff --git a/packages/ember/addon/index.ts b/packages/ember/addon/index.ts index 341af580e960..a7ca8bcad05b 100644 --- a/packages/ember/addon/index.ts +++ b/packages/ember/addon/index.ts @@ -1,5 +1,5 @@ import * as Sentry from '@sentry/browser'; -import { SDK_VERSION, BrowserOptions } from '@sentry/browser'; +import { BrowserOptions, buildMetadata } from '@sentry/browser'; import { macroCondition, isDevelopingApp, getOwnConfig } from '@embroider/macros'; import { next } from '@ember/runloop'; import { assert, warn } from '@ember/debug'; @@ -8,6 +8,8 @@ import { timestampWithMs } from '@sentry/utils'; import { GlobalConfig, OwnConfig } from './types'; import { getGlobalObject } from '@sentry/utils'; +const PACKAGE_NAME = 'ember'; + function _getSentryInitConfig() { const _global = getGlobalObject(); _global.__sentryEmberConfig = _global.__sentryEmberConfig ?? {}; @@ -27,25 +29,14 @@ export function InitSentryForEmber(_runtimeConfig?: BrowserOptions) { // Merge runtime config into environment config, preferring runtime. Object.assign(environmentConfig.sentry, _runtimeConfig || {}); - const initConfig = Object.assign({}, environmentConfig.sentry); - - initConfig._metadata = initConfig._metadata || {}; - initConfig._metadata.sdk = { - name: 'sentry.javascript.ember', - packages: [ - { - name: 'npm:@sentry/ember', - version: SDK_VERSION, - }, - ], - version: SDK_VERSION, - }; + const options = Object.assign({}, environmentConfig.sentry); + buildMetadata(options, PACKAGE_NAME); // Persist Sentry init options so they are identical when performance initializers call init again. const sentryInitConfig = _getSentryInitConfig(); - Object.assign(sentryInitConfig, initConfig); + Object.assign(sentryInitConfig, options); - Sentry.init(initConfig); + Sentry.init(options); if (macroCondition(isDevelopingApp())) { if (environmentConfig.ignoreEmberOnErrorWarning) { diff --git a/packages/gatsby/src/sdk.ts b/packages/gatsby/src/sdk.ts index d3a7cac50a1f..400be15fc700 100644 --- a/packages/gatsby/src/sdk.ts +++ b/packages/gatsby/src/sdk.ts @@ -1,23 +1,15 @@ -import { init as reactInit, SDK_VERSION } from '@sentry/react'; +import { buildMetadata, init as reactInit } from '@sentry/react'; import { getIntegrationsFromOptions } from './utils/integrations'; import { GatsbyOptions } from './utils/types'; +const PACKAGE_NAME = 'gatsby'; + /** * Inits the Sentry Gatsby SDK. */ export function init(options: GatsbyOptions): void { - options._metadata = options._metadata || {}; - options._metadata.sdk = options._metadata.sdk || { - name: 'sentry.javascript.gatsby', - packages: [ - { - name: 'npm:@sentry/gatsby', - version: SDK_VERSION, - }, - ], - version: SDK_VERSION, - }; + buildMetadata(options, PACKAGE_NAME); const integrations = getIntegrationsFromOptions(options); reactInit({ diff --git a/packages/nextjs/src/constants.ts b/packages/nextjs/src/constants.ts new file mode 100644 index 000000000000..5283b73e994b --- /dev/null +++ b/packages/nextjs/src/constants.ts @@ -0,0 +1,5 @@ +export const NEXTJS_PACKAGE_NAME = 'nextjs'; + +export const REACT_PACKAGE_NAME = 'react'; + +export const NODE_PACKAGE_NAME = 'node'; diff --git a/packages/nextjs/src/index.client.ts b/packages/nextjs/src/index.client.ts index 970cadb00a06..e165e43bbd90 100644 --- a/packages/nextjs/src/index.client.ts +++ b/packages/nextjs/src/index.client.ts @@ -1,8 +1,8 @@ -import { configureScope, init as reactInit, Integrations as BrowserIntegrations } from '@sentry/react'; +import { buildMetadata, configureScope, init as reactInit, Integrations as BrowserIntegrations } from '@sentry/react'; import { defaultRequestInstrumentationOptions, Integrations as TracingIntegrations } from '@sentry/tracing'; +import { NEXTJS_PACKAGE_NAME, REACT_PACKAGE_NAME } from './constants'; import { nextRouterInstrumentation } from './performance/client'; -import { MetadataBuilder } from './utils/metadataBuilder'; import { NextjsOptions } from './utils/nextjsOptions'; import { addIntegration, UserIntegrations } from './utils/userIntegrations'; @@ -14,8 +14,7 @@ export const Integrations = { ...BrowserIntegrations, BrowserTracing }; /** Inits the Sentry NextJS SDK on the browser with the React SDK. */ export function init(options: NextjsOptions): void { - const metadataBuilder = new MetadataBuilder(options, ['nextjs', 'react']); - metadataBuilder.addSdkMetadata(); + buildMetadata(options, NEXTJS_PACKAGE_NAME, [NEXTJS_PACKAGE_NAME, REACT_PACKAGE_NAME]); options.environment = options.environment || process.env.NODE_ENV; // Only add BrowserTracing if a tracesSampleRate or tracesSampler is set diff --git a/packages/nextjs/src/index.server.ts b/packages/nextjs/src/index.server.ts index 6fd4e1fce468..6de407c02598 100644 --- a/packages/nextjs/src/index.server.ts +++ b/packages/nextjs/src/index.server.ts @@ -1,13 +1,13 @@ import { Carrier, getHubFromCarrier, getMainCarrier } from '@sentry/hub'; import { RewriteFrames } from '@sentry/integrations'; -import { configureScope, getCurrentHub, init as nodeInit, Integrations } from '@sentry/node'; +import { buildMetadata, configureScope, getCurrentHub, init as nodeInit, Integrations } from '@sentry/node'; import { Event } from '@sentry/types'; import { escapeStringForRegex, logger } from '@sentry/utils'; import * as domainModule from 'domain'; import * as path from 'path'; +import { NEXTJS_PACKAGE_NAME, NODE_PACKAGE_NAME } from './constants'; import { instrumentServer } from './utils/instrumentServer'; -import { MetadataBuilder } from './utils/metadataBuilder'; import { NextjsOptions } from './utils/nextjsOptions'; import { addIntegration } from './utils/userIntegrations'; @@ -33,8 +33,7 @@ export function init(options: NextjsOptions): void { return; } - const metadataBuilder = new MetadataBuilder(options, ['nextjs', 'node']); - metadataBuilder.addSdkMetadata(); + buildMetadata(options, NEXTJS_PACKAGE_NAME, [NEXTJS_PACKAGE_NAME, NODE_PACKAGE_NAME]); options.environment = options.environment || process.env.NODE_ENV; addServerIntegrations(options); // Right now we only capture frontend sessions for Next.js diff --git a/packages/nextjs/src/utils/metadataBuilder.ts b/packages/nextjs/src/utils/metadataBuilder.ts deleted file mode 100644 index 8dba9f821ebc..000000000000 --- a/packages/nextjs/src/utils/metadataBuilder.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { SDK_VERSION } from '@sentry/core'; -import { Package, SdkInfo } from '@sentry/types'; - -import { NextjsOptions } from './nextjsOptions'; - -export const SDK_NAME = 'sentry.javascript.nextjs'; -export const PACKAGE_NAME_PREFIX = 'npm:@sentry/'; - -/** - * A builder for the SDK metadata in the options for the SDK initialization. - */ -export class MetadataBuilder { - private _options: NextjsOptions; - private _packageNames: string[]; - - public constructor(options: NextjsOptions, packages: string[]) { - this._options = options; - this._packageNames = packages; - } - - /** JSDoc */ - public addSdkMetadata(): void { - this._options._metadata = this._options._metadata || {}; - this._options._metadata.sdk = this._getSdkInfo(); - } - - /** JSDoc */ - private _getSdkInfo(): SdkInfo { - return { - name: SDK_NAME, - version: SDK_VERSION, - packages: this._getPackages(), - }; - } - - /** JSDoc */ - private _getPackages(): Package[] { - return this._packageNames.map((pkgName: string) => { - return { - name: PACKAGE_NAME_PREFIX + pkgName, - version: SDK_VERSION, - }; - }); - } -} diff --git a/packages/nextjs/test/utils/metadataBuilder.test.ts b/packages/nextjs/test/utils/metadataBuilder.test.ts deleted file mode 100644 index 888a35f765d4..000000000000 --- a/packages/nextjs/test/utils/metadataBuilder.test.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { SDK_VERSION } from '@sentry/core'; -import { Package, SdkInfo } from '@sentry/types'; - -import { MetadataBuilder, PACKAGE_NAME_PREFIX, SDK_NAME } from '../../src/utils/metadataBuilder'; -import { NextjsOptions } from '../../src/utils/nextjsOptions'; - -describe('build metadata', () => { - test('without packages', () => { - const nextjsOptions: NextjsOptions = {}; - const metadataPackages: string[] = []; - testMetadataBuilder(nextjsOptions, metadataPackages); - }); - - test('with packages', () => { - const nextjsOptions: NextjsOptions = {}; - const metadataPackages: string[] = ['packageA', 'packageB']; - testMetadataBuilder(nextjsOptions, metadataPackages); - }); -}); - -function testMetadataBuilder(nextjsOptions: NextjsOptions, packages: string[]): void { - new MetadataBuilder(nextjsOptions, packages).addSdkMetadata(); - const optionsMetadata = nextjsOptions._metadata; - expect(optionsMetadata).toBeDefined(); - const sdkInfo = optionsMetadata?.sdk; - testSdkInfo(sdkInfo); - testSdkInfoPackages(sdkInfo?.packages, packages); -} - -function testSdkInfo(sdkInfo: SdkInfo | undefined): void { - expect(sdkInfo).toBeDefined(); - expect(sdkInfo?.name).toBeDefined(); - expect(sdkInfo?.name).toEqual(SDK_NAME); - expect(sdkInfo?.version).toEqual(expect.any(String)); - expect(sdkInfo?.packages).toEqual(expect.any(Array)); -} - -function testSdkInfoPackages(actualPkgs: Package[] | undefined, expectedPkgNames: string[]): void { - expect(actualPkgs).toBeDefined(); - expect(actualPkgs).toHaveLength(expectedPkgNames.length); - - const pkgNames = actualPkgs?.map((currentPkg: Package) => { - expect(currentPkg.version).toBeDefined(); - expect(currentPkg.version).toEqual(SDK_VERSION); - - expect(currentPkg.name).toBeDefined(); - const pkgPrefix = currentPkg.name.substring(0, PACKAGE_NAME_PREFIX.length); - expect(pkgPrefix).toEqual(PACKAGE_NAME_PREFIX); - return currentPkg.name.substring(PACKAGE_NAME_PREFIX.length); - }); - expect(pkgNames).toEqual(expectedPkgNames); -} diff --git a/packages/node/src/client.ts b/packages/node/src/client.ts index 7f4842b48ad4..149c802bf29a 100644 --- a/packages/node/src/client.ts +++ b/packages/node/src/client.ts @@ -1,9 +1,10 @@ -import { BaseClient, Scope, SDK_VERSION } from '@sentry/core'; +import { BaseClient, buildMetadata, Scope } from '@sentry/core'; import { SessionFlusher } from '@sentry/hub'; import { Event, EventHint, RequestSessionStatus } from '@sentry/types'; import { logger } from '@sentry/utils'; import { NodeBackend } from './backend'; +import { PACKAGE_NAME } from './constants'; import { NodeOptions } from './types'; /** @@ -20,18 +21,7 @@ export class NodeClient extends BaseClient { * @param options Configuration options for this SDK. */ public constructor(options: NodeOptions) { - options._metadata = options._metadata || {}; - options._metadata.sdk = options._metadata.sdk || { - name: 'sentry.javascript.node', - packages: [ - { - name: 'npm:@sentry/node', - version: SDK_VERSION, - }, - ], - version: SDK_VERSION, - }; - + buildMetadata(options, PACKAGE_NAME); super(NodeBackend, options); } diff --git a/packages/node/src/constants.ts b/packages/node/src/constants.ts new file mode 100644 index 000000000000..7e2753b6330b --- /dev/null +++ b/packages/node/src/constants.ts @@ -0,0 +1 @@ +export const PACKAGE_NAME = 'node'; diff --git a/packages/node/src/index.ts b/packages/node/src/index.ts index b3bae88dfa8a..39915137261e 100644 --- a/packages/node/src/index.ts +++ b/packages/node/src/index.ts @@ -18,6 +18,7 @@ export { export { addGlobalEventProcessor, addBreadcrumb, + buildMetadata, captureException, captureEvent, captureMessage, diff --git a/packages/react/src/sdk.ts b/packages/react/src/sdk.ts index 038a509c03d7..00574b6248cb 100644 --- a/packages/react/src/sdk.ts +++ b/packages/react/src/sdk.ts @@ -1,19 +1,11 @@ -import { BrowserOptions, init as browserInit, SDK_VERSION } from '@sentry/browser'; +import { BrowserOptions, buildMetadata, init as browserInit } from '@sentry/browser'; + +const PACKAGE_NAME = 'react'; /** * Inits the React SDK */ export function init(options: BrowserOptions): void { - options._metadata = options._metadata || {}; - options._metadata.sdk = options._metadata.sdk || { - name: 'sentry.javascript.react', - packages: [ - { - name: 'npm:@sentry/react', - version: SDK_VERSION, - }, - ], - version: SDK_VERSION, - }; + buildMetadata(options, PACKAGE_NAME); browserInit(options); } diff --git a/packages/serverless/src/awslambda.ts b/packages/serverless/src/awslambda.ts index 70b09d3cc97c..ad7ba9ecccad 100644 --- a/packages/serverless/src/awslambda.ts +++ b/packages/serverless/src/awslambda.ts @@ -23,6 +23,7 @@ import { performance } from 'perf_hooks'; import { types } from 'util'; import { AWSServices } from './awsservices'; +import { PACKAGE_NAME } from './constants'; import { serverlessEventProcessor } from './utils'; export * from '@sentry/node'; @@ -65,18 +66,7 @@ export function init(options: Sentry.NodeOptions = {}): void { options.defaultIntegrations = defaultIntegrations; } - options._metadata = options._metadata || {}; - options._metadata.sdk = { - name: 'sentry.javascript.serverless', - integrations: ['AWSLambda'], - packages: [ - { - name: 'npm:@sentry/serverless', - version: Sentry.SDK_VERSION, - }, - ], - version: Sentry.SDK_VERSION, - }; + Sentry.buildMetadata(options, PACKAGE_NAME, [], ['AWSLambda']); Sentry.init(options); Sentry.addGlobalEventProcessor(serverlessEventProcessor); diff --git a/packages/serverless/src/constants.ts b/packages/serverless/src/constants.ts new file mode 100644 index 000000000000..04b3a3a20d1e --- /dev/null +++ b/packages/serverless/src/constants.ts @@ -0,0 +1 @@ +export const PACKAGE_NAME = 'serverless'; diff --git a/packages/serverless/src/gcpfunction/index.ts b/packages/serverless/src/gcpfunction/index.ts index 2cd8a0bec73f..2f92d6e64fc7 100644 --- a/packages/serverless/src/gcpfunction/index.ts +++ b/packages/serverless/src/gcpfunction/index.ts @@ -1,6 +1,7 @@ import * as Sentry from '@sentry/node'; import { Integration } from '@sentry/types'; +import { PACKAGE_NAME } from '../constants'; import { GoogleCloudGrpc } from '../google-cloud-grpc'; import { GoogleCloudHttp } from '../google-cloud-http'; import { serverlessEventProcessor } from '../utils'; @@ -23,18 +24,7 @@ export function init(options: Sentry.NodeOptions = {}): void { options.defaultIntegrations = defaultIntegrations; } - options._metadata = options._metadata || {}; - options._metadata.sdk = { - name: 'sentry.javascript.serverless', - integrations: ['GCPFunction'], - packages: [ - { - name: 'npm:@sentry/serverless', - version: Sentry.SDK_VERSION, - }, - ], - version: Sentry.SDK_VERSION, - }; + Sentry.buildMetadata(options, PACKAGE_NAME, [], ['GCPFunction']); Sentry.init(options); Sentry.addGlobalEventProcessor(serverlessEventProcessor); diff --git a/packages/vue/src/sdk.ts b/packages/vue/src/sdk.ts index ee2e05b13e7e..c2ed1a3875e2 100644 --- a/packages/vue/src/sdk.ts +++ b/packages/vue/src/sdk.ts @@ -1,4 +1,4 @@ -import { init as browserInit, SDK_VERSION } from '@sentry/browser'; +import { buildMetadata, init as browserInit } from '@sentry/browser'; import { getGlobalObject, logger } from '@sentry/utils'; import { DEFAULT_HOOKS } from './constants'; @@ -6,6 +6,8 @@ import { attachErrorHandler } from './errorhandler'; import { createTracingMixins } from './tracing'; import { Options, TracingOptions, Vue } from './types'; +const PACKAGE_NAME = 'vue'; + const DEFAULT_CONFIG: Options = { Vue: getGlobalObject<{ Vue: Vue }>().Vue, attachProps: true, @@ -13,18 +15,6 @@ const DEFAULT_CONFIG: Options = { hooks: DEFAULT_HOOKS, timeout: 2000, trackComponents: false, - _metadata: { - sdk: { - name: 'sentry.javascript.vue', - packages: [ - { - name: 'npm:@sentry/vue', - version: SDK_VERSION, - }, - ], - version: SDK_VERSION, - }, - }, }; /** @@ -38,6 +28,7 @@ export function init( ...config, }; + buildMetadata(options, PACKAGE_NAME); browserInit(options); if (!options.Vue && !options.app) {