全方位立体监控之日志解决方案ELK(2)
来源:互联网 发布:数控画图软件 编辑:程序博客网 时间:2024/05/19 16:03
Logstash详细介绍
下面我们将对ELK框架进行深入详细的了解,了解了其中的原理,才能选择更加高效可靠的配置方案。ElasticSearch的配置比较简单,主要性能瓶颈在于内存以及节点设置方面,Kibana的配置也较为简单,web应用无很大的优化改进空间,主要在于第三方插件的使用。下面我们主要介绍Logstash的方案设计。
Logstash使用Ruby语言编写,它编写了自己的一套DSL。Logstash在处理数据的时候,就像管道一样,每一个配置文件中都必须存在一个input插件和一个output插件,数据以流的形式在管道中进行传输。下面我通用一个图例来表示,日志数据就像是大小形状不同的图案,通过nput进入到管道内部,然后通过一个圆形的filter插件,这样从output出来的数据就都成为了圆形。所以一个标准的Logstash配置,应该同时存在一个nput,filter,output配置。
通过官方文档我们可以看到,由于开放的社区环境,logstash中存在大量的插件,功能丰富且强大。可以接受多种形式的数据,进行多样性的处理,最后传输到各种各样的环境中。下面我们结合实际情况,介绍一些常用的插件。
- 情景:需要监控Apache等生成的日志,可以动态监控文件内容。
解决方案:
监控文件内容,使用input:file插件。Logstash中使用一个名叫FileWatch的Ruby Gem库来监听文件变化,并且会生成一个${Home}/.sincedb的数据库文件来记录被监听的日志文件的当前读取位置。具体实现如下:
input { file { type => “apache” path => "apache_access.log" start_position => "beginning" sincedb_path => "/dev/null" }}
type:通过type字段来表示这个日志的类型或者归属等特性,用来进行区分。
path:指定需要监控的文件,可以使用*号来表示某个路径下的所有满足条件的文件。
start_position:默认为”beginning”,表示每次Logstash重启后文件都从头开始加载,直到当前监控的位置。”end”选项表示,每次读取文件都从最后开始,接收当前传输的最新的文件。
sincedb_path:指定.sincedb文件的位置。每次logstash读取数据时会从since_db中记录的pos开始读取数据。如果在重复测试的时候,为了方便,可以将sincedb_path定义为/dev/null,这样logstash每次重启时都会从头开始读取文件。
情景:获取到日志文件后,需要对数据进行提取,最终以key-value字段的形式显示,便于Elasticsearch对数据进行索引,方便后期Kibana生成图表等。
解决方案:
使用filter:grok插件对数据进行提取。因为logstah会根据事件传输的当前时间自动给事件加上@timestamp字段,后续elasticsearch会根据该字段对事件进行排序。如果需要将日志中的事件抽取为@timestamp字段,还需用到filter:date插件。
假设当前日志为log4j打印日志的格式为:%d [%p] [%c{1}] [%t] %30.30C.%M():%L - %m%n
具体实现如下:
filter { if [type] == "log4j" { grok { match=>["message","(?m)%{TIMESTAMP_ISO8601:timestamp}\[%{LOGLEVEL:logLevel}\] \[%{WORD:method}\] \[%{GREEDYDATA:thread}\] %{GREEDYDATA:javaClass}\(\)\:%{NUMBER:line} - {GREEDYDATA:message}"] remove_field => ["@version"] overwrite => [ "message"] } date { match=>[ "timestamp" , "yyyy-MM-dd HH:mm:ss,SSS"] } }}
==:Logstash可以判断值的正确性,所以这里可以对不同类型的事件进行不同的处理而互不影响。
match:用来处理数据,前面一个字段为原始字段名称。logstash支持正则表达式,现有的库中已经可以满足大部分事件。推荐在编写grok时,使用http://grokdebug.herokuapp.com/ 网站来帮助自己检验grok语法。
remove_field:Logstash会根据自己的模板为所有事件加上一些字段,可以用remove_field移除多余的属性。
overwrite:用正则表达式中提取出的字段来替代原始的字段。
date:用日志中抽取出的时间,取代logstash自动生成的时间字段。保证数据的时序性。默认的@timestamp字段为标准时间,不是本地时间。
效果:
输出的原始日志数据为:(数据有删减)
2016-04-15 16:31:13,758 [INFO] [DubboProtocol] [DubboSharedHandler-thread-1] protocol.dubbo.DubboProtocol$1.disconnected():135 - [DUBBO] pid=2535&revision=1.0.1&side=consumer×tamp=1460709070016, dubbo version: sf.2.0.2, current host: 192.168.2.1
经过filter输出的数据为:
{
“message” => “pid=2535&revision=1.0.1&side=consumer×tamp=1460709070016, dubbo version: sf.2.0.2, current host: 192.168.2.1”,
“@timestamp” => “2016-04-15T08:31:13.758Z”,
“host” => “localhost”,
“sequence” => 13112,
“timestamp” => ” 2016-04-15 16:31:13,758”,
“logLevel” => “INFO”,
“method” => “DubboProtocol”
“thread” => “DubboSharedHandler-thread-1”,
“javaClass” => “protocol.dubbo.DubboProtocol$1.disconnected”,
“line” => “135”
}
- 情景:收集Java错误日志时,由于堆栈消息会产生多行数据,每一行消息都被当做单独的事件收集,并且经常grok出错。
解决方案:
Logstash有专门的codec:multiline插件用来处理多行事件。只需要事先约定好特殊的开始符号或者结束符号即可。
具体实现如下:
input { file { type => "java_stack" path =>"apache.log" codec => multiline { pattern => "^%{TIMESTAMP_ISO8601}" negate => true what => "previous" } }}
pattern:约定好的特殊的开始符或者结束符,一般使用正则符号。
negate:是否使用pattern中的正则匹配。
what:表示匹配的位置,previous表示指定行匹配pattern的内容是上一行的内容(开始部分),next指定行匹配pattern选项是下一行的内容(结束部分)。
- 情景:系统使用Log4j打印日志,生成日志文件,但是Grok占用较多系统资源,寻求更高效可靠的解决方法。
解决方案:
1) 使用之前的input:file插件,所有的数据进入message字段。
2) 配置log4j文件,使用Socket通信+input:log4j插件接收事件。
log4j.properties文件配置如下:
log4j.rootLogger=DEBUG, logstash###SocketAppender###log4j.appender.logstash=org.apache.log4j.net.SocketAppenderlog4j.appender.logstash.Port=4560log4j.appender.logstash.RemoteHost=logstash_hostnamelog4j.appender.logstash.ReconnectionDelay=60000log4j.appender.logstash.LocationInfo=true
log4j.xml文件配置如下:
<appender name="LOGSTASH" class="org.apache.log4j.net.SocketAppender"> <param name="RemoteHost" value="logstash_hostname" /> <param name="ReconnectionDelay" value="60000" /> <param name="LocationInfo" value="true" /> <param name="Threshold" value="DEBUG" /></appender><!—将logstash Appender加入到root中 --><root> <level value="INFO"/> <appender-ref ref="OTHERPLACE"/> <appender-ref ref="LOGSTASH"/></root>
logstash配置文件如下:
input { log4j { type => "log4j-json" port => 4560 }}
这样的方法是利用log4j的socket通信,进行数据传输,但是不推荐这样的方法。因为SocketAppender采用最原始的Socket通讯,IO性能较低。存储和发送日志是一个同步过程,有可能会出现打日志的动作堵死应用程序的场景。但是日志手机最基本的要求是不能影响原有系统的运行,所以不推荐这样的方法。
3) 使用jsonevent-layout插件,设置日志格式为Json形式,然后生成到日志文件中,依赖利用input:file插件,同时省略了grok的过程。
首先在pom.xml文件中,加入以下的配置:
<dependency> <groupId>net.logstash.log4j</groupId> <artifactId>jsonevent-layout</artifactId> <version>1.7</version></dependency>
log4j.properties配置如下:
log4j.rootLogger=debug,jsonlog4j.appender.json=org.apache.log4j.DailyRollingFileAppenderlog4j.appender.json.File=app.loglog4j.appender.json.DatePattern=.yyyy-MM-ddlog4j.appender.json.layout=net.logstash.log4j.JSONEventLayoutV1
log4j.xml配置如下:
<appender name="logstah" class="org.apache.log4j.FileAppender"> <param name="Append" value="true" /> <param name="file" value=" app.log " /> <layout class="net.logstash.log4j.JSONEventLayoutV1" /></appender>
打印出来的日志格式为:
{"thread_name":"ZkClient-EventThread-55-10.118.4.1:2181,10.118.4.2:2181,10.118.4.3:2181","message":" [DUBBO] dubbo version: sf.2.0.2, current host: 192.168.2.1","@timestamp":"2016-04-15T07:15:47.794Z","level":"INFO","mdc":{},"file":"AbstractRegistry.java","class":"com.alibaba.dubbo.registry.support.AbstractRegistry","line_number":"422","logger_name":"com.alibaba.dubbo.registry.zookeeper.ZookeeperRegistry","method":"notify","@version":1,"source_host":"localhost"}
经过处理的事件:
{"thread_name":"ZkClient-EventThread-55-10.118.4.1:2181,10.118.4.2:2181,10.118.4.3:2181","message":" [DUBBO] dubbo version: sf.2.0.2, current host: 192.168.2.1","@timestamp":"2016-04-15T07:15:47.794Z","level":"INFO","mdc":{},"file":"AbstractRegistry.java","class":"com.alibaba.dubbo.registry.support.AbstractRegistry","line_number":"422","logger_name":"com.alibaba.dubbo.registry.zookeeper.ZookeeperRegistry","method":"notify","@version":1,"source_host":"localhost","host":"localhost","sequence":968}
综合性能以及可靠性,推荐使用第三种方案,较为简单方便。
- 情景:接收服务器系统日志,使用syslog进行数据传输。
解决方案:
1) logstash使用input:syslog插件,直接接收数据。
具体实现如下:
input { syslog { port => "514" }}
2) 使用input:tcp插件,接收数据再进行grok转化。
input {tcp { port => "8514"}}filter { grok { match => ["message", "%{SYSLOGLINE}" ] } syslog_pri { }}
其实Logstash的syslog插件也就是使用UDPSocket,TCPServer和filter:grok来实现的,所以我们将syslog进行拆分,走TCP通道,并且使用filter多线程的模式来提高性能,所以推荐第二种方式。
- 全方位立体监控之日志解决方案ELK(2)
- 全方位立体监控之日志解决方案ELK(1)
- 全方位立体监控之日志解决方案ELK(3)
- Grafana+Prometheus打造全方位立体监控系统
- ELK日志监控
- elk监控tomcat日志
- ELK日志监控系统搭建
- ELK日志监控系统搭建
- ELK日志监控系统搭建
- 整站优化之全方位立体式
- 自建ELK vs 日志服务(SLS)全方位对比
- ELK+Filebeat集中式日志解决方案(centos7)
- ELK Stack 日志分析监控平台
- ELK实战-Logstash:监控日志文件
- ELK Stack 日志分析监控平台
- ELK实践系列-系统日志监控
- ELK前端日志分析、监控系统
- ELK日志监控可视化图形展示
- iOS开发之理解iOS中的MVC设计模式
- UIButton之ImageEdgeInsets,TitleEdgeInsets详解
- 2016-06-06-1
- 如何使用layer-list做出阴影效果
- 数据库技术分享
- 全方位立体监控之日志解决方案ELK(2)
- ElasticSearch的工作机制
- Linux下离开vim的常见方式
- 【指南】本地如何搭建IPv6环境测试你的APP
- 4种json解析技术对比
- Xcode 插件管理工具Alcatraz 包管理器
- 第十五周程序阅读-范型程序设计(4)
- 一个控制台应用程序,要求用户输入5个大写字母,如果用户输入的不满足要求,提示帮助信息,并重新输入
- Android美工坊--.9.png格式图片的制作与使用--1