fluentd 1.10.4-x64-mingw32 → 1.11.4-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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +100 -0
- data/example/copy_roundrobin.conf +3 -3
- data/example/counter.conf +1 -1
- data/example/filter_stdout.conf +2 -2
- data/example/{in_dummy_blocks.conf → in_sample_blocks.conf} +4 -4
- data/example/{in_dummy_with_compression.conf → in_sample_with_compression.conf} +3 -3
- data/example/logevents.conf +5 -5
- data/example/multi_filters.conf +1 -1
- data/example/out_exec_filter.conf +2 -2
- data/example/out_forward.conf +1 -1
- data/example/out_forward_buf_file.conf +1 -1
- data/example/out_forward_client.conf +5 -5
- data/example/out_forward_heartbeat_none.conf +1 -1
- data/example/out_forward_sd.conf +1 -1
- data/example/out_forward_shared_key.conf +2 -2
- data/example/out_forward_tls.conf +1 -1
- data/example/out_forward_users.conf +3 -3
- data/example/out_null.conf +4 -4
- data/example/secondary_file.conf +1 -1
- data/fluentd.gemspec +5 -5
- data/lib/fluent/command/fluentd.rb +11 -0
- data/lib/fluent/log.rb +33 -3
- data/lib/fluent/match.rb +9 -0
- data/lib/fluent/plugin/buffer.rb +49 -40
- data/lib/fluent/plugin/buffer/chunk.rb +2 -1
- data/lib/fluent/plugin/in_dummy.rb +2 -123
- data/lib/fluent/plugin/in_exec.rb +4 -2
- data/lib/fluent/plugin/in_gc_stat.rb +16 -0
- data/lib/fluent/plugin/in_http.rb +148 -77
- data/lib/fluent/plugin/in_sample.rb +141 -0
- data/lib/fluent/plugin/in_tail.rb +2 -2
- data/lib/fluent/plugin/in_unix.rb +77 -77
- data/lib/fluent/plugin/out_http.rb +1 -1
- data/lib/fluent/plugin/output.rb +8 -5
- data/lib/fluent/plugin/parser_json.rb +5 -2
- data/lib/fluent/plugin/parser_syslog.rb +215 -54
- data/lib/fluent/plugin_helper/cert_option.rb +5 -8
- data/lib/fluent/plugin_helper/child_process.rb +3 -2
- data/lib/fluent/plugin_helper/inject.rb +2 -1
- data/lib/fluent/plugin_helper/socket.rb +1 -1
- data/lib/fluent/supervisor.rb +11 -5
- data/lib/fluent/system_config.rb +2 -1
- data/lib/fluent/version.rb +1 -1
- data/test/plugin/test_buffer.rb +4 -0
- data/test/plugin/test_in_exec.rb +18 -0
- data/test/plugin/test_in_gc_stat.rb +24 -1
- data/test/plugin/test_in_http.rb +57 -0
- data/test/plugin/{test_in_dummy.rb → test_in_sample.rb} +25 -25
- data/test/plugin/test_in_tail.rb +3 -0
- data/test/plugin/test_in_unix.rb +128 -72
- data/test/plugin/test_output.rb +12 -0
- data/test/plugin/test_parser_syslog.rb +66 -29
- data/test/plugin_helper/data/cert/empty.pem +0 -0
- data/test/plugin_helper/test_cert_option.rb +7 -0
- data/test/plugin_helper/test_child_process.rb +15 -0
- data/test/plugin_helper/test_http_server_helper.rb +5 -0
- data/test/plugin_helper/test_inject.rb +13 -0
- data/test/plugin_helper/test_server.rb +34 -0
- data/test/plugin_helper/test_socket.rb +8 -0
- data/test/test_log.rb +44 -0
- data/test/test_match.rb +11 -0
- data/test/test_static_config_analysis.rb +2 -2
- metadata +19 -16
@@ -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?(
|
274
|
+
unless @ignore_list.include?(p)
|
275
275
|
log.warn "#{p} unreadable. It is excluded and would be examined next time."
|
276
|
-
@ignore_list <<
|
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 '
|
18
|
-
require '
|
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
|
-
|
24
|
-
|
36
|
+
@lsock = nil
|
37
|
+
end
|
25
38
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
config_param :
|
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
|
-
|
37
|
-
@thread = Thread.new(&method(:run))
|
54
|
+
event_loop_attach(@lsock)
|
38
55
|
end
|
39
56
|
|
40
57
|
def shutdown
|
41
|
-
@
|
42
|
-
|
43
|
-
|
44
|
-
|
58
|
+
if @lsock
|
59
|
+
event_loop_detach(@lsock)
|
60
|
+
@lsock.close
|
61
|
+
end
|
45
62
|
|
46
63
|
super
|
47
64
|
end
|
48
65
|
|
49
|
-
|
50
|
-
|
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
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
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
|
-
|
83
|
-
|
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
|
-
|
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
|
-
|
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 ||= EventTime.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 = EventTime.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
|
-
|
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
|
-
@
|
137
|
-
@
|
161
|
+
@parser = Yajl::Parser.new
|
162
|
+
@parser.on_parse_complete = @on_message
|
138
163
|
else
|
139
164
|
m = method(:on_read_msgpack)
|
140
|
-
@
|
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
|
-
@
|
151
|
-
rescue
|
152
|
-
@log.error "unexpected error", error:
|
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
|
-
@
|
159
|
-
rescue
|
160
|
-
@log.error "unexpected error", error:
|
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
|
@@ -215,7 +215,7 @@ module Fluent::Plugin
|
|
215
215
|
req.basic_auth(@auth.username, @auth.password)
|
216
216
|
end
|
217
217
|
set_headers(req)
|
218
|
-
req.body = @json_array ? "[#{chunk.read.chop
|
218
|
+
req.body = @json_array ? "[#{chunk.read.chop}]" : chunk.read
|
219
219
|
req
|
220
220
|
end
|
221
221
|
|
data/lib/fluent/plugin/output.rb
CHANGED
@@ -340,6 +340,7 @@ module Fluent
|
|
340
340
|
buffer_conf = conf.elements(name: 'buffer').first || Fluent::Config::Element.new('buffer', '', {}, [])
|
341
341
|
@buffer = Plugin.new_buffer(buffer_type, parent: self)
|
342
342
|
@buffer.configure(buffer_conf)
|
343
|
+
@buffer.enable_update_timekeys if @chunk_key_time
|
343
344
|
|
344
345
|
@flush_at_shutdown = @buffer_config.flush_at_shutdown
|
345
346
|
if @flush_at_shutdown.nil?
|
@@ -768,17 +769,19 @@ module Fluent
|
|
768
769
|
end
|
769
770
|
end
|
770
771
|
|
771
|
-
|
772
|
-
log.warn "chunk key placeholder '#{$1}' not replaced. template:#{str}"
|
773
|
-
end
|
774
|
-
|
775
|
-
rvalue.sub(CHUNK_ID_PLACEHOLDER_PATTERN) {
|
772
|
+
rvalue = rvalue.sub(CHUNK_ID_PLACEHOLDER_PATTERN) {
|
776
773
|
if chunk_passed
|
777
774
|
dump_unique_id_hex(chunk.unique_id)
|
778
775
|
else
|
779
776
|
log.warn "${chunk_id} is not allowed in this plugin. Pass Chunk instead of metadata in extract_placeholders's 2nd argument"
|
780
777
|
end
|
781
778
|
}
|
779
|
+
|
780
|
+
if rvalue =~ CHUNK_KEY_PLACEHOLDER_PATTERN
|
781
|
+
log.warn "chunk key placeholder '#{$1}' not replaced. template:#{str}"
|
782
|
+
end
|
783
|
+
|
784
|
+
rvalue
|
782
785
|
end
|
783
786
|
end
|
784
787
|
|
@@ -71,8 +71,11 @@ module Fluent
|
|
71
71
|
end
|
72
72
|
|
73
73
|
def parse(text)
|
74
|
-
|
75
|
-
time
|
74
|
+
record = @load_proc.call(text)
|
75
|
+
time = parse_time(record)
|
76
|
+
if @execute_convert_values
|
77
|
+
time, record = convert_values(time, record)
|
78
|
+
end
|
76
79
|
yield time, record
|
77
80
|
rescue @error_class, EncodingError # EncodingError is for oj 3.x or later
|
78
81
|
yield nil, nil
|
@@ -63,16 +63,22 @@ module Fluent
|
|
63
63
|
def initialize
|
64
64
|
super
|
65
65
|
@mutex = Mutex.new
|
66
|
-
@
|
66
|
+
@regexp = nil
|
67
|
+
@regexp3164 = nil
|
68
|
+
@regexp5424 = nil
|
69
|
+
@regexp_parser = nil
|
70
|
+
@time_parser_rfc3164 = nil
|
71
|
+
@time_parser_rfc5424 = nil
|
72
|
+
@space_count_rfc3164 = nil
|
67
73
|
@space_count_rfc5424 = nil
|
74
|
+
@skip_space_count_rfc3164 = false
|
75
|
+
@skip_space_count_rfc5424 = false
|
76
|
+
@time_parser_rfc5424_without_subseconds = nil
|
68
77
|
end
|
69
78
|
|
70
79
|
def configure(conf)
|
71
80
|
super
|
72
81
|
|
73
|
-
@time_parser_rfc3164 = @time_parser_rfc5424 = nil
|
74
|
-
@time_parser_rfc5424_without_subseconds = nil
|
75
|
-
@support_rfc5424_without_subseconds = false
|
76
82
|
@regexp_parser = @parser_type == :regexp
|
77
83
|
@regexp = case @message_format
|
78
84
|
when :rfc3164
|
@@ -85,27 +91,49 @@ module Fluent
|
|
85
91
|
alias_method :parse, :parse_rfc3164
|
86
92
|
end
|
87
93
|
end
|
94
|
+
setup_time_parser_3164(@time_format)
|
88
95
|
RFC3164_WITHOUT_TIME_AND_PRI_REGEXP
|
89
96
|
when :rfc5424
|
90
|
-
|
91
|
-
|
97
|
+
if @regexp_parser
|
98
|
+
class << self
|
99
|
+
alias_method :parse, :parse_rfc5424_regex
|
100
|
+
end
|
101
|
+
else
|
102
|
+
class << self
|
103
|
+
alias_method :parse, :parse_rfc5424
|
104
|
+
end
|
92
105
|
end
|
93
106
|
@time_format = @rfc5424_time_format unless conf.has_key?('time_format')
|
94
|
-
@
|
107
|
+
setup_time_parser_5424(@time_format)
|
95
108
|
RFC5424_WITHOUT_TIME_AND_PRI_REGEXP
|
96
109
|
when :auto
|
97
110
|
class << self
|
98
111
|
alias_method :parse, :parse_auto
|
99
112
|
end
|
100
|
-
|
101
|
-
|
113
|
+
setup_time_parser_3164(@time_format)
|
114
|
+
setup_time_parser_5424(@rfc5424_time_format)
|
102
115
|
nil
|
103
116
|
end
|
104
117
|
|
105
|
-
|
106
|
-
|
107
|
-
|
118
|
+
if @regexp_parser
|
119
|
+
@regexp3164 = RFC3164_WITHOUT_TIME_AND_PRI_REGEXP
|
120
|
+
@regexp5424 = RFC5424_WITHOUT_TIME_AND_PRI_REGEXP
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def setup_time_parser_3164(time_fmt)
|
125
|
+
@time_parser_rfc3164 = time_parser_create(format: time_fmt)
|
126
|
+
if ['%b %d %H:%M:%S', '%b %d %H:%M:%S.%N'].include?(time_fmt)
|
127
|
+
@skip_space_count_rfc3164 = true
|
128
|
+
end
|
129
|
+
@space_count_rfc3164 = time_fmt.squeeze(' ').count(' ') + 1
|
130
|
+
end
|
131
|
+
|
132
|
+
def setup_time_parser_5424(time_fmt)
|
133
|
+
@time_parser_rfc5424 = time_parser_create(format: time_fmt)
|
108
134
|
@time_parser_rfc5424_without_subseconds = time_parser_create(format: "%Y-%m-%dT%H:%M:%S%z")
|
135
|
+
@skip_space_count_rfc5424 = time_fmt.count(' ').zero?
|
136
|
+
@space_count_rfc5424 = time_fmt.squeeze(' ').count(' ') + 1
|
109
137
|
end
|
110
138
|
|
111
139
|
# this method is for tests
|
@@ -118,14 +146,13 @@ module Fluent
|
|
118
146
|
end
|
119
147
|
|
120
148
|
def parse_auto(text, &block)
|
121
|
-
if REGEXP_DETECT_RFC5424.match(text)
|
122
|
-
@
|
123
|
-
|
124
|
-
|
125
|
-
|
149
|
+
if REGEXP_DETECT_RFC5424.match?(text)
|
150
|
+
if @regexp_parser
|
151
|
+
parse_rfc5424_regex(text, &block)
|
152
|
+
else
|
153
|
+
parse_rfc5424(text, &block)
|
154
|
+
end
|
126
155
|
else
|
127
|
-
@regexp = RFC3164_WITHOUT_TIME_AND_PRI_REGEXP
|
128
|
-
@time_parser = @time_parser_rfc3164
|
129
156
|
if @regexp_parser
|
130
157
|
parse_rfc3164_regex(text, &block)
|
131
158
|
else
|
@@ -134,6 +161,8 @@ module Fluent
|
|
134
161
|
end
|
135
162
|
end
|
136
163
|
|
164
|
+
SPLIT_CHAR = ' '.freeze
|
165
|
+
|
137
166
|
def parse_rfc3164_regex(text, &block)
|
138
167
|
idx = 0
|
139
168
|
record = {}
|
@@ -151,22 +180,22 @@ module Fluent
|
|
151
180
|
|
152
181
|
i = idx - 1
|
153
182
|
sq = false
|
154
|
-
@
|
155
|
-
while text[i + 1] ==
|
183
|
+
@space_count_rfc3164.times do
|
184
|
+
while text[i + 1] == SPLIT_CHAR
|
156
185
|
sq = true
|
157
186
|
i += 1
|
158
187
|
end
|
159
188
|
|
160
|
-
i = text.index(
|
189
|
+
i = text.index(SPLIT_CHAR, i + 1)
|
161
190
|
end
|
162
191
|
|
163
|
-
time_str = sq ? text.slice(idx, i - idx).squeeze(
|
164
|
-
time = @mutex.synchronize { @
|
192
|
+
time_str = sq ? text.slice(idx, i - idx).squeeze(SPLIT_CHAR) : text.slice(idx, i - idx)
|
193
|
+
time = @mutex.synchronize { @time_parser_rfc3164.parse(time_str) }
|
165
194
|
if @keep_time_key
|
166
195
|
record['time'] = time_str
|
167
196
|
end
|
168
197
|
|
169
|
-
parse_plain(time, text, i + 1, record, RFC3164_CAPTURES, &block)
|
198
|
+
parse_plain(@regexp3164, time, text, i + 1, record, RFC3164_CAPTURES, &block)
|
170
199
|
end
|
171
200
|
|
172
201
|
def parse_rfc5424_regex(text, &block)
|
@@ -186,40 +215,36 @@ module Fluent
|
|
186
215
|
i = idx - 1
|
187
216
|
sq = false
|
188
217
|
@space_count_rfc5424.times {
|
189
|
-
while text[i + 1] ==
|
218
|
+
while text[i + 1] == SPLIT_CHAR
|
190
219
|
sq = true
|
191
220
|
i += 1
|
192
221
|
end
|
193
222
|
|
194
|
-
i = text.index(
|
223
|
+
i = text.index(SPLIT_CHAR, i + 1)
|
195
224
|
}
|
196
225
|
|
197
|
-
time_str = sq ? text.slice(idx, i - idx).squeeze(
|
226
|
+
time_str = sq ? text.slice(idx, i - idx).squeeze(SPLIT_CHAR) : text.slice(idx, i - idx)
|
198
227
|
time = @mutex.synchronize do
|
199
228
|
begin
|
200
|
-
@
|
229
|
+
@time_parser_rfc5424.parse(time_str)
|
201
230
|
rescue Fluent::TimeParser::TimeParseError => e
|
202
|
-
|
203
|
-
|
204
|
-
@time_parser_rfc5424_without_subseconds.parse(time_str)
|
205
|
-
else
|
206
|
-
raise
|
207
|
-
end
|
231
|
+
log.trace(e)
|
232
|
+
@time_parser_rfc5424_without_subseconds.parse(time_str)
|
208
233
|
end
|
209
234
|
end
|
210
235
|
|
211
236
|
if @keep_time_key
|
212
237
|
record['time'] = time_str
|
213
238
|
end
|
214
|
-
parse_plain(time, text, i + 1, record, RFC5424_CAPTURES, &block)
|
239
|
+
parse_plain(@regexp5424, time, text, i + 1, record, RFC5424_CAPTURES, &block)
|
215
240
|
end
|
216
241
|
|
217
242
|
# @param time [EventTime]
|
218
243
|
# @param idx [Integer] note: this argument is needed to avoid string creation
|
219
244
|
# @param record [Hash]
|
220
245
|
# @param capture_list [Array] for performance
|
221
|
-
def parse_plain(time, text, idx, record, capture_list, &block)
|
222
|
-
m =
|
246
|
+
def parse_plain(re, time, text, idx, record, capture_list, &block)
|
247
|
+
m = re.match(text, idx)
|
223
248
|
if m.nil?
|
224
249
|
yield nil, nil
|
225
250
|
return
|
@@ -244,8 +269,6 @@ module Fluent
|
|
244
269
|
yield time, record
|
245
270
|
end
|
246
271
|
|
247
|
-
SPLIT_CHAR = ' '.freeze
|
248
|
-
|
249
272
|
def parse_rfc3164(text, &block)
|
250
273
|
pri = nil
|
251
274
|
cursor = 0
|
@@ -264,20 +287,35 @@ module Fluent
|
|
264
287
|
end
|
265
288
|
end
|
266
289
|
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
290
|
+
if @skip_space_count_rfc3164
|
291
|
+
# header part
|
292
|
+
time_size = 15 # skip Mmm dd hh:mm:ss
|
293
|
+
time_end = text[cursor + time_size]
|
294
|
+
if time_end == SPLIT_CHAR
|
295
|
+
time_str = text.slice(cursor, time_size)
|
296
|
+
cursor += 16 # time + ' '
|
297
|
+
elsif time_end == '.'.freeze
|
298
|
+
# support subsecond time
|
299
|
+
i = text.index(SPLIT_CHAR, time_size)
|
300
|
+
time_str = text.slice(cursor, i - cursor)
|
301
|
+
cursor = i + 1
|
302
|
+
else
|
303
|
+
yield nil, nil
|
304
|
+
return
|
305
|
+
end
|
278
306
|
else
|
279
|
-
|
280
|
-
|
307
|
+
i = cursor - 1
|
308
|
+
sq = false
|
309
|
+
@space_count_rfc3164.times do
|
310
|
+
while text[i + 1] == SPLIT_CHAR
|
311
|
+
sq = true
|
312
|
+
i += 1
|
313
|
+
end
|
314
|
+
i = text.index(SPLIT_CHAR, i + 1)
|
315
|
+
end
|
316
|
+
|
317
|
+
time_str = sq ? text.slice(idx, i - cursor).squeeze(SPLIT_CHAR) : text.slice(cursor, i - cursor)
|
318
|
+
cursor = i + 1
|
281
319
|
end
|
282
320
|
|
283
321
|
i = text.index(SPLIT_CHAR, cursor)
|
@@ -325,7 +363,130 @@ module Fluent
|
|
325
363
|
msg.chomp!
|
326
364
|
record['message'] = msg
|
327
365
|
|
328
|
-
time = @
|
366
|
+
time = @time_parser_rfc3164.parse(time_str)
|
367
|
+
record['time'] = time_str if @keep_time_key
|
368
|
+
|
369
|
+
yield time, record
|
370
|
+
end
|
371
|
+
|
372
|
+
NILVALUE = '-'.freeze
|
373
|
+
|
374
|
+
def parse_rfc5424(text, &block)
|
375
|
+
pri = nil
|
376
|
+
cursor = 0
|
377
|
+
if @with_priority
|
378
|
+
if text.start_with?('<'.freeze)
|
379
|
+
i = text.index('>'.freeze, 1)
|
380
|
+
if i < 2
|
381
|
+
yield nil, nil
|
382
|
+
return
|
383
|
+
end
|
384
|
+
pri = text.slice(1, i - 1).to_i
|
385
|
+
i = text.index(SPLIT_CHAR, i)
|
386
|
+
cursor = i + 1
|
387
|
+
else
|
388
|
+
yield nil, nil
|
389
|
+
return
|
390
|
+
end
|
391
|
+
end
|
392
|
+
|
393
|
+
# timestamp part
|
394
|
+
if @skip_space_count_rfc5424
|
395
|
+
i = text.index(SPLIT_CHAR, cursor)
|
396
|
+
time_str = text.slice(cursor, i - cursor)
|
397
|
+
cursor = i + 1
|
398
|
+
else
|
399
|
+
i = cursor - 1
|
400
|
+
sq = false
|
401
|
+
@space_count_rfc5424.times do
|
402
|
+
while text[i + 1] == SPLIT_CHAR
|
403
|
+
sq = true
|
404
|
+
i += 1
|
405
|
+
end
|
406
|
+
i = text.index(SPLIT_CHAR, i + 1)
|
407
|
+
end
|
408
|
+
|
409
|
+
time_str = sq ? text.slice(idx, i - cursor).squeeze(SPLIT_CHAR) : text.slice(cursor, i - cursor)
|
410
|
+
cursor = i + 1
|
411
|
+
end
|
412
|
+
|
413
|
+
# Repeat same code for the performance
|
414
|
+
|
415
|
+
# host part
|
416
|
+
i = text.index(SPLIT_CHAR, cursor)
|
417
|
+
unless i
|
418
|
+
yield nil, nil
|
419
|
+
return
|
420
|
+
end
|
421
|
+
slice_size = i - cursor
|
422
|
+
host = text.slice(cursor, slice_size)
|
423
|
+
cursor += slice_size + 1
|
424
|
+
|
425
|
+
# ident part
|
426
|
+
i = text.index(SPLIT_CHAR, cursor)
|
427
|
+
unless i
|
428
|
+
yield nil, nil
|
429
|
+
return
|
430
|
+
end
|
431
|
+
slice_size = i - cursor
|
432
|
+
ident = text.slice(cursor, slice_size)
|
433
|
+
cursor += slice_size + 1
|
434
|
+
|
435
|
+
# pid part
|
436
|
+
i = text.index(SPLIT_CHAR, cursor)
|
437
|
+
unless i
|
438
|
+
yield nil, nil
|
439
|
+
return
|
440
|
+
end
|
441
|
+
slice_size = i - cursor
|
442
|
+
pid = text.slice(cursor, slice_size)
|
443
|
+
cursor += slice_size + 1
|
444
|
+
|
445
|
+
# msgid part
|
446
|
+
i = text.index(SPLIT_CHAR, cursor)
|
447
|
+
unless i
|
448
|
+
yield nil, nil
|
449
|
+
return
|
450
|
+
end
|
451
|
+
slice_size = i - cursor
|
452
|
+
msgid = text.slice(cursor, slice_size)
|
453
|
+
cursor += slice_size + 1
|
454
|
+
|
455
|
+
record = {'host' => host, 'ident' => ident, 'pid' => pid, 'msgid' => msgid}
|
456
|
+
record['pri'] = pri if pri
|
457
|
+
|
458
|
+
# extradata part
|
459
|
+
ed_start = text[cursor]
|
460
|
+
if ed_start == NILVALUE
|
461
|
+
record['extradata'] = NILVALUE
|
462
|
+
cursor += 1
|
463
|
+
else
|
464
|
+
start = cursor
|
465
|
+
i = text.index('] '.freeze, cursor)
|
466
|
+
extradata = if i
|
467
|
+
diff = i + 1 - start # calculate ']' position
|
468
|
+
cursor += diff
|
469
|
+
text.slice(start, diff)
|
470
|
+
else # No message part case
|
471
|
+
cursor = text.bytesize
|
472
|
+
text.slice(start, cursor)
|
473
|
+
end
|
474
|
+
extradata.tr!("\\".freeze, ''.freeze)
|
475
|
+
record['extradata'] = extradata
|
476
|
+
end
|
477
|
+
|
478
|
+
# message part
|
479
|
+
if cursor != text.bytesize
|
480
|
+
msg = text.slice(cursor + 1, text.bytesize)
|
481
|
+
msg.chomp!
|
482
|
+
record['message'] = msg
|
483
|
+
end
|
484
|
+
|
485
|
+
time = begin
|
486
|
+
@time_parser_rfc5424.parse(time_str)
|
487
|
+
rescue Fluent::TimeParser::TimeParseError => e
|
488
|
+
@time_parser_rfc5424_without_subseconds.parse(time_str)
|
489
|
+
end
|
329
490
|
record['time'] = time_str if @keep_time_key
|
330
491
|
|
331
492
|
yield time, record
|