fluentd 0.10.36 → 0.10.37
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 +7 -0
- data/.travis.yml +2 -2
- data/ChangeLog +8 -0
- data/lib/fluent/config.rb +285 -289
- data/lib/fluent/config_dsl.rb +74 -0
- data/lib/fluent/engine.rb +250 -247
- data/lib/fluent/env.rb +5 -5
- data/lib/fluent/event.rb +120 -124
- data/lib/fluent/input.rb +13 -17
- data/lib/fluent/load.rb +1 -0
- data/lib/fluent/log.rb +238 -242
- data/lib/fluent/match.rb +132 -137
- data/lib/fluent/mixin.rb +151 -155
- data/lib/fluent/parser.rb +201 -205
- data/lib/fluent/plugin.rb +117 -121
- data/lib/fluent/plugin/buf_file.rb +8 -0
- data/lib/fluent/plugin/exec_util.rb +49 -0
- data/lib/fluent/plugin/in_exec.rb +44 -30
- data/lib/fluent/plugin/in_forward.rb +4 -2
- data/lib/fluent/plugin/in_http.rb +5 -0
- data/lib/fluent/plugin/in_stream.rb +5 -2
- data/lib/fluent/plugin/out_exec_filter.rb +4 -47
- data/lib/fluent/plugin/out_stdout.rb +21 -1
- data/lib/fluent/process.rb +358 -362
- data/lib/fluent/status.rb +25 -30
- data/lib/fluent/supervisor.rb +277 -281
- data/lib/fluent/test/base.rb +35 -39
- data/lib/fluent/test/input_test.rb +68 -63
- data/lib/fluent/test/output_test.rb +98 -101
- data/lib/fluent/version.rb +1 -1
- data/test/configdsl.rb +77 -0
- data/test/plugin/in_exec.rb +73 -13
- data/test/plugin/in_gc_stat.rb +1 -1
- data/test/plugin/in_object_space.rb +2 -2
- data/test/plugin/out_stdout.rb +45 -2
- data/test/scripts/exec_script.rb +26 -0
- metadata +31 -46
data/lib/fluent/parser.rb
CHANGED
@@ -16,282 +16,278 @@
|
|
16
16
|
# limitations under the License.
|
17
17
|
#
|
18
18
|
module Fluent
|
19
|
+
class TextParser
|
20
|
+
class RegexpParser
|
21
|
+
include Configurable
|
19
22
|
|
23
|
+
config_param :time_format, :string, :default => nil
|
20
24
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
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.warn "pattern not match: #{text.inspect}"
|
39
|
-
return nil, nil
|
25
|
+
def initialize(regexp, conf={})
|
26
|
+
super()
|
27
|
+
@regexp = regexp
|
28
|
+
unless conf.empty?
|
29
|
+
configure(conf)
|
30
|
+
end
|
40
31
|
end
|
41
32
|
|
42
|
-
|
43
|
-
|
33
|
+
def call(text)
|
34
|
+
m = @regexp.match(text)
|
35
|
+
unless m
|
36
|
+
$log.warn "pattern not match: #{text.inspect}"
|
37
|
+
return nil, nil
|
38
|
+
end
|
44
39
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
40
|
+
time = nil
|
41
|
+
record = {}
|
42
|
+
|
43
|
+
m.names.each {|name|
|
44
|
+
if value = m[name]
|
45
|
+
case name
|
46
|
+
when "time"
|
47
|
+
if @time_format
|
48
|
+
time = Time.strptime(value, @time_format).to_i
|
49
|
+
else
|
50
|
+
time = Time.parse(value).to_i
|
51
|
+
end
|
51
52
|
else
|
52
|
-
|
53
|
+
record[name] = value
|
53
54
|
end
|
54
|
-
else
|
55
|
-
record[name] = value
|
56
55
|
end
|
57
|
-
|
58
|
-
}
|
56
|
+
}
|
59
57
|
|
60
|
-
|
58
|
+
time ||= Engine.now
|
61
59
|
|
62
|
-
|
60
|
+
return time, record
|
61
|
+
end
|
63
62
|
end
|
64
|
-
end
|
65
63
|
|
66
|
-
|
67
|
-
|
64
|
+
class JSONParser
|
65
|
+
include Configurable
|
68
66
|
|
69
|
-
|
70
|
-
|
67
|
+
config_param :time_key, :string, :default => 'time'
|
68
|
+
config_param :time_format, :string, :default => nil
|
71
69
|
|
72
|
-
|
73
|
-
|
70
|
+
def call(text)
|
71
|
+
record = Yajl.load(text)
|
74
72
|
|
75
|
-
|
76
|
-
|
77
|
-
|
73
|
+
if value = record.delete(@time_key)
|
74
|
+
if @time_format
|
75
|
+
time = Time.strptime(value, @time_format).to_i
|
76
|
+
else
|
77
|
+
time = value.to_i
|
78
|
+
end
|
78
79
|
else
|
79
|
-
time =
|
80
|
+
time = Engine.now
|
80
81
|
end
|
81
|
-
else
|
82
|
-
time = Engine.now
|
83
|
-
end
|
84
82
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
83
|
+
return time, record
|
84
|
+
rescue Yajl::ParseError
|
85
|
+
$log.warn "pattern not match: #{text.inspect}: #{$!}"
|
86
|
+
return nil, nil
|
87
|
+
end
|
89
88
|
end
|
90
|
-
end
|
91
89
|
|
92
|
-
|
93
|
-
|
90
|
+
class ValuesParser
|
91
|
+
include Configurable
|
94
92
|
|
95
|
-
|
96
|
-
|
97
|
-
|
93
|
+
config_param :keys, :string
|
94
|
+
config_param :time_key, :string, :default => nil
|
95
|
+
config_param :time_format, :string, :default => nil
|
98
96
|
|
99
|
-
|
100
|
-
|
97
|
+
def configure(conf)
|
98
|
+
super
|
101
99
|
|
102
|
-
|
100
|
+
@keys = @keys.split(",")
|
103
101
|
|
104
|
-
|
105
|
-
|
106
|
-
|
102
|
+
if @time_key && !@keys.include?(@time_key)
|
103
|
+
raise ConfigError, "time_key (#{@time_key.inspect}) is not included in keys (#{@keys.inspect})"
|
104
|
+
end
|
107
105
|
|
108
|
-
|
109
|
-
|
106
|
+
if @time_format && !@time_key
|
107
|
+
raise ConfigError, "time_format parameter is ignored because time_key parameter is not set. at #{conf.inspect}"
|
108
|
+
end
|
110
109
|
end
|
111
|
-
end
|
112
110
|
|
113
|
-
|
114
|
-
|
111
|
+
def values_map(values)
|
112
|
+
record = Hash[keys.zip(values)]
|
115
113
|
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
114
|
+
if @time_key
|
115
|
+
value = record.delete(@time_key)
|
116
|
+
if @time_format
|
117
|
+
time = Time.strptime(value, @time_format).to_i
|
118
|
+
else
|
119
|
+
time = Time.parse(value).to_i
|
120
|
+
end
|
120
121
|
else
|
121
|
-
time =
|
122
|
+
time = Engine.now
|
122
123
|
end
|
123
|
-
else
|
124
|
-
time = Engine.now
|
125
|
-
end
|
126
124
|
|
127
|
-
|
125
|
+
return time, record
|
126
|
+
end
|
128
127
|
end
|
129
|
-
end
|
130
128
|
|
131
|
-
|
132
|
-
|
129
|
+
class TSVParser < ValuesParser
|
130
|
+
config_param :delimiter, :string, :default => "\t"
|
133
131
|
|
134
|
-
|
135
|
-
|
132
|
+
def call(text)
|
133
|
+
return values_map(text.split(@delimiter))
|
134
|
+
end
|
136
135
|
end
|
137
|
-
end
|
138
136
|
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
137
|
+
class LabeledTSVParser < ValuesParser
|
138
|
+
config_param :delimiter, :string, :default => "\t"
|
139
|
+
config_param :label_delimiter, :string, :default => ":"
|
140
|
+
config_param :time_key, :string, :default => "time"
|
143
141
|
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
142
|
+
def configure(conf)
|
143
|
+
conf['keys'] = conf['time_key'] || 'time'
|
144
|
+
super(conf)
|
145
|
+
end
|
148
146
|
|
149
|
-
|
150
|
-
|
151
|
-
|
147
|
+
def call(text)
|
148
|
+
@keys = []
|
149
|
+
values = []
|
152
150
|
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
151
|
+
text.split(delimiter).each do |pair|
|
152
|
+
key, value = pair.split(label_delimiter, 2)
|
153
|
+
@keys.push(key)
|
154
|
+
values.push(value)
|
155
|
+
end
|
158
156
|
|
159
|
-
|
157
|
+
return values_map(values)
|
158
|
+
end
|
160
159
|
end
|
161
|
-
end
|
162
160
|
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
161
|
+
class CSVParser < ValuesParser
|
162
|
+
def initialize
|
163
|
+
super
|
164
|
+
require 'csv'
|
165
|
+
end
|
168
166
|
|
169
|
-
|
170
|
-
|
167
|
+
def call(text)
|
168
|
+
return values_map(CSV.parse_line(text))
|
169
|
+
end
|
171
170
|
end
|
172
|
-
end
|
173
171
|
|
174
|
-
|
175
|
-
|
172
|
+
class ApacheParser
|
173
|
+
include Configurable
|
176
174
|
|
177
|
-
|
175
|
+
REGEXP = /^(?<host>[^ ]*) [^ ]* (?<user>[^ ]*) \[(?<time>[^\]]*)\] "(?<method>\S+)(?: +(?<path>[^ ]*) +\S*)?" (?<code>[^ ]*) (?<size>[^ ]*)(?: "(?<referer>[^\"]*)" "(?<agent>[^\"]*)")?$/
|
178
176
|
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
177
|
+
def call(text)
|
178
|
+
m = REGEXP.match(text)
|
179
|
+
unless m
|
180
|
+
$log.warn "pattern not match: #{text.inspect}"
|
181
|
+
return nil, nil
|
182
|
+
end
|
185
183
|
|
186
|
-
|
187
|
-
|
184
|
+
host = m['host']
|
185
|
+
host = (host == '-') ? nil : host
|
188
186
|
|
189
|
-
|
190
|
-
|
187
|
+
user = m['user']
|
188
|
+
user = (user == '-') ? nil : user
|
191
189
|
|
192
|
-
|
193
|
-
|
190
|
+
time = m['time']
|
191
|
+
time = Time.strptime(time, "%d/%b/%Y:%H:%M:%S %z").to_i
|
194
192
|
|
195
|
-
|
196
|
-
|
193
|
+
method = m['method']
|
194
|
+
path = m['path']
|
197
195
|
|
198
|
-
|
199
|
-
|
196
|
+
code = m['code'].to_i
|
197
|
+
code = nil if code == 0
|
200
198
|
|
201
|
-
|
202
|
-
|
199
|
+
size = m['size']
|
200
|
+
size = (size == '-') ? nil : size.to_i
|
203
201
|
|
204
|
-
|
205
|
-
|
202
|
+
referer = m['referer']
|
203
|
+
referer = (referer == '-') ? nil : referer
|
206
204
|
|
207
|
-
|
208
|
-
|
205
|
+
agent = m['agent']
|
206
|
+
agent = (agent == '-') ? nil : agent
|
209
207
|
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
208
|
+
record = {
|
209
|
+
"host" => host,
|
210
|
+
"user" => user,
|
211
|
+
"method" => method,
|
212
|
+
"path" => path,
|
213
|
+
"code" => code,
|
214
|
+
"size" => size,
|
215
|
+
"referer" => referer,
|
216
|
+
"agent" => agent,
|
217
|
+
}
|
220
218
|
|
221
|
-
|
219
|
+
return time, record
|
220
|
+
end
|
222
221
|
end
|
223
|
-
end
|
224
222
|
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
223
|
+
TEMPLATE_FACTORIES = {
|
224
|
+
'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"}) },
|
225
|
+
'apache2' => Proc.new { ApacheParser.new },
|
226
|
+
'syslog' => Proc.new { RegexpParser.new(/^(?<time>[^ ]*\s*[^ ]* [^ ]*) (?<host>[^ ]*) (?<ident>[a-zA-Z0-9_\/\.\-]*)(?:\[(?<pid>[0-9]+)\])?[^\:]*\: *(?<message>.*)$/, {'time_format'=>"%b %d %H:%M:%S"}) },
|
227
|
+
'json' => Proc.new { JSONParser.new },
|
228
|
+
'tsv' => Proc.new { TSVParser.new },
|
229
|
+
'ltsv' => Proc.new { LabeledTSVParser.new },
|
230
|
+
'csv' => Proc.new { CSVParser.new },
|
231
|
+
'nginx' => Proc.new { RegexpParser.new(/^(?<remote>[^ ]*) (?<host>[^ ]*) (?<user>[^ ]*) \[(?<time>[^\]]*)\] "(?<method>\S+)(?: +(?<path>[^\"]*) +\S*)?" (?<code>[^ ]*) (?<size>[^ ]*)(?: "(?<referer>[^\"]*)" "(?<agent>[^\"]*)")?$/, {'time_format'=>"%d/%b/%Y:%H:%M:%S %z"}) },
|
232
|
+
}
|
233
|
+
|
234
|
+
def self.register_template(name, regexp_or_proc, time_format=nil)
|
235
|
+
if regexp_or_proc.is_a?(Regexp)
|
236
|
+
regexp = regexp_or_proc
|
237
|
+
factory = Proc.new { RegexpParser.new(regexp, {'time_format'=>time_format}) }
|
238
|
+
else
|
239
|
+
factory = regexp_or_proc
|
240
|
+
end
|
243
241
|
|
244
|
-
|
245
|
-
|
242
|
+
TEMPLATE_FACTORIES[name] = factory
|
243
|
+
end
|
246
244
|
|
247
|
-
|
248
|
-
|
249
|
-
|
245
|
+
def initialize
|
246
|
+
@parser = nil
|
247
|
+
end
|
250
248
|
|
251
|
-
|
252
|
-
|
249
|
+
def configure(conf, required=true)
|
250
|
+
format = conf['format']
|
253
251
|
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
252
|
+
if format == nil
|
253
|
+
if required
|
254
|
+
raise ConfigError, "'format' parameter is required"
|
255
|
+
else
|
256
|
+
return nil
|
257
|
+
end
|
259
258
|
end
|
260
|
-
end
|
261
259
|
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
260
|
+
if format[0] == ?/ && format[format.length-1] == ?/
|
261
|
+
# regexp
|
262
|
+
begin
|
263
|
+
regexp = Regexp.new(format[1..-2])
|
264
|
+
if regexp.named_captures.empty?
|
265
|
+
raise "No named captures"
|
266
|
+
end
|
267
|
+
rescue
|
268
|
+
raise ConfigError, "Invalid regexp '#{format[1..-2]}': #{$!}"
|
268
269
|
end
|
269
|
-
rescue
|
270
|
-
raise ConfigError, "Invalid regexp '#{format[1..-2]}': #{$!}"
|
271
|
-
end
|
272
270
|
|
273
|
-
|
271
|
+
@parser = RegexpParser.new(regexp)
|
272
|
+
|
273
|
+
else
|
274
|
+
# built-in template
|
275
|
+
factory = TEMPLATE_FACTORIES[format]
|
276
|
+
unless factory
|
277
|
+
raise ConfigError, "Unknown format template '#{format}'"
|
278
|
+
end
|
279
|
+
@parser = factory.call
|
280
|
+
end
|
274
281
|
|
275
|
-
|
276
|
-
|
277
|
-
factory = TEMPLATE_FACTORIES[format]
|
278
|
-
unless factory
|
279
|
-
raise ConfigError, "Unknown format template '#{format}'"
|
282
|
+
if @parser.respond_to?(:configure)
|
283
|
+
@parser.configure(conf)
|
280
284
|
end
|
281
|
-
@parser = factory.call
|
282
|
-
end
|
283
285
|
|
284
|
-
|
285
|
-
@parser.configure(conf)
|
286
|
+
return true
|
286
287
|
end
|
287
288
|
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
def parse(text)
|
292
|
-
return @parser.call(text)
|
289
|
+
def parse(text)
|
290
|
+
return @parser.call(text)
|
291
|
+
end
|
293
292
|
end
|
294
293
|
end
|
295
|
-
|
296
|
-
|
297
|
-
end
|