phihos-fluent-plugin-prometheus 2.0.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 +7 -0
- data/.github/workflows/linux.yml +34 -0
- data/.gitignore +16 -0
- data/.rspec +2 -0
- data/.travis.yml +14 -0
- data/ChangeLog +43 -0
- data/Gemfile +4 -0
- data/LICENSE +202 -0
- data/README.md +537 -0
- data/Rakefile +7 -0
- data/fluent-plugin-prometheus.gemspec +22 -0
- data/lib/fluent/plugin/filter_prometheus.rb +43 -0
- data/lib/fluent/plugin/in_prometheus/async_wrapper.rb +47 -0
- data/lib/fluent/plugin/in_prometheus.rb +230 -0
- data/lib/fluent/plugin/in_prometheus_monitor.rb +107 -0
- data/lib/fluent/plugin/in_prometheus_output_monitor.rb +234 -0
- data/lib/fluent/plugin/in_prometheus_tail_monitor.rb +98 -0
- data/lib/fluent/plugin/out_prometheus.rb +42 -0
- data/lib/fluent/plugin/prometheus/data_store.rb +93 -0
- data/lib/fluent/plugin/prometheus/placeholder_expander.rb +132 -0
- data/lib/fluent/plugin/prometheus.rb +418 -0
- data/lib/fluent/plugin/prometheus_metrics.rb +77 -0
- data/misc/fluentd_sample.conf +170 -0
- data/misc/nginx_proxy.conf +22 -0
- data/misc/prometheus.yaml +13 -0
- data/misc/prometheus_alerts.yaml +59 -0
- data/spec/fluent/plugin/filter_prometheus_spec.rb +118 -0
- data/spec/fluent/plugin/in_prometheus_monitor_spec.rb +42 -0
- data/spec/fluent/plugin/in_prometheus_spec.rb +225 -0
- data/spec/fluent/plugin/in_prometheus_tail_monitor_spec.rb +42 -0
- data/spec/fluent/plugin/out_prometheus_spec.rb +139 -0
- data/spec/fluent/plugin/prometheus/placeholder_expander_spec.rb +110 -0
- data/spec/fluent/plugin/prometheus_metrics_spec.rb +138 -0
- data/spec/fluent/plugin/shared.rb +248 -0
- data/spec/spec_helper.rb +10 -0
- metadata +176 -0
@@ -0,0 +1,225 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'fluent/plugin/in_prometheus'
|
3
|
+
require 'fluent/test/driver/input'
|
4
|
+
|
5
|
+
require 'net/http'
|
6
|
+
|
7
|
+
describe Fluent::Plugin::PrometheusInput do
|
8
|
+
CONFIG = %[
|
9
|
+
@type prometheus
|
10
|
+
]
|
11
|
+
|
12
|
+
LOCAL_CONFIG = %[
|
13
|
+
@type prometheus
|
14
|
+
bind 127.0.0.1
|
15
|
+
]
|
16
|
+
|
17
|
+
let(:config) { CONFIG }
|
18
|
+
let(:port) { 24231 }
|
19
|
+
let(:driver) { Fluent::Test::Driver::Input.new(Fluent::Plugin::PrometheusInput).configure(config) }
|
20
|
+
|
21
|
+
describe '#configure' do
|
22
|
+
describe 'bind' do
|
23
|
+
let(:config) { CONFIG + %[
|
24
|
+
bind 127.0.0.1
|
25
|
+
] }
|
26
|
+
it 'should be configurable' do
|
27
|
+
expect(driver.instance.bind).to eq('127.0.0.1')
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe 'port' do
|
32
|
+
let(:config) { CONFIG + %[
|
33
|
+
port 8888
|
34
|
+
] }
|
35
|
+
it 'should be configurable' do
|
36
|
+
expect(driver.instance.port).to eq(8888)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe 'metrics_path' do
|
41
|
+
let(:config) { CONFIG + %[
|
42
|
+
metrics_path /_test
|
43
|
+
] }
|
44
|
+
it 'should be configurable' do
|
45
|
+
expect(driver.instance.metrics_path).to eq('/_test')
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe '#start' do
|
51
|
+
context 'with transport section' do
|
52
|
+
let(:config) do
|
53
|
+
%[
|
54
|
+
@type prometheus
|
55
|
+
bind 127.0.0.1
|
56
|
+
<transport tls>
|
57
|
+
insecure true
|
58
|
+
</transport>
|
59
|
+
]
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'returns 200' do
|
63
|
+
driver.run(timeout: 1) do
|
64
|
+
Net::HTTP.start('127.0.0.1', port, verify_mode: OpenSSL::SSL::VERIFY_NONE, use_ssl: true) do |http|
|
65
|
+
req = Net::HTTP::Get.new('/metrics')
|
66
|
+
res = http.request(req)
|
67
|
+
expect(res.code).to eq('200')
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
context 'old parameters are given' do
|
74
|
+
context 'when extra_conf is used' do
|
75
|
+
let(:config) do
|
76
|
+
%[
|
77
|
+
@type prometheus
|
78
|
+
bind 127.0.0.1
|
79
|
+
<ssl>
|
80
|
+
enable true
|
81
|
+
extra_conf { "SSLCertName": [["CN", "nobody"], ["DC", "example"]] }
|
82
|
+
</ssl>
|
83
|
+
]
|
84
|
+
end
|
85
|
+
|
86
|
+
it 'uses webrick' do
|
87
|
+
expect(driver.instance).to receive(:start_webrick).once
|
88
|
+
driver.run(timeout: 1)
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'returns 200' do
|
92
|
+
driver.run(timeout: 1) do
|
93
|
+
Net::HTTP.start('127.0.0.1', port, verify_mode: OpenSSL::SSL::VERIFY_NONE, use_ssl: true) do |http|
|
94
|
+
req = Net::HTTP::Get.new('/metrics')
|
95
|
+
res = http.request(req)
|
96
|
+
expect(res.code).to eq('200')
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
context 'cert_path and private_key_path combination' do
|
103
|
+
let(:config) do
|
104
|
+
%[
|
105
|
+
@type prometheus
|
106
|
+
bind 127.0.0.1
|
107
|
+
<ssl>
|
108
|
+
enable true
|
109
|
+
certificate_path path
|
110
|
+
private_key_path path1
|
111
|
+
</ssl>
|
112
|
+
]
|
113
|
+
end
|
114
|
+
|
115
|
+
it 'converts them into new transport section' do
|
116
|
+
expect(driver.instance).to receive(:http_server_create_http_server).with(
|
117
|
+
:in_prometheus_server,
|
118
|
+
addr: anything,
|
119
|
+
logger: anything,
|
120
|
+
port: anything,
|
121
|
+
proto: :tls,
|
122
|
+
tls_opts: { 'cert_path' => 'path', 'private_key_path' => 'path1' }
|
123
|
+
).once
|
124
|
+
|
125
|
+
driver.run(timeout: 1)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
context 'insecure and ca_path' do
|
130
|
+
let(:config) do
|
131
|
+
%[
|
132
|
+
@type prometheus
|
133
|
+
bind 127.0.0.1
|
134
|
+
<ssl>
|
135
|
+
enable true
|
136
|
+
ca_path path
|
137
|
+
</ssl>
|
138
|
+
]
|
139
|
+
end
|
140
|
+
|
141
|
+
it 'converts them into new transport section' do
|
142
|
+
expect(driver.instance).to receive(:http_server_create_http_server).with(
|
143
|
+
:in_prometheus_server,
|
144
|
+
addr: anything,
|
145
|
+
logger: anything,
|
146
|
+
port: anything,
|
147
|
+
proto: :tls,
|
148
|
+
tls_opts: { 'ca_path' => 'path', 'insecure' => true }
|
149
|
+
).once
|
150
|
+
|
151
|
+
driver.run(timeout: 1)
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
context 'when only private_key_path is geven' do
|
156
|
+
let(:config) do
|
157
|
+
%[
|
158
|
+
@type prometheus
|
159
|
+
bind 127.0.0.1
|
160
|
+
<ssl>
|
161
|
+
enable true
|
162
|
+
private_key_path path
|
163
|
+
</ssl>
|
164
|
+
]
|
165
|
+
end
|
166
|
+
|
167
|
+
it 'raises ConfigError' do
|
168
|
+
expect { driver.run(timeout: 1) }.to raise_error(Fluent::ConfigError, 'both certificate_path and private_key_path must be defined')
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
describe '#run' do
|
175
|
+
context '/metrics' do
|
176
|
+
let(:config) { LOCAL_CONFIG }
|
177
|
+
it 'returns 200' do
|
178
|
+
driver.run(timeout: 1) do
|
179
|
+
Net::HTTP.start("127.0.0.1", port) do |http|
|
180
|
+
req = Net::HTTP::Get.new("/metrics")
|
181
|
+
res = http.request(req)
|
182
|
+
expect(res.code).to eq('200')
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
context '/foo' do
|
189
|
+
let(:config) { LOCAL_CONFIG }
|
190
|
+
it 'does not return 200' do
|
191
|
+
driver.run(timeout: 1) do
|
192
|
+
Net::HTTP.start("127.0.0.1", port) do |http|
|
193
|
+
req = Net::HTTP::Get.new("/foo")
|
194
|
+
res = http.request(req)
|
195
|
+
expect(res.code).not_to eq('200')
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
describe '#run_multi_workers' do
|
203
|
+
context '/metrics' do
|
204
|
+
Fluent::SystemConfig.overwrite_system_config('workers' => 4) do
|
205
|
+
let(:config) { CONFIG + %[
|
206
|
+
port #{port - 2}
|
207
|
+
] }
|
208
|
+
|
209
|
+
it 'should configure port using sequential number' do
|
210
|
+
driver = Fluent::Test::Driver::Input.new(Fluent::Plugin::PrometheusInput)
|
211
|
+
driver.instance.instance_eval{ @_fluentd_worker_id = 2 }
|
212
|
+
driver.configure(config)
|
213
|
+
expect(driver.instance.port).to eq(port)
|
214
|
+
driver.run(timeout: 1) do
|
215
|
+
Net::HTTP.start("127.0.0.1", port) do |http|
|
216
|
+
req = Net::HTTP::Get.new("/metrics")
|
217
|
+
res = http.request(req)
|
218
|
+
expect(res.code).to eq('200')
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
@@ -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
|
@@ -0,0 +1,139 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'fluent/test/driver/output'
|
3
|
+
require 'fluent/plugin/out_prometheus'
|
4
|
+
require_relative 'shared'
|
5
|
+
|
6
|
+
describe Fluent::Plugin::PrometheusOutput do
|
7
|
+
let(:tag) { 'prometheus.test' }
|
8
|
+
let(:driver) { Fluent::Test::Driver::Output.new(Fluent::Plugin::PrometheusOutput).configure(config) }
|
9
|
+
let(:registry) { ::Prometheus::Client::Registry.new }
|
10
|
+
|
11
|
+
before do
|
12
|
+
allow(Prometheus::Client).to receive(:registry).and_return(registry)
|
13
|
+
end
|
14
|
+
|
15
|
+
describe '#configure' do
|
16
|
+
it_behaves_like 'output configuration'
|
17
|
+
end
|
18
|
+
|
19
|
+
describe '#run' do
|
20
|
+
let(:message) { {"foo" => 100, "bar" => 100, "baz" => 100, "qux" => 10} }
|
21
|
+
|
22
|
+
context 'simple config' do
|
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
|
+
}
|
33
|
+
|
34
|
+
it 'adds a new counter metric' do
|
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])
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
it_behaves_like 'instruments record'
|
42
|
+
end
|
43
|
+
|
44
|
+
describe '#run with symbolized keys' do
|
45
|
+
let(:message) { {:foo => 100, :bar => 100, :baz => 100, :qux => 10} }
|
46
|
+
|
47
|
+
context 'simple config' do
|
48
|
+
let(:config) {
|
49
|
+
BASE_CONFIG + %(
|
50
|
+
<metric>
|
51
|
+
name simple
|
52
|
+
type counter
|
53
|
+
desc Something foo.
|
54
|
+
key foo
|
55
|
+
</metric>
|
56
|
+
)
|
57
|
+
}
|
58
|
+
|
59
|
+
it 'adds a new counter metric' do
|
60
|
+
expect(registry.metrics.map(&:name)).not_to eq([:simple])
|
61
|
+
driver.run(default_tag: tag) { driver.feed(event_time, message) }
|
62
|
+
expect(registry.metrics.map(&:name)).to eq([:simple])
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
it_behaves_like 'instruments record'
|
67
|
+
end
|
68
|
+
|
69
|
+
describe '#run with retention' do
|
70
|
+
let(:message) { { "foo" => 100, "bar" => 100, "baz" => 100, "qux" => 10 } }
|
71
|
+
let(:labels) { { :bar => 100, :baz => 100, :qux => 10 } }
|
72
|
+
|
73
|
+
context 'config with retention 1' do
|
74
|
+
let(:config) {
|
75
|
+
BASE_CONFIG + %(
|
76
|
+
<metric>
|
77
|
+
name simple
|
78
|
+
type counter
|
79
|
+
desc Something foo.
|
80
|
+
key foo
|
81
|
+
<labels>
|
82
|
+
bar ${bar}
|
83
|
+
baz ${baz}
|
84
|
+
qux ${qux}
|
85
|
+
</labels>
|
86
|
+
retention 1
|
87
|
+
retention_check_interval 1
|
88
|
+
</metric>
|
89
|
+
)
|
90
|
+
}
|
91
|
+
|
92
|
+
it 'expires metric after max 2s' do
|
93
|
+
expect(registry.metrics.map(&:name)).not_to eq([:simple])
|
94
|
+
driver.run(default_tag: tag) {
|
95
|
+
driver.feed(event_time, message)
|
96
|
+
expect(registry.metrics[0].get(labels: labels)).to eq(100)
|
97
|
+
sleep(2)
|
98
|
+
expect(registry.metrics[0].get(labels: labels)).to eq(0.0)
|
99
|
+
}
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
describe '#run with topk' do
|
105
|
+
let(:message1) { { "foo" => 200, "bar" => "a" } }
|
106
|
+
let(:message2) { { "foo" => 300, "bar" => "b" } }
|
107
|
+
let(:message3) { { "foo" => 100, "bar" => "c" } }
|
108
|
+
|
109
|
+
context 'config with retention 1' do
|
110
|
+
let(:config) {
|
111
|
+
BASE_CONFIG + %(
|
112
|
+
<metric>
|
113
|
+
name simple
|
114
|
+
type counter
|
115
|
+
desc Something foo.
|
116
|
+
key foo
|
117
|
+
<labels>
|
118
|
+
bar ${bar}
|
119
|
+
</labels>
|
120
|
+
topk 2
|
121
|
+
</metric>
|
122
|
+
)
|
123
|
+
}
|
124
|
+
|
125
|
+
it 'expires metric after max 2s' do
|
126
|
+
expect(registry.metrics.map(&:name)).not_to eq([:simple])
|
127
|
+
driver.run(default_tag: tag) {
|
128
|
+
driver.feed(event_time, message1)
|
129
|
+
driver.feed(event_time, message2)
|
130
|
+
driver.feed(event_time, message3)
|
131
|
+
}
|
132
|
+
expect(registry.metrics[0].values).to eq({
|
133
|
+
{ :bar => "a" } => 200,
|
134
|
+
{ :bar => "b" } => 300,
|
135
|
+
})
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
@@ -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
|
@@ -0,0 +1,138 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'fluent/plugin/in_prometheus'
|
3
|
+
require 'fluent/test/driver/input'
|
4
|
+
|
5
|
+
require 'net/http'
|
6
|
+
|
7
|
+
describe Fluent::Plugin::PromMetricsAggregator do
|
8
|
+
|
9
|
+
metrics_worker_1 = %[# TYPE fluentd_status_buffer_queue_length gauge
|
10
|
+
# HELP fluentd_status_buffer_queue_length Current buffer queue length.
|
11
|
+
fluentd_status_buffer_queue_length{host="0123456789ab",worker_id="0",plugin_id="plugin-1",plugin_category="output",type="s3"} 0.0
|
12
|
+
fluentd_status_buffer_queue_length{host="0123456789ab",worker_id="0",plugin_id="plugin-2",plugin_category="output",type="s3"} 0.0
|
13
|
+
# TYPE fluentd_status_buffer_total_bytes gauge
|
14
|
+
# HELP fluentd_status_buffer_total_bytes Current total size of queued buffers.
|
15
|
+
fluentd_status_buffer_total_bytes{host="0123456789ab",worker_id="0",plugin_id="plugin-1",plugin_category="output",type="s3"} 0.0
|
16
|
+
fluentd_status_buffer_total_bytes{host="0123456789ab",worker_id="0",plugin_id="plugin-2",plugin_category="output",type="s3"} 0.0
|
17
|
+
# TYPE log_counter counter
|
18
|
+
# HELP log_counter the number of received logs
|
19
|
+
log_counter{worker_id="0",host="0123456789ab",tag="fluent.info"} 1.0
|
20
|
+
# HELP empty_metric A metric with no data
|
21
|
+
# TYPE empty_metric gauge
|
22
|
+
# HELP http_request_duration_seconds The HTTP request latencies in seconds.
|
23
|
+
# TYPE http_request_duration_seconds histogram
|
24
|
+
http_request_duration_seconds_bucket{code="200",worker_id="0",method="GET",le="0.005"} 58
|
25
|
+
http_request_duration_seconds_bucket{code="200",worker_id="0",method="GET",le="0.01"} 58
|
26
|
+
http_request_duration_seconds_bucket{code="200",worker_id="0",method="GET",le="0.05"} 59
|
27
|
+
http_request_duration_seconds_bucket{code="200",worker_id="0",method="GET",le="0.1"} 59
|
28
|
+
http_request_duration_seconds_bucket{code="200",worker_id="0",method="GET",le="1"} 59
|
29
|
+
http_request_duration_seconds_bucket{code="200",worker_id="0",method="GET",le="10"} 59
|
30
|
+
http_request_duration_seconds_bucket{code="200",worker_id="0",method="GET",le="+Inf"} 59
|
31
|
+
http_request_duration_seconds_sum{code="200",worker_id="0",method="GET"} 0.05046115500000003
|
32
|
+
http_request_duration_seconds_count{code="200",worker_id="0",method="GET"} 59
|
33
|
+
]
|
34
|
+
|
35
|
+
metrics_worker_2 = %[# TYPE fluentd_output_status_buffer_queue_length gauge
|
36
|
+
# HELP fluentd_output_status_buffer_queue_length Current buffer queue length.
|
37
|
+
fluentd_output_status_buffer_queue_length{host="0123456789ab",worker_id="0",plugin_id="plugin-1",type="s3"} 0.0
|
38
|
+
fluentd_output_status_buffer_queue_length{host="0123456789ab",worker_id="0",plugin_id="plugin-2",type="s3"} 0.0
|
39
|
+
# TYPE fluentd_output_status_buffer_total_bytes gauge
|
40
|
+
# HELP fluentd_output_status_buffer_total_bytes Current total size of queued buffers.
|
41
|
+
fluentd_output_status_buffer_total_bytes{host="0123456789ab",worker_id="0",plugin_id="plugin-1",type="s3"} 0.0
|
42
|
+
fluentd_output_status_buffer_total_bytes{host="0123456789ab",worker_id="0",plugin_id="plugin-2",type="s3"} 0.0
|
43
|
+
]
|
44
|
+
|
45
|
+
metrics_worker_3 = %[# TYPE fluentd_status_buffer_queue_length gauge
|
46
|
+
# HELP fluentd_status_buffer_queue_length Current buffer queue length.
|
47
|
+
fluentd_status_buffer_queue_length{host="0123456789ab",worker_id="1",plugin_id="plugin-1",plugin_category="output",type="s3"} 0.0
|
48
|
+
fluentd_status_buffer_queue_length{host="0123456789ab",worker_id="1",plugin_id="plugin-2",plugin_category="output",type="s3"} 0.0
|
49
|
+
# TYPE fluentd_status_buffer_total_bytes gauge
|
50
|
+
# HELP fluentd_status_buffer_total_bytes Current total size of queued buffers.
|
51
|
+
fluentd_status_buffer_total_bytes{host="0123456789ab",worker_id="1",plugin_id="plugin-1",plugin_category="output",type="s3"} 0.0
|
52
|
+
fluentd_status_buffer_total_bytes{host="0123456789ab",worker_id="1",plugin_id="plugin-2",plugin_category="output",type="s3"} 0.0
|
53
|
+
# HELP http_request_duration_seconds The HTTP request latencies in seconds.
|
54
|
+
# TYPE http_request_duration_seconds histogram
|
55
|
+
http_request_duration_seconds_bucket{code="200",worker_id="1",method="GET",le="0.005"} 70
|
56
|
+
http_request_duration_seconds_bucket{code="200",worker_id="1",method="GET",le="0.01"} 70
|
57
|
+
http_request_duration_seconds_bucket{code="200",worker_id="1",method="GET",le="0.05"} 71
|
58
|
+
http_request_duration_seconds_bucket{code="200",worker_id="1",method="GET",le="0.1"} 71
|
59
|
+
http_request_duration_seconds_bucket{code="200",worker_id="1",method="GET",le="1"} 71
|
60
|
+
http_request_duration_seconds_bucket{code="200",worker_id="1",method="GET",le="10"} 71
|
61
|
+
http_request_duration_seconds_bucket{code="200",worker_id="1",method="GET",le="+Inf"} 71
|
62
|
+
http_request_duration_seconds_sum{code="200",worker_id="1",method="GET"} 0.05646315600000003
|
63
|
+
http_request_duration_seconds_count{code="200",worker_id="1",method="GET"} 71
|
64
|
+
]
|
65
|
+
|
66
|
+
metrics_merged_1_and_3 = %[# TYPE fluentd_status_buffer_queue_length gauge
|
67
|
+
# HELP fluentd_status_buffer_queue_length Current buffer queue length.
|
68
|
+
fluentd_status_buffer_queue_length{host="0123456789ab",worker_id="0",plugin_id="plugin-1",plugin_category="output",type="s3"} 0.0
|
69
|
+
fluentd_status_buffer_queue_length{host="0123456789ab",worker_id="0",plugin_id="plugin-2",plugin_category="output",type="s3"} 0.0
|
70
|
+
fluentd_status_buffer_queue_length{host="0123456789ab",worker_id="1",plugin_id="plugin-1",plugin_category="output",type="s3"} 0.0
|
71
|
+
fluentd_status_buffer_queue_length{host="0123456789ab",worker_id="1",plugin_id="plugin-2",plugin_category="output",type="s3"} 0.0
|
72
|
+
# TYPE fluentd_status_buffer_total_bytes gauge
|
73
|
+
# HELP fluentd_status_buffer_total_bytes Current total size of queued buffers.
|
74
|
+
fluentd_status_buffer_total_bytes{host="0123456789ab",worker_id="0",plugin_id="plugin-1",plugin_category="output",type="s3"} 0.0
|
75
|
+
fluentd_status_buffer_total_bytes{host="0123456789ab",worker_id="0",plugin_id="plugin-2",plugin_category="output",type="s3"} 0.0
|
76
|
+
fluentd_status_buffer_total_bytes{host="0123456789ab",worker_id="1",plugin_id="plugin-1",plugin_category="output",type="s3"} 0.0
|
77
|
+
fluentd_status_buffer_total_bytes{host="0123456789ab",worker_id="1",plugin_id="plugin-2",plugin_category="output",type="s3"} 0.0
|
78
|
+
# TYPE log_counter counter
|
79
|
+
# HELP log_counter the number of received logs
|
80
|
+
log_counter{worker_id="0",host="0123456789ab",tag="fluent.info"} 1.0
|
81
|
+
# HELP empty_metric A metric with no data
|
82
|
+
# TYPE empty_metric gauge
|
83
|
+
# HELP http_request_duration_seconds The HTTP request latencies in seconds.
|
84
|
+
# TYPE http_request_duration_seconds histogram
|
85
|
+
http_request_duration_seconds_bucket{code="200",worker_id="0",method="GET",le="0.005"} 58
|
86
|
+
http_request_duration_seconds_bucket{code="200",worker_id="0",method="GET",le="0.01"} 58
|
87
|
+
http_request_duration_seconds_bucket{code="200",worker_id="0",method="GET",le="0.05"} 59
|
88
|
+
http_request_duration_seconds_bucket{code="200",worker_id="0",method="GET",le="0.1"} 59
|
89
|
+
http_request_duration_seconds_bucket{code="200",worker_id="0",method="GET",le="1"} 59
|
90
|
+
http_request_duration_seconds_bucket{code="200",worker_id="0",method="GET",le="10"} 59
|
91
|
+
http_request_duration_seconds_bucket{code="200",worker_id="0",method="GET",le="+Inf"} 59
|
92
|
+
http_request_duration_seconds_sum{code="200",worker_id="0",method="GET"} 0.05046115500000003
|
93
|
+
http_request_duration_seconds_count{code="200",worker_id="0",method="GET"} 59
|
94
|
+
http_request_duration_seconds_bucket{code="200",worker_id="1",method="GET",le="0.005"} 70
|
95
|
+
http_request_duration_seconds_bucket{code="200",worker_id="1",method="GET",le="0.01"} 70
|
96
|
+
http_request_duration_seconds_bucket{code="200",worker_id="1",method="GET",le="0.05"} 71
|
97
|
+
http_request_duration_seconds_bucket{code="200",worker_id="1",method="GET",le="0.1"} 71
|
98
|
+
http_request_duration_seconds_bucket{code="200",worker_id="1",method="GET",le="1"} 71
|
99
|
+
http_request_duration_seconds_bucket{code="200",worker_id="1",method="GET",le="10"} 71
|
100
|
+
http_request_duration_seconds_bucket{code="200",worker_id="1",method="GET",le="+Inf"} 71
|
101
|
+
http_request_duration_seconds_sum{code="200",worker_id="1",method="GET"} 0.05646315600000003
|
102
|
+
http_request_duration_seconds_count{code="200",worker_id="1",method="GET"} 71
|
103
|
+
]
|
104
|
+
|
105
|
+
describe 'add_metrics' do
|
106
|
+
context '1st_metrics' do
|
107
|
+
it 'adds all fields' do
|
108
|
+
all_metrics = Fluent::Plugin::PromMetricsAggregator.new
|
109
|
+
all_metrics.add_metrics(metrics_worker_1)
|
110
|
+
result_str = all_metrics.get_metrics
|
111
|
+
|
112
|
+
expect(result_str).to eq(metrics_worker_1)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
context '2nd_metrics' do
|
116
|
+
it 'append new metrics' do
|
117
|
+
all_metrics = Fluent::Plugin::PromMetricsAggregator.new
|
118
|
+
all_metrics.add_metrics(metrics_worker_1)
|
119
|
+
all_metrics.add_metrics(metrics_worker_2)
|
120
|
+
result_str = all_metrics.get_metrics
|
121
|
+
|
122
|
+
expect(result_str).to eq(metrics_worker_1 + metrics_worker_2)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
context '3rd_metrics' do
|
127
|
+
it 'append existing metrics in the right place' do
|
128
|
+
all_metrics = Fluent::Plugin::PromMetricsAggregator.new
|
129
|
+
all_metrics.add_metrics(metrics_worker_1)
|
130
|
+
all_metrics.add_metrics(metrics_worker_2)
|
131
|
+
all_metrics.add_metrics(metrics_worker_3)
|
132
|
+
result_str = all_metrics.get_metrics
|
133
|
+
|
134
|
+
expect(result_str).to eq(metrics_merged_1_and_3 + metrics_worker_2)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|