fluent-plugin-prometheus 0.5.0 → 1.0.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
- SHA256:
3
- metadata.gz: c8de232abd7ede7d5988f3280f6c8735de2c0371c831830ee56574ca5d38a056
4
- data.tar.gz: 5042393a2e68e75dbcc35bf4ae7a857498f9d2e6ebbbd164f62a270e3274be65
2
+ SHA1:
3
+ metadata.gz: b6e00809503106fad10f9d831e67091e69ed56da
4
+ data.tar.gz: 5f84aeff3ed1a79a6da4c7ea18a5332c02304baa
5
5
  SHA512:
6
- metadata.gz: 8acba008b1f5beafae1e7cac6214083ad033def64ea5af572724cbec3337b03c122cef09b1935a9617e375abc0f83b7b33269904f567f7e17ec90d7f79e8da40
7
- data.tar.gz: 7187a5995e479c445bb0457081606b869456ad46bacd539962fb74147f5b9d72d0b78cb45b1d43a64c247328f673c91aa12ce86c53e915e171d6f5fb70e23afa
6
+ metadata.gz: 7658cc206cc8063ea61d83730b37db12a311f152a560c3c5d669c9f73dd9994c417b1a30810531d101c56821f4395f5d875fe5ef5cabb67e72948974186cdad9
7
+ data.tar.gz: ac72182e9fea379125a487f521d42a29bbf354d857abf3dc778daffdec8aa8bd346d444b3ab001cbcac951fde2b72c3ad208e0e2748aa9d5a14d35b34e73e1c3
data/.travis.yml CHANGED
@@ -1,8 +1,8 @@
1
1
  language: ruby
2
2
 
3
3
  rvm:
4
- - "2.3.3"
5
- - "2.4.0"
4
+ - "2.3.4"
5
+ - "2.4.1"
6
6
 
7
7
  gemfile:
8
8
  - Gemfile
data/Gemfile CHANGED
@@ -1,3 +1,4 @@
1
- source 'https://rubygems.org/'
2
- gem 'fluentd', '~> 0.12.0'
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in fluent-plugin-prometheus.gemspec
3
4
  gemspec
data/README.md CHANGED
@@ -1,11 +1,18 @@
1
1
  # fluent-plugin-prometheus, a plugin for [Fluentd](https://www.fluentd.org)
2
2
 
3
- This is the branch to support Fluentd v0.12. If you want to use Fluentd v0.14 or later, see [master branch](https://github.com/fluent/fluent-plugin-prometheus).
4
-
5
- [![Build Status](https://travis-ci.org/fluent/fluent-plugin-prometheus.svg?branch=v0.12)](https://travis-ci.org/fluent/fluent-plugin-prometheus)
3
+ [![Build Status](https://travis-ci.org/fluent/fluent-plugin-prometheus.svg?branch=master)](https://travis-ci.org/fluent/fluent-plugin-prometheus)
6
4
 
7
5
  A fluent plugin that instruments metrics from records and exposes them via web interface. Intended to be used together with a [Prometheus server](https://github.com/prometheus/prometheus).
8
6
 
7
+ If you are using Fluentd v0.10, you have to explicitly install [fluent-plugin-record-reformer](https://github.com/sonots/fluent-plugin-record-reformer) together. With Fluentd v0.12 or v0.14, there is no additional dependency.
8
+
9
+ ## Requirements
10
+
11
+ | fluent-plugin-prometheus | fluentd | ruby |
12
+ |--------------------------|------------|--------|
13
+ | 1.x.y | >= v0.14.8 | >= 2.1 |
14
+ | 0.x.y | >= v0.12.0 | >= 1.9 |
15
+
9
16
  ## Installation
10
17
 
11
18
  Add this line to your application's Gemfile:
@@ -72,7 +79,7 @@ With following configuration, those metrics are collected.
72
79
 
73
80
  More configuration parameters:
74
81
 
75
- - `<labels>`: additional labels for this metric (optional). See [Labels](#Labels)
82
+ - `<labels>`: additional labels for this metric (optional). See [Labels](#labels)
76
83
  - `interval`: interval to update monitor_agent information in seconds (default: 5)
77
84
 
78
85
  ### prometheus_output_monitor input plugin
@@ -106,7 +113,7 @@ With following configuration, those metrics are collected.
106
113
 
107
114
  More configuration parameters:
108
115
 
109
- - `<labels>`: additional labels for this metric (optional). See [Labels](#Labels)
116
+ - `<labels>`: additional labels for this metric (optional). See [Labels](#labels)
110
117
  - `interval`: interval to update monitor_agent information in seconds (default: 5)
111
118
 
112
119
  ### prometheus_tail_monitor input plugin
@@ -133,12 +140,12 @@ Default labels:
133
140
  With following configuration, those metrics are collected.
134
141
 
135
142
  <source>
136
- @type prometheus_output_monitor
143
+ @type prometheus_tail_monitor
137
144
  </source>
138
145
 
139
146
  More configuration parameters:
140
147
 
141
- - `<labels>`: additional labels for this metric (optional). See [Labels](#Labels)
148
+ - `<labels>`: additional labels for this metric (optional). See [Labels](#labels)
142
149
  - `interval`: interval to update monitor_agent information in seconds (default: 5)
143
150
 
144
151
  ### prometheus output/filter plugin
@@ -237,7 +244,7 @@ For details of each metric type, see [Prometheus documentation](http://prometheu
237
244
  - `type`: metric type (required)
238
245
  - `desc`: description of this metric (required)
239
246
  - `key`: key name of record for instrumentation (**optional**)
240
- - `<labels>`: additional labels for this metric (optional). See [Labels](#Labels)
247
+ - `<labels>`: additional labels for this metric (optional). See [Labels](#labels)
241
248
 
242
249
  If key is empty, the metric values is treated as 1, so the counter increments by 1 on each record regardless of contents of the record.
243
250
 
@@ -261,7 +268,7 @@ If key is empty, the metric values is treated as 1, so the counter increments by
261
268
  - `type`: metric type (required)
262
269
  - `desc`: description of metric (required)
263
270
  - `key`: key name of record for instrumentation (required)
264
- - `<labels>`: additional labels for this metric (optional). See [Labels](#Labels)
271
+ - `<labels>`: additional labels for this metric (optional). See [Labels](#labels)
265
272
 
266
273
  ### summary type
267
274
 
@@ -283,7 +290,7 @@ If key is empty, the metric values is treated as 1, so the counter increments by
283
290
  - `type`: metric type (required)
284
291
  - `desc`: description of metric (required)
285
292
  - `key`: key name of record for instrumentation (required)
286
- - `<labels>`: additional labels for this metric (optional). See [Labels](#Labels)
293
+ - `<labels>`: additional labels for this metric (optional). See [Labels](#labels)
287
294
 
288
295
  ### histogram type
289
296
 
@@ -307,7 +314,7 @@ If key is empty, the metric values is treated as 1, so the counter increments by
307
314
  - `desc`: description of metric (required)
308
315
  - `key`: key name of record for instrumentation (required)
309
316
  - `buckets`: buckets of record for instrumentation (optional)
310
- - `<labels>`: additional labels for this metric (optional). See [Labels](#Labels)
317
+ - `<labels>`: additional labels for this metric (optional). See [Labels](#labels)
311
318
 
312
319
  ## Labels
313
320
 
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |spec|
2
2
  spec.name = "fluent-plugin-prometheus"
3
- spec.version = "0.5.0"
3
+ spec.version = "1.0.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.12.0", "< 0.14.0"
16
+ spec.add_dependency "fluentd", ">= 0.14.8", "< 2"
17
17
  spec.add_dependency "prometheus-client"
18
18
  spec.add_development_dependency "bundler"
19
19
  spec.add_development_dependency "rake"
@@ -1,9 +1,10 @@
1
1
  require 'fluent/plugin/prometheus'
2
+ require 'fluent/plugin/filter'
2
3
 
3
- module Fluent
4
- class PrometheusFilter < Filter
5
- Plugin.register_filter('prometheus', self)
6
- include Fluent::Prometheus
4
+ module Fluent::Plugin
5
+ class PrometheusFilter < Fluent::Plugin::Filter
6
+ Fluent::Plugin.register_filter('prometheus', self)
7
+ include Fluent::Plugin::Prometheus
7
8
 
8
9
  def initialize
9
10
  super
@@ -12,8 +13,8 @@ module Fluent
12
13
 
13
14
  def configure(conf)
14
15
  super
15
- labels = Fluent::Prometheus.parse_labels_elements(conf)
16
- @metrics = Fluent::Prometheus.parse_metrics_elements(conf, @registry, labels)
16
+ labels = Fluent::Plugin::Prometheus.parse_labels_elements(conf)
17
+ @metrics = Fluent::Plugin::Prometheus.parse_metrics_elements(conf, @registry, labels)
17
18
  end
18
19
 
19
20
  def filter_stream(tag, es)
@@ -1,31 +1,16 @@
1
- require 'fluent/input'
1
+ require 'fluent/plugin/input'
2
2
  require 'fluent/plugin/prometheus'
3
3
  require 'webrick'
4
4
 
5
- module Fluent
6
- class PrometheusInput < Input
7
- Plugin.register_input('prometheus', self)
5
+ module Fluent::Plugin
6
+ class PrometheusInput < Fluent::Plugin::Input
7
+ Fluent::Plugin.register_input('prometheus', self)
8
8
 
9
- config_param :bind, :string, :default => '0.0.0.0'
10
- config_param :port, :integer, :default => 24231
11
- config_param :metrics_path, :string, :default => '/metrics'
9
+ helpers :thread
12
10
 
13
- desc 'Enable ssl configuration for the server'
14
- config_section :ssl, multi: false, required: false do
15
- config_param :enable, :bool, required: false, default: false
16
-
17
- desc 'Path to the ssl certificate in PEM format. Read from file and added to conf as "SSLCertificate"'
18
- config_param :certificate_path, :string, required: false, default: nil
19
-
20
- desc 'Path to the ssl private key in PEM format. Read from file and added to conf as "SSLPrivateKey"'
21
- config_param :private_key_path, :string, required: false, default: nil
22
-
23
- desc 'Path to CA in PEM format. Read from file and added to conf as "SSLCACertificateFile"'
24
- config_param :ca_path, :string, required: false, default: nil
25
-
26
- desc 'Additional ssl conf for the server. Ref: https://github.com/ruby/webrick/blob/master/lib/webrick/ssl.rb'
27
- config_param :extra_conf, :hash, multi: false, required: false, default: {:SSLCertName => [['CN','nobody'],['DC','example']]}, symbolize_keys: true
28
- end
11
+ config_param :bind, :string, default: '0.0.0.0'
12
+ config_param :port, :integer, default: 24231
13
+ config_param :metrics_path, :string, default: '/metrics'
29
14
 
30
15
  attr_reader :registry
31
16
 
@@ -34,59 +19,27 @@ module Fluent
34
19
  @registry = ::Prometheus::Client.registry
35
20
  end
36
21
 
37
- def configure(conf)
38
- super
39
- end
40
-
41
22
  def start
42
23
  super
43
- config = {
24
+ @server = WEBrick::HTTPServer.new(
44
25
  BindAddress: @bind,
45
26
  Port: @port,
46
27
  MaxClients: 5,
47
28
  Logger: WEBrick::Log.new(STDERR, WEBrick::Log::FATAL),
48
29
  AccessLog: [],
49
- }
50
- unless @ssl.nil? || !@ssl['enable']
51
- require 'webrick/https'
52
- require 'openssl'
53
- if (@ssl['certificate_path'] && @ssl['private_key_path'].nil?) || (@ssl['certificate_path'].nil? && @ssl['private_key_path'])
54
- raise RuntimeError.new("certificate_path and private_key_path most both be defined")
55
- end
56
- ssl_config = {
57
- SSLEnable: true
58
- }
59
- if @ssl['certificate_path']
60
- cert = OpenSSL::X509::Certificate.new(File.read(@ssl['certificate_path']))
61
- ssl_config[:SSLCertificate] = cert
62
- end
63
- if @ssl['private_key_path']
64
- key = OpenSSL::PKey::RSA.new(File.read(@ssl['private_key_path']))
65
- ssl_config[:SSLPrivateKey] = key
66
- end
67
- ssl_config[:SSLCACertificateFile] = @ssl['ca_path'] if @ssl['ca_path']
68
- ssl_config = ssl_config.merge(@ssl['extra_conf'])
69
- config = ssl_config.merge(config)
70
- end
71
- @log.on_debug do
72
- @log.debug("WEBrick conf: #{config}")
73
- end
74
-
75
- @server = WEBrick::HTTPServer.new(config)
30
+ )
76
31
  @server.mount(@metrics_path, MonitorServlet, self)
77
- @thread = Thread.new { @server.start }
32
+ thread_create(:in_prometheus) do
33
+ @server.start
34
+ end
78
35
  end
79
36
 
80
37
  def shutdown
81
- super
82
38
  if @server
83
39
  @server.shutdown
84
40
  @server = nil
85
41
  end
86
- if @thread
87
- @thread.join
88
- @thread = nil
89
- end
42
+ super
90
43
  end
91
44
 
92
45
  class MonitorServlet < WEBrick::HTTPServlet::AbstractServlet
@@ -1,12 +1,14 @@
1
- require 'fluent/input'
1
+ require 'fluent/plugin/input'
2
2
  require 'fluent/plugin/in_monitor_agent'
3
3
  require 'fluent/plugin/prometheus'
4
4
 
5
- module Fluent
6
- class PrometheusMonitorInput < Input
7
- Plugin.register_input('prometheus_monitor', self)
5
+ module Fluent::Plugin
6
+ class PrometheusMonitorInput < Fluent::Plugin::Input
7
+ Fluent::Plugin.register_input('prometheus_monitor', self)
8
8
 
9
- config_param :interval, :time, :default => 5
9
+ helpers :timer
10
+
11
+ config_param :interval, :time, default: 5
10
12
  attr_reader :registry
11
13
 
12
14
  def initialize
@@ -17,9 +19,9 @@ module Fluent
17
19
  def configure(conf)
18
20
  super
19
21
  hostname = Socket.gethostname
20
- expander = Fluent::Prometheus.placeholder_expander(log)
22
+ expander = Fluent::Plugin::Prometheus.placeholder_expander(log)
21
23
  placeholders = expander.prepare_placeholders({'hostname' => hostname})
22
- @base_labels = Fluent::Prometheus.parse_labels_elements(conf)
24
+ @base_labels = Fluent::Plugin::Prometheus.parse_labels_elements(conf)
23
25
  @base_labels.each do |key, value|
24
26
  @base_labels[key] = expander.expand(value, placeholders)
25
27
  end
@@ -48,41 +50,9 @@ module Fluent
48
50
  }
49
51
  end
50
52
 
51
- class TimerWatcher < Coolio::TimerWatcher
52
- def initialize(interval, repeat, log, &callback)
53
- @callback = callback
54
- @log = log
55
- super(interval, repeat)
56
- end
57
-
58
- def on_timer
59
- @callback.call
60
- rescue
61
- @log.error $!.to_s
62
- @log.error_backtrace
63
- end
64
- end
65
-
66
53
  def start
67
54
  super
68
- @loop = Coolio::Loop.new
69
- @timer = TimerWatcher.new(@interval, true, log, &method(:update_monitor_info))
70
- @loop.attach(@timer)
71
- @thread = Thread.new(&method(:run))
72
- end
73
-
74
- def shutdown
75
- super
76
- @loop.watchers.each {|w| w.detach }
77
- @loop.stop
78
- @thread.join
79
- end
80
-
81
- def run
82
- @loop.run
83
- rescue
84
- log.error "unexpected error", :error=>$!.to_s
85
- log.error_backtrace
55
+ timer_execute(:in_prometheus_monitor, @interval, &method(:update_monitor_info))
86
56
  end
87
57
 
88
58
  def update_monitor_info
@@ -2,11 +2,13 @@ require 'fluent/input'
2
2
  require 'fluent/plugin/in_monitor_agent'
3
3
  require 'fluent/plugin/prometheus'
4
4
 
5
- module Fluent
6
- class PrometheusOutputMonitorInput < Input
7
- Plugin.register_input('prometheus_output_monitor', self)
5
+ module Fluent::Plugin
6
+ class PrometheusOutputMonitorInput < Fluent::Input
7
+ Fluent::Plugin.register_input('prometheus_output_monitor', self)
8
8
 
9
- config_param :interval, :time, :default => 5
9
+ helpers :timer
10
+
11
+ config_param :interval, :time, default: 5
10
12
  attr_reader :registry
11
13
 
12
14
  MONITOR_IVARS = [
@@ -32,9 +34,9 @@ module Fluent
32
34
  def configure(conf)
33
35
  super
34
36
  hostname = Socket.gethostname
35
- expander = Fluent::Prometheus.placeholder_expander(log)
37
+ expander = Fluent::Plugin::Prometheus.placeholder_expander(log)
36
38
  placeholders = expander.prepare_placeholders({'hostname' => hostname})
37
- @base_labels = Fluent::Prometheus.parse_labels_elements(conf)
39
+ @base_labels = Fluent::Plugin::Prometheus.parse_labels_elements(conf)
38
40
  @base_labels.each do |key, value|
39
41
  @base_labels[key] = expander.expand(value, placeholders)
40
42
  end
@@ -77,41 +79,9 @@ module Fluent
77
79
  }
78
80
  end
79
81
 
80
- class TimerWatcher < Coolio::TimerWatcher
81
- def initialize(interval, repeat, log, &callback)
82
- @callback = callback
83
- @log = log
84
- super(interval, repeat)
85
- end
86
-
87
- def on_timer
88
- @callback.call
89
- rescue
90
- @log.error $!.to_s
91
- @log.error_backtrace
92
- end
93
- end
94
-
95
82
  def start
96
83
  super
97
- @loop = Coolio::Loop.new
98
- @timer = TimerWatcher.new(@interval, true, log, &method(:update_monitor_info))
99
- @loop.attach(@timer)
100
- @thread = Thread.new(&method(:run))
101
- end
102
-
103
- def shutdown
104
- super
105
- @loop.watchers.each {|w| w.detach }
106
- @loop.stop
107
- @thread.join
108
- end
109
-
110
- def run
111
- @loop.run
112
- rescue
113
- log.error "unexpected error", :error=>$!.to_s
114
- log.error_backtrace
84
+ timer_execute(:in_prometheus_output_monitor, @interval, &method(:update_monitor_info))
115
85
  end
116
86
 
117
87
  def update_monitor_info
@@ -1,12 +1,14 @@
1
- require 'fluent/input'
1
+ require 'fluent/plugin/input'
2
2
  require 'fluent/plugin/in_monitor_agent'
3
3
  require 'fluent/plugin/prometheus'
4
4
 
5
- module Fluent
6
- class PrometheusTailMonitorInput < Input
7
- Plugin.register_input('prometheus_tail_monitor', self)
5
+ module Fluent::Plugin
6
+ class PrometheusTailMonitorInput < Fluent::Plugin::Input
7
+ Fluent::Plugin.register_input('prometheus_tail_monitor', self)
8
8
 
9
- config_param :interval, :time, :default => 5
9
+ helpers :timer
10
+
11
+ config_param :interval, :time, default: 5
10
12
  attr_reader :registry
11
13
 
12
14
  MONITOR_IVARS = [
@@ -21,9 +23,9 @@ module Fluent
21
23
  def configure(conf)
22
24
  super
23
25
  hostname = Socket.gethostname
24
- expander = Fluent::Prometheus.placeholder_expander(log)
26
+ expander = Fluent::Plugin::Prometheus.placeholder_expander(log)
25
27
  placeholders = expander.prepare_placeholders({'hostname' => hostname})
26
- @base_labels = Fluent::Prometheus.parse_labels_elements(conf)
28
+ @base_labels = Fluent::Plugin::Prometheus.parse_labels_elements(conf)
27
29
  @base_labels.each do |key, value|
28
30
  @base_labels[key] = expander.expand(value, placeholders)
29
31
  end
@@ -45,41 +47,9 @@ module Fluent
45
47
  }
46
48
  end
47
49
 
48
- class TimerWatcher < Coolio::TimerWatcher
49
- def initialize(interval, repeat, log, &callback)
50
- @callback = callback
51
- @log = log
52
- super(interval, repeat)
53
- end
54
-
55
- def on_timer
56
- @callback.call
57
- rescue
58
- @log.error $!.to_s
59
- @log.error_backtrace
60
- end
61
- end
62
-
63
50
  def start
64
51
  super
65
- @loop = Coolio::Loop.new
66
- @timer = TimerWatcher.new(@interval, true, log, &method(:update_monitor_info))
67
- @loop.attach(@timer)
68
- @thread = Thread.new(&method(:run))
69
- end
70
-
71
- def shutdown
72
- super
73
- @loop.watchers.each {|w| w.detach }
74
- @loop.stop
75
- @thread.join
76
- end
77
-
78
- def run
79
- @loop.run
80
- rescue
81
- log.error "unexpected error", :error=>$!.to_s
82
- log.error_backtrace
52
+ timer_execute(:in_prometheus_tail_monitor, @interval, &method(:update_monitor_info))
83
53
  end
84
54
 
85
55
  def update_monitor_info
@@ -1,10 +1,10 @@
1
- require 'fluent/output'
1
+ require 'fluent/plugin/output'
2
2
  require 'fluent/plugin/prometheus'
3
3
 
4
- module Fluent
5
- class PrometheusOutput < Output
6
- Plugin.register_output('prometheus', self)
7
- include Fluent::Prometheus
4
+ module Fluent::Plugin
5
+ class PrometheusOutput < Fluent::Plugin::Output
6
+ Fluent::Plugin.register_output('prometheus', self)
7
+ include Fluent::Plugin::Prometheus
8
8
 
9
9
  def initialize
10
10
  super
@@ -13,13 +13,12 @@ module Fluent
13
13
 
14
14
  def configure(conf)
15
15
  super
16
- labels = Fluent::Prometheus.parse_labels_elements(conf)
17
- @metrics = Fluent::Prometheus.parse_metrics_elements(conf, @registry, labels)
16
+ labels = Fluent::Plugin::Prometheus.parse_labels_elements(conf)
17
+ @metrics = Fluent::Plugin::Prometheus.parse_metrics_elements(conf, @registry, labels)
18
18
  end
19
19
 
20
- def emit(tag, es, chain)
20
+ def process(tag, es)
21
21
  instrument(tag, es, @metrics)
22
- chain.next
23
22
  end
24
23
  end
25
24
  end
@@ -1,219 +1,213 @@
1
1
  require 'prometheus/client'
2
2
  require 'prometheus/client/formats/text'
3
+ require 'fluent/plugin/filter_record_transformer'
3
4
 
4
5
  module Fluent
5
- module Prometheus
6
- class AlreadyRegisteredError < StandardError; end
6
+ module Plugin
7
+ module Prometheus
8
+ class AlreadyRegisteredError < StandardError; end
7
9
 
8
- def self.parse_labels_elements(conf)
9
- labels = conf.elements.select { |e| e.name == 'labels' }
10
- if labels.size > 1
11
- raise ConfigError, "labels section must have at most 1"
12
- end
13
-
14
- base_labels = {}
15
- unless labels.empty?
16
- labels.first.each do |key, value|
17
- labels.first.has_key?(key)
18
- base_labels[key.to_sym] = value
10
+ def self.parse_labels_elements(conf)
11
+ labels = conf.elements.select { |e| e.name == 'labels' }
12
+ if labels.size > 1
13
+ raise ConfigError, "labels section must have at most 1"
19
14
  end
20
- end
21
-
22
- base_labels
23
- end
24
15
 
25
- def self.parse_metrics_elements(conf, registry, labels = {})
26
- metrics = []
27
- conf.elements.select { |element|
28
- element.name == 'metric'
29
- }.each { |element|
30
- case element['type']
31
- when 'summary'
32
- metrics << Fluent::Prometheus::Summary.new(element, registry, labels)
33
- when 'gauge'
34
- metrics << Fluent::Prometheus::Gauge.new(element, registry, labels)
35
- when 'counter'
36
- metrics << Fluent::Prometheus::Counter.new(element, registry, labels)
37
- when 'histogram'
38
- metrics << Fluent::Prometheus::Histogram.new(element, registry, labels)
39
- else
40
- raise ConfigError, "type option must be 'counter', 'gauge', 'summary' or 'histogram'"
16
+ base_labels = {}
17
+ unless labels.empty?
18
+ labels.first.each do |key, value|
19
+ labels.first.has_key?(key)
20
+ base_labels[key.to_sym] = value
21
+ end
41
22
  end
42
- }
43
- metrics
44
- end
45
23
 
46
- def self.placeholder_expander(log)
47
- # Use internal class in order to expand placeholder
48
- require 'fluent/plugin/filter_record_transformer'
49
- if defined?(Fluent::Plugin::RecordTransformerFilter::PlaceholderExpander)
50
- # for v0.14
51
- return Fluent::Plugin::RecordTransformerFilter::PlaceholderExpander.new(log: log)
52
- else
53
- # for v0.12
54
- return Fluent::RecordTransformerFilter::PlaceholderExpander.new(log: log)
24
+ base_labels
55
25
  end
56
- rescue LoadError => e
57
- raise ConfigError, "cannot find filter_record_transformer plugin: #{e.message}"
58
- end
59
26
 
60
- def configure(conf)
61
- super
62
- @placeholder_expander = Fluent::Prometheus.placeholder_expander(log)
63
- @hostname = Socket.gethostname
64
- end
27
+ def self.parse_metrics_elements(conf, registry, labels = {})
28
+ metrics = []
29
+ conf.elements.select { |element|
30
+ element.name == 'metric'
31
+ }.each { |element|
32
+ case element['type']
33
+ when 'summary'
34
+ metrics << Fluent::Plugin::Prometheus::Summary.new(element, registry, labels)
35
+ when 'gauge'
36
+ metrics << Fluent::Plugin::Prometheus::Gauge.new(element, registry, labels)
37
+ when 'counter'
38
+ metrics << Fluent::Plugin::Prometheus::Counter.new(element, registry, labels)
39
+ when 'histogram'
40
+ metrics << Fluent::Plugin::Prometheus::Histogram.new(element, registry, labels)
41
+ else
42
+ raise ConfigError, "type option must be 'counter', 'gauge', 'summary' or 'histogram'"
43
+ end
44
+ }
45
+ metrics
46
+ end
65
47
 
66
- def instrument(tag, es, metrics)
67
- placeholder_values = {
68
- 'tag' => tag,
69
- 'hostname' => @hostname,
70
- }
48
+ def self.placeholder_expander(log)
49
+ # Use internal class in order to expand placeholder
50
+ Fluent::Plugin::RecordTransformerFilter::PlaceholderExpander.new(log: log)
51
+ end
71
52
 
72
- es.each do |time, record|
73
- placeholders = record.merge(placeholder_values)
74
- placeholders = @placeholder_expander.prepare_placeholders(placeholders)
75
- metrics.each do |metric|
76
- begin
77
- metric.instrument(record, @placeholder_expander, placeholders)
78
- rescue => e
79
- log.warn "prometheus: failed to instrument a metric.", error_class: e.class, error: e, tag: tag, name: metric.name
80
- router.emit_error_event(tag, time, record, e)
53
+ def configure(conf)
54
+ super
55
+ @placeholder_expander = Fluent::Plugin::Prometheus.placeholder_expander(log)
56
+ @hostname = Socket.gethostname
57
+ end
58
+
59
+ def instrument(tag, es, metrics)
60
+ placeholder_values = {
61
+ 'tag' => tag,
62
+ 'hostname' => @hostname,
63
+ }
64
+
65
+ es.each do |time, record|
66
+ placeholders = record.merge(placeholder_values)
67
+ placeholders = @placeholder_expander.prepare_placeholders(placeholders)
68
+ metrics.each do |metric|
69
+ begin
70
+ metric.instrument(record, @placeholder_expander, placeholders)
71
+ rescue => e
72
+ log.warn "prometheus: failed to instrument a metric.", error_class: e.class, error: e, tag: tag, name: metric.name
73
+ router.emit_error_event(tag, time, record, e)
74
+ end
81
75
  end
82
76
  end
83
77
  end
84
- end
85
78
 
86
- class Metric
87
- attr_reader :type
88
- attr_reader :name
89
- attr_reader :key
90
- attr_reader :desc
79
+ class Metric
80
+ attr_reader :type
81
+ attr_reader :name
82
+ attr_reader :key
83
+ attr_reader :desc
91
84
 
92
- def initialize(element, registry, labels)
93
- ['name', 'desc'].each do |key|
94
- if element[key].nil?
95
- raise ConfigError, "metric requires '#{key}' option"
85
+ def initialize(element, registry, labels)
86
+ ['name', 'desc'].each do |key|
87
+ if element[key].nil?
88
+ raise ConfigError, "metric requires '#{key}' option"
89
+ end
96
90
  end
97
- end
98
- @type = element['type']
99
- @name = element['name']
100
- @key = element['key']
101
- @desc = element['desc']
91
+ @type = element['type']
92
+ @name = element['name']
93
+ @key = element['key']
94
+ @desc = element['desc']
102
95
 
103
- @base_labels = Fluent::Prometheus.parse_labels_elements(element)
104
- @base_labels = labels.merge(@base_labels)
105
- end
96
+ @base_labels = Fluent::Plugin::Prometheus.parse_labels_elements(element)
97
+ @base_labels = labels.merge(@base_labels)
98
+ end
106
99
 
107
- def labels(record, expander, placeholders)
108
- label = {}
109
- @base_labels.each do |k, v|
110
- label[k] = expander.expand(v, placeholders)
100
+ def labels(record, expander, placeholders)
101
+ label = {}
102
+ @base_labels.each do |k, v|
103
+ label[k] = expander.expand(v, placeholders)
104
+ end
105
+ label
111
106
  end
112
- label
113
- end
114
107
 
115
- def self.get(registry, name, type, docstring)
116
- metric = registry.get(name)
108
+ def self.get(registry, name, type, docstring)
109
+ metric = registry.get(name)
117
110
 
118
- # should have same type, docstring
119
- if metric.type != type
120
- raise AlreadyRegisteredError, "#{name} has already been registered as #{type} type"
121
- end
122
- if metric.docstring != docstring
123
- raise AlreadyRegisteredError, "#{name} has already been registered with different docstring"
124
- end
111
+ # should have same type, docstring
112
+ if metric.type != type
113
+ raise AlreadyRegisteredError, "#{name} has already been registered as #{type} type"
114
+ end
115
+ if metric.docstring != docstring
116
+ raise AlreadyRegisteredError, "#{name} has already been registered with different docstring"
117
+ end
125
118
 
126
- metric
119
+ metric
120
+ end
127
121
  end
128
- end
129
122
 
130
- class Gauge < Metric
131
- def initialize(element, registry, labels)
132
- super
133
- if @key.nil?
134
- raise ConfigError, "gauge metric requires 'key' option"
135
- end
123
+ class Gauge < Metric
124
+ def initialize(element, registry, labels)
125
+ super
126
+ if @key.nil?
127
+ raise ConfigError, "gauge metric requires 'key' option"
128
+ end
136
129
 
137
- begin
138
- @gauge = registry.gauge(element['name'].to_sym, element['desc'])
139
- rescue ::Prometheus::Client::Registry::AlreadyRegisteredError
140
- @gauge = Fluent::Prometheus::Metric.get(registry, element['name'].to_sym, :gauge, element['desc'])
130
+ begin
131
+ @gauge = registry.gauge(element['name'].to_sym, element['desc'])
132
+ rescue ::Prometheus::Client::Registry::AlreadyRegisteredError
133
+ @gauge = Fluent::Plugin::Prometheus::Metric.get(registry, element['name'].to_sym, :gauge, element['desc'])
134
+ end
141
135
  end
142
- end
143
136
 
144
- def instrument(record, expander, placeholders)
145
- if record[@key]
146
- @gauge.set(labels(record, expander, placeholders), record[@key])
137
+ def instrument(record, expander, placeholders)
138
+ if record[@key]
139
+ @gauge.set(labels(record, expander, placeholders), record[@key])
140
+ end
147
141
  end
148
142
  end
149
- end
150
143
 
151
- class Counter < Metric
152
- def initialize(element, registry, labels)
153
- super
154
- begin
155
- @counter = registry.counter(element['name'].to_sym, element['desc'])
156
- rescue ::Prometheus::Client::Registry::AlreadyRegisteredError
157
- @counter = Fluent::Prometheus::Metric.get(registry, element['name'].to_sym, :counter, element['desc'])
144
+ class Counter < Metric
145
+ def initialize(element, registry, labels)
146
+ super
147
+ begin
148
+ @counter = registry.counter(element['name'].to_sym, element['desc'])
149
+ rescue ::Prometheus::Client::Registry::AlreadyRegisteredError
150
+ @counter = Fluent::Plugin::Prometheus::Metric.get(registry, element['name'].to_sym, :counter, element['desc'])
151
+ end
158
152
  end
159
- end
160
153
 
161
- def instrument(record, expander, placeholders)
162
- # use record value of the key if key is specified, otherwise just increment
163
- value = @key ? record[@key] : 1
154
+ def instrument(record, expander, placeholders)
155
+ # use record value of the key if key is specified, otherwise just increment
156
+ value = @key ? record[@key] : 1
164
157
 
165
- # ignore if record value is nil
166
- return if value.nil?
158
+ # ignore if record value is nil
159
+ return if value.nil?
167
160
 
168
- @counter.increment(labels(record, expander, placeholders), value)
161
+ @counter.increment(labels(record, expander, placeholders), value)
162
+ end
169
163
  end
170
- end
171
164
 
172
- class Summary < Metric
173
- def initialize(element, registry, labels)
174
- super
175
- if @key.nil?
176
- raise ConfigError, "summary metric requires 'key' option"
177
- end
165
+ class Summary < Metric
166
+ def initialize(element, registry, labels)
167
+ super
168
+ if @key.nil?
169
+ raise ConfigError, "summary metric requires 'key' option"
170
+ end
178
171
 
179
- begin
180
- @summary = registry.summary(element['name'].to_sym, element['desc'])
181
- rescue ::Prometheus::Client::Registry::AlreadyRegisteredError
182
- @summary = Fluent::Prometheus::Metric.get(registry, element['name'].to_sym, :summary, element['desc'])
172
+ begin
173
+ @summary = registry.summary(element['name'].to_sym, element['desc'])
174
+ rescue ::Prometheus::Client::Registry::AlreadyRegisteredError
175
+ @summary = Fluent::Plugin::Prometheus::Metric.get(registry, element['name'].to_sym, :summary, element['desc'])
176
+ end
183
177
  end
184
- end
185
178
 
186
- def instrument(record, expander, placeholders)
187
- if record[@key]
188
- @summary.observe(labels(record, expander, placeholders), record[@key])
179
+ def instrument(record, expander, placeholders)
180
+ if record[@key]
181
+ @summary.observe(labels(record, expander, placeholders), record[@key])
182
+ end
189
183
  end
190
184
  end
191
- end
192
185
 
193
- class Histogram < Metric
194
- def initialize(element, registry, labels)
195
- super
196
- if @key.nil?
197
- raise ConfigError, "histogram metric requires 'key' option"
198
- end
186
+ class Histogram < Metric
187
+ def initialize(element, registry, labels)
188
+ super
189
+ if @key.nil?
190
+ raise ConfigError, "histogram metric requires 'key' option"
191
+ end
199
192
 
200
- begin
201
- if element['buckets']
202
- buckets = element['buckets'].split(/,/).map(&:strip).map do |e|
203
- e[/\A\d+.\d+\Z/] ? e.to_f : e.to_i
193
+ begin
194
+ if element['buckets']
195
+ buckets = element['buckets'].split(/,/).map(&:strip).map do |e|
196
+ e[/\A\d+.\d+\Z/] ? e.to_f : e.to_i
197
+ end
198
+ @histogram = registry.histogram(element['name'].to_sym, element['desc'], {}, buckets)
199
+ else
200
+ @histogram = registry.histogram(element['name'].to_sym, element['desc'])
204
201
  end
205
- @histogram = registry.histogram(element['name'].to_sym, element['desc'], {}, buckets)
206
- else
207
- @histogram = registry.histogram(element['name'].to_sym, element['desc'])
202
+ rescue ::Prometheus::Client::Registry::AlreadyRegisteredError
203
+ @histogram = Fluent::Plugin::Prometheus::Metric.get(registry, element['name'].to_sym, :histogram, element['desc'])
208
204
  end
209
- rescue ::Prometheus::Client::Registry::AlreadyRegisteredError
210
- @histogram = Fluent::Prometheus::Metric.get(registry, element['name'].to_sym, :histogram, element['desc'])
211
205
  end
212
- end
213
206
 
214
- def instrument(record, expander, placeholders)
215
- if record[@key]
216
- @histogram.observe(labels(record, expander, placeholders), record[@key])
207
+ def instrument(record, expander, placeholders)
208
+ if record[@key]
209
+ @histogram.observe(labels(record, expander, placeholders), record[@key])
210
+ end
217
211
  end
218
212
  end
219
213
  end
@@ -85,6 +85,13 @@
85
85
  buffer_type memory
86
86
  flush_interval 1s
87
87
  max_retry_wait 2s
88
+ <buffer>
89
+ # max_retry_wait 10s
90
+ flush_interval 1s
91
+ # retry_type periodic
92
+ disable_retry_limit
93
+ </buffer>
94
+ # retry_limit 3
88
95
  disable_retry_limit
89
96
  <server>
90
97
  host 127.0.0.1
@@ -1,10 +1,11 @@
1
1
  require 'spec_helper'
2
+ require 'fluent/test/driver/filter'
2
3
  require 'fluent/plugin/filter_prometheus'
3
4
  require_relative 'shared'
4
5
 
5
- describe Fluent::PrometheusFilter do
6
+ describe Fluent::Plugin::PrometheusFilter do
6
7
  let(:tag) { 'prometheus.test' }
7
- let(:driver) { Fluent::Test::FilterTestDriver.new(Fluent::PrometheusFilter, tag).configure(config, true) }
8
+ let(:driver) { Fluent::Test::Driver::Filter.new(Fluent::Plugin::PrometheusFilter).configure(config) }
8
9
  let(:registry) { ::Prometheus::Client.registry }
9
10
 
10
11
  describe '#configure' do
@@ -13,7 +14,10 @@ describe Fluent::PrometheusFilter do
13
14
 
14
15
  describe '#run' do
15
16
  let(:message) { {"foo" => 100, "bar" => 100, "baz" => 100, "qux" => 10} }
16
- let(:es) { driver.run { driver.emit(message, Time.now) }.filtered }
17
+ let(:es) {
18
+ driver.run(default_tag: tag) { driver.feed(event_time, message) }
19
+ driver.filtered_records
20
+ }
17
21
 
18
22
  context 'simple config' do
19
23
  include_context 'simple_config'
@@ -25,7 +29,7 @@ describe Fluent::PrometheusFilter do
25
29
  end
26
30
 
27
31
  it 'should keep original message' do
28
- expect(es.first[1]).to eq(message)
32
+ expect(es.first).to eq(message)
29
33
  end
30
34
  end
31
35
 
@@ -1,10 +1,11 @@
1
1
  require 'spec_helper'
2
+ require 'fluent/test/driver/output'
2
3
  require 'fluent/plugin/out_prometheus'
3
4
  require_relative 'shared'
4
5
 
5
- describe Fluent::PrometheusOutput do
6
+ describe Fluent::Plugin::PrometheusOutput do
6
7
  let(:tag) { 'prometheus.test' }
7
- let(:driver) { Fluent::Test::OutputTestDriver.new(Fluent::PrometheusOutput, tag).configure(config) }
8
+ let(:driver) { Fluent::Test::Driver::Output.new(Fluent::Plugin::PrometheusOutput).configure(config) }
8
9
  let(:registry) { ::Prometheus::Client.registry }
9
10
 
10
11
  describe '#configure' do
@@ -13,7 +14,10 @@ describe Fluent::PrometheusOutput do
13
14
 
14
15
  describe '#run' do
15
16
  let(:message) { {"foo" => 100, "bar" => 100, "baz" => 100, "qux" => 10} }
16
- let(:es) { driver.run { driver.emit(message, Time.now) } }
17
+ let(:es) {
18
+ driver.run(default_tag: tag) { driver.feed(event_time, message) }
19
+ driver.events
20
+ }
17
21
 
18
22
  context 'simple config' do
19
23
  include_context 'simple_config'
@@ -1,9 +1,10 @@
1
1
  require 'spec_helper'
2
2
  require 'fluent/plugin/in_prometheus'
3
+ require 'fluent/test/driver/input'
3
4
 
4
5
  require 'net/http'
5
6
 
6
- describe Fluent::PrometheusInput do
7
+ describe Fluent::Plugin::PrometheusInput do
7
8
  CONFIG = %[
8
9
  type prometheus
9
10
  ]
@@ -15,7 +16,7 @@ describe Fluent::PrometheusInput do
15
16
 
16
17
  let(:config) { CONFIG }
17
18
  let(:port) { 24231 }
18
- let(:driver) { Fluent::Test::InputTestDriver.new(Fluent::PrometheusInput).configure(config) }
19
+ let(:driver) { Fluent::Test::Driver::Input.new(Fluent::Plugin::PrometheusInput).configure(config) }
19
20
 
20
21
  describe '#configure' do
21
22
  describe 'bind' do
@@ -50,7 +51,7 @@ describe Fluent::PrometheusInput do
50
51
  context '/metrics' do
51
52
  let(:config) { LOCAL_CONFIG }
52
53
  it 'returns 200' do
53
- driver.run do
54
+ driver.run(timeout: 1) do
54
55
  Net::HTTP.start("127.0.0.1", port) do |http|
55
56
  req = Net::HTTP::Get.new("/metrics")
56
57
  res = http.request(req)
@@ -63,7 +64,7 @@ describe Fluent::PrometheusInput do
63
64
  context '/foo' do
64
65
  let(:config) { LOCAL_CONFIG }
65
66
  it 'does not return 200' do
66
- driver.run do
67
+ driver.run(timeout: 1) do
67
68
  Net::HTTP.start("127.0.0.1", port) do |http|
68
69
  req = Net::HTTP::Get.new("/foo")
69
70
  res = http.request(req)
data/spec/spec_helper.rb CHANGED
@@ -1,8 +1,10 @@
1
1
  $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
2
2
  require 'fluent/test'
3
+ require 'fluent/test/helpers'
3
4
  require 'fluent/plugin/prometheus'
4
5
 
5
6
  # Disable Test::Unit
6
7
  Test::Unit::AutoRunner.need_auto_run = false
7
8
 
8
9
  Fluent::Test.setup
10
+ include Fluent::Test::Helpers
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: 0.5.0
4
+ version: 1.0.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: 2018-09-09 00:00:00.000000000 Z
11
+ date: 2017-11-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: fluentd
@@ -16,20 +16,20 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 0.12.0
19
+ version: 0.14.8
20
20
  - - "<"
21
21
  - !ruby/object:Gem::Version
22
- version: 0.14.0
22
+ version: '2'
23
23
  type: :runtime
24
24
  prerelease: false
25
25
  version_requirements: !ruby/object:Gem::Requirement
26
26
  requirements:
27
27
  - - ">="
28
28
  - !ruby/object:Gem::Version
29
- version: 0.12.0
29
+ version: 0.14.8
30
30
  - - "<"
31
31
  - !ruby/object:Gem::Version
32
- version: 0.14.0
32
+ version: '2'
33
33
  - !ruby/object:Gem::Dependency
34
34
  name: prometheus-client
35
35
  requirement: !ruby/object:Gem::Requirement
@@ -151,7 +151,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
151
151
  version: '0'
152
152
  requirements: []
153
153
  rubyforge_project:
154
- rubygems_version: 2.7.6
154
+ rubygems_version: 2.6.13
155
155
  signing_key:
156
156
  specification_version: 4
157
157
  summary: A fluent plugin that collects metrics and exposes for Prometheus.