From 36081aac53ec86942428f4437684f2a9e02e6b19 Mon Sep 17 00:00:00 2001 From: Abhijeet Prasad Date: Mon, 11 Mar 2024 14:55:18 -0400 Subject: [PATCH 1/3] feat(v8/profiling-node): Use OTEL powered node package --- packages/profiling-node/package.json | 2 +- packages/profiling-node/src/integration.ts | 2 +- .../profiling-node/src/spanProfileUtils.ts | 2 +- packages/profiling-node/src/utils.ts | 4 +- .../profiling-node/test/integration.test.ts | 2 +- .../test/spanProfileUtils.test.ts | 66 +++++++++---------- 6 files changed, 39 insertions(+), 39 deletions(-) diff --git a/packages/profiling-node/package.json b/packages/profiling-node/package.json index e0025e41552f..0c7b6956505d 100644 --- a/packages/profiling-node/package.json +++ b/packages/profiling-node/package.json @@ -78,7 +78,7 @@ }, "devDependencies": { "@sentry/core": "8.0.0-alpha.2", - "@sentry/node-experimental": "8.0.0-alpha.2", + "@sentry/node": "8.0.0-alpha.2", "@sentry/types": "8.0.0-alpha.2", "@sentry/utils": "8.0.0-alpha.2", "@types/node": "16.18.70", diff --git a/packages/profiling-node/src/integration.ts b/packages/profiling-node/src/integration.ts index a417ac2b1c78..4ba3fab44225 100644 --- a/packages/profiling-node/src/integration.ts +++ b/packages/profiling-node/src/integration.ts @@ -1,5 +1,5 @@ import { defineIntegration, getCurrentScope, getRootSpan, spanToJSON } from '@sentry/core'; -import type { NodeClient } from '@sentry/node-experimental'; +import type { NodeClient } from '@sentry/node'; import type { IntegrationFn, Span } from '@sentry/types'; import { logger } from '@sentry/utils'; diff --git a/packages/profiling-node/src/spanProfileUtils.ts b/packages/profiling-node/src/spanProfileUtils.ts index 61e4b7d8a4de..957ee0e16303 100644 --- a/packages/profiling-node/src/spanProfileUtils.ts +++ b/packages/profiling-node/src/spanProfileUtils.ts @@ -1,5 +1,5 @@ import { spanIsSampled, spanToJSON } from '@sentry/core'; -import type { NodeClient } from '@sentry/node-experimental'; +import type { NodeClient } from '@sentry/node'; import type { CustomSamplingContext, Span } from '@sentry/types'; import { logger, uuid4 } from '@sentry/utils'; diff --git a/packages/profiling-node/src/utils.ts b/packages/profiling-node/src/utils.ts index 626d79db9be1..2d9647e2b558 100644 --- a/packages/profiling-node/src/utils.ts +++ b/packages/profiling-node/src/utils.ts @@ -3,7 +3,7 @@ import type { Context, Envelope, Event, StackFrame, StackParser } from '@sentry/ import { env, versions } from 'process'; import { isMainThread, threadId } from 'worker_threads'; -import * as Sentry from '@sentry/node-experimental'; +import { getCurrentHub } from '@sentry/node'; import { GLOBAL_OBJ, forEachEnvelopeItem, logger } from '@sentry/utils'; import { DEBUG_BUILD } from './debug-build'; @@ -318,7 +318,7 @@ export function applyDebugMetadata(resource_paths: ReadonlyArray): Debug } // eslint-disable-next-line deprecation/deprecation - const hub = Sentry.getCurrentHub(); + const hub = getCurrentHub(); // eslint-disable-next-line deprecation/deprecation const client = hub.getClient(); const options = client && client.getOptions(); diff --git a/packages/profiling-node/test/integration.test.ts b/packages/profiling-node/test/integration.test.ts index 40ae171192e8..040ed5297205 100644 --- a/packages/profiling-node/test/integration.test.ts +++ b/packages/profiling-node/test/integration.test.ts @@ -2,7 +2,7 @@ import { EventEmitter } from 'events'; import type { Transport } from '@sentry/types'; -import type { NodeClient } from '@sentry/node-experimental'; +import type { NodeClient } from '@sentry/node'; import { _nodeProfilingIntegration } from '../src/integration'; describe('ProfilingIntegration', () => { diff --git a/packages/profiling-node/test/spanProfileUtils.test.ts b/packages/profiling-node/test/spanProfileUtils.test.ts index 9083576a775c..471668003cc0 100644 --- a/packages/profiling-node/test/spanProfileUtils.test.ts +++ b/packages/profiling-node/test/spanProfileUtils.test.ts @@ -1,15 +1,15 @@ -import * as Sentry from '@sentry/node-experimental'; +import { NodeClient, defaultStackParser, flush, makeNodeTransport, setCurrentClient, startInactiveSpan } from '@sentry/node'; -import { getMainCarrier } from '@sentry/core'; +import { getMainCarrier, } from '@sentry/core'; import type { Transport } from '@sentry/types'; import { GLOBAL_OBJ, createEnvelope, logger } from '@sentry/utils'; import { CpuProfilerBindings } from '../src/cpu_profiler'; import { _nodeProfilingIntegration } from '../src/integration'; -function makeClientWithHooks(): [Sentry.NodeClient, Transport] { +function makeClientWithHooks(): [NodeClient, Transport] { const integration = _nodeProfilingIntegration(); - const client = new Sentry.NodeClient({ - stackParser: Sentry.defaultStackParser, + const client = new NodeClient({ + stackParser: defaultStackParser, tracesSampleRate: 1, profilesSampleRate: 1, debug: true, @@ -17,7 +17,7 @@ function makeClientWithHooks(): [Sentry.NodeClient, Transport] { dsn: 'https://7fa19397baaf433f919fbe02228d5470@o1137848.ingest.sentry.io/6625302', integrations: [integration], transport: _opts => - Sentry.makeNodeTransport({ + makeNodeTransport({ url: 'https://7fa19397baaf433f919fbe02228d5470@o1137848.ingest.sentry.io/6625302', recordDroppedEvent: () => { return undefined; @@ -45,16 +45,16 @@ describe('spanProfileUtils', () => { it('pulls environment from sdk init', async () => { const [client, transport] = makeClientWithHooks(); - Sentry.setCurrentClient(client); + setCurrentClient(client); client.init(); const transportSpy = jest.spyOn(transport, 'send').mockReturnValue(Promise.resolve({})); - const transaction = Sentry.startInactiveSpan({ forceTransaction: true, name: 'profile_hub' }); + const transaction = startInactiveSpan({ forceTransaction: true, name: 'profile_hub' }); await wait(500); transaction.end(); - await Sentry.flush(1000); + await flush(1000); expect(transportSpy.mock.calls?.[0]?.[0]?.[1]?.[0]?.[1]).toMatchObject({ environment: 'test-environment' }); }); @@ -62,7 +62,7 @@ describe('spanProfileUtils', () => { const logSpy = jest.spyOn(logger, 'log'); const [client, transport] = makeClientWithHooks(); - Sentry.setCurrentClient(client); + setCurrentClient(client); client.init(); jest.spyOn(CpuProfilerBindings, 'stopProfiling').mockImplementation(() => { @@ -84,10 +84,10 @@ describe('spanProfileUtils', () => { jest.spyOn(transport, 'send').mockReturnValue(Promise.resolve({})); - const transaction = Sentry.startInactiveSpan({ forceTransaction: true, name: 'profile_hub' }); + const transaction = startInactiveSpan({ forceTransaction: true, name: 'profile_hub' }); transaction.end(); - await Sentry.flush(1000); + await flush(1000); expect(logSpy).toHaveBeenCalledWith('[Profiling] Discarding profile because it contains less than 2 samples'); @@ -100,7 +100,7 @@ describe('spanProfileUtils', () => { const logSpy = jest.spyOn(logger, 'log'); const [client, transport] = makeClientWithHooks(); - Sentry.setCurrentClient(client); + setCurrentClient(client); client.init(); jest.spyOn(CpuProfilerBindings, 'stopProfiling').mockImplementation(() => { @@ -127,11 +127,11 @@ describe('spanProfileUtils', () => { jest.spyOn(transport, 'send').mockReturnValue(Promise.resolve({})); - const transaction = Sentry.startInactiveSpan({ forceTransaction: true, name: 'profile_hub', traceId: 'boop' }); + const transaction = startInactiveSpan({ forceTransaction: true, name: 'profile_hub', traceId: 'boop' }); await wait(500); transaction.end(); - await Sentry.flush(1000); + await flush(1000); expect(logSpy).toHaveBeenCalledWith('[Profiling] Invalid traceId: ' + 'boop' + ' on profiled event'); }); @@ -139,7 +139,7 @@ describe('spanProfileUtils', () => { describe('with hooks', () => { it('calls profiler when transaction is started/stopped', async () => { const [client, transport] = makeClientWithHooks(); - Sentry.setCurrentClient(client); + setCurrentClient(client); client.init(); const startProfilingSpy = jest.spyOn(CpuProfilerBindings, 'startProfiling'); @@ -147,11 +147,11 @@ describe('spanProfileUtils', () => { jest.spyOn(transport, 'send').mockReturnValue(Promise.resolve({})); - const transaction = Sentry.startInactiveSpan({ forceTransaction: true, name: 'profile_hub' }); + const transaction = startInactiveSpan({ forceTransaction: true, name: 'profile_hub' }); await wait(500); transaction.end(); - await Sentry.flush(1000); + await flush(1000); expect(startProfilingSpy).toHaveBeenCalledTimes(1); expect((stopProfilingSpy.mock.calls[stopProfilingSpy.mock.calls.length - 1]?.[0] as string).length).toBe(32); @@ -159,16 +159,16 @@ describe('spanProfileUtils', () => { it('sends profile in the same envelope as transaction', async () => { const [client, transport] = makeClientWithHooks(); - Sentry.setCurrentClient(client); + setCurrentClient(client); client.init(); const transportSpy = jest.spyOn(transport, 'send').mockReturnValue(Promise.resolve({})); - const transaction = Sentry.startInactiveSpan({ forceTransaction: true, name: 'profile_hub' }); + const transaction = startInactiveSpan({ forceTransaction: true, name: 'profile_hub' }); await wait(500); transaction.end(); - await Sentry.flush(1000); + await flush(1000); // One for profile, the other for transaction expect(transportSpy).toHaveBeenCalledTimes(1); @@ -177,7 +177,7 @@ describe('spanProfileUtils', () => { it('does not crash if transaction has no profile context or it is invalid', async () => { const [client] = makeClientWithHooks(); - Sentry.setCurrentClient(client); + setCurrentClient(client); client.init(); // @ts-expect-error transaction is partial @@ -201,7 +201,7 @@ describe('spanProfileUtils', () => { it('if transaction was profiled, but profiler returned null', async () => { const [client, transport] = makeClientWithHooks(); - Sentry.setCurrentClient(client); + setCurrentClient(client); client.init(); jest.spyOn(CpuProfilerBindings, 'stopProfiling').mockReturnValue(null); @@ -211,11 +211,11 @@ describe('spanProfileUtils', () => { return Promise.resolve({}); }); - const transaction = Sentry.startInactiveSpan({ forceTransaction: true, name: 'profile_hub' }); + const transaction = startInactiveSpan({ forceTransaction: true, name: 'profile_hub' }); await wait(500); transaction.end(); - await Sentry.flush(1000); + await flush(1000); // Only transaction is sent expect(transportSpy.mock.calls?.[0]?.[0]?.[1]?.[0]?.[0]).toMatchObject({ type: 'transaction' }); @@ -224,18 +224,18 @@ describe('spanProfileUtils', () => { it('emits preprocessEvent for profile', async () => { const [client] = makeClientWithHooks(); - Sentry.setCurrentClient(client); + setCurrentClient(client); client.init(); const onPreprocessEvent = jest.fn(); client.on('preprocessEvent', onPreprocessEvent); - const transaction = Sentry.startInactiveSpan({ forceTransaction: true, name: 'profile_hub' }); + const transaction = startInactiveSpan({ forceTransaction: true, name: 'profile_hub' }); await wait(500); transaction.end(); - await Sentry.flush(1000); + await flush(1000); expect(onPreprocessEvent.mock.calls[1][0]).toMatchObject({ profile: { @@ -250,10 +250,10 @@ describe('spanProfileUtils', () => { const stopProfilingSpy = jest.spyOn(CpuProfilerBindings, 'stopProfiling'); const [client] = makeClientWithHooks(); - Sentry.setCurrentClient(client); + setCurrentClient(client); client.init(); - const transaction = Sentry.startInactiveSpan({ forceTransaction: true, name: 'txn' }); + const transaction = startInactiveSpan({ forceTransaction: true, name: 'txn' }); transaction.end(); transaction.end(); expect(stopProfilingSpy).toHaveBeenCalledTimes(1); @@ -289,16 +289,16 @@ describe('spanProfileUtils', () => { }); const [client, transport] = makeClientWithHooks(); - Sentry.setCurrentClient(client); + setCurrentClient(client); client.init(); const transportSpy = jest.spyOn(transport, 'send').mockReturnValue(Promise.resolve({})); - const transaction = Sentry.startInactiveSpan({ forceTransaction: true, name: 'profile_hub' }); + const transaction = startInactiveSpan({ forceTransaction: true, name: 'profile_hub' }); await wait(500); transaction.end(); - await Sentry.flush(1000); + await flush(1000); expect(transportSpy.mock.calls?.[0]?.[0]?.[1]?.[1]?.[1]).toMatchObject({ debug_meta: { From ff22dc56e0e5b068f4bbe219a5516dee5942e8e7 Mon Sep 17 00:00:00 2001 From: Abhijeet Prasad Date: Mon, 11 Mar 2024 16:40:59 -0400 Subject: [PATCH 2/3] fix lint issues --- .../profiling-node/test/spanProfileUtils.test.ts | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/packages/profiling-node/test/spanProfileUtils.test.ts b/packages/profiling-node/test/spanProfileUtils.test.ts index 471668003cc0..d87fcd3925c1 100644 --- a/packages/profiling-node/test/spanProfileUtils.test.ts +++ b/packages/profiling-node/test/spanProfileUtils.test.ts @@ -1,6 +1,13 @@ -import { NodeClient, defaultStackParser, flush, makeNodeTransport, setCurrentClient, startInactiveSpan } from '@sentry/node'; - -import { getMainCarrier, } from '@sentry/core'; +import { + NodeClient, + defaultStackParser, + flush, + makeNodeTransport, + setCurrentClient, + startInactiveSpan, +} from '@sentry/node'; + +import { getMainCarrier } from '@sentry/core'; import type { Transport } from '@sentry/types'; import { GLOBAL_OBJ, createEnvelope, logger } from '@sentry/utils'; import { CpuProfilerBindings } from '../src/cpu_profiler'; From 924d7403c002743e8c85ec1df7c575cf3a317033 Mon Sep 17 00:00:00 2001 From: Abhijeet Prasad Date: Tue, 12 Mar 2024 22:50:47 -0400 Subject: [PATCH 3/3] use json plugin --- packages/profiling-node/rollup.npm.config.mjs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/profiling-node/rollup.npm.config.mjs b/packages/profiling-node/rollup.npm.config.mjs index 057d5b8c60a6..e54bd335f7e5 100644 --- a/packages/profiling-node/rollup.npm.config.mjs +++ b/packages/profiling-node/rollup.npm.config.mjs @@ -2,11 +2,12 @@ import commonjs from '@rollup/plugin-commonjs'; import resolve from '@rollup/plugin-node-resolve'; import typescript from '@rollup/plugin-typescript'; import { makeBaseNPMConfig } from '@sentry-internal/rollup-utils'; +import { makeJsonPlugin } from '@sentry-internal/rollup-utils/plugins/index.mjs'; export default makeBaseNPMConfig({ packageSpecificConfig: { input: 'src/index.ts', output: { file: 'lib/index.js', format: 'cjs', dir: undefined, preserveModules: false }, - plugins: [resolve(), commonjs(), typescript({ tsconfig: './tsconfig.json' })], + plugins: [resolve(), makeJsonPlugin(), commonjs(), typescript({ tsconfig: './tsconfig.json' })], }, });