fluentd 0.10.57 → 0.10.58

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.

Files changed (78) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +1 -0
  3. data/ChangeLog +18 -0
  4. data/fluent.conf +26 -16
  5. data/fluentd.gemspec +1 -1
  6. data/lib/fluent/config.rb +1 -8
  7. data/lib/fluent/config/basic_parser.rb +1 -0
  8. data/lib/fluent/config/configure_proxy.rb +7 -7
  9. data/lib/fluent/config/types.rb +1 -0
  10. data/lib/fluent/config/v1_parser.rb +2 -1
  11. data/lib/fluent/engine.rb +0 -26
  12. data/lib/fluent/env.rb +1 -0
  13. data/lib/fluent/formatter.rb +96 -26
  14. data/lib/fluent/input.rb +4 -0
  15. data/lib/fluent/output.rb +7 -2
  16. data/lib/fluent/parser.rb +82 -88
  17. data/lib/fluent/plugin.rb +18 -0
  18. data/lib/fluent/plugin/buf_file.rb +3 -3
  19. data/lib/fluent/plugin/in_dummy.rb +103 -0
  20. data/lib/fluent/plugin/in_exec.rb +1 -1
  21. data/lib/fluent/plugin/in_forward.rb +3 -3
  22. data/lib/fluent/plugin/in_gc_stat.rb +1 -1
  23. data/lib/fluent/plugin/in_http.rb +49 -17
  24. data/lib/fluent/plugin/in_monitor_agent.rb +41 -10
  25. data/lib/fluent/plugin/in_object_space.rb +1 -1
  26. data/lib/fluent/plugin/in_status.rb +1 -1
  27. data/lib/fluent/plugin/in_stream.rb +3 -3
  28. data/lib/fluent/plugin/in_syslog.rb +5 -5
  29. data/lib/fluent/plugin/in_tail.rb +6 -6
  30. data/lib/fluent/plugin/out_copy.rb +1 -1
  31. data/lib/fluent/plugin/out_exec_filter.rb +1 -1
  32. data/lib/fluent/plugin/out_file.rb +3 -3
  33. data/lib/fluent/plugin/out_roundrobin.rb +1 -1
  34. data/lib/fluent/plugin/socket_util.rb +2 -2
  35. data/lib/fluent/supervisor.rb +21 -24
  36. data/lib/fluent/test/base.rb +14 -0
  37. data/lib/fluent/test/output_test.rb +7 -1
  38. data/lib/fluent/version.rb +1 -1
  39. data/test/config/test_config_parser.rb +6 -2
  40. data/test/config/test_configurable.rb +1 -1
  41. data/test/config/test_configure_proxy.rb +1 -1
  42. data/test/config/test_dsl.rb +1 -1
  43. data/test/config/test_literal_parser.rb +2 -2
  44. data/test/config/test_section.rb +1 -1
  45. data/test/config/test_system_config.rb +65 -15
  46. data/test/config/test_types.rb +63 -0
  47. data/test/plugin/test_in_dummy.rb +95 -0
  48. data/test/plugin/test_in_exec.rb +1 -1
  49. data/test/plugin/test_in_forward.rb +1 -2
  50. data/test/plugin/test_in_gc_stat.rb +1 -1
  51. data/test/plugin/test_in_http.rb +77 -2
  52. data/test/plugin/test_in_object_space.rb +1 -1
  53. data/test/plugin/test_in_status.rb +1 -1
  54. data/test/plugin/test_in_stream.rb +1 -2
  55. data/test/plugin/test_in_syslog.rb +1 -2
  56. data/test/plugin/test_in_tail.rb +1 -1
  57. data/test/plugin/test_in_tcp.rb +1 -2
  58. data/test/plugin/test_in_udp.rb +1 -2
  59. data/test/plugin/test_out_copy.rb +12 -1
  60. data/test/plugin/test_out_exec.rb +1 -1
  61. data/test/plugin/test_out_exec_filter.rb +1 -1
  62. data/test/plugin/test_out_file.rb +61 -7
  63. data/test/plugin/test_out_forward.rb +1 -2
  64. data/test/plugin/test_out_roundrobin.rb +12 -1
  65. data/test/plugin/test_out_stdout.rb +1 -1
  66. data/test/plugin/test_out_stream.rb +1 -2
  67. data/test/scripts/fluent/plugin/formatter_known.rb +4 -1
  68. data/{lib → test/scripts}/fluent/plugin/out_test.rb +0 -0
  69. data/test/scripts/fluent/plugin/parser_known.rb +2 -1
  70. data/test/test_config.rb +1 -1
  71. data/test/test_configdsl.rb +1 -2
  72. data/test/test_formatter.rb +172 -3
  73. data/test/test_input.rb +21 -0
  74. data/test/test_match.rb +1 -2
  75. data/test/test_mixin.rb +1 -1
  76. data/test/test_output.rb +25 -1
  77. data/test/test_parser.rb +124 -78
  78. metadata +12 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2d8292e66a20b544c4f2f96165479f81573e7ead
4
- data.tar.gz: 8ac541d791d8d50454e4050f6c4242da7b85a884
3
+ metadata.gz: 3a62e7c7181c7f247c4a76b42638d0a6b4195d8a
4
+ data.tar.gz: 12ccff6793701f59c0b67c17d66804a3d25ac818
5
5
  SHA512:
6
- metadata.gz: b14d9f92215ea493b61825babac41710bef940e0d07f7a4955476f0e831257a3738ea244f84fcf1271011ced7fc0d4a5db20cd2e6759c488110f12ec94dc75d4
7
- data.tar.gz: 480aaf1a575d9c0d1153f24a2d1c2c92fa1ff0308664790b9a023c8b55d5bbaabd2b8ed29ec6209f36ebd899b4a087d40e57cff5bc742150f03ea77cd73391a4
6
+ metadata.gz: 81a1d182345423ecbb41a94351ccb6666f449126128718187345b9e62c187a3f8ed50fa56cfdee19cd5817ed37620471d10d871ca339cd345ef2111e1da76e29
7
+ data.tar.gz: 7a61d7bd4b80b28373fb1ed7824add416a085d77a7ace5a229bb34ebb6965fadf7fbcbd5ff4d61ee89ce6166b05a17011b619d5e7d9e9e42ddade2d6828ab8f0
@@ -14,6 +14,7 @@ os:
14
14
  branches:
15
15
  only:
16
16
  - master
17
+ - v0.10
17
18
 
18
19
  gemfile:
19
20
  - Gemfile
data/ChangeLog CHANGED
@@ -1,3 +1,21 @@
1
+ Release 0.10.58 - 2014/12/14
2
+
3
+ * parser/formatter: Add base class and Plugin.new_xxx/Plugin.register_xxx APIs
4
+ * parser: Fix blank column handling of TSVParser
5
+ * formatter: Add new CSV formatter
6
+ * formatter: Add msgpack format to built-in Formatter to dump records
7
+ * input: Add in_dummy plugin
8
+ * in_http: Add respond_with_empty_img parameter to return empty gif image
9
+ * in_http: Add cors_allow_origins parameter to support CORS request
10
+ * config: Add self.name to configure_proxy error message
11
+ * config: Fix system config using double memory
12
+ * config: Fix v1 config to support multiple tag match
13
+ * config: Fix Config.bool_value regression for nil value
14
+ * buffer: Prevent an exception with large num_retries
15
+ * out_file: Don't create world writable directory in daemon mode
16
+ * add router.emit and router= for compatibility with v0.12
17
+ * Use router instead of Engine.emit
18
+
1
19
  Release 0.10.57 - 2014/11/12
2
20
 
3
21
  * buffer: Make total_queued_chunk_size thread-safe to avoid race condition with in_monitor_agent
@@ -1,26 +1,31 @@
1
+ # In v1 configuration, type and id are @ prefix parameters.
2
+ # @type and @id are recommended. type and id are still available for backward compatibility
1
3
 
2
4
  ## built-in TCP input
3
5
  ## $ echo <json> | fluent-cat <tag>
4
6
  <source>
5
- type forward
7
+ @type forward
8
+ @id forward_input
6
9
  </source>
7
10
 
8
11
  ## built-in UNIX socket input
9
12
  #<source>
10
- # type unix
13
+ # @type unix
11
14
  #</source>
12
15
 
13
16
  # HTTP input
14
17
  # http://localhost:8888/<tag>?json=<json>
15
18
  <source>
16
- type http
19
+ @type http
20
+ @id http_input
21
+
17
22
  port 8888
18
23
  </source>
19
24
 
20
25
  ## File input
21
26
  ## read apache logs with tag=apache.access
22
27
  #<source>
23
- # type tail
28
+ # @type tail
24
29
  # format apache
25
30
  # path /var/log/httpd-access.log
26
31
  # tag apache.access
@@ -31,32 +36,38 @@
31
36
  # http://localhost:24220/api/plugins?type=TYPE
32
37
  # http://localhost:24220/api/plugins?tag=MYTAG
33
38
  <source>
34
- type monitor_agent
39
+ @type monitor_agent
40
+ @id monitor_agent_input
41
+
35
42
  port 24220
36
43
  </source>
37
44
 
38
45
  # Listen DRb for debug
39
46
  <source>
40
- type debug_agent
47
+ @type debug_agent
48
+ @id debug_agent_input
49
+
41
50
  bind 127.0.0.1
42
51
  port 24230
43
52
  </source>
44
53
 
45
-
46
54
  ## match tag=apache.access and write to file
47
55
  #<match apache.access>
48
- # type file
56
+ # @type file
49
57
  # path /var/log/fluent/access
50
58
  #</match>
51
59
 
52
60
  ## match tag=debug.** and dump to console
53
61
  <match debug.**>
54
- type stdout
62
+ @type stdout
63
+ @id stdout_output
55
64
  </match>
56
65
 
57
66
  # match tag=system.** and forward to another fluent server
58
67
  <match system.**>
59
- type forward
68
+ @type forward
69
+ @id forward_output
70
+
60
71
  <server>
61
72
  host 192.168.0.11
62
73
  </server>
@@ -69,9 +80,9 @@
69
80
 
70
81
  ## match tag=myapp.** and forward and write to file
71
82
  #<match myapp.**>
72
- # type copy
83
+ # @type copy
73
84
  # <store>
74
- # type forward
85
+ # @type forward
75
86
  # buffer_type file
76
87
  # buffer_path /var/log/fluent/myapp-forward
77
88
  # retry_limit 50
@@ -81,20 +92,19 @@
81
92
  # </server>
82
93
  # </store>
83
94
  # <store>
84
- # type file
95
+ # @type file
85
96
  # path /var/log/fluent/myapp
86
97
  # </store>
87
98
  #</match>
88
99
 
89
100
  ## match fluent's internal events
90
101
  #<match fluent.**>
91
- # type null
102
+ # @type null
92
103
  #</match>
93
104
 
94
105
  ## match not matched logs and write to file
95
106
  #<match **>
96
- # type file
107
+ # @type file
97
108
  # path /var/log/fluent/else
98
109
  # compress gz
99
110
  #</match>
100
-
@@ -16,7 +16,7 @@ Gem::Specification.new do |gem|
16
16
  gem.require_paths = ["lib"]
17
17
  gem.has_rdoc = false
18
18
 
19
- gem.required_ruby_version = '>= 1.9.2'
19
+ gem.required_ruby_version = '>= 1.9.3'
20
20
 
21
21
  gem.add_runtime_dependency("msgpack", [">= 0.4.4", "!= 0.5.0", "!= 0.5.1", "!= 0.5.2", "!= 0.5.3", "< 0.6.0"])
22
22
  gem.add_runtime_dependency("json", [">= 1.4.3"])
@@ -44,17 +44,10 @@ module Fluent
44
44
 
45
45
  module PluginId
46
46
  def configure(conf)
47
- @id = conf['id']
47
+ @id = conf['@id'] || conf['id']
48
48
  super
49
49
  end
50
50
 
51
- def require_id
52
- unless @id
53
- raise ConfigError, "'id' parameter is required"
54
- end
55
- @id
56
- end
57
-
58
51
  def plugin_id
59
52
  @id ? @id : "object:#{object_id.to_s(16)}"
60
53
  end
@@ -26,6 +26,7 @@ module Fluent
26
26
 
27
27
  LINE_END = /(?:[ \t]*(?:\#.*)?(?:\z|[\r\n]))+/
28
28
  SPACING = /(?:[ \t\r\n]|\z|\#.*?(?:\z|[\r\n]))+/
29
+ ZERO_OR_MORE_SPACING = /(?:[ \t\r\n]|\z|\#.*?(?:\z|[\r\n]))*/
29
30
  SPACING_WITHOUT_COMMENT = /(?:[ \t\r\n]|\z)+/
30
31
 
31
32
  module ClassMethods
@@ -68,13 +68,13 @@ module Fluent
68
68
  elsif a.is_a?(Hash)
69
69
  opts.merge!(a)
70
70
  else
71
- raise ArgumentError, "wrong number of arguments (#{1 + args.length} for #{block ? 2 : 3})"
71
+ raise ArgumentError, "#{self.name}: wrong number of arguments (#{1 + args.length} for #{block ? 2 : 3})"
72
72
  end
73
73
  }
74
74
 
75
75
  type = opts[:type]
76
76
  if block && type
77
- raise ArgumentError, "both of block and type cannot be specified"
77
+ raise ArgumentError, "#{self.name}: both of block and type cannot be specified"
78
78
  end
79
79
 
80
80
  begin
@@ -82,7 +82,7 @@ module Fluent
82
82
  block ||= Configurable.lookup_type(type)
83
83
  rescue ConfigError
84
84
  # override error message
85
- raise ArgumentError, "unknown config_argument type `#{type}'"
85
+ raise ArgumentError, "#{self.name}: unknown config_argument type `#{type}'"
86
86
  end
87
87
 
88
88
  if opts.has_key?(:default)
@@ -94,7 +94,7 @@ module Fluent
94
94
 
95
95
  def config_argument(name, *args, &block)
96
96
  if @argument
97
- raise ArgumentError, "config_argument called twice"
97
+ raise ArgumentError, "#{self.name}: config_argument called twice"
98
98
  end
99
99
  name, block, opts = parameter_configuration(name, *args, &block)
100
100
 
@@ -114,7 +114,7 @@ module Fluent
114
114
  name = name.to_sym
115
115
 
116
116
  if @defaults.has_key?(name)
117
- raise ArgumentError, "default value specified twice for #{name}"
117
+ raise ArgumentError, "#{self.name}: default value specified twice for #{name}"
118
118
  end
119
119
 
120
120
  @defaults[name] = defval
@@ -123,13 +123,13 @@ module Fluent
123
123
 
124
124
  def config_section(name, *args, &block)
125
125
  unless block_given?
126
- raise ArgumentError, "config_section requires block parameter"
126
+ raise ArgumentError, "#{self.name}: config_section requires block parameter"
127
127
  end
128
128
  name = name.to_sym
129
129
 
130
130
  opts = {}
131
131
  unless args.empty? || args.size == 1 && args.first.is_a?(Hash)
132
- raise ArgumentError, "unknown config_section arguments: #{args.inspect}"
132
+ raise ArgumentError, "#{self.name}: unknown config_section arguments: #{args.inspect}"
133
133
  end
134
134
 
135
135
  sub_proxy = ConfigureProxy.new(name, *args)
@@ -33,6 +33,7 @@ module Fluent
33
33
  end
34
34
 
35
35
  def self.bool_value(str)
36
+ return nil if str.nil?
36
37
  case str.to_s
37
38
  when 'true', 'yes'
38
39
  true
@@ -50,6 +50,7 @@ module Fluent
50
50
  end
51
51
 
52
52
  ELEM_SYMBOLS = ['match', 'source', 'filter', 'system']
53
+ RESERVED_PARAMS = %W(@type @id @label)
53
54
 
54
55
  def parse_element(root_element, elem_name, attrs = {}, elems = [])
55
56
  while true
@@ -78,7 +79,7 @@ module Fluent
78
79
  elsif skip(/\</)
79
80
  e_name = scan(ELEMENT_NAME)
80
81
  spacing
81
- e_arg = scan_nonquoted_string(/(?:#{SPACING}|\>)/)
82
+ e_arg = scan_nonquoted_string(/(?:#{ZERO_OR_MORE_SPACING}\>)/)
82
83
  spacing
83
84
  unless skip(/\>/)
84
85
  parse_error! "expected '>'"
@@ -352,30 +352,4 @@ module Fluent
352
352
  end
353
353
 
354
354
  Engine = EngineClass.new
355
-
356
-
357
- module Test
358
- @@test = false
359
-
360
- def test?
361
- @@test
362
- end
363
-
364
- def self.setup
365
- @@test = true
366
-
367
- Fluent.__send__(:remove_const, :Engine)
368
- engine = Fluent.const_set(:Engine, EngineClass.new).init
369
-
370
- engine.define_singleton_method(:now=) {|n|
371
- @now = n.to_i
372
- }
373
- engine.define_singleton_method(:now) {
374
- @now || super()
375
- }
376
-
377
- nil
378
- end
379
- end
380
355
  end
381
-
@@ -4,4 +4,5 @@ module Fluent
4
4
  DEFAULT_SOCKET_PATH = ENV['FLUENT_SOCKET'] || '/var/run/fluent/fluent.sock'
5
5
  DEFAULT_LISTEN_PORT = 24224
6
6
  DEFAULT_FILE_PERMISSION = 0644
7
+ DEFAULT_DIR_PERMISSION = 0755
7
8
  end
@@ -18,6 +18,18 @@
18
18
  module Fluent
19
19
  require 'fluent/registry'
20
20
 
21
+ class Formatter
22
+ include Configurable
23
+
24
+ def configure(conf)
25
+ super
26
+ end
27
+
28
+ def format(tag, time, record)
29
+ raise NotImplementedError, "Implement this method in child class"
30
+ end
31
+ end
32
+
21
33
  module TextFormatter
22
34
  module HandleTagAndTimeMixin
23
35
  def self.included(klass)
@@ -51,8 +63,7 @@ module Fluent
51
63
  end
52
64
  end
53
65
 
54
- class OutFileFormatter
55
- include Configurable
66
+ class OutFileFormatter < Formatter
56
67
  include HandleTagAndTimeMixin
57
68
 
58
69
  config_param :output_time, :bool, :default => true
@@ -65,10 +76,6 @@ module Fluent
65
76
  end
66
77
  end
67
78
 
68
- def configure(conf)
69
- super
70
- end
71
-
72
79
  def format(tag, time, record)
73
80
  filter_record(tag, time, record)
74
81
  header = ''
@@ -78,11 +85,12 @@ module Fluent
78
85
  end
79
86
  end
80
87
 
81
- class JSONFormatter
82
- include Configurable
83
- include HandleTagAndTimeMixin
84
-
85
- config_param :time_as_epoch, :bool, :default => false
88
+ module StructuredFormatMixin
89
+ def self.included(klass)
90
+ klass.instance_eval {
91
+ config_param :time_as_epoch, :bool, :default => false
92
+ }
93
+ end
86
94
 
87
95
  def configure(conf)
88
96
  super
@@ -100,12 +108,29 @@ module Fluent
100
108
  def format(tag, time, record)
101
109
  filter_record(tag, time, record)
102
110
  record[@time_key] = time if @time_as_epoch
111
+ format_record(record)
112
+ end
113
+ end
114
+
115
+ class JSONFormatter < Formatter
116
+ include HandleTagAndTimeMixin
117
+ include StructuredFormatMixin
118
+
119
+ def format_record(record)
103
120
  "#{Yajl.dump(record)}\n"
104
121
  end
105
122
  end
106
123
 
107
- class LabeledTSVFormatter
108
- include Configurable
124
+ class MessagePackFormatter < Formatter
125
+ include HandleTagAndTimeMixin
126
+ include StructuredFormatMixin
127
+
128
+ def format_record(record)
129
+ record.to_msgpack
130
+ end
131
+ end
132
+
133
+ class LabeledTSVFormatter < Formatter
109
134
  include HandleTagAndTimeMixin
110
135
 
111
136
  config_param :delimiter, :string, :default => "\t"
@@ -122,9 +147,37 @@ module Fluent
122
147
  end
123
148
  end
124
149
 
125
- class SingleValueFormatter
126
- include Configurable
150
+ class CsvFormatter < Formatter
151
+ include HandleTagAndTimeMixin
152
+
153
+ config_param :delimiter, :default => ',' do |val|
154
+ ['\t', 'TAB'].include?(val) ? "\t" : val
155
+ end
156
+ config_param :force_quotes, :bool, :default => true
157
+ config_param :fields, :default => [] do |val|
158
+ val.split(',').map do |f|
159
+ f.strip!
160
+ f.size > 0 ? f : nil
161
+ end.compact
162
+ end
163
+
164
+ def initialize
165
+ super
166
+ require 'csv'
167
+ end
168
+
169
+ def format(tag, time, record)
170
+ filter_record(tag, time, record)
171
+ row = @fields.inject([]) do |memo, key|
172
+ memo << record[key]
173
+ memo
174
+ end
175
+ CSV.generate_line(row, :col_sep => @delimiter,
176
+ :force_quotes => @force_quotes)
177
+ end
178
+ end
127
179
 
180
+ class SingleValueFormatter < Formatter
128
181
  config_param :message_key, :string, :default => 'message'
129
182
  config_param :add_newline, :bool, :default => true
130
183
 
@@ -135,41 +188,58 @@ module Fluent
135
188
  end
136
189
  end
137
190
 
191
+ class ProcWrappedFormatter < Formatter
192
+ def initialize(proc)
193
+ @proc = proc
194
+ end
195
+
196
+ def configure(conf)
197
+ end
198
+
199
+ def format(tag, time, record)
200
+ @proc.call(tag, time, record)
201
+ end
202
+ end
203
+
138
204
  TEMPLATE_REGISTRY = Registry.new(:formatter_type, 'fluent/plugin/formatter_')
139
205
  {
140
206
  'out_file' => Proc.new { OutFileFormatter.new },
141
207
  'json' => Proc.new { JSONFormatter.new },
208
+ 'msgpack' => Proc.new { MessagePackFormatter.new },
142
209
  'ltsv' => Proc.new { LabeledTSVFormatter.new },
210
+ 'csv' => Proc.new { CsvFormatter.new },
143
211
  'single_value' => Proc.new { SingleValueFormatter.new },
144
212
  }.each { |name, factory|
145
213
  TEMPLATE_REGISTRY.register(name, factory)
146
214
  }
147
215
 
148
216
  def self.register_template(name, factory_or_proc)
149
- factory = if factory_or_proc.arity == 3
150
- Proc.new { factory_or_proc }
151
- else
217
+ factory = if factory_or_proc.is_a?(Class) # XXXFormatter
218
+ Proc.new { factory_or_proc.new }
219
+ elsif factory_or_proc.arity == 3 # Proc.new { |tag, time, record| }
220
+ Proc.new { ProcWrappedFormatter.new(factory_or_proc) }
221
+ else # Proc.new { XXXFormatter.new }
152
222
  factory_or_proc
153
223
  end
154
224
 
155
225
  TEMPLATE_REGISTRY.register(name, factory)
156
226
  end
157
227
 
228
+ def self.lookup(format)
229
+ TEMPLATE_REGISTRY.lookup(format).call
230
+ end
231
+
232
+ # Keep backward-compatibility
158
233
  def self.create(conf)
159
234
  format = conf['format']
160
235
  if format.nil?
161
236
  raise ConfigError, "'format' parameter is required"
162
237
  end
163
238
 
164
- # built-in template
165
- begin
166
- factory = TEMPLATE_REGISTRY.lookup(format)
167
- rescue ConfigError => e
168
- raise ConfigError, "unknown format: '#{format}'"
239
+ formatter = lookup(format)
240
+ if formatter.respond_to?(:configure)
241
+ formatter.configure(conf)
169
242
  end
170
-
171
- formatter = factory.call
172
- formatter.configure(conf)
173
243
  formatter
174
244
  end
175
245
  end