phihos-fluent-plugin-prometheus 2.0.3.pre.1
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 +50 -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 +49 -0
- data/lib/fluent/plugin/prometheus/data_store.rb +103 -0
- data/lib/fluent/plugin/prometheus/placeholder_expander.rb +132 -0
- data/lib/fluent/plugin/prometheus.rb +445 -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 +145 -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 +166 -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,13 @@
|
|
1
|
+
# A job to scrape an endpoint of Fluentd running on localhost.
|
2
|
+
scrape_configs:
|
3
|
+
- job_name: 'prometheus'
|
4
|
+
scrape_interval: 5s
|
5
|
+
static_configs:
|
6
|
+
- targets:
|
7
|
+
- 'localhost:9090'
|
8
|
+
- job_name: fluentd
|
9
|
+
scrape_interval: 5s
|
10
|
+
static_configs:
|
11
|
+
- targets:
|
12
|
+
- 'localhost:24231'
|
13
|
+
metrics_path: /metrics
|
@@ -0,0 +1,59 @@
|
|
1
|
+
ALERT FluentdNodeDown
|
2
|
+
IF up{job="fluentd"} == 0
|
3
|
+
FOR 10m
|
4
|
+
LABELS {
|
5
|
+
service = "fluentd",
|
6
|
+
severity = "warning"
|
7
|
+
}
|
8
|
+
ANNOTATIONS {
|
9
|
+
summary = "fluentd cannot be scraped",
|
10
|
+
description = "Prometheus could not scrape {{ $labels.job }} for more than 10 minutes",
|
11
|
+
}
|
12
|
+
|
13
|
+
ALERT FluentdNodeDown
|
14
|
+
IF up{job="fluentd"} == 0
|
15
|
+
FOR 30m
|
16
|
+
LABELS {
|
17
|
+
service = "fluentd",
|
18
|
+
severity = "critical"
|
19
|
+
}
|
20
|
+
ANNOTATIONS {
|
21
|
+
summary = "fluentd cannot be scraped",
|
22
|
+
description = "Prometheus could not scrape {{ $labels.job }} for more than 30 minutes",
|
23
|
+
}
|
24
|
+
|
25
|
+
ALERT FluentdQueueLength
|
26
|
+
IF rate(fluentd_status_buffer_queue_length[5m]) > 0.3
|
27
|
+
FOR 1m
|
28
|
+
LABELS {
|
29
|
+
service = "fluentd",
|
30
|
+
severity = "warning"
|
31
|
+
}
|
32
|
+
ANNOTATIONS {
|
33
|
+
summary = "fluentd node are failing",
|
34
|
+
description = "In the last 5 minutes, fluentd queues increased 30%. Current value is {{ $value }} ",
|
35
|
+
}
|
36
|
+
|
37
|
+
ALERT FluentdQueueLength
|
38
|
+
IF rate(fluentd_status_buffer_queue_length[5m]) > 0.5
|
39
|
+
FOR 1m
|
40
|
+
LABELS {
|
41
|
+
service = "fluentd",
|
42
|
+
severity = "critical"
|
43
|
+
}
|
44
|
+
ANNOTATIONS {
|
45
|
+
summary = "fluentd node are critical",
|
46
|
+
description = "In the last 5 minutes, fluentd queues increased 50%. Current value is {{ $value }} ",
|
47
|
+
}
|
48
|
+
|
49
|
+
ALERT FluentdRecordsCountsHigh
|
50
|
+
IF sum(rate(fluentd_output_status_emit_records{job="fluentd"}[5m])) BY (instance) > (3 * sum(rate(fluentd_output_status_emit_records{job="fluentd"}[15m])) BY (instance))
|
51
|
+
FOR 1m
|
52
|
+
LABELS {
|
53
|
+
service = "fluentd",
|
54
|
+
severity = "critical"
|
55
|
+
}
|
56
|
+
ANNOTATIONS {
|
57
|
+
summary = "fluentd records count are critical",
|
58
|
+
description = "In the last 5m, records counts increased 3 times, comparing to the latest 15 min.",
|
59
|
+
}
|
@@ -0,0 +1,145 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'fluent/test/driver/filter'
|
3
|
+
require 'fluent/plugin/filter_prometheus'
|
4
|
+
require_relative 'shared'
|
5
|
+
|
6
|
+
describe Fluent::Plugin::PrometheusFilter do
|
7
|
+
let(:tag) { 'prometheus.test' }
|
8
|
+
let(:driver) { Fluent::Test::Driver::Filter.new(Fluent::Plugin::PrometheusFilter).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
|
+
|
40
|
+
it 'should keep original message' do
|
41
|
+
driver.run(default_tag: tag) { driver.feed(event_time, message) }
|
42
|
+
expect(driver.filtered_records.first).to eq(message)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
it_behaves_like 'instruments record'
|
47
|
+
end
|
48
|
+
|
49
|
+
describe '#run with retention' do
|
50
|
+
let(:message) { { "foo" => 100, "bar" => 100, "baz" => 100, "qux" => 10 } }
|
51
|
+
|
52
|
+
context 'config with retention 1' do
|
53
|
+
let(:config) {
|
54
|
+
BASE_CONFIG + %(
|
55
|
+
<metric>
|
56
|
+
name simple
|
57
|
+
type counter
|
58
|
+
desc Something foo.
|
59
|
+
key foo
|
60
|
+
<labels>
|
61
|
+
bar ${bar}
|
62
|
+
baz ${baz}
|
63
|
+
qux ${qux}
|
64
|
+
</labels>
|
65
|
+
retention 1
|
66
|
+
retention_check_interval 1
|
67
|
+
</metric>
|
68
|
+
)
|
69
|
+
}
|
70
|
+
|
71
|
+
it 'expires metric after max 2s' do
|
72
|
+
expect(registry.metrics.map(&:name)).not_to eq([:simple])
|
73
|
+
driver.run(default_tag: tag) {
|
74
|
+
driver.feed(event_time, message)
|
75
|
+
expect(registry.metrics[0].get(labels: { :bar => 100, :baz => 100, :qux => 10 })).to eq(100)
|
76
|
+
sleep(2)
|
77
|
+
expect(registry.metrics[0].get(labels: { :bar => 100, :baz => 100, :qux => 10 })).to eq(0.0)
|
78
|
+
}
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
describe '#run with topk' do
|
84
|
+
let(:message1) { { "foo" => 200, "bar" => "a" } }
|
85
|
+
let(:message2) { { "foo" => 300, "bar" => "b" } }
|
86
|
+
let(:message3) { { "foo" => 100, "bar" => "c" } }
|
87
|
+
|
88
|
+
context 'config with topk 2' do
|
89
|
+
let(:config) {
|
90
|
+
BASE_CONFIG + %(
|
91
|
+
<metric>
|
92
|
+
name simple
|
93
|
+
type counter
|
94
|
+
desc Something foo.
|
95
|
+
key foo
|
96
|
+
<labels>
|
97
|
+
bar ${bar}
|
98
|
+
</labels>
|
99
|
+
topk 2
|
100
|
+
</metric>
|
101
|
+
)
|
102
|
+
}
|
103
|
+
|
104
|
+
it 'shows only top 2 metrics' do
|
105
|
+
expect(registry.metrics.map(&:name)).not_to eq([:simple])
|
106
|
+
driver.run(default_tag: tag) {
|
107
|
+
driver.feed(event_time, message1)
|
108
|
+
driver.feed(event_time, message2)
|
109
|
+
driver.feed(event_time, message3)
|
110
|
+
}
|
111
|
+
expect(registry.metrics[0].values).to eq({
|
112
|
+
{ :bar => "a" } => 200,
|
113
|
+
{ :bar => "b" } => 300,
|
114
|
+
})
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
describe '#run with reset_after' do
|
120
|
+
let(:message) { { "foo" => 100 } }
|
121
|
+
|
122
|
+
context 'config with reset_after 1' do
|
123
|
+
let(:config) {
|
124
|
+
BASE_CONFIG + %(
|
125
|
+
<metric>
|
126
|
+
name simple
|
127
|
+
type counter
|
128
|
+
desc Something foo.
|
129
|
+
key foo
|
130
|
+
reset_after 1
|
131
|
+
</metric>
|
132
|
+
)
|
133
|
+
}
|
134
|
+
|
135
|
+
it 'resets metric values after max 2s' do
|
136
|
+
expect(registry.metrics.map(&:name)).not_to eq([:simple])
|
137
|
+
driver.run(default_tag: tag) {
|
138
|
+
driver.feed(event_time, message)
|
139
|
+
sleep(2)
|
140
|
+
}
|
141
|
+
expect(registry.metrics[0].values).to eq({ {} => 0 })
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'fluent/plugin/in_prometheus_monitor'
|
3
|
+
require 'fluent/test/driver/input'
|
4
|
+
|
5
|
+
describe Fluent::Plugin::PrometheusMonitorInput do
|
6
|
+
MONITOR_CONFIG = %[
|
7
|
+
@type prometheus_monitor
|
8
|
+
<labels>
|
9
|
+
host ${hostname}
|
10
|
+
foo bar
|
11
|
+
</labels>
|
12
|
+
]
|
13
|
+
|
14
|
+
INVALID_MONITOR_CONFIG = %[
|
15
|
+
@type prometheus_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::PrometheusMonitorInput).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,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,166 @@
|
|
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 topk 2' 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 'shows only top 2 metrics' 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
|
+
|
140
|
+
describe '#run with reset_after' do
|
141
|
+
let(:message) { { "foo" => 100 } }
|
142
|
+
|
143
|
+
context 'config with reset_after 1' do
|
144
|
+
let(:config) {
|
145
|
+
BASE_CONFIG + %(
|
146
|
+
<metric>
|
147
|
+
name simple
|
148
|
+
type counter
|
149
|
+
desc Something foo.
|
150
|
+
key foo
|
151
|
+
reset_after 1
|
152
|
+
</metric>
|
153
|
+
)
|
154
|
+
}
|
155
|
+
|
156
|
+
it 'resets metric values after max 2s' do
|
157
|
+
expect(registry.metrics.map(&:name)).not_to eq([:simple])
|
158
|
+
driver.run(default_tag: tag) {
|
159
|
+
driver.feed(event_time, message)
|
160
|
+
sleep(2)
|
161
|
+
}
|
162
|
+
expect(registry.metrics[0].values).to eq({ {} => 0 })
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|