sampling.js 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. import { logger, isNaN } from '@sentry/utils';
  2. import { DEBUG_BUILD } from '../debug-build.js';
  3. import { SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE } from '../semanticAttributes.js';
  4. import { hasTracingEnabled } from '../utils/hasTracingEnabled.js';
  5. import { spanToJSON } from '../utils/spanUtils.js';
  6. /**
  7. * Makes a sampling decision for the given transaction and stores it on the transaction.
  8. *
  9. * Called every time a transaction is created. Only transactions which emerge with a `sampled` value of `true` will be
  10. * sent to Sentry.
  11. *
  12. * This method muttes the given `transaction` and will set the `sampled` value on it.
  13. * It returns the same transaction, for convenience.
  14. */
  15. function sampleTransaction(
  16. transaction,
  17. options,
  18. samplingContext,
  19. ) {
  20. // nothing to do if tracing is not enabled
  21. if (!hasTracingEnabled(options)) {
  22. // eslint-disable-next-line deprecation/deprecation
  23. transaction.sampled = false;
  24. return transaction;
  25. }
  26. // if the user has forced a sampling decision by passing a `sampled` value in their transaction context, go with that
  27. // eslint-disable-next-line deprecation/deprecation
  28. if (transaction.sampled !== undefined) {
  29. // eslint-disable-next-line deprecation/deprecation
  30. transaction.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE, Number(transaction.sampled));
  31. return transaction;
  32. }
  33. // we would have bailed already if neither `tracesSampler` nor `tracesSampleRate` nor `enableTracing` were defined, so one of these should
  34. // work; prefer the hook if so
  35. let sampleRate;
  36. if (typeof options.tracesSampler === 'function') {
  37. sampleRate = options.tracesSampler(samplingContext);
  38. transaction.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE, Number(sampleRate));
  39. } else if (samplingContext.parentSampled !== undefined) {
  40. sampleRate = samplingContext.parentSampled;
  41. } else if (typeof options.tracesSampleRate !== 'undefined') {
  42. sampleRate = options.tracesSampleRate;
  43. transaction.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE, Number(sampleRate));
  44. } else {
  45. // When `enableTracing === true`, we use a sample rate of 100%
  46. sampleRate = 1;
  47. transaction.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE, sampleRate);
  48. }
  49. // Since this is coming from the user (or from a function provided by the user), who knows what we might get. (The
  50. // only valid values are booleans or numbers between 0 and 1.)
  51. if (!isValidSampleRate(sampleRate)) {
  52. DEBUG_BUILD && logger.warn('[Tracing] Discarding transaction because of invalid sample rate.');
  53. // eslint-disable-next-line deprecation/deprecation
  54. transaction.sampled = false;
  55. return transaction;
  56. }
  57. // if the function returned 0 (or false), or if `tracesSampleRate` is 0, it's a sign the transaction should be dropped
  58. if (!sampleRate) {
  59. DEBUG_BUILD &&
  60. logger.log(
  61. `[Tracing] Discarding transaction because ${
  62. typeof options.tracesSampler === 'function'
  63. ? 'tracesSampler returned 0 or false'
  64. : 'a negative sampling decision was inherited or tracesSampleRate is set to 0'
  65. }`,
  66. );
  67. // eslint-disable-next-line deprecation/deprecation
  68. transaction.sampled = false;
  69. return transaction;
  70. }
  71. // Now we roll the dice. Math.random is inclusive of 0, but not of 1, so strict < is safe here. In case sampleRate is
  72. // a boolean, the < comparison will cause it to be automatically cast to 1 if it's true and 0 if it's false.
  73. // eslint-disable-next-line deprecation/deprecation
  74. transaction.sampled = Math.random() < (sampleRate );
  75. // if we're not going to keep it, we're done
  76. // eslint-disable-next-line deprecation/deprecation
  77. if (!transaction.sampled) {
  78. DEBUG_BUILD &&
  79. logger.log(
  80. `[Tracing] Discarding transaction because it's not included in the random sample (sampling rate = ${Number(
  81. sampleRate,
  82. )})`,
  83. );
  84. return transaction;
  85. }
  86. DEBUG_BUILD &&
  87. // eslint-disable-next-line deprecation/deprecation
  88. logger.log(`[Tracing] starting ${transaction.op} transaction - ${spanToJSON(transaction).description}`);
  89. return transaction;
  90. }
  91. /**
  92. * Checks the given sample rate to make sure it is valid type and value (a boolean, or a number between 0 and 1).
  93. */
  94. function isValidSampleRate(rate) {
  95. // we need to check NaN explicitly because it's of type 'number' and therefore wouldn't get caught by this typecheck
  96. // eslint-disable-next-line @typescript-eslint/no-explicit-any
  97. if (isNaN(rate) || !(typeof rate === 'number' || typeof rate === 'boolean')) {
  98. DEBUG_BUILD &&
  99. logger.warn(
  100. `[Tracing] Given sample rate is invalid. Sample rate must be a boolean or a number between 0 and 1. Got ${JSON.stringify(
  101. rate,
  102. )} of type ${JSON.stringify(typeof rate)}.`,
  103. );
  104. return false;
  105. }
  106. // in case sampleRate is a boolean, it will get automatically cast to 1 if it's true and 0 if it's false
  107. if (rate < 0 || rate > 1) {
  108. DEBUG_BUILD &&
  109. logger.warn(`[Tracing] Given sample rate is invalid. Sample rate must be between 0 and 1. Got ${rate}.`);
  110. return false;
  111. }
  112. return true;
  113. }
  114. export { sampleTransaction };
  115. //# sourceMappingURL=sampling.js.map