traceSearchTokenizer.tsx 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. import type {
  2. NoDataNode,
  3. ParentAutogroupNode,
  4. SiblingAutogroupNode,
  5. TraceTree,
  6. TraceTreeNode,
  7. } from '../traceModels/traceTree';
  8. import grammar from './traceSearch.pegjs';
  9. interface SearchToken {
  10. key: string;
  11. type: 'Token';
  12. value: string | number;
  13. negated?: boolean;
  14. operator?: 'gt' | 'ge' | 'lt' | 'le' | 'eq';
  15. }
  16. type Token = SearchToken;
  17. // typeof can return one of the following string values - we ignore BigInt, Symbol as there
  18. // is no practical case for them + they are not supported by JSON.
  19. // object (special handling for arrays), number, string, boolean, undefined, null
  20. type Type = 'object' | 'number' | 'string' | 'boolean' | 'undefined' | 'null';
  21. // @ts-expect-error we ignore some keys on purpose, the TS error makes it helpful
  22. // for seeing exactly which ones we are ignoring for when we want to add support for them
  23. const SPAN_KEYS: Record<keyof TraceTree.Span, Type> = {
  24. hash: 'string',
  25. span_id: 'string',
  26. start_timestamp: 'number',
  27. timestamp: 'number',
  28. trace_id: 'string',
  29. description: 'string',
  30. exclusive_time: 'number',
  31. op: 'string',
  32. origin: 'string',
  33. parent_span_id: 'string',
  34. same_process_as_parent: 'boolean',
  35. // TODO Jonas Badalic: The response for the avg duration metrics is now an object and can return
  36. // both the avg span_self time and the avg span duration. This will need to be handled differently.
  37. // This one will need to be flattened
  38. 'span.averageResults': 'object',
  39. status: 'string',
  40. // These are both records and will need to be handled differently
  41. sentry_tags: 'string',
  42. tags: 'string',
  43. };
  44. export function traceSearchTokenizer(input: string): Token[] {
  45. return grammar.parse(input);
  46. }
  47. export function traceSearchLexer(_input: string): string[] {
  48. throw new Error('Not implemented');
  49. }
  50. export function evaluateTokenForTraceNode(
  51. node:
  52. | TraceTreeNode<TraceTree.NodeValue>
  53. | ParentAutogroupNode
  54. | SiblingAutogroupNode
  55. | NoDataNode,
  56. token: Token
  57. ): boolean {
  58. const type = SPAN_KEYS[token.key];
  59. // @ts-expect-error ignore the lookup as the value will be dynamic
  60. const value = node.value[token.key];
  61. let match: undefined | boolean = undefined;
  62. if (token.value === undefined) {
  63. match = value === undefined;
  64. }
  65. if (token.value === null) {
  66. match = value === null;
  67. }
  68. // @TODO check for the distinction between obj and array here as L78
  69. // does not guarantee exact same primitive type in this case
  70. if (typeof value !== type && token.value !== null && token.value !== undefined) {
  71. // The two types are not the same.
  72. return false;
  73. }
  74. // prettier-ignore
  75. switch (type) {
  76. case 'string': {
  77. match = value === token.value || value.includes(token.value);
  78. break;
  79. }
  80. case 'number': {
  81. if (!token.operator) {
  82. match = value === token.value;
  83. break;
  84. }
  85. // prettier-ignore
  86. switch (token.operator) {
  87. case 'gt': match = value > token.value; break;
  88. case 'ge': match = value >= token.value; break;
  89. case 'lt': match = value < token.value; break;
  90. case 'le': match = value <= token.value; break;
  91. case 'eq': match = value === token.value; break;
  92. default: break;
  93. }
  94. break;
  95. }
  96. case 'boolean': {
  97. match = value === token.value;
  98. break;
  99. }
  100. case 'object': {
  101. return false;
  102. }
  103. default: break;
  104. }
  105. if (match === undefined) {
  106. return false;
  107. }
  108. return token.negated ? !match : match;
  109. }