From 03786b0782c592d89c5523b2d5b22ac05a2c7cc7 Mon Sep 17 00:00:00 2001 From: JonasBa Date: Wed, 31 Jul 2024 17:31:32 -0400 Subject: [PATCH] ref: 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; + }; }