server-runtime-client.js 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. Object.defineProperty(exports, '__esModule', { value: true });
  2. const utils = require('@sentry/utils');
  3. const baseclient = require('./baseclient.js');
  4. const checkin = require('./checkin.js');
  5. const debugBuild = require('./debug-build.js');
  6. const exports$1 = require('./exports.js');
  7. const aggregator = require('./metrics/aggregator.js');
  8. const sessionflusher = require('./sessionflusher.js');
  9. const hubextensions = require('./tracing/hubextensions.js');
  10. const spanUtils = require('./utils/spanUtils.js');
  11. const getRootSpan = require('./utils/getRootSpan.js');
  12. require('./tracing/spanstatus.js');
  13. const dynamicSamplingContext = require('./tracing/dynamicSamplingContext.js');
  14. /**
  15. * The Sentry Server Runtime Client SDK.
  16. */
  17. class ServerRuntimeClient
  18. extends baseclient.BaseClient {
  19. /**
  20. * Creates a new Edge SDK instance.
  21. * @param options Configuration options for this SDK.
  22. */
  23. constructor(options) {
  24. // Server clients always support tracing
  25. hubextensions.addTracingExtensions();
  26. super(options);
  27. if (options._experiments && options._experiments['metricsAggregator']) {
  28. this.metricsAggregator = new aggregator.MetricsAggregator(this);
  29. }
  30. }
  31. /**
  32. * @inheritDoc
  33. */
  34. eventFromException(exception, hint) {
  35. return utils.resolvedSyncPromise(utils.eventFromUnknownInput(exports$1.getClient(), this._options.stackParser, exception, hint));
  36. }
  37. /**
  38. * @inheritDoc
  39. */
  40. eventFromMessage(
  41. message,
  42. // eslint-disable-next-line deprecation/deprecation
  43. level = 'info',
  44. hint,
  45. ) {
  46. return utils.resolvedSyncPromise(
  47. utils.eventFromMessage(this._options.stackParser, message, level, hint, this._options.attachStacktrace),
  48. );
  49. }
  50. /**
  51. * @inheritDoc
  52. */
  53. // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/explicit-module-boundary-types
  54. captureException(exception, hint, scope) {
  55. // Check if the flag `autoSessionTracking` is enabled, and if `_sessionFlusher` exists because it is initialised only
  56. // when the `requestHandler` middleware is used, and hence the expectation is to have SessionAggregates payload
  57. // sent to the Server only when the `requestHandler` middleware is used
  58. if (this._options.autoSessionTracking && this._sessionFlusher && scope) {
  59. const requestSession = scope.getRequestSession();
  60. // Necessary checks to ensure this is code block is executed only within a request
  61. // Should override the status only if `requestSession.status` is `Ok`, which is its initial stage
  62. if (requestSession && requestSession.status === 'ok') {
  63. requestSession.status = 'errored';
  64. }
  65. }
  66. return super.captureException(exception, hint, scope);
  67. }
  68. /**
  69. * @inheritDoc
  70. */
  71. captureEvent(event, hint, scope) {
  72. // Check if the flag `autoSessionTracking` is enabled, and if `_sessionFlusher` exists because it is initialised only
  73. // when the `requestHandler` middleware is used, and hence the expectation is to have SessionAggregates payload
  74. // sent to the Server only when the `requestHandler` middleware is used
  75. if (this._options.autoSessionTracking && this._sessionFlusher && scope) {
  76. const eventType = event.type || 'exception';
  77. const isException =
  78. eventType === 'exception' && event.exception && event.exception.values && event.exception.values.length > 0;
  79. // If the event is of type Exception, then a request session should be captured
  80. if (isException) {
  81. const requestSession = scope.getRequestSession();
  82. // Ensure that this is happening within the bounds of a request, and make sure not to override
  83. // Session Status if Errored / Crashed
  84. if (requestSession && requestSession.status === 'ok') {
  85. requestSession.status = 'errored';
  86. }
  87. }
  88. }
  89. return super.captureEvent(event, hint, scope);
  90. }
  91. /**
  92. *
  93. * @inheritdoc
  94. */
  95. close(timeout) {
  96. if (this._sessionFlusher) {
  97. this._sessionFlusher.close();
  98. }
  99. return super.close(timeout);
  100. }
  101. /** Method that initialises an instance of SessionFlusher on Client */
  102. initSessionFlusher() {
  103. const { release, environment } = this._options;
  104. if (!release) {
  105. debugBuild.DEBUG_BUILD && utils.logger.warn('Cannot initialise an instance of SessionFlusher if no release is provided!');
  106. } else {
  107. this._sessionFlusher = new sessionflusher.SessionFlusher(this, {
  108. release,
  109. environment,
  110. });
  111. }
  112. }
  113. /**
  114. * Create a cron monitor check in and send it to Sentry.
  115. *
  116. * @param checkIn An object that describes a check in.
  117. * @param upsertMonitorConfig An optional object that describes a monitor config. Use this if you want
  118. * to create a monitor automatically when sending a check in.
  119. */
  120. captureCheckIn(checkIn, monitorConfig, scope) {
  121. const id = 'checkInId' in checkIn && checkIn.checkInId ? checkIn.checkInId : utils.uuid4();
  122. if (!this._isEnabled()) {
  123. debugBuild.DEBUG_BUILD && utils.logger.warn('SDK not enabled, will not capture checkin.');
  124. return id;
  125. }
  126. const options = this.getOptions();
  127. const { release, environment, tunnel } = options;
  128. const serializedCheckIn = {
  129. check_in_id: id,
  130. monitor_slug: checkIn.monitorSlug,
  131. status: checkIn.status,
  132. release,
  133. environment,
  134. };
  135. if ('duration' in checkIn) {
  136. serializedCheckIn.duration = checkIn.duration;
  137. }
  138. if (monitorConfig) {
  139. serializedCheckIn.monitor_config = {
  140. schedule: monitorConfig.schedule,
  141. checkin_margin: monitorConfig.checkinMargin,
  142. max_runtime: monitorConfig.maxRuntime,
  143. timezone: monitorConfig.timezone,
  144. };
  145. }
  146. const [dynamicSamplingContext, traceContext] = this._getTraceInfoFromScope(scope);
  147. if (traceContext) {
  148. serializedCheckIn.contexts = {
  149. trace: traceContext,
  150. };
  151. }
  152. const envelope = checkin.createCheckInEnvelope(
  153. serializedCheckIn,
  154. dynamicSamplingContext,
  155. this.getSdkMetadata(),
  156. tunnel,
  157. this.getDsn(),
  158. );
  159. debugBuild.DEBUG_BUILD && utils.logger.info('Sending checkin:', checkIn.monitorSlug, checkIn.status);
  160. // _sendEnvelope should not throw
  161. // eslint-disable-next-line @typescript-eslint/no-floating-promises
  162. this._sendEnvelope(envelope);
  163. return id;
  164. }
  165. /**
  166. * Method responsible for capturing/ending a request session by calling `incrementSessionStatusCount` to increment
  167. * appropriate session aggregates bucket
  168. */
  169. _captureRequestSession() {
  170. if (!this._sessionFlusher) {
  171. debugBuild.DEBUG_BUILD && utils.logger.warn('Discarded request mode session because autoSessionTracking option was disabled');
  172. } else {
  173. this._sessionFlusher.incrementSessionStatusCount();
  174. }
  175. }
  176. /**
  177. * @inheritDoc
  178. */
  179. _prepareEvent(
  180. event,
  181. hint,
  182. scope,
  183. isolationScope,
  184. ) {
  185. if (this._options.platform) {
  186. event.platform = event.platform || this._options.platform;
  187. }
  188. if (this._options.runtime) {
  189. event.contexts = {
  190. ...event.contexts,
  191. runtime: (event.contexts || {}).runtime || this._options.runtime,
  192. };
  193. }
  194. if (this._options.serverName) {
  195. event.server_name = event.server_name || this._options.serverName;
  196. }
  197. return super._prepareEvent(event, hint, scope, isolationScope);
  198. }
  199. /** Extract trace information from scope */
  200. _getTraceInfoFromScope(
  201. scope,
  202. ) {
  203. if (!scope) {
  204. return [undefined, undefined];
  205. }
  206. // eslint-disable-next-line deprecation/deprecation
  207. const span = scope.getSpan();
  208. if (span) {
  209. const samplingContext = getRootSpan.getRootSpan(span) ? dynamicSamplingContext.getDynamicSamplingContextFromSpan(span) : undefined;
  210. return [samplingContext, spanUtils.spanToTraceContext(span)];
  211. }
  212. const { traceId, spanId, parentSpanId, dsc } = scope.getPropagationContext();
  213. const traceContext = {
  214. trace_id: traceId,
  215. span_id: spanId,
  216. parent_span_id: parentSpanId,
  217. };
  218. if (dsc) {
  219. return [dsc, traceContext];
  220. }
  221. return [dynamicSamplingContext.getDynamicSamplingContextFromClient(traceId, this, scope), traceContext];
  222. }
  223. }
  224. exports.ServerRuntimeClient = ServerRuntimeClient;
  225. //# sourceMappingURL=server-runtime-client.js.map