fluentd 0.10.35 → 0.10.36
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/.travis.yml +13 -0
- data/ChangeLog +9 -0
- data/fluentd.gemspec +1 -1
- data/lib/fluent/buffer.rb +210 -214
- data/lib/fluent/command/fluentd.rb +4 -0
- data/lib/fluent/config.rb +1 -0
- data/lib/fluent/engine.rb +10 -10
- data/lib/fluent/output.rb +404 -406
- data/lib/fluent/plugin/buf_file.rb +146 -151
- data/lib/fluent/plugin/buf_memory.rb +62 -67
- data/lib/fluent/plugin/in_debug_agent.rb +27 -31
- data/lib/fluent/plugin/in_exec.rb +86 -90
- data/lib/fluent/plugin/in_forward.rb +171 -171
- data/lib/fluent/plugin/in_gc_stat.rb +43 -47
- data/lib/fluent/plugin/in_http.rb +214 -216
- data/lib/fluent/plugin/in_monitor_agent.rb +212 -214
- data/lib/fluent/plugin/in_object_space.rb +75 -79
- data/lib/fluent/plugin/in_status.rb +44 -50
- data/lib/fluent/plugin/in_stream.rb +159 -160
- data/lib/fluent/plugin/in_syslog.rb +149 -153
- data/lib/fluent/plugin/in_tail.rb +382 -387
- data/lib/fluent/plugin/out_copy.rb +40 -45
- data/lib/fluent/plugin/out_exec.rb +52 -57
- data/lib/fluent/plugin/out_exec_filter.rb +327 -331
- data/lib/fluent/plugin/out_file.rb +78 -74
- data/lib/fluent/plugin/out_forward.rb +410 -414
- data/lib/fluent/plugin/out_null.rb +15 -19
- data/lib/fluent/plugin/out_roundrobin.rb +63 -68
- data/lib/fluent/plugin/out_stdout.rb +9 -14
- data/lib/fluent/plugin/out_stream.rb +83 -90
- data/lib/fluent/plugin/out_test.rb +42 -46
- data/lib/fluent/supervisor.rb +15 -0
- data/lib/fluent/version.rb +1 -1
- data/test/plugin/in_stream.rb +2 -0
- data/test/plugin/out_file.rb +19 -1
- metadata +6 -5
@@ -46,6 +46,10 @@ op.on('-c', '--config PATH', "config file path (default: #{Fluent::DEFAULT_CONFI
|
|
46
46
|
opts[:config_path] = s
|
47
47
|
}
|
48
48
|
|
49
|
+
op.on('--dry-run', "Check fluentd setup is correct or not", TrueClass) {|b|
|
50
|
+
opts[:dry_run] = b
|
51
|
+
}
|
52
|
+
|
49
53
|
op.on('-p', '--plugin DIR', "add plugin directory") {|s|
|
50
54
|
opts[:plugin_dirs] << s
|
51
55
|
}
|
data/lib/fluent/config.rb
CHANGED
data/lib/fluent/engine.rb
CHANGED
@@ -132,9 +132,9 @@ class EngineClass
|
|
132
132
|
@match_cache_keys << tag
|
133
133
|
end
|
134
134
|
target.emit(tag, es)
|
135
|
-
rescue
|
135
|
+
rescue => e
|
136
136
|
if @suppress_emit_error_log_interval == 0 || now > @next_emit_error_log_time
|
137
|
-
$log.warn "emit transaction failed ", :error
|
137
|
+
$log.warn "emit transaction failed ", :error_class=>e.class, :error=>e
|
138
138
|
$log.warn_backtrace
|
139
139
|
# $log.debug "current next_emit_error_log_time: #{Time.at(@next_emit_error_log_time)}"
|
140
140
|
@next_emit_error_log_time = Time.now.to_i + @suppress_emit_error_log_interval
|
@@ -175,8 +175,8 @@ class EngineClass
|
|
175
175
|
events.each {|tag,time,record|
|
176
176
|
begin
|
177
177
|
Engine.emit(tag, time, record)
|
178
|
-
rescue
|
179
|
-
$log.error "failed to emit fluentd's log event", :tag => tag, :event => record, :error =>
|
178
|
+
rescue => e
|
179
|
+
$log.error "failed to emit fluentd's log event", :tag => tag, :event => record, :error_class => e.class, :error => e
|
180
180
|
end
|
181
181
|
}
|
182
182
|
end
|
@@ -197,8 +197,8 @@ class EngineClass
|
|
197
197
|
# TODO attach async watch for thread pool
|
198
198
|
@default_loop.run
|
199
199
|
|
200
|
-
rescue
|
201
|
-
$log.error "unexpected error", :error
|
200
|
+
rescue => e
|
201
|
+
$log.error "unexpected error", :error_class=>e.class, :error=>e
|
202
202
|
$log.error_backtrace
|
203
203
|
ensure
|
204
204
|
$log.info "shutting down fluentd"
|
@@ -240,8 +240,8 @@ class EngineClass
|
|
240
240
|
Thread.new do
|
241
241
|
begin
|
242
242
|
s.shutdown
|
243
|
-
rescue
|
244
|
-
$log.warn "unexpected error while shutting down", :error
|
243
|
+
rescue => e
|
244
|
+
$log.warn "unexpected error while shutting down", :error_class=>e.class, :error=>e
|
245
245
|
$log.warn_backtrace
|
246
246
|
end
|
247
247
|
end
|
@@ -261,8 +261,8 @@ class EngineClass
|
|
261
261
|
elsif m.is_a?(MultiOutput)
|
262
262
|
flush_recursive(m.outputs)
|
263
263
|
end
|
264
|
-
rescue
|
265
|
-
$log.debug "error while force flushing", :error
|
264
|
+
rescue => e
|
265
|
+
$log.debug "error while force flushing", :error_class=>e.class, :error=>e
|
266
266
|
$log.debug_backtrace
|
267
267
|
end
|
268
268
|
}
|
data/lib/fluent/output.rb
CHANGED
@@ -16,529 +16,527 @@
|
|
16
16
|
# limitations under the License.
|
17
17
|
#
|
18
18
|
module Fluent
|
19
|
+
class OutputChain
|
20
|
+
def initialize(array, tag, es, chain=NullOutputChain.instance)
|
21
|
+
@array = array
|
22
|
+
@tag = tag
|
23
|
+
@es = es
|
24
|
+
@offset = 0
|
25
|
+
@chain = chain
|
26
|
+
end
|
19
27
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
@chain = chain
|
28
|
-
end
|
29
|
-
|
30
|
-
def next
|
31
|
-
if @array.length <= @offset
|
32
|
-
return @chain.next
|
28
|
+
def next
|
29
|
+
if @array.length <= @offset
|
30
|
+
return @chain.next
|
31
|
+
end
|
32
|
+
@offset += 1
|
33
|
+
result = @array[@offset-1].emit(@tag, @es, self)
|
34
|
+
result
|
33
35
|
end
|
34
|
-
@offset += 1
|
35
|
-
result = @array[@offset-1].emit(@tag, @es, self)
|
36
|
-
result
|
37
36
|
end
|
38
|
-
end
|
39
37
|
|
40
|
-
class NullOutputChain
|
41
|
-
|
42
|
-
|
38
|
+
class NullOutputChain
|
39
|
+
require 'singleton'
|
40
|
+
include Singleton
|
43
41
|
|
44
|
-
|
42
|
+
def next
|
43
|
+
end
|
45
44
|
end
|
46
|
-
end
|
47
45
|
|
48
46
|
|
49
|
-
class Output
|
50
|
-
|
51
|
-
|
47
|
+
class Output
|
48
|
+
include Configurable
|
49
|
+
include PluginId
|
52
50
|
|
53
|
-
|
54
|
-
|
55
|
-
|
51
|
+
def initialize
|
52
|
+
super
|
53
|
+
end
|
56
54
|
|
57
|
-
|
58
|
-
|
59
|
-
|
55
|
+
def configure(conf)
|
56
|
+
super
|
57
|
+
end
|
60
58
|
|
61
|
-
|
62
|
-
|
59
|
+
def start
|
60
|
+
end
|
63
61
|
|
64
|
-
|
65
|
-
|
62
|
+
def shutdown
|
63
|
+
end
|
66
64
|
|
67
|
-
|
68
|
-
|
65
|
+
#def emit(tag, es, chain)
|
66
|
+
#end
|
69
67
|
|
70
|
-
|
71
|
-
|
68
|
+
def secondary_init(primary)
|
69
|
+
if primary.class != self.class
|
72
70
|
$log.warn "type of secondary output should be same as primary output", :primary=>primary.class.to_s, :secondary=>self.class.to_s
|
71
|
+
end
|
73
72
|
end
|
74
73
|
end
|
75
|
-
end
|
76
74
|
|
77
75
|
|
78
|
-
class OutputThread
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
76
|
+
class OutputThread
|
77
|
+
def initialize(output)
|
78
|
+
@output = output
|
79
|
+
@finish = false
|
80
|
+
@next_time = Engine.now + 1.0
|
81
|
+
end
|
84
82
|
|
85
|
-
|
86
|
-
|
83
|
+
def configure(conf)
|
84
|
+
end
|
87
85
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
86
|
+
def start
|
87
|
+
@mutex = Mutex.new
|
88
|
+
@cond = ConditionVariable.new
|
89
|
+
@thread = Thread.new(&method(:run))
|
90
|
+
end
|
93
91
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
92
|
+
def shutdown
|
93
|
+
@finish = true
|
94
|
+
@mutex.synchronize {
|
95
|
+
@cond.signal
|
96
|
+
}
|
97
|
+
Thread.pass
|
98
|
+
@thread.join
|
99
|
+
end
|
102
100
|
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
101
|
+
def submit_flush
|
102
|
+
@mutex.synchronize {
|
103
|
+
@next_time = 0
|
104
|
+
@cond.signal
|
105
|
+
}
|
106
|
+
Thread.pass
|
107
|
+
end
|
110
108
|
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
109
|
+
private
|
110
|
+
def run
|
111
|
+
@mutex.lock
|
112
|
+
begin
|
113
|
+
until @finish
|
114
|
+
time = Engine.now
|
115
|
+
|
116
|
+
if @next_time <= time
|
117
|
+
@mutex.unlock
|
118
|
+
begin
|
119
|
+
@next_time = @output.try_flush
|
120
|
+
ensure
|
121
|
+
@mutex.lock
|
122
|
+
end
|
123
|
+
next_wait = @next_time - Engine.now
|
124
|
+
else
|
125
|
+
next_wait = @next_time - time
|
124
126
|
end
|
125
|
-
next_wait = @next_time - Engine.now
|
126
|
-
else
|
127
|
-
next_wait = @next_time - time
|
128
|
-
end
|
129
127
|
|
130
|
-
|
128
|
+
cond_wait(next_wait) if next_wait > 0
|
129
|
+
end
|
130
|
+
ensure
|
131
|
+
@mutex.unlock
|
131
132
|
end
|
133
|
+
rescue
|
134
|
+
$log.error "error on output thread", :error=>$!.to_s
|
135
|
+
$log.error_backtrace
|
136
|
+
raise
|
132
137
|
ensure
|
133
|
-
@mutex.
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
$log.error_backtrace
|
138
|
-
raise
|
139
|
-
ensure
|
140
|
-
@mutex.synchronize {
|
141
|
-
@output.before_shutdown
|
142
|
-
}
|
143
|
-
end
|
138
|
+
@mutex.synchronize {
|
139
|
+
@output.before_shutdown
|
140
|
+
}
|
141
|
+
end
|
144
142
|
|
145
|
-
|
146
|
-
|
143
|
+
def cond_wait(sec)
|
144
|
+
@cond.wait(@mutex, sec)
|
145
|
+
end
|
147
146
|
end
|
148
|
-
end
|
149
147
|
|
150
148
|
|
151
|
-
class BufferedOutput < Output
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
149
|
+
class BufferedOutput < Output
|
150
|
+
def initialize
|
151
|
+
super
|
152
|
+
@next_flush_time = 0
|
153
|
+
@last_retry_time = 0
|
154
|
+
@next_retry_time = 0
|
155
|
+
@error_history = []
|
156
|
+
@error_history.extend(MonitorMixin)
|
157
|
+
@secondary_limit = 8
|
158
|
+
@emit_count = 0
|
159
|
+
end
|
162
160
|
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
161
|
+
config_param :buffer_type, :string, :default => 'memory'
|
162
|
+
config_param :flush_interval, :time, :default => 60
|
163
|
+
config_param :retry_limit, :integer, :default => 17
|
164
|
+
config_param :retry_wait, :time, :default => 1.0
|
165
|
+
config_param :num_threads, :integer, :default => 1
|
166
|
+
config_param :queued_chunk_flush_interval, :time, :default => 1
|
169
167
|
|
170
|
-
|
171
|
-
|
168
|
+
def configure(conf)
|
169
|
+
super
|
172
170
|
|
173
|
-
|
174
|
-
|
171
|
+
@buffer = Plugin.new_buffer(@buffer_type)
|
172
|
+
@buffer.configure(conf)
|
175
173
|
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
174
|
+
if @buffer.respond_to?(:enable_parallel)
|
175
|
+
if @num_threads == 1
|
176
|
+
@buffer.enable_parallel(false)
|
177
|
+
else
|
178
|
+
@buffer.enable_parallel(true)
|
179
|
+
end
|
181
180
|
end
|
182
|
-
end
|
183
181
|
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
182
|
+
@writers = (1..@num_threads).map {
|
183
|
+
writer = OutputThread.new(self)
|
184
|
+
writer.configure(conf)
|
185
|
+
writer
|
186
|
+
}
|
189
187
|
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
188
|
+
if sconf = conf.elements.select {|e| e.name == 'secondary' }.first
|
189
|
+
type = sconf['type'] || conf['type']
|
190
|
+
@secondary = Plugin.new_output(type)
|
191
|
+
@secondary.configure(sconf)
|
194
192
|
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
193
|
+
if secondary_limit = conf['secondary_limit']
|
194
|
+
@secondary_limit = secondary_limit.to_i
|
195
|
+
if @secondary_limit < 0
|
196
|
+
raise ConfigError, "invalid parameter 'secondary_limit #{secondary_limit}'"
|
197
|
+
end
|
199
198
|
end
|
199
|
+
|
200
|
+
@secondary.secondary_init(self)
|
200
201
|
end
|
201
202
|
|
202
|
-
|
203
|
+
Status.register(self, "queue_size") { @buffer.queue_size }
|
204
|
+
Status.register(self, "emit_count") { @emit_count }
|
203
205
|
end
|
204
206
|
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
@buffer.start
|
212
|
-
@secondary.start if @secondary
|
213
|
-
@writers.each {|writer| writer.start }
|
214
|
-
end
|
207
|
+
def start
|
208
|
+
@next_flush_time = Engine.now + @flush_interval
|
209
|
+
@buffer.start
|
210
|
+
@secondary.start if @secondary
|
211
|
+
@writers.each {|writer| writer.start }
|
212
|
+
end
|
215
213
|
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
214
|
+
def shutdown
|
215
|
+
@writers.each {|writer| writer.shutdown }
|
216
|
+
@secondary.shutdown if @secondary
|
217
|
+
@buffer.shutdown
|
218
|
+
end
|
221
219
|
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
220
|
+
def emit(tag, es, chain, key="")
|
221
|
+
@emit_count += 1
|
222
|
+
data = format_stream(tag, es)
|
223
|
+
if @buffer.emit(key, data, chain)
|
224
|
+
submit_flush
|
225
|
+
end
|
227
226
|
end
|
228
|
-
end
|
229
227
|
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
228
|
+
def submit_flush
|
229
|
+
# TODO roundrobin?
|
230
|
+
@writers.first.submit_flush
|
231
|
+
end
|
234
232
|
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
233
|
+
def format_stream(tag, es)
|
234
|
+
out = ''
|
235
|
+
es.each {|time,record|
|
236
|
+
out << format(tag, time, record)
|
237
|
+
}
|
238
|
+
out
|
239
|
+
end
|
242
240
|
|
243
|
-
|
244
|
-
|
241
|
+
#def format(tag, time, record)
|
242
|
+
#end
|
245
243
|
|
246
|
-
|
247
|
-
|
244
|
+
#def write(chunk)
|
245
|
+
#end
|
248
246
|
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
247
|
+
def enqueue_buffer
|
248
|
+
@buffer.keys.each {|key|
|
249
|
+
@buffer.push(key)
|
250
|
+
}
|
251
|
+
end
|
254
252
|
|
255
|
-
|
256
|
-
|
253
|
+
def try_flush
|
254
|
+
time = Engine.now
|
257
255
|
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
256
|
+
empty = @buffer.queue_size == 0
|
257
|
+
if empty && @next_flush_time < (now = Engine.now)
|
258
|
+
@buffer.synchronize do
|
259
|
+
if @next_flush_time < now
|
260
|
+
enqueue_buffer
|
261
|
+
@next_flush_time = now + @flush_interval
|
262
|
+
empty = @buffer.queue_size == 0
|
263
|
+
end
|
265
264
|
end
|
266
265
|
end
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
end
|
271
|
-
|
272
|
-
begin
|
273
|
-
retrying = !@error_history.empty?
|
266
|
+
if empty
|
267
|
+
return time + 1 # TODO 1
|
268
|
+
end
|
274
269
|
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
270
|
+
begin
|
271
|
+
retrying = !@error_history.empty?
|
272
|
+
|
273
|
+
if retrying
|
274
|
+
@error_history.synchronize do
|
275
|
+
if retrying = !@error_history.empty? # re-check in synchronize
|
276
|
+
if @next_retry_time >= time
|
277
|
+
# allow retrying for only one thread
|
278
|
+
return time + 1 # TODO 1
|
279
|
+
end
|
280
|
+
# assume next retry failes and
|
281
|
+
# clear them if when it succeeds
|
282
|
+
@last_retry_time = time
|
283
|
+
@error_history << time
|
284
|
+
@next_retry_time += calc_retry_wait
|
281
285
|
end
|
282
|
-
# assume next retry failes and
|
283
|
-
# clear them if when it succeeds
|
284
|
-
@last_retry_time = time
|
285
|
-
@error_history << time
|
286
|
-
@next_retry_time += calc_retry_wait
|
287
286
|
end
|
288
287
|
end
|
289
|
-
end
|
290
288
|
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
289
|
+
if @secondary && @error_history.size > @retry_limit
|
290
|
+
has_next = flush_secondary(@secondary)
|
291
|
+
else
|
292
|
+
has_next = @buffer.pop(self)
|
293
|
+
end
|
296
294
|
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
295
|
+
# success
|
296
|
+
if retrying
|
297
|
+
@error_history.clear
|
298
|
+
# Note: don't notify to other threads to prevent
|
299
|
+
# burst to recovered server
|
300
|
+
$log.warn "retry succeeded.", :instance=>object_id
|
301
|
+
end
|
304
302
|
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
303
|
+
if has_next
|
304
|
+
return Engine.now + @queued_chunk_flush_interval
|
305
|
+
else
|
306
|
+
return time + 1 # TODO 1
|
307
|
+
end
|
310
308
|
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
309
|
+
rescue => e
|
310
|
+
if retrying
|
311
|
+
error_count = @error_history.size
|
312
|
+
else
|
313
|
+
# first error
|
314
|
+
error_count = 0
|
315
|
+
@error_history.synchronize do
|
316
|
+
if @error_history.empty?
|
317
|
+
@last_retry_time = time
|
318
|
+
@error_history << time
|
319
|
+
@next_retry_time = time + calc_retry_wait
|
320
|
+
end
|
322
321
|
end
|
323
322
|
end
|
324
|
-
end
|
325
323
|
|
326
|
-
|
327
|
-
|
328
|
-
$log.warn_backtrace e.backtrace
|
329
|
-
|
330
|
-
elsif @secondary
|
331
|
-
if error_count == @retry_limit
|
332
|
-
$log.warn "failed to flush the buffer.", :error_class=>e.class.to_s, :error=>e.to_s, :instance=>object_id
|
333
|
-
$log.warn "retry count exceededs limit. falling back to secondary output."
|
334
|
-
$log.warn_backtrace e.backtrace
|
335
|
-
retry # retry immediately
|
336
|
-
elsif error_count <= @retry_limit + @secondary_limit
|
337
|
-
$log.warn "failed to flush the buffer, next retry will be with secondary output.", :next_retry=>Time.at(@next_retry_time), :error_class=>e.class.to_s, :error=>e.to_s, :instance=>object_id
|
324
|
+
if error_count < @retry_limit
|
325
|
+
$log.warn "temporarily failed to flush the buffer.", :next_retry=>Time.at(@next_retry_time), :error_class=>e.class.to_s, :error=>e.to_s, :instance=>object_id
|
338
326
|
$log.warn_backtrace e.backtrace
|
327
|
+
|
328
|
+
elsif @secondary
|
329
|
+
if error_count == @retry_limit
|
330
|
+
$log.warn "failed to flush the buffer.", :error_class=>e.class.to_s, :error=>e.to_s, :instance=>object_id
|
331
|
+
$log.warn "retry count exceededs limit. falling back to secondary output."
|
332
|
+
$log.warn_backtrace e.backtrace
|
333
|
+
retry # retry immediately
|
334
|
+
elsif error_count <= @retry_limit + @secondary_limit
|
335
|
+
$log.warn "failed to flush the buffer, next retry will be with secondary output.", :next_retry=>Time.at(@next_retry_time), :error_class=>e.class.to_s, :error=>e.to_s, :instance=>object_id
|
336
|
+
$log.warn_backtrace e.backtrace
|
337
|
+
else
|
338
|
+
$log.warn "failed to flush the buffer.", :error_class=>e.class, :error=>e.to_s, :instance=>object_id
|
339
|
+
$log.warn "secondary retry count exceededs limit."
|
340
|
+
$log.warn_backtrace e.backtrace
|
341
|
+
write_abort
|
342
|
+
@error_history.clear
|
343
|
+
end
|
344
|
+
|
339
345
|
else
|
340
|
-
$log.warn "failed to flush the buffer.", :error_class=>e.class, :error=>e.to_s, :instance=>object_id
|
341
|
-
$log.warn "
|
346
|
+
$log.warn "failed to flush the buffer.", :error_class=>e.class.to_s, :error=>e.to_s, :instance=>object_id
|
347
|
+
$log.warn "retry count exceededs limit."
|
342
348
|
$log.warn_backtrace e.backtrace
|
343
349
|
write_abort
|
344
350
|
@error_history.clear
|
345
351
|
end
|
346
352
|
|
347
|
-
|
348
|
-
$log.warn "failed to flush the buffer.", :error_class=>e.class.to_s, :error=>e.to_s, :instance=>object_id
|
349
|
-
$log.warn "retry count exceededs limit."
|
350
|
-
$log.warn_backtrace e.backtrace
|
351
|
-
write_abort
|
352
|
-
@error_history.clear
|
353
|
+
return @next_retry_time
|
353
354
|
end
|
354
|
-
|
355
|
-
return @next_retry_time
|
356
355
|
end
|
357
|
-
end
|
358
356
|
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
end
|
363
|
-
|
364
|
-
def before_shutdown
|
365
|
-
begin
|
366
|
-
@buffer.before_shutdown(self)
|
367
|
-
rescue
|
368
|
-
$log.warn "before_shutdown failed", :error=>$!.to_s
|
369
|
-
$log.warn_backtrace
|
357
|
+
def force_flush
|
358
|
+
enqueue_buffer
|
359
|
+
submit_flush
|
370
360
|
end
|
371
|
-
end
|
372
361
|
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
end
|
381
|
-
wait + (rand * (wait / 4.0) - (wait / 8.0))
|
382
|
-
end
|
383
|
-
|
384
|
-
def write_abort
|
385
|
-
$log.error "throwing away old logs."
|
386
|
-
begin
|
387
|
-
@buffer.clear!
|
388
|
-
rescue
|
389
|
-
$log.error "unexpected error while aborting", :error=>$!.to_s
|
390
|
-
$log.error_backtrace
|
362
|
+
def before_shutdown
|
363
|
+
begin
|
364
|
+
@buffer.before_shutdown(self)
|
365
|
+
rescue
|
366
|
+
$log.warn "before_shutdown failed", :error=>$!.to_s
|
367
|
+
$log.warn_backtrace
|
368
|
+
end
|
391
369
|
end
|
392
|
-
end
|
393
|
-
|
394
|
-
def flush_secondary(secondary)
|
395
|
-
@buffer.pop(secondary)
|
396
|
-
end
|
397
|
-
end
|
398
370
|
|
371
|
+
def calc_retry_wait
|
372
|
+
# TODO retry pattern
|
373
|
+
wait = if @error_history.size <= @retry_limit
|
374
|
+
@retry_wait * (2 ** (@error_history.size-1))
|
375
|
+
else
|
376
|
+
# secondary retry
|
377
|
+
@retry_wait * (2 ** (@error_history.size-2-@retry_limit))
|
378
|
+
end
|
379
|
+
wait + (rand * (wait / 4.0) - (wait / 8.0))
|
380
|
+
end
|
399
381
|
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
382
|
+
def write_abort
|
383
|
+
$log.error "throwing away old logs."
|
384
|
+
begin
|
385
|
+
@buffer.clear!
|
386
|
+
rescue
|
387
|
+
$log.error "unexpected error while aborting", :error=>$!.to_s
|
388
|
+
$log.error_backtrace
|
389
|
+
end
|
390
|
+
end
|
404
391
|
|
405
|
-
|
406
|
-
|
407
|
-
key = tag
|
408
|
-
if @buffer.emit(key, data, chain)
|
409
|
-
submit_flush
|
392
|
+
def flush_secondary(secondary)
|
393
|
+
@buffer.pop(secondary)
|
410
394
|
end
|
411
395
|
end
|
412
396
|
|
413
|
-
module BufferedEventStreamMixin
|
414
|
-
include Enumerable
|
415
397
|
|
416
|
-
|
417
|
-
|
398
|
+
class ObjectBufferedOutput < BufferedOutput
|
399
|
+
def initialize
|
400
|
+
super
|
418
401
|
end
|
419
402
|
|
420
|
-
def
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
403
|
+
def emit(tag, es, chain)
|
404
|
+
@emit_count += 1
|
405
|
+
data = es.to_msgpack_stream
|
406
|
+
key = tag
|
407
|
+
if @buffer.emit(key, data, chain)
|
408
|
+
submit_flush
|
409
|
+
end
|
426
410
|
end
|
427
|
-
end
|
428
411
|
|
429
|
-
|
430
|
-
|
431
|
-
write_objects(chunk.key, chunk)
|
432
|
-
end
|
433
|
-
end
|
412
|
+
module BufferedEventStreamMixin
|
413
|
+
include Enumerable
|
434
414
|
|
415
|
+
def repeatable?
|
416
|
+
true
|
417
|
+
end
|
435
418
|
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
@localtime = true
|
440
|
-
#@ignore_old = false # TODO
|
441
|
-
end
|
419
|
+
def each(&block)
|
420
|
+
msgpack_each(&block)
|
421
|
+
end
|
442
422
|
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
config_set_default :flush_interval, nil
|
423
|
+
def to_msgpack_stream
|
424
|
+
read
|
425
|
+
end
|
426
|
+
end
|
448
427
|
|
449
|
-
|
428
|
+
def write(chunk)
|
429
|
+
chunk.extend(BufferedEventStreamMixin)
|
430
|
+
write_objects(chunk.key, chunk)
|
431
|
+
end
|
432
|
+
end
|
450
433
|
|
451
|
-
def configure(conf)
|
452
|
-
super
|
453
434
|
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
elsif conf['localtime']
|
435
|
+
class TimeSlicedOutput < BufferedOutput
|
436
|
+
def initialize
|
437
|
+
super
|
458
438
|
@localtime = true
|
439
|
+
#@ignore_old = false # TODO
|
459
440
|
end
|
460
441
|
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
}
|
469
|
-
end
|
442
|
+
config_param :time_slice_format, :string, :default => '%Y%m%d'
|
443
|
+
config_param :time_slice_wait, :time, :default => 10*60
|
444
|
+
config_set_default :buffer_type, 'file' # overwrite default buffer_type
|
445
|
+
config_set_default :buffer_chunk_limit, 256*1024*1024 # overwrite default buffer_chunk_limit
|
446
|
+
config_set_default :flush_interval, nil
|
447
|
+
|
448
|
+
attr_accessor :localtime
|
470
449
|
|
471
|
-
|
472
|
-
|
473
|
-
@before_key = nil
|
450
|
+
def configure(conf)
|
451
|
+
super
|
474
452
|
|
475
|
-
|
476
|
-
if conf['
|
477
|
-
|
453
|
+
# TODO timezone
|
454
|
+
if conf['utc']
|
455
|
+
@localtime = false
|
456
|
+
elsif conf['localtime']
|
457
|
+
@localtime = true
|
478
458
|
end
|
479
|
-
|
480
|
-
|
481
|
-
|
459
|
+
|
460
|
+
if @localtime
|
461
|
+
@time_slicer = Proc.new {|time|
|
462
|
+
Time.at(time).strftime(@time_slice_format)
|
463
|
+
}
|
464
|
+
else
|
465
|
+
@time_slicer = Proc.new {|time|
|
466
|
+
Time.at(time).utc.strftime(@time_slice_format)
|
482
467
|
}
|
483
468
|
end
|
484
469
|
|
485
|
-
|
486
|
-
@
|
487
|
-
@
|
488
|
-
|
489
|
-
|
490
|
-
|
470
|
+
@time_slice_cache_interval = time_slice_cache_interval
|
471
|
+
@before_tc = nil
|
472
|
+
@before_key = nil
|
473
|
+
|
474
|
+
if @flush_interval
|
475
|
+
if conf['time_slice_wait']
|
476
|
+
$log.warn "time_slice_wait is ignored if flush_interval is specified: #{conf}"
|
477
|
+
end
|
478
|
+
@enqueue_buffer_proc = Proc.new do
|
479
|
+
@buffer.keys.each {|key|
|
491
480
|
@buffer.push(key)
|
492
|
-
|
493
|
-
|
494
|
-
end
|
495
|
-
end
|
496
|
-
end
|
481
|
+
}
|
482
|
+
end
|
497
483
|
|
498
|
-
def emit(tag, es, chain)
|
499
|
-
es.each {|time,record|
|
500
|
-
tc = time / @time_slice_cache_interval
|
501
|
-
if @before_tc == tc
|
502
|
-
key = @before_key
|
503
484
|
else
|
504
|
-
@
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
485
|
+
@flush_interval = [60, @time_slice_cache_interval].min
|
486
|
+
@enqueue_buffer_proc = Proc.new do
|
487
|
+
nowslice = @time_slicer.call(Engine.now.to_i - @time_slice_wait)
|
488
|
+
@buffer.keys.each {|key|
|
489
|
+
if key < nowslice
|
490
|
+
@buffer.push(key)
|
491
|
+
end
|
492
|
+
}
|
493
|
+
end
|
511
494
|
end
|
512
|
-
|
513
|
-
end
|
495
|
+
end
|
514
496
|
|
515
|
-
|
516
|
-
|
517
|
-
|
497
|
+
def emit(tag, es, chain)
|
498
|
+
@emit_count += 1
|
499
|
+
es.each {|time,record|
|
500
|
+
tc = time / @time_slice_cache_interval
|
501
|
+
if @before_tc == tc
|
502
|
+
key = @before_key
|
503
|
+
else
|
504
|
+
@before_tc = tc
|
505
|
+
key = @time_slicer.call(time)
|
506
|
+
@before_key = key
|
507
|
+
end
|
508
|
+
data = format(tag, time, record)
|
509
|
+
if @buffer.emit(key, data, chain)
|
510
|
+
submit_flush
|
511
|
+
end
|
512
|
+
}
|
513
|
+
end
|
518
514
|
|
519
|
-
|
520
|
-
|
515
|
+
def enqueue_buffer
|
516
|
+
@enqueue_buffer_proc.call
|
517
|
+
end
|
521
518
|
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
519
|
+
#def format(tag, event)
|
520
|
+
#end
|
521
|
+
|
522
|
+
private
|
523
|
+
def time_slice_cache_interval
|
524
|
+
if @time_slicer.call(0) != @time_slicer.call(60-1)
|
525
|
+
return 1
|
526
|
+
elsif @time_slicer.call(0) != @time_slicer.call(60*60-1)
|
527
|
+
return 30
|
528
|
+
elsif @time_slicer.call(0) != @time_slicer.call(24*60*60-1)
|
529
|
+
return 60*30
|
530
|
+
else
|
531
|
+
return 24*60*30
|
532
|
+
end
|
532
533
|
end
|
533
534
|
end
|
534
|
-
end
|
535
|
-
|
536
|
-
|
537
|
-
class MultiOutput < Output
|
538
|
-
#def outputs
|
539
|
-
#end
|
540
|
-
end
|
541
535
|
|
542
536
|
|
537
|
+
class MultiOutput < Output
|
538
|
+
#def outputs
|
539
|
+
#end
|
540
|
+
end
|
543
541
|
end
|
544
542
|
|