Rules (XQL)
[INGEST:vendor="iis", product="iis", target_dataset="iis_iis_raw", no_hit = keep]
call MICROSOFT_IIS_PARSE_FIELDS;
[RULE:MICROSOFT_IIS_PARSE_FIELDS]
filter _raw_log ~= "^\d{4}\-\d{2}\-\d{2}\s+\d{2}:\d{2}:\d{2}\s+"
| alter
// util variables used for classifying the relevant log type i.e., access log or http error log
tmp_logfile_name = lowercase(_log_source_file_name),
tmp_logfile_path = lowercase(_log_source_file_path),
// util variables used for classifying the relevant W3C structure for http error logs
tmp_num_of_fields = array_length(regextract(_raw_log, "(\S+)"))
// determine log type according to its origin file name & path
| alter tmp_log_type = if(tmp_logfile_name ~= "httperr" or tmp_logfile_path contains """system32\\logfiles\\httperr""", "Error Log", "Access Log")
// determine log format according to log type and field list length, and extract the log fields accordingly into parsed_fields
| alter parsed_fields = if(
tmp_log_type = "Access Log" and tmp_num_of_fields >= 22, // Schema: https://learn.microsoft.com/en-us/windows/win32/http/w3c-logging
// format: date time s-sitename s-computername s-ip cs-method cs-uri-stem cs-uri-query s-port cs-username c-ip cs-version cs(User-Agent) cs(Cookie) cs(Referer) cs-host sc-status sc-substatus sc-win32-status sc-bytes cs-bytes time-taken
regexcapture(_raw_log, "^(?P<date>\S+)\s+(?P<time>\S+)\s+(?P<s_sitename>\S+)\s+(?P<s_computername>\S+)\s+(?P<s_ip>\S+)\s+(?P<cs_method>\S+)\s+(?P<cs_uri_stem>\S+)\s+(?P<cs_uri_query>\S+)\s+(?P<s_port>\S+)\s+(?P<cs_username>\S+)\s+(?P<c_ip>\S+)\s+(?P<cs_version>\S+)\s+(?P<cs_user_agent>\S+)\s+(?P<cs_cookie>\S+)\s+(?P<cs_referer>\S+)\s+(?P<cs_host>\S+)\s+(?P<sc_status>\S+)\s+(?P<sc_substatus>\S+)\s+(?P<sc_win32_status>\S+)\s+(?P<sc_bytes>\S+)\s+(?P<cs_bytes>\S+)\s+(?P<time_taken>\S+)"),
tmp_log_type = "Error Log" and tmp_num_of_fields = 13, // Error Log (Schema: https://learn.microsoft.com/en-us/windows/win32/http/format-of-the-http-server-api-error-logs)
// format: date time c-ip c-port s-ip s-port cs-version cs-method cs-uri sc-status s-siteid s-reason s-queuename
regexcapture(_raw_log, "^(?P<date>\S+)\s+(?P<time>\S+)\s+(?P<c_ip>\S+)\s+(?P<c_port>\S+)\s+(?P<s_ip>\S+)\s+(?P<s_port>\S+)\s+(?P<cs_version>\S+)\s+(?P<cs_method>\S+)\s+(?P<cs_uri>\S+)\s+(?P<sc_status>\S+)\s+(?P<s_siteid>\S+)\s+(?P<s_reason>\S+)\s+(?P<s_queuename>\S+)"),
tmp_log_type = "Error Log" and tmp_num_of_fields = 14, // Error Log
// format: date time c-ip c-port s-ip s-port cs-version cs-method cs-uri streamid sc-status s-siteid s-reason s-queuename
regexcapture(_raw_log, "^(?P<date>\S+)\s+(?P<time>\S+)\s+(?P<c_ip>\S+)\s+(?P<c_port>\S+)\s+(?P<s_ip>\S+)\s+(?P<s_port>\S+)\s+(?P<cs_version>\S+)\s+(?P<cs_method>\S+)\s+(?P<cs_uri>\S+)\s+(?P<streamid>\S+)\s+(?P<sc_status>\S+)\s+(?P<s_siteid>\S+)\s+(?P<s_reason>\S+)\s+(?P<s_queuename>\S+)"),
tmp_log_type = "Error Log" and tmp_num_of_fields >= 16, // Error Log
// format: date time c-ip c-port s-ip s-port cs-version cs-method cs-uri streamid streamid_ex sc-status s-siteid s-reason s-queuename transport
regexcapture(_raw_log, "^(?P<date>\S+)\s+(?P<time>\S+)\s+(?P<c_ip>\S+)\s+(?P<c_port>\S+)\s+(?P<s_ip>\S+)\s+(?P<s_port>\S+)\s+(?P<cs_version>\S+)\s+(?P<cs_method>\S+)\s+(?P<cs_uri>\S+)\s+(?P<streamid>\S+)\s+(?P<streamid_ex>\S+)\s+(?P<sc_status>\S+)\s+(?P<s_siteid>\S+)\s+(?P<s_reason>\S+)\s+(?P<s_queuename>\S+)\s+(?P<transport>\S+)"),
// default fallback
regexcapture(_raw_log, "(?P<date>\S+)\s+(?P<time>\S+)"))
| alter
// handle timestamp
_time = parse_timestamp("%Y-%m-%d %H:%M:%S", format_string("%s %s", parsed_fields -> date, parsed_fields -> time)),
// add the log type classification to the parsed_fields object
parsed_fields = object_merge(parsed_fields, object_create("log_type", tmp_log_type))
// remove util fields
| fields - tmp_log_type, tmp_num_of_fields, tmp_logfile_name, tmp_logfile_path;