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.
Files changed (36) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/linux.yml +34 -0
  3. data/.gitignore +16 -0
  4. data/.rspec +2 -0
  5. data/.travis.yml +14 -0
  6. data/ChangeLog +43 -0
  7. data/Gemfile +4 -0
  8. data/LICENSE +202 -0
  9. data/README.md +537 -0
  10. data/Rakefile +7 -0
  11. data/fluent-plugin-prometheus.gemspec +22 -0
  12. data/lib/fluent/plugin/filter_prometheus.rb +43 -0
  13. data/lib/fluent/plugin/in_prometheus/async_wrapper.rb +47 -0
  14. data/lib/fluent/plugin/in_prometheus.rb +230 -0
  15. data/lib/fluent/plugin/in_prometheus_monitor.rb +107 -0
  16. data/lib/fluent/plugin/in_prometheus_output_monitor.rb +234 -0
  17. data/lib/fluent/plugin/in_prometheus_tail_monitor.rb +98 -0
  18. data/lib/fluent/plugin/out_prometheus.rb +42 -0
  19. data/lib/fluent/plugin/prometheus/data_store.rb +93 -0
  20. data/lib/fluent/plugin/prometheus/placeholder_expander.rb +132 -0
  21. data/lib/fluent/plugin/prometheus.rb +418 -0
  22. data/lib/fluent/plugin/prometheus_metrics.rb +77 -0
  23. data/misc/fluentd_sample.conf +170 -0
  24. data/misc/nginx_proxy.conf +22 -0
  25. data/misc/prometheus.yaml +13 -0
  26. data/misc/prometheus_alerts.yaml +59 -0
  27. data/spec/fluent/plugin/filter_prometheus_spec.rb +118 -0
  28. data/spec/fluent/plugin/in_prometheus_monitor_spec.rb +42 -0
  29. data/spec/fluent/plugin/in_prometheus_spec.rb +225 -0
  30. data/spec/fluent/plugin/in_prometheus_tail_monitor_spec.rb +42 -0
  31. data/spec/fluent/plugin/out_prometheus_spec.rb +139 -0
  32. data/spec/fluent/plugin/prometheus/placeholder_expander_spec.rb +110 -0
  33. data/spec/fluent/plugin/prometheus_metrics_spec.rb +138 -0
  34. data/spec/fluent/plugin/shared.rb +248 -0
  35. data/spec/spec_helper.rb +10 -0
  36. 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