Module: Fluent::Config

Defined in:
lib/fluent/config.rb,
lib/fluent/config/dsl.rb,
lib/fluent/config/types.rb,
lib/fluent/config/parser.rb,
lib/fluent/config/element.rb,
lib/fluent/config/section.rb,
lib/fluent/config/v1_parser.rb,
lib/fluent/config/yaml_parser.rb,
lib/fluent/config/basic_parser.rb,
lib/fluent/config/literal_parser.rb,
lib/fluent/config/configure_proxy.rb,
lib/fluent/config/yaml_parser/loader.rb,
lib/fluent/config/yaml_parser/parser.rb,
lib/fluent/config/yaml_parser/fluent_value.rb,
lib/fluent/config/yaml_parser/section_builder.rb

Defined Under Namespace

Modules: DSL, SectionGenerator, YamlParser Classes: BasicParser, ConfigureProxy, Element, LiteralParser, Parser, Section, V1Parser

Constant Summary collapse

STRING_TYPE =
Proc.new { |val, opts = {}, name = nil|
  Config.string_value(val, opts, name)
}
SYMBOL_TYPE =
Proc.new { |val, opts = {}, name = nil|
  Config.symbol_value(val, opts, name)
}
ENUM_TYPE =
Proc.new { |val, opts = {}, name = nil|
  Config.enum_value(val, opts, name)
}
INTEGER_TYPE =
Proc.new { |val, opts = {}, name = nil|
  if val.nil?
    nil
  elsif opts[:strict]
    begin
      Integer(val)
    rescue ArgumentError, TypeError => e
      raise ConfigError, "#{name}: #{e.message}"
    end
  else
    val.to_i
  end
}
FLOAT_TYPE =
Proc.new { |val, opts = {}, name = nil|
  if val.nil?
    nil
  elsif opts[:strict]
    begin
      Float(val)
    rescue ArgumentError, TypeError => e
      raise ConfigError, "#{name}: #{e.message}"
    end
  else
    val.to_f
  end
}
SIZE_TYPE =
Proc.new { |val, opts = {}, name = nil|
  Config.size_value(val, opts, name)
}
BOOL_TYPE =
Proc.new { |val, opts = {}, name = nil|
  Config.bool_value(val, opts, name)
}
TIME_TYPE =
Proc.new { |val, opts = {}, name = nil|
  Config.time_value(val, opts, name)
}
REGEXP_TYPE =
Proc.new { |val, opts = {}, name = nil|
  Config.regexp_value(val, opts, name)
}
REFORMAT_VALUE =
->(type, value, opts = {}, name = nil) {
  if value.nil?
    value
  else
    case type
    when :string  then value.to_s.force_encoding(Encoding::UTF_8)
    when :integer then INTEGER_TYPE.call(value, opts, name)
    when :float   then FLOAT_TYPE.call(value, opts, name)
    when :size then Config.size_value(value, opts, name)
    when :bool then Config.bool_value(value, opts, name)
    when :time then Config.time_value(value, opts, name)
    when :regexp then Config.regexp_value(value, opts, name)
    when :symbol then Config.symbol_value(value, opts, name)
    else
      raise "unknown type in REFORMAT: #{type}"
    end
  end
}
HASH_TYPE =
Proc.new { |val, opts = {}, name = nil|
  Config.hash_value(val, opts, name)
}
ARRAY_TYPE =
Proc.new { |val, opts = {}, name = nil|
  Config.array_value(val, opts, name)
}

Class Method Summary collapse

Class Method Details

.array_value(val, opts = {}, name = nil) ⇒ Object



227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
# File 'lib/fluent/config/types.rb', line 227

def self.array_value(val, opts = {}, name = nil)
  return nil if val.nil?

  param = if val.is_a?(String)
            val.start_with?('[') ? JSON.parse(val) : val.strip.split(/\s*,\s*/)
          else
            val
          end
  if param.class != Array
    raise ConfigError, "array required but got #{val.inspect}"
  end
  if opts[:value_type]
    param.map{|v| REFORMAT_VALUE.call(opts[:value_type], v, opts, nil) }
  else
    param
  end
end

.bool_value(str, opts = {}, name = nil) ⇒ Object



61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/fluent/config/types.rb', line 61

def self.bool_value(str, opts = {}, name = nil)
  return nil if str.nil?

  case str.to_s
  when 'true', 'yes'
    true
  when 'false', 'no'
    false
  when ''
    true
  else
    # Current parser passes comment without actual values, e.g. "param #foo".
    # parser should pass empty string in this case but changing behaviour may break existing environment so keep parser behaviour. Just ignore comment value in boolean handling for now.
    if str.respond_to?('start_with?') && str.start_with?('#')
      true
    elsif opts[:strict]
      raise Fluent::ConfigError, "#{name}: invalid bool value: #{str}"
    else
      nil
    end
  end
end

.build(config_path:, encoding: 'utf-8', additional_config: nil, use_v1_config: true, type: nil) ⇒ Fluent::Config

Parameters:

  • config_path (String)

    config file path

  • encoding (String) (defaults to: 'utf-8')

    encoding of config file

  • additional_config (String) (defaults to: nil)

    config which is added to last of config body

  • use_v1_config (Bool) (defaults to: true)

    config is formatted with v1 or not

Returns:



29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/fluent/config.rb', line 29

def self.build(config_path:, encoding: 'utf-8', additional_config: nil, use_v1_config: true, type: nil)
  if type == :guess
    config_file_ext = File.extname(config_path)
    if config_file_ext == '.yaml' || config_file_ext == '.yml'
      type = :yaml
    end
  end

  if type == :yaml || type == :yml
    return Fluent::Config::YamlParser.parse(config_path)
  end

  config_fname = File.basename(config_path)
  config_basedir = File.dirname(config_path)
  config_data = File.open(config_path, "r:#{encoding}:utf-8") do |f|
    s = f.read
    if additional_config
      c = additional_config.gsub("\\n", "\n")
      s += "\n#{c}"
    end
    s
  end

  Fluent::Config.parse(config_data, config_fname, config_basedir, use_v1_config)
end

.enum_value(val, opts = {}, name = nil) ⇒ Object



121
122
123
124
125
126
127
128
129
130
131
# File 'lib/fluent/config/types.rb', line 121

def self.enum_value(val, opts = {}, name = nil)
  return nil if val.nil?

  s = val.to_sym
  list = opts[:list]
  raise "Plugin BUG: config type 'enum' requires :list of symbols" unless list.is_a?(Array) && list.all?{|v| v.is_a? Symbol }
  unless list.include?(s)
    raise ConfigError, "valid options are #{list.join(',')} but got #{val}"
  end
  s
end

.hash_value(val, opts = {}, name = nil) ⇒ Object



200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
# File 'lib/fluent/config/types.rb', line 200

def self.hash_value(val, opts = {}, name = nil)
  return nil if val.nil?

  param = if val.is_a?(String)
            val.start_with?('{') ? JSON.parse(val) : Hash[val.strip.split(/\s*,\s*/).map{|v| v.split(':', 2)}]
          else
            val
          end
  if param.class != Hash
    raise ConfigError, "hash required but got #{val.inspect}"
  end
  if opts.empty?
    param
  else
    newparam = {}
    param.each_pair do |key, value|
      new_key = opts[:symbolize_keys] ? key.to_sym : key
      newparam[new_key] = opts[:value_type] ? REFORMAT_VALUE.call(opts[:value_type], value, opts, new_key) : value
    end
    newparam
  end
end

.new(name = '') ⇒ Object



85
86
87
# File 'lib/fluent/config.rb', line 85

def self.new(name = '')
  Element.new(name, '', {}, [])
end

.parse(str, fname, basepath = Dir.pwd, v1_config = nil, syntax: :v1) ⇒ Object



55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/fluent/config.rb', line 55

def self.parse(str, fname, basepath = Dir.pwd, v1_config = nil, syntax: :v1)
  parser = if fname =~ /\.rb$/ || syntax == :ruby
             :ruby
           elsif v1_config.nil?
             case syntax
             when :v1 then :v1
             when :v0 then :v0
             else
               raise ArgumentError, "Unknown Fluentd configuration syntax: '#{syntax}'"
             end
           elsif v1_config then :v1
           else :v0
           end
  case parser
  when :v1
    require 'fluent/config/v1_parser'
    V1Parser.parse(str, fname, basepath, Kernel.binding)
  when :v0
    # TODO: show deprecated message in v1
    require 'fluent/config/parser'
    Parser.parse(str, fname, basepath)
  when :ruby
    require 'fluent/config/dsl'
    $log.warn("Ruby DSL configuration format is deprecated. Please use original configuration format. https://docs.fluentd.org/configuration/config-file") if $log
    Config::DSL::Parser.parse(str, File.join(basepath, fname))
  else
    raise "[BUG] unknown configuration parser specification:'#{parser}'"
  end
end

.reformatted_value(type, val, opts = {}, name = nil) ⇒ Object



23
24
25
# File 'lib/fluent/config/types.rb', line 23

def self.reformatted_value(type, val, opts = {}, name = nil)
  REFORMAT_VALUE.call(type, val, opts, name)
end

.regexp_value(str, opts = {}, name = nil) ⇒ Object



84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/fluent/config/types.rb', line 84

def self.regexp_value(str, opts = {}, name = nil)
  return nil unless str

  return Regexp.compile(str) unless str.start_with?("/")
  right_slash_position = str.rindex("/")
  if right_slash_position < str.size - 3
    raise Fluent::ConfigError, "invalid regexp: missing right slash: #{str}"
  end
  options = str[(right_slash_position + 1)..-1]
  option = 0
  option |= Regexp::IGNORECASE if options.include?("i")
  option |= Regexp::MULTILINE if options.include?("m")
  Regexp.compile(str[1...right_slash_position], option)
end

.size_value(str, opts = {}, name = nil) ⇒ Object



27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/fluent/config/types.rb', line 27

def self.size_value(str, opts = {}, name = nil)
  return nil if str.nil?

  case str.to_s
  when /([0-9]+)k/i
    $~[1].to_i * 1024
  when /([0-9]+)m/i
    $~[1].to_i * (1024 ** 2)
  when /([0-9]+)g/i
    $~[1].to_i * (1024 ** 3)
  when /([0-9]+)t/i
    $~[1].to_i * (1024 ** 4)
  else
    INTEGER_TYPE.call(str, opts, name)
  end
end

.string_value(val, opts = {}, name = nil) ⇒ Object



99
100
101
102
103
104
105
# File 'lib/fluent/config/types.rb', line 99

def self.string_value(val, opts = {}, name = nil)
  return nil if val.nil?

  v = val.to_s
  v = v.frozen? ? v.dup : v # config_param can't assume incoming string is mutable
  v.force_encoding(Encoding::UTF_8)
end

.symbol_value(val, opts = {}, name = nil) ⇒ Object



111
112
113
114
115
# File 'lib/fluent/config/types.rb', line 111

def self.symbol_value(val, opts = {}, name = nil)
  return nil if val.nil? || val.empty?

  val.delete_prefix(":").to_sym
end

.time_value(str, opts = {}, name = nil) ⇒ Object



44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/fluent/config/types.rb', line 44

def self.time_value(str, opts = {}, name = nil)
  return nil if str.nil?

  case str.to_s
  when /([0-9]+)s/
    $~[1].to_i
  when /([0-9]+)m/
    $~[1].to_i * 60
  when /([0-9]+)h/
    $~[1].to_i * 60 * 60
  when /([0-9]+)d/
    $~[1].to_i * 24 * 60 * 60
  else
    FLOAT_TYPE.call(str, opts, name)
  end
end