From 0a3779182e914e58de2810437aef979a24b42464 Mon Sep 17 00:00:00 2001 From: JonasBa Date: Wed, 31 Jul 2024 17:31:32 -0400 Subject: [PATCH 1/5] feat: attach sdk info to chunks --- packages/profiling-node/src/integration.ts | 2 +- packages/profiling-node/src/utils.ts | 8 ++++ .../test/spanProfileUtils.test.ts | 47 ++++++++++++++++++- packages/types/src/profiling.ts | 4 ++ 4 files changed, 59 insertions(+), 2 deletions(-) diff --git a/packages/profiling-node/src/integration.ts b/packages/profiling-node/src/integration.ts index b05a919fc949..6b773444efc6 100644 --- a/packages/profiling-node/src/integration.ts +++ b/packages/profiling-node/src/integration.ts @@ -231,7 +231,7 @@ class ContinuousProfiler { } DEBUG_BUILD && logger.log(`[Profiling] Profile chunk ${this._chunkData.id} sent to Sentry.`); - const chunk = createProfilingChunkEvent(this._client, this._client.getOptions(), profile, { + const chunk = createProfilingChunkEvent(this._client, this._client.getOptions(), profile, this._client.getSdkMetadata()?.sdk, { chunk_id: this._chunkData.id, trace_id: this._chunkData.startTraceID, profiler_id: this._profilerId, diff --git a/packages/profiling-node/src/utils.ts b/packages/profiling-node/src/utils.ts index 673901990d90..2b3d0b7cbff4 100644 --- a/packages/profiling-node/src/utils.ts +++ b/packages/profiling-node/src/utils.ts @@ -194,12 +194,14 @@ function createProfileChunkPayload( trace_id, profiler_id, chunk_id, + sdk, }: { release: string; environment: string; trace_id: string | undefined; chunk_id: string; profiler_id: string; + sdk: SdkInfo | undefined; }, ): ProfileChunk { // Log a warning if the profile has an invalid traceId (should be uuidv4). @@ -213,6 +215,10 @@ function createProfileChunkPayload( const profile: ProfileChunk = { chunk_id: chunk_id, + client_sdk: { + name: sdk?.name ?? 'unknown', + version: sdk?.version ?? 'unknown', + }, profiler_id: profiler_id, platform: 'node', version: CONTINUOUS_FORMAT_VERSION, @@ -235,6 +241,7 @@ export function createProfilingChunkEvent( client: Client, options: { release?: string; environment?: string }, profile: RawChunkCpuProfile, + sdk: SdkInfo | undefined, identifiers: { trace_id: string | undefined; chunk_id: string; profiler_id: string }, ): ProfileChunk | null { if (!isValidProfileChunk(profile)) { @@ -247,6 +254,7 @@ export function createProfilingChunkEvent( trace_id: identifiers.trace_id ?? '', chunk_id: identifiers.chunk_id, profiler_id: identifiers.profiler_id, + sdk }); } diff --git a/packages/profiling-node/test/spanProfileUtils.test.ts b/packages/profiling-node/test/spanProfileUtils.test.ts index 766a0059d02e..9843aa5fa6e6 100644 --- a/packages/profiling-node/test/spanProfileUtils.test.ts +++ b/packages/profiling-node/test/spanProfileUtils.test.ts @@ -2,7 +2,7 @@ import * as Sentry from '@sentry/node'; import { getMainCarrier } from '@sentry/core'; import type { NodeClientOptions } from '@sentry/node/build/types/types'; -import type { Transport } from '@sentry/types'; +import type { ProfileChunk, Transport } from '@sentry/types'; import { GLOBAL_OBJ, createEnvelope, logger } from '@sentry/utils'; import { CpuProfilerBindings } from '../src/cpu_profiler'; import { type ProfilingIntegration, _nodeProfilingIntegration } from '../src/integration'; @@ -402,6 +402,51 @@ describe('continuous profiling', () => { delete getMainCarrier().__SENTRY__; }); + it('attaches sdk metadata to chunks', () => { + // @ts-expect-error we just mock the return type and ignore the signature + jest.spyOn(CpuProfilerBindings, 'stopProfiling').mockImplementation(() => { + return { + samples: [ + { + stack_id: 0, + thread_id: '0', + elapsed_since_start_ns: '10', + }, + { + stack_id: 0, + thread_id: '0', + elapsed_since_start_ns: '10', + }, + ], + measurements: {}, + stacks: [[0]], + frames: [], + resources: [], + profiler_logging_mode: 'lazy', + }; + }); + + const [client, transport] = makeContinuousProfilingClient(); + Sentry.setCurrentClient(client); + client.init(); + + const transportSpy = jest.spyOn(transport, 'send').mockReturnValue(Promise.resolve({})); + + const integration = client.getIntegrationByName('ProfilingIntegration'); + if (!integration) { + throw new Error('Profiling integration not found'); + } + integration._profiler.start(); + jest.advanceTimersByTime(1000); + integration._profiler.stop(); + jest.advanceTimersByTime(1000); + + const profile = transportSpy.mock.calls?.[0]?.[0]?.[1]?.[0]?.[1] as ProfileChunk; + expect(profile.client_sdk.name).toBe('sentry.javascript.node'); + expect(profile.client_sdk.version).toEqual(expect.stringMatching(/\d+\.\d+\.\d+/)); + }); + + it('initializes the continuous profiler and binds the sentry client', () => { const startProfilingSpy = jest.spyOn(CpuProfilerBindings, 'startProfiling'); diff --git a/packages/types/src/profiling.ts b/packages/types/src/profiling.ts index 48dd797492bf..8f5f4cc2e890 100644 --- a/packages/types/src/profiling.ts +++ b/packages/types/src/profiling.ts @@ -126,4 +126,8 @@ export interface Profile extends BaseProfile { export interface ProfileChunk extends BaseProfile { chunk_id: string; profiler_id: string; + client_sdk: { + name: string; + version: string; + }; } From 1b50dec4ef81f973a3d0d13f75e6e1e58a23ceb9 Mon Sep 17 00:00:00 2001 From: JonasBa Date: Wed, 31 Jul 2024 18:18:48 -0400 Subject: [PATCH 2/5] add sentry.javascript.node as default sdk name --- packages/profiling-node/src/utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/profiling-node/src/utils.ts b/packages/profiling-node/src/utils.ts index 2b3d0b7cbff4..d643a4060f16 100644 --- a/packages/profiling-node/src/utils.ts +++ b/packages/profiling-node/src/utils.ts @@ -216,7 +216,7 @@ function createProfileChunkPayload( const profile: ProfileChunk = { chunk_id: chunk_id, client_sdk: { - name: sdk?.name ?? 'unknown', + name: sdk?.name ?? 'sentry.javascript.node', version: sdk?.version ?? 'unknown', }, profiler_id: profiler_id, From 1403bf59bf0aceb614b05f8d855d42f8c1c52cbf Mon Sep 17 00:00:00 2001 From: JonasBa Date: Wed, 31 Jul 2024 21:17:42 -0400 Subject: [PATCH 3/5] default version to 0.0.0 --- packages/profiling-node/src/utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/profiling-node/src/utils.ts b/packages/profiling-node/src/utils.ts index d643a4060f16..98e16b0523d6 100644 --- a/packages/profiling-node/src/utils.ts +++ b/packages/profiling-node/src/utils.ts @@ -217,7 +217,7 @@ function createProfileChunkPayload( chunk_id: chunk_id, client_sdk: { name: sdk?.name ?? 'sentry.javascript.node', - version: sdk?.version ?? 'unknown', + version: sdk?.version ?? '0.0.0', }, profiler_id: profiler_id, platform: 'node', From 2e8957e51ea845b57813551ebdb7328521c26723 Mon Sep 17 00:00:00 2001 From: JonasBa Date: Thu, 1 Aug 2024 09:33:47 -0400 Subject: [PATCH 4/5] format --- packages/profiling-node/src/integration.ts | 16 +++++++++++----- packages/profiling-node/src/utils.ts | 2 +- .../profiling-node/test/spanProfileUtils.test.ts | 1 - 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/packages/profiling-node/src/integration.ts b/packages/profiling-node/src/integration.ts index 6b773444efc6..17cf4fdafbca 100644 --- a/packages/profiling-node/src/integration.ts +++ b/packages/profiling-node/src/integration.ts @@ -231,11 +231,17 @@ class ContinuousProfiler { } DEBUG_BUILD && logger.log(`[Profiling] Profile chunk ${this._chunkData.id} sent to Sentry.`); - const chunk = createProfilingChunkEvent(this._client, this._client.getOptions(), profile, this._client.getSdkMetadata()?.sdk, { - chunk_id: this._chunkData.id, - trace_id: this._chunkData.startTraceID, - profiler_id: this._profilerId, - }); + const chunk = createProfilingChunkEvent( + this._client, + this._client.getOptions(), + profile, + this._client.getSdkMetadata()?.sdk, + { + chunk_id: this._chunkData.id, + trace_id: this._chunkData.startTraceID, + profiler_id: this._profilerId, + }, + ); if (!chunk) { DEBUG_BUILD && logger.log(`[Profiling] Failed to create profile chunk for: ${this._chunkData.id}`); diff --git a/packages/profiling-node/src/utils.ts b/packages/profiling-node/src/utils.ts index 98e16b0523d6..0eb4fe4281b4 100644 --- a/packages/profiling-node/src/utils.ts +++ b/packages/profiling-node/src/utils.ts @@ -254,7 +254,7 @@ export function createProfilingChunkEvent( trace_id: identifiers.trace_id ?? '', chunk_id: identifiers.chunk_id, profiler_id: identifiers.profiler_id, - sdk + sdk, }); } diff --git a/packages/profiling-node/test/spanProfileUtils.test.ts b/packages/profiling-node/test/spanProfileUtils.test.ts index 9843aa5fa6e6..4a90caa0f353 100644 --- a/packages/profiling-node/test/spanProfileUtils.test.ts +++ b/packages/profiling-node/test/spanProfileUtils.test.ts @@ -446,7 +446,6 @@ describe('continuous profiling', () => { expect(profile.client_sdk.version).toEqual(expect.stringMatching(/\d+\.\d+\.\d+/)); }); - it('initializes the continuous profiler and binds the sentry client', () => { const startProfilingSpy = jest.spyOn(CpuProfilerBindings, 'startProfiling'); From abf6bea0cee9c0f3db67dfa24cb70f4ef615cab2 Mon Sep 17 00:00:00 2001 From: JonasBa Date: Thu, 1 Aug 2024 11:09:04 -0400 Subject: [PATCH 5/5] disable max lines for this file --- packages/profiling-node/src/integration.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/profiling-node/src/integration.ts b/packages/profiling-node/src/integration.ts index 17cf4fdafbca..50f240bff732 100644 --- a/packages/profiling-node/src/integration.ts +++ b/packages/profiling-node/src/integration.ts @@ -1,3 +1,5 @@ +/* eslint-disable max-lines */ + import { defineIntegration, getCurrentScope,