tracing.ts 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. /**
  2. * Get non overlapping duration of the ranges as they can overlap or have gaps.
  3. */
  4. import { FieldType, MutableDataFrame, NodeGraphDataFrameFieldNames as Fields } from '@grafana/data';
  5. export function getNonOverlappingDuration(ranges: Array<[number, number]>): number {
  6. ranges.sort((a, b) => a[0] - b[0]);
  7. const mergedRanges = ranges.reduce((acc, range) => {
  8. if (!acc.length) {
  9. return [range];
  10. }
  11. const tail = acc.slice(-1)[0];
  12. const [prevStart, prevEnd] = tail;
  13. const [start, end] = range;
  14. if (end < prevEnd) {
  15. // In this case the range is completely inside the prev range so we can just ignore it.
  16. return acc;
  17. }
  18. if (start > prevEnd) {
  19. // There is no overlap so we can just add it to stack
  20. return [...acc, range];
  21. }
  22. // We know there is overlap and current range ends later than previous so we can just extend the range
  23. return [...acc.slice(0, -1), [prevStart, end]] as Array<[number, number]>;
  24. }, [] as Array<[number, number]>);
  25. return mergedRanges.reduce((acc, range) => {
  26. return acc + (range[1] - range[0]);
  27. }, 0);
  28. }
  29. /**
  30. * Returns a map of the spans with children array for easier processing. It will also contain empty spans in case
  31. * span is missing but other spans are it's children. This is more generic because it needs to allow iterating over
  32. * both arrays and dataframe views.
  33. */
  34. export function makeSpanMap<T>(getSpan: (index: number) => { span: T; id: string; parentIds: string[] } | undefined): {
  35. [id: string]: { span: T; children: string[] };
  36. } {
  37. const spanMap: { [id: string]: { span?: T; children: string[] } } = {};
  38. let span;
  39. for (let index = 0; (span = getSpan(index)), !!span; index++) {
  40. if (!spanMap[span.id]) {
  41. spanMap[span.id] = {
  42. span: span.span,
  43. children: [],
  44. };
  45. } else {
  46. spanMap[span.id].span = span.span;
  47. }
  48. for (const parentId of span.parentIds) {
  49. if (parentId) {
  50. if (!spanMap[parentId]) {
  51. spanMap[parentId] = {
  52. span: undefined,
  53. children: [span.id],
  54. };
  55. } else {
  56. spanMap[parentId].children.push(span.id);
  57. }
  58. }
  59. }
  60. }
  61. return spanMap as { [id: string]: { span: T; children: string[] } };
  62. }
  63. export function getStats(duration: number, traceDuration: number, selfDuration: number) {
  64. return {
  65. main: `${toFixedNoTrailingZeros(duration)}ms (${toFixedNoTrailingZeros((duration / traceDuration) * 100)}%)`,
  66. secondary: `${toFixedNoTrailingZeros(selfDuration)}ms (${toFixedNoTrailingZeros(
  67. (selfDuration / duration) * 100
  68. )}%)`,
  69. };
  70. }
  71. function toFixedNoTrailingZeros(n: number) {
  72. return parseFloat(n.toFixed(2));
  73. }
  74. /**
  75. * Create default frames used when returning data for node graph.
  76. */
  77. export function makeFrames() {
  78. const nodesFrame = new MutableDataFrame({
  79. fields: [
  80. { name: Fields.id, type: FieldType.string },
  81. { name: Fields.title, type: FieldType.string },
  82. { name: Fields.subTitle, type: FieldType.string },
  83. { name: Fields.mainStat, type: FieldType.string, config: { displayName: 'Total time (% of trace)' } },
  84. { name: Fields.secondaryStat, type: FieldType.string, config: { displayName: 'Self time (% of total)' } },
  85. {
  86. name: Fields.color,
  87. type: FieldType.number,
  88. config: { color: { mode: 'continuous-GrYlRd' }, displayName: 'Self time / Trace duration' },
  89. },
  90. ],
  91. meta: {
  92. preferredVisualisationType: 'nodeGraph',
  93. },
  94. });
  95. const edgesFrame = new MutableDataFrame({
  96. fields: [
  97. { name: Fields.id, type: FieldType.string },
  98. { name: Fields.target, type: FieldType.string },
  99. { name: Fields.source, type: FieldType.string },
  100. ],
  101. meta: {
  102. preferredVisualisationType: 'nodeGraph',
  103. },
  104. });
  105. return [nodesFrame, edgesFrame];
  106. }