在项目中会产生大量的日志以方便问题跟踪,有时需要统计分析系统运行期间的日志,例如:分析系统使用情况,使用人数,系统错误信息等等。根据不同的日志类别,生成可视化图表展示,所以就需要需要对日志进行处理,将每一行拆分成多个字段,存入数据库或者es,便于统计分析,生成报表。
由于之前没有接触过,网上通过搜集资料,找到使用logstash来分割反向代理的日志,由单个简单的正则组合,就能对一大段文字进行切割,惊叹与简单可配置。后来找到了java也可以通过Grok进行日志的统计分析,Grok进行日志处理的好处有:1:默认集成了多中正则表达式;2:支持自定义的正则表达式。
grok是一种采用组合多个预定义的正则表达式,用来匹配分割文本并映射到关键字的工具。通常用来对日志数据进行预处理。logstash的filter模块中grok插件是其实现之一。
Grok内置了许多的正则表达式库,便于我们直接使用开发(github搜索grok,项目一般都有这个pattern文件)
grok支持自定义匹配字段规则,可以灵活满足扩展的需求。
grok预定义匹配字段
USERNAME [a-zA-Z0-9._-]+
USER %{USERNAME}
INT (?:[+-]?(?:[0-9]+))
BASE10NUM (?<![0-9.+-])(?>[+-]?(?:(?:[0-9]+(?:\.[0-9]+)?)|(?:\.[0-9]+)))
NUMBER (?:%{BASE10NUM})
BASE16NUM (?<![0-9A-Fa-f])(?:[+-]?(?:0x)?(?:[0-9A-Fa-f]+))
BASE16FLOAT \b(?<![0-9A-Fa-f.])(?:[+-]?(?:0x)?(?:(?:[0-9A-Fa-f]+(?:\.[0-9A-Fa-f]*)?)|(?:\.[0-9A-Fa-f]+)))\b
POSINT \b(?:[1-9][0-9]*)\b
NONNEGINT \b(?:[0-9]+)\b
WORD \b\w+\b
NOTSPACE \S+
SPACE \s*
DATA .*?
GREEDYDATA .*
QUOTEDSTRING (?>(?<!\\)(?>"(?>\\.|[^\\"]+)+"|""|(?>'(?>\\.|[^\\']+)+')|''|(?>`(?>\\.|[^\\`]+)+`)|``))
UUID [A-Fa-f0-9]{8}-(?:[A-Fa-f0-9]{4}-){3}[A-Fa-f0-9]{12}
# Networking
MAC (?:%{CISCOMAC}|%{WINDOWSMAC}|%{COMMONMAC})
CISCOMAC (?:(?:[A-Fa-f0-9]{4}\.){2}[A-Fa-f0-9]{4})
WINDOWSMAC (?:(?:[A-Fa-f0-9]{2}-){5}[A-Fa-f0-9]{2})
COMMONMAC (?:(?:[A-Fa-f0-9]{2}:){5}[A-Fa-f0-9]{2})
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}))|:)))(%.+)?
IPV4 (?<![0-9])(?:(?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2}))(?![0-9])
IP (?:%{IPV6}|%{IPV4})
HOSTNAME \b(?:[0-9A-Za-z][0-9A-Za-z-]{0,62})(?:\.(?:[0-9A-Za-z][0-9A-Za-z-]{0,62}))*(\.?|\b)
HOST %{HOSTNAME}
IPORHOST (?:%{HOSTNAME}|%{IP})
HOSTPORT %{IPORHOST}:%{POSINT}
# paths
PATH (?:%{UNIXPATH}|%{WINPATH})
UNIXPATH (?>/(?>[\w_%!$@:.,-]+|\\.)*)+
TTY (?:/dev/(pts|tty([pq])?)(\w+)?/?(?:[0-9]+))
WINPATH (?>[A-Za-z]+:|\\)(?:\\[^\\?*]*)+
URIPROTO [A-Za-z]+(\+[A-Za-z+]+)?
URIHOST %{IPORHOST}(?::%{POSINT:port})?
# uripath comes loosely from RFC1738, but mostly from what Firefox
# doesn't turn into %XX
URIPATH (?:/[A-Za-z0-9$.+!*'(){},~:;=@#%_\-]*)+
#URIPARAM \?(?:[A-Za-z0-9]+(?:=(?:[^&]*))?(?:&(?:[A-Za-z0-9]+(?:=(?:[^&]*))?)?)*)?
URIPARAM \?[A-Za-z0-9$.+!*'|(){},~@#%&/=:;_?\-\[\]]*
URIPATHPARAM %{URIPATH}(?:%{URIPARAM})?
URI %{URIPROTO}://(?:%{USER}(?::[^@]*)?@)?(?:%{URIHOST})?(?:%{URIPATHPARAM})?
# Months: January, Feb, 3, 03, 12, December
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
MONTHNUM (?:0?[1-9]|1[0-2])
MONTHNUM2 (?:0[1-9]|1[0-2])
MONTHDAY (?:(?:0[1-9])|(?:[12][0-9])|(?:3[01])|[1-9])
# Days: Monday, Tue, Thu, etc...
DAY (?:Mon(?:day)?|Tue(?:sday)?|Wed(?:nesday)?|Thu(?:rsday)?|Fri(?:day)?|Sat(?:urday)?|Sun(?:day)?)
# Years?
YEAR (?>\d\d){1,2}
HOUR (?:2[0123]|[01]?[0-9])
MINUTE (?:[0-5][0-9])
# '60' is a leap second in most time standards and thus is valid.
SECOND (?:(?:[0-5]?[0-9]|60)(?:[:.,][0-9]+)?)
TIME (?!<[0-9])%{HOUR}:%{MINUTE}(?::%{SECOND})(?![0-9])
# datestamp is YYYY/MM/DD-HH:MM:SS.UUUU (or something like it)
DATE_US %{MONTHNUM}[/-]%{MONTHDAY}[/-]%{YEAR}
DATE_EU %{MONTHDAY}[./-]%{MONTHNUM}[./-]%{YEAR}
ISO8601_TIMEZONE (?:Z|[+-]%{HOUR}(?::?%{MINUTE}))
ISO8601_SECOND (?:%{SECOND}|60)
TIMESTAMP_ISO8601 %{YEAR}-%{MONTHNUM}-%{MONTHDAY}[T ]%{HOUR}:?%{MINUTE}(?::?%{SECOND})?%{ISO8601_TIMEZONE}?
DATE %{DATE_US}|%{DATE_EU}
DATESTAMP %{DATE}[- ]%{TIME}
TZ (?:[PMCE][SD]T|UTC)
DATESTAMP_RFC822 %{DAY} %{MONTH} %{MONTHDAY} %{YEAR} %{TIME} %{TZ}
DATESTAMP_RFC2822 %{DAY}, %{MONTHDAY} %{MONTH} %{YEAR} %{TIME} %{ISO8601_TIMEZONE}
DATESTAMP_OTHER %{DAY} %{MONTH} %{MONTHDAY} %{TIME} %{TZ} %{YEAR}
DATESTAMP_EVENTLOG %{YEAR}%{MONTHNUM2}%{MONTHDAY}%{HOUR}%{MINUTE}%{SECOND}
# Syslog Dates: Month Day HH:MM:SS
SYSLOGTIMESTAMP %{MONTH} +%{MONTHDAY} %{TIME}
PROG (?:[\w._/%-]+)
SYSLOGPROG %{PROG:program}(?:\[%{POSINT:pid}\])?
SYSLOGHOST %{IPORHOST}
SYSLOGFACILITY <%{NONNEGINT:facility}.%{NONNEGINT:priority}>
HTTPDATE %{MONTHDAY}/%{MONTH}/%{YEAR}:%{TIME} %{INT}
# Shortcuts
QS %{QUOTEDSTRING}
# Log formats
SYSLOGBASE %{SYSLOGTIMESTAMP:timestamp} (?:%{SYSLOGFACILITY} )?%{SYSLOGHOST:logsource} %{SYSLOGPROG}:
COMMONAPACHELOG %{IPORHOST:clientip} %{USER:ident} %{USER:auth} \[%{HTTPDATE:timestamp}\] "(?:%{WORD:verb} %{NOTSPACE:request}(?: HTTP/%{NUMBER:httpversion})?|%{DATA:rawrequest})" %{NUMBER:response} (?:%{NUMBER:bytes}|-)
COMBINEDAPACHELOG %{COMMONAPACHELOG} %{QS:referrer} %{QS:agent}
# Log Levels
LOGLEVEL ([Aa]lert|ALERT|[Tt]race|TRACE|[Dd]ebug|DEBUG|[Nn]otice|NOTICE|[Ii]nfo|INFO|[Ww]arn?(?:ing)?|WARN?(?:ING)?|[Ee]rr?(?:or)?|ERR?(?:OR)?|[Cc]rit?(?:ical)?|CRIT?(?:ICAL)?|[Ff]atal|FATAL|[Ss]evere|SEVERE|EMERG(?:ENCY)?|[Ee]merg(?:ency)?)
maven 项目添加对应依赖
<dependency>
<groupId>io.krakens</groupId>
<artifactId>java-grok</artifactId>
<version>0.1.9</version>
</dependency>
由于不同系统的日志各不相同,其结构也挺复杂,所以grok使用正则表达式来解析日志,它对于一些常见系统的日志(如:nginx、tomcat、apache)已经内置好了正则表达式库,基本上满足绝大多数日志的需求,也可以根据日志的格式自定义正则表达式库,使用起来很简单,代码如下:
GrokCompiler grokCompiler = GrokCompiler.newInstance();
// 进行注册, registerDefaultPatterns()方法注册的是Grok内置的patterns
grokCompiler.registerDefaultPatterns();
// 添加自定的正则表达式,解析日期(例如:2021-07-07 13:45:39.210)
grokCompiler.register("DATETIME","[0-9,\\.\\-: ]+");
/* 传入自定义的pattern, 会从已注册的patterns里面进行配对,
* 例如: %{DATETIME:datetime}
* 配对成功后, 会在match时按照固定的解析格式将解析结果存入map中, 此处datetime作为输出的key
Grok grok = grokCompiler.compile("%{DATETIME:datetime} %{LOGLEVEL:level} %{INT:pid} --- \\[%{NOTSPACE:thread}\\] %{NOTSPACE:classed}\\s*:%{GREEDYDATA:message}");
String logMsg = "2021-07-07 13:45:39.210 INFO 16100 --- [SpringContextShutdownHook] com.zaxxer.hikari.HikariDataSource : Shutdown completed.";
// 通过match()方法进行匹配, 对log进行解析, 按照指定的格式进行输出
Match grokMatch = grok.match(logMsg);
// 获取结果
Map<String, Object> resultMap = grokMatch.capture();
System.out.print(resultMap);
{datetime=2021-07-07 13:45:39.210 , level=INFO, classed=com.zaxxer.hikari.HikariDataSource, pid=16100, thread=SpringContextShutdownHook, message= Shutdown completed.}
grok在线调试地址:
在线Grok Debug工具,Grok校验|调试
在项目中会产生大量的日志以方便问题跟踪,有时需要统计分析系统运行期间的日志,例如:分析系统使用情况,使用人数,系统错误信息等等。根据不同的日志类别,生成可视化图表展示,所以就需要需要对日志进行处理,将每一行拆分成多个字段,存入数据库或者es,便于统计分析,生成报表。由于之前没有接触过,网上通过搜集资料,找到使用logstash来分割反向代理的日志,由单个简单的正则组合,就能对一大段文字进行切割,惊叹与简单可配置。后来找到了java也可以通过Grok进行日志的统计分析,Grok进行日志处理的好处有:1:默
Java
Grok
是简单的API,可让您轻松
解析
日志
和其他
文件
(单行)。
使用
Java
Grok
,您可以将非结构化
日志
和事件数据转换为结构化数据(JSON)。
我可以将
Grok
用作什么?
从
日志
和流程中报告错误和其他模式
解析
复杂的文本输出并将其转换为json以进行外部处理
将“一次写入,随处
使用
”应用于正则表达式
自动为未知文本输入提供模式(您想要生成模式以供将来匹配的
日志
)
Maven仓库
<dependency>
<groupId>io.krakens</groupId>
<artifactId>
java
-
grok
</artifactId>
<version>0.1.9</version>
</dependency>
还是用gradle
compile " io.krakens:
java
-
grok
:0.1.9 "
旧版本()
用法( )
如何
使用
java
Open
Grok
-邪恶的快速源浏览器
Open
Grok
是
使用
Java
编写的快速且可用的源代码搜索和交叉引用引擎。 它可以帮助您搜索,交叉引用和导航您的源代码树。 它可以理解许多源代码管理系统的各种程序
文件
格式和版本控制历史。
该项目的官方页面位于: :
2. Open
Grok
安装和设置
2. 1.更新
Open
Grok
使用
,版本组件进一步指示有关更新到较新版本的更多详细信息。 版本方案为xyz,任何组件的更改均解释为:
x-主要向后不兼容的更新
y-需要对存储库进行完全干净的重新索引(例如,索
Logstash的
Grok
可以使蹩脚的、无结构的
日志
内容结构化
需要注意的地方
grok
模式是正则表达式,因此这个插件的性能受到正则表达式引擎严重影响,效率并不高。如果通过给定的匹配格式匹配不上会Kibana查询的时候打上tag 为
grok
failed 的标签
grok
模式的语法如下:
%{SYNTAX:SEMANTIC}
SYNTAX:代表匹配值的类型,例如3.44可以...
由于项目中,要求统计分析系统运行期间的
日志
,根据不同的
日志
类别,在前台JSP通过Echarts图标展示,所以需要对
日志
进行处理,将其整理成能够
使用
的JSON格式
日志
,然后输出前台展示。
由于之前没有接触过,一开始比较懵逼,网上通过搜集资料,找到了大家都基本上通过
Grok
进行
日志
的统计分析,
Grok
进行
日志
处理的好处有:1:默认集成了多中正则表达式;2:支持自定义的正则表达式。
1、正则表达式库
Grok
内置了许多的正则表达式库,便于我们直接
使用
开发(github搜索
grok
,项目一般都有这个patte
因为是maven项目,所以可以直接在pom中添加依赖,这样包就自己下载下来了:
&amp;lt;dependency&amp;gt;
&amp;lt;groupId&amp;gt;io.krakens&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;
java
-
grok
&amp
<!-- https://mvnrepository.com/artifact/io.thekraken/
grok
-->
<dependency>
<groupId>io.krakens</groupId>
<artifactId>
java
-
grok
</artifactId>
<version>0.1.9</version>
</depend
Free
Grok
是用
Java
编写的快速且可用的源代码搜索和交叉引用引擎。
它可以帮助您搜索,交叉引用和导航您的源代码树。
它可以理解许多源代码管理系统的各种程序
文件
格式和版本控制历史。
该项目的官方页面位于:
最新的
Java
(至少1.8)
像Tomcat(8.x或更高版本)这样的Servlet容器,支持Servlet
2.5和JSP
旺盛的标签或通用标签
源代码管理安装,取决于建立索引的存储库的类型
如果要构建Free
Grok
:
蚂蚁(1.9.4及更高版本)
JFlex
Netbeans(可选,至少为8.2,将需要Ant
1.9.4)
Free
Grok
通常在servlet容器(例如Tomcat)中运行。
SRC_ROOT环境变量引用包含您的源树的目录。
Free
Grok
分析源代码树,并建立搜索索引以及源
文件
的交叉引用超文本版本。
这些生成的数据
文件
将存储在环
Java
使用
的正则引擎是NFA(非确定型有限状态自动机)。
一个状态可以通过标记了字符或ε的多条边跳转到另一个状态。字符或ε 分别表示读入一个字符或不读入字符可以跳转到另一个状态上,比如遇到表达式的右括号和回溯。NFA的特点是匹配过程面临很多的岔路去做出选择,一旦某条岔路失败,就需要回溯,类似于深度优先搜索。不过并不一定完全遍历,完成匹配之后就停止搜索了。
比如(a|b)*abb
如果没有
日志
解析
,搜索和可视化
日志
几乎是不可能的,一个被低估的技能记录器需要读取他们的数据。
解析
结构化你的传入(非结构化)
日志
,以便用户可以在调查期间或设置仪表板时搜索清晰的字段和值。
最流行的
日志
解析
语言是
Grok
。 你可以
使用
Grok
插件在各种
日志
管理和分析工具比如 Elastic Stack 中
解析
日志
数据。在这里查看我之前的的
Grok
教程。
但是用
Grok
解析
日志
可能会很棘手。 本博客将研究一些
Grok
模式示例,这些示例可以帮助您了解如何
解析
日志
数据。
开始
使用
Gr.
- `input` 部分
使用
`file` 插件,用于从指定目录下收集
日志
文件
。`path` 参数指定了
日志
文件
所在的路径,`start_position` 参数设置为 `beginning`,表示从
文件
开头开始读取。如果设置为 `end`,则表示从
文件
末尾开始读取。
- `filter` 部分用于对收集到的
日志
进行过滤和处理。例如,可以
使用
`
grok
` 插件对
日志
进行
解析
,
使用
`mutate` 插件进行字段操作等。
- `output` 部分用于将处理后的
日志
输出到指定的目的地。例如,可以将
日志
输出到 Elasticsearch 中,或者
使用
`stdout` 插件将
日志
输出到控制台。