logstash+logback收集spring boot日志

    项目上线都已经有一段了时间,新的功能在不断上,bug也随着时间慢慢浮现。令人差异的是,每次出现bug都是用户发现的,虽然开发迭代的版主里,一直都没有测试跟着我们走,但是让用户去发现bug实在有点说不过了。在项目初期我用backlog做了info,error文件切分,但是每次看日志都是要用head | more这些命令去看,而且效率也很慢。没这么多时间天天去看error.log。业界做日志处理都是用elk,自己从零开始琢磨到构建完成,一点点心得分享出来,也当作一次学习笔记。

   Logstash介绍

《logstash+logback收集spring boot日志》

Logstash 是开源的服务器端数据处理管道,能够同时 从多个来源采集数据、转换数据,然后将数据发送到您最喜欢的 “存储库” 中。

图片的上部分可以理解为:logstash各种输入源input ,可以从日志文件追加的形式,就像linux tail -f 命令将日志添加进来,或者开启tcp端口,监听文件传输(我就是用这种方法收集),udp方法等等,这些都是基于插件完成的。中间圆形的就是logstash的核心,也是功能最强大的地方filter,可以将日志进行切分,过滤,类型转换。下面想想都知道是输出output,把处理好日志放到elasticsearch,或者redis,mongodb等等都是可以的。

   安装启动Logstash

在下载之前请确认电脑是否安装了java,logstash5.0之后的版本好像都需要1.8以上的支持,没有的话,最好装一个jdk1.8。下载地址 点击logstash选择相应的版本即可,下载完成后解压文件后,使用cmd进入解压的目录/bin

《logstash+logback收集spring boot日志》 测试是否安装成功  logstash -e ‘input { stdin { } } output { stdout {} }’

如果看见下面信息 9600端口启动了,说明logstash启动成功,网上有些教程是:logstash -e  ‘input { stdin { } } output { stdout { codec => rubydebug } }’在我的电脑上没有用,这个命令在高版本没用

《logstash+logback收集spring boot日志》

springboot logback配合

要使用logback一个插件来将数据转成json,引入maven配置

<dependency>

      <groupId>net.logstash.logback</groupId>

      <artifactId>logstash-logback-encoder</artifactId>

     <version>4.10</version>

</dependency>

在springboot的resource创建logback.xml文件

<xml version=”1.0″ encoding=”UTF-8″?>

    <configuration scan=”true” scanPeriod=”60 seconds” debug=”true”>

         <contextName>logstash-test</contextName>

   <!– 这个是控制台日志输出格式 方便调试对比—>

    <appender name=”console” class=”ch.qos.logback.core.ConsoleAppender”>

      <encoder>

          <pattern>%d{yyyy-MM-dd HH:mm:ss} %contextName %-5level %logger{50} -%msg%n</pattern>

   </encoder>

</appender>

<appender name=”stash” class=”net.logstash.logback.appender.LogstashTcpSocketAppender”>

  <destination>localhost:8888</destination> 这是是logstash服务器地址 端口

  <encoder class=”net.logstash.logback.encoder.LogstashEncoder” /> 输出的格式,推荐使用这个

</appender>

<root level=”info”>

   <appender-ref ref=”console”/>

   <appender-ref ref=”stash”/>

</root>

启动项目,就会请求localhost:8888,如果有监听,就会自动发送日志。

logstash配置

input {

             tcp {

                        host => “localhost” #这个一定要是logstash本机ip,不然logstash 无法启动,也可以去除

                        port => 8888

                       codec => json_lines

                       mode => “server”

                  }

}

filter {

                 grok {

               match => {

“message” => “%{URIPATH:request} %{IP:clientip} %{NUMBER:response:int} \”%{WORD:sources}\” (?:%{URI:referrer}|-) \[%{GREEDYDATA:agent}\] \{%{GREEDYDATA:params}\}”

     }

}

geoip { #利用geoLite数据库,将ip转成经纬度

            source => [“clientip”]

           database => “E:/java_software/logstash-5.4.0/config/GeoLite2-City.mmdb” }

           mutate { remove_field => [“port”,”@version”,”level_value”]

      }

}

output {

       stdout { codec => rubydebug } #标准输出,在命令行中输出方便调试

elasticsearch { hosts => [ “localhost:9200” ]

index => “pybbs”

document_type => “weblog”

    }

}

大家看见这个配置文件都是一头雾水吧!主要重点在于filter grok。Grok是将非结构化日志数据解析为结构化和可查询的好方法。

这个工具非常适合syslog日志,apache和其他web服务器日志,mysql日志,以及通常为人类而不是计算机消耗的任何日志格式。

默认情况下,Logstash附带约120个模式。你可以在这里找到它们:https://github.com/logstash-plugins/logstash-patterns-core/tree/master/patterns

Grok通过将文本模式组合成与日志匹配的东西来工作。

grok模式的语法是%{SYNTAX:SEMANTIC}

这SYNTAX是与您的文字相匹配的图案的名称。例如,3.44将被匹配的NUMBER模式,55.3.244.1并将被匹配的IP模式。语法是你如何匹配。

这SEMANTIC是你给正在匹配的文本的标识符。例如,3.44可能是一个事件的持续时间,所以你可以简单地调用它duration。此外,一个字符串55.3.244.1可能会识别client发出请求。

对于上面的例子,你的Grok过滤器看起来像这样:

%{NUMBER:response}%{IP:clientIp}

或者,您可以将数据类型转换添加到您的grok模式。默认情况下,所有的语义都保存为字符串。如果您希望转换语义的数据类型,例如将字符串更改为整数,则将其后缀与目标数据类型。例如%{NUMBER:num:int},将num语义从一个字符串转换为一个整数。目前唯一支持的转换是int和float。

例子:用这个语法和语义的思想,我们可以从一个样本日志中抽出有用的字段,就像这个虚构的http请求日志:

55.3.244.1 GET /index.html 15824 0.043

这种模式可能是:

%{IP:client} %{WORD:method} %{URIPATHPARAM:request} %{NUMBER:bytes}%{NUMBER:duration}

一个更现实的例子,让我们从文件中读取这些日志:

input {

      file { path => “/var/log/http.log” }

}

filter {

grok {

match => { “message” => “%{IP:client} %{WORD:method} %{URIPATHPARAM:request} %{NUMBER:bytes} %{NUMBER:duration}”

   }

}

}

在grok过滤器之后,会将行日志转化成json格式

client: 55.3.244.1,

method: GET,

request: /index.html,

bytes: 15824,

duration: 0.043,

在调试的过程中,不要一次性把全部的日志打出来,一次性将grok的表达式写出来,如果有一个写错的话,日志切分失败,错误很难排查出来。建议每一个一个字段地添加测试,比较快上手。对于一些特别长的字符串尽量是一些特殊字符包裹起来,比如使用

[“User-agent”]

这样会让gork表达式比较容易匹配

这个是我自己摸索出来日志格式,对应上面gork message

log.info(“{} {} {} \”{}\” {} [{}] {}”,request.getRequestURI(),IpUtil.getIpAddr(request),executionTime,value,request.getHeader(“Referer”),request.getHeader(“User-Agent”),“(请求参数)”);

打印的信息从左往右分别是:uri,客户端ip,请求执行时间,日志来源,Referer,User-Agent,我这样摆放是多次实验成果,得出最好方法。像uri,客户端Ip这种比较容易匹配放在前面,这些信息不容易为空,保证日志切分不会失效,像请求参数这些可能为空的字段,一定要放在最后,即使为空了,也不会影响整条日志切分。注意当Referer,User-Agent为空的情况下,会导致整条日志切分失败,在打印日志之前,最好做一下非空处理。

在调试这个logstash过程,我都是参考logstash gork nginx日志格式来写的。

nginx日志:

08/Jan/2016:08:27:43 +0800 – 10.10.6.212:8088 10.10.6.110:80 GET /vvv/te/stat/indexproptype=11&level=2&srtype=2&city=dzion=XJ&begindate=2016-01-08&enddate=2016-01-08&apiKey=c2c959b203d669a9a21861379cb4523c&test=2 – 10.10.6.10 HTTP/1.1 [Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.99 Safari/537.36] [JSESSIONID=kq3v6xi2b74j1a9yxvfvcq131] www.test.cn www.test.com 200 0 0 485 209 0″-” 1.642 1.642

对应的grok表达式

NGINXACCESS %{HTTPDATE:timestamp} – (?:%{HOSTPORT:upstream}|-) %{HOSTPORT:request_server} %{WORD:request_method} %{URIPATH:uri} %{URIPARAM1:args} – %{IP:clientip} HTTP/%{NUMBER:httpversion} \[%{GREEDYDATA:agent}\] \[%{GREEDYDATA:cookie}\] (?:%{REFER:referrer}|-) %{HOSTNAME:domain} %{NUMBER:status:int} 0 0 %{NUMBER:body_sent:int} %{NUMBER:request_length:int} 0\”(?:%{WORD:cache_status}|-)\”

最后copy从别人的帖子分享grok参数含义

常用表达式

USERNAME 或 USER

用户名,由数字、大小写及特殊字符(._-)组成的字符串

比如:1234、Bob、Alex.Wong等

EMAILLOCALPART

电子邮件用户名部分,首位由大小写字母组成,其他位由数字、大小写及特殊字符(_.+-=:)组成的字符串。注意,国内的QQ纯数字邮箱账号是无法匹配的,需要修改正则

比如:stone、Gary_Lu、abc-123等

EMAILADDRESS

电子邮件

比如:stone@abc.com、Gary_Lu@gmail.com、abc-123@163.com等

HTTPDUSER

Apache服务器的用户,可以是EMAILADDRESS或USERNAME

INT

整数,包括0和正负整数

比如:0、-123、43987等

BASE10NUM 或 NUMBER

十进制数字,包括整数和小数

比如:0、18、5.23等

BASE16NUM

十六进制数字,整数

比如:0x0045fa2d、-0x3F8709等

BASE16FLOAT

十六进制数字,整数和小数

WORD

字符串,包括数字和大小写字母

比如:String、3529345、ILoveYou等

NOTSPACE

不带任何空格的字符串

SPACE

空格字符串

QUOTEDSTRING 或 QS

带引号的字符串

比如:”This is an apple”、’What is your name?’等

UUID

标准UUID

比如:550E8400-E29B-11D4-A716-446655440000

MAC

MAC地址,可以是Cisco设备里的MAC地址,也可以是通用或者Windows系统的MAC地址

IP

IP地址,IPv4或IPv6地址

比如:127.0.0.1、FE80:0000:0000:0000:AAAA:0000:00C2:0002等

HOSTNAME

主机名称

IPORHOST

IP或者主机名称

HOSTPORT

主机名(IP)+端口

比如:127.0.0.1:3306、api.stozen.net:8000等

PATH

路径,Unix系统或者Windows系统里的路径格式

比如:/usr/local/nginx/sbin/nginx、c:\windows\system32\clr.exe等

URIPROTO

URI协议

比如:http、ftp等

URIHOST

URI主机

比如:www.stozen.net、10.0.0.1:22等

URIPATH

URI路径

比如://www.stozen.net/abc/、/api.php等

URIPARAM

URI里的GET参数

比如:?a=1&b=2&c=3

URIPATHPARAM

URI路径+GET参数

比如://www.stozen.net/abc/api.php?a=1&b=2&c=3

URI

完整的URI

比如:http://www.stozen.net/abc/api.php?a=1&b=2&c=3

日期时间表达式

MONTH

月份名称

比如:Jan、January等

MONTHNUM

月份数字

比如:03、9、12等

MONTHDAY

日期数字

比如:03、9、31等

DAY

星期几名称

比如:Mon、Monday等

YEAR

年份数字

HOUR

小时数字

MINUTE

分钟数字

SECOND

秒数字

TIME

时间

    原文作者:神易风
    原文地址: https://www.jianshu.com/p/9170a7a65dd4
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞