fluent-plugin-prometheus 1.6.0 → 1.7.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +7 -1
- data/fluent-plugin-prometheus.gemspec +2 -2
- data/lib/fluent/plugin/filter_prometheus.rb +3 -3
- data/lib/fluent/plugin/in_prometheus_monitor.rb +3 -3
- data/lib/fluent/plugin/in_prometheus_output_monitor.rb +3 -3
- data/lib/fluent/plugin/in_prometheus_tail_monitor.rb +3 -3
- data/lib/fluent/plugin/prometheus.rb +35 -16
- data/lib/fluent/plugin/prometheus/placeholder_expander.rb +132 -0
- data/spec/fluent/plugin/filter_prometheus_spec.rb +20 -10
- data/spec/fluent/plugin/in_prometheus_monitor_spec.rb +0 -1
- data/spec/fluent/plugin/{prometheus_spec.rb → in_prometheus_spec.rb} +0 -0
- data/spec/fluent/plugin/in_prometheus_tail_monitor_spec.rb +42 -0
- data/spec/fluent/plugin/out_prometheus_spec.rb +18 -9
- data/spec/fluent/plugin/prometheus/placeholder_expander_spec.rb +110 -0
- data/spec/fluent/plugin/shared.rb +50 -101
- metadata +14 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1f14f2b2162bace2a18a80f885df28261ed260a7b8e865a12e7828d46af9b02f
|
4
|
+
data.tar.gz: 20749cd6ee743ac3726719e654e1a4f046aa2f953245604e6aa75cd87ed00e62
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 28ca37140a4b634665a9ba184c1615380bc7c458ed745d5548cb75b92d75d3b1069cd342d3119785a11d1beb369e7b41b5fa0319021bb0f69400ffe327dea83e
|
7
|
+
data.tar.gz: b04770fec96856fc37b6943c7129c5e8ef16ce8b1415b425932e4419594e58a3255406de54e3aad1c28af1e3d62074391bd2b40e4aded8b5f598fbece53cab82
|
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.
|
3
|
+
spec.version = "1.7.3"
|
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.}
|
@@ -14,7 +14,7 @@ Gem::Specification.new do |spec|
|
|
14
14
|
spec.require_paths = ["lib"]
|
15
15
|
|
16
16
|
spec.add_dependency "fluentd", ">= 0.14.20", "< 2"
|
17
|
-
spec.add_dependency "prometheus-client"
|
17
|
+
spec.add_dependency "prometheus-client", "< 0.10"
|
18
18
|
spec.add_development_dependency "bundler"
|
19
19
|
spec.add_development_dependency "rake"
|
20
20
|
spec.add_development_dependency "rspec"
|
@@ -22,9 +22,9 @@ module Fluent::Plugin
|
|
22
22
|
@metrics = Fluent::Plugin::Prometheus.parse_metrics_elements(conf, @registry, labels)
|
23
23
|
end
|
24
24
|
|
25
|
-
def
|
26
|
-
|
27
|
-
|
25
|
+
def filter(tag, time, record)
|
26
|
+
instrument_single(tag, time, record, @metrics)
|
27
|
+
record
|
28
28
|
end
|
29
29
|
end
|
30
30
|
end
|
@@ -24,14 +24,14 @@ module Fluent::Plugin
|
|
24
24
|
def configure(conf)
|
25
25
|
super
|
26
26
|
hostname = Socket.gethostname
|
27
|
-
|
28
|
-
|
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
|
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
|
-
|
47
|
-
|
46
|
+
expander_builder = Fluent::Plugin::Prometheus.placeholder_expander(log)
|
47
|
+
expander = expander_builder.build({ '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
|
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
|
-
|
32
|
-
|
31
|
+
expander_builder = Fluent::Plugin::Prometheus.placeholder_expander(log)
|
32
|
+
expander = expander_builder.build({ '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
|
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/
|
3
|
+
require 'fluent/plugin/prometheus/placeholder_expander'
|
4
4
|
|
5
5
|
module Fluent
|
6
6
|
module Plugin
|
@@ -82,16 +82,35 @@ module Fluent
|
|
82
82
|
end
|
83
83
|
|
84
84
|
def self.placeholder_expander(log)
|
85
|
-
|
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 = {}
|
91
|
+
@placeholder_expander_builder = Fluent::Plugin::Prometheus.placeholder_expander(log)
|
92
92
|
@hostname = Socket.gethostname
|
93
93
|
end
|
94
94
|
|
95
|
+
def instrument_single(tag, time, record, metrics)
|
96
|
+
@placeholder_values[tag] ||= {
|
97
|
+
'tag' => tag,
|
98
|
+
'hostname' => @hostname,
|
99
|
+
'worker_id' => fluentd_worker_id,
|
100
|
+
}
|
101
|
+
|
102
|
+
placeholders = record.merge(@placeholder_values[tag])
|
103
|
+
expander = @placeholder_expander_builder.build(placeholders)
|
104
|
+
metrics.each do |metric|
|
105
|
+
begin
|
106
|
+
metric.instrument(record, expander)
|
107
|
+
rescue => e
|
108
|
+
log.warn "prometheus: failed to instrument a metric.", error_class: e.class, error: e, tag: tag, name: metric.name
|
109
|
+
router.emit_error_event(tag, time, record, e)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
95
114
|
def instrument(tag, es, metrics)
|
96
115
|
placeholder_values = {
|
97
116
|
'tag' => tag,
|
@@ -101,10 +120,10 @@ module Fluent
|
|
101
120
|
|
102
121
|
es.each do |time, record|
|
103
122
|
placeholders = record.merge(placeholder_values)
|
104
|
-
|
123
|
+
expander = @placeholder_expander_builder.build(placeholders)
|
105
124
|
metrics.each do |metric|
|
106
125
|
begin
|
107
|
-
metric.instrument(record,
|
126
|
+
metric.instrument(record, expander)
|
108
127
|
rescue => e
|
109
128
|
log.warn "prometheus: failed to instrument a metric.", error_class: e.class, error: e, tag: tag, name: metric.name
|
110
129
|
router.emit_error_event(tag, time, record, e)
|
@@ -134,11 +153,11 @@ module Fluent
|
|
134
153
|
@base_labels = labels.merge(@base_labels)
|
135
154
|
end
|
136
155
|
|
137
|
-
def labels(record, expander
|
156
|
+
def labels(record, expander)
|
138
157
|
label = {}
|
139
158
|
@base_labels.each do |k, v|
|
140
159
|
if v.is_a?(String)
|
141
|
-
label[k] = expander.expand(v
|
160
|
+
label[k] = expander.expand(v)
|
142
161
|
else
|
143
162
|
label[k] = v.call(record)
|
144
163
|
end
|
@@ -175,14 +194,14 @@ module Fluent
|
|
175
194
|
end
|
176
195
|
end
|
177
196
|
|
178
|
-
def instrument(record, expander
|
197
|
+
def instrument(record, expander)
|
179
198
|
if @key.is_a?(String)
|
180
199
|
value = record[@key]
|
181
200
|
else
|
182
201
|
value = @key.call(record)
|
183
202
|
end
|
184
203
|
if value
|
185
|
-
@gauge.set(labels(record, expander
|
204
|
+
@gauge.set(labels(record, expander), value)
|
186
205
|
end
|
187
206
|
end
|
188
207
|
end
|
@@ -197,7 +216,7 @@ module Fluent
|
|
197
216
|
end
|
198
217
|
end
|
199
218
|
|
200
|
-
def instrument(record, expander
|
219
|
+
def instrument(record, expander)
|
201
220
|
# use record value of the key if key is specified, otherwise just increment
|
202
221
|
if @key.nil?
|
203
222
|
value = 1
|
@@ -210,7 +229,7 @@ module Fluent
|
|
210
229
|
# ignore if record value is nil
|
211
230
|
return if value.nil?
|
212
231
|
|
213
|
-
@counter.increment(labels(record, expander
|
232
|
+
@counter.increment(labels(record, expander), value)
|
214
233
|
end
|
215
234
|
end
|
216
235
|
|
@@ -228,14 +247,14 @@ module Fluent
|
|
228
247
|
end
|
229
248
|
end
|
230
249
|
|
231
|
-
def instrument(record, expander
|
250
|
+
def instrument(record, expander)
|
232
251
|
if @key.is_a?(String)
|
233
252
|
value = record[@key]
|
234
253
|
else
|
235
254
|
value = @key.call(record)
|
236
255
|
end
|
237
256
|
if value
|
238
|
-
@summary.observe(labels(record, expander
|
257
|
+
@summary.observe(labels(record, expander), value)
|
239
258
|
end
|
240
259
|
end
|
241
260
|
end
|
@@ -261,14 +280,14 @@ module Fluent
|
|
261
280
|
end
|
262
281
|
end
|
263
282
|
|
264
|
-
def instrument(record, expander
|
283
|
+
def instrument(record, expander)
|
265
284
|
if @key.is_a?(String)
|
266
285
|
value = record[@key]
|
267
286
|
else
|
268
287
|
value = @key.call(record)
|
269
288
|
end
|
270
289
|
if value
|
271
|
-
@histogram.observe(labels(record, expander
|
290
|
+
@histogram.observe(labels(record, expander), value)
|
272
291
|
end
|
273
292
|
end
|
274
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.
|
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
|
-
|
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
|
27
|
-
|
28
|
-
expect(registry.metrics.map(&:name)).to
|
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
|
-
|
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
|
|
File without changes
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'fluent/plugin/in_prometheus_tail_monitor'
|
3
|
+
require 'fluent/test/driver/input'
|
4
|
+
|
5
|
+
describe Fluent::Plugin::PrometheusTailMonitorInput do
|
6
|
+
MONITOR_CONFIG = %[
|
7
|
+
@type prometheus_tail_monitor
|
8
|
+
<labels>
|
9
|
+
host ${hostname}
|
10
|
+
foo bar
|
11
|
+
</labels>
|
12
|
+
]
|
13
|
+
|
14
|
+
INVALID_MONITOR_CONFIG = %[
|
15
|
+
@type prometheus_tail_monitor
|
16
|
+
|
17
|
+
<labels>
|
18
|
+
host ${hostname}
|
19
|
+
foo bar
|
20
|
+
invalid_use1 $.foo.bar
|
21
|
+
invalid_use2 $[0][1]
|
22
|
+
</labels>
|
23
|
+
]
|
24
|
+
|
25
|
+
let(:config) { MONITOR_CONFIG }
|
26
|
+
let(:driver) { Fluent::Test::Driver::Input.new(Fluent::Plugin::PrometheusTailMonitorInput).configure(config) }
|
27
|
+
|
28
|
+
describe '#configure' do
|
29
|
+
describe 'valid' do
|
30
|
+
it 'does not raise error' do
|
31
|
+
expect { driver }.not_to raise_error
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe 'invalid' do
|
36
|
+
let(:config) { INVALID_MONITOR_CONFIG }
|
37
|
+
it 'expect raise error' do
|
38
|
+
expect { driver }.to raise_error
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -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.
|
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
|
-
|
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
|
27
|
-
|
28
|
-
expect(registry.metrics.map(&:name)).to
|
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
|
160
|
-
expect{driver}.not_to raise_error
|
161
|
-
end
|
115
|
+
it { expect { driver }.not_to raise_error }
|
162
116
|
end
|
163
117
|
|
164
|
-
|
165
|
-
|
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
|
-
|
170
|
-
|
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
|
-
|
175
|
-
|
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
|
-
|
180
|
-
|
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 '
|
185
|
-
|
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)
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
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
|
-
|
204
|
-
|
156
|
+
before do
|
157
|
+
driver.run(default_tag: tag) { driver.feed(event_time, message) }
|
158
|
+
end
|
205
159
|
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
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
|
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(
|
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
|
-
|
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
|
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
|
-
|
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
|
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
|
-
|
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
|
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.
|
4
|
+
version: 1.7.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Masahiro Sano
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-02-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: fluentd
|
@@ -34,16 +34,16 @@ dependencies:
|
|
34
34
|
name: prometheus-client
|
35
35
|
requirement: !ruby/object:Gem::Requirement
|
36
36
|
requirements:
|
37
|
-
- - "
|
37
|
+
- - "<"
|
38
38
|
- !ruby/object:Gem::Version
|
39
|
-
version: '0'
|
39
|
+
version: '0.10'
|
40
40
|
type: :runtime
|
41
41
|
prerelease: false
|
42
42
|
version_requirements: !ruby/object:Gem::Requirement
|
43
43
|
requirements:
|
44
|
-
- - "
|
44
|
+
- - "<"
|
45
45
|
- !ruby/object:Gem::Version
|
46
|
-
version: '0'
|
46
|
+
version: '0.10'
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: bundler
|
49
49
|
requirement: !ruby/object:Gem::Requirement
|
@@ -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,11 @@ 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
|
134
|
+
- spec/fluent/plugin/in_prometheus_tail_monitor_spec.rb
|
132
135
|
- spec/fluent/plugin/out_prometheus_spec.rb
|
136
|
+
- spec/fluent/plugin/prometheus/placeholder_expander_spec.rb
|
133
137
|
- spec/fluent/plugin/prometheus_metrics_spec.rb
|
134
|
-
- spec/fluent/plugin/prometheus_spec.rb
|
135
138
|
- spec/fluent/plugin/shared.rb
|
136
139
|
- spec/spec_helper.rb
|
137
140
|
homepage: https://github.com/fluent/fluent-plugin-prometheus
|
@@ -153,16 +156,17 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
153
156
|
- !ruby/object:Gem::Version
|
154
157
|
version: '0'
|
155
158
|
requirements: []
|
156
|
-
|
157
|
-
rubygems_version: 2.7.6
|
159
|
+
rubygems_version: 3.0.3
|
158
160
|
signing_key:
|
159
161
|
specification_version: 4
|
160
162
|
summary: A fluent plugin that collects metrics and exposes for Prometheus.
|
161
163
|
test_files:
|
162
164
|
- spec/fluent/plugin/filter_prometheus_spec.rb
|
163
165
|
- spec/fluent/plugin/in_prometheus_monitor_spec.rb
|
166
|
+
- spec/fluent/plugin/in_prometheus_spec.rb
|
167
|
+
- spec/fluent/plugin/in_prometheus_tail_monitor_spec.rb
|
164
168
|
- spec/fluent/plugin/out_prometheus_spec.rb
|
169
|
+
- spec/fluent/plugin/prometheus/placeholder_expander_spec.rb
|
165
170
|
- spec/fluent/plugin/prometheus_metrics_spec.rb
|
166
|
-
- spec/fluent/plugin/prometheus_spec.rb
|
167
171
|
- spec/fluent/plugin/shared.rb
|
168
172
|
- spec/spec_helper.rb
|