ELK之Logstash安装与使用

Logstash作为ELK技术栈中重要的一员,本文介绍Logstash的一些使用。

官网  Logstash:收集、解析和转换日志 | Elastic

拉到下方有 Logstash文档  和 Logstash论坛 以及 下载 的链接。

1、简介

Logstash 是一个开源的数据收集引擎。它具有实时的数据传输能力,可以按照我们定制的规范来做数据的收集、解析和存储。也就是说Logstash有3个核心组成部分,分别是数据收集、数据解析和数据转存。这个三个部分组成了一个类似于管道的数据流,由输入端进行数据的采集,管道本身做数据的过滤和解析,输出端把过滤和解析后的数据输出到目标数据库中。

大致翻一下官方手册可以看到其功能还是非常强大的。Logstash Reference [8.4] | Elastic

能用上的就有不少,如 elasticsearch/redis/file/http/kafka/tcp/udp/stdout/websocket/mongodb等。 

#Input有如下插件

Input plugins
	azure_event_hubs
	beats
	cloudwatch
	couchdb_changes
	dead_letter_queue
	elastic_agent
	elasticsearch
	exec
	file
	ganglia
	gelf
	generator
	github
	google_cloud_storage
	google_pubsub
	graphite
	heartbeat
	http
	http_poller
	imap
	irc
	java_generator
	java_stdin
	jdbc
	jms
	jmx
	kafka
	kinesis
	log4j
	lumberjack
	meetup
	pipe
	puppet_facter
	rabbitmq
	redis
	relp
	rss
	s3
	s3-sns-sqs
	salesforce
	snmp
	snmptrap
	sqlite
	sqs
	stdin
	stomp
	syslog
	tcp
	twitter
	udp
	unix
	varnishlog
	websocket
	wmi
	xmpp
#output有如下插件

Output plugins
	boundary
	circonus
	cloudwatch
	csv
	datadog
	datadog_metrics
	dynatrace
	elastic_app_search
	elastic_workplace_search
	elasticsearch
	email
	exec
	file
	ganglia
	gelf
	google_bigquery
	google_cloud_storage
	google_pubsub
	graphite
	graphtastic
	http
	influxdb
	irc
	java_stdout
	juggernaut
	kafka
	librato
	loggly
	lumberjack
	metriccatcher
	mongodb
	nagios
	nagios_nsca
	opentsdb
	pagerduty
	pipe
	rabbitmq
	redis
	redmine
	riak
	riemann
	s3
	sink
	sns
	solr_http
	sqs
	statsd
	stdout
	stomp
	syslog
	tcp
	timber
	udp
	webhdfs
	websocket
	xmpp
	zabbix

https://www.elastic.co/guide/en/logstash/current/index.html

2、Logstash安装

1.安装java环境

这里就不多说了,如下确保java环境是ok的即可。 

2.下载与安装

curl -L -O https://artifacts.elastic.co/downloads/logstash/logstash-7.3.0.tar.gz
tar -xzvf logstash-7.3.0.tar.gz

3.启动与验证

cd logstash-7.3.0
#启动logstash,-e选项指定输入输出;这里输入采用标准输入,标准输出作为输出。
./bin/logstash -e 'input { stdin { } } output { stdout {} }'

启动完毕后输入字符串,可以得到响应的输出,如下说明安装成功。

更多安装方式见   如何安装 Elastic 栈中的 Logstash_Elastic 中国社区官方博客的博客-CSDN博客

3、Logstash使用

Logstash管道有两个必须元素,输入(inputs)和输出(outputs),以及一个可选元素filters。

3.1、配置 config/logstash.yml

将其中的 config.reload.automatic 选项改为 true。其好处是每次改完配置文件后不需要重启Logstash,会自动加载变化后的配置文件。

3.2、实践——接受tcp端口数据

在config目录下(其实啥目录都行),创建test.conf文件,内容如下。

input 监听9900端口的的tcp数据
output  打印到标准输出

input {
  tcp {
    port => 9900
  }
}
 
output {
  stdout {
     codec => rubydebug  #以rubydebug格式在控制台输出
     #codec => json   #以json格式在控制台输出
  }
}




执行logstash

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

另外起一个终端,通过nc命令向9900端口发送数据。

echo 'hello logstash!!!!!!!' | nc localhost 9900

#注:别的机器发也行,ip位置指定为logstash所在的ip即可

效果如下:

 如下图:上方为修改配置文件后自动加载的日志记录、下方位置为改成json格式之后的输出。

3.3、实践——Grok过滤器的数据处理

input {
  tcp {
    port => 9900
  }
}
 
filter {
  grok {
    match => { "message" => "%{COMBINEDAPACHELOG}" }
  }
}
 
output {
  stdout {
    codec => rubydebug  #以rubydebug格式在控制台输出
  }
}

创建一个文本文件test.log,内容如下:

14.49.42.25 - - [12/May/2019:01:24:44 +0000] "GET /articles/ppp-over-ssh/ HTTP/1.1" 200 18586 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2b1) Gecko/20091014 Firefox/3.6b1 GTB5"
14.49.42.25 - - [12/May/2019:01:24:15 +0000] "GET /articles/openldap-with-saslauthd/ HTTP/1.1" 200 12700 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2b1) Gecko/20091014 Firefox/3.6b1 GTB5"
14.49.42.25 - - [12/May/2019:01:24:06 +0000] "GET /articles/dynamic-dns-with-dhcp/ HTTP/1.1" 200 18848 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2b1) Gecko/20091014 Firefox/3.6b1 GTB5"
14.49.42.25 - - [12/May/2019:01:24:54 +0000] "GET /articles/ssh-security/ HTTP/1.1" 200 16543 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2b1) Gecko/20091014 Firefox/3.6b1 GTB5"
14.49.42.25 - - [12/May/2019:01:25:25 +0000] "GET /articles/week-of-unix-tools/ HTTP/1.1" 200 9313 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2b1) Gecko/20091014 Firefox/3.6b1 GTB5"
14.49.42.25 - - [12/May/2019:01:25:33 +0000] "GET /blog/geekery/headless-wrapper-for-ephemeral-xservers.html HTTP/1.1" 200 11902 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2b1) Gecko/20091014 Firefox/3.6b1 GTB5"
66.249.73.135 - - [12/May/2019:01:25:58 +0000] "GET /misc/nmh/replcomps HTTP/1.1" 200 891 "-" "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)"
114.80.81.51 - - [12/May/2019:01:26:10 +0000] "GET /blog/geekery/xvfb-firefox.html HTTP/1.1" 200 10975 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2b1) Gecko/20091014 Firefox/3.6b1 GTB5"
46.105.14.53 - - [12/May/2019:01:26:18 +0000] "GET /blog/tags/puppet?flav=rss20 HTTP/1.1" 200 14872 "-" "UniversalFeedParser/4.2-pre-314-svn +http://feedparser.org/"
61.55.141.10 - - [12/May/2019:01:26:17 +0000] "GET /blog/tags/boredom-induced-research HTTP/1.0" 200 17808 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2b1) Gecko/20091014 Firefox/3.6b1 GTB5"

执行命令 

head -n 1 test.log | nc localhost 9900

效果如下:

 也就是说通过Grok过滤器,他会通过正则表达式进行匹配把我们输入的非结构化数据变为一个结构化的数据。从上面可以看到其提取出来了request、port、host、clientip等字段。

更多关于Grok过滤器参见   Logstash:Grok filter 入门_Elastic 中国社区官方博客的博客-CSDN博客

3.4、实践——Geoip过滤器

前面知道了clientip,但是不知道这个IP是从哪儿来的,即具体的国家、经纬度地理信息。为此可以使用Geoip过滤器。

input {
  tcp {
    port => 9900
  }
}
 
filter {
  grok {
    match => { "message" => "%{COMBINEDAPACHELOG}" }
  }
 
  geoip {
    source => "clientip"
  }
}
 
output {
  stdout { }
}

执行

head -n 1 test.log | nc localhost 9900

效果如下

3.5、实践——Useragent过滤器

我们注意到agent字段比较长。但是并没有明确区分浏览器、语言等字段。为此可以使用useragent过滤器来进一步丰富。

3.6、实践——mutate/convert过滤器

注意到bytes是一个字符串类型,但实际可能希望他是一个数值。为此可以使用mutate:convert过滤器。

input {
  tcp {
    port => 9900
  }
}
 
filter {
  grok {
    match => { "message" => "%{COMBINEDAPACHELOG}" }
  }
 
  mutate {
    convert => {
      "bytes" => "integer"
    }
  }
 
  geoip {
    source => "clientip"
  }
 
  useragent {
    source => "agent"
    target => "useragent"
  }
 
}
 
output {
  stdout { }
}

不过agent看起来并没有提取相应字段

3.7、实践——导入数据至elastic

前面所有的输出都是stdout,也就是输出到Logstash运行的console(控制台)。下面演示将数据输出到Elasticsearch。

注:本机已经部署好了elasticsearch和kibana,且已经成功启动可用。

input {
  tcp {
    port => 9900
  }
}
 
filter {
  grok {
    match => { "message" => "%{COMBINEDAPACHELOG}" }
  }
 
  mutate {
    convert => {
      "bytes" => "integer"
    }
  }
 
  geoip {
    source => "clientip"
  }
 
  useragent {
    source => "agent"
    target => "useragent"
  }
 
  date {
    match => ["timestamp", "dd/MMM/yyyy:HH:mm:ss Z"]
  }
}
 
output {
  stdout { }
 
  elasticsearch {
    hosts => ["localhost:9200"]
    #user => "elastic"
    #password => "changeme"
  }
}


关于输入我们保留了stdout和elasticsearch,前者主要是为了方便调试。

执行命令

head -n 1 test.log | nc localhost 9900

在kibana中执行如下指令即可查看到写入es的数据。

#统计数据条数
GET logstash/_count

#访问数据
GET logstash/_search

#也可以看到对应的logstash命名的索引
GET _cat/aliases

3.8、实践——迁移ES数据

注意:有的ES实例的ip可能是禁止ping的,我们可以通过curl指令判断logstash所在机器是否能成功访问到ES实例。参见  ES(elasticsearch)常用的curl命令_焱齿的博客-CSDN博客_curl查询es某个索引数据

关于具体怎么配置,在官方说明文档中找到input、output等对应的elasticsearch插件看看样例就都知道了。

Elasticsearch input plugin | Logstash Reference [8.4] | Elastic

(1)input设置elasticsearch

 根据官方使用手册,列出一些常用的参数。

1、hosts:指定一个或多个你要查询的ES的主机。每个主机可以是 IP,HOST,IP:port,或者 HOSY:port。默认的端口是9200.
2、index:指定作用的索引。所有索引 "*" 即可
3、query:指定查询语句
4、proxy:设置为正向的http代理。空的话默认为没有设置代理。
5、request_timeout_seconds:秒单位的单次请求ES的最大时间,当单次请求的数量十分巨大的时候,超时极易发生。数值默认为60s。
6、schedule:顾名思义 定期的运行cron格式的时间表,例如 "* * * * *" 表示每分钟执行一次查询。默认情况认为无时间表,此时仅执行一次。
7、scroll: 参数控制scroll请求两次间隔间的保活时间(单位是秒),并且启动scroll过程。超时适用于每次往返即上一次滚动请求到下一个滚动请求之间. 默认值1m
8、size:设置每次scroll返回的最大消息条数。默认 1000
9、docinfo:如果设置的话在事件中就会包括诸如index,type,docid等文档信息。bool值默认为false
10、docinfo_fields: 如已经通过设置docinfo为true执行需要元数据存储,此字段列出事件中需要保存的元数据字段有哪些。默认值是 ["_index", "_type", "_id"]。
11、docinfo_target:如已经通过设置docinfo为true执行需要元数据存储,则此选项将在其下存储元数据字段的字段命名为子字段。

创建es_sync.conf文件:

#好用的
input {
  elasticsearch {
    hosts => ["http://11.168.176.227:9200"]
    index => "es_qidian_flow_oa_20220906"
    query => '{"query":{"bool":{ "must":[{"term":{"session_id": "webim_2852199659_240062447027410_1662447030899"}}]}}}'
  }
}

output {
  stdout { }
}


#最好有缩进,看起来更舒服。这个也是可以的
input {
  elasticsearch {
    hosts => ["http://11.168.176.227:9200"]
    index => "es_qidian_flow_oa_20220906"
    query => '{
      "query":{
        "bool":{
          "must":[
            {
              "term":{"session_id": "webim_2852199659_240062447027410_1662447030899"}
            }
          ]
        }
      }
    }'
  }
}

output {
  stdout { }
}



#其中的type感觉不用指定也是ok的。

注:此时如果继续往源ES中写入满足条件的数据,是不会被增量同步过来的(只执行一次嘛)。

设置定时任务。如下为 每分钟查询一次并将结果输出至console标准输出 的配置。

input {
  elasticsearch {
    hosts => ["http://11.168.xxx.227:9200"]
    index => "es_qidian_flow_oa_20220906"
    query => '{
      "query":{
        "bool":{
          "must":[
            {
              "term":{"session_id": "webim_2852199659_240062447027410_1662447030899"}
            }
          ]
        }
      }
    }'
    scroll => "1m"
    docinfo => true 
    size => 2000
    schedule => "* * * * *"  #定时任务,每分钟1次
  }
}

filter {
    mutate {
       remove_field => ["flow_type", "source", "@version", "@timestamp"]
 }
}

output {
  stdout { }
}

问:如何实现增量同步? 

大:借助schedule做定时任务,在output处配置docid去重。仅仅这样可能还是不够,query语句处指定过滤最近t分钟内的数据进行同步。t的取值要和scroll间隔相匹配。如下配置就为每1min同步最近3分钟的内的数据,这样应该就不会丢数据了;另外通过docid也可以实现去重。

注:看了下logstash从elasticsearch导出数据,增量同步貌似都是这么实现的。

input {
    elasticsearch {
        hosts => "1.1.1.1:9200"
        index => "es-runlog-2019.11.20"
        query => '{"query":{"range":{"@timestamp":{"gte":"now-3m","lte":"now/m"}}}}'
        size => 5000
        scroll => "1m"
        docinfo => true
        schedule => "* * * * *" #定时任务,每分钟执行一次
      }
}
filter {
     mutate {
   remove_field => ["source", "@version"]
 }
}
output {
    stdout {}
}

(2)filter插件

功能也非常多,这里简单列几个。Mutate filter plugin | Logstash Reference [8.4] | Elastic

date插件、grok插件、geoip插件前面都有简单演示过,这里专门介绍下 mutate(变异)插件

 适用于所有filter插件的通用选项:

1、add_field:在事件中添加任意字段。字段名称可以是动态的,并使用%{Field}包含事件的各个部分。
    filter {
      mutate {
        add_field => { "foo_%{somefield}" => "Hello world, from %{host}" }
      }
    }
2、remove_field:从此事件中删除任意字段。字段名称可以是动态的,并使用%{field}包含事件的各个部分示例。
    filter {
      mutate {
        remove_field => [ "foo_%{somefield}" ]
      }
    }
3、add_tag:
4、remove_tag:

mutate插件的一些选项 

1、convert:将字段的值转换为其他类型,如将字符串转换为整数。如果字段值是数组,则将转换所有成员。如果字段是散列,则不会采取任何操作。
    filter {
      mutate {
        convert => {
          "fieldname" => "integer"
          "booleanfield" => "boolean"
        }
      }
    }
2、copy:将现有字段复制到其他字段。现有目标字段将被覆盖。
    filter {
      mutate {
         copy => { "source_field" => "dest_field" }
      }
    }

3、merge:
4、rename:
5、replace:
6、update:

上述conf中加入mutate→remove_field之后可以看到输出就不包括remove列出的那些字段了。

(3)output插件 设置 elasticsearch

参见官网  Output plugins | Logstash Reference [8.4] | Elastic

将一个ES的数据导入另一个ES,索引、type、docid保持不变;同时也配置了schedule定时任务。如下。

input {
  elasticsearch {
    hosts => ["http://11.168.xxx.227:9200"]
    index => "es_qidian_flow_oa_20220906"
    query => '{
      "query":{
        "bool":{
          "must":[
            {
              "term":{"session_id": "webim_2852199659_240062447027410_1662447030899"}
            }
          ]
        }
      }
    }'
    scroll => "1m"
    docinfo => true 
    size => 2000
    schedule => "* * * * *"
  }
}

filter {
    mutate {
       remove_field => ["flow_type", "source", "@version", "@timestamp"]
 }
}

output {
  elasticsearch {
        hosts => ["http://10.101.xxx.15:9200"]
        index => "%{[@metadata][_index]}"
        document_type => "%{[@metadata][_type]}"
        document_id => "%{[@metadata][_id]}"
  }
  stdout { }
}

经过测试效果完全符合预期。

如果事件中没有包含目标索引前缀的字段,该怎么办?

这时候可以使用mutate过滤器和条件添加[@metadata]字段来设置每个事件的目标索引。[@metadata]字段将不会发送到Elasticsearch。

input {
  elasticsearch {
    hosts => ["http://11.168.176.227:9200"]
    index => "es_qidian_flow_oa_20220906"
    query => '{
      "query":{
        "bool":{
          "must":[
            {
              "term":{"session_id": "webim_2852199659_240062447027410_1662447030899"}
            }
          ]
        }
      }
    }'
    scroll => "1m"
    docinfo => true 
    size => 2000
    schedule => "* * * * *"
  }
}

filter {
    mutate {
       remove_field => ["flow_type", "source", "@version", "@timestamp"]
       add_field => { "[@metadata][new_index]" => "es_qidian_flow_oa_zs_%{+YYYY_MM}"}
 }
}

output {
  elasticsearch {
        hosts => ["http://10.101.203.15:9200"]
        index => "%{[@metadata][new_index]}"
        document_type => "%{[@metadata][_type]}"
        document_id => "%{[@metadata][_id]}"
  }
  stdout { }
}

这个时候出来的索引名称如下。

再给一个实例。总之各种拼接都是ok的。

    filter {
      if [log_type] in [ "test", "staging" ] {
        mutate { add_field => { "[@metadata][target_index]" => "test-%{+YYYY.MM}" } }
      } else if [log_type] == "production" {
        mutate { add_field => { "[@metadata][target_index]" => "prod-%{+YYYY.MM.dd}" } }
      } else {
        mutate { add_field => { "[@metadata][target_index]" => "unknown-%{+YYYY}" } }
      }
    }
    output {
      elasticsearch {
        index => "%{[@metadata][target_index]}"
      }
    }

关于增量迁移可以参照是个实践:

记一次在线跨集群迁移ES数据 - 腾讯云开发者社区-腾讯云

猜你喜欢

转载自blog.csdn.net/mijichui2153/article/details/127113364