如何编写 Logstash 过滤插件
要为 Logstash 开发一个新的过滤器,请构建一个独立的 Ruby gem,其源代码存放在它自己的 GitHub 仓库中。然后,这个 Ruby gem 可以托管并在 RubyGems.org 上共享。你可以使用示例过滤器的实现作为起点。(如果你对 Ruby 不熟悉,可以在 https://ruby-lang.cn/en/documentation/quickstart/ 找到一份极好的快速入门指南。)
让我们一步步使用示例过滤插件来创建一个过滤插件。
每个 Logstash 插件都存放在自己的 GitHub 仓库中。为你的插件创建一个新仓库:
登录 GitHub。
点击 Repositories 标签页。你将看到你 fork 过或贡献过的其他仓库列表。
点击右上角的绿色 New 按钮。
为你的新仓库指定以下设置:
- 仓库名称——形如
logstash-filter-pluginname的唯一名称。 - Public 或 Private(公开或私有)——由你选择,但如果要将其提交为官方插件,则仓库必须是公开的(Public)。
- Initialize this repository with a README(使用 README 初始化此仓库)——允许你立即将仓库克隆到本地计算机。
- 仓库名称——形如
点击 Create Repository。
你可以在几秒钟内创建自己的 Logstash 插件!bin/logstash-plugin 的 generate 子命令使用模板化文件为新的 Logstash 插件奠定基础。它会创建正确的目录结构、gemspec 文件和依赖项,以便你开始添加自定义代码来通过 Logstash 处理数据。
欲了解更多信息,请参阅生成插件
或者,你也可以使用我们在 github.com 上托管的示例仓库
克隆你的插件。将
GITUSERNAME替换为你的 github 用户名,将MYPLUGINNAME替换为你的插件名称。git clone https://github.com/GITUSERNAME/logstash-``filter-MYPLUGINNAME.git- 或者通过 ssh:
git clone git@github.com:GITUSERNAME/logstash``-filter-MYPLUGINNAME.git
- 或者通过 ssh:
cd logstash-filter-MYPLUGINNAME
克隆过滤插件示例并将其复制到你的插件分支。
你不需要包含示例的 .git 目录或其内容,因此请在复制示例之前将其删除。
cd /tmpgit clone https://github.com/logstash-plugins/logstash``-filter-example.gitcd logstash-filter-examplerm -rf .gitcp -R * /path/to/logstash-filter-mypluginname/
将以下文件重命名以匹配你的插件名称。
logstash-filter-example.gemspecexample.rbexample_spec.rbcd /path/to/logstash-filter-mypluginname mv logstash-filter-example.gemspec logstash-filter-mypluginname.gemspec mv lib/logstash/filters/example.rb lib/logstash/filters/mypluginname.rb mv spec/filters/example_spec.rb spec/filters/mypluginname_spec.rb
你的文件结构应该类似于这样:
$ tree logstash-filter-mypluginname
├── Gemfile
├── LICENSE
├── README.md
├── Rakefile
├── lib
│ └── logstash
│ └── filters
│ └── mypluginname.rb
├── logstash-filter-mypluginname.gemspec
└── spec
└── filters
└── mypluginname_spec.rb
有关 Ruby gem 文件结构的更多信息以及 Ruby gem 创建过程的优秀演练,请参阅 http://timelessrepo.com/making-ruby-gems
在我们深入探讨细节之前,请在您喜爱的文本编辑器中打开插件文件并看一看。
require "logstash/filters/base"
require "logstash/namespace"
# Add any asciidoc formatted documentation here
# This example filter will replace the contents of the default
# message field with whatever you specify in the configuration.
#
# It is only intended to be used as an example.
class LogStash::Filters::Example < LogStash::Filters::Base
# Setting the config_name here is required. This is how you
# configure this filter from your Logstash config.
#
# filter {
# example { message => "My message..." }
# }
config_name "example"
# Replace the message with this value.
config :message, :validate => :string, :default => "Hello World!"
public
def register
# Add instance variables
end
public
def filter(event)
if @message
# Replace the event message with our message as configured in the
# config file.
event.set("message", @message)
end
# filter_matched should go in the last line of our successful code
filter_matched(event)
end
end
- def register
- def filter
- class LogStash<>FiltersExample
现在让我们逐行查看示例插件。
Logstash 过滤插件需要定义在 logstash/filters/base 和 logstash/namespace 中的父类
require "logstash/filters/base"
require "logstash/namespace"
当然,你构建的插件可能依赖于其他代码,甚至依赖于 gems。只需将它们与这些 Logstash 依赖项一起放在这里即可。
让我们来看一下插件本身的各个元素。
过滤插件类应该是 LogStash::Filters::Base 的子类
class LogStash::Filters::Example < LogStash::Filters::Base
类名应该与插件名称紧密呼应,例如
LogStash::Filters::Example
config_name "example"
这是你的插件将在 filter 配置块中调用的名称。
如果你在插件代码中设置了 config_name "example",则相应的 Logstash 配置块看起来需要像这样:
config :variable_name, :validate => :variable_type, :default => "Default value", :required => boolean, :deprecated => boolean, :obsolete => string
配置(或 config)部分允许你定义启用 Logstash 处理事件所需的尽可能多(或尽可能少)的参数。
有几个配置属性:
:validate- 允许你强制为此配置选项向 Logstash 传递特定的数据类型,例如:string、:password、:boolean、:number、:array、:hash、:path(文件系统路径)、uri、:codec(1.2.0 起支持)、:bytes. 请注意,这也起到了强制类型转换的作用,如果在布尔值中指定了 "true"(尽管技术上是一个字符串),它会在配置中变成一个有效的布尔值。这种类型转换对于:number类型也同样有效,其中 "1.2" 会变成浮点数,"22" 会变成整数。:default- 允许你为参数指定默认值:required- 此参数是否为必填项(布尔值true或:list- 此值是否应为值的列表。将对列表成员进行类型检查,并将标量转换为单元素列表。请注意,这在很大程度上免去了对数组类型的需要,不过如果你需要复杂对象的列表,数组会更合适。false):deprecated- 信息性的(同样是布尔值true或false):obsolete- 用于声明某个给定设置已被移除且不再起作用。其目的是为仍在使用的用户提供一条知情的升级路径。
Logstash 过滤器必须实现 register 和 filter 方法。
public
def register
end
- def register
Logstash 的 register 方法类似于 initialize 方法。它最初是为了强制调用 super 而创建的,从而避免新手的烦恼。(注意:它将来可能会被 initialize 取代,并结合一些强制测试以确保调用了 super。)
public 意味着该方法可以在任何地方调用,而不仅仅是在类内部。这是 Ruby 中方法的默认行为,但此处仍将其显式指定。
你还可以在此处分配实例变量(以 @ 开头的变量)。配置变量现在作为实例变量在作用域内,例如 @message
public
def filter(event)
if @message
# Replace the event message with our message as configured in the
# config file.
event.set("message", @message)
end
# filter_matched should go in the last line of our successful code
filter_matched(event)
end
- def filter
插件的 filter 方法是实际进行过滤工作的地方!在 filter 方法内部,你可以使用 Event 对象引用事件数据。Event 是封装 Logstash 内部数据流的主要对象,并为插件开发者提供了一个用于与事件内容进行交互的 API。
filter 方法还应通过显式调用 Event 类中提供的 sprintf 方法来处理任何与事件相关的配置。例如
field_foo = event.sprintf(field)
请注意,配置变量现在作为实例变量在作用域内,例如 @message
filter_matched(event)
在插件成功执行后调用 filter_matched 方法,将确保通过此过滤器的 Logstash 配置添加的任何字段或标签都能得到正确处理。例如,任何 add_field、remove_field、add_tag 和/或 remove_tag 操作都将在此时执行。
现在可以使用诸如 event.cancel 之类的 Event 方法来控制正在处理的事件的工作流。
在此阶段,你已经完成了插件的代码编写,并准备好从中构建 Ruby Gem。以下信息将帮助你完成该过程。
Ruby 中的 require 语句用于引入必要的代码。在某些情况下,你的插件可能需要其他文件。例如,collectd 插件使用了 collectd 提供的 types.db 文件。在插件的主目录中,有一个名为 vendor.json 的文件,这些文件就是在其中进行描述的。
vendor.json 文件包含一个 JSON 对象数组,每个对象描述一个文件依赖项。此示例来自 collectd 编解码器插件
[{
"sha1": "a90fe6cc53b76b7bdd56dc57950d90787cb9c96e",
"url": "http://collectd.org/files/collectd-5.4.0.tar.gz",
"files": [ "/src/types.db" ]
}]
sha1是用于验证url引用的文件完整性的 sha1 签名。url是 Logstash 下载该文件的地址。files是要从下载的文件中提取的文件的可选数组。请注意,虽然 tar 归档文件可以使用绝对路径或相对路径,但在该数组中请将它们视为绝对路径。如果不存在files,则所有文件将被解压缩并提取到 vendor 目录中。
vendor.json 文件的另一个例子是 geoip 过滤器
用于下载这些依赖项的过程是调用 rake vendor。本文档的测试部分将对此进行进一步讨论。
另一种外部依赖是关于 jar 文件的。这将在“添加 gemspec 文件”一节中进行描述。
随着插件的演进,某个选项或功能可能不再满足预期的目的,开发人员可能希望将其用法弃用。弃用会向用户发出关于该选项状态的警告,这样当它在以后的版本中被移除时,用户就不会感到措手不及。
Logstash 7.6 引入了弃用记录器(deprecation logger),以便更轻松地处理这些情况。你可以使用适配器来确保你的插件可以使用弃用记录器,同时仍然支持旧版本的 Logstash。有关更多信息以及有关使用适配器的说明,请参阅 readme。
弃用信息记录在 log 目录下的 logstash-deprecation.log 文件中。
Gemfile 允许 Ruby 的 Bundler 为你的插件维护依赖项。目前,我们所需要的只是用于测试的 Logstash gem,但如果你需要其他 gem,则应该将它们添加在此处。
有关更多详细信息,请参阅 Bundler 的 Gemfile 页面。
source 'https://rubygems.org.cn'
gemspec
gem "logstash", :github => "elastic/logstash", :branch => "master"
Gemspec 定义了将被构建并包含你的插件的 Ruby gem。
更多信息可以在 Rubygems 规范页面上找到。
Gem::Specification.new do |s|
s.name = 'logstash-filter-example'
s.version = '0.1.0'
s.licenses = ['Apache License (2.0)']
s.summary = "This filter does x, y, z in Logstash"
s.description = "This gem is a logstash plugin required to be installed on top of the Logstash core pipeline using $LS_HOME/bin/logstash-plugin install gemname. This gem is not a stand-alone program"
s.authors = ["Elastic"]
s.email = 'info@elastic.co'
s.homepage = "https://esdocs.cn/guide/en/logstash/current/index.html"
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", ">= 1.60", "<= 2.99"
s.add_development_dependency 'logstash-devutils'
end
更改这些值以适应你的插件是合适的。特别是,s.name 和 s.summary 应该反映你的插件的名称和行为。
s.licenses 和 s.version 也非常重要,当准备发布插件时它们将发挥作用。
Logstash 及其所有插件均根据 Apache License, version 2 ("ALv2") 获得许可。如果你通过 RubyGems.org 公开提供你的插件,请确保在 gemspec 中包含此行
s.licenses = ['Apache License (2.0)']
由 s.version 指定的 gem 版本有助于随时间跟踪插件的更改。你应该对版本号使用 语义化版本控制(semver) 策略。
gemspec 文件的底部是一个带有注释的部分:Gem dependencies。这是必须提及任何其他所需 gem 的地方。如果某个 gem 对于插件的运行是必不可少的,则它是运行时依赖项。如果某个 gem 仅用于测试,则它是开发依赖项。
你还可以对依赖项(包括其他 Logstash 插件)提出版本控制要求
# Gem dependencies
s.add_runtime_dependency "logstash-core-plugin-api", ">= 1.60", "<= 2.99"
s.add_development_dependency 'logstash-devutils'
此 gemspec 对 logstash-core-plugin-api 具有运行时依赖关系,并要求其版本号大于或等于 1.60 且小于或等于 2.99。
所有插件都对 logstash-core-plugin-api gem 具有运行时依赖关系,并对 logstash-devutils 具有开发依赖关系。
在某些情况下,例如 Elasticsearch 输出插件,你的代码可能依赖于一个 jar 文件。在这种情况下,依赖项是以这种方式添加到 gemspec 文件中的
# Jar dependencies
s.requirements << "jar 'org.elasticsearch:elasticsearch', '5.0.0'"
s.add_runtime_dependency 'jar-dependencies'
定义了这两者后,安装过程将在 http://mvnrepository.com 上搜索所需的 jar 文件并下载指定的版本。
文档是插件的重要组成部分。所有插件文档都会被渲染并放置在 Logstash 参考文档和版本化插件文档中。
有关提示和指南,请参阅编写插件文档。
Logstash 酷爱测试。大量的测试。如果你在生产环境中使用新的过滤插件,你会希望有一些测试来确保你没有破坏任何现有的功能。
对 RSpec 的全面阐述超出了本文档的范围。在 https://rspec.ruby-lang.org.cn 了解有关 RSpec 的更多信息
要了解有关测试的帮助信息,请查看其他几个类似插件的 spec/filters/ 目录。
现在,让我们从插件的全新克隆开始,构建它并运行测试。
将你的插件克隆到临时位置 将
GITUSERNAME替换为你的 github 用户名,将MYPLUGINNAME替换为你的插件名称。git clone https://github.com/GITUSERNAME/logstash-``filter-MYPLUGINNAME.git- 或者通过 ssh:
git clone git@github.com:GITUSERNAME/logstash-``filter-MYPLUGINNAME.git
- 或者通过 ssh:
cd logstash-filter-MYPLUGINNAME
然后,你需要使用 bundler 安装插件的依赖项
bundle install
如果你的插件具有 vendor.json 中描述的外部文件依赖项,则必须在运行或测试之前下载该依赖项。你可以通过运行以下命令来完成此操作
rake vendor
最后,运行测试
bundle exec rspec
你应该会看到一条成功消息,它看起来类似于这样
Finished in 0.034 seconds
1 example, 0 failures
太棒了!你快成功了!(除非你看到了失败……你应该先修复那些错误)。
现在你准备好将你的(经过充分测试的)插件构建为 Ruby gem 了。
你已经拥有了所有必要的要素,因此让我们继续运行构建命令
gem build logstash-filter-example.gemspec
就是这样!你的 gem 应该已经构建完成,并且位于相同的路径下,名称为
logstash-filter-mypluginname-0.1.0.gem
gemspec 文件中的 s.version 号将提供 gem 版本,在本例中为 0.1.0。
你应该将插件测试安装到全新安装的 Logstash 中。从 Logstash 下载页面下载最新版本。
解压 tar 包并进入该目录
curl -O https://download.elastic.co/logstash/logstash/logstash-9.0.0.tar.gz tar xzvf logstash-9.0.0.tar.gz cd logstash-9.0.0使用插件工具,我们可以安装刚刚构建的 gem。
将
/my/logstash/plugins替换为你环境中 gem 的正确路径,并将0.1.0替换为 gemspec 文件中的正确版本号。bin/logstash-plugin install /my/logstash/plugins/logstash-filter-example/logstash-filter-example-0.1.0.gem运行此命令后,你应该会看到来自 Logstash 的反馈,表明它已成功安装
validating /my/logstash/plugins/logstash-filter-example/logstash-filter-example-0.1.0.gem >= 0 Valid logstash plugin. Continuing... Successfully installed 'logstash-filter-example' with version '0.1.0'提示你还可以使用 Logstash 插件工具来确定当前可用的插件
bin/logstash-plugin list根据你安装的内容,你可能会看到一个简短或很长的插件列表:inputs(输入)、codecs(编解码器)、filters(过滤器)和 outputs(输出)。
现在尝试使用
-e标志通过命令行传入简单的配置来运行 Logstash。注意你的结果将取决于你的过滤插件旨在做什么。
bin/logstash -e 'input { stdin{} } filter { example {} } output {stdout { codec => rubydebug }}'
通过 stdin 发送输入并通过带有 rubydebug 编解码器(可提高可读性)的 stdout 输出(过滤后)来测试你的过滤器。
以示例过滤插件为例,你发送的任何文本都将被 message 配置参数的内容替换,默认值为 "Hello World!"
Testing 1, 2, 3
{
"message" => "Hello World!",
"@version" => "1",
"@timestamp" => "2015-01-27T19:17:18.932Z",
"host" => "cadenza"
}
随时可以通过更改 message 参数来对其进行实验和测试
bin/logstash -e 'input { stdin{} } filter { example { message => "This is a new message!"} } output {stdout { codec => rubydebug }}'
恭喜!你已经构建、部署并成功运行了一个 Logstash 过滤器。
Logstash 使用 RubyGems.org 作为其所有插件构件的仓库。开发完新插件后,只需将其发布到 RubyGems.org,即可让 Logstash 用户使用它。
Logstash 及其所有插件均采用 Apache 2.0 许可证 ("ALv2")。如果您通过 RubyGems.org 公开发布您的插件,请确保在您的 gemspec 文件中包含以下这行代码:
s.licenses = ['Apache License (2.0)']
首先,你需要在 RubyGems.org 上拥有一个账号
创建帐户后,从 RubyGems.org 获取一个 API 密钥。默认情况下,RubyGems 使用 ~/.gem/credentials 文件来存储您的 API 密钥。这些凭据将用于发布 gem。请将 username 和 password 替换为您在 RubyGems.org 上创建的凭据。
curl -u username:password https://rubygems.org.cn/api/v1/api_key.yaml > ~/.gem/credentials
chmod 0600 ~/.gem/credentials
在继续之前,请确保您的 gemspec 文件中版本号正确,并提交您的更改。
s.version = '0.1.0'
要发布您的新 logstash gem 的 0.1.0 版本
bundle install
bundle exec rake vendor
bundle exec rspec
bundle exec rake publish_gem
执行 rake publish_gem
- 从 gemspec 文件中读取版本号 (
s.version = '0.1.0') - 在您的本地仓库中检查是否存在该版本的标签。如果标签已存在,它将中止该过程。否则,它会在您的本地仓库中创建一个新的版本标签。
- 构建 gem
- 将 gem 发布到 RubyGems.org
完成了!您的插件已发布!Logstash 用户现在可以通过运行以下命令来安装您的插件:
bin/logstash-plugin install logstash-filter-mypluginname
不强制要求将你的源代码贡献给 logstash-plugins github 组织,但我们总是欢迎新插件!
将你的插件纳入 logstash-plugins 仓库的众多好处包括:
- 易于发现。你的插件将出现在 Logstash 参考文档中,Logstash 用户通常首先会在那里查找插件和文档。
- 文档。你的插件文档将自动添加到 Logstash 参考文档中。
- 测试。通过我们的测试基础设施,你的插件将针对 Logstash 的当前和未来版本进行持续测试。因此,用户可以确信,如果出现不兼容问题,将会被迅速发现并纠正。
- 代码审查。 您的插件必须经过社区成员的审查,以确保其连贯性、质量、可读性、稳定性和安全性。
- 测试。你的插件必须包含测试才能被接受。这些测试还需要接受代码审查以检查其范围和完整性。如果你不知道如何编写测试也没关系——我们会指导你。我们正在努力发布一本关于为 Logstash 创建测试的指南,这将使之更加容易。同时,你可以参考 http://betterspecs.org/ 获取示例。
要开始将你的插件迁移到 logstash-plugins,只需在 Logstash 仓库中创建一个新的 issue。当验收准则完成后,我们将使用推荐的 github 流程协助迁移到 logstash-plugins 组织。