Skip to content

Commit 50c773b

Browse files
authored
Merge pull request #3484 from cosmo0920/buffer-metrics-statistics
buffer: Use metrics plugin mechanism on a plugin base class
2 parents b28f7d7 + 206ca69 commit 50c773b

File tree

4 files changed

+109
-28
lines changed

4 files changed

+109
-28
lines changed

lib/fluent/plugin/buffer.rb

Lines changed: 84 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
require 'fluent/plugin/base'
1818
require 'fluent/plugin/owned_by_mixin'
19+
require 'fluent/plugin_id'
20+
require 'fluent/plugin_helper'
1921
require 'fluent/unique_id'
2022
require 'fluent/ext_monitor_require'
2123

@@ -24,7 +26,9 @@ module Plugin
2426
class Buffer < Base
2527
include OwnedByMixin
2628
include UniqueId::Mixin
29+
include PluginId
2730
include MonitorMixin
31+
include PluginHelper::Mixin # for metrics
2832

2933
class BufferError < StandardError; end
3034
class BufferOverflowError < BufferError; end
@@ -39,6 +43,8 @@ class BufferChunkOverflowError < BufferError; end # A record size is larger than
3943

4044
configured_in :buffer
4145

46+
helpers_internal :metrics
47+
4248
# TODO: system total buffer limit size in bytes by SystemConfig
4349

4450
config_param :chunk_limit_size, :size, default: DEFAULT_CHUNK_LIMIT_SIZE
@@ -153,8 +159,11 @@ def hash
153159
end
154160
end
155161

162+
# for metrics
163+
attr_reader :stage_size_metrics, :stage_length_metrics, :queue_size_metrics, :queue_length_metrics
164+
attr_reader :available_buffer_space_ratios_metrics, :total_queued_size_metrics
165+
attr_reader :newest_timekey_metrics, :oldest_timekey_metrics
156166
# for tests
157-
attr_accessor :stage_size, :queue_size
158167
attr_reader :stage, :queue, :dequeued, :queued_num
159168

160169
def initialize
@@ -171,12 +180,35 @@ def initialize
171180
@queued_num = {} # metadata => int (number of queued chunks)
172181
@dequeued_num = {} # metadata => int (number of dequeued chunks)
173182

174-
@stage_size = @queue_size = 0
183+
@stage_length_metrics = nil
184+
@stage_size_metrics = nil
185+
@queue_length_metrics = nil
186+
@queue_size_metrics = nil
187+
@available_buffer_space_ratios_metrics = nil
188+
@total_queued_size_metrics = nil
189+
@newest_timekey_metrics = nil
190+
@oldest_timekey_metrics = nil
175191
@timekeys = Hash.new(0)
176192
@enable_update_timekeys = false
177193
@mutex = Mutex.new
178194
end
179195

196+
def stage_size
197+
@stage_size_metrics.get
198+
end
199+
200+
def stage_size=(value)
201+
@stage_size_metrics.set(value)
202+
end
203+
204+
def queue_size
205+
@queue_size_metrics.get
206+
end
207+
208+
def queue_size=(value)
209+
@queue_size_metrics.set(value)
210+
end
211+
180212
def persistent?
181213
false
182214
end
@@ -187,6 +219,28 @@ def configure(conf)
187219
unless @queue_limit_length.nil?
188220
@total_limit_size = @chunk_limit_size * @queue_limit_length
189221
end
222+
@stage_length_metrics = metrics_create(namespace: "fluentd", subsystem: "buffer", name: "stage_length",
223+
help_text: 'Length of stage buffers', prefer_gauge: true)
224+
@stage_length_metrics.set(0)
225+
@stage_size_metrics = metrics_create(namespace: "fluentd", subsystem: "buffer", name: "stage_byte_size",
226+
help_text: 'Total size of stage buffers', prefer_gauge: true)
227+
@stage_size_metrics.set(0) # Ensure zero.
228+
@queue_length_metrics = metrics_create(namespace: "fluentd", subsystem: "buffer", name: "queue_length",
229+
help_text: 'Length of queue buffers', prefer_gauge: true)
230+
@queue_length_metrics.set(0)
231+
@queue_size_metrics = metrics_create(namespace: "fluentd", subsystem: "buffer", name: "queue_byte_size",
232+
help_text: 'Total size of queue buffers', prefer_gauge: true)
233+
@queue_size_metrics.set(0) # Ensure zero.
234+
@available_buffer_space_ratios_metrics = metrics_create(namespace: "fluentd", subsystem: "buffer", name: "available_buffer_space_ratios",
235+
help_text: 'Ratio of available space in buffer', prefer_gauge: true)
236+
@available_buffer_space_ratios_metrics.set(100) # Default is 100%.
237+
@total_queued_size_metrics = metrics_create(namespace: "fluentd", subsystem: "buffer", name: "total_queued_size",
238+
help_text: 'Total size of stage and queue buffers', prefer_gauge: true)
239+
@total_queued_size_metrics.set(0)
240+
@newest_timekey_metrics = metrics_create(namespace: "fluentd", subsystem: "buffer", name: "newest_timekey",
241+
help_text: 'Newest timekey in buffer', prefer_gauge: true)
242+
@oldest_timekey_metrics = metrics_create(namespace: "fluentd", subsystem: "buffer", name: "oldest_timekey",
243+
help_text: 'Oldest timekey in buffer', prefer_gauge: true)
190244
end
191245

192246
def enable_update_timekeys
@@ -198,15 +252,15 @@ def start
198252

199253
@stage, @queue = resume
200254
@stage.each_pair do |metadata, chunk|
201-
@stage_size += chunk.bytesize
255+
@stage_size_metrics.add(chunk.bytesize)
202256
end
203257
@queue.each do |chunk|
204258
@queued_num[chunk.metadata] ||= 0
205259
@queued_num[chunk.metadata] += 1
206-
@queue_size += chunk.bytesize
260+
@queue_size_metrics.add(chunk.bytesize)
207261
end
208262
update_timekeys
209-
log.debug "buffer started", instance: self.object_id, stage_size: @stage_size, queue_size: @queue_size
263+
log.debug "buffer started", instance: self.object_id, stage_size: @stage_size_metrics.get, queue_size: @queue_size_metrics.get
210264
end
211265

212266
def close
@@ -228,17 +282,19 @@ def close
228282
def terminate
229283
super
230284
@dequeued = @stage = @queue = @queued_num = nil
231-
@stage_size = @queue_size = 0
285+
@stage_length_metrics = @stage_size_metrics = @queue_length_metrics = @queue_size_metrics = nil
286+
@available_buffer_space_ratios_metrics = @total_queued_size_metrics = nil
287+
@newest_timekey_metrics = @oldest_timekey_metrics = nil
232288
@timekeys.clear
233289
end
234290

235291
def storable?
236-
@total_limit_size > @stage_size + @queue_size
292+
@total_limit_size > @stage_size_metrics.get + @queue_size_metrics.get
237293
end
238294

239295
## TODO: for back pressure feature
240296
# def used?(ratio)
241-
# @total_limit_size * ratio > @stage_size + @queue_size
297+
# @total_limit_size * ratio > @stage_size_metrics.get + @queue_size_metrics.get
242298
# end
243299

244300
def resume
@@ -344,7 +400,7 @@ def write(metadata_and_data, format: nil, size: nil, enqueue: false)
344400
#
345401
staged_bytesizes_by_chunk.each do |chunk, bytesize|
346402
chunk.synchronize do
347-
synchronize { @stage_size += bytesize }
403+
synchronize { @stage_size_metrics.add(bytesize) }
348404
log.on_trace { log.trace { "chunk #{chunk.path} size_added: #{bytesize} new_size: #{chunk.bytesize}" } }
349405
end
350406
end
@@ -361,7 +417,7 @@ def write(metadata_and_data, format: nil, size: nil, enqueue: false)
361417
u.metadata.seq = 0
362418
synchronize {
363419
@stage[m] = u.staged!
364-
@stage_size += u.bytesize
420+
@stage_size_metrics.add(u.bytesize)
365421
}
366422
end
367423
end
@@ -428,8 +484,8 @@ def enqueue_chunk(metadata)
428484
chunk.enqueued!
429485
end
430486
bytesize = chunk.bytesize
431-
@stage_size -= bytesize
432-
@queue_size += bytesize
487+
@stage_size_metrics.sub(bytesize)
488+
@queue_size_metrics.add(bytesize)
433489
end
434490
end
435491
nil
@@ -446,7 +502,7 @@ def enqueue_unstaged_chunk(chunk)
446502
@queued_num[metadata] = @queued_num.fetch(metadata, 0) + 1
447503
chunk.enqueued!
448504
end
449-
@queue_size += chunk.bytesize
505+
@queue_size_metrics.add(chunk.bytesize)
450506
end
451507
end
452508

@@ -531,7 +587,7 @@ def purge_chunk(chunk_id)
531587
begin
532588
bytesize = chunk.bytesize
533589
chunk.purge
534-
@queue_size -= bytesize
590+
@queue_size_metrics.sub(bytesize)
535591
rescue => e
536592
log.error "failed to purge buffer chunk", chunk_id: dump_unique_id_hex(chunk_id), error_class: e.class, error: e
537593
log.error_backtrace
@@ -562,7 +618,7 @@ def clear_queue!
562618
log.error_backtrace
563619
end
564620
end
565-
@queue_size = 0
621+
@queue_size_metrics.set(0)
566622
end
567623
end
568624

@@ -765,23 +821,29 @@ def write_step_by_step(metadata, data, format, splits_count, &block)
765821
]
766822

767823
def statistics
768-
stage_size, queue_size = @stage_size, @queue_size
824+
stage_size, queue_size = @stage_size_metrics.get, @queue_size_metrics.get
769825
buffer_space = 1.0 - ((stage_size + queue_size * 1.0) / @total_limit_size)
826+
@stage_length_metrics.set(@stage.size)
827+
@queue_length_metrics.set(@queue.size)
828+
@available_buffer_space_ratios_metrics.set(buffer_space * 100)
829+
@total_queued_size_metrics.set(stage_size + queue_size)
770830
stats = {
771-
'stage_length' => @stage.size,
831+
'stage_length' => @stage_length_metrics.get,
772832
'stage_byte_size' => stage_size,
773-
'queue_length' => @queue.size,
833+
'queue_length' => @queue_length_metrics.get,
774834
'queue_byte_size' => queue_size,
775-
'available_buffer_space_ratios' => (buffer_space * 100).round(1),
776-
'total_queued_size' => stage_size + queue_size,
835+
'available_buffer_space_ratios' => @available_buffer_space_ratios_metrics.get.round(1),
836+
'total_queued_size' => @total_queued_size_metrics.get,
777837
}
778838

779839
tkeys = timekeys
780840
if (m = tkeys.min)
781-
stats['oldest_timekey'] = m
841+
@oldest_timekey_metrics.set(m)
842+
stats['oldest_timekey'] = @oldest_timekey_metrics.get
782843
end
783844
if (m = tkeys.max)
784-
stats['newest_timekey'] = m
845+
@newest_timekey_metrics.set(m)
846+
stats['newest_timekey'] = @newest_timekey_metrics.get
785847
end
786848

787849
{ 'buffer' => stats }

lib/fluent/plugin_helper/metrics.rb

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,11 @@ def configure(conf)
4242
@plugin_type_or_id = if self.plugin_id_configured?
4343
self.plugin_id
4444
else
45-
"#{conf["@type"] || conf["type"]}.#{self.plugin_id}"
45+
if type = (conf["@type"] || conf["type"])
46+
"#{type}.#{self.plugin_id}"
47+
else
48+
"#{self.class.to_s.split("::").last.downcase}.#{self.plugin_id}"
49+
end
4650
end
4751
end
4852

test/plugin/test_buffer.rb

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -238,8 +238,14 @@ def create_chunk_es(metadata, es)
238238
assert_nil @p.queue
239239
assert_nil @p.dequeued
240240
assert_nil @p.queued_num
241-
assert_equal 0, @p.stage_size
242-
assert_equal 0, @p.queue_size
241+
assert_nil @p.stage_length_metrics
242+
assert_nil @p.stage_size_metrics
243+
assert_nil @p.queue_length_metrics
244+
assert_nil @p.queue_size_metrics
245+
assert_nil @p.available_buffer_space_ratios_metrics
246+
assert_nil @p.total_queued_size_metrics
247+
assert_nil @p.newest_timekey_metrics
248+
assert_nil @p.oldest_timekey_metrics
243249
assert_equal [], @p.timekeys
244250
end
245251

test/plugin_helper/test_metrics.rb

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,26 +39,35 @@ def configure(conf)
3939

4040
test 'creates metrics instances' do
4141
d = Dummy.new
42-
d.configure(config_element())
4342
i = d.metrics_create(namespace: "fluentd_test", subsystem: "unit-test", name: "metrics1", help_text: "metrics testing")
43+
d.configure(config_element())
44+
assert do
45+
d.instance_variable_get(:@plugin_type_or_id).include?("dummy.object")
46+
end
4447
assert{ i.is_a?(Fluent::Plugin::LocalMetrics) }
4548
assert_true i.has_methods_for_counter
4649
assert_false i.has_methods_for_gauge
4750

4851
d = Dummy.new
49-
d.configure(config_element())
5052
i = d.metrics_create(namespace: "fluentd_test", subsystem: "unit-test", name: "metrics2", help_text: "metrics testing", prefer_gauge: true)
53+
d.configure(config_element())
54+
assert do
55+
d.instance_variable_get(:@plugin_type_or_id).include?("dummy.object")
56+
end
5157
assert{ i.is_a?(Fluent::Plugin::LocalMetrics) }
5258
assert_false i.has_methods_for_counter
5359
assert_true i.has_methods_for_gauge
5460
end
5561

5662
test 'calls lifecycle methods for all plugin instances via owner plugin' do
5763
@d = d = Dummy.new
58-
d.configure(config_element())
5964
i1 = d.metrics_create(namespace: "fluentd_test", subsystem: "unit-test", name: "metrics1", help_text: "metrics testing")
6065
i2 = d.metrics_create(namespace: "fluentd_test", subsystem: "unit-test", name: "metrics2", help_text: "metrics testing", prefer_gauge: true)
6166
i3 = d.metrics_create(namespace: "fluentd_test", subsystem: "unit-test", name: "metrics3", help_text: "metrics testing")
67+
d.configure(config_element())
68+
assert do
69+
d.instance_variable_get(:@plugin_type_or_id).include?("dummy.object")
70+
end
6271
d.start
6372

6473
assert i1.started?

0 commit comments

Comments
 (0)