Logstash使用正则之多索引输出

公司产品是spring cloud框架,有很多个不同的服务,每个服务有多个实例。实例日志输出格式基本是一样的,且都在同一个文件夹,日志中有一个字段表示的就是服务名称。我想实现每个服务日志都生成自己的服务名称的索引,每台终端使用filebeat作为日志采集器,输出到logstash中,然后再推送进ES。

一、方案初步选择

每台机器可能放了好几个不同类型的服务,如果我要按日志分别输出到不通的索引中的话,大致有一下方式:

  • 在每台机器下给每个日志类型文件增加一个 log_type字段,然后在es output中按照log_type创建索引。这样的话不够灵活,一旦服务器有新的服务,就需要手动添加一个日志源,配置也多。
  • 在filebeat日志源头上直接指定*.log(服务日志在同一个文件夹下),然后在es grok中进行日志清洗,找出servername, 然后output中使用%{servername}变量名称创建索引。这样客户端就可以随意加不同的实例,但是logstash因为grok负载就略有升高。
二、logstash 中条件判断

有时您只想在特定条件下过滤或输出事件。为此,您可以使用条件(conditional)。比如在elk系统中想要添加一个type类型的关键字来根据不同的条件赋值,最后好做统计。官网链接
条件语支持if,else if和else语句并且可以嵌套。

条件语法如下:

if EXPRESSION {
  ...
} else if EXPRESSION {
  ...
} else {
  ...
}

比较操作:

相等: ==, !=, <, >, <=, >=
正则: =~(匹配正则), !~(不匹配正则)
包含: in(包含), not in(不包含)

布尔操作:

and(与), or(或), nand(非与), xor(非或)

一元运算符:

表达式可能很长且很复杂。表达式可以包含其他表达式,您可以使用!来取反表达式,并且可以使用括号(...)对它们进行分组。

!(取反)
()(复合表达式), !()(对复合表达式结果取反)
三、 Logstash 中Grok失败处理

按照上面我们的第二个方案的话,如果我们以grok出来的变量名称作为索引名称的话,如果grok失败,那么肯定就会以变量名称创建索引,比如创建成这样 bituan-%(servername)-2019-05-24这不是我们想要得到的结果,所以我们需要处理grok失败的单独放到一个索引中,如果grok失败,会在tags字段打上_grokparsefailures。参考官网配置

input { # ... }
filter {
  grok {
    match => { "message" => "%{TIMESTAMP_ISO8601:timestamp} \[%{IPV4:ip};%{WORD:environment}\] %{LOGLEVEL:log_level} %{GREEDYDATA:message}" }
  }
}
output {
  if "_grokparsefailure" in [tags] {
    # write events that didn't match to a file
    file { "path" => "/tmp/grok_failures.txt" }
  } else {
     elasticsearch { }
  }
}
四、线上Logstash 配置示例
  • filebeat中日志源头指定*.log,且指定了log_type(就是类似与一个tag,fields.log_type都以bituan-开头)
  • output中[fields][log_type] =~ "bituan-*"使用了正则,所以其同一类型的日志就不要再单独写一个output输出了,比如在前面又写了一个if [fields][log_type] == "bituan-sms-gateway" { elasticsearch { } },这样的话sms-gateway的日志就会重复记录,分别输出到不同的索引(在logstash 6.2版本中测试是这样),此时就应该用if else if else 这样写就不会重复写入。
log日志格式:
2019-05-24 10:36:22.406  INFO [query,,,] 19129 --- [trap-executor-0] c.n.d.s.r.aws.ConfigClusterResolver      : Resolving eureka endpoints via configuration

input {
        file {
                path => "/data/logs/nginx/access.log"
                type => "nginx-access"
                start_position => "beginning"
                # sincedb_path => "/usr/local/logstash/sincedb"
                codec => "json"
        }

        beats {
                host => "172.31.37.118" 
                port => 5400
        } 
}

filter {

        if [fields][log_type] =~ "bituan-*" {
            grok {
                match => ["message", "%{TIMESTAMP_ISO8601:logdate}[T ]*%{LOGLEVEL:loglevel}[T ]*\[(?([a-zA-Z0-9._-]+))%{GREEDYDATA:loginfo}"]
            }
            date {
                match => ["logdate", "yyyy-MM-dd HH:mm:ss.SSS"]
                target => "@timestamp"
            }
            mutate {
                update => {"message" => "%{logdate}  [%{servername}%{loginfo}"}
                remove_field => ["logdate","loginfo"]
            }
        }

        if [type] == "nginx-access" {
                geoip {
                        source => "http_x_forwarded_for"
                        target => "geoip"
                        database => "/home/GeoLite2-City_20190226/GeoLite2-City.mmdb"
                        add_field => [ "[geoip][coordinates]", "%{[geoip][longitude]}" ]
                        add_field => [ "[geoip][coordinates]", "%{[geoip][latitude]}"  ]
                }
                mutate {
                        convert => [ "[geoip][coordinates]", "float"]
                }
        }
}

output {
        if [type] == "nginx-access" {
                elasticsearch {
                        hosts => ["172.31.15.220:9200"]
                        manage_template => true
                        index => "logstash-nginx-web-%{+YYYY-MM-dd}"
                }
        }
        else if [fields][log_type] == "sms-gateway" {
                elasticsearch {
                        hosts => ["172.31.15.220:9200"]
                        manage_template => true
                        index => "bituan-sms-gateway-%{+YYYY-MM-dd}"
                }     
         }
         
        else if [fields][log_type] == "mycat" {
                elasticsearch {
                        hosts => ["172.31.15.220:9200"]
                        manage_template => true
                        index => "bituan-mycat-%{+YYYY-MM-dd}"
                }     
         }

	    else if "_grokparsefailure" not in [tags] {
                 if [fields][log_type] =~ "bituan-*" {
        	        elasticsearch {
                	        hosts => ["172.31.15.220:9200"]
                        	manage_template => true
	                        index => "bituan-%{servername}-%{+YYYY-MM-dd}"
                	}     
                 }
         } 
         
         else {
               elasticsearch {
		    	      hosts => ["172.31.15.220:9200"]
        	    	  index => "bituan-failure-%{+YYYY-MM-dd}"
		     }
         }

#        stdout { codec => "rubydebug"}
}

你可能感兴趣的:(Elastic,Stack)