fluent-plugin-prometheus 1.6.0 → 1.7.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|