Filter 使用字段作为Logstash Grok过滤器模式的输入

Filter 使用字段作为Logstash Grok过滤器模式的输入,filter,logstash,grok,Filter,Logstash,Grok,我想知道是否可以使用Logstash消息中的字段作为Grok模式的输入。假设我有一个条目,看起来像: { "message":"10.1.1.1", "grok_filter":"%{IP:client}" } 我希望能够做到以下几点: filter { grok { match => ["message", ["%{grok_filter}"]] } } 问题是这会使Logstash崩溃,因为它似乎将“{grok_filter}”视为grok filt

我想知道是否可以使用Logstash消息中的字段作为Grok模式的输入。假设我有一个条目,看起来像:

{
    "message":"10.1.1.1",
    "grok_filter":"%{IP:client}"
}
我希望能够做到以下几点:

filter {
  grok {
    match => ["message", ["%{grok_filter}"]]
  }
}
问题是这会使Logstash崩溃,因为它似乎将“{grok_filter}”视为grok filter本身,而不是grok_filter的值。Logstash崩溃后,我得到以下信息:

The error reported is: 
  pattern %{grok_filter} not defined
是否可以从Grok筛选器块内部获取字段值并将其用作Grok模式的输入?

答案是否--
Grok
筛选器在初始化筛选器时编译其模式。如果需要这样做,您必须编写自己的过滤器,每次编译模式(并支付性能损失)

如果你不知道为什么要这样做,就很难推荐最佳的行动方案。如果模式数量有限,只需设置一个
grok\u filter\u type
参数,然后在[grok\u filter\u type]='ip'{grok{…}类型的情况下设置一组

这里有一个自定义过滤器,它允许您做您想做的事情——它主要是grok代码的副本,但有一些更改/简化。我已经测试过了,它似乎对我有用

# encoding: utf-8
require "logstash/filters/base"
require "logstash/namespace"
require "logstash/environment"
require "set"

# A version of grok that can parse from a log-defined pattern.  Not really
# recommended for high usage patterns, but for the occassional pattern it
# should work
#     filter {
#       grok_dynamic {
#         match_field => "message"
#     pattern_field => "message_pattern"
#       }
#     }
#
class LogStash::Filters::GrokDynamic < LogStash::Filters::Base
  config_name "grok_dynamic"
  milestone 1

  # The field that contains the data to match against
  config :match_field, :validate => :string, :required => true
  # the field that contains the pattern
  config :pattern_field, :validate => :string, :required => true
  # where the patterns are
  config :patterns_dir, :validate => :array, :default => []

  # If true, only store named captures from grok.
  config :named_captures_only, :validate => :boolean, :default => true

  # If true, keep empty captures as event fields.
  config :keep_empty_captures, :validate => :boolean, :default => false

  # Append values to the 'tags' field when there has been no
  # successful match
  config :tag_on_failure, :validate => :array, :default => ["_grokparsefailure"]

  # The fields to overwrite.
  #
  # This allows you to overwrite a value in a field that already exists.
  config :overwrite, :validate => :array, :default => []

  # Detect if we are running from a jarfile, pick the right path.
  @@patterns_path ||= Set.new
  @@patterns_path += [LogStash::Environment.pattern_path("*")]

  public
  def initialize(params)
    super(params)
    @handlers = {}
  end

  public
  def register
    require "grok-pure" # rubygem 'jls-grok'

    @patternfiles = []

    # Have @@patterns_path show first. Last-in pattern definitions win; this
    # will let folks redefine built-in patterns at runtime.
    @patterns_dir = @@patterns_path.to_a + @patterns_dir
    @logger.info? and @logger.info("Grok patterns path", :patterns_dir => @patterns_dir)
    @patterns_dir.each do |path|
      if File.directory?(path)
        path = File.join(path, "*")
      end

      Dir.glob(path).each do |file|
        @logger.info? and @logger.info("Grok loading patterns from file", :path => file)
        @patternfiles << file
      end
    end

    @patterns = Hash.new { |h,k| h[k] = [] }

    @grok = Grok.new
    @patternfiles.each { |path| @grok.add_patterns_from_file(path) }

  end # def register

  public
  def filter(event)
    return unless filter?(event)
    return if event[@match_field].nil? || event[@pattern_field].nil?

    @logger.debug? and @logger.debug("Running grok_dynamic filter", :event => event);
    @grok.compile(event[@pattern_field]);
    if match(@grok,@match_field, event)
      filter_matched(event)
    else
      # Tag this event if we can't parse it. We can use this later to
      # reparse+reindex logs if we improve the patterns given.
      @tag_on_failure.each do |tag|
        event["tags"] ||= []
        event["tags"] << tag unless event["tags"].include?(tag)
      end
    end

    @logger.debug? and @logger.debug("Event now: ", :event => event)
  end # def filter

  private
  def match(grok, field, event)
    input = event[field]
    if input.is_a?(Array)
      success = true
      input.each do |input|
        match = grok.match(input)
        if match
          match.each_capture do |capture, value|
            handle(capture, value, event)
          end
        else
          success = false
        end
      end
      return success
    #elsif input.is_a?(String)
    else
      # Convert anything else to string (number, hash, etc)
      match = grok.match(input.to_s)
      return false if !match

      match.each_capture do |capture, value|
        handle(capture, value, event)
      end
      return true
    end
  rescue StandardError => e
    @logger.warn("Grok regexp threw exception", :exception => e.message)
  end

  private
  def handle(capture, value, event)
    handler = @handlers[capture] ||= compile_capture_handler(capture)
    return handler.call(value, event)
  end

  private
  def compile_capture_handler(capture)
    # SYNTAX:SEMANTIC:TYPE
    syntax, semantic, coerce = capture.split(":")

    # each_capture do |fullname, value|
    #   capture_handlers[fullname].call(value, event)
    # end

    code = []
    code << "# for capture #{capture}"
    code << "lambda do |value, event|"
    #code << "  p :value => value, :event => event"
    if semantic.nil?
      if @named_captures_only
        # Abort early if we are only keeping named (semantic) captures
        # and this capture has no semantic name.
        code << "  return"
      else
        field = syntax
      end
    else
      field = semantic
    end
    code << "  return if value.nil? || value.empty?" unless @keep_empty_captures
    if coerce
      case coerce
        when "int"; code << "  value = value.to_i"
        when "float"; code << "  value = value.to_f"
      end
    end

    code << "  # field: #{field}"
    if @overwrite.include?(field)
      code << "  event[field] = value"
    else
      code << "  v = event[field]"
      code << "  if v.nil?"
      code << "    event[field] = value"
      code << "  elsif v.is_a?(Array)"
      code << "    event[field] << value"
      code << "  elsif v.is_a?(String)"
      # Promote to array since we aren't overwriting.
      code << "    event[field] = [v, value]"
      code << "  end"
    end
    code << "  return"
    code << "end"

    #puts code
    return eval(code.join("\n"), binding, "<grok capture #{capture}>")
  end # def compile_capture_handler

end # class LogStash::Filters::Grok
编码:utf-8 需要“日志存储/过滤器/基础” 需要“日志存储/命名空间” 需要“日志/环境” 需要“设置” #grok的一个版本,可以从日志定义的模式进行解析。不完全是 #推荐用于高使用率模式,但对于偶然模式 #应该有用 #滤器{ #格罗库动力{ #匹配_字段=>“消息” #模式\字段=>“消息\模式” # } # } # 类LogStash::Filters::GrokDynamic:string,:required=>true #包含模式的字段 config:pattern_字段,:validate=>:string,:required=>true #模式在哪里 配置:patterns\u dir,:validate=>:array,:default=>[] #如果为true,则仅存储来自grok的命名捕获。 config:named_仅捕获_,:validate=>:boolean,:default=>true #如果为true,则将空捕获保留为事件字段。 配置:keep_empty_捕获,:validate=>:boolean,:default=>false #当没有标记时,将值附加到“标记”字段 #成功的比赛 config:tag\u on\u failure,:validate=>:array,:default=>[“\u grokparsefailure”] #要覆盖的字段。 # #这允许您覆盖已存在字段中的值。 配置:overwrite,:validate=>:array,:default=>[] #检测是否从JAR文件运行,选择正确的路径。 @@patterns|u path | |=Set.new @@patterns\u path+=[LogStash::Environment.pattern\u path(“*”)] 公众的 def初始化(参数) 超级(参数) @处理程序={} 结束 公众的 def寄存器 需要“grok pure”#rubygem'jls grok' @模式文件=[] #首先显示@@patterns\u路径。最后在模式定义中获胜;这 #将允许人们在运行时重新定义内置模式。 @patterns_dir=@@patterns_path.to_a+@patterns_dir @logger.info?和@logger.info(“Grok patterns path”,:patterns\u dir=>@patterns\u dir) @模式_dir.每个do |路径| if File.directory?(路径) path=File.join(路径“*”) 结束 Dir.glob(path)| @logger.info?和@logger.info(“Grok从文件加载模式”,:path=>file) @事件); @编译(事件[@pattern_field]); 如果匹配(@grok,@match_字段,事件) 过滤器匹配(事件) 其他的 #如果无法分析此事件,请标记它。我们以后可以用这个来 #如果我们改进给定的模式,请重新分析并重新索引日志。 @标记故障。每个do标记| 事件[“标记”]| |=[] 事件[“标记”]事件) 结束#def过滤器 私有的 def匹配(地面、场地、事件) 输入=事件[字段] 如果输入。_是?(数组) 成功=正确 输入。每个do |输入| 匹配=全局匹配(输入) 如果匹配 匹配。每个捕获都做捕获,值| 句柄(捕获、值、事件) 结束 其他的 成功=错误 结束 结束 回归成功 #elsif输入。是否为?(字符串) 其他的 #将其他内容转换为字符串(数字、哈希等) match=grok.match(输入到) 如果返回false!比赛 匹配。每个捕获都做捕获,值| 句柄(捕获、值、事件) 结束 返回真值 结束 营救标准错误=>e @logger.warn(“Grok regexp抛出异常”,:异常=>e.message) 结束 私有的 def句柄(捕获、值、事件) handler=@handlers[capture]| |=compile_capture_handler(capture) 返回处理程序.call(值、事件) 结束 私有的 def编译捕获处理程序(捕获) #语法:语义:类型 语法,语义,强制=capture.split(“:”) #每个捕获都有全名、值| #捕获\u处理程序[fullname]。调用(值、事件) #结束 代码=[]
代码用例是一个日志解决方案,其中发送日志的客户端能够包含一个“type”属性(使用logstash转发器),因此我可以在服务器端定义许多grok模式。但是,如果我想解析一个不太常见的日志,我宁愿在客户机上配置grok Patrn,而不是每次都重新配置和重新启动logstash。我还没有仔细查看Grok的来源。您认为我可以通过提供一个模式和一个父名称来调整Grok过滤器,以便在第一次收到它时编译过滤器吗?i、 grok_名称,grok_模式作为字段?这似乎是你最好的选择。。。基于grok制作一个新的过滤器,可以从grok_字段中获取grok_,然后以这种方式重新设置新的grok过滤器。。。可以摆脱处理一系列pat的复杂性