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

  1. Khởi tạo biến: Khai báo tất cả biến rỗng trước khi xử lý
  2. Truy cập field: Sử dụng .field cho các field JSON
  3. split!(): Tách request thành method, url, protocol (có thể fail nên dùng !)
  4. split(): Tách URL thành path và query (không thể fail)
  5. contains(): Kiểm tra URL có chứa query string
  6. 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

FunctionPurpose
split!Split string by delimiter (có thể fail)
splitSplit string by delimiter (không thể fail)
containsCheck if string contains substring
to_stringConvert value to string
parse_timestamp!Parse timestamp string
format_timestamp!Format timestamp to string

ECS Fields Mapped

ECS FieldSourceDescription
timestamptimestampThời gian sự kiện (key chính)
source.ipremote_addrIP client
http.request.methodrequest0HTTP method (GET, POST...)
url.fullrequest1Full URL path
url.pathParsed from URLURL path without query
url.queryParsed from URLQuery string
http.versionrequest2HTTP protocol version
http.response.status_codestatusHTTP response status
destination.bytesbody_bytes_sentBytes sent from server
http.request.referrerhttp_refererReferer URL
user_agent.originalhttp_user_agentUser agent string
url.domainhost_headerTarget host domain
host.nameserver_nameServer hostname
event.durationrequest_timeTotal request duration
http.request.idrequest_idRequest tracking ID
server.addressupstream_addrUpstream server address
labelsfields.*Object chứa env, log_type, upstream info
agent.nameagent.nameFilebeat agent name
agent.typeagent.typeAgent type
agent.versionagent.versionAgent version
log.file.pathlog.file.pathSource log file path

logo
CMC Telecom
Aspire to Inspire the Digital World