What a Suricata (eve.json) line looks like
The JSON sample below is fed verbatim into the engine to produce every parser on this page.
{"timestamp":"2026-07-03T14:22:15.123456+0300","event_type":"alert","src_ip":"203.0.113.66","src_port":44121,"dest_ip":"192.0.2.30","dest_port":8080,"proto":"TCP","alert":{"signature":"ET EXPLOIT Apache Log4j RCE Attempt","category":"Attempted Administrator Privilege Gain","severity":1}}
{"timestamp":"2026-07-03T14:22:49.774112+0300","event_type":"alert","src_ip":"198.51.100.23","src_port":51002,"dest_ip":"192.0.2.31","dest_port":445,"proto":"TCP","alert":{"signature":"ET SCAN Behavioral Unusual Port 445","category":"Detection of a Network Scan","severity":2}} Detected fields
The engine classified this sample as json and consolidated 10 fields across 2 lines. Fields marked literal were identical on every sample line, so they are baked into the pattern as anchors rather than captured.
- timestamp : timestamp
- event_type : severity · literal
- src_ip : ipv4
- src_port : port
- dest_ip : ipv4
- dest_port : port
- proto : quoted_string · literal
- alert_signature : quoted_string
- alert_category : quoted_string
- alert_severity : number
Regex (named capture groups)
# sample: {"timestamp":"2026-07-03T14:22:15.123456+0300","event_type":"alert","src_ip":"203.0.113.66","src_port":44121,"dest_ip":"192.0.2.30","dest_port":8080,"proto":"TCP","alert":{"signature":"ET EXPLOIT Apache Log4j RCE Attempt","category":"Attempted Administrator Privilege Gain","severity":1}}
# groups: timestamp=2026-07-03T14:22:15.123456+0300, src_ip=203.0.113.66, src_port=44121, dest_ip=192.0.2.30, dest_port=8080, alert_signature=ET EXPLOIT Apache Log4j RCE Attempt, alert_category=Attempted Administrator Privilege Gain, alert_severity=1
^(?=.*?"timestamp":"(?<timestamp>[^"]*)")(?=.*?"event_type":"alert")(?=.*?"src_ip":"(?<src_ip>[^"]*)")(?=.*?"src_port":(?<src_port>\d{1,5}))(?=.*?"dest_ip":"(?<dest_ip>[^"]*)")(?=.*?"dest_port":(?<dest_port>\d{1,5}))(?=.*?"proto":"TCP")(?=.*?"signature":"(?<alert_signature>[^"]*)")(?=.*?"category":"(?<alert_category>[^"]*)")(?=.*?"severity":(?<alert_severity>-?\d+(?:\.\d+)?)).*$ - note input is JSON — use a JSON parser (jq, Logstash json filter, …) instead of a regex where possible
- note a single linear template could not reproduce every input line — fields are captured with order-independent lookaheads instead
Grok pattern (Logstash / Elastic)
# custom patterns
SURICATA_NOTDQUOTE [^"]*
\{"timestamp":"%{TIMESTAMP_ISO8601:timestamp}","event_type":"alert","src_ip":"%{IPV4:src_ip}","src_port":%{INT:src_port},"dest_ip":"%{IPV4:dest_ip}","dest_port":%{INT:dest_port},"proto":"TCP","alert":\{"signature":"%{SURICATA_NOTDQUOTE:alert_signature}","category":"%{SURICATA_NOTDQUOTE:alert_category}","severity":%{NUMBER:alert_severity} - note json input — consider the Logstash json codec/filter instead of grok
- note constant field "event_type" embedded as literal anchor "alert" (varying=false)
- note constant field "proto" embedded as literal anchor "TCP" (varying=false)
- note custom patterns emitted — save the '# custom patterns' block to a file in your patterns_dir
Wazuh decoder (OS_Regex XML)
<!--
Generated by LogForge - Wazuh decoder (OS_Regex dialect, not PCRE)
sample: {"timestamp":"2026-07-03T14:22:15.123456+0300","event_type":"alert","src_ip":"203.0.113.66","src_port":44121,"dest_ip":"192.0.2.30","dest_port":8080,"proto":"TC
test with: /var/ossec/bin/wazuh-logtest
-->
<decoder name="suricata-json">
<prematch>^{</prematch>
<plugin_decoder>JSON_Decoder</plugin_decoder>
</decoder>
- note JSON input: emitted a JSON_Decoder plugin decoder — Wazuh extracts every key automatically as dynamic fields (nested keys become dotted names)
- note field names above are what the other LogForge generators use; JSON_Decoder will use the raw JSON keys instead
- note decoder order and prematch specificity may need site-specific tuning (other decoders in your ruleset can shadow these) — validate with /var/ossec/bin/wazuh-logtest
rsyslog template / liblognorm rulebase
version=2
# suricata — liblognorm v2 rulebase (generated by LogForge)
# Usage with rsyslog (mmnormalize runs liblognorm):
# module(load="mmnormalize")
# action(type="mmnormalize" rulebase="/etc/rsyslog.d/suricata.rb" useRawMsg="on")
# Literal "%" is escaped as "%%"; raw tabs are written as \x09.
rule=suricata:{"timestamp":"%timestamp:date-rfc5424%","event_type":"alert","src_ip":"%src_ip:ipv4%","src_port":%src_port:number%,"dest_ip":"%dest_ip:ipv4%","dest_port":%dest_port:number%,"proto":"TCP","alert":{"signature":"%alert_signature:char-to{"extradata":"\""}%","category":"%alert_category:char-to{"extradata":"\""}%","severity":%alert_severity:number%}}
- note json structure: rsyslog mmjsonparse handles CEE/JSON natively — consider action(type="mmjsonparse") instead of this rulebase
- note trailing literal "}}" reconstructed from line 1
- note chosen parser types: timestamp=date-rfc5424, src_ip=ipv4, src_port=number, dest_ip=ipv4, dest_port=number, alert_signature=char-to("), alert_category=char-to("), alert_severity=number
FAQ
- What is event_type in Suricata EVE JSON and why branch on it?
- event_type is the discriminator that names the record kind — alert, dns, http, tls, flow, fileinfo, and others. The meaningful nested object differs per type (an alert has an alert object, a dns record has a dns object), so you read event_type first and then reach into the matching sub-object. Fields from one type do not exist on another.
- Why is Suricata alert.severity 1 more serious than 3?
- Suricata inverts the scale: alert.severity 1 is the HIGHEST priority and larger numbers are lower priority (3 is routine). This catches people who assume bigger means worse. Triage and paging logic must treat severity 1 as most urgent.
- How do I correlate related Suricata events?
- Group by flow_id. Suricata assigns one flow_id to a connection, and the alert, http, tls, dns, and flow records for that same connection all carry it. Joining on flow_id lets you enrich an alert with the corresponding http.url, tls.sni, or dns.rrname to understand what actually happened.
- Which fields identify the rule that fired?
- On an alert record: alert.signature (the human-readable rule name), alert.signature_id (the numeric sid), alert.category (the classtype), plus alert.gid and alert.rev. Together with alert.severity these tell you exactly which rule triggered, how it is classified, and how urgent it is.
Try it on your own Suricata (eve.json) lines
Paste a few real lines, review the detected fields, and copy whichever format your stack needs. Free, no account, nothing uploaded.
Open this sample in LogForge →