ELK日志分析系统(本地分析)

前段时间,老大叫我在新闻服务上,查看下redis的read time out的异常,我用linux命令查,感觉有点麻烦,所以就自己搭了一个elk的日志收集系统。注意这里只能在本地分析日志文件,如果日志文件在别的主机上,在下一章会进行讲述。

我采用了很笨的方法,我把要分析的日志拷贝到本地主机上,然后在本地虚拟机上创建了一个elk系统。

这里先给出我要分析的日志格式,不过我只要error的日志,其他级别的不分析:
 

2018-07-16 13:00:08.026  WARN [newsservice,bf045afa588eb7f9,f7ac1088fb74eab3,false] 17864 --- [ XNIO-5 task-12] c.i.n.controller.v3.UniteNewsController  : uniteChannelNews V1 cost time is 4466 ms! The request URL is http://172.18.0.2:8182/v3/uniteChannelNews:installChannel=qita&ac=1&cCode=4504&oldestTime=0&romVersion=Meizu&snapshotNumber=0&latitude=23.474561&channelType=0&language=zh&devicePlatform=android&pageNum=1&md5Hash=6b5eca59c0c0376cc0468e6c57e4ff8f&osVersion=6.0.1&pCode=45&aCode=450403&refreshType=0&deviceModel=M3X&deviceBrand=Meizu&channelId=612&longitude=111.301625
2018-07-16 13:00:08.222  INFO [newsservice,,,] 17864 --- [cTaskExecutor-1] c.i.n.s.rabbitmq.NewsRabbitMQReceiver    : received news update message: {"action":"publish","targetType":"news","id":9042825}
2018-07-16 13:00:11.620  WARN [newsservice,f98adb8057c64034,9513bd6c84a454d8,false] 17864 --- [ XNIO-5 task-84] c.i.n.controller.v3.UniteNewsController  : [checkpoint] checkpoint1 , cost time: 887
2018-07-16 13:00:11.656 ERROR [newsservice,,,] 17864 --- [cTaskExecutor-1] c.i.n.s.rabbitmq.NewsRabbitMQReceiver    : Deal with news to redis error sid: 9042825

org.springframework.data.redis.RedisConnectionFailureException: java.net.SocketTimeoutException: Read timed out; nested exception is redis.clients.jedis.exceptions.JedisConnectionException: java.net.SocketTimeoutException: Read timed out
	at org.springframework.data.redis.connection.jedis.JedisExceptionConverter.convert(JedisExceptionConverter.java:67)
	at org.springframework.data.redis.connection.jedis.JedisExceptionConverter.convert(JedisExceptionConverter.java:41)
	at org.springframework.data.redis.PassThroughExceptionTranslationStrategy.translate(PassThroughExceptionTranslationStrategy.java:37)
	at org.springframework.data.redis.FallbackExceptionTranslationStrategy.translate(FallbackExceptionTranslationStrategy.java:37)
	at org.springframework.data.redis.connection.jedis.JedisConnection.convertJedisAccessException(JedisConnection.java:212)
	at org.springframework.data.redis.connection.jedis.JedisConnection.sAdd(JedisConnection.java:1874)
	at org.springframework.data.redis.connection.DefaultStringRedisConnection.sAdd(DefaultStringRedisConnection.java:692)
	at org.springframework.data.redis.core.DefaultSetOperations$1.doInRedis(DefaultSetOperations.java:46)
	at org.springframework.data.redis.core.DefaultSetOperations$1.doInRedis(DefaultSetOperations.java:43)
	at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:202)
	at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:164)
	at org.springframework.data.redis.core.AbstractOperations.execute(AbstractOperations.java:88)
	at org.springframework.data.redis.core.DefaultSetOperations.add(DefaultSetOperations.java:43)
	at cn.itouchtv.news.service.impl.MediaCacheImp.beautifyMediaInfoIntoSetter(MediaCacheImp.java:676)
	at cn.itouchtv.news.service.rabbitmq.NewsRabbitMQReceiver.receive(NewsRabbitMQReceiver.java:119)
	at cn.itouchtv.news.service.rabbitmq.NewsRabbitMQReceiver$$FastClassBySpringCGLIB$$bf59a8ef.invoke(<generated>)
	at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:720)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
	at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:85)
	at cn.itouchtv.debug.StopTaskAndMqAspect.aroundMQStop(StopTaskAndMqAspect.java:57)
	at sun.reflect.GeneratedMethodAccessor281.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:629)
	at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:618)
	at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:70)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:168)
	at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
	at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:655)
	at cn.itouchtv.news.service.rabbitmq.NewsRabbitMQReceiver$$EnhancerBySpringCGLIB$$63fa09c6.receive(<generated>)
	at sun.reflect.GeneratedMethodAccessor550.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:197)
	at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:115)
	at org.springframework.amqp.rabbit.listener.adapter.DelegatingInvocableHandler.invoke(DelegatingInvocableHandler.java:108)
	at org.springframework.amqp.rabbit.listener.adapter.HandlerAdapter.invoke(HandlerAdapter.java:52)
	at org.springframework.amqp.rabbit.listener.adapter.MessagingMessageListenerAdapter.invokeHandler(MessagingMessageListenerAdapter.java:125)
	at org.springframework.amqp.rabbit.listener.adapter.MessagingMessageListenerAdapter.onMessage(MessagingMessageListenerAdapter.java:105)
	at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:777)
	at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.invokeListener(AbstractMessageListenerContainer.java:700)
	at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.access$001(SimpleMessageListenerContainer.java:95)
	at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$1.invokeListener(SimpleMessageListenerContainer.java:187)
	at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.invokeListener(SimpleMessageListenerContainer.java:1187)
	at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.executeListener(AbstractMessageListenerContainer.java:681)
	at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.doReceiveAndExecute(SimpleMessageListenerContainer.java:1165)
	at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.receiveAndExecute(SimpleMessageListenerContainer.java:1149)
	at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.access$1100(SimpleMessageListenerContainer.java:95)
	at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$AsyncMessageProcessingConsumer.run(SimpleMessageListenerContainer.java:1312)
	at java.lang.Thread.run(Thread.java:745)
Caused by: redis.clients.jedis.exceptions.JedisConnectionException: java.net.SocketTimeoutException: Read timed out
	at redis.clients.util.RedisInputStream.ensureFill(RedisInputStream.java:202)
	at redis.clients.util.RedisInputStream.readByte(RedisInputStream.java:40)
	at redis.clients.jedis.Protocol.process(Protocol.java:151)
	at redis.clients.jedis.Protocol.read(Protocol.java:215)
	at redis.clients.jedis.Connection.readProtocolWithCheckingBroken(Connection.java:340)
	at redis.clients.jedis.Connection.getIntegerReply(Connection.java:265)
	at redis.clients.jedis.BinaryJedis.sadd(BinaryJedis.java:1298)
	at org.springframework.data.redis.connection.jedis.JedisConnection.sAdd(JedisConnection.java:1872)
	... 46 common frames omitted
Caused by: java.net.SocketTimeoutException: Read timed out
	at java.net.SocketInputStream.socketRead0(Native Method)
	at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
	at java.net.SocketInputStream.read(SocketInputStream.java:170)
	at java.net.SocketInputStream.read(SocketInputStream.java:141)
	at java.net.SocketInputStream.read(SocketInputStream.java:127)
	at redis.clients.util.RedisInputStream.ensureFill(RedisInputStream.java:196)
	... 53 common frames omitted

2018-07-16 13:00:11.657 ERROR [newsservice,,,] 17864 --- [ XNIO-5 task-52] io.undertow.request                      : UT005023: Exception handling request to /v6/hotNews

用到的elk如下:

elasticsearch-6.3.1.tar.gz 

kibana-6.3.1-linux-x86_64.tar.gz
logstash-6.3.1.tar.gz 

elasticserach直接解压后启动即可:./bin/elasticserach  -d (-d表示后台运行)

kibana直接解压,然后把访问的localhost改成本机的ip地址:

server.host: "192.168.86.128"

然后启动kibana,运行 ./kibana &

注意:我这里主要是想在我本机windows的浏览器上访问kibana来方便查看数据而已

最后就是logstash了,基本大部分工作在这里:

解压logstash,然后进入config目录,创建一个配置文件errorlog.conf

具体配置如下:

# 输入插件
input {
    file {
	   # 代表要分析的日志的位置,这里也可以使用正则的,比如*.log,就会读入所有的.log结尾的日志
       path => "/home/itouchtv/log/nohup.log" 
	    
	   # 这里是多行读入,默认情况下,logstash是一行一行读的,刚开始的时候,我返现一个错误信息,分成几十行
	   # 非常不方便,我想要完整的错误信息。
       codec => multiline {
	      # 正则配置的模式,这里我是自定义的,^代表以什么开头,%{YEAR}-%{MONTHNUM}-%{MONTHDAY}代表yyyy-MM-dd格式的日期
		  # \s代表是一个空格,*代表前面的空格出现的次数可以为0次或者多次,%{TIME}代表 HH:mm:ss格式的时间
		  # 2018-07-16 13:00:11会被匹配到,然后在下一个匹配成功的前的所有行,会被当成同一个事件。所以同一个error的信息
		  # 会被放到一起。
          pattern => "^%{YEAR}-%{MONTHNUM}-%{MONTHDAY}\s*%{TIME}" 
		  
		  # 是否启用正则
          negate => true
		  
		  # 先前闭合,意思是在下一个成功匹配之前,这些数据不读入
		  # 比如最后一个2018-07-16 13:00:11被匹配了,然后下面没有再出现这种格式的数据,那么这段数据就不会读入到logstash中
          what => "previous"
        }
	   
	   # 文件的读入位置,文件开始的位置读,不过要保证:logstash-6.3.1/data/plugins/inputs/file下没有记录你要分析文件的偏移地址
	   # 你在该目录下 ls -a 会看到是否有这种类型的文件 .sincedb_2905c14f44d79b0840f736856456d179,一般开始的时候,没有这个文件
	   # 所以它会读入全部文件,读完之后,会记录读入的位置,下次再发现文件更新的时候,再增量的读入新增的内容。
       start_position => "beginning"
	   
	   # 这个是我读入多种类型的数据,进行区分的时候加入的,我再实际的开发中,除了读入这种异常分析的日志外,还读入了访问的日志,
	   # 进行访问。
       type => "errorlog"
    }
}

# 过滤器
filter {
   # 固定的语法,你想要引用一个变量的话,用[],比如这里就是引入上面的type=>"errorlog"这个变量
   if [type] == "errorlog" {
      # 这是个好东西,可以进行很正则分析,然后提取出需要的信息
      grok {
	     # message固定写法,上述input中每个事件的信息都会放入到这里来,然后再通过后面的正则进行匹配
		 # 2018-07-16 13:00:14.544  WARN [newsservice,7dfc2622d7e5af21,9ab170947a9b7429,false] 17864 --- [ XNIO-5 task-20] 
		 # %{YEAR}-%{MONTHNUM}-%{MONTHDAY}\s*%{TIME}这里和上述一样功能,接下来的.就是点本身,\d是代表数字{3},出现三次,所以
		 # 这里刚好是.544被匹配到了,同样的再匹配0个或者多个空格,(?<Level>[A-Z]{3,20}),这里是自定义正则匹配,匹配的数据会
		 # 放入到Level中,比如这里(?<Level>xxx),xxx是正则表达式,[A-Z]{3,20}是说这里可以是长度为3到20的字符串,由A-Z的任意字目
		 # 组成,比如上述的例子  WARN 是由[A-Z]组成的,切长度为4,也在(3,20)内,所以会被匹配赋给Level这个变量
         match => ["message","%{YEAR}-%{MONTHNUM}-%{MONTHDAY}\s*%{TIME}.\d{3}\s*(?<Level>[A-Z]{3,20})"]
      }
      
	  # 获取Level的变量值,如果和右边的字符串相等,就丢弃这个事件,数据就会被忽略
      if [Level] == "DEBUG" {
         drop {}
      }
 
      if [Level] == "WARN" {
         drop {}
      }
 
      if [Level] == "INFO" {
         drop {}
      }
   }

}

# 输出插件
output {
  if [type] == "errorlog" {
     # 固定格式,表示输出到es中
     elasticsearch {
	    # es的地址和端口好
        hosts => ["localhost:9200"]
		# 输入到es中的索引的名字,%{}表示会在字符串中应用变量
		# %{type} 输入accesslog这个值,%{+YYYY.MM.dd} 固定写法
		# 会读入当前系统的日期
        index => "itouchtv-%{type}-%{+YYYY.MM.dd}"
     }
  }
}

然后启动logstash:

./bin/logstash -f config/errorlog.conf 

启动完后,就可以通过kibana查看数据了。

访问 http://192.168.31.98:5601(访问的时候注意下,要关闭防火墙才行),即可,kibana里面对数据的操作,放到下一章,记录远程日志分析的时候再讲。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值