需求:我们需要把线上日志收集起来进行分析。在开发阶段,更多的时候程序是运行在本地,所以使用FileBeats就有点繁琐。我们采用直接将日志通过tcp输出到logstash的方案。
同时,我们的日志并没有统一的格式,按照日志分析的需求格式都不一样。比如我们需要监控http请求的日志,监控websocket对话的日志,监控搜索关键词的日志等等。这就需要我们需要根据不同的需求制定各自的格式,然后分开输出到ES数据库。
一、安装ELK
这里对此不作过多讲解。es我使用的是docker版本,logstash的docker版本有点问题,所以最终使用的是rpm版本。
二、配置文件
我们就按照http和ws两种日志来处理。
创建logstash.conf文件,内容如下:
input {
tcp {
mode => "server"
host => "0.0.0.0"
port => 4560
codec => json_lines
}
}
filter {
grok {
match => [
"message","%{NOTSPACE:tag}[T ]%{NOTSPACE:method}[T ]%{NOTSPACE:api}[T ]%{NOTSPACE:params}",
"message","%{NOTSPACE:tag}[T ]%{NOTSPACE:author}[T ]%{NOTSPACE:msg}"
]
}
}
output {
if[tag]=="HTTP"{
elasticsearch {
hosts => ["192.168.0.101:9200"]
index => "logstash-test-http-%{+YYYY.MM.dd}"
}
}
if[tag]=="WS"{
elasticsearch {
hosts => ["192.168.0.101:9200"]
index => "logstash-test-ws-%{+YYYY.MM.dd}"
}
}
}
大致讲解一下:
输入使用tcp插件。
过滤插件grok针对两种日志进行处理,我们设置两个标记HTTP和WS,把这两个值放在message的前边,HTTP日志用空格分成了四段,而WS日志只有三段。
这里要说明的是,日志格式都是简单地使用空格分隔,所以每一段输出的内容就不能带空格,否则解析会出错。如果确实需要空格,则每段信息就需要用符号进行分隔或者包裹,比如方括号。
输出插件根据处理之后的tag字段,按照不同的结构把数据写入到ES不同的index中。
logstash的运行命令
logstash -f /etc/logstash/conf.d/logstash.conf
如果测试完成,可以使用后台运行命令:
nohup logstash -f /etc/logstash/conf.d/logstash.conf >/var/log/logstash.log 2>&1 &
日志文件的位置需要提前创建。
三、Springboot项目
创建一个普通的Springboot项目。
1. 在pom中加入logstash依赖:
net.logstash.logback
logstash-logback-encoder
5.3
2. 在静态资源文件夹下创建logback-spring.xml文件
192.168.0.101:4560
UTC
{
"logLevel": "%level",
"serviceName": "${springAppName:-}",
"pid": "${PID:-}",
"thread": "%thread",
"class": "%logger{40}",
"message": "%message"
}
主要关注LOGSTASH的appender,以及相关的级别设置。
3. yml文件
server:
port: 8011
spring:
application:
name: logstash-test
logging:
level:
com.chris.log: debug
注意日志级别设置,否则日志不能输出。
4.写一个用于测试的接口
@RestController
@RequestMapping("api")
public class TestController {
Logger logger = LoggerFactory.getLogger(TestController.class);
/**
* 测试不同格式的message过滤处理之后写入不同的elasticsearch-index
*
* @param type
* @return
*/
@GetMapping("test")
public Boolean test(int type) {
switch (type) {
case 1:
logger.info("{} {} {} {}", "HTTP", "GET", "/api/test", "none");
break;
case 2:
logger.info("{} {} {} {}", "HTTP", "POST", "/api/test", "天王盖地虎");
break;
case 3:
logger.info("{} {} {}", "WS", "ChenFabao", "我已到达");
break;
default:
logger.info("{} {} {} {}", "HTTP", "GET", "/api/test", "other");
break;
}
return true;
}
}
这里可以看出,第三条ws日志与http日志格式不同。
四、测试
运行起来,调用接口
http://localhost:8011/api/test?type=3
改变参数,刷新ES,可以看到出现了两个不同的index,查看内容,数据得到了正确的解析,结构也有分别。这样就便于我们正确查询和处理线上日志,解决bug。
五、问题
由于是临时方案,也遇到一个问题。用例是,应用程序修改了一点代码,然后重新运行,这时logstash就会报Connection reset by peer的错误,意思是tcp链接出现了问题。目前研究得比较浅,不知道怎么处理。看来如果需要在线上收集日志而不出现这个问题,还是借用FileBeats中转一下比较好,或者使用file输入插件读取日志文件来输入。