ELK日志分析平台环境搭建

前一篇博客讲到Elasticsearch的基本概念以及安装步骤,此篇为拓展篇,讲的是ELK日志分析系统。为什么需要这个日志分析的平台呢?
当一个项目越发复杂、业务扩展越大时,业务系统的拆分对于运维、排错等都是相当庞大的任务,发现错误或者流量高峰负载过大等问题时,很难收集到各微服务系统的日志信息,及时捕捉采取相应措施。而ELK的出现,刚好是解决了这个问题,它可以将所有的日志进行统一收集,然后呈现在平台上,通过具体的索引->查找对应的日志信息。

那什么是ELK?

  • Elasticsearch 是个开源分布式搜索引擎,它的特点有:分布式,零配置,自动发现,索引自动分片,索引副本机制,restful 风格接口,多数据源,自动搜索负载等。
  • Logstash 是一个完全开源的工具,他可以对你的日志进行收集、过滤,并将其存储供以后使用(如,搜索)。
  • Kibana 也是一个开源和免费的工具,它 Kibana 可以为 Logstash 和 ElasticSearch 提供的日志分析友好的 Web 界面,可以帮助您汇总、分析和搜索重要数据日志。

  • 整个过程: logstash读取日志信息->存入到elasticsearch中->kibana展示信息

安装步骤

官方下载地址:https://www.elastic.co/downloads/

注意:由于不同版本会导致一系列问题,而且问题查找难度较高,所以建议大家在安装ELK时,尽量使用同一个版本,这里均使用 6.2.4版本

  • elasticsearch的安装请参照前一篇博客

Logstash 安装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
在 /usr/local 目录下解压:

tar -zxvf logstash-6.2.4.tar.gz

#更改文件夹名称
mv logstash-6.2.4 logstash

进入解压后的目录:

cd /usr/local/logstash/bin

新增配置文件:

vim logstash.conf

增加:

input{
file{
# 此处是指定输入的文件
path => ["/var/log/*.log"]
}
}

output{
#指明输出的elasticsearch,日志索引名称
elasticsearch{
hosts => ["localhost:9200"]
index => "logstash-log"
}
}

启动logstash:

1
2
3
在 /usr/local/logstash/bin 目录下运行:

./logstash -f logstash.conf

安装kibana

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
解压:

tar -zxvf kibana-6.2.4-linux-x86_64.tar.gz

cd /usr/local/kibana/

若只使用本地单机,不需要配置以下内容,若使用其他服务器,则配置:

修改配置文件 config/kibana.yml 如下:

Server.host //配置机器ip/hostname

Server.name //此kibana服务的名称

elasticsearch.url //es master节点url

Kibana启动方式:

1
2
3
在 /usr/local/kibana/bin 目录下运行:

./kibana

在浏览器中打开 localhost:5601即可登录kibana

在左侧Management中进行索引创建Index Patterns如下图:


图

点击页面右下方的next按钮,会跳转到下一个页面,在此页面还需要选择一个时间维度,如下图所示


图

在此点击下一步,便创建kibana的索引完成,此时再次点击左侧导航栏的Discover链接,便可以看到刚才创建索引的一些视图,如下图所示


图

在Discover即可查看到对应的日志信息,在图中有一个input输入框,笔者可以在里面填写筛选所需要的关键词;如果没有筛选出结果,也可检查左侧的时间筛选项是否设置正确,如笔者的时间筛选项设置的是Today,也就代表筛选当天的数据。

ELK的整体操作流程比较简单,首先是logstash收集各种日志并进行过滤,然后将过滤后的内容发送到ES服务中,最后用户通过Kibana的页面查看ES中的日志数据;

Logstash不同情况下的配置

Nginx–>Logstash

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
input {
file {
type => "nginx_access"
path => ["/usr/local/nginx/logs/*.log"]
exclude => ["*.gz","error.log","nginx.pid"]
sincedb_path => "/dev/null"
codec => "json"
}
}

output {
stdout {}
elasticsearch {
cluster => "elasticsearch"
codec => "json"
protocol => "http"
}
}

然后在nginx启动之前,我们需要先修改一下nginx的配置文件(nginx.conf):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
log_format   json  '{"@timestamp":"$time_iso8601",'
'"@source":"$server_addr",'
'"@nginx_fields":{'
'"client":"$remote_addr",'
'"size":$body_bytes_sent,'
'"responsetime":"$request_time",'
'"upstreamtime":"$upstream_response_time",'
'"upstreamaddr":"$upstream_addr",'
'"request_method":"$request_method",'
'"domain":"$host",'
'"url":"$uri",'
'"http_user_agent":"$http_user_agent",'
'"status":$status,'
'"x_forwarded_for":"$http_x_forwarded_for"'
'}'
'}';

access_log logs/access.log json;

这部分是为了logstash读取到的文件进行格式化,启动nginx后,浏览器访问nginx下的页面,你会看到kibana中的对应更新。

Tomcat–>Logstash

tomcat的日志比nginx要复杂一些,打开对应的日志文件(catalina.out),你会发现类似下面这样的日志结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
Jun 12, 2014 11:17:34 AM org.apache.catalina.core.AprLifecycleListener init
INFO: The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: /usr/java/packages/lib/amd64:/usr/lib64:/lib64:/lib:/usr/lib
Jun 12, 2014 11:17:34 AM org.apache.coyote.AbstractProtocol init
INFO: Initializing ProtocolHandler ["http-bio-8080"]
Jun 12, 2014 11:17:34 AM org.apache.coyote.AbstractProtocol init
SEVERE: Failed to initialize end point associated with ProtocolHandler ["http-bio-8080"]
java.net.BindException: Address already in use <null>:8080
at org.apache.tomcat.util.net.JIoEndpoint.bind(JIoEndpoint.java:411)
at org.apache.tomcat.util.net.AbstractEndpoint.init(AbstractEndpoint.java:640)
at org.apache.coyote.AbstractProtocol.init(AbstractProtocol.java:434)
at org.apache.coyote.http11.AbstractHttp11JsseProtocol.init(AbstractHttp11JsseProtocol.java:119)
at org.apache.catalina.connector.Connector.initInternal(Connector.java:978)
at org.apache.catalina.util.LifecycleBase.init(LifecycleBase.java:102)
at org.apache.catalina.core.StandardService.initInternal(StandardService.java:559)
at org.apache.catalina.util.LifecycleBase.init(LifecycleBase.java:102)
at org.apache.catalina.core.StandardServer.initInternal(StandardServer.java:813)
at org.apache.catalina.util.LifecycleBase.init(LifecycleBase.java:102)
at org.apache.catalina.startup.Catalina.load(Catalina.java:638)
at org.apache.catalina.startup.Catalina.load(Catalina.java:663)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.apache.catalina.startup.Bootstrap.load(Bootstrap.java:280)
at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:454)
Caused by: java.net.BindException: Address already in use
at java.net.PlainSocketImpl.socketBind(Native Method)
at java.net.AbstractPlainSocketImpl.bind(AbstractPlainSocketImpl.java:376)
at java.net.ServerSocket.bind(ServerSocket.java:376)
at java.net.ServerSocket.<init>(ServerSocket.java:237)
at java.net.ServerSocket.<init>(ServerSocket.java:181)
at org.apache.tomcat.util.net.DefaultServerSocketFactory.createSocket(DefaultServerSocketFactory.java:49)
at org.apache.tomcat.util.net.JIoEndpoint.bind(JIoEndpoint.java:398)
... 17 more

这样格式的日志输出并不友好,logstash提供了强大的插件来帮助我们解析各种各样的日志输出结构,分析一下可以得出,日志结构是:时间戳,后面跟着类名,再后面跟着日志信息,这样,我们就可以根据这种结构来写过滤规则:

1
2
3
4
5
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}

CATALINA_DATESTAMP %{MONTH} %{MONTHDAY}, 20%{YEAR} %{HOUR}:?%{MINUTE}(?::?%{SECOND}) (?:AM|PM)
CATALINALOG %{CATALINA_DATESTAMP:timestamp} %{JAVACLASS:class} %{JAVALOGMESSAGE:logmessage}

将这部分配置写到一个grok-patterns文件中,在logstash安装目录下,

1
2
3
4
5
cd /usr/local/logstash/

mkdir patterns

vim grok-patterns

再进行修改logstash的配置文件 logstash.conf:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
input {
file {
type => "tomcat_access"
path => ["/usr/local/tomcat/logs/catalina.out"]
exclude => ["*.log","*.txt"]
sincedb_path => "/dev/null"
start_position => "beginning"
}
file {
type => "apache_access"
path => ["/usr/local/tomcat/logs/*.txt"]
exclude => ["*.log"]
sincedb_path => "/dev/null"
start_position => "beginning"
}
}

filter {
if [type] == "tomcat_access" {
multiline {
patterns_dir => "/usr/local/logstash/patterns"
pattern => "(^%{CATALINA_DATESTAMP})"
negate => true
what => "previous"
}
if "_grokparsefailure" in [tags] {
drop { }
}
grok {
patterns_dir => "/usr/local/logstash/patterns"
match => [ "message", "%{CATALINALOG}" ]
}
date {
match => [ "timestamp", "yyyy-MM-dd HH:mm:ss,SSS Z", "MMM dd, yyyy HH:mm:ss a" ]
}
}
if [type] == "apache" {
grok {
patterns_dir => "/usr/local/logstash/patterns"
match => { "message" => "%{COMBINEDAPACHELOG}" }
}
date {
match => [ "timestamp", "dd/MMM/yyyy:HH:mm:ss Z" ]
}
}
}

output {
stdout {}
elasticsearch {
cluster => "elasticsearch"
protocol => "http"
embedded => true
}
}

然后你就可以重启一下logstash看结果啦。注意这里,我配置的是start_position => “beginning”,字面意思就是从日志文件头部开始解析,这样可以把一些原始日志给收集过来,但是可能会造成一些重复日志~~

Log4j–>Logstash

通过上面两个场景可以大致知道这个流程,就是指定好要监控的日志文件(input),然后解析对应的格式(filter),然后导入到对应的存储中(output),而且整个过程是管道化的,前面提到了,由于咱们的测试环境是单机本地化,所以并没有使用消息队列,否则你会感受到更明显的管道化风格。

把log4j产生的日志导入到logstash要做的事儿依然如此,不过官方提供了更简单的方式:log4j-jsonevent-layout,这玩意儿的作用相当于我们在nginx中干的事儿,直接将log4j的日志格式定义成json的,有助于性能提升~

剩下的事儿就是老样子了,只需要改一下我们的logstash配置文件即可:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
input {
file {
type => "log4j"
path => ["/usr/local/tomcat/logs/logTest.log"]
sincedb_path => "/dev/null"
start_position => "beginning"
}
}

output {
stdout {}
elasticsearch {
cluster => "elasticsearch"
codec => "json"
protocol => "http"
}
}

到此,基本流程就讲完了,此过程中会有些坑,比如logstash启动报错的问题等等,
根据提示信息一般都能找到对应的解决办法。比如:multiline-filter插件的安装。

上面的场景和简单介绍都是非常入门级的,放在线上场景中肯定太粗糙了,肯定还需要考量更多的因素,例如数据量,日志大小,通信方式等,不过我相信到现在大家应该对ELK有了一个基本的认知。

-------------本文结束感谢您的阅读-------------
0%