Parser Example
Parser Example: WAF Access Log (JSON Format)
Parser Example: WAF Access Log (JSON Format)
Input Log Sample
{"@timestamp":"2026-03-16T07:16:57.278Z","@version":"1","agent":{"ephemeral_id":"28133908-e6ec-4150-b5d0-ee46f470af1e","id":"ea9393e8-9c27-4571-a61b-1fc779b742a4","name":"waf-hn-main","type":"filebeat","version":"8.9.0"},"body_bytes_sent":"183891","ecs":{"version":"8.0.0"},"fields":{"env":"production","log_type":"waf_access_log_v2"},"headers":{},"host":{"name":"waf-hn-main"},"host_header":"careerviet.vn","http_referer":"https://careerviet.vn/vi/tim-viec-lam/ky-su-qs-du-an-xay-dung.35C65B52.html","http_user_agent":"Mozilla/5.0 (iPad; CPU OS 26_3_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/145.0.7632.108 Mobile/15E148 Safari/604.1","http_x_forwarded_for":"-","input":{"type":"log"},"log":{"file":{"path":"/log/access.log"},"offset":9631460125},"message":"171.224.178.18 - - [16/Mar/2026:07:16:57 +0000] \"GET /vi/employers?_rsc=1vs0z HTTP/1.1\" 200 183891 \"https://careerviet.vn/vi/tim-viec-lam/ky-su-qs-du-an-xay-dung.35C65B52.html\" \"Mozilla/5.0 (iPad; CPU OS 26_3_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/145.0.7632.108 Mobile/15E148 Safari/604.1\" \"-\" \"careerviet.vn\" sn=\"careerviet.vn\" rt=1.389 ua=\"222.255.236.231:443\" us=\"200\" ut=\"1.390\" ul=\"183913\" cs=- rid=cfd30872ab24f8fbaf4278d5d47690dc","message_key":null,"raw_data":"171.224.178.18 - - [16/Mar/2026:07:16:57 +0000] \"GET /vi/employers?_rsc=1vs0z HTTP/1.1\" 200 183891 \"https://careerviet.vn/vi/tim-viec-lam/ky-su-qs-du-an-xay-dung.35C65B52.html\" \"Mozilla/5.0 (iPad; CPU OS 26_3_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/145.0.7632.108 Mobile/15E148 Safari/604.1\" \"-\" \"careerviet.vn\" sn=\"careerviet.vn\" rt=1.389 ua=\"222.255.236.231:443\" us=\"200\" ut=\"1.390\" ul=\"183913\" cs=- rid=cfd30872ab24f8fbaf4278d5d47690dc","remote_addr":"171.224.178.18","remote_user":"-","request":"GET /vi/employers?_rsc=1vs0z HTTP/1.1","request_id":"cfd30872ab24f8fbaf4278d5d47690dc","request_time":"1.389","server_name":"careerviet.vn","status":"200","tags":["beats_input_codec_plain_applied"],"time_iso":"2026-03-16 07:16:57.278","timestamp":"2026-03-16T07:17:00.124Z","upstream_addr":"222.255.236.231:443","upstream_cache_status":"-","upstream_response_length":"183913","upstream_response_time":"1.390","upstream_status":"200"}
Parser Configuration
#regex
#conditional
event_timestamp = ""
src_ip = ""
http_method = ""
url_full = ""
url_path = ""
url_query = ""
http_protocol = ""
http_status = ""
response_bytes = ""
http_referer = ""
user_agent = ""
server_hostname = ""
host_header = ""
request_duration = ""
request_id = ""
upstream_server = ""
upstream_status = ""
upstream_duration = ""
upstream_bytes = ""
log_env = ""
log_type = ""
agent_name = ""
agent_type = ""
agent_version = ""
log_file_path = ""
event_timestamp = .timestamp
src_ip = .remote_addr
request_parts = split!(.request, " ")
http_method = request_parts[0]
url_full = request_parts[1]
http_protocol = request_parts[2]
if (contains(to_string(url_full), "?")) {
url_parts = split(to_string(url_full), "?")
url_path = url_parts[0]
url_query = url_parts[1]
} else {
url_path = url_full
url_query = ""
}
http_status = .status
response_bytes = .body_bytes_sent
http_referer = .http_referer
user_agent = .http_user_agent
host_header = .host_header
server_hostname = .server_name
request_duration = .request_time
request_id = .request_id
upstream_server = .upstream_addr
upstream_status = .upstream_status
upstream_duration = .upstream_response_time
upstream_bytes = .upstream_response_length
log_env = .fields.env
log_type = .fields.log_type
agent_name = .agent.name
agent_type = .agent.type
agent_version = .agent.version
log_file_path = .log.file.path
#normalize
timestamp: format_timestamp!(parse_timestamp!(event_timestamp, "%Y-%m-%dT%H:%M:%S.%3fZ"), "%Y-%m-%d %H:%M:%S")
source.ip: src_ip
http.request.method: http_method
url.full: url_full
url.path: url_path
url.query: url_query
http.version: http_protocol
http.response.status_code: http_status
destination.bytes: response_bytes
http.request.referrer: http_referer
user_agent.original: user_agent
url.domain: host_header
host.name: server_hostname
event.duration: request_duration
http.request.id: request_id
server.address: upstream_server
labels: {"env": log_env, "log_type": log_type, "upstream_status": upstream_status, "upstream_duration": upstream_duration, "upstream_bytes": upstream_bytes}
agent.name: agent_name
agent.type: agent_type
agent.version: agent_version
log.file.path: log_file_path
Output (ECS Format)
{
"timestamp": "2026-03-16 07:17:00",
"source.ip": "171.224.178.18",
"http.request.method": "GET",
"url.full": "/vi/employers?_rsc=1vs0z",
"url.path": "/vi/employers",
"url.query": "_rsc=1vs0z",
"http.version": "HTTP/1.1",
"http.response.status_code": "200",
"destination.bytes": "183891",
"http.request.referrer": "https://careerviet.vn/vi/tim-viec-lam/ky-su-qs-du-an-xay-dung.35C65B52.html",
"user_agent.original": "Mozilla/5.0 (iPad; CPU OS 26_3_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/145.0.7632.108 Mobile/15E148 Safari/604.1",
"url.domain": "careerviet.vn",
"host.name": "careerviet.vn",
"event.duration": "1.389",
"http.request.id": "cfd30872ab24f8fbaf4278d5d47690dc",
"server.address": "222.255.236.231:443",
"labels": {
"env": "production",
"log_type": "waf_access_log_v2",
"upstream_status": "200",
"upstream_duration": "1.390",
"upstream_bytes": "183913"
},
"agent.name": "waf-hn-main",
"agent.type": "filebeat",
"agent.version": "8.9.0",
"log.file.path": "/log/access.log"
}
Explanation
#regex Block
- Để trống vì log đã ở dạng JSON
- Không cần regex để tách field, truy cập trực tiếp các field JSON
#conditional Block
- Khởi tạo biến: Khai báo tất cả biến rỗng trước khi xử lý
- Truy cập field: Sử dụng
.fieldcho các field JSON - split!(): Tách request thành method, url, protocol (có thể fail nên dùng
!) - split(): Tách URL thành path và query (không thể fail)
- contains(): Kiểm tra URL có chứa query string
- Nested object access:
.agent.name,.fields.env,.log.file.path
#normalize Block
- timestamp: Key chính, format từ ISO8601 sang
%Y-%m-%d %H:%M:%S - HTTP info: method, status, referer, user agent
- URL parsing: full URL, path, query string, domain
- Network info: source IP, server address
- Timing: request duration (event.duration)
- Request ID: http.request.id
- Metadata: labels (JSON object), agent info, log file path
VRL Functions Used
| Function | Purpose |
|---|---|
split! | Split string by delimiter (có thể fail) |
split | Split string by delimiter (không thể fail) |
contains | Check if string contains substring |
to_string | Convert value to string |
parse_timestamp! | Parse timestamp string |
format_timestamp! | Format timestamp to string |
ECS Fields Mapped
| ECS Field | Source | Description |
|---|---|---|
timestamp | timestamp | Thời gian sự kiện (key chính) |
source.ip | remote_addr | IP client |
http.request.method | request0 | HTTP method (GET, POST...) |
url.full | request1 | Full URL path |
url.path | Parsed from URL | URL path without query |
url.query | Parsed from URL | Query string |
http.version | request2 | HTTP protocol version |
http.response.status_code | status | HTTP response status |
destination.bytes | body_bytes_sent | Bytes sent from server |
http.request.referrer | http_referer | Referer URL |
user_agent.original | http_user_agent | User agent string |
url.domain | host_header | Target host domain |
host.name | server_name | Server hostname |
event.duration | request_time | Total request duration |
http.request.id | request_id | Request tracking ID |
server.address | upstream_addr | Upstream server address |
labels | fields.* | Object chứa env, log_type, upstream info |
agent.name | agent.name | Filebeat agent name |
agent.type | agent.type | Agent type |
agent.version | agent.version | Agent version |
log.file.path | log.file.path | Source log file path |