utils.ts 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. import {RawSpanType} from 'sentry/components/events/interfaces/spans/types';
  2. import {EntryType, EventOrGroupType, EventTransaction} from 'sentry/types';
  3. export enum ProblemSpan {
  4. PARENT = 'parent',
  5. OFFENDER = 'offender',
  6. }
  7. export const EXAMPLE_TRANSACTION_TITLE = '/api/0/transaction-test-endpoint/';
  8. type AddSpanOpts = {
  9. endTimestamp: number;
  10. startTimestamp: number;
  11. childOpts?: AddSpanOpts[];
  12. description?: string;
  13. op?: string;
  14. problemSpan?: ProblemSpan;
  15. status?: string;
  16. };
  17. export class TransactionEventBuilder {
  18. TRACE_ID = '8cbbc19c0f54447ab702f00263262726';
  19. ROOT_SPAN_ID = '0000000000000000';
  20. #event: EventTransaction;
  21. #spans: RawSpanType[] = [];
  22. constructor(id?: string, title?: string) {
  23. this.#event = {
  24. id: id ?? 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
  25. eventID: id ?? 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
  26. title: title ?? EXAMPLE_TRANSACTION_TITLE,
  27. type: EventOrGroupType.TRANSACTION,
  28. startTimestamp: 0,
  29. endTimestamp: 0,
  30. contexts: {
  31. trace: {
  32. trace_id: this.TRACE_ID,
  33. span_id: this.ROOT_SPAN_ID,
  34. op: 'pageload',
  35. status: 'ok',
  36. type: 'trace',
  37. },
  38. },
  39. entries: [
  40. {
  41. data: this.#spans,
  42. type: EntryType.SPANS,
  43. },
  44. ],
  45. perfProblem: {
  46. causeSpanIds: [],
  47. offenderSpanIds: [],
  48. parentSpanIds: [],
  49. },
  50. // For the purpose of mock data, we don't care as much about the properties below.
  51. // They're here to satisfy the type constraints, but in the future if we need actual values here
  52. // for testing purposes, we can add methods on the builder to set them.
  53. crashFile: null,
  54. culprit: '',
  55. dateReceived: '',
  56. dist: null,
  57. errors: [],
  58. fingerprints: [],
  59. location: null,
  60. message: '',
  61. metadata: {
  62. current_level: undefined,
  63. current_tree_label: undefined,
  64. directive: undefined,
  65. display_title_with_tree_label: undefined,
  66. filename: undefined,
  67. finest_tree_label: undefined,
  68. function: undefined,
  69. message: undefined,
  70. origin: undefined,
  71. stripped_crash: undefined,
  72. title: undefined,
  73. type: undefined,
  74. uri: undefined,
  75. value: undefined,
  76. },
  77. projectID: '',
  78. size: 0,
  79. tags: [],
  80. user: null,
  81. };
  82. }
  83. addSpan(mSpan: MockSpan, parentSpanId?: string) {
  84. // Convert the num of spans to a hex string to get its ID
  85. const spanId = (this.#spans.length + 1).toString(16).padStart(16, '0');
  86. const {span} = mSpan;
  87. span.span_id = spanId;
  88. span.trace_id = this.TRACE_ID;
  89. span.parent_span_id = parentSpanId ?? this.ROOT_SPAN_ID;
  90. this.#event.entries[0].data.push(span);
  91. switch (mSpan.problemSpan) {
  92. case ProblemSpan.PARENT:
  93. this.#event.perfProblem?.parentSpanIds.push(spanId);
  94. break;
  95. case ProblemSpan.OFFENDER:
  96. this.#event.perfProblem?.offenderSpanIds.push(spanId);
  97. break;
  98. default:
  99. break;
  100. }
  101. if (span.timestamp > this.#event.endTimestamp) {
  102. this.#event.endTimestamp = span.timestamp;
  103. }
  104. mSpan.children.forEach(child => this.addSpan(child, spanId));
  105. }
  106. getEvent() {
  107. return this.#event;
  108. }
  109. }
  110. /**
  111. * A MockSpan object to be used for testing. This object is intended to be used in tandem with `TransactionEventBuilder`
  112. */
  113. export class MockSpan {
  114. span: RawSpanType;
  115. children: MockSpan[] = [];
  116. problemSpan: ProblemSpan | undefined;
  117. /**
  118. *
  119. * @param opts.startTimestamp
  120. * @param opts.endTimestamp
  121. * @param opts.op The operation of the span
  122. * @param opts.description The description of the span
  123. * @param opts.status Optional span specific status, defaults to 'ok'
  124. * @param opts.problemSpan If this span should be part of a performance problem, indicates the type of problem span (i.e ProblemSpan.OFFENDER, ProblemSpan.PARENT)
  125. * @param opts.parentSpanId When provided, will explicitly set this span's parent ID. If you are creating nested spans via `childOpts`, this will be handled automatically and you do not need to provide an ID.
  126. * Defaults to the root span's ID.
  127. * @param opts.childOpts An array containing options for direct children of the current span. Will create direct child spans for each set of options provided
  128. */
  129. constructor(opts: AddSpanOpts) {
  130. const {startTimestamp, endTimestamp, op, description, status, problemSpan} = opts;
  131. this.span = {
  132. start_timestamp: startTimestamp,
  133. timestamp: endTimestamp,
  134. op,
  135. description,
  136. status: status ?? 'ok',
  137. data: {},
  138. // These values are automatically assigned by the TransactionEventBuilder when the spans are added
  139. span_id: '',
  140. trace_id: '',
  141. parent_span_id: '',
  142. };
  143. this.problemSpan = problemSpan;
  144. }
  145. /**
  146. *
  147. * @param opts.numSpans If provided, will create the same span numSpan times
  148. */
  149. addChild(opts: AddSpanOpts, numSpans = 1) {
  150. const {startTimestamp, endTimestamp, op, description, status, problemSpan} = opts;
  151. for (let i = 0; i < numSpans; i++) {
  152. const span = new MockSpan({
  153. startTimestamp,
  154. endTimestamp,
  155. op,
  156. description,
  157. status,
  158. problemSpan,
  159. });
  160. this.children.push(span);
  161. }
  162. return this;
  163. }
  164. }