fluentd 0.10.26 → 0.10.27
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.
- data/ChangeLog +6 -0
- data/VERSION +1 -1
- data/lib/fluent/output.rb +2 -2
- data/lib/fluent/plugin.rb +1 -1
- data/lib/fluent/plugin/buf_file.rb +30 -17
- data/lib/fluent/plugin/buf_memory.rb +5 -0
- data/lib/fluent/version.rb +1 -1
- metadata +2 -4
- data/lib/fluent/parser.rb.orig +0 -159
- data/lib/fluent/parser.rb.rej +0 -91
data/ChangeLog
CHANGED
@@ -1,4 +1,10 @@
|
|
1
1
|
|
2
|
+
Release 0.10.27 - 2012/10/11
|
3
|
+
|
4
|
+
* added BufferChunk#unique_id which is an unique identifier of a buffered chunk
|
5
|
+
* BufferedOutput: show 'temporarily failed' message
|
6
|
+
|
7
|
+
|
2
8
|
Release 0.10.26 - 2012/09/26
|
3
9
|
|
4
10
|
* added in_debug_agent plugin and fluent-debug command which enable you to
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.10.
|
1
|
+
0.10.27
|
data/lib/fluent/output.rb
CHANGED
@@ -333,7 +333,7 @@ class BufferedOutput < Output
|
|
333
333
|
end
|
334
334
|
|
335
335
|
if error_count < @retry_limit
|
336
|
-
$log.warn "failed to flush the buffer,
|
336
|
+
$log.warn "temporarily failed to flush the buffer, next retry will be at #{Time.at(@next_retry_time)}.", :error=>e.to_s, :instance=>object_id
|
337
337
|
$log.warn_backtrace e.backtrace
|
338
338
|
|
339
339
|
elsif @secondary
|
@@ -343,7 +343,7 @@ class BufferedOutput < Output
|
|
343
343
|
$log.warn_backtrace e.backtrace
|
344
344
|
retry # retry immediately
|
345
345
|
elsif error_count <= @retry_limit + @secondary_limit
|
346
|
-
$log.warn "failed to flush the buffer,
|
346
|
+
$log.warn "failed to flush the buffer, next retry will be with secondary output at #{Time.at(@next_retry_time)}.", :error=>e.to_s, :instance=>object_id
|
347
347
|
$log.warn_backtrace e.backtrace
|
348
348
|
else
|
349
349
|
$log.warn "failed to flush the buffer.", :error=>e.to_s, :instance=>object_id
|
data/lib/fluent/plugin.rb
CHANGED
@@ -19,14 +19,17 @@ module Fluent
|
|
19
19
|
|
20
20
|
|
21
21
|
class FileBufferChunk < BufferChunk
|
22
|
-
def initialize(key, path, mode="a+")
|
22
|
+
def initialize(key, path, unique_id, mode="a+")
|
23
23
|
super(key)
|
24
24
|
@path = path
|
25
|
+
@unique_id = unique_id
|
25
26
|
@file = File.open(@path, mode)
|
26
27
|
@file.sync = true
|
27
28
|
@size = @file.stat.size
|
28
29
|
end
|
29
30
|
|
31
|
+
attr_reader :unique_id
|
32
|
+
|
30
33
|
def <<(data)
|
31
34
|
@file.write(data)
|
32
35
|
@size += data.bytesize
|
@@ -103,8 +106,9 @@ class FileBuffer < BasicBuffer
|
|
103
106
|
|
104
107
|
def new_chunk(key)
|
105
108
|
encoded_key = encode_key(key)
|
106
|
-
path = make_path(encoded_key, "b")
|
107
|
-
|
109
|
+
path, tsuffix = make_path(encoded_key, "b")
|
110
|
+
unique_id = tsuffix_to_unique_id(tsuffix)
|
111
|
+
FileBufferChunk.new(key, path, unique_id)
|
108
112
|
end
|
109
113
|
|
110
114
|
def resume
|
@@ -116,28 +120,30 @@ class FileBuffer < BasicBuffer
|
|
116
120
|
if m = PATH_MATCH.match(match)
|
117
121
|
key = decode_key(m[1])
|
118
122
|
bq = m[2]
|
119
|
-
tsuffix = m[3]
|
123
|
+
tsuffix = m[3]
|
124
|
+
timestamp = m[3].to_i(16)
|
125
|
+
unique_id = tsuffix_to_unique_id(tsuffix)
|
120
126
|
|
121
127
|
if bq == 'b'
|
122
|
-
chunk = FileBufferChunk.new(key, path, "a+")
|
123
|
-
maps << [
|
128
|
+
chunk = FileBufferChunk.new(key, path, unique_id, "a+")
|
129
|
+
maps << [timestamp, chunk]
|
124
130
|
elsif bq == 'q'
|
125
|
-
chunk = FileBufferChunk.new(key, path, "r")
|
126
|
-
queues << [
|
131
|
+
chunk = FileBufferChunk.new(key, path, unique_id, "r")
|
132
|
+
queues << [timestamp, chunk]
|
127
133
|
end
|
128
134
|
end
|
129
135
|
}
|
130
136
|
|
131
137
|
map = {}
|
132
|
-
maps.sort_by {|(
|
133
|
-
|
134
|
-
}.each {|(
|
138
|
+
maps.sort_by {|(timestamp,chunk)|
|
139
|
+
timestamp
|
140
|
+
}.each {|(timestamp,chunk)|
|
135
141
|
map[chunk.key] = chunk
|
136
142
|
}
|
137
143
|
|
138
|
-
queue = queues.sort_by {|(
|
139
|
-
|
140
|
-
}.map {|(
|
144
|
+
queue = queues.sort_by {|(timestamp,chunk)|
|
145
|
+
timestamp
|
146
|
+
}.map {|(timestamp,chunk)|
|
141
147
|
chunk
|
142
148
|
}
|
143
149
|
|
@@ -150,7 +156,8 @@ class FileBuffer < BasicBuffer
|
|
150
156
|
|
151
157
|
m = PATH_MATCH.match(mp)
|
152
158
|
encoded_key = m ? m[1] : ""
|
153
|
-
|
159
|
+
tsuffix = m[3]
|
160
|
+
npath = "#{@buffer_path_prefix}#{encoded_key}.q#{tsuffix}#{@buffer_path_suffix}"
|
154
161
|
|
155
162
|
chunk.mv(npath)
|
156
163
|
end
|
@@ -166,8 +173,14 @@ class FileBuffer < BasicBuffer
|
|
166
173
|
|
167
174
|
def make_path(encoded_key, bq)
|
168
175
|
now = Time.now.utc
|
169
|
-
|
170
|
-
|
176
|
+
timestamp = ((now.to_i*1000*1000+now.usec) << 12 | rand(0xfff))
|
177
|
+
tsuffix = timestamp.to_s(16)
|
178
|
+
path = "#{@buffer_path_prefix}#{encoded_key}.#{bq}#{tsuffix}#{@buffer_path_suffix}"
|
179
|
+
return path, tsuffix
|
180
|
+
end
|
181
|
+
|
182
|
+
def tsuffix_to_unique_id(tsuffix)
|
183
|
+
tsuffix.scan(/../).map {|x| x.to_i(16) }.pack('C*') * 2
|
171
184
|
end
|
172
185
|
end
|
173
186
|
|
@@ -22,9 +22,14 @@ class MemoryBufferChunk < BufferChunk
|
|
22
22
|
def initialize(key, data='')
|
23
23
|
@data = data
|
24
24
|
@data.force_encoding('ASCII-8BIT')
|
25
|
+
now = Time.now.utc
|
26
|
+
u1 = ((now.to_i*1000*1000+now.usec) << 12 | rand(0xfff))
|
27
|
+
@unique_id = [u1 >> 32, u1 & u1 & 0xffffffff, rand(0xffffffff), rand(0xffffffff)].pack('NNNN')
|
25
28
|
super(key)
|
26
29
|
end
|
27
30
|
|
31
|
+
attr_reader :unique_id
|
32
|
+
|
28
33
|
def <<(data)
|
29
34
|
data.force_encoding('ASCII-8BIT')
|
30
35
|
@data << data
|
data/lib/fluent/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fluentd
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.10.
|
4
|
+
version: 0.10.27
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-10-11 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: msgpack
|
@@ -193,8 +193,6 @@ files:
|
|
193
193
|
- lib/fluent/mixin.rb
|
194
194
|
- lib/fluent/output.rb
|
195
195
|
- lib/fluent/parser.rb
|
196
|
-
- lib/fluent/parser.rb.orig
|
197
|
-
- lib/fluent/parser.rb.rej
|
198
196
|
- lib/fluent/plugin.rb
|
199
197
|
- lib/fluent/plugin/buf_file.rb
|
200
198
|
- lib/fluent/plugin/buf_memory.rb
|
data/lib/fluent/parser.rb.orig
DELETED
@@ -1,159 +0,0 @@
|
|
1
|
-
#
|
2
|
-
# Fluent
|
3
|
-
#
|
4
|
-
# Copyright (C) 2011 FURUHASHI Sadayuki
|
5
|
-
#
|
6
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
-
# you may not use this file except in compliance with the License.
|
8
|
-
# You may obtain a copy of the License at
|
9
|
-
#
|
10
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
-
#
|
12
|
-
# Unless required by applicable law or agreed to in writing, software
|
13
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
-
# See the License for the specific language governing permissions and
|
16
|
-
# limitations under the License.
|
17
|
-
#
|
18
|
-
module Fluent
|
19
|
-
|
20
|
-
|
21
|
-
class TextParser
|
22
|
-
class RegexpParser
|
23
|
-
include Configurable
|
24
|
-
|
25
|
-
config_param :time_format, :string, :default => nil
|
26
|
-
|
27
|
-
def initialize(regexp, conf={})
|
28
|
-
super()
|
29
|
-
@regexp = regexp
|
30
|
-
unless conf.empty?
|
31
|
-
configure(conf)
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
def call(text)
|
36
|
-
m = @regexp.match(text)
|
37
|
-
unless m
|
38
|
-
$log.debug "pattern not match: #{text}"
|
39
|
-
# TODO?
|
40
|
-
return nil, nil
|
41
|
-
end
|
42
|
-
|
43
|
-
time = nil
|
44
|
-
record = {}
|
45
|
-
|
46
|
-
m.names.each {|name|
|
47
|
-
if value = m[name]
|
48
|
-
case name
|
49
|
-
when "time"
|
50
|
-
if @time_format
|
51
|
-
time = Time.strptime(value, @time_format).to_i
|
52
|
-
else
|
53
|
-
time = Time.parse(value).to_i
|
54
|
-
end
|
55
|
-
else
|
56
|
-
record[name] = value
|
57
|
-
end
|
58
|
-
end
|
59
|
-
}
|
60
|
-
|
61
|
-
time ||= Engine.now
|
62
|
-
|
63
|
-
return time, record
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
class JSONParser
|
68
|
-
include Configurable
|
69
|
-
|
70
|
-
config_param :time_key, :string, :default => 'time'
|
71
|
-
config_param :time_format, :string, :default => nil
|
72
|
-
|
73
|
-
def call(text)
|
74
|
-
record = Yajl.load(text)
|
75
|
-
|
76
|
-
if value = record.delete(@time_key)
|
77
|
-
if @time_format
|
78
|
-
time = Time.strptime(value, @time_format).to_i
|
79
|
-
else
|
80
|
-
time = value.to_i
|
81
|
-
end
|
82
|
-
else
|
83
|
-
time = Engine.now
|
84
|
-
end
|
85
|
-
|
86
|
-
return time, record
|
87
|
-
rescue Yajl::ParseError
|
88
|
-
# TODO?
|
89
|
-
return nil, nil
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
TEMPLATES = {
|
94
|
-
'apache' => RegexpParser.new(/^(?<host>[^ ]*) [^ ]* (?<user>[^ ]*) \[(?<time>[^\]]*)\] "(?<method>\S+)(?: +(?<path>[^ ]*) +\S*)?" (?<code>[^ ]*) (?<size>[^ ]*)(?: "(?<referer>[^\"]*)" "(?<agent>[^\"]*)")?$/, {'time_format'=>"%d/%b/%Y:%H:%M:%S %z"}),
|
95
|
-
'syslog' => RegexpParser.new(/^(?<time>[^ ]*\s*[^ ]* [^ ]*) (?<host>[^ ]*) (?<ident>[a-zA-Z0-9_\/\.\-]*)(?:\[(?<pid>[0-9]+)\])?[^\:]*\: *(?<message>.*)$/, {'time_format'=>"%b %d %H:%M:%S"}),
|
96
|
-
'json' => JSONParser.new,
|
97
|
-
}
|
98
|
-
|
99
|
-
def self.register_template(name, regexp_or_proc, time_format=nil)
|
100
|
-
if regexp_or_proc.is_a?(Regexp)
|
101
|
-
regexp = regexp_or_proc
|
102
|
-
pr = RegexpParser.new(regexp, {'time_format'=>time_format})
|
103
|
-
else
|
104
|
-
pr = regexp_or_proc
|
105
|
-
end
|
106
|
-
|
107
|
-
TEMPLATES[name] = pr
|
108
|
-
end
|
109
|
-
|
110
|
-
def initialize
|
111
|
-
@parser = nil
|
112
|
-
end
|
113
|
-
|
114
|
-
def configure(conf, required=true)
|
115
|
-
format = conf['format']
|
116
|
-
|
117
|
-
if format == nil
|
118
|
-
if required
|
119
|
-
raise ConfigError, "'format' parameter is required"
|
120
|
-
else
|
121
|
-
return nil
|
122
|
-
end
|
123
|
-
end
|
124
|
-
|
125
|
-
if format[0] == ?/ && format[format.length-1] == ?/
|
126
|
-
# regexp
|
127
|
-
begin
|
128
|
-
regexp = Regexp.new(format[1..-2])
|
129
|
-
if regexp.named_captures.empty?
|
130
|
-
raise "No named captures"
|
131
|
-
end
|
132
|
-
rescue
|
133
|
-
raise ConfigError, "Invalid regexp '#{format[1..-2]}': #{$!}"
|
134
|
-
end
|
135
|
-
|
136
|
-
@parser = RegexpParser.new(regexp)
|
137
|
-
|
138
|
-
else
|
139
|
-
# built-in template
|
140
|
-
@parser = TEMPLATES[format]
|
141
|
-
unless @parser
|
142
|
-
raise ConfigError, "Unknown format template '#{format}'"
|
143
|
-
end
|
144
|
-
end
|
145
|
-
|
146
|
-
if @parser.respond_to?(:configure)
|
147
|
-
@parser.configure(conf)
|
148
|
-
end
|
149
|
-
|
150
|
-
return true
|
151
|
-
end
|
152
|
-
|
153
|
-
def parse(text)
|
154
|
-
return @parser.call(text)
|
155
|
-
end
|
156
|
-
end
|
157
|
-
|
158
|
-
|
159
|
-
end
|
data/lib/fluent/parser.rb.rej
DELETED
@@ -1,91 +0,0 @@
|
|
1
|
-
***************
|
2
|
-
*** 90,107 ****
|
3
|
-
end
|
4
|
-
end
|
5
|
-
|
6
|
-
TEMPLATES = {
|
7
|
-
- 'apache' => RegexpParser.new(/^(?<host>[^ ]*) [^ ]* (?<user>[^ ]*) \[(?<time>[^\]]*)\] "(?<method>\S+)(?: +(?<path>[^ ]*) +\S*)?" (?<code>[^ ]*) (?<size>[^ ]*)(?: "(?<referer>[^\"]*)" "(?<agent>[^\"]*)")?$/, {'time_format'=>"%d/%b/%Y:%H:%M:%S %z"}),
|
8
|
-
- 'syslog' => RegexpParser.new(/^(?<time>[^ ]*\s*[^ ]* [^ ]*) (?<host>[^ ]*) (?<ident>[a-zA-Z0-9_\/\.\-]*)(?:\[(?<pid>[0-9]+)\])?[^\:]*\: *(?<message>.*)$/, {'time_format'=>"%b %d %H:%M:%S"}),
|
9
|
-
- 'json' => JSONParser.new,
|
10
|
-
}
|
11
|
-
|
12
|
-
def self.register_template(name, regexp_or_proc, time_format=nil)
|
13
|
-
if regexp_or_proc.is_a?(Regexp)
|
14
|
-
- pr = regexp_or_proc
|
15
|
-
else
|
16
|
-
regexp = regexp_or_proc
|
17
|
-
- pr = RegexpParser.new(regexp, {'time_format'=>time_format})
|
18
|
-
end
|
19
|
-
|
20
|
-
TEMPLATES[name] = pr
|
21
|
-
--- 90,159 ----
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
+ class ApacheParser
|
26
|
-
+ include Configurable
|
27
|
-
+
|
28
|
-
+ REGEXP = /^(?<host>[^ ]*) [^ ]* (?<user>[^ ]*) \[(?<time>[^\]]*)\] "(?<method>\S+)(?: +(?<path>[^ ]*) +\S*)?" (?<code>[^ ]*) (?<size>[^ ]*)(?: "(?<referer>[^\"]*)" "(?<agent>[^\"]*)")?$/
|
29
|
-
+
|
30
|
-
+ def call(text)
|
31
|
-
+ m = REGEXP.match(text)
|
32
|
-
+ unless m
|
33
|
-
+ $log.debug "pattern not match: #{text}"
|
34
|
-
+ return nil, nil
|
35
|
-
+ end
|
36
|
-
+
|
37
|
-
+ host = m['host']
|
38
|
-
+ host = (host == '-') ? nil : host
|
39
|
-
+
|
40
|
-
+ user = m['user']
|
41
|
-
+ user = (user == '-') ? nil : user
|
42
|
-
+
|
43
|
-
+ time = m['time']
|
44
|
-
+ time = Time.strptime(time, "%d/%b/%Y:%H:%M:%S %z").to_i
|
45
|
-
+
|
46
|
-
+ method = m['method']
|
47
|
-
+ path = m['path']
|
48
|
-
+
|
49
|
-
+ code = m['code'].to_i
|
50
|
-
+ code = nil if code == 0
|
51
|
-
+
|
52
|
-
+ size = m['size']
|
53
|
-
+ size = (size == '-') ? nil : size.to_i
|
54
|
-
+
|
55
|
-
+ referer = m['referer']
|
56
|
-
+ referer = (referer == '-') ? nil : referer
|
57
|
-
+
|
58
|
-
+ agent = m['agent']
|
59
|
-
+ agent = (agent == '-') ? nil : agent
|
60
|
-
+
|
61
|
-
+ record = {
|
62
|
-
+ "host" => host,
|
63
|
-
+ "user" => user,
|
64
|
-
+ "method" => method,
|
65
|
-
+ "path" => path,
|
66
|
-
+ "code" => code,
|
67
|
-
+ "size" => size,
|
68
|
-
+ "referer" => referer,
|
69
|
-
+ "agent" => agent,
|
70
|
-
+ }
|
71
|
-
+
|
72
|
-
+ return time, record
|
73
|
-
+ end
|
74
|
-
+ end
|
75
|
-
+
|
76
|
-
TEMPLATES = {
|
77
|
-
+ 'apache' => Proc.new { RegexpParser.new(/^(?<host>[^ ]*) [^ ]* (?<user>[^ ]*) \[(?<time>[^\]]*)\] "(?<method>\S+)(?: +(?<path>[^ ]*) +\S*)?" (?<code>[^ ]*) (?<size>[^ ]*)(?: "(?<referer>[^\"]*)" "(?<agent>[^\"]*)")?$/, {'time_format'=>"%d/%b/%Y:%H:%M:%S %z"}) },
|
78
|
-
+ 'apache2' => Proc.new { ApacheParser.new },
|
79
|
-
+ 'syslog' => Proc.new { RegexpParser.new(/^(?<time>[^ ]*\s*[^ ]* [^ ]*) (?<host>[^ ]*) (?<ident>[a-zA-Z0-9_\/\.\-]*)(?:\[(?<pid>[0-9]+)\])?[^\:]*\: *(?<message>.*)$/, {'time_format'=>"%b %d %H:%M:%S"}) },
|
80
|
-
+ 'json' => Proc.new { JSONParser.new },
|
81
|
-
}
|
82
|
-
|
83
|
-
def self.register_template(name, regexp_or_proc, time_format=nil)
|
84
|
-
if regexp_or_proc.is_a?(Regexp)
|
85
|
-
+ pr = Proc.new { regexp_or_proc }
|
86
|
-
else
|
87
|
-
regexp = regexp_or_proc
|
88
|
-
+ pr = Proc.new { RegexpParser.new(regexp, {'time_format'=>time_format}) }
|
89
|
-
end
|
90
|
-
|
91
|
-
TEMPLATES[name] = pr
|