Logstash实现自定义插件在filter中读取redis
需求:
埋点的数据,在logstash数据抽取中,需要实时关联mysql的业务数据,最终形成一个数据输出。
实现:
1. 根据官网提示,先生成一个模版
bin/logstash-plugin generate --type filter --name redis --path vendor/localgems
生成之后的目录是: ./vendor/localgems/logstash-filter-redis
生成目录的树状结构如下:
[root@node004 localgems]# tree logstash-filter-redis/
logstash-filter-redis/
├── CONTRIBUTORS
├── docs
│ └── index.asciidoc
├── Gemfile
├── lib
│ └── logstash
│ └── filters
│ └── redis.rb
├── LICENSE
├── logstash-filter-redis.gemspec
├── Rakefile
└── spec
├── filters
│ └── test_spec.rb
└── spec_helper.rb
2. 主要用到的文件及文件夹
lib: 存放插件代码。
logstash-filter-redis.gemspec: 存放插件注册信息。
Gem::Specification.new do |s|
s.name = 'logstash-filter-redis'
s.version = '0.1.0'
s.licenses = ['Apache-2.0']
s.summary = '读取redis数据,至filter中 '
s.description = '用户可以在logstash中添加该filter,最直观的结果,可以产生一个新的字段,从redis产生 '
s.homepage = 'http://www.elastic.co/guide/en/logstash/current/index.html'
s.authors = ['rookieuncle']
s.email = ['rookieuncle@163.com']
s.require_paths = ['lib']
# Files
s.files = Dir['lib/**/*','spec/**/*','vendor/**/*','*.gemspec','*.md','CONTRIBUTORS','Gemfile','LICENSE','NOTICE.TXT']
# Tests
s.test_files = s.files.grep(%r{^(test|spec|features)/})
# Special flag to let us know this is actually a logstash plugin
s.metadata = { "logstash_plugin" => "true", "logstash_group" => "filter" }
# Gem dependencies
s.add_runtime_dependency "logstash-core-plugin-api", "~> 2.0"
s.add_development_dependency 'logstash-devutils'
s.add_development_dependency 'redis'
end
s.name 定义了插件名字
s.version 定义了插件版本(注意:默认是0.1.0开始,但是如果版本小于1.0 会被认为是孵化版本,使用的时候logstash输出日志会记录,但是不影响使用)
s.licenses 协议版本,遵循开源协议,默认是apache-2.0
s.summary 一个关于插件的小简介,如果不想写,可以删除该行,但是不能空着,会报错
s.description 一个详细的简介,如果不想写,可以删除该行,但是不能空着,会报错
s.homepage 插件所属网站,如果不想写,可以删除该行,但是不能空着,会报错
s.authors 作者
s.email 邮箱
s.require_paths 代码所在目录
中间几个一般不需要修改
s.add_runtime_dependency 运行时依赖参数,指定了core的依赖是2.0版本的
s.add_development_dependency 开发依赖,需要的话自己可以配置
我们做修改的地方有一下几个:
s.summary = '读取redis数据,至filter中 ’
s.description = ‘用户可以在logstash中添加该filter,最直观的结果,可以产生一个新的字段,从redis产生’
s.homepage = ‘http://www.elastic.co/guide/en/logstash/current/index.html’
s.authors = [‘rookieuncle’]
s.email = [‘rookieuncle@163.com’]
···
s.add_development_dependency ‘redis’
最后添加的redis,是因为我们需要使用redis,相当于import redis相关依赖
3. 主要代码文件
- config 配置规则
config :variable_name, :validate => :variable_type, :default => “Default value”, :required => boolean, :deprecated => boolean, :obsolete => string
:variable_name:参数名称 (host port db 等 )
:validate:验证参数类型 (:string,:password,:boolean,:number,:array,:hash,:path等)
:required:是否必须配置 (true 或者 false)
:default:默认值
:deprecated:是否废弃 (true 或者 false)
:obsolete:声明该配置不再使用,同时提供用户提供明智的升级方案
- reby中
# encoding: utf-8
# 第一行的utf-8设置,是reby的格式,类似与shell中的.sh脚本,不要动!
require "logstash/filters/base"
require "logstash/namespace"
require "redis" # 添加redis依赖
class LogStash::Filters::Redis < LogStash::Filters::Base
# 定义name 需要与上边配置文件保持一致
config_name "redis"
default :codec, "json" # 设置配置文件默认的格式
config :host, :validate => :string, :default => "127.0.0.1" # 设置 redis host 参数,默认 127.0.0.1
config :port, :validate => :number, :default => 6379 # 设置 port 参数,默认 6379
config :db, :validate => :number, :default => 0 # 设置 db 参数,默认 0
config :password, :validate => :string # 设置 password 参数,不默认
config :timeout, :validate => :number, :default => 5 # 设置 timeout 参数,不默认
config :key, :validate => :string # 设置 查询的rediskey 参数,不默认
config :target, :validate => :string, :default => "target" # 设置 返回 参数,不设置默认为 "target"
public
# register 是初始化代码,和init类似 必须实现两个方法的第一个
def register
# 做redis初始化工作
@logger = self.logger
begin
$redis = Redis.new(:host => @host,:port => @port, :db => @db, :password => @password)
rescue => e
@logger.error("Field to init redis:", :exception => e) # 如果redis初始化失败,则报错
end
@logger.info("redis filter is ok, the plugin param: host is #{@host}; port is #{@port}; db is #{@db}; password is #{@password};") # 打印info日志,将配置文件内容打印输出
end
public
# filter 是具体功能实现。 必须实现两个方法的第二个 如果你编写的是input或者output 则根据自动生成的看
def filter(event)
_key=event.get(@key)
# @logger.info("_key_1: #{_key}\t")
if !_key.nil?
# @logger.info("_key: #{_key}\t")
_value=$redis.get(_key)
# @logger.info("_key: #{_key}, _value: #{_value}")
if (!_value.nil?)&&(!_value.empty?)
if @target
@logger.debug? && @logger.debug("Overwriting existing target field", :target => @target)
event.set(@target, _value)
end
else
_action=event.get("action")
@logger.info("The value was not found in Redis! _key: #{_key}, _action: #{_action}")
if @message
event.set("message", @message)
end # @message
end # _value.nil?
end # _key.nil?
filter_matched(event) # 该方法会把事件传入下一个过滤器
end # def filter
# 为了在logstash关闭时候不丢失数据,建议实现这个方法,logstash会自动执行(在output插件中实现,filter不必实现)
# public
# def teardown
# end
end # Redis
在上述filter方法中可以使用几个默认的方法:
- filter_matched() 该方法会把事件传入下一个过滤器
- add_field、remove_field 添加或者移除一个字段
- add_tags、remove_tags 添加或者移除一个标签
- event.cancel 取消当前的事件,即不在继续向下走。(在split插件中有典型的使用场景)
4. 配置完成将插件配置到logstash配置文件中
- 这里使用之前 是需要对安装一下redis的依赖库,默认logstash7.1.0是不带redis依赖的
安装方式:切换到logstash的根目录的 vendor/jruby/bin 目录下,然后执行
./gem install redis
安装完成后 在 vendor/jruby/lib/ruby/gems/shared/gems目录下查看有没有redis相关文件夹
- 然后代码中引用的redis依赖才会生效,要保证
- logstash-filter-redis.gemspec 中最后添加
s.add_development_dependency 'redis'
- 保证 ruby 开头
require "redis" # 添加redis依赖
- 在logstash根目录下的Gemfile文件中添加依赖(path是文件生成位置)
gem "logstash-filter-test", :path => "vendor/localgems/logstash-filter-test"
5. logstash中使用自定义的redis插件
input {
stdin { }
}
filter{
redis {
host => "127.0.0.1"
password => "root"
key => "find_key"
target => "out_value"
}
}
output {
stdout { }
}
测试输出正常是可以有结果的!
到这里就差不多了,有什么问题,欢迎留言讨论