DebugSection.tsx 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. import { css } from '@emotion/css';
  2. import cx from 'classnames';
  3. import React, { useState } from 'react';
  4. import { ArrayVector, Field, FieldType, LinkModel } from '@grafana/data';
  5. import { LegacyForms } from '@grafana/ui';
  6. import { getFieldLinksForExplore } from '../../../../features/explore/utils/links';
  7. import { DerivedFieldConfig } from '../types';
  8. const { FormField } = LegacyForms;
  9. type Props = {
  10. derivedFields?: DerivedFieldConfig[];
  11. className?: string;
  12. };
  13. export const DebugSection = (props: Props) => {
  14. const { derivedFields, className } = props;
  15. const [debugText, setDebugText] = useState('');
  16. let debugFields: DebugField[] = [];
  17. if (debugText && derivedFields) {
  18. debugFields = makeDebugFields(derivedFields, debugText);
  19. }
  20. return (
  21. <div className={className}>
  22. <FormField
  23. labelWidth={12}
  24. label={'Debug log message'}
  25. inputEl={
  26. <textarea
  27. placeholder={'Paste an example log line here to test the regular expressions of your derived fields'}
  28. className={cx(
  29. 'gf-form-input gf-form-textarea',
  30. css`
  31. width: 100%;
  32. `
  33. )}
  34. value={debugText}
  35. onChange={(event) => setDebugText(event.currentTarget.value)}
  36. />
  37. }
  38. />
  39. {!!debugFields.length && <DebugFields fields={debugFields} />}
  40. </div>
  41. );
  42. };
  43. type DebugFieldItemProps = {
  44. fields: DebugField[];
  45. };
  46. const DebugFields = ({ fields }: DebugFieldItemProps) => {
  47. return (
  48. <table className={'filter-table'}>
  49. <thead>
  50. <tr>
  51. <th>Name</th>
  52. <th>Value</th>
  53. <th>Url</th>
  54. </tr>
  55. </thead>
  56. <tbody>
  57. {fields.map((field) => {
  58. let value: any = field.value;
  59. if (field.error) {
  60. value = field.error.message;
  61. } else if (field.href) {
  62. value = <a href={field.href}>{value}</a>;
  63. }
  64. return (
  65. <tr key={`${field.name}=${field.value}`}>
  66. <td>{field.name}</td>
  67. <td>{value}</td>
  68. <td>{field.href ? <a href={field.href}>{field.href}</a> : ''}</td>
  69. </tr>
  70. );
  71. })}
  72. </tbody>
  73. </table>
  74. );
  75. };
  76. type DebugField = {
  77. name: string;
  78. error?: any;
  79. value?: string;
  80. href?: string;
  81. };
  82. function makeDebugFields(derivedFields: DerivedFieldConfig[], debugText: string): DebugField[] {
  83. return derivedFields
  84. .filter((field) => field.name && field.matcherRegex)
  85. .map((field) => {
  86. try {
  87. const testMatch = debugText.match(field.matcherRegex);
  88. const value = testMatch && testMatch[1];
  89. let link: LinkModel<Field> | null = null;
  90. if (field.url && value) {
  91. link = getFieldLinksForExplore({
  92. field: {
  93. name: '',
  94. type: FieldType.string,
  95. values: new ArrayVector([value]),
  96. config: {
  97. links: [{ title: '', url: field.url }],
  98. },
  99. },
  100. rowIndex: 0,
  101. range: {} as any,
  102. })[0];
  103. }
  104. return {
  105. name: field.name,
  106. value: value || '<no match>',
  107. href: link && link.href,
  108. } as DebugField;
  109. } catch (error) {
  110. return {
  111. name: field.name,
  112. error,
  113. } as DebugField;
  114. }
  115. });
  116. }