fluent-plugin-prometheus 1.7.0 → 1.7.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 95008f0031db355e5a5bbf4ed21f8f9f0a07839480e40bf44e974046b04f562f
4
- data.tar.gz: 994a30da7b1ff0ad77f12e5b47d9218a2deb97effc31a36fa83175077cc6ed69
3
+ metadata.gz: 32e8a803f1394e445d273b41ec9bde5f238f4193956c431a0866c93b2a2a0426
4
+ data.tar.gz: 281024e977c3aee02030691ffb7cd86361b759dae259bb8103934db7e195f751
5
5
  SHA512:
6
- metadata.gz: e0dc26e78e242e51e0fa87257b85c68af2ae32c11f7dabd1b4245e3ad7e1b1a7182b1b8432578f98af8a5a22d14c14e664285a238f74ebc40df0c0461026f323
7
- data.tar.gz: fb31a79f327ce31e8203fa1fa9a5b9d9166410d71f9b62d4fd5411d246c768dfde5c9c076ff6e72f0d9f5bd4c7657c9180eb91ba4ee383729856da0704930404
6
+ metadata.gz: 6e784fec1bca9a2ea8f725b5970ed5f08069b6d457ae11b23e1c22017d188046cab4718573c67a94b230acff1583ac12d6378a372a3713f311470c2b9a5818e3
7
+ data.tar.gz: 805673a26e562f4607cefbbf256c12e3557317e115a88096357ddde30f6d5f8dea67835e580100c6bfb5aa9abfb542d0f5b0bff9374b6d4b48046034fea5527a
data/README.md CHANGED
@@ -369,7 +369,13 @@ Reserved placeholders are:
369
369
  - `${worker_id}`: fluent worker id
370
370
  - `${tag}`: tag name
371
371
  - only available in Prometheus output/filter plugin
372
-
372
+ - `${tag_parts[N]}` refers to the Nth part of the tag.
373
+ - only available in Prometheus output/filter plugin
374
+ - `${tag_prefix[N]}` refers to the [0..N] part of the tag.
375
+ - only available in Prometheus output/filter plugin
376
+ - `${tag_suffix[N]}` refers to the [`tagsize`-1-N..] part of the tag.
377
+ - where `tagsize` is the size of tag which is splitted with `.` (when tag is `1.2.3`, then `tagsize` is 3)
378
+ - only available in Prometheus output/filter plugin
373
379
 
374
380
  ### top-level labels and labels inside metric
375
381
 
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |spec|
2
2
  spec.name = "fluent-plugin-prometheus"
3
- spec.version = "1.7.0"
3
+ spec.version = "1.7.1"
4
4
  spec.authors = ["Masahiro Sano"]
5
5
  spec.email = ["sabottenda@gmail.com"]
6
6
  spec.summary = %q{A fluent plugin that collects metrics and exposes for Prometheus.}
@@ -24,14 +24,14 @@ module Fluent::Plugin
24
24
  def configure(conf)
25
25
  super
26
26
  hostname = Socket.gethostname
27
- expander = Fluent::Plugin::Prometheus.placeholder_expander(log)
28
- placeholders = expander.prepare_placeholders({'hostname' => hostname, 'worker_id' => fluentd_worker_id})
27
+ expander_builder = Fluent::Plugin::Prometheus.placeholder_expander(log)
28
+ expander = expander_builder.build({ 'hostname' => hostname, 'worker_id' => fluentd_worker_id })
29
29
  @base_labels = parse_labels_elements(conf)
30
30
  @base_labels.each do |key, value|
31
31
  unless value.is_a?(String)
32
32
  raise Fluent::ConfigError, "record accessor syntax is not available in prometheus_monitor"
33
33
  end
34
- @base_labels[key] = expander.expand(value, placeholders)
34
+ @base_labels[key] = expander.expand(value)
35
35
  end
36
36
 
37
37
  if defined?(Fluent::Plugin) && defined?(Fluent::Plugin::MonitorAgentInput)
@@ -43,14 +43,14 @@ module Fluent::Plugin
43
43
  def configure(conf)
44
44
  super
45
45
  hostname = Socket.gethostname
46
- expander = Fluent::Plugin::Prometheus.placeholder_expander(log)
47
- placeholders = expander.prepare_placeholders({'hostname' => hostname, 'worker_id' => fluentd_worker_id})
46
+ expander_builder = Fluent::Plugin::Prometheus.placeholder_expander(log)
47
+ expander = expander_builder.buidl({ 'hostname' => hostname, 'worker_id' => fluentd_worker_id })
48
48
  @base_labels = parse_labels_elements(conf)
49
49
  @base_labels.each do |key, value|
50
50
  unless value.is_a?(String)
51
51
  raise Fluent::ConfigError, "record accessor syntax is not available in prometheus_output_monitor"
52
52
  end
53
- @base_labels[key] = expander.expand(value, placeholders)
53
+ @base_labels[key] = expander.expand(value)
54
54
  end
55
55
 
56
56
  if defined?(Fluent::Plugin) && defined?(Fluent::Plugin::MonitorAgentInput)
@@ -28,14 +28,14 @@ module Fluent::Plugin
28
28
  def configure(conf)
29
29
  super
30
30
  hostname = Socket.gethostname
31
- expander = Fluent::Plugin::Prometheus.placeholder_expander(log)
32
- placeholders = expander.prepare_placeholders({'hostname' => hostname, 'worker_id' => fluentd_worker_id})
31
+ expander_builder = Fluent::Plugin::Prometheus.placeholder_expander(log)
32
+ expander = expander_builder.prepare_placeholders({ 'hostname' => hostname, 'worker_id' => fluentd_worker_id })
33
33
  @base_labels = parse_labels_elements(conf)
34
34
  @base_labels.each do |key, value|
35
35
  unless value.is_a?(String)
36
36
  raise Fluent::ConfigError, "record accessor syntax is not available in prometheus_tail_monitor"
37
37
  end
38
- @base_labels[key] = expander.expand(value, placeholders)
38
+ @base_labels[key] = expander.expand(value)
39
39
  end
40
40
 
41
41
  if defined?(Fluent::Plugin) && defined?(Fluent::Plugin::MonitorAgentInput)
@@ -1,6 +1,6 @@
1
1
  require 'prometheus/client'
2
2
  require 'prometheus/client/formats/text'
3
- require 'fluent/plugin/filter_record_transformer'
3
+ require 'fluent/plugin/prometheus/placeholder_expander'
4
4
 
5
5
  module Fluent
6
6
  module Plugin
@@ -82,14 +82,13 @@ module Fluent
82
82
  end
83
83
 
84
84
  def self.placeholder_expander(log)
85
- # Use internal class in order to expand placeholder
86
- Fluent::Plugin::RecordTransformerFilter::PlaceholderExpander.new(log: log)
85
+ Fluent::Plugin::Prometheus::ExpandBuilder.new(log: log)
87
86
  end
88
87
 
89
88
  def configure(conf)
90
89
  super
91
90
  @placeholder_values = {}
92
- @placeholder_expander = Fluent::Plugin::Prometheus.placeholder_expander(log)
91
+ @placeholder_expander_builder = Fluent::Plugin::Prometheus.placeholder_expander(log)
93
92
  @hostname = Socket.gethostname
94
93
  end
95
94
 
@@ -101,10 +100,10 @@ module Fluent
101
100
  }
102
101
 
103
102
  placeholders = record.merge(@placeholder_values[tag])
104
- placeholders = @placeholder_expander.prepare_placeholders(placeholders)
103
+ expander = @placeholder_expander_builder.build(placeholders)
105
104
  metrics.each do |metric|
106
105
  begin
107
- metric.instrument(record, @placeholder_expander, placeholders)
106
+ metric.instrument(record, expander)
108
107
  rescue => e
109
108
  log.warn "prometheus: failed to instrument a metric.", error_class: e.class, error: e, tag: tag, name: metric.name
110
109
  router.emit_error_event(tag, time, record, e)
@@ -121,10 +120,10 @@ module Fluent
121
120
 
122
121
  es.each do |time, record|
123
122
  placeholders = record.merge(placeholder_values)
124
- placeholders = @placeholder_expander.prepare_placeholders(placeholders)
123
+ expander = @placeholder_expander_builder.build(placeholders)
125
124
  metrics.each do |metric|
126
125
  begin
127
- metric.instrument(record, @placeholder_expander, placeholders)
126
+ metric.instrument(record, expander)
128
127
  rescue => e
129
128
  log.warn "prometheus: failed to instrument a metric.", error_class: e.class, error: e, tag: tag, name: metric.name
130
129
  router.emit_error_event(tag, time, record, e)
@@ -154,11 +153,11 @@ module Fluent
154
153
  @base_labels = labels.merge(@base_labels)
155
154
  end
156
155
 
157
- def labels(record, expander, placeholders)
156
+ def labels(record, expander)
158
157
  label = {}
159
158
  @base_labels.each do |k, v|
160
159
  if v.is_a?(String)
161
- label[k] = expander.expand(v, placeholders)
160
+ label[k] = expander.expand(v)
162
161
  else
163
162
  label[k] = v.call(record)
164
163
  end
@@ -195,14 +194,14 @@ module Fluent
195
194
  end
196
195
  end
197
196
 
198
- def instrument(record, expander, placeholders)
197
+ def instrument(record, expander)
199
198
  if @key.is_a?(String)
200
199
  value = record[@key]
201
200
  else
202
201
  value = @key.call(record)
203
202
  end
204
203
  if value
205
- @gauge.set(labels(record, expander, placeholders), value)
204
+ @gauge.set(labels(record, expander), value)
206
205
  end
207
206
  end
208
207
  end
@@ -217,7 +216,7 @@ module Fluent
217
216
  end
218
217
  end
219
218
 
220
- def instrument(record, expander, placeholders)
219
+ def instrument(record, expander)
221
220
  # use record value of the key if key is specified, otherwise just increment
222
221
  if @key.nil?
223
222
  value = 1
@@ -230,7 +229,7 @@ module Fluent
230
229
  # ignore if record value is nil
231
230
  return if value.nil?
232
231
 
233
- @counter.increment(labels(record, expander, placeholders), value)
232
+ @counter.increment(labels(record, expander), value)
234
233
  end
235
234
  end
236
235
 
@@ -248,14 +247,14 @@ module Fluent
248
247
  end
249
248
  end
250
249
 
251
- def instrument(record, expander, placeholders)
250
+ def instrument(record, expander)
252
251
  if @key.is_a?(String)
253
252
  value = record[@key]
254
253
  else
255
254
  value = @key.call(record)
256
255
  end
257
256
  if value
258
- @summary.observe(labels(record, expander, placeholders), value)
257
+ @summary.observe(labels(record, expander), value)
259
258
  end
260
259
  end
261
260
  end
@@ -281,14 +280,14 @@ module Fluent
281
280
  end
282
281
  end
283
282
 
284
- def instrument(record, expander, placeholders)
283
+ def instrument(record, expander)
285
284
  if @key.is_a?(String)
286
285
  value = record[@key]
287
286
  else
288
287
  value = @key.call(record)
289
288
  end
290
289
  if value
291
- @histogram.observe(labels(record, expander, placeholders), value)
290
+ @histogram.observe(labels(record, expander), value)
292
291
  end
293
292
  end
294
293
  end
@@ -0,0 +1,132 @@
1
+ module Fluent
2
+ module Plugin
3
+ module Prometheus
4
+ class ExpandBuilder
5
+ def self.build(placeholder, log:)
6
+ new(log: log).build(placeholder)
7
+ end
8
+
9
+ def initialize(log:)
10
+ @log = log
11
+ end
12
+
13
+ def build(placeholder_values)
14
+ placeholders = {}
15
+ placeholder_values.each do |key, value|
16
+ case value
17
+ when Array
18
+ size = value.size
19
+ value.each_with_index do |v, i|
20
+ placeholders["${#{key}[#{i}]}"] = v
21
+ placeholders["${#{key}[#{i - size}]}"] = v
22
+ end
23
+ when Hash
24
+ value.each do |k, v|
25
+ placeholders[%(${#{key}["#{k}"]})] = v
26
+ end
27
+ else
28
+ if key == 'tag'
29
+ placeholders.merge!(build_tag(value))
30
+ else
31
+ placeholders["${#{key}}"] = value
32
+ end
33
+ end
34
+ end
35
+
36
+ Fluent::Plugin::Prometheus::ExpandBuilder::PlaceholderExpander.new(@log, placeholders)
37
+ end
38
+
39
+ private
40
+
41
+ def build_tag(tag)
42
+ tags = tag.split('.')
43
+
44
+ placeholders = { '${tag}' => tag }
45
+
46
+ size = tags.size
47
+
48
+ tags.each_with_index do |v, i|
49
+ placeholders["${tag_parts[#{i}]}"] = v
50
+ placeholders["${tag_parts[#{i - size}]}"] = v
51
+ end
52
+
53
+ tag_prefix(tags).each_with_index do |v, i|
54
+ placeholders["${tag_prefix[#{i}]}"] = v
55
+ end
56
+
57
+ tag_suffix(tags).each_with_index do |v, i|
58
+ placeholders["${tag_suffix[#{i}]}"] = v
59
+ end
60
+
61
+ placeholders
62
+ end
63
+
64
+ def tag_prefix(tags)
65
+ tags = tags.dup
66
+ return [] if tags.empty?
67
+
68
+ ret = [tags.shift]
69
+ tags.each.with_index(1) do |tag, i|
70
+ ret[i] = "#{ret[i-1]}.#{tag}"
71
+ end
72
+ ret
73
+ end
74
+
75
+ def tag_suffix(tags)
76
+ return [] if tags.empty?
77
+
78
+ tags = tags.dup.reverse
79
+ ret = [tags.shift]
80
+ tags.each.with_index(1) do |tag, i|
81
+ ret[i] = "#{tag}.#{ret[i-1]}"
82
+ end
83
+ ret
84
+ end
85
+
86
+ class PlaceholderExpander
87
+ PLACEHOLDER_REGEX = /(\${[^\[}]+(\[[^\]]+\])?})/.freeze
88
+
89
+ attr_reader :placeholder
90
+
91
+ def initialize(log, placeholder)
92
+ @placeholder = placeholder
93
+ @log = log
94
+ @expander_cache = {}
95
+ end
96
+
97
+ def merge_placeholder(placeholder)
98
+ @placeholder.merge!(placeholder)
99
+ end
100
+
101
+ def expand(str, dynamic_placeholders: nil)
102
+ expander = if dynamic_placeholders
103
+ if @expander_cache[dynamic_placeholders]
104
+ @expander_cache[dynamic_placeholders]
105
+ else
106
+ e = ExpandBuilder.build(dynamic_placeholders, log: @log)
107
+ e.merge_placeholder(@placeholder)
108
+ @expander_cache[dynamic_placeholders] = e
109
+ e
110
+ end
111
+ else
112
+ self
113
+ end
114
+
115
+ expander.expand!(str)
116
+ end
117
+
118
+ protected
119
+
120
+ def expand!(str)
121
+ str.gsub(PLACEHOLDER_REGEX) { |value|
122
+ @placeholder.fetch(value) do
123
+ @log.warn("unknown placeholder `#{value}` found")
124
+ value # return as it is
125
+ end
126
+ }
127
+ end
128
+ end
129
+ end
130
+ end
131
+ end
132
+ end
@@ -6,7 +6,11 @@ require_relative 'shared'
6
6
  describe Fluent::Plugin::PrometheusFilter do
7
7
  let(:tag) { 'prometheus.test' }
8
8
  let(:driver) { Fluent::Test::Driver::Filter.new(Fluent::Plugin::PrometheusFilter).configure(config) }
9
- let(:registry) { ::Prometheus::Client.registry }
9
+ let(:registry) { ::Prometheus::Client::Registry.new }
10
+
11
+ before do
12
+ allow(Prometheus::Client).to receive(:registry).and_return(registry)
13
+ end
10
14
 
11
15
  describe '#configure' do
12
16
  it_behaves_like 'output configuration'
@@ -14,22 +18,28 @@ describe Fluent::Plugin::PrometheusFilter do
14
18
 
15
19
  describe '#run' do
16
20
  let(:message) { {"foo" => 100, "bar" => 100, "baz" => 100, "qux" => 10} }
17
- let(:es) {
18
- driver.run(default_tag: tag) { driver.feed(event_time, message) }
19
- driver.filtered_records
20
- }
21
21
 
22
22
  context 'simple config' do
23
- include_context 'simple_config'
23
+ let(:config) {
24
+ BASE_CONFIG + %(
25
+ <metric>
26
+ name simple
27
+ type counter
28
+ desc Something foo.
29
+ key foo
30
+ </metric>
31
+ )
32
+ }
24
33
 
25
34
  it 'adds a new counter metric' do
26
- expect(registry.metrics.map(&:name)).not_to include(name)
27
- es
28
- expect(registry.metrics.map(&:name)).to include(name)
35
+ expect(registry.metrics.map(&:name)).not_to eq([:simple])
36
+ driver.run(default_tag: tag) { driver.feed(event_time, message) }
37
+ expect(registry.metrics.map(&:name)).to eq([:simple])
29
38
  end
30
39
 
31
40
  it 'should keep original message' do
32
- expect(es.first).to eq(message)
41
+ driver.run(default_tag: tag) { driver.feed(event_time, message) }
42
+ expect(driver.filtered_records.first).to eq(message)
33
43
  end
34
44
  end
35
45
 
@@ -23,7 +23,6 @@ describe Fluent::Plugin::PrometheusMonitorInput do
23
23
  ]
24
24
 
25
25
  let(:config) { MONITOR_CONFIG }
26
- let(:port) { 24231 }
27
26
  let(:driver) { Fluent::Test::Driver::Input.new(Fluent::Plugin::PrometheusMonitorInput).configure(config) }
28
27
 
29
28
  describe '#configure' do
@@ -6,7 +6,11 @@ require_relative 'shared'
6
6
  describe Fluent::Plugin::PrometheusOutput do
7
7
  let(:tag) { 'prometheus.test' }
8
8
  let(:driver) { Fluent::Test::Driver::Output.new(Fluent::Plugin::PrometheusOutput).configure(config) }
9
- let(:registry) { ::Prometheus::Client.registry }
9
+ let(:registry) { ::Prometheus::Client::Registry.new }
10
+
11
+ before do
12
+ allow(Prometheus::Client).to receive(:registry).and_return(registry)
13
+ end
10
14
 
11
15
  describe '#configure' do
12
16
  it_behaves_like 'output configuration'
@@ -14,18 +18,23 @@ describe Fluent::Plugin::PrometheusOutput do
14
18
 
15
19
  describe '#run' do
16
20
  let(:message) { {"foo" => 100, "bar" => 100, "baz" => 100, "qux" => 10} }
17
- let(:es) {
18
- driver.run(default_tag: tag) { driver.feed(event_time, message) }
19
- driver.events
20
- }
21
21
 
22
22
  context 'simple config' do
23
- include_context 'simple_config'
23
+ let(:config) {
24
+ BASE_CONFIG + %(
25
+ <metric>
26
+ name simple
27
+ type counter
28
+ desc Something foo.
29
+ key foo
30
+ </metric>
31
+ )
32
+ }
24
33
 
25
34
  it 'adds a new counter metric' do
26
- expect(registry.metrics.map(&:name)).not_to include(name)
27
- es
28
- expect(registry.metrics.map(&:name)).to include(name)
35
+ expect(registry.metrics.map(&:name)).not_to eq([:simple])
36
+ driver.run(default_tag: tag) { driver.feed(event_time, message) }
37
+ expect(registry.metrics.map(&:name)).to eq([:simple])
29
38
  end
30
39
  end
31
40
 
@@ -0,0 +1,110 @@
1
+ require 'logger'
2
+
3
+ require 'spec_helper'
4
+ require 'fluent/plugin/prometheus/placeholder_expander'
5
+ require_relative '../shared'
6
+
7
+ describe Fluent::Plugin::Prometheus::ExpandBuilder::PlaceholderExpander do
8
+ let(:log) do
9
+ Logger.new('/dev/null')
10
+ end
11
+
12
+ let(:builder) do
13
+ Fluent::Plugin::Prometheus::ExpandBuilder.new(log: log)
14
+ end
15
+
16
+ describe '#expand' do
17
+ context 'with static placeholder' do
18
+ let(:static_placeholder) do
19
+ {
20
+ 'hostname' => 'host_value',
21
+ 'tag' => '1.2.3',
22
+ 'ary_value' => ['1', '2', '3'],
23
+ 'hash_value' => { 'key1' => 'val1' },
24
+ }
25
+ end
26
+
27
+ let(:dynamic_placeholder) do
28
+ end
29
+
30
+ it 'expands values' do
31
+ expander = builder.build(static_placeholder)
32
+ expect(expander.expand('${hostname}')).to eq('host_value')
33
+ expect(expander.expand('${ary_value[0]}.${ary_value[1]}.${ary_value[2]}')).to eq('1.2.3')
34
+ expect(expander.expand('${ary_value[-3]}.${ary_value[-2]}.${ary_value[-1]}')).to eq('1.2.3')
35
+ expect(expander.expand('${hash_value["key1"]}')).to eq('val1')
36
+
37
+ expect(expander.expand('${tag}')).to eq('1.2.3')
38
+ expect(expander.expand('${tag_parts[0]}.${tag_parts[1]}.${tag_parts[2]}')).to eq('1.2.3')
39
+ expect(expander.expand('${tag_parts[-3]}.${tag_parts[-2]}.${tag_parts[-1]}')).to eq('1.2.3')
40
+ expect(expander.expand('${tag_prefix[0]}.${tag_prefix[1]}.${tag_prefix[2]}')).to eq('1.1.2.1.2.3')
41
+ expect(expander.expand('${tag_suffix[0]}.${tag_suffix[1]}.${tag_suffix[2]}')).to eq('3.2.3.1.2.3')
42
+ end
43
+
44
+ it 'does not create new expander' do
45
+ builder # cached before mock
46
+
47
+ expect(Fluent::Plugin::Prometheus::ExpandBuilder).to receive(:build).with(anything, log: anything).never
48
+ expander = builder.build(static_placeholder)
49
+ expander.expand('${hostname}')
50
+ expander.expand('${hostname}')
51
+ end
52
+
53
+ context 'when not found placeholder' do
54
+ it 'prints wanring log and as it is' do
55
+ expect(log).to receive(:warn).with('unknown placeholder `${tag_prefix[100]}` found').once
56
+
57
+ expander = builder.build(static_placeholder)
58
+ expect(expander.expand('${tag_prefix[100]}')).to eq('${tag_prefix[100]}')
59
+ end
60
+ end
61
+ end
62
+
63
+ context 'with dynamic placeholder' do
64
+ let(:static_placeholder) do
65
+ {
66
+ 'hostname' => 'host_value',
67
+ 'ary_value' => ['1', '2', '3'],
68
+ 'hash_value' => { 'key1' => 'val1' },
69
+ }
70
+ end
71
+
72
+ let(:dynamic_placeholder) do
73
+ { 'tag' => '1.2.3'}
74
+ end
75
+
76
+ it 'expands values' do
77
+ expander = builder.build(static_placeholder)
78
+ expect(expander.expand('${hostname}', dynamic_placeholders: dynamic_placeholder)).to eq('host_value')
79
+ expect(expander.expand('${ary_value[0]}.${ary_value[1]}.${ary_value[2]}', dynamic_placeholders: dynamic_placeholder)).to eq('1.2.3')
80
+ expect(expander.expand('${ary_value[-3]}.${ary_value[-2]}.${ary_value[-1]}', dynamic_placeholders: dynamic_placeholder)).to eq('1.2.3')
81
+ expect(expander.expand('${hash_value["key1"]}', dynamic_placeholders: dynamic_placeholder)).to eq('val1')
82
+
83
+ expect(expander.expand('${tag}', dynamic_placeholders: dynamic_placeholder)).to eq('1.2.3')
84
+ expect(expander.expand('${tag_parts[0]}.${tag_parts[1]}.${tag_parts[2]}', dynamic_placeholders: dynamic_placeholder)).to eq('1.2.3')
85
+ expect(expander.expand('${tag_parts[-3]}.${tag_parts[-2]}.${tag_parts[-1]}', dynamic_placeholders: dynamic_placeholder)).to eq('1.2.3')
86
+ expect(expander.expand('${tag_prefix[0]}.${tag_prefix[1]}.${tag_prefix[2]}', dynamic_placeholders: dynamic_placeholder)).to eq('1.1.2.1.2.3')
87
+ expect(expander.expand('${tag_suffix[0]}.${tag_suffix[1]}.${tag_suffix[2]}', dynamic_placeholders: dynamic_placeholder)).to eq('3.2.3.1.2.3')
88
+ end
89
+
90
+ it 'does not create expander twice if given the same placeholder' do
91
+ builder # cached before mock
92
+
93
+ expect(Fluent::Plugin::Prometheus::ExpandBuilder).to receive(:build).with(anything, log: anything).once.and_call_original
94
+ expander = builder.build(static_placeholder)
95
+ placeholder = { 'tag' => 'val.test' }
96
+ expander.expand('${hostname}', dynamic_placeholders: placeholder)
97
+ expander.expand('${hostname}', dynamic_placeholders: placeholder)
98
+ end
99
+
100
+ it 'creates new expander for each placeholder' do
101
+ builder # cached before mock
102
+
103
+ expect(Fluent::Plugin::Prometheus::ExpandBuilder).to receive(:build).with(anything, log: anything).twice.and_call_original
104
+ expander = builder.build(static_placeholder)
105
+ expander.expand('${hostname}', dynamic_placeholders: { 'tag' => 'val.test' })
106
+ expander.expand('${hostname}', dynamic_placeholders: { 'tag' => 'val.test2' })
107
+ end
108
+ end
109
+ end
110
+ end
@@ -3,9 +3,7 @@ BASE_CONFIG = %[
3
3
  type prometheus
4
4
  ]
5
5
 
6
-
7
6
  SIMPLE_CONFIG = BASE_CONFIG + %[
8
- type prometheus
9
7
  <metric>
10
8
  name simple_foo
11
9
  type counter
@@ -111,109 +109,65 @@ COUNTER_WITHOUT_KEY_CONFIG = BASE_CONFIG + %[
111
109
  </metric>
112
110
  ]
113
111
 
114
- def gen_time_suffix
115
- return Time.now.to_f.to_s.gsub('.', '')
116
- end
117
-
118
- shared_context 'simple_config' do
119
- let(:orig_name) { 'simple_foo' }
120
- let(:config) { SIMPLE_CONFIG.gsub(orig_name, name.to_s) }
121
- let(:name) { "#{orig_name}_#{gen_time_suffix}".to_sym }
122
- let(:counter) { registry.get(name) }
123
- end
124
-
125
- shared_context 'full_config' do
126
- let(:config) { FULL_CONFIG }
127
- let(:counter) { registry.get(:full_foo) }
128
- let(:gauge) { registry.get(:full_bar) }
129
- let(:summary) { registry.get(:full_baz) }
130
- let(:histogram) { registry.get(:full_qux) }
131
- let(:summary_with_accessor) { registry.get(:full_accessor1) }
132
- let(:counter_with_accessor) { registry.get(:full_accessor2) }
133
- end
134
-
135
- shared_context 'placeholder_config' do
136
- let(:orig_name) { 'placeholder_foo' }
137
- let(:config) { PLACEHOLDER_CONFIG.gsub(orig_name, name.to_s) }
138
- let(:name) { "#{orig_name}_#{gen_time_suffix}".to_sym }
139
- let(:counter) { registry.get(name) }
140
- end
141
-
142
- shared_context 'accessor_config' do
143
- let(:orig_name) { 'accessor_foo' }
144
- let(:config) { ACCESSOR_CONFIG.gsub(orig_name, name.to_s) }
145
- let(:name) { "#{orig_name}_#{gen_time_suffix}".to_sym }
146
- let(:counter) { registry.get(name) }
147
- end
148
-
149
- shared_context 'counter_without_key_config' do
150
- let(:orig_name) { 'without_key_foo' }
151
- let(:config) { COUNTER_WITHOUT_KEY_CONFIG.gsub(orig_name, name.to_s) }
152
- let(:name) { "#{orig_name}_#{gen_time_suffix}".to_sym }
153
- let(:counter) { registry.get(name) }
154
- end
155
-
156
112
  shared_examples_for 'output configuration' do
157
113
  context 'base config' do
158
114
  let(:config) { BASE_CONFIG }
159
- it 'does not raise error' do
160
- expect{driver}.not_to raise_error
161
- end
115
+ it { expect { driver }.not_to raise_error }
162
116
  end
163
117
 
164
- describe 'configure simple configuration' do
165
- include_context 'simple_config'
166
- it { expect{driver}.not_to raise_error }
118
+ context 'with simple configuration' do
119
+ let(:config) { SIMPLE_CONFIG }
120
+ it { expect { driver }.not_to raise_error }
167
121
  end
168
122
 
169
- describe 'configure full configuration' do
170
- include_context 'full_config'
171
- it { expect{driver}.not_to raise_error }
123
+ context 'with full configuration' do
124
+ let(:config) { FULL_CONFIG }
125
+ it { expect { driver }.not_to raise_error }
172
126
  end
173
127
 
174
- describe 'configure placeholder configuration' do
175
- include_context 'placeholder_config'
176
- it { expect{driver}.not_to raise_error }
128
+ context 'with placeholder configuration' do
129
+ let(:config) { PLACEHOLDER_CONFIG }
130
+ it { expect { driver }.not_to raise_error }
177
131
  end
178
132
 
179
- describe 'configure accessor configuration' do
180
- include_context 'accessor_config'
181
- it { expect{driver}.not_to raise_error }
133
+ context 'with accessor configuration' do
134
+ let(:config) { ACCESSOR_CONFIG }
135
+ it { expect { driver }.not_to raise_error }
182
136
  end
183
137
 
184
- describe 'configure counter without key configuration' do
185
- include_context 'counter_without_key_config'
186
- it { expect{driver}.not_to raise_error }
138
+ describe 'with counter without key configuration' do
139
+ let(:config) { COUNTER_WITHOUT_KEY_CONFIG }
140
+ it { expect { driver }.not_to raise_error }
187
141
  end
188
142
 
189
- context 'unknown type' do
190
- let(:config) { BASE_CONFIG + %[
191
- <metric>
192
- type foo
193
- </metric>
194
- ] }
195
- it 'raises ConfigError' do
196
- expect{driver}.to raise_error Fluent::ConfigError
143
+ context 'with unknown type' do
144
+ let(:config) do
145
+ BASE_CONFIG + %[
146
+ <metric>
147
+ type foo
148
+ </metric>
149
+ ]
197
150
  end
151
+ it { expect { driver }.to raise_error(Fluent::ConfigError) }
198
152
  end
199
153
  end
200
154
 
201
- emit_count = 0
202
155
  shared_examples_for 'instruments record' do
203
- context 'full config' do
204
- include_context 'full_config'
156
+ before do
157
+ driver.run(default_tag: tag) { driver.feed(event_time, message) }
158
+ end
205
159
 
206
- before :each do
207
- es
208
- emit_count += 1
209
- end
160
+ context 'full config' do
161
+ let(:config) { FULL_CONFIG }
162
+ let(:counter) { registry.get(:full_foo) }
163
+ let(:gauge) { registry.get(:full_bar) }
164
+ let(:summary) { registry.get(:full_baz) }
165
+ let(:histogram) { registry.get(:full_qux) }
166
+ let(:summary_with_accessor) { registry.get(:full_accessor1) }
167
+ let(:counter_with_accessor) { registry.get(:full_accessor2) }
210
168
 
211
169
  it 'adds all metrics' do
212
- expect(registry.metrics.map(&:name)).to include(:full_foo)
213
- expect(registry.metrics.map(&:name)).to include(:full_bar)
214
- expect(registry.metrics.map(&:name)).to include(:full_baz)
215
- expect(registry.metrics.map(&:name)).to include(:full_accessor1)
216
- expect(registry.metrics.map(&:name)).to include(:full_accessor2)
170
+ expect(registry.metrics.map(&:name)).to eq(%i[full_foo full_bar full_baz full_qux full_accessor1 full_accessor2])
217
171
  expect(counter).to be_kind_of(::Prometheus::Client::Metric)
218
172
  expect(gauge).to be_kind_of(::Prometheus::Client::Metric)
219
173
  expect(summary).to be_kind_of(::Prometheus::Client::Metric)
@@ -241,21 +195,22 @@ shared_examples_for 'instruments record' do
241
195
  end
242
196
 
243
197
  it 'instruments histogram metric' do
198
+ driver.run(default_tag: tag) do
199
+ 4.times { driver.feed(event_time, message) }
200
+ end
201
+
244
202
  expect(histogram.type).to eq(:histogram)
245
203
  expect(histogram.get({test_key: 'test_value', key: 'foo4'})).to be_kind_of(Hash)
246
- expect(histogram.get({test_key: 'test_value', key: 'foo4'})[10]).to eq(emit_count)
204
+ expect(histogram.get({test_key: 'test_value', key: 'foo4'})[10]).to eq(5) # 4 + `es` in before
247
205
  end
248
206
  end
249
207
 
250
208
  context 'placeholder config' do
251
- include_context 'placeholder_config'
252
-
253
- before :each do
254
- es
255
- end
209
+ let(:config) { PLACEHOLDER_CONFIG }
210
+ let(:counter) { registry.get(:placeholder_foo) }
256
211
 
257
212
  it 'expands placeholders with record values' do
258
- expect(registry.metrics.map(&:name)).to include(name)
213
+ expect(registry.metrics.map(&:name)).to eq([:placeholder_foo])
259
214
  expect(counter).to be_kind_of(::Prometheus::Client::Metric)
260
215
  key, _ = counter.values.find {|k,v| v == 100 }
261
216
  expect(key).to be_kind_of(Hash)
@@ -268,14 +223,11 @@ shared_examples_for 'instruments record' do
268
223
  end
269
224
 
270
225
  context 'accessor config' do
271
- include_context 'accessor_config'
272
-
273
- before :each do
274
- es
275
- end
226
+ let(:config) { ACCESSOR_CONFIG }
227
+ let(:counter) { registry.get(:accessor_foo) }
276
228
 
277
229
  it 'expands accessor with record values' do
278
- expect(registry.metrics.map(&:name)).to include(name)
230
+ expect(registry.metrics.map(&:name)).to eq([:accessor_foo])
279
231
  expect(counter).to be_kind_of(::Prometheus::Client::Metric)
280
232
  key, _ = counter.values.find {|k,v| v == 100 }
281
233
  expect(key).to be_kind_of(Hash)
@@ -284,14 +236,11 @@ shared_examples_for 'instruments record' do
284
236
  end
285
237
 
286
238
  context 'counter_without config' do
287
- include_context 'counter_without_key_config'
288
-
289
- before :each do
290
- es
291
- end
239
+ let(:config) { COUNTER_WITHOUT_KEY_CONFIG }
240
+ let(:counter) { registry.get(:without_key_foo) }
292
241
 
293
242
  it 'just increments by 1' do
294
- expect(registry.metrics.map(&:name)).to include(name)
243
+ expect(registry.metrics.map(&:name)).to eq([:without_key_foo])
295
244
  expect(counter).to be_kind_of(::Prometheus::Client::Metric)
296
245
  _, value = counter.values.find {|k,v| k == {} }
297
246
  expect(value).to eq(1)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fluent-plugin-prometheus
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.7.0
4
+ version: 1.7.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Masahiro Sano
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-10-31 00:00:00.000000000 Z
11
+ date: 2020-02-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: fluentd
@@ -122,6 +122,7 @@ files:
122
122
  - lib/fluent/plugin/in_prometheus_tail_monitor.rb
123
123
  - lib/fluent/plugin/out_prometheus.rb
124
124
  - lib/fluent/plugin/prometheus.rb
125
+ - lib/fluent/plugin/prometheus/placeholder_expander.rb
125
126
  - lib/fluent/plugin/prometheus_metrics.rb
126
127
  - misc/fluentd_sample.conf
127
128
  - misc/nginx_proxy.conf
@@ -129,9 +130,10 @@ files:
129
130
  - misc/prometheus_alerts.yaml
130
131
  - spec/fluent/plugin/filter_prometheus_spec.rb
131
132
  - spec/fluent/plugin/in_prometheus_monitor_spec.rb
133
+ - spec/fluent/plugin/in_prometheus_spec.rb
132
134
  - spec/fluent/plugin/out_prometheus_spec.rb
135
+ - spec/fluent/plugin/prometheus/placeholder_expander_spec.rb
133
136
  - spec/fluent/plugin/prometheus_metrics_spec.rb
134
- - spec/fluent/plugin/prometheus_spec.rb
135
137
  - spec/fluent/plugin/shared.rb
136
138
  - spec/spec_helper.rb
137
139
  homepage: https://github.com/fluent/fluent-plugin-prometheus
@@ -160,8 +162,9 @@ summary: A fluent plugin that collects metrics and exposes for Prometheus.
160
162
  test_files:
161
163
  - spec/fluent/plugin/filter_prometheus_spec.rb
162
164
  - spec/fluent/plugin/in_prometheus_monitor_spec.rb
165
+ - spec/fluent/plugin/in_prometheus_spec.rb
163
166
  - spec/fluent/plugin/out_prometheus_spec.rb
167
+ - spec/fluent/plugin/prometheus/placeholder_expander_spec.rb
164
168
  - spec/fluent/plugin/prometheus_metrics_spec.rb
165
- - spec/fluent/plugin/prometheus_spec.rb
166
169
  - spec/fluent/plugin/shared.rb
167
170
  - spec/spec_helper.rb