如何编写 Logstash 输出插件
要为 Logstash 开发新的输出,请构建一个独立的 Ruby gem,其源代码位于自己的 GitHub 仓库中。 然后,可以将 Ruby gem 托管在 RubyGems.org 上并进行共享。 您可以使用示例输出实现作为起点。(如果您不熟悉 Ruby,可以在 https://ruby-lang.org.cn/en/documentation/quickstart/ 找到一个优秀的快速入门指南。)
让我们逐步完成使用 示例输出插件 创建输出插件的过程。
每个 Logstash 插件都位于自己的 GitHub 仓库中。 要为您的插件创建新的仓库
登录到 GitHub。
单击仓库选项卡。 您将看到您已经 fork 或贡献的其他仓库的列表。
单击右上角的绿色新建按钮。
为您的新仓库指定以下设置
- 仓库名称 — 一种唯一名称,格式为
logstash-output-pluginname
。 - 公开或私有 — 您的选择,但如果您想将其作为官方插件提交,则仓库必须是公开的。
- 使用 README 初始化此仓库 — 使您能够立即将仓库克隆到您的计算机。
- 仓库名称 — 一种唯一名称,格式为
单击创建仓库。
您可以在几秒钟内创建自己的 Logstash 插件! bin/logstash-plugin
的 generate
子命令为具有模板化文件的新 Logstash 插件创建基础。 它创建正确的目录结构、gemspec 文件和依赖项,以便您可以开始添加自定义代码以使用 Logstash 处理数据。
有关更多信息,请参见 生成插件
或者,您可以使用我们在 github.com 上托管的示例仓库
克隆您的插件。 将
GITUSERNAME
替换为您的 github 用户名,并将MYPLUGINNAME
替换为您的插件名称。git clone https://github.com/GITUSERNAME/logstash-``output-MYPLUGINNAME.git
- 或者,通过 ssh:
git clone git@github.com:GITUSERNAME/logstash``-output-MYPLUGINNAME.git
- 或者,通过 ssh:
cd logstash-output-MYPLUGINNAME
克隆输出插件示例并将其复制到您的插件分支。
您不想包含示例 .git 目录或其内容,因此在复制示例之前将其删除。
cd /tmp
git clone https://github.com/logstash-plugins/logstash``-output-example.git
cd logstash-output-example
rm -rf .git
cp -R * /path/to/logstash-output-mypluginname/
重命名以下文件以匹配您的插件名称。
logstash-output-example.gemspec
example.rb
example_spec.rb
cd /path/to/logstash-output-mypluginname mv logstash-output-example.gemspec logstash-output-mypluginname.gemspec mv lib/logstash/outputs/example.rb lib/logstash/outputs/mypluginname.rb mv spec/outputs/example_spec.rb spec/outputs/mypluginname_spec.rb
您的文件结构应如下所示
$ tree logstash-output-mypluginname
├── Gemfile
├── LICENSE
├── README.md
├── Rakefile
├── lib
│ └── logstash
│ └── outputs
│ └── mypluginname.rb
├── logstash-output-mypluginname.gemspec
└── spec
└── outputs
└── mypluginname_spec.rb
有关 Ruby gem 文件结构以及 Ruby gem 创建过程的优秀演练的更多信息,请参见 http://timelessrepo.com/making-ruby-gems
在我们深入了解细节之前,请在您喜欢的文本编辑器中打开插件文件并查看一下。
require "logstash/outputs/base"
require "logstash/namespace"
# Add any asciidoc formatted documentation here
# An example output that does nothing.
class LogStash::Outputs::Example < LogStash::Outputs::Base
config_name "example"
# This sets the concurrency behavior of this plugin. By default it is :legacy, which was the standard
# way concurrency worked before Logstash 2.4
#
# You should explicitly set it to either :single or :shared as :legacy will be removed in Logstash 6.0
#
# When configured as :single a single instance of the Output will be shared among the
# pipeline worker threads. Access to the `#multi_receive/#multi_receive_encoded/#receive` method will be synchronized
# i.e. only one thread will be active at a time making threadsafety much simpler.
#
# You can set this to :shared if your output is threadsafe. This will maximize
# concurrency but you will need to make appropriate uses of mutexes in `#multi_receive/#receive`.
#
# Only the `#multi_receive/#multi_receive_encoded` methods need to actually be threadsafe, the other methods
# will only be executed in a single thread
concurrency :single
public
def register
end
public
# Takes an array of events
# Must be threadsafe if `concurrency :shared` is set
def multi_receive(events)
end
end
- def register
- def multi_receive
- class LogStash::Outputs::Example
现在让我们逐行查看示例插件。
Logstash 输出插件需要 logstash/outputs/base
和 logstash/namespace 中定义的父类
require "logstash/outputs/base"
require "logstash/namespace"
当然,您构建的插件可能依赖于其他代码,甚至 gem。 只需将它们与这些 Logstash 依赖项一起放在此处即可。
让我们浏览一下插件的各种元素。
输出插件类应该是 LogStash::Outputs::Base
的子类
class LogStash::Outputs::Example < LogStash::Outputs::Base
类名应与插件名称紧密对应,例如
LogStash::Outputs::Example
config_name "example"
这是您的插件将在输出配置块中调用的名称。
如果您在插件代码中设置 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
和 multi_receive
方法。
public
def register
end
- def register
Logstash register
方法类似于 initialize
方法。 它最初创建的目的是强制调用 super
,以避免新手出现问题。(注意:它可能会被 initialize
取代,同时进行一些强制测试以确保调用 super
。)
public
意味着该方法可以在任何地方调用,而不仅仅是在类中。 这是 Ruby 中方法的默认行为,但无论如何在这里明确指定。
您也可以在此处分配实例变量(以 @
开头的变量)。 配置变量现在在范围内,作为实例变量,如 @message
在此过程的这一点上,您已经编写了插件的代码,并准备从中构建 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
是 sha1 签名,用于验证url
引用的文件的完整性。url
是 Logstash 将从中下载文件的地址。files
是一个可选的文件数组,用于从下载的文件中提取。 请注意,虽然 tar 存档可以使用绝对或相对路径,但在此数组中将其视为绝对路径。 如果files
不存在,则所有文件将被解压缩并提取到 vendor 目录中。
vendor.json
文件的另一个示例是 geoip
过滤器
用于下载这些依赖项的过程是调用 rake vendor
。 这将在本文档的测试部分中进一步讨论。
另一种外部依赖项是 jar 文件。 这将在“添加 gemspec
文件”部分中描述。
随着插件的发展,某个选项或功能可能不再达到预期目的,开发人员可能希望弃用其用法。 弃用会警告用户该选项的状态,以便他们不会在以后的版本中删除该选项时感到意外。
Logstash 7.6 引入了弃用记录器,以简化处理这些情况。 您可以使用 适配器 来确保您的插件可以使用弃用记录器,同时仍支持旧版本的 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-output-example'
s.version = '0.1.0'
s.licenses = ['Apache License (2.0)']
s.summary = "This output 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://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" => "output" }
# 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/outputs/
目录。
现在让我们从一个全新的插件克隆开始,构建它并运行测试。
将您的插件克隆到一个临时位置 将
GITUSERNAME
替换为您的 github 用户名,将MYPLUGINNAME
替换为您的插件名称。git clone https://github.com/GITUSERNAME/logstash-``output-MYPLUGINNAME.git
- 或者,通过 ssh:
git clone git@github.com:GITUSERNAME/logstash-``output-MYPLUGINNAME.git
- 或者,通过 ssh:
cd logstash-output-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-output-example.gemspec
就是这样!您的 gem 应该已构建并位于与名称相同的路径中
logstash-output-mypluginname-0.1.0.gem
来自 gemspec 文件的 s.version
号码将提供 gem 版本,在本例中为 0.1.0
。
您应该测试将您的插件安装到 Logstash 的全新安装中。从 Logstash 下载页面 下载最新版本。
解压并进入目录
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-output-example/logstash-output-example-0.1.0.gem
运行此命令后,您应该会看到来自 Logstash 的反馈,表明它已成功安装
validating /my/logstash/plugins/logstash-output-example/logstash-output-example-0.1.0.gem >= 0 Valid logstash plugin. Continuing... Successfully installed 'logstash-output-example' with version '0.1.0'
提示您还可以使用 Logstash 插件工具来确定当前可用的插件
bin/logstash-plugin list
根据您安装的内容,您可能会看到一个简短或冗长的插件列表:输入、编解码器、过滤器和输出。
现在尝试通过命令行运行 Logstash,使用
-e
标志传递一个简单的配置。注意您的结果将取决于您的输出插件的设计用途。
恭喜!您已经构建、部署并成功运行了 Logstash 输出。
Logstash 使用 RubyGems.org 作为其所有插件工件的存储库。开发完新插件后,您只需将其发布到 RubyGems.org 即可将其提供给 Logstash 用户。
Logstash 及其所有插件均在 Apache License, version 2 ("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-output-mypluginname
不需要将您的源代码贡献给 logstash-plugins github 组织,但我们始终欢迎新的插件!
在 logstash-plugins 存储库中拥有您的插件的一些好处是
- 发现。 您的插件将出现在 Logstash 参考 中,Logstash 用户首先在此处查找插件和文档。
- 文档。 您的插件文档将自动添加到 Logstash 参考 中。
- 测试。 借助我们的测试基础设施,您的插件将针对当前和未来的 Logstash 版本进行持续测试。因此,用户可以确信,如果出现不兼容问题,将会被快速发现和纠正。
- 代码审查。 您的插件必须由社区成员审查,以确保其一致性、质量、可读性、稳定性和安全性。
- 测试。 您的插件必须包含测试才能被接受。这些测试也要经过代码审查,以确保其范围和完整性。如果您不知道如何编写测试也没关系——我们会指导您。我们正在努力发布一个为 Logstash 创建测试的指南,这将使其更容易。同时,您可以参考 http://betterspecs.org/ 获取示例。
要开始将您的插件迁移到 logstash-plugins,只需在 Logstash 存储库中创建一个新的 issue。验收指南完成后,我们将使用推荐的 github 流程 促进迁移到 logstash-plugins 组织。