fluentd 0.12.17 → 0.12.18
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of fluentd might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/.travis.yml +1 -2
- data/ChangeLog +25 -0
- data/lib/fluent/buffer.rb +2 -0
- data/lib/fluent/config/configure_proxy.rb +2 -2
- data/lib/fluent/configurable.rb +2 -2
- data/lib/fluent/log.rb +1 -0
- data/lib/fluent/plugin/buf_file.rb +2 -0
- data/lib/fluent/plugin/buf_memory.rb +1 -0
- data/lib/fluent/plugin/exec_util.rb +21 -0
- data/lib/fluent/plugin/filter_record_transformer.rb +6 -0
- data/lib/fluent/plugin/filter_stdout.rb +1 -0
- data/lib/fluent/plugin/in_exec.rb +33 -22
- data/lib/fluent/plugin/in_forward.rb +5 -0
- data/lib/fluent/plugin/in_http.rb +9 -0
- data/lib/fluent/plugin/in_stream.rb +2 -0
- data/lib/fluent/plugin/in_syslog.rb +6 -0
- data/lib/fluent/plugin/in_tail.rb +16 -1
- data/lib/fluent/plugin/in_tcp.rb +1 -0
- data/lib/fluent/plugin/out_copy.rb +1 -0
- data/lib/fluent/plugin/out_exec.rb +6 -0
- data/lib/fluent/plugin/out_exec_filter.rb +15 -0
- data/lib/fluent/plugin/out_file.rb +5 -0
- data/lib/fluent/plugin/out_forward.rb +15 -0
- data/lib/fluent/plugin/out_stdout.rb +1 -0
- data/lib/fluent/plugin/socket_util.rb +5 -0
- data/lib/fluent/process.rb +19 -9
- data/lib/fluent/supervisor.rb +19 -1
- data/lib/fluent/test.rb +2 -0
- data/lib/fluent/test/formatter_test.rb +60 -0
- data/lib/fluent/test/parser_test.rb +66 -0
- data/lib/fluent/version.rb +1 -1
- data/test/config/test_configure_proxy.rb +1 -10
- data/test/plugin/test_in_exec.rb +31 -3
- data/test/plugin/test_out_forward.rb +6 -0
- data/test/scripts/exec_script.rb +6 -0
- data/test/test_formatter.rb +35 -2
- data/test/test_parser.rb +43 -19
- data/test/test_process.rb +47 -0
- metadata +7 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 07240444ef56a97335d1f42c0153a8be4059e77a
|
4
|
+
data.tar.gz: 31cec22258753e9e6e51780b6a8d33e1194879c2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 404559093a12caba1b073e0106287975f9e3dd3ea4ae8be191e95a71abf8d49b13c81c53539830bc2672e0a4741d5088cae800b6906fe3789a7849a8f19997b0
|
7
|
+
data.tar.gz: d8d4411e79d2211526ca7ce69d47263c18b7d8b47606be018a926b2dbf44a25195ffc35fa4aadb23a77067e390d7f4dbe2d395b9d81e912ad25aca085683e63b
|
data/.travis.yml
CHANGED
data/ChangeLog
CHANGED
@@ -1,5 +1,30 @@
|
|
1
1
|
# v0.12
|
2
2
|
|
3
|
+
## Release 0.12.18 - 2015/12/09
|
4
|
+
|
5
|
+
### New features / Enhancement
|
6
|
+
|
7
|
+
* in_exec: Stop in_exec immediately at shutdown
|
8
|
+
https://github.com/fluent/fluentd/pull/526
|
9
|
+
* in_exec: Support built-in text parsers
|
10
|
+
https://github.com/fluent/fluentd/pull/704
|
11
|
+
* out_forward: raises ZeroDivisionError when no <server> is available
|
12
|
+
https://github.com/fluent/fluentd/pull/707
|
13
|
+
* Add process_name parameter in system to change fluentd's process name
|
14
|
+
https://github.com/fluent/fluentd/pull/708
|
15
|
+
* test: Add ParserTestDriver
|
16
|
+
https://github.com/fluent/fluentd/pull/702
|
17
|
+
* test: Add FormatterTestDriver
|
18
|
+
https://github.com/fluent/fluentd/pull/712
|
19
|
+
* Add parameter description to built-in plugins
|
20
|
+
|
21
|
+
### Bug fixes
|
22
|
+
|
23
|
+
* fix bug not to protect in-memory-buffer for multi thread emitting / run loop
|
24
|
+
https://github.com/fluent/fluentd/pull/710
|
25
|
+
* in_tail: expand_paths exclude unreadable files
|
26
|
+
https://github.com/fluent/fluentd/pull/734
|
27
|
+
|
3
28
|
## Release 0.12.17 - 2015/11/04
|
4
29
|
|
5
30
|
### New features / Enhancement
|
data/lib/fluent/buffer.rb
CHANGED
@@ -139,7 +139,9 @@ module Fluent
|
|
139
139
|
# This configuration assumes plugins to send records to a remote server.
|
140
140
|
# Local file based plugins which should provide more reliability and efficiency
|
141
141
|
# should override buffer_chunk_limit with a larger size.
|
142
|
+
desc 'The size of each buffer chunk.'
|
142
143
|
config_param :buffer_chunk_limit, :size, :default => 8*1024*1024
|
144
|
+
desc 'The length limit of the chunk queue.'
|
143
145
|
config_param :buffer_queue_limit, :integer, :default => 256
|
144
146
|
|
145
147
|
alias chunk_limit buffer_chunk_limit
|
@@ -235,7 +235,7 @@ module Fluent
|
|
235
235
|
end
|
236
236
|
|
237
237
|
def dump(level = 0)
|
238
|
-
dumped_config = "
|
238
|
+
dumped_config = ""
|
239
239
|
indent = " " * level
|
240
240
|
@params.each do |name, config|
|
241
241
|
dumped_config << "#{indent}#{name}: #{config[1][:type]}: <#{@defaults[name].inspect}>"
|
@@ -243,7 +243,7 @@ module Fluent
|
|
243
243
|
dumped_config << "\n"
|
244
244
|
end
|
245
245
|
@sections.each do |section_name, sub_proxy|
|
246
|
-
dumped_config << "#{indent}#{section_name}#{sub_proxy.dump(level + 1)}"
|
246
|
+
dumped_config << "#{indent}#{section_name}\n#{sub_proxy.dump(level + 1)}"
|
247
247
|
end
|
248
248
|
dumped_config
|
249
249
|
end
|
data/lib/fluent/configurable.rb
CHANGED
@@ -130,8 +130,8 @@ module Fluent
|
|
130
130
|
configurables.map{ |a| a.configure_proxy(a.name || a.object_id.to_s) }.reduce(:merge)
|
131
131
|
end
|
132
132
|
|
133
|
-
def dump
|
134
|
-
configure_proxy_map[self.to_s].dump
|
133
|
+
def dump(level = 0)
|
134
|
+
configure_proxy_map[self.to_s].dump(level)
|
135
135
|
end
|
136
136
|
end
|
137
137
|
end
|
data/lib/fluent/log.rb
CHANGED
@@ -343,6 +343,7 @@ module Fluent
|
|
343
343
|
module PluginLoggerMixin
|
344
344
|
def self.included(klass)
|
345
345
|
klass.instance_eval {
|
346
|
+
desc 'Allows the user to set different levels of logging for each plugin.'
|
346
347
|
config_param :log_level, :string, :default => nil, :alias => :@log_level
|
347
348
|
}
|
348
349
|
end
|
@@ -82,7 +82,9 @@ module Fluent
|
|
82
82
|
@uri_parser = URI::Parser.new
|
83
83
|
end
|
84
84
|
|
85
|
+
desc 'The path where buffer chunks are stored.'
|
85
86
|
config_param :buffer_path, :string
|
87
|
+
desc 'If true, queued chunks are flushed at shutdown process.'
|
86
88
|
config_param :flush_at_shutdown, :bool, :default => false
|
87
89
|
|
88
90
|
# 'symlink_path' is currently only for out_file.
|
@@ -70,6 +70,7 @@ module Fluent
|
|
70
70
|
super
|
71
71
|
end
|
72
72
|
|
73
|
+
desc 'If true, queued chunks are flushed at shutdown process. Otherwise queued chunks are discarded'
|
73
74
|
config_param :flush_at_shutdown, :bool, :default => true
|
74
75
|
# Overwrite default BasicBuffer#buffer_queue_limit
|
75
76
|
# to limit total memory usage upto 512MB.
|
@@ -16,6 +16,8 @@
|
|
16
16
|
|
17
17
|
module Fluent
|
18
18
|
module ExecUtil
|
19
|
+
require 'fluent/parser'
|
20
|
+
|
19
21
|
SUPPORTED_FORMAT = {
|
20
22
|
'tsv' => :tsv,
|
21
23
|
'json' => :json,
|
@@ -28,6 +30,25 @@ module Fluent
|
|
28
30
|
end
|
29
31
|
end
|
30
32
|
|
33
|
+
class TextParserWrapperParser < Parser
|
34
|
+
def initialize(conf, on_message)
|
35
|
+
@parser = Plugin.new_parser(conf['format'])
|
36
|
+
@parser.configure(conf)
|
37
|
+
super(on_message)
|
38
|
+
end
|
39
|
+
|
40
|
+
def call(io)
|
41
|
+
io.each_line(&method(:each_line))
|
42
|
+
end
|
43
|
+
|
44
|
+
def each_line(line)
|
45
|
+
line.chomp!
|
46
|
+
@parser.parse(line) { |time, record|
|
47
|
+
@on_message.call(record, time)
|
48
|
+
}
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
31
52
|
class TSVParser < Parser
|
32
53
|
def initialize(keys, on_message)
|
33
54
|
@keys = keys
|
@@ -25,11 +25,17 @@ module Fluent
|
|
25
25
|
super
|
26
26
|
end
|
27
27
|
|
28
|
+
desc 'A comma-delimited list of keys to delete.'
|
28
29
|
config_param :remove_keys, :string, :default => nil
|
30
|
+
desc 'A comma-delimited list of keys to keep.'
|
29
31
|
config_param :keep_keys, :string, :default => nil
|
32
|
+
desc 'Create new Hash to transform incoming data'
|
30
33
|
config_param :renew_record, :bool, :default => false
|
34
|
+
desc 'Specify field name of the record to overwrite the time of events. Its value must be unix time.'
|
31
35
|
config_param :renew_time_key, :string, :default => nil
|
36
|
+
desc 'When set to true, the full Ruby syntax is enabled in the ${...} expression.'
|
32
37
|
config_param :enable_ruby, :bool, :default => false
|
38
|
+
desc 'Use original value type.'
|
33
39
|
config_param :auto_typecast, :bool, :default => false # false for lower version compatibility
|
34
40
|
|
35
41
|
def configure(conf)
|
@@ -24,25 +24,23 @@ module Fluent
|
|
24
24
|
require 'fluent/timezone'
|
25
25
|
end
|
26
26
|
|
27
|
-
|
28
|
-
'tsv' => :tsv,
|
29
|
-
'json' => :json,
|
30
|
-
'msgpack' => :msgpack,
|
31
|
-
}
|
32
|
-
|
27
|
+
desc 'The command (program) to execute.'
|
33
28
|
config_param :command, :string
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
f
|
38
|
-
end
|
29
|
+
desc 'The format used to map the program output to the incoming event.(tsv,json,msgpack)'
|
30
|
+
config_param :format, :string, :default => 'tsv'
|
31
|
+
desc 'Specify the comma-separated keys when using the tsv format.'
|
39
32
|
config_param :keys, :default => [] do |val|
|
40
33
|
val.split(',')
|
41
34
|
end
|
35
|
+
desc 'Tag of the output events.'
|
42
36
|
config_param :tag, :string, :default => nil
|
37
|
+
desc 'The key to use as the event tag instead of the value in the event record. '
|
43
38
|
config_param :tag_key, :string, :default => nil
|
39
|
+
desc 'The key to use as the event time instead of the value in the event record.'
|
44
40
|
config_param :time_key, :string, :default => nil
|
41
|
+
desc 'The format of the event time used for the time_key parameter.'
|
45
42
|
config_param :time_format, :string, :default => nil
|
43
|
+
desc 'The interval time between periodic program runs.'
|
46
44
|
config_param :run_interval, :time, :default => nil
|
47
45
|
|
48
46
|
def configure(conf)
|
@@ -72,16 +70,22 @@ module Fluent
|
|
72
70
|
end
|
73
71
|
end
|
74
72
|
|
73
|
+
@parser = setup_parser(conf)
|
74
|
+
end
|
75
|
+
|
76
|
+
def setup_parser(conf)
|
75
77
|
case @format
|
76
|
-
when
|
78
|
+
when 'tsv'
|
77
79
|
if @keys.empty?
|
78
80
|
raise ConfigError, "keys option is required on exec input for tsv format"
|
79
81
|
end
|
80
|
-
|
81
|
-
when
|
82
|
-
|
83
|
-
when
|
84
|
-
|
82
|
+
ExecUtil::TSVParser.new(@keys, method(:on_message))
|
83
|
+
when 'json'
|
84
|
+
ExecUtil::JSONParser.new(method(:on_message))
|
85
|
+
when 'msgpack'
|
86
|
+
ExecUtil::MessagePackParser.new(method(:on_message))
|
87
|
+
else
|
88
|
+
ExecUtil::TextParserWrapperParser.new(conf, method(:on_message))
|
85
89
|
end
|
86
90
|
end
|
87
91
|
|
@@ -99,6 +103,8 @@ module Fluent
|
|
99
103
|
def shutdown
|
100
104
|
if @run_interval
|
101
105
|
@finished = true
|
106
|
+
# call Thread#run which interupts sleep in order to stop run_periodic thread immediately.
|
107
|
+
@thread.run
|
102
108
|
@thread.join
|
103
109
|
else
|
104
110
|
begin
|
@@ -122,12 +128,13 @@ module Fluent
|
|
122
128
|
end
|
123
129
|
|
124
130
|
def run_periodic
|
131
|
+
sleep @run_interval
|
125
132
|
until @finished
|
126
133
|
begin
|
127
|
-
sleep @run_interval
|
128
134
|
io = IO.popen(@command, "r")
|
129
135
|
@parser.call(io)
|
130
136
|
Process.waitpid(io.pid)
|
137
|
+
sleep @run_interval
|
131
138
|
rescue
|
132
139
|
log.error "exec failed to run or shutdown child process", :error => $!.to_s, :error_class => $!.class.to_s
|
133
140
|
log.warn_backtrace $!.backtrace
|
@@ -137,17 +144,21 @@ module Fluent
|
|
137
144
|
|
138
145
|
private
|
139
146
|
|
140
|
-
def on_message(record)
|
147
|
+
def on_message(record, parsed_time = nil)
|
141
148
|
if val = record.delete(@tag_key)
|
142
149
|
tag = val
|
143
150
|
else
|
144
151
|
tag = @tag
|
145
152
|
end
|
146
153
|
|
147
|
-
if
|
148
|
-
time =
|
154
|
+
if parsed_time
|
155
|
+
time = parsed_time
|
149
156
|
else
|
150
|
-
|
157
|
+
if val = record.delete(@time_key)
|
158
|
+
time = @time_parse_proc.call(val)
|
159
|
+
else
|
160
|
+
time = Engine.now
|
161
|
+
end
|
151
162
|
end
|
152
163
|
|
153
164
|
router.emit(tag, time, record)
|
@@ -23,15 +23,20 @@ module Fluent
|
|
23
23
|
require 'fluent/plugin/socket_util'
|
24
24
|
end
|
25
25
|
|
26
|
+
desc 'The port to listen to.'
|
26
27
|
config_param :port, :integer, :default => DEFAULT_LISTEN_PORT
|
28
|
+
desc 'The bind address to listen to.'
|
27
29
|
config_param :bind, :string, :default => '0.0.0.0'
|
28
30
|
config_param :backlog, :integer, :default => nil
|
29
31
|
# SO_LINGER 0 to send RST rather than FIN to avoid lots of connections sitting in TIME_WAIT at src
|
32
|
+
desc 'The timeout time used to set linger option.'
|
30
33
|
config_param :linger_timeout, :integer, :default => 0
|
31
34
|
# This option is for Cool.io's loop wait timeout to avoid loop stuck at shutdown. Almost users don't need to change this value.
|
32
35
|
config_param :blocking_timeout, :time, :default => 0.5
|
33
36
|
|
37
|
+
desc 'Log warning if received chunk size is larger than this value.'
|
34
38
|
config_param :chunk_size_warn_limit, :size, :default => nil
|
39
|
+
desc 'Received chunk is dropped if it is larger than this value.'
|
35
40
|
config_param :chunk_size_limit, :size, :default => nil
|
36
41
|
|
37
42
|
def configure(conf)
|
@@ -30,16 +30,25 @@ module Fluent
|
|
30
30
|
|
31
31
|
EMPTY_GIF_IMAGE = "GIF89a\u0001\u0000\u0001\u0000\x80\xFF\u0000\xFF\xFF\xFF\u0000\u0000\u0000,\u0000\u0000\u0000\u0000\u0001\u0000\u0001\u0000\u0000\u0002\u0002D\u0001\u0000;".force_encoding("UTF-8")
|
32
32
|
|
33
|
+
desc 'The port to listen to.'
|
33
34
|
config_param :port, :integer, :default => 9880
|
35
|
+
desc 'The bind address to listen to.'
|
34
36
|
config_param :bind, :string, :default => '0.0.0.0'
|
37
|
+
desc 'The size limit of the POSTed element. Default is 32MB.'
|
35
38
|
config_param :body_size_limit, :size, :default => 32*1024*1024 # TODO default
|
39
|
+
desc 'The timeout limit for keeping the connection alive.'
|
36
40
|
config_param :keepalive_timeout, :time, :default => 10 # TODO default
|
37
41
|
config_param :backlog, :integer, :default => nil
|
42
|
+
desc 'Add HTTP_ prefix headers to the record.'
|
38
43
|
config_param :add_http_headers, :bool, :default => false
|
44
|
+
desc 'Add REMOTE_ADDR header to the record.'
|
39
45
|
config_param :add_remote_addr, :bool, :default => false
|
46
|
+
desc 'The format of the HTTP body.'
|
40
47
|
config_param :format, :string, :default => 'default'
|
41
48
|
config_param :blocking_timeout, :time, :default => 0.5
|
49
|
+
desc 'Set a white list of domains that can do CORS (Cross-Origin Resource Sharing)'
|
42
50
|
config_param :cors_allow_origins, :array, :default => nil
|
51
|
+
desc 'Respond with empty gif image of 1x1 pixel.'
|
43
52
|
config_param :respond_with_empty_img, :bool, :default => false
|
44
53
|
|
45
54
|
def configure(conf)
|
@@ -164,7 +164,9 @@ module Fluent
|
|
164
164
|
class UnixInput < StreamInput
|
165
165
|
Plugin.register_input('unix', self)
|
166
166
|
|
167
|
+
desc 'The path to your Unix Domain Socket.'
|
167
168
|
config_param :path, :string, :default => DEFAULT_SOCKET_PATH
|
169
|
+
desc 'The backlog of Unix Domain Socket.'
|
168
170
|
config_param :backlog, :integer, :default => nil
|
169
171
|
|
170
172
|
def configure(conf)
|
@@ -64,9 +64,13 @@ module Fluent
|
|
64
64
|
require 'fluent/plugin/socket_util'
|
65
65
|
end
|
66
66
|
|
67
|
+
desc 'The port to listen to.'
|
67
68
|
config_param :port, :integer, :default => 5140
|
69
|
+
desc 'The bind address to listen to.'
|
68
70
|
config_param :bind, :string, :default => '0.0.0.0'
|
71
|
+
desc 'The prefix of the tag. The tag itself is generated by the tag prefix, facility level, and priority.'
|
69
72
|
config_param :tag, :string
|
73
|
+
desc 'The transport protocol used to receive logs.(udp, tcp)'
|
70
74
|
config_param :protocol_type, :default => :udp do |val|
|
71
75
|
case val.downcase
|
72
76
|
when 'tcp'
|
@@ -77,7 +81,9 @@ module Fluent
|
|
77
81
|
raise ConfigError, "syslog input protocol type should be 'tcp' or 'udp'"
|
78
82
|
end
|
79
83
|
end
|
84
|
+
desc 'If true, add source host to event record.'
|
80
85
|
config_param :include_source_host, :bool, :default => false
|
86
|
+
desc 'Specify key of source host when include_source_host is true.'
|
81
87
|
config_param :source_host_key, :string, :default => 'source_host'.freeze
|
82
88
|
config_param :blocking_timeout, :time, :default => 0.5
|
83
89
|
|
@@ -24,13 +24,21 @@ module Fluent
|
|
24
24
|
@tails = {}
|
25
25
|
end
|
26
26
|
|
27
|
+
desc 'The paths to read. Multiple paths can be specified, separated by comma.'
|
27
28
|
config_param :path, :string
|
29
|
+
desc 'The tag of the event.'
|
28
30
|
config_param :tag, :string
|
31
|
+
desc 'The paths to exclude the files from watcher list.'
|
29
32
|
config_param :exclude_path, :array, :default => []
|
33
|
+
desc 'Specify interval to keep reference to old file when rotate a file.'
|
30
34
|
config_param :rotate_wait, :time, :default => 5
|
35
|
+
desc 'Fluentd will record the position it last read into this file.'
|
31
36
|
config_param :pos_file, :string, :default => nil
|
37
|
+
desc 'Start to read the logs from the head of file, not bottom.'
|
32
38
|
config_param :read_from_head, :bool, :default => false
|
39
|
+
desc 'The interval of refreshing the list of watch file.'
|
33
40
|
config_param :refresh_interval, :time, :default => 60
|
41
|
+
desc 'The number of reading lines at each IO.'
|
34
42
|
config_param :read_lines_limit, :integer, :default => 1000
|
35
43
|
|
36
44
|
attr_reader :paths
|
@@ -106,7 +114,14 @@ module Fluent
|
|
106
114
|
@paths.each { |path|
|
107
115
|
path = date.strftime(path)
|
108
116
|
if path.include?('*')
|
109
|
-
paths += Dir.glob(path)
|
117
|
+
paths += Dir.glob(path).select { |p|
|
118
|
+
if File.readable?(p)
|
119
|
+
true
|
120
|
+
else
|
121
|
+
log.warn "#{p} unreadable. It is excluded and would be examined next time."
|
122
|
+
false
|
123
|
+
end
|
124
|
+
}
|
110
125
|
else
|
111
126
|
# When file is not created yet, Dir.glob returns an empty array. So just add when path is static.
|
112
127
|
paths << path
|
data/lib/fluent/plugin/in_tcp.rb
CHANGED
@@ -21,6 +21,7 @@ module Fluent
|
|
21
21
|
Plugin.register_input('tcp', self)
|
22
22
|
|
23
23
|
config_set_default :port, 5170
|
24
|
+
desc 'The payload is read up to this character.'
|
24
25
|
config_param :delimiter, :string, :default => "\n" # syslog family add "\n" to each message and this seems only way to split messages in tcp stream
|
25
26
|
|
26
27
|
def listen(callback)
|
@@ -26,13 +26,19 @@ module Fluent
|
|
26
26
|
@localtime = false
|
27
27
|
end
|
28
28
|
|
29
|
+
desc 'The command (program) to execute. The exec plugin passes the path of a TSV file as the last argumen'
|
29
30
|
config_param :command, :string
|
31
|
+
desc 'Specify the comma-separated keys when using the tsv format.'
|
30
32
|
config_param :keys, :default => [] do |val|
|
31
33
|
val.split(',')
|
32
34
|
end
|
35
|
+
desc 'The name of the key to use as the event tag. This replaces the value in the event record.'
|
33
36
|
config_param :tag_key, :string, :default => nil
|
37
|
+
desc 'The name of the key to use as the event time. This replaces the the value in the event record.'
|
34
38
|
config_param :time_key, :string, :default => nil
|
39
|
+
desc 'The format for event time used when the time_key parameter is specified. The default is UNIX time (integer).'
|
35
40
|
config_param :time_format, :string, :default => nil
|
41
|
+
desc "The format used to map the incoming events to the program input. (#{ExecUtil::SUPPORTED_FORMAT.keys.join(',')})"
|
36
42
|
config_param :format, :default => :tsv do |val|
|
37
43
|
f = ExecUtil::SUPPORTED_FORMAT[val]
|
38
44
|
raise ConfigError, "Unsupported format '#{val}'" unless f
|