@sentry/profiling-node 8.29.0 → 8.31.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/bindings/cpu_profiler.cc +16 -15
  2. package/lib/cjs/index.js +73 -34
  3. package/lib/cjs/index.js.map +1 -1
  4. package/lib/esm/index.js +89 -43
  5. package/lib/esm/index.js.map +1 -1
  6. package/lib/sentry_cpu_profiler-darwin-arm64-108.node +0 -0
  7. package/lib/sentry_cpu_profiler-darwin-arm64-115.node +0 -0
  8. package/lib/sentry_cpu_profiler-darwin-arm64-127.node +0 -0
  9. package/lib/sentry_cpu_profiler-darwin-arm64-93.node +0 -0
  10. package/lib/sentry_cpu_profiler-darwin-x64-108.node +0 -0
  11. package/lib/sentry_cpu_profiler-darwin-x64-115.node +0 -0
  12. package/lib/sentry_cpu_profiler-darwin-x64-127.node +0 -0
  13. package/lib/sentry_cpu_profiler-darwin-x64-93.node +0 -0
  14. package/lib/sentry_cpu_profiler-linux-arm64-glibc-108.node +0 -0
  15. package/lib/sentry_cpu_profiler-linux-arm64-glibc-115.node +0 -0
  16. package/lib/sentry_cpu_profiler-linux-arm64-glibc-127.node +0 -0
  17. package/lib/sentry_cpu_profiler-linux-arm64-glibc-93.node +0 -0
  18. package/lib/sentry_cpu_profiler-linux-arm64-musl-108.node +0 -0
  19. package/lib/sentry_cpu_profiler-linux-arm64-musl-115.node +0 -0
  20. package/lib/sentry_cpu_profiler-linux-arm64-musl-127.node +0 -0
  21. package/lib/sentry_cpu_profiler-linux-arm64-musl-93.node +0 -0
  22. package/lib/sentry_cpu_profiler-linux-x64-glibc-108.node +0 -0
  23. package/lib/sentry_cpu_profiler-linux-x64-glibc-115.node +0 -0
  24. package/lib/sentry_cpu_profiler-linux-x64-glibc-127.node +0 -0
  25. package/lib/sentry_cpu_profiler-linux-x64-glibc-93.node +0 -0
  26. package/lib/sentry_cpu_profiler-linux-x64-musl-108.node +0 -0
  27. package/lib/sentry_cpu_profiler-linux-x64-musl-115.node +0 -0
  28. package/lib/sentry_cpu_profiler-linux-x64-musl-127.node +0 -0
  29. package/lib/sentry_cpu_profiler-linux-x64-musl-93.node +0 -0
  30. package/lib/sentry_cpu_profiler-win32-x64-108.node +0 -0
  31. package/lib/sentry_cpu_profiler-win32-x64-115.node +0 -0
  32. package/lib/sentry_cpu_profiler-win32-x64-127.node +0 -0
  33. package/lib/sentry_cpu_profiler-win32-x64-93.node +0 -0
  34. package/lib/types/cpu_profiler.d.ts.map +1 -1
  35. package/lib/types/integration.d.ts.map +1 -1
  36. package/package.json +5 -5
package/lib/esm/index.js CHANGED
@@ -2,23 +2,17 @@ import { _nullishCoalesce, _optionalChain, _optionalChainDelete } from '@sentry/
2
2
  import { spanIsSampled, spanToJSON, defineIntegration, getRootSpan, getCurrentScope, getIsolationScope, getGlobalScope } from '@sentry/core';
3
3
  import { logger, GLOBAL_OBJ, parseSemver, forEachEnvelopeItem, createEnvelope, uuid4, dsnToString, LRUMap } from '@sentry/utils';
4
4
  import { platform as platform$1, arch as arch$1 } from 'node:os';
5
- import { resolve, join } from 'node:path';
5
+ import cjsPath, { resolve, join } from 'node:path';
6
6
  import { versions, env } from 'node:process';
7
7
  import { threadId } from 'node:worker_threads';
8
8
  import { familySync } from 'detect-libc';
9
9
  import { getAbi } from 'node-abi';
10
+ import cjsUrl from 'node:url';
11
+ import cjsModule from 'node:module';
10
12
  import * as os from 'os';
11
13
  import { versions as versions$1, env as env$1 } from 'process';
12
14
  import { threadId as threadId$1, isMainThread } from 'worker_threads';
13
15
 
14
-
15
- // -- Shims --
16
- import cjsUrl from 'node:url';
17
- import cjsPath from 'node:path';
18
- import cjsModule from 'node:module';
19
- const __filename = cjsUrl.fileURLToPath(import.meta.url);
20
- const __dirname = cjsPath.dirname(__filename);
21
- const require = cjsModule.createRequire(import.meta.url);
22
16
  /**
23
17
  * This serves as a build time flag that will be true by default, but false in non-debug builds or if users replace `__SENTRY_DEBUG__` in their generated code.
24
18
  *
@@ -26,6 +20,19 @@ const require = cjsModule.createRequire(import.meta.url);
26
20
  */
27
21
  const DEBUG_BUILD = (typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__);
28
22
 
23
+ if(typeof __filename === 'undefined'){
24
+ globalThis.__filename = cjsUrl.fileURLToPath(import.meta.url);
25
+ }
26
+
27
+ if(typeof __dirname === 'undefined'){
28
+ globalThis.__dirname = cjsPath.dirname(__filename);
29
+ }
30
+
31
+ if(typeof require === 'undefined'){
32
+ globalThis.require = cjsModule.createRequire(import.meta.url);
33
+ }
34
+
35
+
29
36
  const stdlib = familySync();
30
37
  const platform = process.env['BUILD_PLATFORM'] || platform$1();
31
38
  const arch = process.env['BUILD_ARCH'] || arch$1();
@@ -905,10 +912,10 @@ function setupAutomatedSpanProfiling(client) {
905
912
  });
906
913
  }
907
914
 
908
- class ContinuousProfiler {constructor() { ContinuousProfiler.prototype.__init.call(this);ContinuousProfiler.prototype.__init2.call(this);ContinuousProfiler.prototype.__init3.call(this); }
909
- __init() {this._profilerId = uuid4();}
910
- __init2() {this._client = undefined;}
911
- __init3() {this._chunkData = undefined;}
915
+ class ContinuousProfiler {constructor() { ContinuousProfiler.prototype.__init.call(this);ContinuousProfiler.prototype.__init2.call(this); }
916
+
917
+ __init() {this._client = undefined;}
918
+ __init2() {this._chunkData = undefined;}
912
919
 
913
920
  /**
914
921
  * Called when the profiler is attached to the client (continuous mode is enabled). If of the profiler
@@ -917,15 +924,48 @@ class ContinuousProfiler {constructor() { ContinuousProfiler.prototype.__init.ca
917
924
  */
918
925
  initialize(client) {
919
926
  this._client = client;
927
+
928
+ // Attaches a listener to beforeSend which will add the threadId data to the event being sent.
929
+ // This adds a constant overhead to all events being sent which could be improved to only attach
930
+ // and detach the listener during a profiler session
931
+ this._client.on('beforeSendEvent', this._onBeforeSendThreadContextAssignment.bind(this));
920
932
  }
921
933
 
922
934
  /**
923
- * Recursively schedules chunk profiling to start and stop at a set interval.
924
- * Once the user calls stop(), the current chunk will be stopped and flushed to Sentry and no new chunks will
925
- * will be started. To restart continuous mode after calling stop(), the user must call start() again.
935
+ * Initializes a new profilerId session and schedules chunk profiling.
926
936
  * @returns void
927
937
  */
928
938
  start() {
939
+ if (!this._client) {
940
+ DEBUG_BUILD && logger.log('[Profiling] Failed to start, sentry client was never attached to the profiler.');
941
+ return;
942
+ }
943
+
944
+ // Flush any existing chunks before starting a new one.
945
+ this._chunkStop();
946
+
947
+ // Restart the profiler session
948
+ this._setupSpanChunkInstrumentation();
949
+ this._chunkStart();
950
+ }
951
+
952
+ /**
953
+ * Stops the current chunk and flushes the profile to Sentry.
954
+ * @returns void
955
+ */
956
+ stop() {
957
+ if (!this._client) {
958
+ DEBUG_BUILD && logger.log('[Profiling] Failed to stop, sentry client was never attached to the profiler.');
959
+ return;
960
+ }
961
+ this._chunkStop();
962
+ this._teardownSpanChunkInstrumentation();
963
+ }
964
+
965
+ /**
966
+ * Stop profiler and initializes profiling of the next chunk
967
+ */
968
+ _chunkStart() {
929
969
  if (!this._client) {
930
970
  // The client is not attached to the profiler if the user has not enabled continuous profiling.
931
971
  // In this case, calling start() and stop() is a noop action.The reason this exists is because
@@ -938,20 +978,16 @@ class ContinuousProfiler {constructor() { ContinuousProfiler.prototype.__init.ca
938
978
  logger.log(
939
979
  `[Profiling] Chunk with chunk_id ${this._chunkData.id} is still running, current chunk will be stopped a new chunk will be started.`,
940
980
  );
941
- this.stop();
981
+ this._chunkStop();
942
982
  }
943
983
 
944
- const traceId =
945
- getCurrentScope().getPropagationContext().traceId || getIsolationScope().getPropagationContext().traceId;
946
- this._initializeChunk(traceId);
947
- this._startChunkProfiling(this._chunkData);
984
+ this._startChunkProfiling();
948
985
  }
949
986
 
950
987
  /**
951
- * Stops the current chunk and flushes the profile to Sentry.
952
- * @returns void
988
+ * Stops profiling of the current chunks and flushes the profile to Sentry
953
989
  */
954
- stop() {
990
+ _chunkStop() {
955
991
  if (_optionalChain([this, 'access', _6 => _6._chunkData, 'optionalAccess', _7 => _7.timer])) {
956
992
  global.clearTimeout(this._chunkData.timer);
957
993
  this._chunkData.timer = undefined;
@@ -968,12 +1004,17 @@ class ContinuousProfiler {constructor() { ContinuousProfiler.prototype.__init.ca
968
1004
  return;
969
1005
  }
970
1006
 
971
- const profile = this._stopChunkProfiling(this._chunkData);
1007
+ const profile = CpuProfilerBindings.stopProfiling(this._chunkData.id, ProfileFormat.CHUNK);
972
1008
 
973
1009
  if (!profile) {
974
1010
  DEBUG_BUILD && logger.log(`[Profiling] _chunkiledStartTraceID to collect profile for: ${this._chunkData.id}`);
975
1011
  return;
976
1012
  }
1013
+ if (!this._profilerId) {
1014
+ DEBUG_BUILD &&
1015
+ logger.log('[Profiling] Profile chunk does not contain a valid profiler_id, this is a bug in the SDK');
1016
+ return;
1017
+ }
977
1018
  if (profile) {
978
1019
  DEBUG_BUILD && logger.log(`[Profiling] Sending profile chunk ${this._chunkData.id}.`);
979
1020
  }
@@ -993,7 +1034,7 @@ class ContinuousProfiler {constructor() { ContinuousProfiler.prototype.__init.ca
993
1034
 
994
1035
  if (!chunk) {
995
1036
  DEBUG_BUILD && logger.log(`[Profiling] Failed to create profile chunk for: ${this._chunkData.id}`);
996
- this._reset();
1037
+ this._resetChunkData();
997
1038
  return;
998
1039
  }
999
1040
 
@@ -1002,7 +1043,7 @@ class ContinuousProfiler {constructor() { ContinuousProfiler.prototype.__init.ca
1002
1043
  // the format may negatively impact the performance of the application. To avoid
1003
1044
  // blocking for too long, enqueue the next chunk start inside the next macrotask.
1004
1045
  // clear current chunk
1005
- this._reset();
1046
+ this._resetChunkData();
1006
1047
  }
1007
1048
 
1008
1049
  /**
@@ -1032,29 +1073,23 @@ class ContinuousProfiler {constructor() { ContinuousProfiler.prototype.__init.ca
1032
1073
  });
1033
1074
  }
1034
1075
 
1035
- /**
1036
- * Stops the profile and clears chunk instrumentation from global scope
1037
- * @returns void
1038
- */
1039
- _stopChunkProfiling(chunk) {
1040
- this._teardownSpanChunkInstrumentation();
1041
- return CpuProfilerBindings.stopProfiling(chunk.id, ProfileFormat.CHUNK);
1042
- }
1043
-
1044
1076
  /**
1045
1077
  * Starts the profiler and registers the flush timer for a given chunk.
1046
1078
  * @param chunk
1047
1079
  */
1048
- _startChunkProfiling(chunk) {
1049
- this._setupSpanChunkInstrumentation();
1080
+ _startChunkProfiling() {
1081
+ const traceId =
1082
+ getCurrentScope().getPropagationContext().traceId || getIsolationScope().getPropagationContext().traceId;
1083
+ const chunk = this._initializeChunk(traceId);
1084
+
1050
1085
  CpuProfilerBindings.startProfiling(chunk.id);
1051
1086
  DEBUG_BUILD && logger.log(`[Profiling] starting profiling chunk: ${chunk.id}`);
1052
1087
 
1053
1088
  chunk.timer = global.setTimeout(() => {
1054
1089
  DEBUG_BUILD && logger.log(`[Profiling] Stopping profiling chunk: ${chunk.id}`);
1055
- this.stop();
1090
+ this._chunkStop();
1056
1091
  DEBUG_BUILD && logger.log('[Profiling] Starting new profiling chunk.');
1057
- setImmediate(this.start.bind(this));
1092
+ setImmediate(this._chunkStart.bind(this));
1058
1093
  }, CHUNK_INTERVAL_MS);
1059
1094
 
1060
1095
  // Unref timeout so it doesn't keep the process alive.
@@ -1068,21 +1103,31 @@ class ContinuousProfiler {constructor() { ContinuousProfiler.prototype.__init.ca
1068
1103
  _setupSpanChunkInstrumentation() {
1069
1104
  if (!this._client) {
1070
1105
  DEBUG_BUILD &&
1071
- logger.log('[Profiling] Failed to collect profile, sentry client was never attached to the profiler.');
1106
+ logger.log(
1107
+ '[Profiling] Failed to initialize span profiling, sentry client was never attached to the profiler.',
1108
+ );
1072
1109
  return;
1073
1110
  }
1074
1111
 
1112
+ this._profilerId = uuid4();
1075
1113
  getGlobalScope().setContext('profile', {
1076
1114
  profiler_id: this._profilerId,
1077
1115
  });
1116
+ }
1078
1117
 
1079
- this._client.on('beforeSendEvent', e => this._assignThreadIdContext(e));
1118
+ /**
1119
+ * Assigns thread_id and thread name context to a profiled event if there is an active profiler session
1120
+ */
1121
+ _onBeforeSendThreadContextAssignment(event) {
1122
+ if (!this._client || !this._profilerId) return;
1123
+ this._assignThreadIdContext(event);
1080
1124
  }
1081
1125
 
1082
1126
  /**
1083
1127
  * Clear profiling information from global context when a profile is not running.
1084
1128
  */
1085
1129
  _teardownSpanChunkInstrumentation() {
1130
+ this._profilerId = undefined;
1086
1131
  const globalScope = getGlobalScope();
1087
1132
  globalScope.setContext('profile', {});
1088
1133
  }
@@ -1096,6 +1141,7 @@ class ContinuousProfiler {constructor() { ContinuousProfiler.prototype.__init.ca
1096
1141
  startTraceID: traceId,
1097
1142
  timer: undefined,
1098
1143
  };
1144
+ return this._chunkData;
1099
1145
  }
1100
1146
 
1101
1147
  /**
@@ -1125,7 +1171,7 @@ class ContinuousProfiler {constructor() { ContinuousProfiler.prototype.__init.ca
1125
1171
  /**
1126
1172
  * Resets the current chunk state.
1127
1173
  */
1128
- _reset() {
1174
+ _resetChunkData() {
1129
1175
  this._chunkData = undefined;
1130
1176
  }
1131
1177
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../src/debug-build.ts","../../src/cpu_profiler.ts","../../src/nodeVersion.ts","../../src/utils.ts","../../src/spanProfileUtils.ts","../../src/types.ts","../../src/integration.ts"],"sourcesContent":["declare const __DEBUG_BUILD__: boolean;\n\n/**\n * This serves as a build time flag that will be true by default, but false in non-debug builds or if users replace `__SENTRY_DEBUG__` in their generated code.\n *\n * ATTENTION: This constant must never cross package boundaries (i.e. be exported) to guarantee that it can be used for tree shaking.\n */\nexport const DEBUG_BUILD = __DEBUG_BUILD__;\n","import { arch as _arch, platform as _platform } from 'node:os';\nimport { join, resolve } from 'node:path';\nimport { env, versions } from 'node:process';\nimport { threadId } from 'node:worker_threads';\nimport { familySync } from 'detect-libc';\nimport { getAbi } from 'node-abi';\n\nimport { GLOBAL_OBJ, logger } from '@sentry/utils';\nimport { DEBUG_BUILD } from './debug-build';\nimport type {\n PrivateV8CpuProfilerBindings,\n RawChunkCpuProfile,\n RawThreadCpuProfile,\n V8CpuProfilerBindings,\n} from './types';\nimport type { ProfileFormat } from './types';\n\nconst stdlib = familySync();\nconst platform = process.env['BUILD_PLATFORM'] || _platform();\nconst arch = process.env['BUILD_ARCH'] || _arch();\nconst abi = getAbi(versions.node, 'node');\nconst identifier = [platform, arch, stdlib, abi].filter(c => c !== undefined && c !== null).join('-');\n\nconst built_from_source_path = resolve(__dirname, '..', `./sentry_cpu_profiler-${identifier}`);\n\n/**\n * Imports cpp bindings based on the current platform and architecture.\n */\n// eslint-disable-next-line complexity\nexport function importCppBindingsModule(): PrivateV8CpuProfilerBindings {\n // If a binary path is specified, use that.\n if (env['SENTRY_PROFILER_BINARY_PATH']) {\n const envPath = env['SENTRY_PROFILER_BINARY_PATH'];\n return require(envPath);\n }\n\n // If a user specifies a different binary dir, they are in control of the binaries being moved there\n if (env['SENTRY_PROFILER_BINARY_DIR']) {\n const binaryPath = join(resolve(env['SENTRY_PROFILER_BINARY_DIR']), `sentry_cpu_profiler-${identifier}`);\n return require(`${binaryPath}.node`);\n }\n\n // We need the fallthrough so that in the end, we can fallback to the require dynamice require.\n // This is for cases where precompiled binaries were not provided, but may have been compiled from source.\n if (platform === 'darwin') {\n if (arch === 'x64') {\n if (abi === '93') {\n return require('../sentry_cpu_profiler-darwin-x64-93.node');\n }\n if (abi === '108') {\n return require('../sentry_cpu_profiler-darwin-x64-108.node');\n }\n if (abi === '115') {\n return require('../sentry_cpu_profiler-darwin-x64-115.node');\n }\n if (abi === '127') {\n return require('../sentry_cpu_profiler-darwin-x64-127.node');\n }\n }\n\n if (arch === 'arm64') {\n if (abi === '93') {\n return require('../sentry_cpu_profiler-darwin-arm64-93.node');\n }\n if (abi === '108') {\n return require('../sentry_cpu_profiler-darwin-arm64-108.node');\n }\n if (abi === '115') {\n return require('../sentry_cpu_profiler-darwin-arm64-115.node');\n }\n if (abi === '127') {\n return require('../sentry_cpu_profiler-darwin-arm64-127.node');\n }\n }\n }\n\n if (platform === 'win32') {\n if (arch === 'x64') {\n if (abi === '93') {\n return require('../sentry_cpu_profiler-win32-x64-93.node');\n }\n if (abi === '108') {\n return require('../sentry_cpu_profiler-win32-x64-108.node');\n }\n if (abi === '115') {\n return require('../sentry_cpu_profiler-win32-x64-115.node');\n }\n if (abi === '127') {\n return require('../sentry_cpu_profiler-win32-x64-127.node');\n }\n }\n }\n\n if (platform === 'linux') {\n if (arch === 'x64') {\n if (stdlib === 'musl') {\n if (abi === '93') {\n return require('../sentry_cpu_profiler-linux-x64-musl-93.node');\n }\n if (abi === '108') {\n return require('../sentry_cpu_profiler-linux-x64-musl-108.node');\n }\n if (abi === '115') {\n return require('../sentry_cpu_profiler-linux-x64-musl-115.node');\n }\n if (abi === '127') {\n return require('../sentry_cpu_profiler-linux-x64-musl-127.node');\n }\n }\n if (stdlib === 'glibc') {\n if (abi === '93') {\n return require('../sentry_cpu_profiler-linux-x64-glibc-93.node');\n }\n if (abi === '108') {\n return require('../sentry_cpu_profiler-linux-x64-glibc-108.node');\n }\n if (abi === '115') {\n return require('../sentry_cpu_profiler-linux-x64-glibc-115.node');\n }\n if (abi === '127') {\n return require('../sentry_cpu_profiler-linux-x64-glibc-127.node');\n }\n }\n }\n if (arch === 'arm64') {\n if (stdlib === 'musl') {\n if (abi === '93') {\n return require('../sentry_cpu_profiler-linux-arm64-musl-93.node');\n }\n if (abi === '108') {\n return require('../sentry_cpu_profiler-linux-arm64-musl-108.node');\n }\n if (abi === '115') {\n return require('../sentry_cpu_profiler-linux-arm64-musl-115.node');\n }\n if (abi === '127') {\n return require('../sentry_cpu_profiler-linux-arm64-musl-127.node');\n }\n }\n if (stdlib === 'glibc') {\n if (abi === '93') {\n return require('../sentry_cpu_profiler-linux-arm64-glibc-93.node');\n }\n if (abi === '108') {\n return require('../sentry_cpu_profiler-linux-arm64-glibc-108.node');\n }\n if (abi === '115') {\n return require('../sentry_cpu_profiler-linux-arm64-glibc-115.node');\n }\n if (abi === '127') {\n return require('../sentry_cpu_profiler-linux-arm64-glibc-127.node');\n }\n }\n }\n }\n return require(`${built_from_source_path}.node`);\n}\n\nconst PrivateCpuProfilerBindings: PrivateV8CpuProfilerBindings = importCppBindingsModule();\n\nclass Bindings implements V8CpuProfilerBindings {\n public startProfiling(name: string): void {\n if (!PrivateCpuProfilerBindings) {\n DEBUG_BUILD && logger.log('[Profiling] Bindings not loaded, ignoring call to startProfiling.');\n return;\n }\n\n return PrivateCpuProfilerBindings.startProfiling(name);\n }\n\n public stopProfiling(name: string, format: ProfileFormat.THREAD): RawThreadCpuProfile | null;\n public stopProfiling(name: string, format: ProfileFormat.CHUNK): RawChunkCpuProfile | null;\n public stopProfiling(\n name: string,\n format: ProfileFormat.CHUNK | ProfileFormat.THREAD,\n ): RawThreadCpuProfile | RawChunkCpuProfile | null {\n if (!PrivateCpuProfilerBindings) {\n DEBUG_BUILD &&\n logger.log('[Profiling] Bindings not loaded or profile was never started, ignoring call to stopProfiling.');\n return null;\n }\n\n return PrivateCpuProfilerBindings.stopProfiling(\n name,\n format as unknown as any,\n threadId,\n !!GLOBAL_OBJ._sentryDebugIds,\n );\n }\n}\n\nconst CpuProfilerBindings = new Bindings();\n\nexport { PrivateCpuProfilerBindings };\nexport { CpuProfilerBindings };\n","import { parseSemver } from '@sentry/utils';\n\nexport const NODE_VERSION = parseSemver(process.versions.node) as { major: number; minor: number; patch: number };\nexport const NODE_MAJOR = NODE_VERSION.major;\n","/* eslint-disable max-lines */\nimport * as os from 'os';\nimport type {\n Client,\n Context,\n ContinuousThreadCpuProfile,\n DebugImage,\n DsnComponents,\n Envelope,\n Event,\n EventEnvelopeHeaders,\n Profile,\n ProfileChunk,\n ProfileChunkEnvelope,\n ProfileChunkItem,\n SdkInfo,\n StackFrame,\n StackParser,\n ThreadCpuProfile,\n} from '@sentry/types';\nimport { GLOBAL_OBJ, createEnvelope, dsnToString, forEachEnvelopeItem, logger, uuid4 } from '@sentry/utils';\n\nimport { env, versions } from 'process';\nimport { isMainThread, threadId } from 'worker_threads';\n\nimport { DEBUG_BUILD } from './debug-build';\nimport type { RawChunkCpuProfile, RawThreadCpuProfile } from './types';\n\n// We require the file because if we import it, it will be included in the bundle.\n// I guess tsc does not check file contents when it's imported.\nexport const PROFILER_THREAD_ID_STRING = String(threadId);\nexport const PROFILER_THREAD_NAME = isMainThread ? 'main' : 'worker';\nconst FORMAT_VERSION = '1';\nconst CONTINUOUS_FORMAT_VERSION = '2';\n\n// Os machine was backported to 16.18, but this was not reflected in the types\n// @ts-expect-error ignore missing\nconst machine = typeof os.machine === 'function' ? os.machine() : os.arch();\n\n// Machine properties (eval only once)\nconst PLATFORM = os.platform();\nconst RELEASE = os.release();\nconst VERSION = os.version();\nconst TYPE = os.type();\nconst MODEL = machine;\nconst ARCH = os.arch();\n\n/**\n * Checks if the profile is a raw profile or a profile enriched with thread information.\n * @param {ThreadCpuProfile | RawThreadCpuProfile} profile\n * @returns {boolean}\n */\nfunction isRawThreadCpuProfile(\n profile: ThreadCpuProfile | RawThreadCpuProfile | ContinuousThreadCpuProfile | RawChunkCpuProfile,\n): profile is RawThreadCpuProfile | RawChunkCpuProfile {\n return !('thread_metadata' in profile);\n}\n\n/**\n * Enriches the profile with threadId of the current thread.\n * This is done in node as we seem to not be able to get the info from C native code.\n *\n * @param {ThreadCpuProfile | RawThreadCpuProfile} profile\n * @returns {ThreadCpuProfile}\n */\nexport function enrichWithThreadInformation(\n profile: ThreadCpuProfile | RawThreadCpuProfile | ContinuousThreadCpuProfile | RawChunkCpuProfile,\n): ThreadCpuProfile | ContinuousThreadCpuProfile {\n if (!isRawThreadCpuProfile(profile)) {\n return profile;\n }\n\n return {\n samples: profile.samples,\n frames: profile.frames,\n stacks: profile.stacks,\n thread_metadata: {\n [PROFILER_THREAD_ID_STRING]: {\n name: PROFILER_THREAD_NAME,\n },\n },\n } as ThreadCpuProfile | ContinuousThreadCpuProfile;\n}\n\n/**\n * Creates a profiling envelope item, if the profile does not pass validation, returns null.\n * @param {RawThreadCpuProfile}\n * @param {Event}\n * @returns {Profile | null}\n */\nexport function createProfilingEvent(client: Client, profile: RawThreadCpuProfile, event: Event): Profile | null {\n if (!isValidProfile(profile)) {\n return null;\n }\n\n return createProfilePayload(client, profile, {\n release: event.release ?? '',\n environment: event.environment ?? '',\n event_id: event.event_id ?? '',\n transaction: event.transaction ?? '',\n start_timestamp: event.start_timestamp ? event.start_timestamp * 1000 : Date.now(),\n trace_id: event.contexts?.['trace']?.['trace_id'] ?? '',\n profile_id: profile.profile_id,\n });\n}\n\n/**\n * Create a profile\n * @param {RawThreadCpuProfile} cpuProfile\n * @param {options}\n * @returns {Profile}\n */\nfunction createProfilePayload(\n client: Client,\n cpuProfile: RawThreadCpuProfile,\n {\n release,\n environment,\n event_id,\n transaction,\n start_timestamp,\n trace_id,\n profile_id,\n }: {\n release: string;\n environment: string;\n event_id: string;\n transaction: string;\n start_timestamp: number;\n trace_id: string | undefined;\n profile_id: string;\n },\n): Profile {\n // Log a warning if the profile has an invalid traceId (should be uuidv4).\n // All profiles and transactions are rejected if this is the case and we want to\n // warn users that this is happening if they enable debug flag\n if (trace_id && trace_id.length !== 32) {\n DEBUG_BUILD && logger.log(`[Profiling] Invalid traceId: ${trace_id} on profiled event`);\n }\n\n const enrichedThreadProfile = enrichWithThreadInformation(cpuProfile);\n\n const profile: Profile = {\n event_id: profile_id,\n timestamp: new Date(start_timestamp).toISOString(),\n platform: 'node',\n version: FORMAT_VERSION,\n release: release,\n environment: environment,\n measurements: cpuProfile.measurements,\n runtime: {\n name: 'node',\n version: versions.node || '',\n },\n os: {\n name: PLATFORM,\n version: RELEASE,\n build_number: VERSION,\n },\n device: {\n locale: env['LC_ALL'] || env['LC_MESSAGES'] || env['LANG'] || env['LANGUAGE'] || '',\n model: MODEL,\n manufacturer: TYPE,\n architecture: ARCH,\n is_emulator: false,\n },\n debug_meta: {\n images: applyDebugMetadata(client, cpuProfile.resources),\n },\n profile: enrichedThreadProfile as ThreadCpuProfile,\n transaction: {\n name: transaction,\n id: event_id,\n trace_id: trace_id || '',\n active_thread_id: PROFILER_THREAD_ID_STRING,\n },\n };\n\n return profile;\n}\n\n/**\n * Create a profile chunk from raw thread profile\n * @param {RawThreadCpuProfile} cpuProfile\n * @param {options}\n * @returns {Profile}\n */\nfunction createProfileChunkPayload(\n client: Client,\n cpuProfile: RawChunkCpuProfile,\n {\n release,\n environment,\n trace_id,\n profiler_id,\n chunk_id,\n sdk,\n }: {\n release: string;\n environment: string;\n trace_id: string | undefined;\n chunk_id: string;\n profiler_id: string;\n sdk: SdkInfo | undefined;\n },\n): ProfileChunk {\n // Log a warning if the profile has an invalid traceId (should be uuidv4).\n // All profiles and transactions are rejected if this is the case and we want to\n // warn users that this is happening if they enable debug flag\n if (trace_id && trace_id.length !== 32) {\n DEBUG_BUILD && logger.log(`[Profiling] Invalid traceId: ${trace_id} on profiled event`);\n }\n\n const enrichedThreadProfile = enrichWithThreadInformation(cpuProfile);\n\n const profile: ProfileChunk = {\n chunk_id: chunk_id,\n client_sdk: {\n name: sdk?.name ?? 'sentry.javascript.node',\n version: sdk?.version ?? '0.0.0',\n },\n profiler_id: profiler_id,\n platform: 'node',\n version: CONTINUOUS_FORMAT_VERSION,\n release: release,\n environment: environment,\n measurements: cpuProfile.measurements,\n debug_meta: {\n images: applyDebugMetadata(client, cpuProfile.resources),\n },\n profile: enrichedThreadProfile as ContinuousThreadCpuProfile,\n };\n\n return profile;\n}\n\n/**\n * Creates a profiling chunk envelope item, if the profile does not pass validation, returns null.\n */\nexport function createProfilingChunkEvent(\n client: Client,\n options: { release?: string; environment?: string },\n profile: RawChunkCpuProfile,\n sdk: SdkInfo | undefined,\n identifiers: { trace_id: string | undefined; chunk_id: string; profiler_id: string },\n): ProfileChunk | null {\n if (!isValidProfileChunk(profile)) {\n return null;\n }\n\n return createProfileChunkPayload(client, profile, {\n release: options.release ?? '',\n environment: options.environment ?? '',\n trace_id: identifiers.trace_id ?? '',\n chunk_id: identifiers.chunk_id,\n profiler_id: identifiers.profiler_id,\n sdk,\n });\n}\n\n/**\n * Checks the given sample rate to make sure it is valid type and value (a boolean, or a number between 0 and 1).\n * @param {unknown} rate\n * @returns {boolean}\n */\nexport function isValidSampleRate(rate: unknown): boolean {\n // we need to check NaN explicitly because it's of type 'number' and therefore wouldn't get caught by this typecheck\n if ((typeof rate !== 'number' && typeof rate !== 'boolean') || (typeof rate === 'number' && isNaN(rate))) {\n DEBUG_BUILD &&\n logger.warn(\n `[Profiling] Invalid sample rate. Sample rate must be a boolean or a number between 0 and 1. Got ${JSON.stringify(\n rate,\n )} of type ${JSON.stringify(typeof rate)}.`,\n );\n return false;\n }\n\n // Boolean sample rates are always valid\n if (rate === true || rate === false) {\n return true;\n }\n\n // in case sampleRate is a boolean, it will get automatically cast to 1 if it's true and 0 if it's false\n if (rate < 0 || rate > 1) {\n DEBUG_BUILD && logger.warn(`[Profiling] Invalid sample rate. Sample rate must be between 0 and 1. Got ${rate}.`);\n return false;\n }\n return true;\n}\n\n/**\n * Checks if the profile is valid and can be sent to Sentry.\n * @param {RawThreadCpuProfile} profile\n * @returns {boolean}\n */\nexport function isValidProfile(profile: RawThreadCpuProfile): profile is RawThreadCpuProfile & { profile_id: string } {\n if (profile.samples.length <= 1) {\n DEBUG_BUILD &&\n // Log a warning if the profile has less than 2 samples so users can know why\n // they are not seeing any profiling data and we cant avoid the back and forth\n // of asking them to provide us with a dump of the profile data.\n logger.log('[Profiling] Discarding profile because it contains less than 2 samples');\n return false;\n }\n\n if (!profile.profile_id) {\n return false;\n }\n\n return true;\n}\n\n/**\n * Checks if the profile chunk is valid and can be sent to Sentry.\n * @param profile\n * @returns\n */\nexport function isValidProfileChunk(profile: RawChunkCpuProfile): profile is RawChunkCpuProfile {\n if (profile.samples.length <= 1) {\n DEBUG_BUILD &&\n // Log a warning if the profile has less than 2 samples so users can know why\n // they are not seeing any profiling data and we cant avoid the back and forth\n // of asking them to provide us with a dump of the profile data.\n logger.log('[Profiling] Discarding profile chunk because it contains less than 2 samples');\n return false;\n }\n\n return true;\n}\n\n/**\n * Adds items to envelope if they are not already present - mutates the envelope.\n * @param {Envelope} envelope\n * @param {Profile[]} profiles\n * @returns {Envelope}\n */\nexport function addProfilesToEnvelope(envelope: Envelope, profiles: Profile[]): Envelope {\n if (!profiles.length) {\n return envelope;\n }\n\n for (const profile of profiles) {\n // @ts-expect-error untyped envelope\n envelope[1].push([{ type: 'profile' }, profile]);\n }\n return envelope;\n}\n\n/**\n * Finds transactions with profile_id context in the envelope\n * @param {Envelope} envelope\n * @returns {Event[]}\n */\nexport function findProfiledTransactionsFromEnvelope(envelope: Envelope): Event[] {\n const events: Event[] = [];\n\n forEachEnvelopeItem(envelope, (item, type) => {\n if (type !== 'transaction') {\n return;\n }\n\n // First item is the type, so we can skip it, everything else is an event\n for (let j = 1; j < item.length; j++) {\n const event = item[j];\n\n if (!event) {\n // Shouldnt happen, but lets be safe\n continue;\n }\n\n // @ts-expect-error profile_id is not part of the metadata type\n const profile_id = (event.contexts as Context)?.['profile']?.['profile_id'];\n\n if (event && profile_id) {\n events.push(item[j] as Event);\n }\n }\n });\n\n return events;\n}\n\n/**\n * Creates event envelope headers for a profile chunk. This is separate from createEventEnvelopeHeaders util\n * as the profile chunk does not conform to the sentry event type\n */\nexport function createEventEnvelopeHeaders(\n sdkInfo: SdkInfo | undefined,\n tunnel: string | undefined,\n dsn?: DsnComponents,\n): EventEnvelopeHeaders {\n return {\n event_id: uuid4(),\n sent_at: new Date().toISOString(),\n ...(sdkInfo && { sdk: sdkInfo }),\n ...(!!tunnel && dsn && { dsn: dsnToString(dsn) }),\n };\n}\n\n/**\n * Creates a standalone profile_chunk envelope.\n */\nexport function makeProfileChunkEnvelope(\n chunk: ProfileChunk,\n sdkInfo: SdkInfo | undefined,\n tunnel: string | undefined,\n dsn?: DsnComponents,\n): ProfileChunkEnvelope {\n const profileChunkHeader: ProfileChunkItem[0] = {\n type: 'profile_chunk',\n };\n\n return createEnvelope<ProfileChunkEnvelope>(createEventEnvelopeHeaders(sdkInfo, tunnel, dsn), [\n [profileChunkHeader, chunk],\n ]);\n}\n\nconst debugIdStackParserCache = new WeakMap<StackParser, Map<string, StackFrame[]>>();\n\n/**\n * Cross reference profile collected resources with debug_ids and return a list of debug images.\n * @param {string[]} resource_paths\n * @returns {DebugImage[]}\n */\nexport function applyDebugMetadata(client: Client, resource_paths: ReadonlyArray<string>): DebugImage[] {\n const debugIdMap = GLOBAL_OBJ._sentryDebugIds;\n if (!debugIdMap) {\n return [];\n }\n\n const options = client.getOptions();\n\n if (!options || !options.stackParser) {\n return [];\n }\n\n let debugIdStackFramesCache: Map<string, StackFrame[]>;\n const cachedDebugIdStackFrameCache = debugIdStackParserCache.get(options.stackParser);\n if (cachedDebugIdStackFrameCache) {\n debugIdStackFramesCache = cachedDebugIdStackFrameCache;\n } else {\n debugIdStackFramesCache = new Map<string, StackFrame[]>();\n debugIdStackParserCache.set(options.stackParser, debugIdStackFramesCache);\n }\n\n // Build a map of filename -> debug_id.\n const filenameDebugIdMap = Object.keys(debugIdMap).reduce<Record<string, string>>((acc, debugIdStackTrace) => {\n let parsedStack: StackFrame[];\n\n const cachedParsedStack = debugIdStackFramesCache.get(debugIdStackTrace);\n if (cachedParsedStack) {\n parsedStack = cachedParsedStack;\n } else {\n parsedStack = options.stackParser(debugIdStackTrace);\n debugIdStackFramesCache.set(debugIdStackTrace, parsedStack);\n }\n\n for (let i = parsedStack.length - 1; i >= 0; i--) {\n const stackFrame = parsedStack[i];\n const file = stackFrame && stackFrame.filename;\n\n if (stackFrame && file) {\n acc[file] = debugIdMap[debugIdStackTrace] as string;\n break;\n }\n }\n return acc;\n }, {});\n\n const images: DebugImage[] = [];\n\n for (const resource of resource_paths) {\n if (resource && filenameDebugIdMap[resource]) {\n images.push({\n type: 'sourcemap',\n code_file: resource,\n debug_id: filenameDebugIdMap[resource] as string,\n });\n }\n }\n\n return images;\n}\n","import { spanIsSampled, spanToJSON } from '@sentry/core';\nimport type { NodeClient } from '@sentry/node';\nimport type { CustomSamplingContext, Span } from '@sentry/types';\nimport { logger, uuid4 } from '@sentry/utils';\n\nimport { CpuProfilerBindings } from './cpu_profiler';\nimport { DEBUG_BUILD } from './debug-build';\nimport type { RawThreadCpuProfile } from './types';\nimport { isValidSampleRate } from './utils';\n\nexport const MAX_PROFILE_DURATION_MS = 30 * 1000;\n\n/**\n * Takes a transaction and determines if it should be profiled or not. If it should be profiled, it returns the\n * profile_id, otherwise returns undefined. Takes care of setting profile context on transaction as well\n */\nexport function maybeProfileSpan(\n client: NodeClient | undefined,\n span: Span,\n customSamplingContext?: CustomSamplingContext,\n): string | undefined {\n // profilesSampleRate is multiplied with tracesSampleRate to get the final sampling rate. We dont perform\n // the actual multiplication to get the final rate, but we discard the profile if the span was sampled,\n // so anything after this block from here is based on the span sampling.\n if (!spanIsSampled(span)) {\n return;\n }\n\n // Client and options are required for profiling\n if (!client) {\n DEBUG_BUILD && logger.log('[Profiling] Profiling disabled, no client found.');\n return;\n }\n\n const options = client.getOptions();\n if (!options) {\n DEBUG_BUILD && logger.log('[Profiling] Profiling disabled, no options found.');\n return;\n }\n\n const profilesSampler = options.profilesSampler;\n let profilesSampleRate: number | boolean | undefined = options.profilesSampleRate;\n\n // Prefer sampler to sample rate if both are provided.\n if (typeof profilesSampler === 'function') {\n const { description: spanName = '<unknown>', data } = spanToJSON(span);\n // We bail out early if that is not the case\n const parentSampled = true;\n\n profilesSampleRate = profilesSampler({\n name: spanName,\n attributes: data,\n transactionContext: {\n name: spanName,\n parentSampled,\n },\n parentSampled,\n ...customSamplingContext,\n });\n }\n\n // Since this is coming from the user (or from a function provided by the user), who knows what we might get. (The\n // only valid values are booleans or numbers between 0 and 1.)\n if (!isValidSampleRate(profilesSampleRate)) {\n DEBUG_BUILD && logger.warn('[Profiling] Discarding profile because of invalid sample rate.');\n return;\n }\n\n // if the function returned 0 (or false), or if `profileSampleRate` is 0, it's a sign the profile should be dropped\n if (!profilesSampleRate) {\n DEBUG_BUILD &&\n logger.log(\n `[Profiling] Discarding profile because ${\n typeof profilesSampler === 'function'\n ? 'profileSampler returned 0 or false'\n : 'a negative sampling decision was inherited or profileSampleRate is set to 0'\n }`,\n );\n return;\n }\n\n // Now we roll the dice. Math.random is inclusive of 0, but not of 1, so strict < is safe here. In case sampleRate is\n // a boolean, the < comparison will cause it to be automatically cast to 1 if it's true and 0 if it's false.\n const sampled = profilesSampleRate === true ? true : Math.random() < profilesSampleRate;\n // Check if we should sample this profile\n if (!sampled) {\n DEBUG_BUILD &&\n logger.log(\n `[Profiling] Discarding profile because it's not included in the random sample (sampling rate = ${Number(\n profilesSampleRate,\n )})`,\n );\n return;\n }\n\n const profile_id = uuid4();\n CpuProfilerBindings.startProfiling(profile_id);\n DEBUG_BUILD && logger.log(`[Profiling] started profiling transaction: ${spanToJSON(span).description}`);\n\n // set transaction context - do this regardless if profiling fails down the line\n // so that we can still see the profile_id in the transaction context\n return profile_id;\n}\n\n/**\n * Stops the profiler for profile_id and returns the profile\n * @param transaction\n * @param profile_id\n * @returns\n */\nexport function stopSpanProfile(span: Span, profile_id: string | undefined): RawThreadCpuProfile | null {\n // Should not happen, but satisfy the type checker and be safe regardless.\n if (!profile_id) {\n return null;\n }\n\n const profile = CpuProfilerBindings.stopProfiling(profile_id, 0);\n DEBUG_BUILD && logger.log(`[Profiling] stopped profiling of transaction: ${spanToJSON(span).description}`);\n\n // In case of an overlapping span, stopProfiling may return null and silently ignore the overlapping profile.\n if (!profile) {\n DEBUG_BUILD &&\n logger.log(\n `[Profiling] profiler returned null profile for: ${spanToJSON(span).description}`,\n 'this may indicate an overlapping span or a call to stopProfiling with a profile title that was never started',\n );\n return null;\n }\n\n // Assign profile_id to the profile\n profile.profile_id = profile_id;\n return profile;\n}\n","import type { Event } from '@sentry/types';\n\ninterface Sample {\n stack_id: number;\n thread_id: string;\n elapsed_since_start_ns: string;\n}\n\ninterface ChunkSample {\n stack_id: number;\n thread_id: string;\n timestamp: number;\n}\n\ntype Frame = {\n function: string;\n file: string;\n lineno: number;\n colno: number;\n};\n\ninterface Measurement {\n unit: string;\n values: {\n elapsed_since_start_ns: number;\n value: number;\n }[];\n}\n\n// Profile is marked as optional because it is deleted from the metadata\n// by the integration before the event is processed by other integrations.\nexport interface ProfiledEvent extends Event {\n sdkProcessingMetadata: {\n profile?: RawThreadCpuProfile;\n };\n}\n\ninterface BaseProfile {\n profile_id?: string;\n stacks: number[][];\n frames: Frame[];\n resources: string[];\n profiler_logging_mode: 'eager' | 'lazy';\n measurements: Record<string, Measurement>;\n}\nexport interface RawThreadCpuProfile extends BaseProfile {\n samples: Sample[];\n}\n\nexport interface RawChunkCpuProfile extends BaseProfile {\n samples: ChunkSample[];\n}\n\nexport interface PrivateV8CpuProfilerBindings {\n startProfiling(name: string): void;\n\n stopProfiling(\n name: string,\n format: ProfileFormat.THREAD,\n threadId: number,\n collectResources: boolean,\n ): RawThreadCpuProfile | null;\n stopProfiling(\n name: string,\n format: ProfileFormat.CHUNK,\n threadId: number,\n collectResources: boolean,\n ): RawChunkCpuProfile | null;\n\n // Helper methods exposed for testing\n getFrameModule(abs_path: string): string;\n}\n\nexport enum ProfileFormat {\n THREAD = 0,\n CHUNK = 1,\n}\n\nexport interface V8CpuProfilerBindings {\n startProfiling(name: string): void;\n\n stopProfiling(name: string, format: ProfileFormat.THREAD): RawThreadCpuProfile | null;\n stopProfiling(name: string, format: ProfileFormat.CHUNK): RawChunkCpuProfile | null;\n}\n","/* eslint-disable max-lines */\n\nimport {\n defineIntegration,\n getCurrentScope,\n getGlobalScope,\n getIsolationScope,\n getRootSpan,\n spanToJSON,\n} from '@sentry/core';\nimport type { NodeClient } from '@sentry/node';\nimport type { Event, IntegrationFn, Profile, ProfileChunk, ProfilingIntegration, Span } from '@sentry/types';\n\nimport { LRUMap, logger, uuid4 } from '@sentry/utils';\n\nimport { CpuProfilerBindings } from './cpu_profiler';\nimport { DEBUG_BUILD } from './debug-build';\nimport { NODE_MAJOR, NODE_VERSION } from './nodeVersion';\nimport { MAX_PROFILE_DURATION_MS, maybeProfileSpan, stopSpanProfile } from './spanProfileUtils';\nimport type { RawChunkCpuProfile, RawThreadCpuProfile } from './types';\nimport { ProfileFormat } from './types';\nimport { PROFILER_THREAD_NAME } from './utils';\n\nimport {\n PROFILER_THREAD_ID_STRING,\n addProfilesToEnvelope,\n createProfilingChunkEvent,\n createProfilingEvent,\n findProfiledTransactionsFromEnvelope,\n makeProfileChunkEnvelope,\n} from './utils';\n\nconst CHUNK_INTERVAL_MS = 5000;\nconst PROFILE_MAP = new LRUMap<string, RawThreadCpuProfile>(50);\nconst PROFILE_TIMEOUTS: Record<string, NodeJS.Timeout> = {};\n\nfunction addToProfileQueue(profile_id: string, profile: RawThreadCpuProfile): void {\n PROFILE_MAP.set(profile_id, profile);\n}\n\nfunction takeFromProfileQueue(profile_id: string): RawThreadCpuProfile | undefined {\n const profile = PROFILE_MAP.get(profile_id);\n PROFILE_MAP.remove(profile_id);\n return profile;\n}\n\n/**\n * Instruments the client to automatically invoke the profiler on span start and stop events.\n * @param client\n */\nfunction setupAutomatedSpanProfiling(client: NodeClient): void {\n const spanToProfileIdMap = new WeakMap<Span, string>();\n\n client.on('spanStart', span => {\n if (span !== getRootSpan(span)) {\n return;\n }\n\n const profile_id = maybeProfileSpan(client, span);\n\n if (profile_id) {\n const options = client.getOptions();\n // Not intended for external use, hence missing types, but we want to profile a couple of things at Sentry that\n // currently exceed the default timeout set by the SDKs.\n const maxProfileDurationMs =\n (options._experiments && options._experiments['maxProfileDurationMs']) || MAX_PROFILE_DURATION_MS;\n\n if (PROFILE_TIMEOUTS[profile_id]) {\n global.clearTimeout(PROFILE_TIMEOUTS[profile_id]);\n // eslint-disable-next-line @typescript-eslint/no-dynamic-delete\n delete PROFILE_TIMEOUTS[profile_id];\n }\n\n // Enqueue a timeout to prevent profiles from running over max duration.\n const timeout = global.setTimeout(() => {\n DEBUG_BUILD &&\n logger.log('[Profiling] max profile duration elapsed, stopping profiling for:', spanToJSON(span).description);\n\n const profile = stopSpanProfile(span, profile_id);\n if (profile) {\n addToProfileQueue(profile_id, profile);\n }\n }, maxProfileDurationMs);\n\n // Unref timeout so it doesn't keep the process alive.\n timeout.unref();\n\n getCurrentScope().setContext('profile', { profile_id });\n spanToProfileIdMap.set(span, profile_id);\n }\n });\n\n client.on('spanEnd', span => {\n const profile_id = spanToProfileIdMap.get(span);\n\n if (profile_id) {\n if (PROFILE_TIMEOUTS[profile_id]) {\n global.clearTimeout(PROFILE_TIMEOUTS[profile_id]);\n // eslint-disable-next-line @typescript-eslint/no-dynamic-delete\n delete PROFILE_TIMEOUTS[profile_id];\n }\n const profile = stopSpanProfile(span, profile_id);\n\n if (profile) {\n addToProfileQueue(profile_id, profile);\n }\n }\n });\n\n client.on('beforeEnvelope', (envelope): void => {\n // if not profiles are in queue, there is nothing to add to the envelope.\n if (!PROFILE_MAP.size) {\n return;\n }\n\n const profiledTransactionEvents = findProfiledTransactionsFromEnvelope(envelope);\n if (!profiledTransactionEvents.length) {\n return;\n }\n\n const profilesToAddToEnvelope: Profile[] = [];\n\n for (const profiledTransaction of profiledTransactionEvents) {\n const profileContext = profiledTransaction.contexts?.['profile'];\n const profile_id = profileContext?.['profile_id'];\n\n if (!profile_id) {\n throw new TypeError('[Profiling] cannot find profile for a transaction without a profile context');\n }\n\n // Remove the profile from the transaction context before sending, relay will take care of the rest.\n if (profileContext) {\n delete profiledTransaction.contexts?.['profile'];\n }\n\n const cpuProfile = takeFromProfileQueue(profile_id);\n if (!cpuProfile) {\n DEBUG_BUILD && logger.log(`[Profiling] Could not retrieve profile for transaction: ${profile_id}`);\n continue;\n }\n\n const profile = createProfilingEvent(client, cpuProfile, profiledTransaction);\n if (!profile) return;\n\n profilesToAddToEnvelope.push(profile);\n\n // @ts-expect-error profile does not inherit from Event\n client.emit('preprocessEvent', profile, {\n event_id: profiledTransaction.event_id,\n });\n }\n\n addProfilesToEnvelope(envelope, profilesToAddToEnvelope);\n });\n}\n\ninterface ChunkData {\n id: string;\n timer: NodeJS.Timeout | undefined;\n startTraceID: string;\n}\n\nclass ContinuousProfiler {\n private _profilerId = uuid4();\n private _client: NodeClient | undefined = undefined;\n private _chunkData: ChunkData | undefined = undefined;\n\n /**\n * Called when the profiler is attached to the client (continuous mode is enabled). If of the profiler\n * methods called before the profiler is initialized will result in a noop action with debug logs.\n * @param client\n */\n public initialize(client: NodeClient): void {\n this._client = client;\n }\n\n /**\n * Recursively schedules chunk profiling to start and stop at a set interval.\n * Once the user calls stop(), the current chunk will be stopped and flushed to Sentry and no new chunks will\n * will be started. To restart continuous mode after calling stop(), the user must call start() again.\n * @returns void\n */\n public start(): void {\n if (!this._client) {\n // The client is not attached to the profiler if the user has not enabled continuous profiling.\n // In this case, calling start() and stop() is a noop action.The reason this exists is because\n // it makes the types easier to work with and avoids users having to do null checks.\n DEBUG_BUILD && logger.log('[Profiling] Profiler was never attached to the client.');\n return;\n }\n if (this._chunkData) {\n DEBUG_BUILD &&\n logger.log(\n `[Profiling] Chunk with chunk_id ${this._chunkData.id} is still running, current chunk will be stopped a new chunk will be started.`,\n );\n this.stop();\n }\n\n const traceId =\n getCurrentScope().getPropagationContext().traceId || getIsolationScope().getPropagationContext().traceId;\n this._initializeChunk(traceId);\n this._startChunkProfiling(this._chunkData!);\n }\n\n /**\n * Stops the current chunk and flushes the profile to Sentry.\n * @returns void\n */\n public stop(): void {\n if (this._chunkData?.timer) {\n global.clearTimeout(this._chunkData.timer);\n this._chunkData.timer = undefined;\n DEBUG_BUILD && logger.log(`[Profiling] Stopping profiling chunk: ${this._chunkData.id}`);\n }\n if (!this._client) {\n DEBUG_BUILD &&\n logger.log('[Profiling] Failed to collect profile, sentry client was never attached to the profiler.');\n return;\n }\n if (!this._chunkData?.id) {\n DEBUG_BUILD &&\n logger.log(`[Profiling] Failed to collect profile for: ${this._chunkData?.id}, the chunk_id is missing.`);\n return;\n }\n\n const profile = this._stopChunkProfiling(this._chunkData);\n\n if (!profile) {\n DEBUG_BUILD && logger.log(`[Profiling] _chunkiledStartTraceID to collect profile for: ${this._chunkData.id}`);\n return;\n }\n if (profile) {\n DEBUG_BUILD && logger.log(`[Profiling] Sending profile chunk ${this._chunkData.id}.`);\n }\n\n DEBUG_BUILD && logger.log(`[Profiling] Profile chunk ${this._chunkData.id} sent to Sentry.`);\n const chunk = createProfilingChunkEvent(\n this._client,\n this._client.getOptions(),\n profile,\n this._client.getSdkMetadata()?.sdk,\n {\n chunk_id: this._chunkData.id,\n trace_id: this._chunkData.startTraceID,\n profiler_id: this._profilerId,\n },\n );\n\n if (!chunk) {\n DEBUG_BUILD && logger.log(`[Profiling] Failed to create profile chunk for: ${this._chunkData.id}`);\n this._reset();\n return;\n }\n\n this._flush(chunk);\n // Depending on the profile and stack sizes, stopping the profile and converting\n // the format may negatively impact the performance of the application. To avoid\n // blocking for too long, enqueue the next chunk start inside the next macrotask.\n // clear current chunk\n this._reset();\n }\n\n /**\n * Flushes the profile chunk to Sentry.\n * @param chunk\n */\n private _flush(chunk: ProfileChunk): void {\n if (!this._client) {\n DEBUG_BUILD &&\n logger.log('[Profiling] Failed to collect profile, sentry client was never attached to the profiler.');\n return;\n }\n\n const transport = this._client.getTransport();\n if (!transport) {\n DEBUG_BUILD && logger.log('[Profiling] No transport available to send profile chunk.');\n return;\n }\n\n const dsn = this._client.getDsn();\n const metadata = this._client.getSdkMetadata();\n const tunnel = this._client.getOptions().tunnel;\n\n const envelope = makeProfileChunkEnvelope(chunk, metadata?.sdk, tunnel, dsn);\n transport.send(envelope).then(null, reason => {\n DEBUG_BUILD && logger.error('Error while sending profile chunk envelope:', reason);\n });\n }\n\n /**\n * Stops the profile and clears chunk instrumentation from global scope\n * @returns void\n */\n private _stopChunkProfiling(chunk: ChunkData): RawChunkCpuProfile | null {\n this._teardownSpanChunkInstrumentation();\n return CpuProfilerBindings.stopProfiling(chunk.id, ProfileFormat.CHUNK);\n }\n\n /**\n * Starts the profiler and registers the flush timer for a given chunk.\n * @param chunk\n */\n private _startChunkProfiling(chunk: ChunkData): void {\n this._setupSpanChunkInstrumentation();\n CpuProfilerBindings.startProfiling(chunk.id);\n DEBUG_BUILD && logger.log(`[Profiling] starting profiling chunk: ${chunk.id}`);\n\n chunk.timer = global.setTimeout(() => {\n DEBUG_BUILD && logger.log(`[Profiling] Stopping profiling chunk: ${chunk.id}`);\n this.stop();\n DEBUG_BUILD && logger.log('[Profiling] Starting new profiling chunk.');\n setImmediate(this.start.bind(this));\n }, CHUNK_INTERVAL_MS);\n\n // Unref timeout so it doesn't keep the process alive.\n chunk.timer.unref();\n }\n\n /**\n * Attaches profiling information to spans that were started\n * during a profiling session.\n */\n private _setupSpanChunkInstrumentation(): void {\n if (!this._client) {\n DEBUG_BUILD &&\n logger.log('[Profiling] Failed to collect profile, sentry client was never attached to the profiler.');\n return;\n }\n\n getGlobalScope().setContext('profile', {\n profiler_id: this._profilerId,\n });\n\n this._client.on('beforeSendEvent', e => this._assignThreadIdContext(e));\n }\n\n /**\n * Clear profiling information from global context when a profile is not running.\n */\n private _teardownSpanChunkInstrumentation(): void {\n const globalScope = getGlobalScope();\n globalScope.setContext('profile', {});\n }\n\n /**\n * Initializes new profile chunk metadata\n */\n private _initializeChunk(traceId: string): void {\n this._chunkData = {\n id: uuid4(),\n startTraceID: traceId,\n timer: undefined,\n };\n }\n\n /**\n * Assigns thread_id and thread name context to a profiled event.\n */\n private _assignThreadIdContext(event: Event): any {\n if (!event?.['contexts']?.['profile']) {\n return;\n }\n\n if (!event.contexts) {\n return;\n }\n\n // @ts-expect-error the trace fallback value is wrong, though it should never happen\n // and in case it does, we dont want to override whatever was passed initially.\n event.contexts['trace'] = {\n ...(event.contexts?.['trace'] ?? {}),\n data: {\n ...(event.contexts?.['trace']?.['data'] ?? {}),\n ['thread.id']: PROFILER_THREAD_ID_STRING,\n ['thread.name']: PROFILER_THREAD_NAME,\n },\n };\n }\n\n /**\n * Resets the current chunk state.\n */\n private _reset(): void {\n this._chunkData = undefined;\n }\n}\n\n/** Exported only for tests. */\nexport const _nodeProfilingIntegration = ((): ProfilingIntegration<NodeClient> => {\n if (DEBUG_BUILD && ![16, 18, 20, 22].includes(NODE_MAJOR)) {\n logger.warn(\n `[Profiling] You are using a Node.js version that does not have prebuilt binaries (${NODE_VERSION}).`,\n 'The @sentry/profiling-node package only has prebuilt support for the following LTS versions of Node.js: 16, 18, 20, 22.',\n 'To use the @sentry/profiling-node package with this version of Node.js, you will need to compile the native addon from source.',\n 'See: https://github.com/getsentry/sentry-javascript/tree/develop/packages/profiling-node#building-the-package-from-source',\n );\n }\n\n return {\n name: 'ProfilingIntegration',\n _profiler: new ContinuousProfiler(),\n setup(client: NodeClient) {\n DEBUG_BUILD && logger.log('[Profiling] Profiling integration setup.');\n const options = client.getOptions();\n\n const mode =\n (options.profilesSampleRate === undefined ||\n options.profilesSampleRate === null ||\n options.profilesSampleRate === 0) &&\n !options.profilesSampler\n ? 'continuous'\n : 'span';\n switch (mode) {\n case 'continuous': {\n DEBUG_BUILD && logger.log('[Profiling] Continuous profiler mode enabled.');\n this._profiler.initialize(client);\n break;\n }\n // Default to span profiling when no mode profiler mode is set\n case 'span':\n case undefined: {\n DEBUG_BUILD && logger.log('[Profiling] Span profiler mode enabled.');\n setupAutomatedSpanProfiling(client);\n break;\n }\n default: {\n DEBUG_BUILD && logger.warn(`[Profiling] Unknown profiler mode: ${mode}, profiler was not initialized`);\n }\n }\n },\n };\n}) satisfies IntegrationFn;\n\n/**\n * We need this integration in order to send data to Sentry. We hook into the event processor\n * and inspect each event to see if it is a transaction event and if that transaction event\n * contains a profile on it's metadata. If that is the case, we create a profiling event envelope\n * and delete the profile from the transaction metadata.\n */\nexport const nodeProfilingIntegration = defineIntegration(_nodeProfilingIntegration);\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;AAEA;AACA;AACA;;;AAGO;;ACUP;AACA;AACA;AACA;AACA;;AAEA;;AAE4F;;;AAGA;AACA;AACA;AACA;;;AAGA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;;AAGA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;;;AAGA;;;;AAMA;;AAEA;;;;AAIA;;;;AAIA;AACA;;;AAGA;AACA;;AAEA;;AC7LrF;AACA;;ACHP;;AA4BA;AACA;AACO;AACA;AACP;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACE;AACF;AACE;AACF;;AAEA;;AAEA;AACA;;;;AAIO;AACL;AACF;AACE;;AAEA;;AAEA;;AAEE;AACA;AACA;;;;;;AAMJ;;AAEA;AACA;;;;;AAKO;;;AAGL;;AAEA;;;;;AAKE;AACA;;AAEJ;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACE;;AAEA;AACE;;AAEA;;AAEA;AACA;;AAED;;AAQD;AACF;;AAEA;;AAEE;AACE;AACF;;AAEA;;;AAGE;;AAEA;;AAEA;;AAEA;AACA;;;;AAIA;;AAEE;AACA;;AAEF;AACE;;AAEA;AACA;AACA;;;;;;;AAOA;;AAEA;AACA;;;;;AAKN;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACE;;AAEA;AACE;;AAEA;;AAEA;AACA;AACD;;AAOD;AACF;;AAEA;;AAEE;AACE;AACF;;AAEA;;;AAGE;;;;;;AAMA;AACA;AACA;;AAEA;;;;;;;;AAQJ;;AAEA;AACA;;AAEO;AACL;AACA;AACA;AACA;;AAEF;AACE;;AAEA;;;;;;;AAOE;AACA;AACJ;AACA;;AAEA;AACA;AACA;AACA;;AAEO;;AAEL;;;;;AAKF;;;AAGE;;AAEF;;;AAGE;;AAEF;AACE;;;AAGA;;AAEF;;AAEA;;AAEA;AACA;;AAEO;;;;AAIP;;AAEM;;AAEJ;;;;AAIA;;;AAGF;;AAEA;;;AAGA;;AAEO;;;;AAIP;;AAEM;;AAEJ;;;AAGF;;AAEA;AACA;;;AAGA;;AAEO;AACL;AACE;AACF;;;AAGF;AACI;AACF;AACA;AACF;;AAEA;;;AAGA;;AAEO;AACL;;AAEA;;AAEI;AACF;;;;AAIE;;;;AAIE;AACF;;;;;AAKA;AACE;AACF;AACF;AACJ;;;AAGA;;AAEA;AACA;;;AAGO;AACL;AACA;AACA;AACF;AACE;AACE;AACA;;AAEA;;AAEJ;;AAEA;AACA;;AAEO;;AAEL;AACA;AACA;AACF;;AAEI;;;AAGF;;AAEF;AACA;;AAEA;;AAEA;AACA;AACA;;;AAGO;AACL;AACA;AACE;AACF;;AAEA;;AAEA;AACE;AACF;;;AAGA;AACA;;;AAGE;AACA;AACF;;AAEF;AACE;AACE;;AAEA;AACA;;;;;AAKA;;AAEA;AACE;AACA;;AAEA;AACE;;AAEF;AACF;AACA;;;AAGF;;AAEA;AACE;;AAEI;AACA;AACA;AACR;AACI;AACF;;;AAGF;;ACxdO;;AAEP;AACA;AACA;;AAEO;AACL;;AAEA;AACF;AACA;AACA;;;AAGI;AACF;;AAEF;;AAEI;AACA;AACF;;AAEA;;AAEE;AACA;AACF;;AAEA;;;AAGF;AACE;;AAEF;;;AAGI;;AAEE;AACA;;;;;;AAMN;AACE;;AAEF;;AAEE;AACE;AACA;AACF;;;;;;AAMM;AACE;AACV;AACA;AACA;;AAES;AACA;;AAEA;AACA;AACA;AACA;;;;AAIA;AACA;;;AAGA;AACA;;;;;;AAMA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA;;;;;AAKA;;;;AAIA;AACA;;;AAGA;;;;;AAKA;;AC3DiB;AACxB;AACA;AACF;;AC5EA;;AAgCA;AACA;AACA;;AAEA;AACE;AACF;;AAEA;AACE;AACA;;AAEF;;AAEA;AACA;;;AAGA;AACE;;;;AAII;AACF;;AAEA;;AAEA;AACE;AACN;;;AAGQ;;AAEF;;;AAGE;AACF;;;AAGA;;;;AAIE;;AAEE;AACF;;;AAGR;AACM;;;AAGA;AACF;AACJ;;;AAGI;;AAEA;AACE;;;AAGE;AACF;AACA;;;AAGE;AACF;AACF;AACJ;;AAEE;;AAEE;AACE;AACF;;AAEA;AACA;AACE;AACF;;AAEA;;;;AAIE;;AAEA;AACE;AACF;;AAEN;AACM;;AAEA;;;AAGA;AACE;AACgG;AACA;;AAEA;AACA;;AAEA;;;AAGA;AACA;AACA;AACA;;;AAGA;AACA;;AAQA;AACA;AACA;AACA;;AAEA;AACA;AACA;;;AAGA;AACA;AACA;;AAEA;AACA;AACA;AACA;;;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;AAMA;;;;AAIA;AACA;AACA;;AAEA;;;;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;;;;;AAMA;AACA;;AAEA;AACA;;AAEA;AACA;;;AAGA;AACA;AACA;;AAEA;;;;;;AAMA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;;;;AAIA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;;AAGA;AACA;AACA;AACA;;AAEA;;;;;AAKA;AACA;AACA;;AAEA;;;;;AAKA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;;;AAIA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;;AAGA;;AAEA;AACA;;AAEA;;AAEA;;;;;AAKA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;;;AAIA;AACA;AACA;;;AAGA;;AAEA;;;AAGA;;AAEA;AACA;;AAEA;AACA;;;AAGA;;;;;AAKA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;;AAGA;;AAEA;AACA;AACA;;AAEA;;;AAGA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;;AAGA;;AAEA;AACA;AACA;AACA;;;AAGA;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"cpu_profiler.d.ts","sourceRoot":"","sources":["../../src/cpu_profiler.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EACV,4BAA4B,EAC5B,kBAAkB,EAClB,mBAAmB,EACnB,qBAAqB,EACtB,MAAM,SAAS,CAAC;AACjB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAU7C;;GAEG;AAEH,wBAAgB,uBAAuB,IAAI,4BAA4B,CA+HtE;AAED,QAAA,MAAM,0BAA0B,EAAE,4BAAwD,CAAC;AAE3F,cAAM,QAAS,YAAW,qBAAqB;IACtC,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IASlC,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,CAAC,MAAM,GAAG,mBAAmB,GAAG,IAAI;IACrF,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,CAAC,KAAK,GAAG,kBAAkB,GAAG,IAAI;CAkB3F;AAED,QAAA,MAAM,mBAAmB,UAAiB,CAAC;AAE3C,OAAO,EAAE,0BAA0B,EAAE,CAAC;AACtC,OAAO,EAAE,mBAAmB,EAAE,CAAC"}
1
+ {"version":3,"file":"cpu_profiler.d.ts","sourceRoot":"","sources":["../../src/cpu_profiler.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EACV,4BAA4B,EAC5B,kBAAkB,EAClB,mBAAmB,EACnB,qBAAqB,EACtB,MAAM,SAAS,CAAC;AACjB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAgB7C;;GAEG;AAEH,wBAAgB,uBAAuB,IAAI,4BAA4B,CA+HtE;AAED,QAAA,MAAM,0BAA0B,EAAE,4BAAwD,CAAC;AAE3F,cAAM,QAAS,YAAW,qBAAqB;IACtC,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IASlC,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,CAAC,MAAM,GAAG,mBAAmB,GAAG,IAAI;IACrF,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,CAAC,KAAK,GAAG,kBAAkB,GAAG,IAAI;CAkB3F;AAED,QAAA,MAAM,mBAAmB,UAAiB,CAAC;AAE3C,OAAO,EAAE,0BAA0B,EAAE,CAAC;AACtC,OAAO,EAAE,mBAAmB,EAAE,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"integration.d.ts","sourceRoot":"","sources":["../../src/integration.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,KAAK,EAA+C,oBAAoB,EAAQ,MAAM,eAAe,CAAC;AAwX7G,+BAA+B;AAC/B,eAAO,MAAM,yBAAyB,QAAQ,qBAAqB,UAAU,CA2CnD,CAAC;AAE3B;;;;;GAKG;AACH,eAAO,MAAM,wBAAwB,2CAA+C,CAAC"}
1
+ {"version":3,"file":"integration.d.ts","sourceRoot":"","sources":["../../src/integration.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,KAAK,EAA+C,oBAAoB,EAAQ,MAAM,eAAe,CAAC;AA+Z7G,+BAA+B;AAC/B,eAAO,MAAM,yBAAyB,QAAQ,qBAAqB,UAAU,CA2CnD,CAAC;AAE3B;;;;;GAKG;AACH,eAAO,MAAM,wBAAwB,2CAA+C,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sentry/profiling-node",
3
- "version": "8.29.0",
3
+ "version": "8.31.0-beta.0",
4
4
  "description": "Official Sentry SDK for Node.js Profiling",
5
5
  "repository": "git://github.com/getsentry/sentry-javascript.git",
6
6
  "homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/profiling-node",
@@ -75,10 +75,10 @@
75
75
  "test": "cross-env SENTRY_PROFILER_BINARY_DIR=lib jest --config jest.config.js"
76
76
  },
77
77
  "dependencies": {
78
- "@sentry/core": "8.29.0",
79
- "@sentry/node": "8.29.0",
80
- "@sentry/types": "8.29.0",
81
- "@sentry/utils": "8.29.0",
78
+ "@sentry/core": "8.31.0-beta.0",
79
+ "@sentry/node": "8.31.0-beta.0",
80
+ "@sentry/types": "8.31.0-beta.0",
81
+ "@sentry/utils": "8.31.0-beta.0",
82
82
  "detect-libc": "^2.0.2",
83
83
  "node-abi": "^3.61.0"
84
84
  },