@sentry/profiling-node 8.30.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 (35) 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 +73 -34
  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/integration.d.ts.map +1 -1
  35. package/package.json +5 -5
@@ -73,7 +73,7 @@ enum class ProfileStatus {
73
73
 
74
74
  class MeasurementsTicker {
75
75
  private:
76
- uv_timer_t timer;
76
+ uv_timer_t *timer;
77
77
  uint64_t period_ms;
78
78
  std::unordered_map<std::string,
79
79
  const std::function<bool(uint64_t, v8::HeapStatistics &)>>
@@ -87,9 +87,10 @@ private:
87
87
  public:
88
88
  MeasurementsTicker(uv_loop_t *loop)
89
89
  : period_ms(100), isolate(v8::Isolate::GetCurrent()) {
90
- uv_timer_init(loop, &timer);
91
- uv_handle_set_data(reinterpret_cast<uv_handle_t *>(&timer), this);
92
- uv_unref(reinterpret_cast<uv_handle_t *>(&timer));
90
+ timer = new uv_timer_t;
91
+ uv_timer_init(loop, timer);
92
+ uv_handle_set_data((uv_handle_t *)timer, this);
93
+ uv_ref((uv_handle_t *)timer);
93
94
  }
94
95
 
95
96
  static void ticker(uv_timer_t *);
@@ -112,13 +113,13 @@ public:
112
113
  size_t listener_count();
113
114
 
114
115
  ~MeasurementsTicker() {
115
- uv_timer_stop(&timer);
116
+ uv_handle_t *handle = (uv_handle_t *)timer;
116
117
 
117
- auto handle = reinterpret_cast<uv_handle_t *>(&timer);
118
+ uv_timer_stop(timer);
119
+ uv_unref(handle);
118
120
 
119
- // Calling uv_close on an inactive handle will cause a segfault.
120
- if (uv_is_active(handle)) {
121
- uv_close(handle, nullptr);
121
+ if (!uv_is_closing(handle)) {
122
+ uv_close(handle, [](uv_handle_t *handle) { delete handle; });
122
123
  }
123
124
  }
124
125
  };
@@ -143,8 +144,8 @@ void MeasurementsTicker::add_heap_listener(
143
144
  heap_listeners.emplace(profile_id, cb);
144
145
 
145
146
  if (listener_count() == 1) {
146
- uv_timer_set_repeat(&timer, period_ms);
147
- uv_timer_start(&timer, ticker, 0, period_ms);
147
+ uv_timer_set_repeat(timer, period_ms);
148
+ uv_timer_start(timer, ticker, 0, period_ms);
148
149
  }
149
150
  }
150
151
 
@@ -154,7 +155,7 @@ void MeasurementsTicker::remove_heap_listener(
154
155
  heap_listeners.erase(profile_id);
155
156
 
156
157
  if (listener_count() == 0) {
157
- uv_timer_stop(&timer);
158
+ uv_timer_stop(timer);
158
159
  }
159
160
  };
160
161
 
@@ -223,8 +224,8 @@ void MeasurementsTicker::add_cpu_listener(
223
224
  cpu_listeners.emplace(profile_id, cb);
224
225
 
225
226
  if (listener_count() == 1) {
226
- uv_timer_set_repeat(&timer, period_ms);
227
- uv_timer_start(&timer, ticker, 0, period_ms);
227
+ uv_timer_set_repeat(timer, period_ms);
228
+ uv_timer_start(timer, ticker, 0, period_ms);
228
229
  }
229
230
  }
230
231
 
@@ -233,7 +234,7 @@ void MeasurementsTicker::remove_cpu_listener(
233
234
  cpu_listeners.erase(profile_id);
234
235
 
235
236
  if (listener_count() == 0) {
236
- uv_timer_stop(&timer);
237
+ uv_timer_stop(timer);
237
238
  }
238
239
  };
239
240
 
package/lib/cjs/index.js CHANGED
@@ -904,10 +904,10 @@ function setupAutomatedSpanProfiling(client) {
904
904
  });
905
905
  }
906
906
 
907
- class ContinuousProfiler {constructor() { ContinuousProfiler.prototype.__init.call(this);ContinuousProfiler.prototype.__init2.call(this);ContinuousProfiler.prototype.__init3.call(this); }
908
- __init() {this._profilerId = utils.uuid4();}
909
- __init2() {this._client = undefined;}
910
- __init3() {this._chunkData = undefined;}
907
+ class ContinuousProfiler {constructor() { ContinuousProfiler.prototype.__init.call(this);ContinuousProfiler.prototype.__init2.call(this); }
908
+
909
+ __init() {this._client = undefined;}
910
+ __init2() {this._chunkData = undefined;}
911
911
 
912
912
  /**
913
913
  * Called when the profiler is attached to the client (continuous mode is enabled). If of the profiler
@@ -916,15 +916,48 @@ class ContinuousProfiler {constructor() { ContinuousProfiler.prototype.__init.ca
916
916
  */
917
917
  initialize(client) {
918
918
  this._client = client;
919
+
920
+ // Attaches a listener to beforeSend which will add the threadId data to the event being sent.
921
+ // This adds a constant overhead to all events being sent which could be improved to only attach
922
+ // and detach the listener during a profiler session
923
+ this._client.on('beforeSendEvent', this._onBeforeSendThreadContextAssignment.bind(this));
919
924
  }
920
925
 
921
926
  /**
922
- * Recursively schedules chunk profiling to start and stop at a set interval.
923
- * Once the user calls stop(), the current chunk will be stopped and flushed to Sentry and no new chunks will
924
- * will be started. To restart continuous mode after calling stop(), the user must call start() again.
927
+ * Initializes a new profilerId session and schedules chunk profiling.
925
928
  * @returns void
926
929
  */
927
930
  start() {
931
+ if (!this._client) {
932
+ DEBUG_BUILD && utils.logger.log('[Profiling] Failed to start, sentry client was never attached to the profiler.');
933
+ return;
934
+ }
935
+
936
+ // Flush any existing chunks before starting a new one.
937
+ this._chunkStop();
938
+
939
+ // Restart the profiler session
940
+ this._setupSpanChunkInstrumentation();
941
+ this._chunkStart();
942
+ }
943
+
944
+ /**
945
+ * Stops the current chunk and flushes the profile to Sentry.
946
+ * @returns void
947
+ */
948
+ stop() {
949
+ if (!this._client) {
950
+ DEBUG_BUILD && utils.logger.log('[Profiling] Failed to stop, sentry client was never attached to the profiler.');
951
+ return;
952
+ }
953
+ this._chunkStop();
954
+ this._teardownSpanChunkInstrumentation();
955
+ }
956
+
957
+ /**
958
+ * Stop profiler and initializes profiling of the next chunk
959
+ */
960
+ _chunkStart() {
928
961
  if (!this._client) {
929
962
  // The client is not attached to the profiler if the user has not enabled continuous profiling.
930
963
  // In this case, calling start() and stop() is a noop action.The reason this exists is because
@@ -937,20 +970,16 @@ class ContinuousProfiler {constructor() { ContinuousProfiler.prototype.__init.ca
937
970
  utils.logger.log(
938
971
  `[Profiling] Chunk with chunk_id ${this._chunkData.id} is still running, current chunk will be stopped a new chunk will be started.`,
939
972
  );
940
- this.stop();
973
+ this._chunkStop();
941
974
  }
942
975
 
943
- const traceId =
944
- core.getCurrentScope().getPropagationContext().traceId || core.getIsolationScope().getPropagationContext().traceId;
945
- this._initializeChunk(traceId);
946
- this._startChunkProfiling(this._chunkData);
976
+ this._startChunkProfiling();
947
977
  }
948
978
 
949
979
  /**
950
- * Stops the current chunk and flushes the profile to Sentry.
951
- * @returns void
980
+ * Stops profiling of the current chunks and flushes the profile to Sentry
952
981
  */
953
- stop() {
982
+ _chunkStop() {
954
983
  if (_optionalChain([this, 'access', _6 => _6._chunkData, 'optionalAccess', _7 => _7.timer])) {
955
984
  global.clearTimeout(this._chunkData.timer);
956
985
  this._chunkData.timer = undefined;
@@ -967,12 +996,17 @@ class ContinuousProfiler {constructor() { ContinuousProfiler.prototype.__init.ca
967
996
  return;
968
997
  }
969
998
 
970
- const profile = this._stopChunkProfiling(this._chunkData);
999
+ const profile = CpuProfilerBindings.stopProfiling(this._chunkData.id, ProfileFormat.CHUNK);
971
1000
 
972
1001
  if (!profile) {
973
1002
  DEBUG_BUILD && utils.logger.log(`[Profiling] _chunkiledStartTraceID to collect profile for: ${this._chunkData.id}`);
974
1003
  return;
975
1004
  }
1005
+ if (!this._profilerId) {
1006
+ DEBUG_BUILD &&
1007
+ utils.logger.log('[Profiling] Profile chunk does not contain a valid profiler_id, this is a bug in the SDK');
1008
+ return;
1009
+ }
976
1010
  if (profile) {
977
1011
  DEBUG_BUILD && utils.logger.log(`[Profiling] Sending profile chunk ${this._chunkData.id}.`);
978
1012
  }
@@ -992,7 +1026,7 @@ class ContinuousProfiler {constructor() { ContinuousProfiler.prototype.__init.ca
992
1026
 
993
1027
  if (!chunk) {
994
1028
  DEBUG_BUILD && utils.logger.log(`[Profiling] Failed to create profile chunk for: ${this._chunkData.id}`);
995
- this._reset();
1029
+ this._resetChunkData();
996
1030
  return;
997
1031
  }
998
1032
 
@@ -1001,7 +1035,7 @@ class ContinuousProfiler {constructor() { ContinuousProfiler.prototype.__init.ca
1001
1035
  // the format may negatively impact the performance of the application. To avoid
1002
1036
  // blocking for too long, enqueue the next chunk start inside the next macrotask.
1003
1037
  // clear current chunk
1004
- this._reset();
1038
+ this._resetChunkData();
1005
1039
  }
1006
1040
 
1007
1041
  /**
@@ -1031,29 +1065,23 @@ class ContinuousProfiler {constructor() { ContinuousProfiler.prototype.__init.ca
1031
1065
  });
1032
1066
  }
1033
1067
 
1034
- /**
1035
- * Stops the profile and clears chunk instrumentation from global scope
1036
- * @returns void
1037
- */
1038
- _stopChunkProfiling(chunk) {
1039
- this._teardownSpanChunkInstrumentation();
1040
- return CpuProfilerBindings.stopProfiling(chunk.id, ProfileFormat.CHUNK);
1041
- }
1042
-
1043
1068
  /**
1044
1069
  * Starts the profiler and registers the flush timer for a given chunk.
1045
1070
  * @param chunk
1046
1071
  */
1047
- _startChunkProfiling(chunk) {
1048
- this._setupSpanChunkInstrumentation();
1072
+ _startChunkProfiling() {
1073
+ const traceId =
1074
+ core.getCurrentScope().getPropagationContext().traceId || core.getIsolationScope().getPropagationContext().traceId;
1075
+ const chunk = this._initializeChunk(traceId);
1076
+
1049
1077
  CpuProfilerBindings.startProfiling(chunk.id);
1050
1078
  DEBUG_BUILD && utils.logger.log(`[Profiling] starting profiling chunk: ${chunk.id}`);
1051
1079
 
1052
1080
  chunk.timer = global.setTimeout(() => {
1053
1081
  DEBUG_BUILD && utils.logger.log(`[Profiling] Stopping profiling chunk: ${chunk.id}`);
1054
- this.stop();
1082
+ this._chunkStop();
1055
1083
  DEBUG_BUILD && utils.logger.log('[Profiling] Starting new profiling chunk.');
1056
- setImmediate(this.start.bind(this));
1084
+ setImmediate(this._chunkStart.bind(this));
1057
1085
  }, CHUNK_INTERVAL_MS);
1058
1086
 
1059
1087
  // Unref timeout so it doesn't keep the process alive.
@@ -1067,21 +1095,31 @@ class ContinuousProfiler {constructor() { ContinuousProfiler.prototype.__init.ca
1067
1095
  _setupSpanChunkInstrumentation() {
1068
1096
  if (!this._client) {
1069
1097
  DEBUG_BUILD &&
1070
- utils.logger.log('[Profiling] Failed to collect profile, sentry client was never attached to the profiler.');
1098
+ utils.logger.log(
1099
+ '[Profiling] Failed to initialize span profiling, sentry client was never attached to the profiler.',
1100
+ );
1071
1101
  return;
1072
1102
  }
1073
1103
 
1104
+ this._profilerId = utils.uuid4();
1074
1105
  core.getGlobalScope().setContext('profile', {
1075
1106
  profiler_id: this._profilerId,
1076
1107
  });
1108
+ }
1077
1109
 
1078
- this._client.on('beforeSendEvent', e => this._assignThreadIdContext(e));
1110
+ /**
1111
+ * Assigns thread_id and thread name context to a profiled event if there is an active profiler session
1112
+ */
1113
+ _onBeforeSendThreadContextAssignment(event) {
1114
+ if (!this._client || !this._profilerId) return;
1115
+ this._assignThreadIdContext(event);
1079
1116
  }
1080
1117
 
1081
1118
  /**
1082
1119
  * Clear profiling information from global context when a profile is not running.
1083
1120
  */
1084
1121
  _teardownSpanChunkInstrumentation() {
1122
+ this._profilerId = undefined;
1085
1123
  const globalScope = core.getGlobalScope();
1086
1124
  globalScope.setContext('profile', {});
1087
1125
  }
@@ -1095,6 +1133,7 @@ class ContinuousProfiler {constructor() { ContinuousProfiler.prototype.__init.ca
1095
1133
  startTraceID: traceId,
1096
1134
  timer: undefined,
1097
1135
  };
1136
+ return this._chunkData;
1098
1137
  }
1099
1138
 
1100
1139
  /**
@@ -1124,7 +1163,7 @@ class ContinuousProfiler {constructor() { ContinuousProfiler.prototype.__init.ca
1124
1163
  /**
1125
1164
  * Resets the current chunk state.
1126
1165
  */
1127
- _reset() {
1166
+ _resetChunkData() {
1128
1167
  this._chunkData = undefined;
1129
1168
  }
1130
1169
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
package/lib/esm/index.js CHANGED
@@ -912,10 +912,10 @@ function setupAutomatedSpanProfiling(client) {
912
912
  });
913
913
  }
914
914
 
915
- class ContinuousProfiler {constructor() { ContinuousProfiler.prototype.__init.call(this);ContinuousProfiler.prototype.__init2.call(this);ContinuousProfiler.prototype.__init3.call(this); }
916
- __init() {this._profilerId = uuid4();}
917
- __init2() {this._client = undefined;}
918
- __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;}
919
919
 
920
920
  /**
921
921
  * Called when the profiler is attached to the client (continuous mode is enabled). If of the profiler
@@ -924,15 +924,48 @@ class ContinuousProfiler {constructor() { ContinuousProfiler.prototype.__init.ca
924
924
  */
925
925
  initialize(client) {
926
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));
927
932
  }
928
933
 
929
934
  /**
930
- * Recursively schedules chunk profiling to start and stop at a set interval.
931
- * Once the user calls stop(), the current chunk will be stopped and flushed to Sentry and no new chunks will
932
- * 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.
933
936
  * @returns void
934
937
  */
935
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() {
936
969
  if (!this._client) {
937
970
  // The client is not attached to the profiler if the user has not enabled continuous profiling.
938
971
  // In this case, calling start() and stop() is a noop action.The reason this exists is because
@@ -945,20 +978,16 @@ class ContinuousProfiler {constructor() { ContinuousProfiler.prototype.__init.ca
945
978
  logger.log(
946
979
  `[Profiling] Chunk with chunk_id ${this._chunkData.id} is still running, current chunk will be stopped a new chunk will be started.`,
947
980
  );
948
- this.stop();
981
+ this._chunkStop();
949
982
  }
950
983
 
951
- const traceId =
952
- getCurrentScope().getPropagationContext().traceId || getIsolationScope().getPropagationContext().traceId;
953
- this._initializeChunk(traceId);
954
- this._startChunkProfiling(this._chunkData);
984
+ this._startChunkProfiling();
955
985
  }
956
986
 
957
987
  /**
958
- * Stops the current chunk and flushes the profile to Sentry.
959
- * @returns void
988
+ * Stops profiling of the current chunks and flushes the profile to Sentry
960
989
  */
961
- stop() {
990
+ _chunkStop() {
962
991
  if (_optionalChain([this, 'access', _6 => _6._chunkData, 'optionalAccess', _7 => _7.timer])) {
963
992
  global.clearTimeout(this._chunkData.timer);
964
993
  this._chunkData.timer = undefined;
@@ -975,12 +1004,17 @@ class ContinuousProfiler {constructor() { ContinuousProfiler.prototype.__init.ca
975
1004
  return;
976
1005
  }
977
1006
 
978
- const profile = this._stopChunkProfiling(this._chunkData);
1007
+ const profile = CpuProfilerBindings.stopProfiling(this._chunkData.id, ProfileFormat.CHUNK);
979
1008
 
980
1009
  if (!profile) {
981
1010
  DEBUG_BUILD && logger.log(`[Profiling] _chunkiledStartTraceID to collect profile for: ${this._chunkData.id}`);
982
1011
  return;
983
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
+ }
984
1018
  if (profile) {
985
1019
  DEBUG_BUILD && logger.log(`[Profiling] Sending profile chunk ${this._chunkData.id}.`);
986
1020
  }
@@ -1000,7 +1034,7 @@ class ContinuousProfiler {constructor() { ContinuousProfiler.prototype.__init.ca
1000
1034
 
1001
1035
  if (!chunk) {
1002
1036
  DEBUG_BUILD && logger.log(`[Profiling] Failed to create profile chunk for: ${this._chunkData.id}`);
1003
- this._reset();
1037
+ this._resetChunkData();
1004
1038
  return;
1005
1039
  }
1006
1040
 
@@ -1009,7 +1043,7 @@ class ContinuousProfiler {constructor() { ContinuousProfiler.prototype.__init.ca
1009
1043
  // the format may negatively impact the performance of the application. To avoid
1010
1044
  // blocking for too long, enqueue the next chunk start inside the next macrotask.
1011
1045
  // clear current chunk
1012
- this._reset();
1046
+ this._resetChunkData();
1013
1047
  }
1014
1048
 
1015
1049
  /**
@@ -1039,29 +1073,23 @@ class ContinuousProfiler {constructor() { ContinuousProfiler.prototype.__init.ca
1039
1073
  });
1040
1074
  }
1041
1075
 
1042
- /**
1043
- * Stops the profile and clears chunk instrumentation from global scope
1044
- * @returns void
1045
- */
1046
- _stopChunkProfiling(chunk) {
1047
- this._teardownSpanChunkInstrumentation();
1048
- return CpuProfilerBindings.stopProfiling(chunk.id, ProfileFormat.CHUNK);
1049
- }
1050
-
1051
1076
  /**
1052
1077
  * Starts the profiler and registers the flush timer for a given chunk.
1053
1078
  * @param chunk
1054
1079
  */
1055
- _startChunkProfiling(chunk) {
1056
- this._setupSpanChunkInstrumentation();
1080
+ _startChunkProfiling() {
1081
+ const traceId =
1082
+ getCurrentScope().getPropagationContext().traceId || getIsolationScope().getPropagationContext().traceId;
1083
+ const chunk = this._initializeChunk(traceId);
1084
+
1057
1085
  CpuProfilerBindings.startProfiling(chunk.id);
1058
1086
  DEBUG_BUILD && logger.log(`[Profiling] starting profiling chunk: ${chunk.id}`);
1059
1087
 
1060
1088
  chunk.timer = global.setTimeout(() => {
1061
1089
  DEBUG_BUILD && logger.log(`[Profiling] Stopping profiling chunk: ${chunk.id}`);
1062
- this.stop();
1090
+ this._chunkStop();
1063
1091
  DEBUG_BUILD && logger.log('[Profiling] Starting new profiling chunk.');
1064
- setImmediate(this.start.bind(this));
1092
+ setImmediate(this._chunkStart.bind(this));
1065
1093
  }, CHUNK_INTERVAL_MS);
1066
1094
 
1067
1095
  // Unref timeout so it doesn't keep the process alive.
@@ -1075,21 +1103,31 @@ class ContinuousProfiler {constructor() { ContinuousProfiler.prototype.__init.ca
1075
1103
  _setupSpanChunkInstrumentation() {
1076
1104
  if (!this._client) {
1077
1105
  DEBUG_BUILD &&
1078
- 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
+ );
1079
1109
  return;
1080
1110
  }
1081
1111
 
1112
+ this._profilerId = uuid4();
1082
1113
  getGlobalScope().setContext('profile', {
1083
1114
  profiler_id: this._profilerId,
1084
1115
  });
1116
+ }
1085
1117
 
1086
- 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);
1087
1124
  }
1088
1125
 
1089
1126
  /**
1090
1127
  * Clear profiling information from global context when a profile is not running.
1091
1128
  */
1092
1129
  _teardownSpanChunkInstrumentation() {
1130
+ this._profilerId = undefined;
1093
1131
  const globalScope = getGlobalScope();
1094
1132
  globalScope.setContext('profile', {});
1095
1133
  }
@@ -1103,6 +1141,7 @@ class ContinuousProfiler {constructor() { ContinuousProfiler.prototype.__init.ca
1103
1141
  startTraceID: traceId,
1104
1142
  timer: undefined,
1105
1143
  };
1144
+ return this._chunkData;
1106
1145
  }
1107
1146
 
1108
1147
  /**
@@ -1132,7 +1171,7 @@ class ContinuousProfiler {constructor() { ContinuousProfiler.prototype.__init.ca
1132
1171
  /**
1133
1172
  * Resets the current chunk state.
1134
1173
  */
1135
- _reset() {
1174
+ _resetChunkData() {
1136
1175
  this._chunkData = undefined;
1137
1176
  }
1138
1177
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -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.30.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.30.0",
79
- "@sentry/node": "8.30.0",
80
- "@sentry/types": "8.30.0",
81
- "@sentry/utils": "8.30.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
  },