module LogStash::Config::Mixin::DSL

Attributes

flags[RW]

Public Instance Methods

config(name, opts={}) click to toggle source

Define a new configuration setting

# File lib/logstash/config/mixin.rb, line 133
def config(name, opts={})
  @config ||= Hash.new
  # TODO(sissel): verify 'name' is of type String, Symbol, or Regexp

  name = name.to_s if name.is_a?(Symbol)
  @config[name] = opts  # ok if this is empty

  if name.is_a?(String)
    define_method(name) { instance_variable_get("@#{name}") }
    define_method("#{name}=") { |v| instance_variable_set("@#{name}", v) }
  end
end
config_name(name=nil) click to toggle source

If name is given, set the name and return it. If no name given (nil), return the current name.

# File lib/logstash/config/mixin.rb, line 117
def config_name(name=nil)
  @config_name = name if !name.nil?
  LogStash::Config::Registry.registry[@config_name] = self
  return @config_name
end
default(name, value) click to toggle source
# File lib/logstash/config/mixin.rb, line 146
def default(name, value)
  @defaults ||= {}
  @defaults[name.to_s] = value
end
default?(name) click to toggle source
# File lib/logstash/config/mixin.rb, line 159
def default?(name)
  return @defaults && @defaults.include?(name)
end
get_config() click to toggle source
# File lib/logstash/config/mixin.rb, line 151
def get_config
  return @config
end
get_default(name) click to toggle source
# File lib/logstash/config/mixin.rb, line 155
def get_default(name)
  return @defaults && @defaults[name]
end
hash_or_array(value) click to toggle source
# File lib/logstash/config/mixin.rb, line 457
def hash_or_array(value)
  if !value.is_a?(Hash)
    value = [*value] # coerce scalar to array if necessary
  end
  return value
end
inherited(subclass) click to toggle source

This is called whenever someone subclasses a class that has this mixin.

# File lib/logstash/config/mixin.rb, line 175
def inherited(subclass)
  # Copy our parent's config to a subclass.
  # This method is invoked whenever someone subclasses us, like:
  # class Foo < Bar ...
  subconfig = Hash.new
  if !@config.nil?
    @config.each do |key, val|
      subconfig[key] = val
    end
  end
  subclass.instance_variable_set("@config", subconfig)
  @@milestone_notice_given = false
end
milestone(m=nil) click to toggle source
# File lib/logstash/config/mixin.rb, line 127
def milestone(m=nil)
  @milestone = m if !m.nil?
  return @milestone
end
options(opts) click to toggle source
# File lib/logstash/config/mixin.rb, line 163
def options(opts)
  # add any options from this class
  prefix = self.name.split("::").last.downcase
  @flags.each do |flag|
    flagpart = flag[:args].first.gsub(/^--/,"")
    # TODO(sissel): logger things here could help debugging.

    opts.on("--#{prefix}-#{flagpart}", *flag[:args][1..-1], &flag[:block])
  end
end
plugin_status(status=nil) click to toggle source
# File lib/logstash/config/mixin.rb, line 123
def plugin_status(status=nil)
  milestone(status)
end
validate(params) click to toggle source
# File lib/logstash/config/mixin.rb, line 189
def validate(params)
  @plugin_name = config_name
  @plugin_type = ancestors.find { |a| a.name =~ /::Base$/ }.config_name
  @logger = Cabin::Channel.get(LogStash)
  is_valid = true

  is_valid &&= validate_milestone
  is_valid &&= validate_check_invalid_parameter_names(params)
  is_valid &&= validate_check_required_parameter_names(params)
  is_valid &&= validate_check_parameter_values(params)

  return is_valid
end
validate_check_invalid_parameter_names(params) click to toggle source
# File lib/logstash/config/mixin.rb, line 223
def validate_check_invalid_parameter_names(params)
  invalid_params = params.keys
  # Filter out parameters that match regexp keys.
  # These are defined in plugins like this:
  #   config /foo.*/ => ...
  @config.each_key do |config_key|
    if config_key.is_a?(Regexp)
      invalid_params.reject! { |k| k =~ config_key }
    elsif config_key.is_a?(String)
      invalid_params.reject! { |k| k == config_key }
    end
  end

  if invalid_params.size > 0
    invalid_params.each do |name|
      @logger.error("Unknown setting '#{name}' for #{@plugin_name}")
    end
    return false
  end # if invalid_params.size > 0
  return true
end
validate_check_parameter_values(params) click to toggle source
# File lib/logstash/config/mixin.rb, line 265
def validate_check_parameter_values(params)
  # Filter out parametrs that match regexp keys.
  # These are defined in plugins like this:
  #   config /foo.*/ => ...
  is_valid = true

  params.each do |key, value|
    @config.keys.each do |config_key|
      next unless (config_key.is_a?(Regexp) && key =~ config_key) \
                  || (config_key.is_a?(String) && key == config_key)
      config_val = @config[config_key][:validate]
      #puts "  Key matches."
      success, result = validate_value(value, config_val)
      if success 
        # Accept coerced value if success
        # Used for converting values in the config to proper objects.
        params[key] = result if !result.nil?
      else
        @logger.error(I18n.t("logstash.agent.configuration.setting_invalid",
                             :plugin => @plugin_name, :type => @plugin_type,
                             :setting => key, :value => value.inspect,
                             :value_type => config_val,
                             :note => result))
      end
      #puts "Result: #{key} / #{result.inspect} / #{success}"
      is_valid &&= success

      break # done with this param key
    end # config.each
  end # params.each

  return is_valid
end
validate_check_required_parameter_names(params) click to toggle source
# File lib/logstash/config/mixin.rb, line 245
def validate_check_required_parameter_names(params)
  is_valid = true

  @config.each do |config_key, config|
    next unless config[:required]

    if config_key.is_a?(Regexp)
      next if params.keys.select { |k| k =~ config_key }.length > 0
    elsif config_key.is_a?(String)
      next if params.keys.member?(config_key)
    end
    @logger.error(I18n.t("logstash.agent.configuration.setting_missing",
                         :setting => config_key, :plugin => @plugin_name,
                         :type => @plugin_type))
    is_valid = false
  end

  return is_valid
end
validate_milestone() click to toggle source
# File lib/logstash/config/mixin.rb, line 203
def validate_milestone
  return true if @@milestone_notice_given
  docmsg = "For more information about plugin milestones, see http://logstash.net/docs/#{LOGSTASH_VERSION}/plugin-milestones "
  plugin_type = ancestors.find { |a| a.name =~ /::Base$/ }.config_name
  case @milestone
    when 0,1,2
      @logger.warn(I18n.t("logstash.plugin.milestone.#{@milestone}", 
                          :type => plugin_type, :name => @config_name,
                          :LOGSTASH_VERSION => LOGSTASH_VERSION))
    when 3
      # No message to log for milestone 3 plugins.
    when nil
      raise "#{@config_name} must set a milestone. #{docmsg}"
    else
      raise "#{@config_name} set an invalid plugin status #{@milestone}. Valid values are 0, 1, 2, or 3. #{docmsg}"
  end
  @@milestone_notice_given = true
  return true
end
validate_value(value, validator) click to toggle source
# File lib/logstash/config/mixin.rb, line 309
def validate_value(value, validator)
  # Validator comes from the 'config' pieces of plugins.
  # They look like this
  #   config :mykey => lambda do |value| ... end
  # (see LogStash::Inputs::File for example)
  result = nil

  if validator.nil?
    return true
  elsif validator.is_a?(Array)
    value = [*value]
    if value.size > 1
      return false, "Expected one of #{validator.inspect}, got #{value.inspect}"
    end

    if !validator.include?(value.first)
      return false, "Expected one of #{validator.inspect}, got #{value.inspect}"
    end
    result = value.first
  elsif validator.is_a?(Symbol)
    # TODO(sissel): Factor this out into a coersion method?
    # TODO(sissel): Document this stuff.
    value = hash_or_array(value)

    case validator
      when :codec
        if value.first.is_a?(String)
          value = LogStash::Plugin.lookup("codec", value.first).new
          return true, value
        else
          value = value.first
          return true, value
        end
      when :hash
        if value.is_a?(Hash)
          return true, value
        end

        if value.size % 2 == 1
          return false, "This field must contain an even number of items, got #{value.size}"
        end

        # Convert the array the config parser produces into a hash.
        result = {}
        value.each_slice(2) do |key, value|
          entry = result[key]
          if entry.nil?
            result[key] = value
          else
            if entry.is_a?(Array)
              entry << value
            else
              result[key] = [entry, value]
            end
          end
        end
      when :array
        result = value
      when :string
        if value.size > 1 # only one value wanted
          return false, "Expected string, got #{value.inspect}"
        end
        result = value.first
      when :number
        if value.size > 1 # only one value wanted
          return false, "Expected number, got #{value.inspect} (type #{value.class})"
        end

        v = value.first
        case v
          when Numeric
            result = v
          when String
            if v.to_s.to_f.to_s != v.to_s \
               && v.to_s.to_i.to_s != v.to_s
              return false, "Expected number, got #{v.inspect} (type #{v})"
            end
            if v.include?(".")
              # decimal value, use float.
              result = v.to_f
            else
              result = v.to_i
            end
        end # case v
      when :boolean
        if value.size > 1 # only one value wanted
          return false, "Expected boolean, got #{value.inspect}"
        end

        bool_value = value.first
        if !!bool_value == bool_value
          # is_a does not work for booleans
          # we have Boolean and not a string
          result = bool_value
        else
          if bool_value !~ /^(true|false)$/
            return false, "Expected boolean 'true' or 'false', got #{bool_value.inspect}"
          end

          result = (bool_value == "true")
        end
      when :ipaddr
        if value.size > 1 # only one value wanted
          return false, "Expected IPaddr, got #{value.inspect}"
        end

        octets = value.split(".")
        if octets.length != 4
          return false, "Expected IPaddr, got #{value.inspect}"
        end
        octets.each do |o|
          if o.to_i < 0 or o.to_i > 255
            return false, "Expected IPaddr, got #{value.inspect}"
          end
        end
        result = value.first
      when :password
        if value.size > 1
          return false, "Expected password (one value), got #{value.size} values?"
        end

        result = ::LogStash::Util::Password.new(value.first)
      when :path
        if value.size > 1 # Only 1 value wanted
          return false, "Expected path (one value), got #{value.size} values?"
        end

        # Paths must be absolute
        #if !Pathname.new(value.first).absolute?
          #return false, "Require absolute path, got relative path #{value.first}?"
        #end

        if !File.exists?(value.first) # Check if the file exists
          return false, "File does not exist or cannot be opened #{value.first}"
        end

        result = value.first
      else
        return false, "Unknown validator symbol #{validator}"
    end # case validator
  else
    return false, "Unknown validator #{validator.class}"
  end

  # Return the validator for later use, like with type coercion.
  return true, result
end
validator_find(key) click to toggle source
# File lib/logstash/config/mixin.rb, line 299
def validator_find(key)
  @config.each do |config_key, config_val|
    if (config_key.is_a?(Regexp) && key =~ config_key) \
       || (config_key.is_a?(String) && key == config_key)
      return config_val
    end
  end # @config.each
  return nil
end