正在加载

如何编写 Logstash 输入插件

要为 Logstash 开发新的输入,请构建一个独立的 Ruby gem,其源代码位于自己的 GitHub 仓库中。然后,可以将 Ruby gem 托管在 RubyGems.org 上并进行共享。您可以将示例输入实现用作起点。(如果您不熟悉 Ruby,可以在 https://ruby-lang.org.cn/en/documentation/quickstart/ 找到一个出色的快速入门指南。)

让我们逐步了解如何使用 示例输入插件 创建输入插件。

每个 Logstash 插件都位于自己的 GitHub 仓库中。要为您的插件创建一个新的仓库

  1. 登录到 GitHub。

  2. 点击 Repositories 选项卡。您将看到您已 fork 或贡献的其他仓库的列表。

  3. 点击右上角的绿色 New 按钮。

  4. 为您的新仓库指定以下设置

    • Repository name — 形式为 logstash-input-pluginname 的唯一名称。
    • Public or Private — 您的选择,但如果您想将其作为官方插件提交,则仓库必须为 Public。
    • Initialize this repository with a README — 使您能够立即将仓库克隆到您的计算机。
  5. 点击 Create Repository

您可以在几秒钟内创建自己的 Logstash 插件!bin/logstash-plugingenerate 子命令使用模板化文件为新的 Logstash 插件创建基础。它创建正确的目录结构、gemspec 文件和依赖项,以便您可以开始添加自定义代码以使用 Logstash 处理数据。

有关更多信息,请参阅 生成插件

或者,您可以使用我们在 github.com 上托管的示例仓库

  1. 克隆您的插件。GITUSERNAME 替换为您的 github 用户名,将 MYPLUGINNAME 替换为您的插件名称。

    • git clone https://github.com/GITUSERNAME/logstash-``input-MYPLUGINNAME.git

      • 或者,通过 ssh:git clone git@github.com:GITUSERNAME/logstash``-input-MYPLUGINNAME.git
    • cd logstash-input-MYPLUGINNAME

  2. 克隆输入插件示例并将其复制到您的插件分支。

    您不想包含示例 .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/
  3. 重命名以下文件以匹配您的插件名称。

    • 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"

# 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 run(queue)
    Stud.interval(@interval) do
      event = LogStash::Event.new("message" => @message, "host" => @host)
      decorate(event)
      queue << event
    end
  end

end
  1. for Socket.gethostname
  2. def register
  3. loop
  4. def run
  5. class LogStash::Inputs::Example

现在让我们逐行查看示例插件。

Logstash 输入插件需要 logstash/inputs/base 和 logstash/namespace 中定义的父类

require "logstash/inputs/base"
require "logstash/namespace"

当然,您构建的插件可能依赖于其他代码,甚至 gem。只需将它们与这些 Logstash 依赖项一起放在此处。

让我们来了解一下插件本身的各种元素。

输入插件类应该是 LogStash::Inputs::Base 的子类

class LogStash::Inputs::Example < LogStash::Inputs::Base

类名应与插件名称密切相关,例如

LogStash::Inputs::Example
config_name "example"

这是您的插件将在输入配置块内部调用的名称。

如果您在插件代码中设置 config_name "example",则相应的 Logstash 配置块需要如下所示

input {
  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 - 信息性(也是布尔值 truefalse
  • :obsolete - 用于声明给定的设置已被删除且不再起作用。目的是为仍在使用的现在已删除的设置的用户提供明智的升级路径。

Logstash 输入必须实现两个主要方法:registerrun

public
def register
end
  1. 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
end
  1. loop
  2. def run

run 方法是来自输入的数据流变成事件的地方。

该流可以是纯文本的,也可以是生成的,如 heartbeat 输入插件所示。在这些情况下,即使没有使用编解码器,也必须在代码中设置默认编解码器,以避免错误。

这是另一个示例 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
  finished
end
  1. while true
  2. 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 引入了一个弃用日志记录器,以便更轻松地处理这些情况。您可以使用 adapter,以确保您的插件可以使用弃用日志记录器,同时仍支持旧版本的 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-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 = '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" => "input" }

  # Gem dependencies
  s.add_runtime_dependency "logstash-core-plugin-api", ">= 1.60", "<= 2.99"
  s.add_development_dependency 'logstash-devutils'
end

可以根据您的插件调整这些值。特别是,s.names.summary 应反映您插件的名称和行为。

s.licensess.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/inputs/ 目录。

现在让我们从插件的全新克隆开始,构建它并运行测试。

  • 将您的插件克隆到临时位置GITUSERNAME 替换为您的 github 用户名,并将 MYPLUGINNAME 替换为您的插件名称。

    • git clone https://github.com/GITUSERNAME/logstash-``input-MYPLUGINNAME.git

      • 或者,通过 ssh:git clone git@github.com:GITUSERNAME/logstash-``input-MYPLUGINNAME.git
    • 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 下载页面 下载最新版本。

  1. 解压并 cd 进入目录

    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
    
  2. 使用插件工具,我们可以安装刚刚构建的 gem。

    • 用您的环境的 gem 的正确路径替换 /my/logstash/plugins,并用 gemspec 文件中的正确版本号替换 0.1.0

      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
      

      根据您安装的内容,您可能会看到一个简短或很长的插件列表:inputs、codecs、filters 和 outputs。

  3. 现在,尝试使用通过命令行传入的简单配置来运行 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"
}

随意试验和测试,方法是更改 messageinterval 参数

bin/logstash -e 'input { example{ message => "A different message" interval => 5 } } output {stdout { codec => rubydebug }}'

恭喜! 您已经构建、部署并成功运行了 Logstash 输入。

RubyGems.orglogstash-plugins 提交您的插件

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。 用您在 RubyGems.org 创建的凭据替换 usernamepassword

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

  1. 从 gemspec 文件(s.version = '0.1.0')读取版本
  2. 在您的本地存储库中检查是否存在该版本的标签。 如果该标签已存在,则中止该过程。 否则,它将在您的本地存储库中创建一个新的版本标签。
  3. 构建 gem
  4. 将 gem 发布到 RubyGems.org

就这样! 您的插件已发布! Logstash 用户现在可以通过运行以下命令来安装您的插件

bin/logstash-plugin install logstash-input-mypluginname

不需要将您的源代码贡献给 logstash-plugins github 组织,但我们始终欢迎新的插件!

将您的插件放在 logstash-plugins 存储库中的许多好处包括

  • 发现。 您的插件将出现在Logstash 参考中,Logstash 用户首先在此处查找插件和文档。
  • 文档。 您的插件文档将自动添加到 Logstash 参考中。
  • 测试。 借助我们的测试基础设施,您的插件将针对当前和将来的 Logstash 版本进行持续测试。 因此,用户可以放心,如果出现不兼容情况,它们将很快被发现和纠正。
  • 代码审查。 您的插件必须由社区成员进行审查,以确保其连贯性、质量、可读性、稳定性和安全性。
  • 测试。 您的插件必须包含测试才能被接受。 这些测试也需要经过代码审查,以检查其范围和完整性。 即使您不知道如何编写测试也没关系 - 我们会指导您。 我们正在努力发布一个为 Logstash 创建测试的指南,这将使其更容易。 同时,您可以参考 http://betterspecs.org/ 以获取示例。

要开始将您的插件迁移到 logstash-plugins,只需在 Logstash 存储库中创建一个新的 issue。 当验收指南完成后,我们将使用推荐的 github 流程 来促进向 logstash-plugins 组织的转移。

© . All rights reserved.