Нормализация событий c использованием GROK
Плагин позволяет извлекать и приводить к модели события Elastic Common Schema
исходные события любого формата на основе паттернов, которые были указаны в patterns
и definitions
.
Если явно не указывать название полей событий в паттернах, то в полях маппинга оно отображаться не будет.
Существует возможность делать преобразования к типам int
и float
, задавать шаблоны даты и времени, используя конструкцию date("...")
Шаблон Grok
паттерна: %{MATCHER:EXTRACT:FILTER}
, где
MATCHER
- правило (возможно, ссылка на другой паттерн), описывающее, что следует ожидать (NUMBER
, WORD
и т.д.)
EXTRACT
- идентификатор, представляющий место назначения для фрагмента текста, совпавшего с MATCHER
FILTER
- пост-процессор правила для его преобразования. Если не указывать, то преобразует найденное выражение к string
. (Возможные фильтры: int
, float
)
Примеры всех MATCHER
, которые могут использоваться по умолчанию находятся в файлах внутри этой директории. Все остальные матчеры можно создавать самостоятельно в defenitions
Примеры
1. Событие с полем Ctime
, пример конфигурации:
Регулярное выражение :
processors:
- module: grok
from: Raw
patterns:
Komrad_Pattern: "%{COMMONAPACHELOG}"
Пример исходного события:
232.0.0.0 - - [30/Apr/2020:14:30:53 -0500] "GET /images/hm_bg.jpg HTTP/1.0" 200 24736
Результат:
ECS.HTTP.RequestBodyContent: /images/hm_bg.jpg
ECS.HTTP.RequestMethod: GET
ECS.HTTP.ResponseBodyBytes: 24736
ECS.HTTP.ResponseStatusCode: 200
ECS.HTTP.Version: 1.0
ECS.Source.Address: 232.0.0.0
CTime
не отображается, т.к. это внутреннее событие event
, но он был получен. В результате можно заметить преобразование к полям ECS
. Это происходит, потому что внутри себя %\{COMMONAPACHELOG\}
содержит другие регулярные выражения, у которых MATCHER
является одним из свойств ECS
. Определение же типа для свойств ECS
задаётся заданными внутри KOMRAD дефолтными значениями.
2. Событие с полем ECS
, пример конфигурации:
Регулярное выражение:
processors:
- module: grok
from: Raw
patterns:
Komrad_Pattern: "%{IP:Ecs.client.ip}:%{NUMBER:ecs.Client.port}"
Пример исходного события:
127.0.0.1:3900
Результат:
ECS.Client.IP: 127.0.0.1
ECS.Client.Port: 3900
3. Использование defenitions
:
Регулярное выражение:
processors:
- module: grok
from: Raw
patterns:
MyParsingRule: "%{user_info} %{connection} %{server}"
definitions:
user_info: "%{WORD:user.name} id:%{NUMBER:user.id:int}"
connection: "connected on %{date(\"MM/dd/yyyy\"):connect.date}"
server: "on server %{NOTSPACE:server.name} in %{NOTSPACE:server.env}"
Пример исходного события:
john id:12345 connected on 11/08/2017 on server XYZ in production
Результат:
Connect.Date: 2017-11-08T00:00:00Z
Server.Env: production
Server.Name: XYZ
User.ID: 12345
User.Name: john
4. Парсинг простого log-сообщения:
Регулярное выражение:
processors:
- module: grok
from: Raw
patterns:
LOG_MESSAGE: "%{TIMESTAMP_ISO8601:timestamp} %{LOGLEVEL:level} %{GREEDYDATA:message}"
Пример исходного события:
2020-10-02T23:22:12.223222Z info start server
Результат:
Level: info
Message: start server
Timestamp: 2020-10-02T23:22:12.223222Z
5. Парсинг log-сообщения с определениями:
Регулярное выражение:
processors:
- module: grok
from: Raw
patterns:
message: "%{SYSLOGBASE} %{POSTFIX_QUEUEID:queue_id}: %{MSG:syslog_message}"
definitions:
POSTFIX_QUEUEID: "[0-9A-F]{10,11}"
MSG: "message-id=<%{GREEDYDATA}>"
Пример исходного события:
Jan 1 06:25:43 mailserver14 postfix/cleanup[21403]: BEF25A72965: message-id=<20130101142543.5828399CCAF@mailserver14.example.com>
Результат:
ECS.Host.Name: mailserver14
ECS.Process.Name: postfix/cleanup
ECS.Process.PID: 21403
QueueId: BEF25A72965
SyslogMessage: message-id=<20130101142543.5828399CCAF@mailserver14.example.com>
6. Парсинг результата работы системы:
Регулярное выражение:
processors:
- module: grok
from: Raw
patterns:
message: "Inventory error: %{DATA:error_message} for product %{INT:product_id}"
Пример исходного события:
Inventory error: out of memory processing thumbnail for product 7186
Результат:
ErrorMessage: out of memory processing thumbnail
ProductId: 7186
7. Парсинг с использованием фильтров:
Регулярное выражение:
processors:
- module: grok
from: Raw
patterns:
message: "%{WORD:type}: %{IP:ipclient} - %{IP:ipuser} [%{HTTPDATE:datetime}] \"%{WORD:method} %{URIPATHPARAM:request} %{WORD}/%{NUMBER:httpversion:float}\" %{WORD:status:int} %{NUMBER:bytes:integer} - %{NUMBER:responsetime:number}"
Пример исходного события:
info: ::ffff:127.0.0.1 - ::ffff:127.0.0.1 [26/Jun/2019:11:52:36 +0000] "OPTIONS /api/categories/5ced18e2a0c9a01e879ce704 HTTP/1.1" 200 19 - 0.652
Результат:
Bytes: 19
Datetime: 26/Jun/2019:11:52:36 +0000
Httpversion: 1.1
Ipclient: ::ffff:127.0.0.1
Ipuser: ::ffff:127.0.0.1
Method: OPTIONS
Request: /api/categories/5ced18e2a0c9a01e879ce704
Responsetime: 0.652
Status: 200
Type: info
В данном примере для полей: httpversion
, status
, bytes
, responsetime
мы указали фильтры:
number
, int
, integer
, float
. На отображение результата это никак не повлияло,
но тип полей этих событий при парсинге изменился со строки, на тот, который им присвоили.
Даты разбора
Сопоставитель даты преобразует вашу метку времени в формат EPOCH
(единица измерения миллисекунды).
Регулярное выражение | Пример исходного события | Извлечённые поля |
---|---|---|
date: "%{date(\"HH:mm:ss\"):date}" | 14:20:15 | 2022-12-29T14:20:15Z |
date: "%{date(\"hh:mm:ss a\"):date}" | 02:20:15 PM | 2022-12-29T14:20:15Z |
date: "%{date(\"dd/MM/yyyy\"):date}" | 11/10/2014 | 2014-10-11T00:00:00Z |
date: "%{date(\"EEE MMM dd HH:mm:ss yyyy\"):date}" | Thu Jun 16 08:29:03 2016 | 2016-06-16T08:29:03Z |
date: "%{date(\"EEE MMM d HH:mm:ss yyyy\"):date}" | Tue Nov 1 08:29:03 2016 | 2016-11-01T08:29:03Z |
date: "%{date(\"dd/MMM/yyyy:HH:mm:ss Z\"):date}" | 06/Mar/2013:01:36:30 +0900 | 2013-03-05T16:36:30Z |
date: "%{date(\"yyyy-MM-dd’T’HH:mm:ss.SSSZZ\"):date}" | 2016-11-29T16:21:36.431+00:00 | 2016-11-29T16:21:36.431Z |
date: "%{date(\"dd/MMM/yyyy:HH:mm:ss.SSS\"):date}" | 06/Feb/2009:12:14:14.655 | 2009-02-06T12:14:14.655Z |
date: "%{date(\"yyyy-MM-dd HH:mm:ss.SSS z\"):date}" | 2007-08-31 19:22:22.427 UTC | 2007-08-31 19:22:22.427 UTC |
date: "%{date(\"EEE MMM dd HH:mm:ss yyyy\",\"Europe/Paris\"):date}" | Thu Jun 16 08:29:03 2016 | 2016-06-16T06:29:03Z |
date: "%{date(\"EEE MMM dd HH:mm:ss yyyy\",\"UTC+5\"):date}" | Thu Jun 16 08:29:03 2016 | 2016-06-16T03:29:03Z |
Пример заполнения полей:
processors:
- module: grok
from: Raw
patterns:
MyParsingRule: "%{date(\"EEE MMM dd HH:mm:ss yyyy\",\"UTC+5\"):date}"
Пример исходного события:
Thu Jun 16 08:29:03 2016
Результат:
Date: 2016-06-16T03:29:03Z
Список всех часовых поясов
Только Timezone GMT, UTC, CET, EET, HST, MST, EST работают валидно, во всех остальных случаях стоит пользоваться GMT/UTC (+-)XX:XX
синтаксисом
Экранирование
Есть 2 возможности экранировать символы:
- Экранировать надо через
\\
- Если надо использовать (или), то заменяем кавычки
"
на ``, убираем экранирование"
внутри строки, и добавляем экранирование на (и)
Standard
Есть паттерны по умолчанию, они отвечают за базовую нормализацию.
## COMMON LOG PATTERNS
BASE10NUM ([+-]?(?:[0-9]+(?:\.[0-9]+)?)|\.[0-9]+) //404
BASE16NUM (0[xX]?[0-9a-fA-F]+) //000000002
CISCOMAC (?:(?:[A-Fa-f0-9]{4}\.){2}[A-Fa-f0-9]{4}) //8041.a473.453b
CLIENT (?:%{IPV6}|%{IPV4}|%{HOSTNAME}|%{HOSTPORT}) //docs.etecs.ru
COMBINEDAPACHELOG %{COMMONAPACHELOG} %{QS:ECS.HTTP.RequestReferrer} %{QS:ECS.Observer.Name}
COMBINED_LOG_FORMAT %{COMMON_LOG_FORMAT} "%{DATA:ECS.HTTP.RequestReferrer}" "%{DATA:ECS.UserAgent.Original}"
COMMONAPACHELOG %{IPORHOST:ECS.Source.Address} %{USER:Ident} %{USER:Auth} \[%{HTTPDATE:CTime}\] "(?:%{WORD:ECS.HTTP.RequestMethod} %{NOTSPACE:ECS.HTTP.RequestBodyContent}(?: HTTP/%{NUMBER:ECS.HTTP.Version})?|%{DATA:ECS.HTTP.RequestBodyContent})" %{NUMBER:ECS.HTTP.ResponseStatusCode} (?:%{NUMBER:ECS.HTTP.ResponseBodyBytes}|-)
COMMONMAC (?:(?:[A-Fa-f0-9]{2}:){5}[A-Fa-f0-9]{2})
COMMON_LOG_FORMAT %{CLIENT:ECS.Source.IP} %{NOTSPACE:Ident} %{NOTSPACE:Auth} \[%{HTTPDATE:CTime:ts-httpd}\] "(?:%{WORD:ECS.HTTP.RequestMethod} %{NOTSPACE:ECS.HTTP.RequestBodyContent}(?: HTTP/%{NUMBER:ECS.HTTP.Version})?|%{DATA})" %{NUMBER:ECS.HTTP.ResponseStatusCode} (?:%{NUMBER:ECS.HTTP.ResponseBodyBytes}|-)
DATA .*?
DATE %{DATE_US}|%{DATE_EU}
DATESTAMP %{DATE}[- ]%{TIME}
DATESTAMP_OTHER %{DAY} %{MONTH} %{MONTHDAY} %{TIME} %{TZ} %{YEAR}
DATESTAMP_RFC822 %{DAY} %{MONTH} %{MONTHDAY} %{YEAR} %{TIME} %{TZ}
DATE_EU %{MONTHDAY}[./-]%{MONTHNUM}[./-]%{YEAR}
DATE_US %{MONTHNUM}[/-]%{MONTHDAY}[/-]%{YEAR} //11/5/2011
DAY (?:Mon(?:day)?|Tue(?:sday)?|Wed(?:nesday)?|Thu(?:rsday)?|Fri(?:day)?|Sat(?:urday)?|Sun(?:day)?)
DURATION %{NUMBER}[nuµm]?s
GREEDYDATA .*
HOST %{HOSTNAME} //docs.etecs.ru
HOSTNAME \b(?:[0-9A-Za-z][0-9A-Za-z-]{0,62})(?:\.(?:[0-9A-Za-z][0-9A-Za-z-]{0,62}))*(\.?|\b) //docs.etecs.ru
HOSTPORT %{IPORHOST}:%{POSINT}
HOUR (?:2[0123]|[01]?[0-9])
HTTPD20_ERRORLOG \[%{HTTPDERROR_DATE:CTime}\] \[%{LOGLEVEL:ECS.Log.Level}\] (?:\[client %{IPORHOST:ECS.Source.IP}\] ){0,1}%{GREEDYDATA:ECS.Base.Message}
HTTPD24_ERRORLOG \[%{HTTPDERROR_DATE:CTime}\] \[%{WORD:ECS.Event.Module}:%{LOGLEVEL:ECS.Log.Level}\] \[pid %{POSINT:ECS.Process.PID}:tid %{NUMBER:ECS.Process.ThreadID}\]( \(%{POSINT:Proxy.ErrorCode:int}\)%{DATA:Proxy.ErrorMessage}:)?( \[client %{IPORHOST:ECS.Source.Host}:%{POSINT:ECS.Source.Port}\])? %{DATA:ECS.HTTP.ResponseStatusCode}: %{GREEDYDATA:ECS.Base.Message}
HTTPDATE %{MONTHDAY}/%{MONTH}/%{YEAR}:%{TIME} %{INT}
HTTPDERROR_DATE %{DAY} %{MONTH} %{MONTHDAY} %{TIME} %{YEAR}
HTTPD_ERRORLOG %{HTTPD20_ERRORLOG}|%{HTTPD24_ERRORLOG}
INT (?:[+-]?(?:[0-9]+))
IP (?:%{IPV6}|%{IPV4})
IPORHOST (?:%{HOSTNAME}|%{IP})
IPV4 (?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?) //192.168.1.1
IPV6 ((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)? //2001:0db8:85a3:0000:0000:8a2e:0370:7334
ISO8601_SECOND (?:%{SECOND}|60)
ISO8601_TIMEZONE (?:Z|[+-]%{HOUR}(?::?%{MINUTE}))
LOGLEVEL ([A-a]lert|ALERT|[T|t]race|TRACE|[D|d]ebug|DEBUG|[N|n]otice|NOTICE|[I|i]nfo|INFO|[W|w]arn?(?:ing)?|WARN?(?:ING)?|[E|e]rr?(?:or)?|ERR?(?:OR)?|[C|c]rit?(?:ical)?|CRIT?(?:ICAL)?|[F|f]atal|FATAL|[S|s]evere|SEVERE|EMERG(?:ENCY)?|[Ee]merg(?:ency)?)
MAC (?:%{CISCOMAC}|%{WINDOWSMAC}|%{COMMONMAC})
MINUTE (?:[0-5][0-9])
MONTH \b(?:Jan(?:uary)?|Feb(?:ruary)?|Mar(?:ch)?|Apr(?:il)?|May|Jun(?:e)?|Jul(?:y)?|Aug(?:ust)?|Sep(?:tember)?|Oct(?:ober)?|Nov(?:ember)?|Dec(?:ember)?)\b
MONTHDAY (?:(?:0[1-9])|(?:[12][0-9])|(?:3[01])|[1-9])
MONTHNUM (?:0?[1-9]|1[0-2])
NGUSER %{NGUSERNAME}
NGUSERNAME [a-zA-Z0-9\.\@\-\+_%]+
NONNEGINT \b(?:[0-9]+)\b
NOTSPACE \S+
NUMBER (?:%{BASE10NUM})
PATH (?:%{UNIXPATH}|%{WINPATH}) //C:\Windows\Logs или /home/echelon
POSINT \b(?:[1-9][0-9]*)\b
PROG (?:[\w._/%-]+)
QS %{QUOTEDSTRING}
QUOTEDSTRING "(**(\\.[^"\\]**)**)"|\'([^\'\\]**(\\.**)**)\'
RESPONSE_CODE %{NUMBER:ECS.HTTP.ResponseStatusCode}
RESPONSE_TIME %{DURATION:ECS.Event.Duration}
SECOND (?:(?:[0-5][0-9]|60)(?:[:.,][0-9]+)?)
SPACE \s*
SYSLOGBASE %{SYSLOGTIMESTAMP:CTime} (?:%{SYSLOGFACILITY} )?%{SYSLOGHOST:ECS.Host.Name} %{SYSLOGPROG}:
SYSLOGFACILITY <%{NONNEGINT:ECS.Log.SyslogFacilityCode}.%{NONNEGINT:ECS.Log.SyslogPriority}>
SYSLOGHOST %{IPORHOST}
SYSLOGPROG %{PROG:ECS.Process.Name}(?:\[%{POSINT:ECS.Process.PID}\])?
SYSLOGTIMESTAMP %{MONTH} +%{MONTHDAY} %{TIME}
TIME ([^0-9]?)%{HOUR}:%{MINUTE}(?::%{SECOND})([^0-9]?)
TIMESTAMP_ISO8601 %{YEAR}-%{MONTHNUM}-%{MONTHDAY}[T ]%{HOUR}:?%{MINUTE}(?::?%{SECOND})?%{ISO8601_TIMEZONE}?
TTY (?:/dev/(pts|tty([pq])?)(\w+)?/?(?:[0-9]+))
TZ (?:[PMCE][SD]T|UTC|GMT) //GMT
UNIXPATH (/[\w_%!$@:.,-]?/?)(\S+)? ///home/echelon
URI %{URIPROTO}://(?:%{USER}(?::[^@]*)?@)?(?:%{URIHOST})?(?:%{URIPATHPARAM})?
URIHOST %{IPORHOST}(?::%{POSINT:ECS.Source.Port})?
URIPARAM \?[A-Za-z0-9$.+!**'|(){},~@#%&/=:;_?\-\[\]]** //?application=&inf.name=eth0
URIPATH (?:/[A-Za-z0-9$.+!**'(){},~:;=@#%_\-]**)+ // //spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles
URIPATHPARAM %{URIPATH}(?:%{URIPARAM})? //s?application=&inf.name=eth0
URIPROTO [A-Za-z]+(\+[A-Za-z+]+)? //" http
USER %{USERNAME} //komrad
USERNAME [a-zA-Z0-9._-]+ //komrad
UUID [A-Fa-f0-9]{8}-(?:[A-Fa-f0-9]{4}-){3}[A-Fa-f0-9]{12} //9d3b594e-c94e-11ed-afa1-0242ac120002
WINDOWSMAC (?:(?:[A-Fa-f0-9]{2}-){5}[A-Fa-f0-9]{2}) //0A-00-27-00-00-11
WINPATH ([A-Za-z]:|\\)(?:\\[^\\?**]**)+ //C:\Windows\Logs
WORD \b\w+\b //komrad
YEAR (\d\d){1,2} //2023