class LogStash::Filters::Rest

Logstash REST Filter This filter calls a defined URL and saves the answer into a specified field.

Public Instance Methods

filter(event) click to toggle source
# File lib/logstash/filters/rest.rb, line 288
def filter(event)
  return unless filter?(event)
  request = LogStash::Util.deep_clone(@request)
  @logger.debug? && @logger.debug('processing request',
                                  :request => request,
                                  :sprintf_needed => @sprintf_needed)

  if @sprintf_needed
    request = field_intrpl(request, event)
    @logger.debug? && @logger.debug('interpolated request',
                                    :request => request)
  end

  client_error = nil
  begin
    code, body = request_http(request)
  rescue StandardError => e
    client_error = e
  end

  if !client_error && code.between?(200, 299)
    @logger.debug? && @logger.debug('success received',
                                    :code => code, :body => body)
    process_response(body, event)
  else
    @logger.debug? && @logger.debug('http error received',
                                    :code => code, :body => body,
                                    :client_error => client_error)
    if @fallback.empty?
      @logger.error('error in rest filter',
                    :request => request, :json => @json,
                    :code => code, :body => body,
                    :client_error => client_error)
      @tag_on_rest_failure.each { |tag| event.tag(tag) }
    else
      @logger.debug? && @logger.debug('setting fallback',
                                      :fallback => @fallback)
      event.set(@target, @fallback)
    end
  end
  filter_matched(event)
end
register() click to toggle source
# File lib/logstash/filters/rest.rb, line 143
def register
  @request = normalize_request(@request).deep_freeze
  @sprintf_fields = find_sprintf(
    LogStash::Util.deep_clone(@request)
  ).deep_freeze
  @sprintf_needed = !@sprintf_fields.empty?
  @target = normalize_target(@target).freeze
end

Private Instance Methods

field_intrpl(intrpl_fields, event) click to toggle source
# File lib/logstash/filters/rest.rb, line 266
def field_intrpl(intrpl_fields, event)
  case intrpl_fields
  when String
    result = event.sprintf(intrpl_fields)
  when Array
    result = []
    intrpl_fields.each do |v|
      result << field_intrpl(v, event)
    end
  when Hash
    result = {}
    intrpl_fields.each do |k, v|
      result[k] = field_intrpl(v, event)
    end
  else
    result = intrpl_fields
  end
  result
end
find_sprintf(config) click to toggle source
# File lib/logstash/filters/rest.rb, line 208
def find_sprintf(config)
  field_matcher = /%\{[^}]+\}/
  if config.is_a?(Hash)
    config.keep_if do |_k, v|
      find_sprintf(v)
    end.compact
  elsif config.is_a?(Array)
    config.keep_if do |v|
      find_sprintf(v)
    end.compact
  elsif config.is_a?(String) && config =~ field_matcher
    config
  end
end
normalize_request(url_or_spec) click to toggle source
# File lib/logstash/filters/rest.rb, line 164
def normalize_request(url_or_spec)
  if url_or_spec.is_a?(String)
    res = [:get, url_or_spec]
  elsif url_or_spec.is_a?(Hash)
    # The client will expect keys / values
    spec = Hash[url_or_spec.clone.map { |k, v| [k.to_sym, v] }]

    # method and url aren't really part of the options, so we pull them out
    method = (spec.delete(:method) || :get).to_sym.downcase
    url = spec.delete(:url)

    # if it is a post and json, it is used as body string, not params
    spec[:body] = spec.delete(:params) if method == :post && spec[:params]

    # We need these strings to be keywords!
    spec[:auth] = { user: spec[:auth]['user'], pass: spec[:auth]['password'] } if spec[:auth]

    res = [method.freeze, url, spec]
  else
    raise LogStash::ConfigurationError, "Invalid URL or request spec: '#{url_or_spec}', expected a String or Hash!"
  end

  validate_request!(url_or_spec, res)
  res
end
normalize_target(target) click to toggle source
# File lib/logstash/filters/rest.rb, line 154
def normalize_target(target)
  # make sure @target is in the format [field name] if defined,
  # i.e. not empty and surrounded by brakets
  raise LogStash::ConfigurationError, 'target config string is empty, please set a valid field name' if target.empty?
  target = "[#{target}]" if target && target !~ /^\[[^\[\]]+\]$/
  target
end
process_response(response, event) click to toggle source
# File lib/logstash/filters/rest.rb, line 239
def process_response(response, event)
  if @json
    begin
      parsed = LogStash::Json.load(response)
      if parsed.empty?
        @logger.warn('rest response empty',
                     :response => response, :event => event)
        @tag_on_rest_failure.each { |tag| event.tag(tag) }
      else
        event.set(@target, parsed)
      end
    rescue
      if @fallback.empty?
        @logger.warn('JSON parsing error',
                     :response => response, :event => event)
        @tag_on_json_failure.each { |tag| event.tag(tag) }
      else
        event.set(@target, @fallback)
      end
    end
  else
    event.set(@target, response.strip)
  end
end
request_http(request) click to toggle source
# File lib/logstash/filters/rest.rb, line 225
def request_http(request)
  if request[2].key?(:body) && @json
    request[2][:body] = LogStash::Json.dump(request[2][:body])
  end
  @logger.debug? && @logger.debug('fetching request',
                                  :request => request)

  method, url, *request_opts = request
  response = client.http(method, url, *request_opts)
  [response.code, response.body]
end
validate_request!(url_or_spec, request) click to toggle source
# File lib/logstash/filters/rest.rb, line 192
def validate_request!(url_or_spec, request)
  method, url, spec = request

  raise LogStash::ConfigurationError, "No URL provided for request! #{url_or_spec}" unless url
  raise LogStash::ConfigurationError, "Not supported request method #{method}" unless [ :get, :post ].include?( method )

  if spec && spec[:auth]
    raise LogStash::ConfigurationError, "Auth was specified, but 'user' was not!" unless spec[:auth][:user]
    raise LogStash::ConfigurationError, "Auth was specified, but 'password' was not!" unless spec[:auth][:pass]
  end

  request
end