ELK Stack — Grok Patterns
What Is Grok?
Grok is a pattern-matching syntax built on top of regular expressions. It ships with over 120 pre-built patterns for common log formats. Instead of writing raw regex, you compose readable patterns from named building blocks.
Grok is available in:
- Logstash —
grokfilter plugin - Elasticsearch —
grokingest processor - Kibana — Grok Debugger (Dev Tools)
Grok Syntax
The basic Grok syntax is:
%{PATTERN:field_name}
%{PATTERN:field_name:data_type}
| Component | Description |
|---|---|
PATTERN |
A named regex pattern (built-in or custom) |
field_name |
The field name to assign the matched value to |
data_type |
Optional type conversion — int, float, or boolean |
Examples:
%{IP:client_ip} → Matches an IP address, stores as "client_ip"
%{NUMBER:bytes:int} → Matches a number, converts to integer
%{WORD:http_method} → Matches a single word
%{GREEDYDATA:message} → Matches everything remaining
Built-In Grok Patterns
Grok ships with a rich library of pre-built patterns. Here are the most commonly used ones:
General Patterns
| Pattern | Matches | Example |
|---|---|---|
WORD |
A single word \b\w+\b |
GET, error, admin |
NUMBER |
Integer or decimal | 200, 3.14, -42 |
INT |
Integer only | 200, -42 |
DATA |
Non-greedy match .*? |
Anything (shortest match) |
GREEDYDATA |
Greedy match .* |
Anything (longest match) |
NOTSPACE |
Non-whitespace characters | 192.168.1.1, /api/users |
SPACE |
Whitespace | Spaces, tabs |
QS |
Quoted string | "GET /api HTTP/1.1" |
QUOTEDSTRING |
Same as QS | "some value" |
Network Patterns
| Pattern | Matches | Example |
|---|---|---|
IP |
IPv4 or IPv6 | 192.168.1.1, ::1 |
IPV4 |
IPv4 only | 10.0.0.1 |
IPV6 |
IPv6 only | fe80::1 |
HOSTNAME |
Hostname or IP | web01.example.com |
HOSTPORT |
Host with port | web01:8080 |
IPORHOST |
IP or hostname | 192.168.1.1 or web01 |
URI |
Full URI | https://example.com/path?q=1 |
URIPATH |
URI path portion | /api/v1/users |
Date/Time Patterns
| Pattern | Matches | Example |
|---|---|---|
TIMESTAMP_ISO8601 |
ISO 8601 timestamp | 2026-04-01T10:15:30+00:00 |
HTTPDATE |
Apache-style date | 01/Apr/2026:10:15:30 +0000 |
DATE_US |
US date | 04-01-2026, 04/01/2026 |
DATE_EU |
European date | 01-04-2026, 01.04.2026 |
TIME |
Time HH:MM:SS |
10:15:30 |
Composite Patterns (Log Formats)
| Pattern | Matches |
|---|---|
COMBINEDAPACHELOG |
Full Apache combined access log line |
COMMONAPACHELOG |
Apache common log format |
SYSLOGBASE |
Syslog priority, timestamp, host, process |
SYSLOG5424BASE |
RFC 5424 syslog header |
Using Grok in Logstash
Basic Grok Filter
filter {
grok {
match => {
"message" => "%{COMBINEDAPACHELOG}"
}
}
}
Multiple Match Patterns
When logs have different formats, provide multiple patterns. Logstash tries each pattern in order:
filter {
grok {
match => {
"message" => [
"%{COMBINEDAPACHELOG}",
"%{COMMONAPACHELOG}",
"%{SYSLOGBASE} %{GREEDYDATA:syslog_message}"
]
}
break_on_match => true
}
}
The break_on_match option (default: true) stops after the first successful match. Set it to false to apply all patterns.
Type Conversion
filter {
grok {
match => {
"message" => "%{IP:client_ip} - %{WORD:user} \[%{HTTPDATE:timestamp}\] \"%{WORD:method} %{URIPATH:request} HTTP/%{NUMBER:http_version}\" %{NUMBER:status:int} %{NUMBER:bytes:int}"
}
}
}
Tag on Failure
When no pattern matches, Logstash adds _grokparsefailure to the tags field. You can customize this:
filter {
grok {
match => {
"message" => "%{COMBINEDAPACHELOG}"
}
tag_on_failure => ["_grok_apache_fail"]
}
}
Using Grok in Elasticsearch Ingest Pipeline
PUT _ingest/pipeline/apache-access-log
{
"description": "Parse Apache access logs",
"processors": [
{
"grok": {
"field": "message",
"patterns": [
"%{COMBINEDAPACHELOG}"
]
}
},
{
"date": {
"field": "timestamp",
"formats": ["dd/MMM/yyyy:HH:mm:ss Z"],
"target_field": "@timestamp"
}
},
{
"convert": {
"field": "response",
"type": "integer"
}
},
{
"convert": {
"field": "bytes",
"type": "integer"
}
}
]
}
Test the pipeline:
POST _ingest/pipeline/apache-access-log/_simulate
{
"docs": [
{
"_source": {
"message": "192.168.1.50 - admin [01/Apr/2026:10:15:30 +0000] \"GET /api/users HTTP/1.1\" 200 1234 \"https://example.com/\" \"Mozilla/5.0\""
}
}
]
}
Example 1 — Parsing Apache Access Logs
Raw log:
192.168.1.50 - admin [01/Apr/2026:10:15:30 +0000] "GET /api/users HTTP/1.1" 200 1234 "https://example.com/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)"
Grok pattern:
%{COMBINEDAPACHELOG}
Or equivalently, the expanded form:
%{IPORHOST:clientip} %{USER:ident} %{USER:auth} \[%{HTTPDATE:timestamp}\] "%{WORD:verb} %{NOTSPACE:request} HTTP/%{NUMBER:httpversion}" %{NUMBER:response} (?:%{NUMBER:bytes}|-) %{QS:referrer} %{QS:agent}
Parsed output:
{
"clientip": "192.168.1.50",
"ident": "-",
"auth": "admin",
"timestamp": "01/Apr/2026:10:15:30 +0000",
"verb": "GET",
"request": "/api/users",
"httpversion": "1.1",
"response": "200",
"bytes": "1234",
"referrer": "\"https://example.com/\"",
"agent": "\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)\""
}
Example 2 — Parsing Syslog
Raw log:
Apr 1 10:15:30 web01 sshd[12345]: Accepted publickey for admin from 10.0.0.5 port 52413 ssh2
Grok pattern:
%{SYSLOGTIMESTAMP:syslog_timestamp} %{SYSLOGHOST:hostname} %{DATA:process}\[%{POSINT:pid:int}\]: %{GREEDYDATA:syslog_message}
Logstash config:
filter {
grok {
match => {
"message" => "%{SYSLOGTIMESTAMP:syslog_timestamp} %{SYSLOGHOST:hostname} %{DATA:process}\[%{POSINT:pid:int}\]: %{GREEDYDATA:syslog_message}"
}
}
}
Parsed output:
{
"syslog_timestamp": "Apr 1 10:15:30",
"hostname": "web01",
"process": "sshd",
"pid": 12345,
"syslog_message": "Accepted publickey for admin from 10.0.0.5 port 52413 ssh2"
}
Example 3 — Parsing Custom Application Logs
Raw log:
2026-04-01 10:15:30.456 [main] ERROR com.example.UserService - Failed to fetch user id=42, reason=timeout, duration=5023ms
Grok pattern:
%{TIMESTAMP_ISO8601:timestamp} \[%{DATA:thread}\] %{LOGLEVEL:level} %{NOTSPACE:logger} - %{GREEDYDATA:log_message}
Logstash config:
filter {
grok {
match => {
"message" => "%{TIMESTAMP_ISO8601:timestamp} \[%{DATA:thread}\] %{LOGLEVEL:level} %{NOTSPACE:logger} - %{GREEDYDATA:log_message}"
}
}
# Further parse the log message for key=value pairs
kv {
source => "log_message"
field_split => ", "
value_split => "="
target => "parsed"
}
}
Parsed output:
{
"timestamp": "2026-04-01 10:15:30.456",
"thread": "main",
"level": "ERROR",
"logger": "com.example.UserService",
"log_message": "Failed to fetch user id=42, reason=timeout, duration=5023ms",
"parsed": {
"id": "42",
"reason": "timeout",
"duration": "5023ms"
}
}
Grok Debugger
Kibana Grok Debugger
Kibana includes a built-in Grok Debugger under Dev Tools → Grok Debugger:
- Open Kibana → Management → Dev Tools
- Click Grok Debugger tab
- Paste your sample log message
- Enter your Grok pattern
- Click Simulate to see parsed output
Online Grok Debugger Tools
- Grok Constructor: https://grokconstructor.appspot.com/
- Grok Debugger (Heroku): https://grokdebugger.com/
These tools let you test Grok patterns without a running Logstash or Elasticsearch instance. They are invaluable when building complex patterns.
Pattern Directory
Logstash loads patterns from the default patterns directory. You can add custom patterns using the patterns_dir option:
filter {
grok {
patterns_dir => ["/etc/logstash/patterns"]
match => {
"message" => "%{MY_CUSTOM_PATTERN:parsed}"
}
}
}
Pattern files are plain text, one pattern per line:
MY_CUSTOM_PATTERN %{TIMESTAMP_ISO8601:timestamp} %{LOGLEVEL:level} %{GREEDYDATA:message}
Performance Tips
| Tip | Description |
|---|---|
| Anchor patterns | Use ^ and $ to avoid backtracking |
| Avoid GREEDYDATA at the start | Greedy patterns at the start cause excessive backtracking |
| Use COMBINEDAPACHELOG | Pre-built patterns are optimized |
| Limit match patterns | Fewer patterns = faster matching |
| Consider dissect first | For delimiter-based logs, dissect is 5-10x faster |
| Use break_on_match | Stop after first successful pattern match |
Quick Reference
# Grok syntax
%{PATTERN:field_name}
%{PATTERN:field_name:data_type} # int, float, boolean
# Common patterns
%{IP:client_ip} # IP address
%{WORD:method} # Single word
%{NUMBER:status:int} # Number → integer
%{TIMESTAMP_ISO8601:ts} # ISO timestamp
%{COMBINEDAPACHELOG} # Full Apache log
%{GREEDYDATA:msg} # Match everything
# Logstash grok filter
filter {
grok {
match => { "message" => "PATTERN" }
break_on_match => true
tag_on_failure => ["_grokparsefailure"]
patterns_dir => ["/etc/logstash/patterns"]
}
}
# ES ingest grok processor
{
"grok": {
"field": "message",
"patterns": ["PATTERN"]
}
}
Previous: Log Parsing ← · Next: Custom Grok Patterns →