src/platform/packages/shared/kbn-grok-ui/README.md
Tools for parsing/converting Grok expressions (into Oniguruma/JS Regex) and UI components for working with Grok patterns.
This package provides two ways to work with Grok patterns:
GrokCollection and DraftGrokExpression instances for lower-level controlThe context-based API abstracts away the complexity of managing DraftGrokExpression instances. You work with plain string[] arrays, and the package handles the lifecycle management internally.
Wrap your application with the GrokCollectionProvider:
import { GrokCollection, GrokCollectionProvider } from '@kbn/grok-ui';
const grokCollection = new GrokCollection();
// Collection setup will happen automatically
function App() {
return (
<GrokCollectionProvider grokCollection={grokCollection}>
<YourComponents />
</GrokCollectionProvider>
);
}
Use the useGrokExpressions hook to convert plain strings to managed expression instances:
import { useGrokExpressions } from '@kbn/grok-ui';
function GrokEditor() {
const [patterns, setPatterns] = useState(['%{TIMESTAMP} %{LOGLEVEL}']);
// Automatically converts strings to DraftGrokExpression instances
const expressions = useGrokExpressions(patterns);
// expressions lifecycle is managed automatically - no cleanup needed!
}
For rendering Grok pattern highlights in your UI, use the provider + context pattern:
import {
GrokCollectionProvider,
GrokExpressionsProvider,
GrokSampleWithContext
} from '@kbn/grok-ui';
function SampleHighlighter() {
const patterns = ['%{TIMESTAMP:timestamp} %{LOGLEVEL:level}'];
const sampleLog = '2024-01-27 10:30:00 INFO Application started';
return (
<GrokCollectionProvider grokCollection={collection}>
<GrokExpressionsProvider patterns={patterns}>
<GrokSampleWithContext sample={sampleLog} />
</GrokExpressionsProvider>
</GrokCollectionProvider>
);
}
GrokSampleWithContextRead-only sample highlighting (optimized for data grids):
<GrokExpressionsProvider patterns={patterns}>
<GrokSampleWithContext sample="2024-01-27 192.168.1.1 GET /api" />
</GrokExpressionsProvider>
GrokSampleInputWithContextEditable sample input with Monaco editor:
<GrokExpressionsProvider patterns={patterns}>
<GrokSampleInputWithContext sample={editableSample} />
</GrokExpressionsProvider>
Forms can work directly with string[] arrays:
interface GrokFormData {
patterns: string[]; // ← Plain strings!
from: string;
}
function GrokProcessorForm() {
const { control, watch } = useForm<GrokFormData>({
defaultValues: {
patterns: [''],
from: 'message',
},
});
const patternStrings = watch('patterns');
// Convert to expressions for validation/preview
const expressions = useGrokExpressions(patternStrings);
// Form submits plain strings, no conversion needed!
}
useGrokCollection()Access the GrokCollection instance from context:
const { grokCollection, isLoading, error } = useGrokCollection();
useGrokExpressions(patterns: string[])Convert pattern strings to managed DraftGrokExpression instances:
const patterns = ['%{IP}', '%{TIMESTAMP}'];
const expressions = useGrokExpressions(patterns);
// Auto-managed lifecycle - created, updated, and destroyed automatically
useGrokExpressionsFromContext()Access expressions from the GrokExpressionsProvider:
const expressions = useGrokExpressionsFromContext();
For lower-level control, you can work directly with the models.
import { GrokCollection } from '@kbn/grok-ui';
const collection = new GrokCollection();
// Add pattern definitions
Object.entries(PATTERN_MAP).forEach(([key, value]) => {
collection.addPattern(key, String.raw`${value}`);
});
// Setup (resolves patterns)
await collection.setup();
import { DraftGrokExpression } from '@kbn/grok-ui';
const draftGrokExpression = new DraftGrokExpression(collection, initialPattern);
// Update the expression
draftGrokExpression.updateExpression(
String.raw`^\"(?<rid>[^\"]+)\" \| %{IPORHOST:clientip} \[%{HTTPDATE:timestamp}\]`
);
// Get the compiled regex
const regexp = draftGrokExpression.getRegex();
// Or parse samples directly
const parsed = draftGrokExpression.parse([
'"uRzbUwp5eZgAAAAaqIAAAAAa" | 5.3.2.1 [24/Feb/2013:13:40:51 +0100]',
'"URzbTwp5eZgAAAAWlbUAAAAV" | 4.3.2.7 [14/Feb/2013:13:40:47 +0100]',
]);
// Don't forget to clean up!
draftGrokExpression.destroy();
If you're not using contexts, components require props:
The Expression component accepts a simple string pattern and internally manages a DraftGrokExpression instance:
import { Expression } from '@kbn/grok-ui';
<Expression
pattern="%{IP:client} %{WORD:method}"
grokCollection={grokCollection}
onChange={(newPattern) => console.log(newPattern)}
/>
import { Sample } from '@kbn/grok-ui';
<Sample
grokCollection={grokCollection}
draftGrokExpressions={[expression1, expression2]}
sample="log line to highlight"
/>
import { SampleInput } from '@kbn/grok-ui';
<SampleInput
grokCollection={grokCollection}
draftGrokExpressions={expressions}
sample={sample}
onChangeSample={setSample}
/>
You can update custom patterns dynamically:
// With context
const { grokCollection } = useGrokCollection();
grokCollection.setCustomPatterns({
MY_CUSTOM_PATTERN: '\\d{3}-\\d{4}',
ANOTHER_PATTERN: '[A-Z]+\\d+',
});
// Direct
collection.setCustomPatterns({ /* ... */ });
GrokCollectionProvider
└─> Provides GrokCollection instance
└─> Handles setup and lifecycle
GrokExpressionsProvider
└─> Converts string[] → DraftGrokExpression[]
└─> Manages expression lifecycle automatically
Components
└─> Read from contexts or accept props directly
✅ Simpler API: Work with plain string[] instead of DraftGrokExpression[]
✅ Automatic Lifecycle: No manual .destroy() calls needed
✅ Better Performance: Single management point for all expressions
✅ Less Boilerplate: No need to create/manage instances manually
✅ Type Safety: TypeScript ensures correct usage
See the Streams processing UI for a complete implementation example at:
x-pack/platform/plugins/shared/streams_app/public/components/data_management/stream_detail_enrichment/