Files
baim0-learn/elk/13【案例】通过ELK收集Tomcat访问日志和状态日志.md
T
2024-03-09 13:38:35 +08:00

14 KiB

13【案例】通过ELK收集Tomcat访问日志和状态日志

1、tomcat日志解析

对tomcat的日志监控和分析主要有有两种类型,分别是访问日志(localhost_access_log.Y-M-D.txt)和运行状态日志(catalina.out),其中,访问日志记录访问的时间,IP,访问的资料等相关信息,catalina.out其实记录了tomcat的标准输出(stdout)和标准出错(stderr),这是在tomcat的启动脚本里指定的,默认情况下stdout和stderr都会重定向到这里。所以可以在应用里使用System.out打印的东西都会输出到这里来。此文件对监控tomcat的运行状态非常重要。

在企业具体的运维监控中,对访问日志的监控主要是看访问量,访问来源等信息,因此,这部分日志输出可以入到elasticsearch中,然后在Kibana中展示分析,而对catalina.out文件的监控,主要是监控日志中是否有错误、告警等信息,如果监控到有类似信息,那么就进行告警,因此对catalina.out文件的日志收集,需要过滤关键字,然后输出到zabbix进行告警。

下面就开始对tomcat两种不同类型的日志进行收集、过滤和告警设置。

2、配置tomcat的访问日志和catalina.out文件

2.1、配置访问日志(localhost_access_log.Y-M-D.txt)输出为JSON格式

要配置访问日志文件的输出格式,需要修改tomcat的server.xml文件,这里以tomcat8.5.30为例,打开server.xml,找到如下内容:

    <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
           prefix="localhost_access_log" suffix=".txt"
           pattern="%h %l %u %t "%r" %s %b" />

将此内容修改为如下配置:

    <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
           prefix="localhost_access_log" suffix=".log"
           pattern="{"client":"%h",  "client user":"%l",   "authenticated":"%u",   "access time":"%t",     "method":"%r",   "status":"%s",  "send bytes":"%b",  "Query?string":"%q",  "partner":"%{Referer}i",  "Agent version":"%{User-Agent}i"}"/>

介绍下出现的一些参数的含义:

directory:日志文件存放的目录。通常设置为tomcat下已有的那个logs文件。
prefix:日志文件的名称前缀。
suffix :日志文件的名称后缀。
pattern:比较重要的一个参数。下面列出这个参数常用的选项和含义:

%a   这是记录访问者的IP,在日志里是127.0.0.1
%A   这是记录本地服务器的IP。
%b   发送信息的字节数,不包括http头,如果字节数为0的话,显示为“-”
%B   发送信息的字节数,不包括http头。
%h   服务器的名称。如果resolveHosts为false的话,这里就是IP地址
%H   访问者的协议
%l   记录浏览者进行身份验证时提供的名称
%m   访问的方式,是GET还是POST
%p   本地接收访问的端口 
%q   比如你访问的是aaa.jsp?bbb=ccc,那么这里就显示?bbb=ccc,表示query string的意思
%r   请求的方法和URL
%s   http的响应状态码 
%S   用户的session ID,每次都会生成不同的session ID
%t   请求时间
%u   得到了验证的访问者,否则就是"-"
%U   访问的URI地址
%v   服务器名称
%D  请求消耗的时间,以毫秒记
%T   请求消耗的时间,以秒记

配置完成后,重启tomcat,可以查看tomcat的访问日志是否输出了json格式,如下所示:

{"client":"172.16.213.132",  "client user":"-",   "authenticated":"-",   "access time":"[13/Sep/2018:19:01:09 +0800]",     "method":"GET /docs/jndi-datasource-examples-howto.html HTTP/1.1",   "status":"200",  "send bytes":"-",  "Query?string":"",  "partner":"http://172.16.213.233:8080/",  "Agent version":"Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36"}
{"client":"172.16.213.132",  "client user":"-",   "authenticated":"-",   "access time":"[13/Sep/2018:19:01:09 +0800]",     "method":"GET /docs/jndi-datasource-examples-howto.html HTTP/1.1",   "status":"200",  "send bytes":"35230",  "Query?string":"",  "partner":"http://172.16.213.233:8080/",  "Agent version":"Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36"}
{"client":"172.16.213.132",  "client user":"-",   "authenticated":"-",   "access time":"[13/Sep/2018:19:01:10 +0800]",     "method":"GET /favicon.ico HTTP/1.1",   "status":"200",  "send bytes":"21630",  "Query?string":"",  "partner":"http://172.16.213.233:8080/docs/jndi-datasource-examples-howto.html",  "Agent version":"Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36"}

简单整理一下,输出的json格式如下:

{
    "client": "172.16.213.132",
    "client user": "-",
    "authenticated": "-",
    "access time": "[13/Sep/2018:19:01:09 +0800]",
    "method": "GET /docs/jndi-datasource-examples-howto.html HTTP/1.1",
    "status": "200",
    "send bytes": "-",
    "Query?string": "",
    "partner": "http://172.16.213.233:8080/",
    "Agent version": "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36"
}

2.2、配置tomcat的catalina.out文件

默认情况下,tomcat8.5版本中catalina.out文件的输出格式如下:

17-Sep-2018 15:57:10.387 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["http-nio-8080"]
17-Sep-2018 15:57:10.425 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["ajp-nio-8009"]
17-Sep-2018 15:57:10.443 INFO [main] org.apache.catalina.startup.Catalina.start Server startup in 31377 ms

在这个日志中,时间字段输出不是很友好,我们需要修改下时间自动的输出为类似“2018-09-17 15:57:10.387”这种格式,要修改catalina.out的时间输出字段,需要修改logging.properties文件,此文件位于tomcat配置文件目录conf下,打开此文件,添加如下内容:

1catalina.org.apache.juli.AsyncFileHandler.formatter = java.util.logging.SimpleFormatter
java.util.logging.SimpleFormatter.format = %1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS.%1$tL [%4$s] [%3$s] %2$s %5$s %6$s%n

同时删除如下行:

java.util.logging.ConsoleHandler.formatter = org.apache.juli.OneLineFormatter

这样,catalina.out文件输出的时间字段就变成比较友好的格式了,如下图所示:

2018-09-17 16:03:56.540 [INFO] [org.apache.coyote.http11.Http11NioProtocol] org.apache.coyote.AbstractProtocol start Starting ProtocolHandler ["http-nio-8080"] 
2018-09-17 16:03:56.582 [INFO] [org.apache.coyote.ajp.AjpNioProtocol] org.apache.coyote.AbstractProtocol start Starting ProtocolHandler ["ajp-nio-8009"] 
2018-09-17 16:03:56.602 [INFO] [org.apache.catalina.startup.Catalina] org.apache.catalina.startup.Catalina start Server startup in 41372 ms 

对于catalina.out文件的内容,我们只需要过滤出来四个字段即可,分别是时间字段、日志输出级别字段、异常信息字段以及运行状态内容字段,对上面的日志信息,通过logstash的grok插件进行过滤,可以很方便的取出这四个字段,登录http://grokdebug.herokuapp.com/ ,然后今天在线调试,可以很轻松得出过滤规则:

%{TIMESTAMP_ISO8601:access_time}\s+\[%{LOGLEVEL:loglevel}\]\s+\[%{DATA:exception_info}\](?<tomcatcontent>[\s\S]*)

其中,access_time取的是时间字段、loglevel取的是日志输出级别字段、exception_info取的是异常信息字段,tomcatcontent取的是运行状态字段。

3、配置filebeat

在tomcat所在的服务器(172.16.213.233)上安装filebeat,然后配置filebeat,配置好的filebeat.yml文件内容如下:

filebeat.inputs:
- type: log
  enabled: true
  paths:
   - /usr/local/tomcat/logs/localhost_access_log.2018-09*.txt       #这是tomcat的访问日志文件
  fields:
    log_topic: tomcatlogs       #这是新增的字段,用于后面的kafka的topic,其实是对tomcat访问日志文件分类

- type: log
  enabled: true
  paths:
   - /usr/local/tomcat/logs/catalina.out        #这是定义的第二个tomcat日志文件catalina.out,注意写的格式。
  fields:
    log_topic: tomcatlogs_catalina      #这是新增的字段,用于后面的kafka的topic,专门用于存储catalina.out日志文件

processors:
 - drop_fields:
    fields: ["beat", "input", "source", "offset", "prospector"]
filebeat.config.modules:
  path: ${path.config}/modules.d/*.yml
  reload.enabled: false

name: 172.16.213.233
output.kafka:
  enabled: true
  hosts: ["172.16.213.51:9092", "172.16.213.75:9092", "172.16.213.109:9092"]
  version: "0.10"
  topic: '%{[fields.log_topic]}'    #这是指定topic,注意写法,上面新增了两个字段,两个对应的日志文件会分别写入不同的topic
  partition.round_robin:
    reachable_only: true
  worker: 2
  required_acks: 1
  compression: gzip
  max_message_bytes: 10000000
logging.level: debug

配置文件编写好后,启动filebeat服务即可:

[root@filebeat232 ~]# cd /usr/local/filebeat
[root@filebeat232 filebeat]#nohup ./filebeat  -e -c filebeat.yml & 

4、通过Logstash的grok插件过滤、分析配置tomcat日志

Logstash服务部署在172.16.213.120服务器上,下面给出Logstash事件配置文件,命名为kafka_tomcat_into_es.conf,内容如下:

input { #这里定义了两个消费topic,分别读取的是tomcat的访问日志和catalina.out文件
        kafka {
        bootstrap_servers => "172.16.213.51:9092,172.16.213.75:9092,172.16.213.109:9092"
        topics => ["tomcatlogs"]    
        codec => "json"
        }
        kafka {
        bootstrap_servers => "172.16.213.51:9092,172.16.213.75:9092,172.16.213.109:9092"
        topics => ["tomcatlogs_catalina"]
        codec => "json"
        }
}

filter {
    if [fields][log_topic] == "tomcatlogs_catalina" {   #判断语句,根据topic不同,对日志做不同的过滤、分析,先分析的是catalina.out文件
             mutate {
             add_field => [ "[zabbix_key]", "tomcatlogs_catalina" ]
             add_field => [ "[zabbix_host]", "%{[host][name]}" ]
             }
    grok {
             match => { "message" => "%{TIMESTAMP_ISO8601:access_time}\s+\[(?<loglevel>[\s\S]*)\]\s+\[%{DATA:exception_info}\](?<tomcatcontent>[\s\S]*)" }
        }
        date {
                match => [ "access_time","MMM  d HH:mm:ss", "MMM dd HH:mm:ss", "ISO8601"]
        }
        mutate {
            remove_field => "@version"
            remove_field => "message"
            #remove_field => "[fields][log_topic]"
            #remove_field => "fields"
            remove_field => "access_time"
        }

   }
   if [fields][log_topic] == "tomcatlogs" {     #判断语句,根据topic不同,对日志做不同的过滤、分析,这里分析的是访问日志文件
     json {
        source => "message"     #由于访问日志文件已经是json格式,所以这里解码出来即可
      }
    date {
    match => [ "access time" , "[dd/MMM/yyyy:HH:mm:ss Z]" ] #时间字段转换,然后赋值给@timestamp字段
       }
    mutate {
            remove_field => "@version"      #删除不需要的字段
            remove_field => "message"
     }
  }
}

output {
        if [fields][log_topic] == "tomcatlogs_catalina" {       #输出判断,根据不同的topic,做不同的输出设置
          if ([loglevel] =~ "INFO"  or [tomcatcontent] =~ /(Exception|error|ERROR|Failed)/ ) {   #对catalina.out文件出现前面指定的关键字,就过滤出来,然后告警
              zabbix {
                        zabbix_host => "[zabbix_host]"
                        zabbix_key => "[zabbix_key]"
                        zabbix_server_host => "172.16.213.140"
                        zabbix_server_port => "10051"
                        zabbix_value => "tomcatcontent" #这是输出到zabbix的内容配置
                        }
                    }
        }
       if [fields][log_topic] == "tomcatlogs" {     #输出判断,根据不同的topic,做不同的输出设置,这是将访问日志输出到elasticsearch集群
         elasticsearch {
           hosts => ["172.16.213.37:9200","172.16.213.77:9200","172.16.213.78:9200"]
           index => "tomcatlogs-%{+YYYY.MM.dd}"
             }
       }
       stdout { codec => rubydebug }    #调试模式,可以方便观看日志输出是否正常,调试完成后,删除即可
}

这个配置文件稍微复杂,将两个topic的日志分别做了不同处理,将catalina.out文件首先进行grok分割,然后进行关键字过滤,如果输出指定关键字,那么将和zabbix进行联动,发出告警;

接着,将tomcat的访问日志进行简单过滤后,直接输出到 elasticsearch集群,最后在Kibana进行展示。

5、配置zabbix输出并告警

登录zabbix web平台,首先创建一个模板logstash-output-zabbix,然后在此模块下创建一个监控项,如下图所示:

最后,要实现监控、告警,还需要创建一个触发器,进入刚刚创建好的模板中,创建一个触发器,如下图所示:

这个触发器的含义是:如果收到logstash发送过来的数据就进行告警,或者说接收到的数据大于0就告警。

可以模拟产生一些包含上面关键字的日志信息,然后观察是否会进行告警。

6、Kibana平台创建tomcat访问日志索引

tomcat日志的索引名称为tomcatlogs-%{+YYYY.MM.dd},登录Kibana,选择创建索引,然后添加索引名tomcatlogs-*,然后按照时间添加排序规则,即可完成访问日志索引创建,然后到discover查看日志,如果日志输出正常,即可看到访问日志,如下图所示:

至此,ELK收集tomcat日志完成。