fluentd 1.10.3-x64-mingw32 → 1.11.3-x64-mingw32

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 (71) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +102 -0
  3. data/CONTRIBUTING.md +1 -1
  4. data/example/copy_roundrobin.conf +3 -3
  5. data/example/counter.conf +1 -1
  6. data/example/filter_stdout.conf +2 -2
  7. data/example/{in_dummy_blocks.conf → in_sample_blocks.conf} +4 -4
  8. data/example/{in_dummy_with_compression.conf → in_sample_with_compression.conf} +3 -3
  9. data/example/logevents.conf +5 -5
  10. data/example/multi_filters.conf +1 -1
  11. data/example/out_exec_filter.conf +2 -2
  12. data/example/out_forward.conf +1 -1
  13. data/example/out_forward_buf_file.conf +1 -1
  14. data/example/out_forward_client.conf +5 -5
  15. data/example/out_forward_heartbeat_none.conf +1 -1
  16. data/example/out_forward_sd.conf +1 -1
  17. data/example/out_forward_shared_key.conf +2 -2
  18. data/example/out_forward_tls.conf +1 -1
  19. data/example/out_forward_users.conf +3 -3
  20. data/example/out_null.conf +4 -4
  21. data/example/secondary_file.conf +1 -1
  22. data/fluentd.gemspec +5 -5
  23. data/lib/fluent/command/fluentd.rb +11 -0
  24. data/lib/fluent/log.rb +33 -3
  25. data/lib/fluent/match.rb +9 -0
  26. data/lib/fluent/plugin/buffer.rb +49 -40
  27. data/lib/fluent/plugin/buffer/chunk.rb +2 -1
  28. data/lib/fluent/plugin/in_dummy.rb +2 -123
  29. data/lib/fluent/plugin/in_exec.rb +4 -2
  30. data/lib/fluent/plugin/in_forward.rb +2 -2
  31. data/lib/fluent/plugin/in_gc_stat.rb +16 -0
  32. data/lib/fluent/plugin/in_http.rb +148 -77
  33. data/lib/fluent/plugin/in_monitor_agent.rb +1 -1
  34. data/lib/fluent/plugin/in_sample.rb +141 -0
  35. data/lib/fluent/plugin/in_tail.rb +2 -2
  36. data/lib/fluent/plugin/in_unix.rb +77 -77
  37. data/lib/fluent/plugin/out_file.rb +1 -1
  38. data/lib/fluent/plugin/out_forward.rb +1 -1
  39. data/lib/fluent/plugin/out_forward/load_balancer.rb +1 -1
  40. data/lib/fluent/plugin/out_http.rb +15 -2
  41. data/lib/fluent/plugin/output.rb +1 -0
  42. data/lib/fluent/plugin/parser_json.rb +5 -2
  43. data/lib/fluent/plugin/parser_syslog.rb +215 -54
  44. data/lib/fluent/plugin_helper/cert_option.rb +5 -8
  45. data/lib/fluent/plugin_helper/child_process.rb +3 -2
  46. data/lib/fluent/plugin_helper/socket.rb +1 -1
  47. data/lib/fluent/supervisor.rb +15 -6
  48. data/lib/fluent/system_config.rb +2 -1
  49. data/lib/fluent/test/filter_test.rb +2 -2
  50. data/lib/fluent/test/output_test.rb +3 -3
  51. data/lib/fluent/version.rb +1 -1
  52. data/test/plugin/out_forward/test_load_balancer.rb +46 -0
  53. data/test/plugin/test_buffer.rb +4 -0
  54. data/test/plugin/test_in_exec.rb +18 -0
  55. data/test/plugin/test_in_gc_stat.rb +24 -1
  56. data/test/plugin/test_in_http.rb +57 -0
  57. data/test/plugin/{test_in_dummy.rb → test_in_sample.rb} +25 -25
  58. data/test/plugin/test_in_tail.rb +3 -0
  59. data/test/plugin/test_in_unix.rb +128 -73
  60. data/test/plugin/test_out_http.rb +38 -0
  61. data/test/plugin/test_parser_syslog.rb +66 -29
  62. data/test/plugin_helper/data/cert/empty.pem +0 -0
  63. data/test/plugin_helper/test_cert_option.rb +7 -0
  64. data/test/plugin_helper/test_child_process.rb +15 -0
  65. data/test/plugin_helper/test_http_server_helper.rb +5 -0
  66. data/test/plugin_helper/test_server.rb +34 -0
  67. data/test/plugin_helper/test_socket.rb +8 -0
  68. data/test/test_log.rb +44 -0
  69. data/test/test_match.rb +11 -0
  70. data/test/test_static_config_analysis.rb +2 -2
  71. metadata +19 -16
@@ -223,7 +223,7 @@ module Fluent::Plugin
223
223
  opts = {with_config: false, with_retry: false}
224
224
  timer_execute(:in_monitor_agent_emit, @emit_interval, repeat: true) {
225
225
  es = Fluent::MultiEventStream.new
226
- now = Fluent::Engine.now
226
+ now = Fluent::EventTime.now
227
227
  plugins_info_all(opts).each { |record|
228
228
  es.add(now, record)
229
229
  }
@@ -0,0 +1,141 @@
1
+ #
2
+ # Fluentd
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ #
16
+
17
+ require 'json'
18
+
19
+ require 'fluent/plugin/input'
20
+ require 'fluent/config/error'
21
+
22
+ module Fluent::Plugin
23
+ class SampleInput < Input
24
+ Fluent::Plugin.register_input('sample', self)
25
+ Fluent::Plugin.register_input('dummy', self)
26
+
27
+ helpers :thread, :storage
28
+
29
+ BIN_NUM = 10
30
+ DEFAULT_STORAGE_TYPE = 'local'
31
+
32
+ desc "The value is the tag assigned to the generated events."
33
+ config_param :tag, :string
34
+ desc "The number of events in event stream of each emits."
35
+ config_param :size, :integer, default: 1
36
+ desc "It configures how many events to generate per second."
37
+ config_param :rate, :integer, default: 1
38
+ desc "If specified, each generated event has an auto-incremented key field."
39
+ config_param :auto_increment_key, :string, default: nil
40
+ desc "The boolean to suspend-and-resume incremental value after restart"
41
+ config_param :suspend, :bool, default: false,deprecated: 'This parameters is ignored'
42
+ desc "The sample data to be generated. An array of JSON hashes or a single JSON hash."
43
+ config_param :sample, alias: :dummy, default: [{"message" => "sample"}] do |val|
44
+ begin
45
+ parsed = JSON.parse(val)
46
+ rescue JSON::ParserError => ex
47
+ # Fluent::ConfigParseError, "got incomplete JSON" will be raised
48
+ # at literal_parser.rb with --use-v1-config, but I had to
49
+ # take care at here for the case of --use-v0-config.
50
+ raise Fluent::ConfigError, "#{ex.class}: #{ex.message}"
51
+ end
52
+ sample = parsed.is_a?(Array) ? parsed : [parsed]
53
+ sample.each_with_index do |e, i|
54
+ raise Fluent::ConfigError, "#{i}th element of sample, #{e}, is not a hash" unless e.is_a?(Hash)
55
+ end
56
+ sample
57
+ end
58
+
59
+ def initialize
60
+ super
61
+ @storage = nil
62
+ end
63
+
64
+ def configure(conf)
65
+ super
66
+ @sample_index = 0
67
+ config = conf.elements.select{|e| e.name == 'storage' }.first
68
+ @storage = storage_create(usage: 'suspend', conf: config, default_type: DEFAULT_STORAGE_TYPE)
69
+ end
70
+
71
+ def multi_workers_ready?
72
+ true
73
+ end
74
+
75
+ def start
76
+ super
77
+
78
+ @storage.put(:increment_value, 0) unless @storage.get(:increment_value)
79
+ # keep 'dummy' to avoid breaking changes for existing environment. Change it in fluentd v2
80
+ @storage.put(:dummy_index, 0) unless @storage.get(:dummy_index)
81
+
82
+ if @auto_increment_key && !@storage.get(:auto_increment_value)
83
+ @storage.put(:auto_increment_value, -1)
84
+ end
85
+
86
+ thread_create(:sample_input, &method(:run))
87
+ end
88
+
89
+ def run
90
+ batch_num = (@rate / BIN_NUM).to_i
91
+ residual_num = (@rate % BIN_NUM)
92
+ while thread_current_running?
93
+ current_time = Time.now.to_i
94
+ BIN_NUM.times do
95
+ break unless (thread_current_running? && Time.now.to_i <= current_time)
96
+ wait(0.1) { emit(batch_num) }
97
+ end
98
+ emit(residual_num) if thread_current_running?
99
+ # wait for next second
100
+ while thread_current_running? && Time.now.to_i <= current_time
101
+ sleep 0.01
102
+ end
103
+ end
104
+ end
105
+
106
+ def emit(num)
107
+ begin
108
+ if @size > 1
109
+ num.times do
110
+ router.emit_array(@tag, Array.new(@size) { [Fluent::EventTime.now, generate] })
111
+ end
112
+ else
113
+ num.times { router.emit(@tag, Fluent::EventTime.now, generate) }
114
+ end
115
+ rescue => _
116
+ # ignore all errors not to stop emits by emit errors
117
+ end
118
+ end
119
+
120
+ def generate
121
+ d = @sample[@sample_index]
122
+ unless d
123
+ @sample_index = 0
124
+ d = @sample[@sample_index]
125
+ end
126
+ @sample_index += 1
127
+ if @auto_increment_key
128
+ d = d.dup
129
+ d[@auto_increment_key] = @storage.update(:auto_increment_value){|v| v + 1 }
130
+ end
131
+ d
132
+ end
133
+
134
+ def wait(time)
135
+ start_time = Time.now
136
+ yield
137
+ sleep_time = time - (Time.now - start_time)
138
+ sleep sleep_time if sleep_time > 0
139
+ end
140
+ end
141
+ end
@@ -271,9 +271,9 @@ module Fluent::Plugin
271
271
  end
272
272
  else
273
273
  if is_file
274
- unless @ignore_list.include?(path)
274
+ unless @ignore_list.include?(p)
275
275
  log.warn "#{p} unreadable. It is excluded and would be examined next time."
276
- @ignore_list << path if @ignore_repeated_permission_error
276
+ @ignore_list << p if @ignore_repeated_permission_error
277
277
  end
278
278
  end
279
279
  false
@@ -14,50 +14,68 @@
14
14
  # limitations under the License.
15
15
  #
16
16
 
17
- require 'fileutils'
18
- require 'socket'
17
+ require 'fluent/env'
18
+ require 'fluent/plugin/input'
19
+ require 'fluent/msgpack_factory'
19
20
 
20
21
  require 'cool.io'
21
22
  require 'yajl'
23
+ require 'fileutils'
24
+ require 'socket'
25
+
26
+ module Fluent::Plugin
27
+ # TODO: This plugin will be 3rd party plugin
28
+ class UnixInput < Input
29
+ Fluent::Plugin.register_input('unix', self)
30
+
31
+ helpers :event_loop
32
+
33
+ def initialize
34
+ super
22
35
 
23
- require 'fluent/input'
24
- require 'fluent/event'
36
+ @lsock = nil
37
+ end
25
38
 
26
- module Fluent
27
- # obsolete
28
- class StreamInput < Input
29
- config_param :blocking_timeout, :time, default: 0.5
39
+ desc 'The path to your Unix Domain Socket.'
40
+ config_param :path, :string, default: Fluent::DEFAULT_SOCKET_PATH
41
+ desc 'The backlog of Unix Domain Socket.'
42
+ config_param :backlog, :integer, default: nil
43
+ desc "New tag instead of incoming tag"
44
+ config_param :tag, :string, default: nil
45
+
46
+ def configure(conf)
47
+ super
48
+ end
30
49
 
31
50
  def start
32
51
  super
33
52
 
34
- @loop = Coolio::Loop.new
35
53
  @lsock = listen
36
- @loop.attach(@lsock)
37
- @thread = Thread.new(&method(:run))
54
+ event_loop_attach(@lsock)
38
55
  end
39
56
 
40
57
  def shutdown
41
- @loop.watchers.each {|w| w.detach }
42
- @loop.stop
43
- @lsock.close
44
- @thread.join
58
+ if @lsock
59
+ event_loop_detach(@lsock)
60
+ @lsock.close
61
+ end
45
62
 
46
63
  super
47
64
  end
48
65
 
49
- #def listen
50
- #end
66
+ def listen
67
+ if File.exist?(@path)
68
+ log.warn "Found existing '#{@path}'. Remove this file for in_unix plugin"
69
+ File.unlink(@path)
70
+ end
71
+ FileUtils.mkdir_p(File.dirname(@path))
51
72
 
52
- def run
53
- @loop.run(@blocking_timeout)
54
- rescue
55
- log.error "unexpected error", error: $!.to_s
56
- log.error_backtrace
73
+ log.info "listening fluent socket on #{@path}"
74
+ s = Coolio::UNIXServer.new(@path, Handler, log, method(:on_message))
75
+ s.listen(@backlog) unless @backlog.nil?
76
+ s
57
77
  end
58
78
 
59
- private
60
-
61
79
  # message Entry {
62
80
  # 1: long time
63
81
  # 2: object record
@@ -79,23 +97,27 @@ module Fluent
79
97
  # 3: object record
80
98
  # }
81
99
  def on_message(msg)
82
- # TODO format error
83
- tag = msg[0].to_s
100
+ unless msg.is_a?(Array)
101
+ log.warn "incoming data is broken:", msg: msg
102
+ return
103
+ end
104
+
105
+ tag = @tag || (msg[0].to_s)
84
106
  entries = msg[1]
85
107
 
86
- if entries.class == String
108
+ case entries
109
+ when String
87
110
  # PackedForward
88
- es = MessagePackEventStream.new(entries)
111
+ es = Fluent::MessagePackEventStream.new(entries)
89
112
  router.emit_stream(tag, es)
90
113
 
91
- elsif entries.class == Array
114
+ when Array
92
115
  # Forward
93
- es = MultiEventStream.new
116
+ es = Fluent::MultiEventStream.new
94
117
  entries.each {|e|
95
118
  record = e[1]
96
119
  next if record.nil?
97
- time = e[0]
98
- time = (now ||= Engine.now) if time.to_i == 0
120
+ time = convert_time(e[0])
99
121
  es.add(time, record)
100
122
  }
101
123
  router.emit_stream(tag, es)
@@ -105,25 +127,28 @@ module Fluent
105
127
  record = msg[2]
106
128
  return if record.nil?
107
129
 
108
- time = msg[1]
109
- time = Engine.now if time.to_i == 0
130
+ time = convert_time(msg[1])
110
131
  router.emit(tag, time, record)
111
132
  end
112
133
  end
113
134
 
135
+ def convert_time(time)
136
+ case time
137
+ when nil, 0
138
+ Fluent::EventTime.now
139
+ when Fluent::EventTime
140
+ time
141
+ else
142
+ Fluent::EventTime.from_time(Time.at(time))
143
+ end
144
+ end
145
+
114
146
  class Handler < Coolio::Socket
115
147
  def initialize(io, log, on_message)
116
148
  super(io)
117
- if io.is_a?(TCPSocket)
118
- opt = [1, @timeout.to_i].pack('I!I!') # { int l_onoff; int l_linger; }
119
- io.setsockopt(Socket::SOL_SOCKET, Socket::SO_LINGER, opt)
120
- end
149
+
121
150
  @on_message = on_message
122
151
  @log = log
123
- @log.trace {
124
- remote_port, remote_addr = *Socket.unpack_sockaddr_in(@_io.getpeername) rescue nil
125
- "accepted fluent socket from '#{remote_addr}:#{remote_port}': object_id=#{self.object_id}"
126
- }
127
152
  end
128
153
 
129
154
  def on_connect
@@ -131,13 +156,13 @@ module Fluent
131
156
 
132
157
  def on_read(data)
133
158
  first = data[0]
134
- if first == '{' || first == '['
159
+ if first == '{'.freeze || first == '['.freeze
135
160
  m = method(:on_read_json)
136
- @y = Yajl::Parser.new
137
- @y.on_parse_complete = @on_message
161
+ @parser = Yajl::Parser.new
162
+ @parser.on_parse_complete = @on_message
138
163
  else
139
164
  m = method(:on_read_msgpack)
140
- @u = Fluent::MessagePackFactory.msgpack_unpacker
165
+ @parser = Fluent::MessagePackFactory.msgpack_unpacker
141
166
  end
142
167
 
143
168
  singleton_class.module_eval do
@@ -147,17 +172,17 @@ module Fluent
147
172
  end
148
173
 
149
174
  def on_read_json(data)
150
- @y << data
151
- rescue
152
- @log.error "unexpected error", error: $!.to_s
175
+ @parser << data
176
+ rescue => e
177
+ @log.error "unexpected error in json payload", error: e.to_s
153
178
  @log.error_backtrace
154
179
  close
155
180
  end
156
181
 
157
182
  def on_read_msgpack(data)
158
- @u.feed_each(data, &@on_message)
159
- rescue
160
- @log.error "unexpected error", error: $!.to_s
183
+ @parser.feed_each(data, &@on_message)
184
+ rescue => e
185
+ @log.error "unexpected error in msgpack payload", error: e.to_s
161
186
  @log.error_backtrace
162
187
  close
163
188
  end
@@ -167,29 +192,4 @@ module Fluent
167
192
  end
168
193
  end
169
194
  end
170
-
171
- class UnixInput < StreamInput
172
- Plugin.register_input('unix', self)
173
-
174
- desc 'The path to your Unix Domain Socket.'
175
- config_param :path, :string, default: DEFAULT_SOCKET_PATH
176
- desc 'The backlog of Unix Domain Socket.'
177
- config_param :backlog, :integer, default: nil
178
-
179
- def configure(conf)
180
- super
181
- #log.warn "'unix' input is obsoleted and will be removed. Use 'forward' instead."
182
- end
183
-
184
- def listen
185
- if File.exist?(@path)
186
- File.unlink(@path)
187
- end
188
- FileUtils.mkdir_p File.dirname(@path)
189
- log.info "listening fluent socket on #{@path}"
190
- s = Coolio::UNIXServer.new(@path, Handler, log, method(:on_message))
191
- s.listen(@backlog) unless @backlog.nil?
192
- s
193
- end
194
- end
195
195
  end
@@ -155,7 +155,7 @@ module Fluent::Plugin
155
155
  dummy_record_keys = get_placeholders_keys(@path_template) || ['message']
156
156
  dummy_record = Hash[dummy_record_keys.zip(['data'] * dummy_record_keys.size)]
157
157
 
158
- test_chunk1 = chunk_for_test(dummy_tag, Fluent::Engine.now, dummy_record)
158
+ test_chunk1 = chunk_for_test(dummy_tag, Fluent::EventTime.now, dummy_record)
159
159
  test_path = extract_placeholders(@path_template, test_chunk1)
160
160
  unless ::Fluent::FileUtil.writable_p?(test_path)
161
161
  raise Fluent::ConfigError, "out_file: `#{test_path}` is not writable"
@@ -709,7 +709,7 @@ module Fluent::Plugin
709
709
  @resolved_host ||= resolve_dns!
710
710
 
711
711
  else
712
- now = Fluent::Engine.now
712
+ now = Fluent::EventTime.now
713
713
  rh = @resolved_host
714
714
  if !rh || now - @resolved_time >= @sender.expire_dns_cache
715
715
  rh = @resolved_host = resolve_dns!
@@ -56,7 +56,7 @@ module Fluent::Plugin
56
56
  end
57
57
 
58
58
  def rebuild_weight_array(nodes)
59
- standby_nodes, regular_nodes = nodes.partition {|n|
59
+ standby_nodes, regular_nodes = nodes.select { |e| e.weight > 0 }.partition {|n|
60
60
  n.standby?
61
61
  }
62
62
 
@@ -37,6 +37,8 @@ module Fluent::Plugin
37
37
  config_param :proxy, :string, default: ENV['HTTP_PROXY'] || ENV['http_proxy']
38
38
  desc 'Content-Type for HTTP request'
39
39
  config_param :content_type, :string, default: nil
40
+ desc 'JSON array data format for HTTP request body'
41
+ config_param :json_array, :bool, default: false
40
42
  desc 'Additional headers for HTTP request'
41
43
  config_param :headers, :hash, default: nil
42
44
 
@@ -100,6 +102,13 @@ module Fluent::Plugin
100
102
  @proxy_uri = URI.parse(@proxy) if @proxy
101
103
  @formatter = formatter_create
102
104
  @content_type = setup_content_type unless @content_type
105
+
106
+ if @json_array
107
+ if @formatter_configs.first[:@type] != "json"
108
+ raise Fluent::ConfigError, "json_array option could be used with json formatter only"
109
+ end
110
+ define_singleton_method(:format, method(:format_json_array))
111
+ end
103
112
  end
104
113
 
105
114
  def multi_workers_ready?
@@ -114,6 +123,10 @@ module Fluent::Plugin
114
123
  @formatter.format(tag, time, record)
115
124
  end
116
125
 
126
+ def format_json_array(tag, time, record)
127
+ @formatter.format(tag, time, record) << ","
128
+ end
129
+
117
130
  def write(chunk)
118
131
  uri = parse_endpoint(chunk)
119
132
  req = create_request(chunk, uri)
@@ -128,7 +141,7 @@ module Fluent::Plugin
128
141
  def setup_content_type
129
142
  case @formatter_configs.first[:@type]
130
143
  when 'json'
131
- 'application/x-ndjson'
144
+ @json_array ? 'application/json' : 'application/x-ndjson'
132
145
  when 'csv'
133
146
  'text/csv'
134
147
  when 'tsv', 'ltsv'
@@ -202,7 +215,7 @@ module Fluent::Plugin
202
215
  req.basic_auth(@auth.username, @auth.password)
203
216
  end
204
217
  set_headers(req)
205
- req.body = chunk.read
218
+ req.body = @json_array ? "[#{chunk.read.chop!}]" : chunk.read
206
219
  req
207
220
  end
208
221