要为 Logstash 开发新的输入插件,需要构建一个自包含的 Ruby gem,其源代码位于其自己的 GitHub 存储库中。然后,可以将 Ruby gem 托管并在 RubyGems.org 上共享。您可以使用示例输入实现作为起点。(如果您不熟悉 Ruby,可以在 https://www.ruby-lang.org.cn/en/documentation/quickstart/ 找到一个优秀的快速入门指南。)
让我们逐步使用 示例输入插件 创建一个输入插件。
每个 Logstash 插件都位于其自己的 GitHub 存储库中。要为您的插件创建一个新的存储库
- 登录 GitHub。
- 点击 存储库 选项卡。您将看到您已分叉或贡献的其他存储库的列表。
- 点击右上角的绿色 新建 按钮。
-
为您的新存储库指定以下设置
-
存储库名称 — 一个格式为
logstash-input-pluginname
的唯一名称。 - 公开或私有 — 您的选择,但如果您想将其作为官方插件提交,则存储库必须是公开的。
- 使用自述文件初始化此存储库 — 使您可以立即将存储库克隆到您的计算机。
-
存储库名称 — 一个格式为
- 点击 创建存储库。
您可以在几秒钟内创建自己的 Logstash 插件!bin/logstash-plugin
的 generate
子命令使用模板化文件创建 Logstash 插件的基础。它创建正确的目录结构、gemspec 文件和依赖项,以便您可以开始添加自定义代码以使用 Logstash 处理数据。
有关更多信息,请参阅 生成插件
或者,您可以使用我们在 github.com 上托管的示例存储库
-
克隆您的插件。 将
GITUSERNAME
替换为您的 github 用户名,将MYPLUGINNAME
替换为您的插件名称。-
git clone https://github.com/GITUSERNAME/logstash-
input-MYPLUGINNAME.git
- 或者,通过 ssh:
git clone [email protected]:GITUSERNAME/logstash
-input-MYPLUGINNAME.git
- 或者,通过 ssh:
-
cd logstash-input-MYPLUGINNAME
-
-
克隆输入插件示例并将其复制到您的插件分支。
您不希望包含示例 .git 目录或其内容,因此在复制示例之前将其删除。
-
cd /tmp
-
git clone https://github.com/logstash-plugins/logstash
-input-example.git
-
cd logstash-input-example
-
rm -rf .git
-
cp -R * /path/to/logstash-input-mypluginname/
-
-
重命名以下文件以匹配您的插件名称。
-
logstash-input-example.gemspec
-
example.rb
-
example_spec.rb
cd /path/to/logstash-input-mypluginname mv logstash-input-example.gemspec logstash-input-mypluginname.gemspec mv lib/logstash/inputs/example.rb lib/logstash/inputs/mypluginname.rb mv spec/inputs/example_spec.rb spec/inputs/mypluginname_spec.rb
-
您的文件结构应如下所示
$ tree logstash-input-mypluginname ├── Gemfile ├── LICENSE ├── README.md ├── Rakefile ├── lib │ └── logstash │ └── inputs │ └── mypluginname.rb ├── logstash-input-mypluginname.gemspec └── spec └── inputs └── mypluginname_spec.rb
有关 Ruby gem 文件结构和 Ruby gem 创建过程的优秀演练的更多信息,请参阅 http://timelessrepo.com/making-ruby-gems
在深入了解细节之前,请在您喜欢的文本编辑器中打开插件文件并查看。
require "logstash/inputs/base" require "logstash/namespace" require "stud/interval" require "socket" # for Socket.gethostname # Add any asciidoc formatted documentation here # Generate a repeating message. # # This plugin is intended only as an example. class LogStash::Inputs::Example < LogStash::Inputs::Base config_name "example" # If undefined, Logstash will complain, even if codec is unused. default :codec, "plain" # The message string to use in the event. config :message, :validate => :string, :default => "Hello World!" # Set how frequently messages should be sent. # # The default, `1`, means send a message every second. config :interval, :validate => :number, :default => 1 public def register @host = Socket.gethostname end # def register def run(queue) Stud.interval(@interval) do event = LogStash::Event.new("message" => @message, "host" => @host) decorate(event) queue << event end # loop end # def run end # class LogStash::Inputs::Example
现在让我们逐行查看示例插件。
让我们遍历插件本身的各个元素。
输入插件类应该是 LogStash::Inputs::Base
的子类
class LogStash::Inputs::Example < LogStash::Inputs::Base
类名应与插件名称非常相似,例如
LogStash::Inputs::Example
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
和 run
。
public def register end # def register
Logstash register
方法类似于 initialize
方法。它最初是为了强制调用 super
而创建的,避免了新手出现头痛问题。(注意:它可能会被 initialize
取代,并结合一些强制性测试以确保调用了 super
。)
public
表示该方法可以在任何地方调用,而不仅仅是在类中。这是 Ruby 中方法的默认行为,但这里还是明确指定了它。
您也可以在此处分配实例变量(以 @
开头的变量)。配置变量现在在作用域内作为实例变量,例如 @message
示例输入插件具有以下 run
方法
def run(queue) Stud.interval(@interval) do event = LogStash::Event.new("message" => @message, "host" => @host) decorate(event) queue << event end # loop end # def run
在 run
方法中,来自输入的数据流将变为事件。
数据流可以是纯文本或生成的,如 心跳 输入插件一样。在这些情况下,即使没有使用编解码器,也必须在代码中设置 默认编解码器 以避免错误。
这是另一个 run
方法示例
def run(queue) while true begin # Based on some testing, there is no way to interrupt an IO.sysread nor # IO.select call in JRuby. data = $stdin.sysread(16384) @codec.decode(data) do |event| decorate(event) event.set("host", @host) if !event.include?("host") queue << event end rescue IOError, EOFError, LogStash::ShutdownSignal # stdin closed or a requested shutdown break end end # while true finished end # def run
在此示例中,data
被发送到配置块中定义的编解码器以 decode
数据流并返回事件。
在这两个示例中,生成的 event
都传递给 decorate
方法
decorate(event)
这将应用您可能在输入配置块中设置的任何标签。例如,tags => ["tag1", "tag2"]
。
此外,在这两个示例中,“装饰”后的 event
都附加到队列中
queue << event
这会将事件插入管道中。
由于输入插件的范围从简单到复杂,因此查看更多关于它们创建方式的示例很有帮助
在 logstash-plugin github 存储库 中还有更多其他示例。
在流程的这一点上,您已经编写了插件并准备从中构建一个 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 引入了弃用日志记录器,使处理这些情况变得更容易。您可以使用 适配器 确保您的插件可以使用弃用日志记录器,同时仍然支持旧版本的 Logstash。有关更多信息以及有关使用适配器的说明,请参阅 自述文件。
弃用记录在 log
目录中的 logstash-deprecation.log
文件中。
Gemfile 允许 Ruby 的 Bundler 维护插件的依赖项。目前,我们只需要 Logstash gem 用于测试,但如果您需要其他 gem,则应在此处添加它们。
有关更多详细信息,请参阅 Bundler 的 Gemfile 页面。
source 'https://rubygems.org.cn' gemspec gem "logstash", :github => "elastic/logstash", :branch => "8.16"
Gemspec 定义将要构建的 Ruby gem 并包含您的插件。
有关更多信息,请参阅 Rubygems 规范页面。
Gem::Specification.new do |s| s.name = 'logstash-input-example' s.version = '0.1.0' s.licenses = ['Apache License (2.0)'] s.summary = "This input 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 = '[email protected]' s.homepage = "https://elastic.ac.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" => "input" } # 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 许可证 2.0 版 (“ALv2”) 下获得许可。如果您通过 RubyGems.org 公开发布您的插件,请确保您的 gemspec 中包含此行
-
s.licenses = ['Apache License (2.0)']
由 s.version
指定的 gem 版本有助于跟踪插件随时间的变化。您应该使用 语义化版本控制 策略作为版本号。
在 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 热爱测试。大量的测试。如果您在生产环境中使用新的输入插件,则需要进行一些测试以确保您不会破坏任何现有功能。
本文档不包含关于 RSpec 的完整阐述。在 https://rspec.ruby-lang.org.cn 了解更多关于 RSpec 的信息
有关学习测试和测试的帮助,请查看其他几个类似插件的 spec/inputs/
目录。
现在让我们从插件的新克隆开始,构建它并运行测试。
-
将您的插件克隆到临时位置 将
GITUSERNAME
替换为您的 github 用户名,并将MYPLUGINNAME
替换为您的插件名称。-
git clone https://github.com/GITUSERNAME/logstash-
input-MYPLUGINNAME.git
- 或者,通过 ssh:
git clone [email protected]:GITUSERNAME/logstash-
input-MYPLUGINNAME.git
- 或者,通过 ssh:
-
cd logstash-input-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-input-example.gemspec
就是这样!您的 gem 应该已经构建完成,并位于同一路径下,名称为
logstash-input-mypluginname-0.1.0.gem
来自您的 gemspec 文件的 s.version
号码将提供 gem 版本,在本例中为 0.1.0
。
您应该在 Logstash 的干净安装中测试安装您的插件。从 Logstash 下载页面 下载最新版本。
-
解压缩并 cd 到目录中
curl -O https://download.elastic.co/logstash/logstash/logstash-8.16.0.tar.gz tar xzvf logstash-8.16.0.tar.gz cd logstash-8.16.0
-
使用插件工具,我们可以安装我们刚刚构建的 gem。
-
将
/my/logstash/plugins
替换为适合您环境的 gem 的正确路径,并将0.1.0
替换为 gemspec 文件中正确的版本号。bin/logstash-plugin install /my/logstash/plugins/logstash-input-example/logstash-input-example-0.1.0.gem
-
运行此命令后,您应该会看到 Logstash 反馈已成功安装
validating /my/logstash/plugins/logstash-input-example/logstash-input-example-0.1.0.gem >= 0 Valid logstash plugin. Continuing... Successfully installed 'logstash-input-example' with version '0.1.0'
您还可以使用 Logstash 插件工具来确定当前可用的插件
bin/logstash-plugin list
根据您安装的内容,您可能会看到一个简短或冗长的插件列表:输入、编解码器、过滤器和输出。
-
-
现在尝试使用通过命令行传递的简单配置运行 Logstash,使用
-e
标志。您的结果将取决于您的输入插件的设计用途。
bin/logstash -e 'input { example{} } output {stdout { codec => rubydebug }}'
示例输入插件将每秒发送 message
的内容(默认消息为“Hello World!”)。
{ "message" => "Hello World!", "@version" => "1", "@timestamp" => "2015-01-27T19:17:18.932Z", "host" => "cadenza" }
随意通过更改 message
和 interval
参数进行实验和测试
bin/logstash -e 'input { example{ message => "A different message" interval => 5 } } output {stdout { codec => rubydebug }}'
恭喜!您已构建、部署并成功运行了 Logstash 输入。
将您的插件提交到 RubyGems.org 和 logstash-plugins
Logstash 使用 RubyGems.org 作为其所有插件工件的存储库。开发完新插件后,您可以通过将其发布到 RubyGems.org 来让 Logstash 用户使用它。
Logstash 及其所有插件均在 Apache 许可证 2.0 版 (“ALv2”) 下获得许可。如果您通过 RubyGems.org 公开发布您的插件,请确保您的 gemspec 中包含此行
-
s.licenses = ['Apache License (2.0)']
发布到 RubyGems.org
首先,您需要在 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-input-mypluginname
将您的源代码贡献到 logstash-plugins
不需要将您的源代码贡献到 logstash-plugins github 组织,但我们始终欢迎新的插件!
将您的插件置于 logstash-plugins 存储库中的众多好处包括
- 发现。 您的插件将出现在 Logstash 参考 中,Logstash 用户首先在其中查找插件和文档。
- 文档。 您的插件文档将自动添加到 Logstash 参考 中。
- 测试。 通过我们的测试基础设施,您的插件将针对 Logstash 的当前版本和未来版本进行持续测试。因此,用户可以确信,如果出现不兼容性,将很快被发现并纠正。
- 代码审查。 您的插件必须由社区成员审查其一致性、质量、可读性、稳定性和安全性。
- 测试。 您的插件必须包含测试才能被接受。这些测试也将接受代码审查以确保范围和完整性。如果您不知道如何编写测试,也没关系——我们会指导您。我们正在努力发布一份关于为 Logstash 创建测试的指南,这将使操作更容易。同时,您可以参考http://betterspecs.org/ 获取示例。
要开始将您的插件迁移到 logstash-plugins,只需在 Logstash 存储库中创建一个新的问题。当验收指南完成时,我们将使用推荐的GitHub 流程促进迁移到 logstash-plugins 组织。