fluentd 0.10.20 → 0.10.21
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 +10 -0
- data/VERSION +1 -1
- data/lib/fluent/log.rb +8 -0
- data/lib/fluent/output.rb +1 -1
- data/lib/fluent/parser.rb +107 -66
- data/lib/fluent/plugin/in_tail.rb +26 -15
- data/lib/fluent/plugin/out_stdout.rb +2 -4
- data/lib/fluent/supervisor.rb +9 -2
- data/lib/fluent/version.rb +1 -1
- metadata +20 -20
data/ChangeLog
CHANGED
@@ -1,4 +1,14 @@
|
|
1
1
|
|
2
|
+
Release 0.10.21 - 2012/05/01
|
3
|
+
|
4
|
+
* in_tail and TextParser support 'format json'
|
5
|
+
* in_tail and TextParser support 'time_key' and 'time_format' parameters for 'format json'
|
6
|
+
* in_tail: improved the file reader not to consume too much memory if the file is huge
|
7
|
+
* out_stdout: uses logger instead of STDOUT to show records even if Fluentd is daemonized
|
8
|
+
* Fixed the type of 'retry_wait' parameter of buffered output plugins from 'float' to 'time'
|
9
|
+
* Fixed owner of log files for log rotation to work properly with --user and --group options
|
10
|
+
|
11
|
+
|
2
12
|
Release 0.10.20 - 2012/04/27
|
3
13
|
|
4
14
|
* Fixed Config#to_s
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.10.
|
1
|
+
0.10.21
|
data/lib/fluent/log.rb
CHANGED
data/lib/fluent/output.rb
CHANGED
@@ -174,7 +174,7 @@ class BufferedOutput < Output
|
|
174
174
|
config_param :buffer_type, :string, :default => 'memory'
|
175
175
|
config_param :flush_interval, :time, :default => 60
|
176
176
|
config_param :retry_limit, :integer, :default => 17
|
177
|
-
config_param :retry_wait, :
|
177
|
+
config_param :retry_wait, :time, :default => 1.0
|
178
178
|
config_param :num_threads, :integer, :default => 1
|
179
179
|
|
180
180
|
def configure(conf)
|
data/lib/fluent/parser.rb
CHANGED
@@ -19,95 +19,136 @@ module Fluent
|
|
19
19
|
|
20
20
|
|
21
21
|
class TextParser
|
22
|
-
|
23
|
-
|
24
|
-
'syslog' => [/^(?<time>[^ ]*\s*[^ ]* [^ ]*) (?<host>[^ ]*) (?<ident>[a-zA-Z0-9_\/\.\-]*)(?:\[(?<pid>[0-9]+)\])?[^\:]*\: *(?<message>.*)$/, "%b %d %H:%M:%S"],
|
25
|
-
}
|
22
|
+
class RegexpParser
|
23
|
+
include Configurable
|
26
24
|
|
27
|
-
|
28
|
-
TEMPLATES[name] = [regexp, time_format]
|
29
|
-
end
|
25
|
+
config_param :time_format, :string
|
30
26
|
|
31
|
-
|
32
|
-
|
33
|
-
|
27
|
+
def initialize(regexp, conf={})
|
28
|
+
super()
|
29
|
+
@regexp = regexp
|
30
|
+
unless conf.empty?
|
31
|
+
configure(conf)
|
32
|
+
end
|
33
|
+
end
|
34
34
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
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
|
+
}
|
40
60
|
|
41
|
-
|
61
|
+
time ||= Engine.now
|
42
62
|
|
43
|
-
|
44
|
-
@regexp, @time_format = TextParser.get_template(name)
|
45
|
-
unless @regexp
|
46
|
-
raise ConfigError, "Unknown format template '#{name}'"
|
63
|
+
return time, record
|
47
64
|
end
|
48
65
|
end
|
49
66
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
@regexp = Regexp.new(format[1..-2])
|
56
|
-
if @regexp.named_captures.empty?
|
57
|
-
raise "No named captures"
|
58
|
-
end
|
59
|
-
rescue
|
60
|
-
raise ConfigError, "Invalid regexp '#{format[1..-2]}': #{$!}"
|
61
|
-
end
|
67
|
+
class JSONParser
|
68
|
+
include Configurable
|
69
|
+
|
70
|
+
config_param :time_key, :string, :default => 'time'
|
71
|
+
config_param :time_format, :string, :default => nil
|
62
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
|
63
82
|
else
|
64
|
-
|
65
|
-
use_template(format)
|
83
|
+
time = Engine.now
|
66
84
|
end
|
67
|
-
|
68
|
-
return
|
69
|
-
raise ConfigError, "'format' parameter is required"
|
85
|
+
|
86
|
+
return time, record
|
70
87
|
end
|
88
|
+
end
|
71
89
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
90
|
+
TEMPLATES = {
|
91
|
+
'apache' => RegexpParser.new(/^(?<host>[^ ]*) [^ ]* (?<user>[^ ]*) \[(?<time>[^\]]*)\] "(?<method>\S+)(?: +(?<path>[^ ]*) +\S*)?" (?<code>[^ ]*) (?<size>[^ ]*)(?: "(?<referer>[^\"]*)" "(?<agent>[^\"]*)")?$/, {'time_format'=>"%d/%b/%Y:%H:%M:%S %z"}),
|
92
|
+
'syslog' => RegexpParser.new(/^(?<time>[^ ]*\s*[^ ]* [^ ]*) (?<host>[^ ]*) (?<ident>[a-zA-Z0-9_\/\.\-]*)(?:\[(?<pid>[0-9]+)\])?[^\:]*\: *(?<message>.*)$/, {'time_format'=>"%b %d %H:%M:%S"}),
|
93
|
+
'json' => JSONParser.new,
|
94
|
+
}
|
95
|
+
|
96
|
+
def self.register_template(name, regexp_or_proc, time_format=nil)
|
97
|
+
if regexp_or_proc.is_a?(Regexp)
|
98
|
+
pr = regexp_or_proc
|
99
|
+
else
|
100
|
+
regexp = regexp_or_proc
|
101
|
+
pr = RegexpParser.new(regexp, {'time_format'=>time_format})
|
77
102
|
end
|
78
103
|
|
79
|
-
|
104
|
+
TEMPLATES[name] = pr
|
80
105
|
end
|
81
106
|
|
82
|
-
def
|
83
|
-
|
84
|
-
|
85
|
-
$log.debug "pattern not match: #{text}"
|
86
|
-
# TODO?
|
87
|
-
return nil, nil
|
88
|
-
end
|
107
|
+
def initialize
|
108
|
+
@parser = nil
|
109
|
+
end
|
89
110
|
|
90
|
-
|
91
|
-
|
111
|
+
def configure(conf, required=true)
|
112
|
+
format = conf['format']
|
92
113
|
|
93
|
-
|
94
|
-
if
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
114
|
+
if format == nil
|
115
|
+
if required
|
116
|
+
raise ConfigError, "'format' parameter is required"
|
117
|
+
else
|
118
|
+
return nil
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
if format[0] == ?/ && format[format.length-1] == ?/
|
123
|
+
# regexp
|
124
|
+
begin
|
125
|
+
regexp = Regexp.new(format[1..-2])
|
126
|
+
if regexp.named_captures.empty?
|
127
|
+
raise "No named captures"
|
104
128
|
end
|
129
|
+
rescue
|
130
|
+
raise ConfigError, "Invalid regexp '#{format[1..-2]}': #{$!}"
|
131
|
+
end
|
132
|
+
|
133
|
+
@parser = RegexpParser.new(regexp)
|
134
|
+
|
135
|
+
else
|
136
|
+
# built-in template
|
137
|
+
@parser = TEMPLATES[format]
|
138
|
+
unless @parser
|
139
|
+
raise ConfigError, "Unknown format template '#{format}'"
|
105
140
|
end
|
106
|
-
|
141
|
+
end
|
142
|
+
|
143
|
+
if @parser.respond_to?(:configure)
|
144
|
+
@parser.configure(conf)
|
145
|
+
end
|
107
146
|
|
108
|
-
|
147
|
+
return true
|
148
|
+
end
|
109
149
|
|
110
|
-
|
150
|
+
def parse(text)
|
151
|
+
return @parser.call(text)
|
111
152
|
end
|
112
153
|
end
|
113
154
|
|
@@ -255,6 +255,8 @@ class TailInput < Input
|
|
255
255
|
end
|
256
256
|
end
|
257
257
|
|
258
|
+
MAX_LINES_AT_ONCE = 1000
|
259
|
+
|
258
260
|
class IOHandler
|
259
261
|
def initialize(io, pe, &receive_lines)
|
260
262
|
$log.info "following tail of #{io.path}"
|
@@ -268,27 +270,36 @@ class TailInput < Input
|
|
268
270
|
attr_reader :io
|
269
271
|
|
270
272
|
def on_notify
|
271
|
-
|
273
|
+
begin
|
274
|
+
lines = []
|
275
|
+
read_more = false
|
272
276
|
|
273
|
-
while true
|
274
277
|
begin
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
278
|
+
while true
|
279
|
+
if @buffer.empty?
|
280
|
+
@io.read_nonblock(2048, @buffer)
|
281
|
+
else
|
282
|
+
@buffer << @io.read_nonblock(2048, @iobuf)
|
283
|
+
end
|
284
|
+
while line = @buffer.slice!(/.*?\n/m)
|
285
|
+
lines << line
|
286
|
+
end
|
287
|
+
if lines.size >= MAX_LINES_AT_ONCE
|
288
|
+
# not to use too much memory in case the file is very large
|
289
|
+
read_more = true
|
290
|
+
break
|
291
|
+
end
|
282
292
|
end
|
283
293
|
rescue EOFError
|
284
|
-
break
|
285
294
|
end
|
286
|
-
end
|
287
295
|
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
296
|
+
unless lines.empty?
|
297
|
+
@receive_lines.call(lines)
|
298
|
+
@pe.update_pos(@io.pos - @buffer.bytesize)
|
299
|
+
end
|
300
|
+
|
301
|
+
end while read_more
|
302
|
+
|
292
303
|
rescue
|
293
304
|
$log.error $!.to_s
|
294
305
|
$log.error_backtrace
|
@@ -21,13 +21,11 @@ module Fluent
|
|
21
21
|
class StdoutOutput < Output
|
22
22
|
Plugin.register_output('stdout', self)
|
23
23
|
|
24
|
-
config_param :autoflush, :bool, :default => false
|
25
|
-
|
26
24
|
def emit(tag, es, chain)
|
27
25
|
es.each {|time,record|
|
28
|
-
|
26
|
+
$log.write "#{Time.at(time).localtime} #{tag}: #{Yajl.dump(record)}\n"
|
29
27
|
}
|
30
|
-
|
28
|
+
$log.flush
|
31
29
|
|
32
30
|
chain.next
|
33
31
|
end
|
data/lib/fluent/supervisor.rb
CHANGED
@@ -20,14 +20,21 @@ module Fluent
|
|
20
20
|
|
21
21
|
class Supervisor
|
22
22
|
class LoggerInitializer
|
23
|
-
def initialize(path, level)
|
23
|
+
def initialize(path, level, chuser, chgroup)
|
24
24
|
@path = path
|
25
25
|
@level = level
|
26
|
+
@chuser = chuser
|
27
|
+
@chgroup = chgroup
|
26
28
|
end
|
27
29
|
|
28
30
|
def init
|
29
31
|
if @path && @path != "-"
|
30
32
|
@io = File.open(@path, "a")
|
33
|
+
if @chuser || @chgroup
|
34
|
+
chuid = @chuser ? `id -u #{@chuser}`.to_i : nil
|
35
|
+
chgid = @chgroup ? `id -g #{@chgroup}`.to_i : nil
|
36
|
+
File.chown(chuid, chgid, @path)
|
37
|
+
end
|
31
38
|
else
|
32
39
|
@io = STDOUT
|
33
40
|
end
|
@@ -61,7 +68,7 @@ class Supervisor
|
|
61
68
|
@plugin_dirs = opt[:plugin_dirs]
|
62
69
|
@inline_config = opt[:inline_config]
|
63
70
|
|
64
|
-
@log = LoggerInitializer.new(@log_path, @log_level)
|
71
|
+
@log = LoggerInitializer.new(@log_path, @log_level, @chuser, @chgroup)
|
65
72
|
@finished = false
|
66
73
|
@main_pid = nil
|
67
74
|
end
|
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.21
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-05-01 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: msgpack
|
16
|
-
requirement: &
|
16
|
+
requirement: &70301065884780 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ~>
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: 0.4.4
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70301065884780
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: json
|
27
|
-
requirement: &
|
27
|
+
requirement: &70301065884240 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: 1.4.3
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70301065884240
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: yajl-ruby
|
38
|
-
requirement: &
|
38
|
+
requirement: &70301065883720 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ~>
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: '1.0'
|
44
44
|
type: :runtime
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *70301065883720
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: cool.io
|
49
|
-
requirement: &
|
49
|
+
requirement: &70301065883120 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ~>
|
@@ -54,10 +54,10 @@ dependencies:
|
|
54
54
|
version: 1.1.0
|
55
55
|
type: :runtime
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *70301065883120
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: http_parser.rb
|
60
|
-
requirement: &
|
60
|
+
requirement: &70301065880180 !ruby/object:Gem::Requirement
|
61
61
|
none: false
|
62
62
|
requirements:
|
63
63
|
- - ~>
|
@@ -65,10 +65,10 @@ dependencies:
|
|
65
65
|
version: 0.5.1
|
66
66
|
type: :runtime
|
67
67
|
prerelease: false
|
68
|
-
version_requirements: *
|
68
|
+
version_requirements: *70301065880180
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: rake
|
71
|
-
requirement: &
|
71
|
+
requirement: &70301065879580 !ruby/object:Gem::Requirement
|
72
72
|
none: false
|
73
73
|
requirements:
|
74
74
|
- - ! '>='
|
@@ -76,10 +76,10 @@ dependencies:
|
|
76
76
|
version: 0.9.2
|
77
77
|
type: :development
|
78
78
|
prerelease: false
|
79
|
-
version_requirements: *
|
79
|
+
version_requirements: *70301065879580
|
80
80
|
- !ruby/object:Gem::Dependency
|
81
81
|
name: rr
|
82
|
-
requirement: &
|
82
|
+
requirement: &70301065878920 !ruby/object:Gem::Requirement
|
83
83
|
none: false
|
84
84
|
requirements:
|
85
85
|
- - ! '>='
|
@@ -87,10 +87,10 @@ dependencies:
|
|
87
87
|
version: 1.0.0
|
88
88
|
type: :development
|
89
89
|
prerelease: false
|
90
|
-
version_requirements: *
|
90
|
+
version_requirements: *70301065878920
|
91
91
|
- !ruby/object:Gem::Dependency
|
92
92
|
name: timecop
|
93
|
-
requirement: &
|
93
|
+
requirement: &70301065878300 !ruby/object:Gem::Requirement
|
94
94
|
none: false
|
95
95
|
requirements:
|
96
96
|
- - ! '>='
|
@@ -98,10 +98,10 @@ dependencies:
|
|
98
98
|
version: 0.3.0
|
99
99
|
type: :development
|
100
100
|
prerelease: false
|
101
|
-
version_requirements: *
|
101
|
+
version_requirements: *70301065878300
|
102
102
|
- !ruby/object:Gem::Dependency
|
103
103
|
name: jeweler
|
104
|
-
requirement: &
|
104
|
+
requirement: &70301065877720 !ruby/object:Gem::Requirement
|
105
105
|
none: false
|
106
106
|
requirements:
|
107
107
|
- - ! '>='
|
@@ -109,7 +109,7 @@ dependencies:
|
|
109
109
|
version: 1.0.0
|
110
110
|
type: :development
|
111
111
|
prerelease: false
|
112
|
-
version_requirements: *
|
112
|
+
version_requirements: *70301065877720
|
113
113
|
description:
|
114
114
|
email: frsyuki@gmail.com
|
115
115
|
executables:
|