Docker ELK实践之Logstash

前言

日志这个东西在日常开发中起了很重要的作用。当你的服务部署到服务器上去,报了出了你意想不到的的错误,然后通过ssh去连接服务器查看日志,还要使用grep语句等查找语句,如果是直接部署到服务器还好,但是部署到Docker上面的话,那查看日志就更加麻烦了。所以为了方便,能快速找到报出异常的日志,搭建ELK平台是十分重要的。

本文先讲解Logstash的搭建,Logstash的主要作用是解析日志。

日志统一

能快速定位错误日志的前提是,正确的打日志。为了方便我们解析日志,我们所有的项目需要统一日志格式。

在我们项目中,我们统一用logback打印日志,配置统一的logback文件即可。

贴下我们logback的配置

Dubbo Main方式启动设置logback

我们的纯Dubbo项目不是通过web容器启动,所以需要做一些配置让logback生效

MDC

logback内置的日志字段还是比较少,如果我们需要打印有关业务的更多的内容,包括自定义的一些数据,需要借助logback MDC机制,MDC为“Mapped Diagnostic Context”(映射诊断上下文),即将一些运行时的上下文数据通过logback打印出来;此时我们需要借助org.sl4j.MDC类。

MDC类基本原理其实非常简单,其内部持有一个InheritableThreadLocal实例,用于保存context数据,MDC提供了put/get/clear等几个核心接口,用于操作ThreadLocal中的数据;ThreadLocal中的K-V,可以在logback.xml中声明,最终将会打印在日志中。

那么在logback.xml中,即可在layout中通过声明“%X”来打印此信息。

Dubbo Main启动方式设置MDC

这种启动方式设置MDC十分简单在main函数中增加一下代码即可

web容器启动方式设置MDC

这里我们通过监听spring上下文的ContextRefreshedEvent事件实现,代码如下

正确的打日志

日志最大的作用就是排查问题,如果你打的日志没有把问题产生点输出,那这个日志就是白打。在我们项目中,我看到这么一些打印日志的代码把异常也通过占位符输出了,那么会调用e.toString()方法,只会打出当前方法的错误日志,看不到整个异常栈。

正确的做法是

日志框架会把整个异常栈打印出来

Logstash安装

Logstash在Docker中启动,由于公司服务器不能连接elastic官网镜像,所以通过下面命令从docker官方镜像库拉取,版本不能保证是官方最新。

拉好镜像之后就是启动容器了

上面这个命令我不保证完全正确,因为我都是在rancher配置参数启动的,接下来有空我会写个demo测试

-v /app/logs:/app/logs 映射日志存储的目录,日志产生的docker容器也需要配置这个-v /etc/logstash/pipeline/first-pipeline.conf:/etc/logstash/pipeline/first-pipeline.conf 映射pipeline配置文件-v /etc/logstash/logstash.yml:/etc/logstash/logstash.yml 映射logstash配置文件-v /app/data/logstash:/app/data/logstash 映射logstash的一些存储文件,我主要想保存file的读取位置,保证镜像升级后不会重新读取

一个重要的点

这边需要mark一下, /app/data/logstash这个目录,docker镜像内需要向这个目录写入文件,但是在宿主机权限一般是root用户,docker内部的用户不是root,就算是root id也匹配不上,所以docker容器内向宿主机目录写入的时候会报错。两种解决方式,第一种,暴力解决,chmod +777 ,第二种,通过 cat /etc/passwd拿到docker容器内logstash用户id,然后再宿主机,通过chown id /app/data/logstash设置目录权限。

配置文件编写

在使用logstash前,需要对它有一定的了解。logstash的组件其实很简单,主要包括input、filter、output、codec四个部分。

input 用于读取内容,常用的有stdin(直接从控制台输入)、file(读取文件)等,另外还提供了对接redis、kafka等的插件

filter 用于对输入的文本进行处理,常用的有grok(基于正则表达式提取字段)、kv(解析键值对形式的数据)、csv、xml等,另外还提供了了一个ruby插件,这个插件如果会用的话,几乎是万能的。

output 用于把fitler得到的内容输出到指定的接收端,常用的自然是elasticsearch(对接ES)、file(输出到文件)、stdout(直接输出到控制台)

codec 它用于格式化对应的内容,可以再Input和output插件中使用,比如在output的stdout中使用rubydebug以json的形式输出到控制台

以下是我的配置文件

input模块用来配置日志的来源,我这边是文件,codec => multiline用来处理日志分行的情况,异常报错日志有很多行,但是每个日志都是时间开头的

filter用来解析日志,提取有用信息。grok模块用来提取字段,我们可以在http://grokdebug.herokuapp.com/这个网站来验证自己写的表达式是否正确,在http://grokdebug.herokuapp.com/patterns可以查看各种自带的配置表达式,我的第一个grok用来解析日志中有用字段,第二个grok通过日志的目录来解析出应用名称。mutate模块对时间进行处理,加上时区,不然在kibana查询会有8个小时时间差。date模块用来转换时间,经过研究可有可无,直接用date字段即可。

output模块用来选择解析后的日志输出位置,我这边配置了控制台(用于调试)和ES。测试通过后,需要把stdout这块删除。

下面贴上logstash.yml

没什么东西,主要设置了path.data,再这个目录下面会保存文件读取位置

注意这个文件是隐藏的,并且它再plugin/input/file目录下,因为这个读取位置的文件是和file有关的

看下这个文件的内容吧

sincedb的格式为inode majorNumber minor Number pos。每行记录每个文件处理进度,比如下面的例子,表示inode为177037的文件处理到25951716位置、inode为176956的文件处理到32955178位置。

什么是inode请看这篇文章(https://www.cnblogs.com/bkylee/p/5484288.html)

如果我们测试的时候需要重新读取,那么把这个文件删掉就可以了

总结

我这个ELK是给开发测试预发环境使用,因为现在的设计是每个环境搭一套,所以没有必要使用filebeat这种轻量级的收集器,我现在也只是把开发环境搭好了,准备向运维单独申请服务器放置ELK,然后再各个环境启动filebeat,如果ELK消费不过来,中间再弄一个消息队列缓冲。这都是以后的事情了。

下一篇就讲解下Docker搭建ES和Kibana以及一些操作把。相对于本章较简单。

接下来上一点我学习的链接logstash官方文档(https://www.elastic.co/guide/en/logstash/current/index.html)一篇很好的ELK入门文章(https://www.cnblogs.com/xing901022/p/6596182.html)这家伙的logstash介绍也还凑合(http://www.51niux.com/?id=203)grok表达式工具网站(http://grokdebug.herokuapp.com/)logbakc MDC(http://shift-alt-ctrl.iteye.com/blog/2345272)解决Docker不能向宿主机目录写入问题(https://blog.csdn.net/csdn_duomaomao/article/details/78567748)logstash处理文件进度记录机制(https://blog.csdn.net/wangyangzhizhou/article/details/53328040)

最后

看到这里的观众,关注吧,关于技术的一切我都有可能分享

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20180725G1E6ML00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

同媒体快讯

扫码关注云+社区

领取腾讯云代金券