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 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.26
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, retrying.", :error=>e.to_s, :instance=>object_id
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, retrying secondary.", :error=>e.to_s, :instance=>object_id
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
@@ -120,7 +120,7 @@ class PluginClass
120
120
  }.compact
121
121
  unless files.empty?
122
122
  # prefer newer version
123
- require files.sort.last
123
+ require File.expand_path(files.sort.last)
124
124
  return
125
125
  end
126
126
 
@@ -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
- FileBufferChunk.new(key, path)
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].to_i(16)
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 << [tsuffix, chunk]
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 << [tsuffix, chunk]
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 {|(tsuffix,chunk)|
133
- tsuffix
134
- }.each {|(tsuffix,chunk)|
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 {|(tsuffix,chunk)|
139
- tsuffix
140
- }.map {|(tsuffix,chunk)|
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
- npath = make_path(encoded_key, "q")
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
- tsuffix = ((now.to_i*1000*1000+now.usec) << 12 | rand(0xfff)).to_s(16)
170
- "#{@buffer_path_prefix}#{encoded_key}.#{bq}#{tsuffix}#{@buffer_path_suffix}"
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
@@ -1,5 +1,5 @@
1
1
  module Fluent
2
2
 
3
- VERSION = '0.10.26'
3
+ VERSION = '0.10.27'
4
4
 
5
5
  end
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.26
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-09-26 00:00:00.000000000 Z
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
@@ -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
@@ -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