trace.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364
  1. Object.defineProperty(exports, '__esModule', { value: true });
  2. const utils = require('@sentry/utils');
  3. const debugBuild = require('../debug-build.js');
  4. const exports$1 = require('../exports.js');
  5. const hub = require('../hub.js');
  6. const handleCallbackErrors = require('../utils/handleCallbackErrors.js');
  7. const hasTracingEnabled = require('../utils/hasTracingEnabled.js');
  8. const spanUtils = require('../utils/spanUtils.js');
  9. /**
  10. * Wraps a function with a transaction/span and finishes the span after the function is done.
  11. *
  12. * Note that if you have not enabled tracing extensions via `addTracingExtensions`
  13. * or you didn't set `tracesSampleRate`, this function will not generate spans
  14. * and the `span` returned from the callback will be undefined.
  15. *
  16. * This function is meant to be used internally and may break at any time. Use at your own risk.
  17. *
  18. * @internal
  19. * @private
  20. *
  21. * @deprecated Use `startSpan` instead.
  22. */
  23. function trace(
  24. context,
  25. callback,
  26. // eslint-disable-next-line @typescript-eslint/no-empty-function
  27. onError = () => {},
  28. // eslint-disable-next-line @typescript-eslint/no-empty-function
  29. afterFinish = () => {},
  30. ) {
  31. // eslint-disable-next-line deprecation/deprecation
  32. const hub$1 = hub.getCurrentHub();
  33. const scope = exports$1.getCurrentScope();
  34. // eslint-disable-next-line deprecation/deprecation
  35. const parentSpan = scope.getSpan();
  36. const ctx = normalizeContext(context);
  37. const activeSpan = createChildSpanOrTransaction(hub$1, parentSpan, ctx);
  38. // eslint-disable-next-line deprecation/deprecation
  39. scope.setSpan(activeSpan);
  40. return handleCallbackErrors.handleCallbackErrors(
  41. () => callback(activeSpan),
  42. error => {
  43. activeSpan && activeSpan.setStatus('internal_error');
  44. onError(error, activeSpan);
  45. },
  46. () => {
  47. activeSpan && activeSpan.end();
  48. // eslint-disable-next-line deprecation/deprecation
  49. scope.setSpan(parentSpan);
  50. afterFinish();
  51. },
  52. );
  53. }
  54. /**
  55. * Wraps a function with a transaction/span and finishes the span after the function is done.
  56. * The created span is the active span and will be used as parent by other spans created inside the function
  57. * and can be accessed via `Sentry.getSpan()`, as long as the function is executed while the scope is active.
  58. *
  59. * If you want to create a span that is not set as active, use {@link startInactiveSpan}.
  60. *
  61. * Note that if you have not enabled tracing extensions via `addTracingExtensions`
  62. * or you didn't set `tracesSampleRate`, this function will not generate spans
  63. * and the `span` returned from the callback will be undefined.
  64. */
  65. function startSpan(context, callback) {
  66. const ctx = normalizeContext(context);
  67. return hub.runWithAsyncContext(() => {
  68. return exports$1.withScope(context.scope, scope => {
  69. // eslint-disable-next-line deprecation/deprecation
  70. const hub$1 = hub.getCurrentHub();
  71. // eslint-disable-next-line deprecation/deprecation
  72. const parentSpan = scope.getSpan();
  73. const shouldSkipSpan = context.onlyIfParent && !parentSpan;
  74. const activeSpan = shouldSkipSpan ? undefined : createChildSpanOrTransaction(hub$1, parentSpan, ctx);
  75. // eslint-disable-next-line deprecation/deprecation
  76. scope.setSpan(activeSpan);
  77. return handleCallbackErrors.handleCallbackErrors(
  78. () => callback(activeSpan),
  79. () => {
  80. // Only update the span status if it hasn't been changed yet
  81. if (activeSpan) {
  82. const { status } = spanUtils.spanToJSON(activeSpan);
  83. if (!status || status === 'ok') {
  84. activeSpan.setStatus('internal_error');
  85. }
  86. }
  87. },
  88. () => activeSpan && activeSpan.end(),
  89. );
  90. });
  91. });
  92. }
  93. /**
  94. * @deprecated Use {@link startSpan} instead.
  95. */
  96. const startActiveSpan = startSpan;
  97. /**
  98. * Similar to `Sentry.startSpan`. Wraps a function with a transaction/span, but does not finish the span
  99. * after the function is done automatically. You'll have to call `span.end()` manually.
  100. *
  101. * The created span is the active span and will be used as parent by other spans created inside the function
  102. * and can be accessed via `Sentry.getActiveSpan()`, as long as the function is executed while the scope is active.
  103. *
  104. * Note that if you have not enabled tracing extensions via `addTracingExtensions`
  105. * or you didn't set `tracesSampleRate`, this function will not generate spans
  106. * and the `span` returned from the callback will be undefined.
  107. */
  108. function startSpanManual(
  109. context,
  110. callback,
  111. ) {
  112. const ctx = normalizeContext(context);
  113. return hub.runWithAsyncContext(() => {
  114. return exports$1.withScope(context.scope, scope => {
  115. // eslint-disable-next-line deprecation/deprecation
  116. const hub$1 = hub.getCurrentHub();
  117. // eslint-disable-next-line deprecation/deprecation
  118. const parentSpan = scope.getSpan();
  119. const shouldSkipSpan = context.onlyIfParent && !parentSpan;
  120. const activeSpan = shouldSkipSpan ? undefined : createChildSpanOrTransaction(hub$1, parentSpan, ctx);
  121. // eslint-disable-next-line deprecation/deprecation
  122. scope.setSpan(activeSpan);
  123. function finishAndSetSpan() {
  124. activeSpan && activeSpan.end();
  125. }
  126. return handleCallbackErrors.handleCallbackErrors(
  127. () => callback(activeSpan, finishAndSetSpan),
  128. () => {
  129. // Only update the span status if it hasn't been changed yet, and the span is not yet finished
  130. if (activeSpan && activeSpan.isRecording()) {
  131. const { status } = spanUtils.spanToJSON(activeSpan);
  132. if (!status || status === 'ok') {
  133. activeSpan.setStatus('internal_error');
  134. }
  135. }
  136. },
  137. );
  138. });
  139. });
  140. }
  141. /**
  142. * Creates a span. This span is not set as active, so will not get automatic instrumentation spans
  143. * as children or be able to be accessed via `Sentry.getSpan()`.
  144. *
  145. * If you want to create a span that is set as active, use {@link startSpan}.
  146. *
  147. * Note that if you have not enabled tracing extensions via `addTracingExtensions`
  148. * or you didn't set `tracesSampleRate` or `tracesSampler`, this function will not generate spans
  149. * and the `span` returned from the callback will be undefined.
  150. */
  151. function startInactiveSpan(context) {
  152. if (!hasTracingEnabled.hasTracingEnabled()) {
  153. return undefined;
  154. }
  155. const ctx = normalizeContext(context);
  156. // eslint-disable-next-line deprecation/deprecation
  157. const hub$1 = hub.getCurrentHub();
  158. const parentSpan = context.scope
  159. ? // eslint-disable-next-line deprecation/deprecation
  160. context.scope.getSpan()
  161. : getActiveSpan();
  162. const shouldSkipSpan = context.onlyIfParent && !parentSpan;
  163. if (shouldSkipSpan) {
  164. return undefined;
  165. }
  166. const isolationScope = hub.getIsolationScope();
  167. const scope = exports$1.getCurrentScope();
  168. let span;
  169. if (parentSpan) {
  170. // eslint-disable-next-line deprecation/deprecation
  171. span = parentSpan.startChild(ctx);
  172. } else {
  173. const { traceId, dsc, parentSpanId, sampled } = {
  174. ...isolationScope.getPropagationContext(),
  175. ...scope.getPropagationContext(),
  176. };
  177. // eslint-disable-next-line deprecation/deprecation
  178. span = hub$1.startTransaction({
  179. traceId,
  180. parentSpanId,
  181. parentSampled: sampled,
  182. ...ctx,
  183. metadata: {
  184. dynamicSamplingContext: dsc,
  185. // eslint-disable-next-line deprecation/deprecation
  186. ...ctx.metadata,
  187. },
  188. });
  189. }
  190. setCapturedScopesOnSpan(span, scope, isolationScope);
  191. return span;
  192. }
  193. /**
  194. * Returns the currently active span.
  195. */
  196. function getActiveSpan() {
  197. // eslint-disable-next-line deprecation/deprecation
  198. return exports$1.getCurrentScope().getSpan();
  199. }
  200. const continueTrace = (
  201. {
  202. sentryTrace,
  203. baggage,
  204. }
  205. ,
  206. callback,
  207. ) => {
  208. // TODO(v8): Change this function so it doesn't do anything besides setting the propagation context on the current scope:
  209. /*
  210. return withScope((scope) => {
  211. const propagationContext = propagationContextFromHeaders(sentryTrace, baggage);
  212. scope.setPropagationContext(propagationContext);
  213. return callback();
  214. })
  215. */
  216. const currentScope = exports$1.getCurrentScope();
  217. // eslint-disable-next-line deprecation/deprecation
  218. const { traceparentData, dynamicSamplingContext, propagationContext } = utils.tracingContextFromHeaders(
  219. sentryTrace,
  220. baggage,
  221. );
  222. currentScope.setPropagationContext(propagationContext);
  223. if (debugBuild.DEBUG_BUILD && traceparentData) {
  224. utils.logger.log(`[Tracing] Continuing trace ${traceparentData.traceId}.`);
  225. }
  226. const transactionContext = {
  227. ...traceparentData,
  228. metadata: utils.dropUndefinedKeys({
  229. dynamicSamplingContext,
  230. }),
  231. };
  232. if (!callback) {
  233. return transactionContext;
  234. }
  235. return hub.runWithAsyncContext(() => {
  236. return callback(transactionContext);
  237. });
  238. };
  239. function createChildSpanOrTransaction(
  240. hub$1,
  241. parentSpan,
  242. ctx,
  243. ) {
  244. if (!hasTracingEnabled.hasTracingEnabled()) {
  245. return undefined;
  246. }
  247. const isolationScope = hub.getIsolationScope();
  248. const scope = exports$1.getCurrentScope();
  249. let span;
  250. if (parentSpan) {
  251. // eslint-disable-next-line deprecation/deprecation
  252. span = parentSpan.startChild(ctx);
  253. } else {
  254. const { traceId, dsc, parentSpanId, sampled } = {
  255. ...isolationScope.getPropagationContext(),
  256. ...scope.getPropagationContext(),
  257. };
  258. // eslint-disable-next-line deprecation/deprecation
  259. span = hub$1.startTransaction({
  260. traceId,
  261. parentSpanId,
  262. parentSampled: sampled,
  263. ...ctx,
  264. metadata: {
  265. dynamicSamplingContext: dsc,
  266. // eslint-disable-next-line deprecation/deprecation
  267. ...ctx.metadata,
  268. },
  269. });
  270. }
  271. setCapturedScopesOnSpan(span, scope, isolationScope);
  272. return span;
  273. }
  274. /**
  275. * This converts StartSpanOptions to TransactionContext.
  276. * For the most part (for now) we accept the same options,
  277. * but some of them need to be transformed.
  278. *
  279. * Eventually the StartSpanOptions will be more aligned with OpenTelemetry.
  280. */
  281. function normalizeContext(context) {
  282. if (context.startTime) {
  283. const ctx = { ...context };
  284. ctx.startTimestamp = spanUtils.spanTimeInputToSeconds(context.startTime);
  285. delete ctx.startTime;
  286. return ctx;
  287. }
  288. return context;
  289. }
  290. const SCOPE_ON_START_SPAN_FIELD = '_sentryScope';
  291. const ISOLATION_SCOPE_ON_START_SPAN_FIELD = '_sentryIsolationScope';
  292. function setCapturedScopesOnSpan(span, scope, isolationScope) {
  293. if (span) {
  294. utils.addNonEnumerableProperty(span, ISOLATION_SCOPE_ON_START_SPAN_FIELD, isolationScope);
  295. utils.addNonEnumerableProperty(span, SCOPE_ON_START_SPAN_FIELD, scope);
  296. }
  297. }
  298. /**
  299. * Grabs the scope and isolation scope off a span that were active when the span was started.
  300. */
  301. function getCapturedScopesOnSpan(span) {
  302. return {
  303. scope: (span )[SCOPE_ON_START_SPAN_FIELD],
  304. isolationScope: (span )[ISOLATION_SCOPE_ON_START_SPAN_FIELD],
  305. };
  306. }
  307. exports.continueTrace = continueTrace;
  308. exports.getActiveSpan = getActiveSpan;
  309. exports.getCapturedScopesOnSpan = getCapturedScopesOnSpan;
  310. exports.startActiveSpan = startActiveSpan;
  311. exports.startInactiveSpan = startInactiveSpan;
  312. exports.startSpan = startSpan;
  313. exports.startSpanManual = startSpanManual;
  314. exports.trace = trace;
  315. //# sourceMappingURL=trace.js.map