fluent-plugin-prometheus 1.7.3 → 1.8.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1f14f2b2162bace2a18a80f885df28261ed260a7b8e865a12e7828d46af9b02f
4
- data.tar.gz: 20749cd6ee743ac3726719e654e1a4f046aa2f953245604e6aa75cd87ed00e62
3
+ metadata.gz: 3f98778420f98da85a1325661e897dce930a9eaec03675f3112ca9223a8435a4
4
+ data.tar.gz: 864fd85893d2cbe49c2aa5d8e59026405098d9075e54499cbe3efc8e30025a3d
5
5
  SHA512:
6
- metadata.gz: 28ca37140a4b634665a9ba184c1615380bc7c458ed745d5548cb75b92d75d3b1069cd342d3119785a11d1beb369e7b41b5fa0319021bb0f69400ffe327dea83e
7
- data.tar.gz: b04770fec96856fc37b6943c7129c5e8ef16ce8b1415b425932e4419594e58a3255406de54e3aad1c28af1e3d62074391bd2b40e4aded8b5f598fbece53cab82
6
+ metadata.gz: ae6ec1075cf1fa4ab375a888c0a37c2653cf067e25a87b588ef5b5a332aa090cb1794b9add155314e4b867a188cca55450b064ea04ec99cb9299ad2fcfbde37b
7
+ data.tar.gz: c0d269902c7efff6fe7cb153c853fc17eaf9b0a740994ece3701854308fff45af2fa906c17efa2d0af32f882dfdcdd40340c5f3b8ad21a58469655104064a0c1
data/README.md CHANGED
@@ -8,9 +8,13 @@ A fluent plugin that instruments metrics from records and exposes them via web i
8
8
 
9
9
  | fluent-plugin-prometheus | fluentd | ruby |
10
10
  |--------------------------|------------|--------|
11
- | 1.x.y | >= v0.14.8 | >= 2.1 |
11
+ | 1.x.y | >= v1.9.1 | >= 2.4 |
12
+ | 1.[0-7].y | >= v0.14.8 | >= 2.1 |
12
13
  | 0.x.y | >= v0.12.0 | >= 1.9 |
13
14
 
15
+ Since v1.8.0, fluent-plugin-prometheus uses [http_server helper](https://docs.fluentd.org/plugin-helper-overview/api-plugin-helper-http_server) to launch HTTP server.
16
+ If you want to handle lots of connections, install `async-http` gem.
17
+
14
18
  ## Installation
15
19
 
16
20
  Add this line to your application's Gemfile:
@@ -63,6 +67,19 @@ More configuration parameters:
63
67
  When using multiple workers, each worker binds to port + `fluent_worker_id`.
64
68
  To scrape metrics from all workers at once, you can access http://localhost:24231/aggregated_metrics.
65
69
 
70
+ #### TLS setting
71
+
72
+ Use `<trasnport tls>`. See [transport config article](https://docs.fluentd.org/configuration/transport-section) for more details.
73
+
74
+ ```
75
+ <source>
76
+ @type prometheus
77
+ <transport tls>
78
+ # TLS parameters...
79
+ </transport
80
+ </source>
81
+ ```
82
+
66
83
  ### prometheus_monitor input plugin
67
84
 
68
85
  This plugin collects internal metrics in Fluentd. The metrics are similar to/part of [monitor_agent](https://docs.fluentd.org/input/monitor_agent).
@@ -71,7 +88,7 @@ This plugin collects internal metrics in Fluentd. The metrics are similar to/par
71
88
  #### Exposed metrics
72
89
 
73
90
  - `fluentd_status_buffer_queue_length`
74
- - `fluentd_status_buffer_total_queued_size`
91
+ - `fluentd_status_buffer_total_bytes`
75
92
  - `fluentd_status_retry_count`
76
93
  - `fluentd_status_buffer_newest_timekey` from fluentd v1.4.2
77
94
  - `fluentd_status_buffer_oldest_timekey` from fluentd v1.4.2
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |spec|
2
2
  spec.name = "fluent-plugin-prometheus"
3
- spec.version = "1.7.3"
3
+ spec.version = "1.8.0"
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.}
@@ -13,7 +13,7 @@ Gem::Specification.new do |spec|
13
13
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
14
14
  spec.require_paths = ["lib"]
15
15
 
16
- spec.add_dependency "fluentd", ">= 0.14.20", "< 2"
16
+ spec.add_dependency "fluentd", ">= 1.9.1", "< 2"
17
17
  spec.add_dependency "prometheus-client", "< 0.10"
18
18
  spec.add_development_dependency "bundler"
19
19
  spec.add_development_dependency "rake"
@@ -2,13 +2,13 @@ require 'fluent/plugin/input'
2
2
  require 'fluent/plugin/prometheus'
3
3
  require 'fluent/plugin/prometheus_metrics'
4
4
  require 'net/http'
5
- require 'webrick'
5
+ require 'openssl'
6
6
 
7
7
  module Fluent::Plugin
8
8
  class PrometheusInput < Fluent::Plugin::Input
9
9
  Fluent::Plugin.register_input('prometheus', self)
10
10
 
11
- helpers :thread
11
+ helpers :thread, :http_server
12
12
 
13
13
  config_param :bind, :string, default: '0.0.0.0'
14
14
  config_param :port, :integer, default: 24231
@@ -17,30 +17,25 @@ module Fluent::Plugin
17
17
 
18
18
  desc 'Enable ssl configuration for the server'
19
19
  config_section :ssl, required: false, multi: false do
20
- config_param :enable, :bool, default: false
20
+ config_param :enable, :bool, default: false, deprecated: 'Use <transport tls> section'
21
21
 
22
22
  desc 'Path to the ssl certificate in PEM format. Read from file and added to conf as "SSLCertificate"'
23
- config_param :certificate_path, :string, default: nil
23
+ config_param :certificate_path, :string, default: nil, deprecated: 'Use cert_path in <transport tls> section'
24
24
 
25
25
  desc 'Path to the ssl private key in PEM format. Read from file and added to conf as "SSLPrivateKey"'
26
- config_param :private_key_path, :string, default: nil
26
+ config_param :private_key_path, :string, default: nil, deprecated: 'Use private_key_path in <transport tls> section'
27
27
 
28
28
  desc 'Path to CA in PEM format. Read from file and added to conf as "SSLCACertificateFile"'
29
- config_param :ca_path, :string, default: nil
29
+ config_param :ca_path, :string, default: nil, deprecated: 'Use ca_path in <transport tls> section'
30
30
 
31
31
  desc 'Additional ssl conf for the server. Ref: https://github.com/ruby/webrick/blob/master/lib/webrick/ssl.rb'
32
- config_param :extra_conf, :hash, default: {:SSLCertName => [['CN','nobody'],['DC','example']]}, symbolize_keys: true
32
+ config_param :extra_conf, :hash, default: nil, symbolize_keys: true, deprecated: 'See http helper config'
33
33
  end
34
34
 
35
- attr_reader :registry
36
-
37
- attr_reader :num_workers
38
- attr_reader :base_port
39
- attr_reader :metrics_path
40
-
41
35
  def initialize
42
36
  super
43
37
  @registry = ::Prometheus::Client.registry
38
+ @secure = nil
44
39
  end
45
40
 
46
41
  def configure(conf)
@@ -55,6 +50,7 @@ module Fluent::Plugin
55
50
  nil
56
51
  end
57
52
  @num_workers = sysconf && sysconf.workers ? sysconf.workers : 1
53
+ @secure = @transport_config.protocol == :tls || (@ssl && @ssl['enable'])
58
54
 
59
55
  @base_port = @port
60
56
  @port += fluentd_worker_id
@@ -66,7 +62,63 @@ module Fluent::Plugin
66
62
 
67
63
  def start
68
64
  super
69
- log.debug "listening prometheus http server on http://#{@bind}:#{@port}/#{@metrics_path} for worker#{fluentd_worker_id}"
65
+
66
+ scheme = @secure ? 'https' : 'http'
67
+ log.debug "listening prometheus http server on #{scheme}:://#{@bind}:#{@port}/#{@metrics_path} for worker#{fluentd_worker_id}"
68
+
69
+ proto = @secure ? :tls : :tcp
70
+
71
+ if @ssl && @ssl['enable'] && @ssl['extra_conf']
72
+ start_webrick
73
+ return
74
+ end
75
+
76
+ tls_opt = if @ssl && @ssl['enable']
77
+ ssl_config = {}
78
+
79
+ if (@ssl['certificate_path'] && @ssl['private_key_path'].nil?) || (@ssl['certificate_path'].nil? && @ssl['private_key_path'])
80
+ raise Fluent::ConfigError.new('both certificate_path and private_key_path must be defined')
81
+ end
82
+
83
+ if @ssl['certificate_path']
84
+ ssl_config['cert_path'] = @ssl['certificate_path']
85
+ end
86
+
87
+ if @ssl['private_key_path']
88
+ ssl_config['private_key_path'] = @ssl['private_key_path']
89
+ end
90
+
91
+ if @ssl['ca_path']
92
+ ssl_config['ca_path'] = @ssl['ca_path']
93
+ # Only ca_path is insecure in fluentd
94
+ # https://github.com/fluent/fluentd/blob/2236ad45197ba336fd9faf56f442252c8b226f25/lib/fluent/plugin_helper/cert_option.rb#L68
95
+ ssl_config['insecure'] = true
96
+ end
97
+
98
+ ssl_config
99
+ end
100
+
101
+ http_server_create_http_server(:in_prometheus_server, addr: @bind, port: @port, logger: log, proto: proto, tls_opts: tls_opt) do |server|
102
+ server.get(@metrics_path) { |_req| all_metrics }
103
+ server.get(@aggregated_metrics_path) { |_req| all_workers_metrics }
104
+ end
105
+ end
106
+
107
+ def shutdown
108
+ if @webrick_server
109
+ @webrick_server.shutdown
110
+ @webrick_server = nil
111
+ end
112
+ super
113
+ end
114
+
115
+ private
116
+
117
+ # For compatiblity because http helper can't support extra_conf option
118
+ def start_webrick
119
+ require 'webrick/https'
120
+ require 'webrick'
121
+
70
122
  config = {
71
123
  BindAddress: @bind,
72
124
  Port: @port,
@@ -74,90 +126,96 @@ module Fluent::Plugin
74
126
  Logger: WEBrick::Log.new(STDERR, WEBrick::Log::FATAL),
75
127
  AccessLog: [],
76
128
  }
77
- unless @ssl.nil? || !@ssl['enable']
78
- require 'webrick/https'
79
- require 'openssl'
80
- if (@ssl['certificate_path'] && @ssl['private_key_path'].nil?) || (@ssl['certificate_path'].nil? && @ssl['private_key_path'])
81
- raise RuntimeError.new("certificate_path and private_key_path most both be defined")
82
- end
83
- ssl_config = {
84
- SSLEnable: true
85
- }
86
- if @ssl['certificate_path']
87
- cert = OpenSSL::X509::Certificate.new(File.read(@ssl['certificate_path']))
88
- ssl_config[:SSLCertificate] = cert
89
- end
90
- if @ssl['private_key_path']
91
- key = OpenSSL::PKey::RSA.new(File.read(@ssl['private_key_path']))
92
- ssl_config[:SSLPrivateKey] = key
93
- end
94
- ssl_config[:SSLCACertificateFile] = @ssl['ca_path'] if @ssl['ca_path']
95
- ssl_config = ssl_config.merge(@ssl['extra_conf'])
96
- config = ssl_config.merge(config)
129
+ if (@ssl['certificate_path'] && @ssl['private_key_path'].nil?) || (@ssl['certificate_path'].nil? && @ssl['private_key_path'])
130
+ raise RuntimeError.new("certificate_path and private_key_path most both be defined")
131
+ end
132
+
133
+ ssl_config = {
134
+ SSLEnable: true,
135
+ SSLCertName: [['CN', 'nobody'], ['DC', 'example']]
136
+ }
137
+
138
+ if @ssl['certificate_path']
139
+ cert = OpenSSL::X509::Certificate.new(File.read(@ssl['certificate_path']))
140
+ ssl_config[:SSLCertificate] = cert
97
141
  end
142
+
143
+ if @ssl['private_key_path']
144
+ key = OpenSSL::PKey.read(@ssl['private_key_path'])
145
+ ssl_config[:SSLPrivateKey] = key
146
+ end
147
+
148
+ ssl_config[:SSLCACertificateFile] = @ssl['ca_path'] if @ssl['ca_path']
149
+ ssl_config = ssl_config.merge(@ssl['extra_conf']) if @ssl['extra_conf']
150
+ config = ssl_config.merge(config)
151
+
98
152
  @log.on_debug do
99
153
  @log.debug("WEBrick conf: #{config}")
100
154
  end
101
155
 
102
- @server = WEBrick::HTTPServer.new(config)
103
- @server.mount(@metrics_path, MonitorServlet, self)
104
- @server.mount(@aggregated_metrics_path, MonitorServletAll, self)
105
- thread_create(:in_prometheus) do
106
- @server.start
156
+ @webrick_server = WEBrick::HTTPServer.new(config)
157
+ @webrick_server.mount_proc(@metrics_path) do |_req, res|
158
+ status, header, body = all_metrics
159
+ res.status = status
160
+ res['Content-Type'] = header['Content-Type']
161
+ res.body = body
162
+ res
107
163
  end
108
- end
109
164
 
110
- def shutdown
111
- if @server
112
- @server.shutdown
113
- @server = nil
165
+ @webrick_server.mount_proc(@aggregated_metrics_path) do |_req, res|
166
+ status, header, body = all_workers_metrics
167
+ res.status = status
168
+ res['Content-Type'] = header['Content-Type']
169
+ res.body = body
170
+ res
171
+ end
172
+
173
+ thread_create(:in_prometheus_webrick) do
174
+ @webrick_server.start
114
175
  end
115
- super
116
176
  end
117
177
 
118
- class MonitorServlet < WEBrick::HTTPServlet::AbstractServlet
119
- def initialize(server, prometheus)
120
- @prometheus = prometheus
178
+ def all_metrics
179
+ [200, { 'Content-Type' => ::Prometheus::Client::Formats::Text::CONTENT_TYPE }, ::Prometheus::Client::Formats::Text.marshal(@registry)]
180
+ rescue => e
181
+ [500, { 'Content-Type' => 'text/plain' }, e.to_s]
182
+ end
183
+
184
+ def all_workers_metrics
185
+ full_result = PromMetricsAggregator.new
186
+
187
+ send_request_to_each_worker do |resp|
188
+ if resp.is_a?(Net::HTTPSuccess)
189
+ full_result.add_metrics(resp.body)
190
+ end
121
191
  end
122
192
 
123
- def do_GET(req, res)
124
- res.status = 200
125
- res['Content-Type'] = ::Prometheus::Client::Formats::Text::CONTENT_TYPE
126
- res.body = ::Prometheus::Client::Formats::Text.marshal(@prometheus.registry)
127
- rescue
128
- res.status = 500
129
- res['Content-Type'] = 'text/plain'
130
- res.body = $!.to_s
193
+ [200, { 'Content-Type' => ::Prometheus::Client::Formats::Text::CONTENT_TYPE }, full_result.get_metrics]
194
+ rescue => e
195
+ [500, { 'Content-Type' => 'text/plain' }, e.to_s]
196
+ end
197
+
198
+ def send_request_to_each_worker
199
+ bind = (@bind == '0.0.0.0') ? '127.0.0.1' : @bind
200
+ req = Net::HTTP::Get.new(@metrics_path)
201
+ [*(@base_port...(@base_port + @num_workers))].each do |worker_port|
202
+ do_request(host: bind, port: worker_port, secure: @secure) do |http|
203
+ yield(http.request(req))
204
+ end
131
205
  end
132
206
  end
133
207
 
134
- class MonitorServletAll < WEBrick::HTTPServlet::AbstractServlet
135
- def initialize(server, prometheus)
136
- @prometheus = prometheus
208
+ def do_request(host:, port:, secure:)
209
+ http = Net::HTTP.new(host, port)
210
+
211
+ if secure
212
+ http.use_ssl = true
213
+ # target is our child process. so it's secure.
214
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
137
215
  end
138
216
 
139
- def do_GET(req, res)
140
- res.status = 200
141
- res['Content-Type'] = ::Prometheus::Client::Formats::Text::CONTENT_TYPE
142
-
143
- full_result = PromMetricsAggregator.new
144
- fluent_server_ip = @prometheus.bind == '0.0.0.0' ? '127.0.0.1' : @prometheus.bind
145
- current_worker = 0
146
- while current_worker < @prometheus.num_workers
147
- Net::HTTP.start(fluent_server_ip, @prometheus.base_port + current_worker) do |http|
148
- req = Net::HTTP::Get.new(@prometheus.metrics_path)
149
- result = http.request(req)
150
- if result.is_a?(Net::HTTPSuccess)
151
- full_result.add_metrics(result.body)
152
- end
153
- end
154
- current_worker += 1
155
- end
156
- res.body = full_result.get_metrics
157
- rescue
158
- res.status = 500
159
- res['Content-Type'] = 'text/plain'
160
- res.body = $!.to_s
217
+ http.start do
218
+ yield(http)
161
219
  end
162
220
  end
163
221
  end
@@ -6,11 +6,11 @@ require 'net/http'
6
6
 
7
7
  describe Fluent::Plugin::PrometheusInput do
8
8
  CONFIG = %[
9
- type prometheus
9
+ @type prometheus
10
10
  ]
11
11
 
12
12
  LOCAL_CONFIG = %[
13
- type prometheus
13
+ @type prometheus
14
14
  bind 127.0.0.1
15
15
  ]
16
16
 
@@ -47,6 +47,130 @@ describe Fluent::Plugin::PrometheusInput do
47
47
  end
48
48
  end
49
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
+
50
174
  describe '#run' do
51
175
  context '/metrics' do
52
176
  let(:config) { LOCAL_CONFIG }
@@ -1,6 +1,6 @@
1
1
 
2
2
  BASE_CONFIG = %[
3
- type prometheus
3
+ @type prometheus
4
4
  ]
5
5
 
6
6
  SIMPLE_CONFIG = BASE_CONFIG + %[
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.7.3
4
+ version: 1.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Masahiro Sano
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-02-14 00:00:00.000000000 Z
11
+ date: 2020-05-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: fluentd
@@ -16,7 +16,7 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 0.14.20
19
+ version: 1.9.1
20
20
  - - "<"
21
21
  - !ruby/object:Gem::Version
22
22
  version: '2'
@@ -26,7 +26,7 @@ dependencies:
26
26
  requirements:
27
27
  - - ">="
28
28
  - !ruby/object:Gem::Version
29
- version: 0.14.20
29
+ version: 1.9.1
30
30
  - - "<"
31
31
  - !ruby/object:Gem::Version
32
32
  version: '2'