fluent-plugin-prometheus 1.2.0 → 1.6.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
- SHA1:
3
- metadata.gz: da342f3a63fc1bb0e727eb1910c7b13734600dd2
4
- data.tar.gz: 46ec363b48352bad9e781695d7358172f06fb5c0
2
+ SHA256:
3
+ metadata.gz: 3f079822fa7231b77912e5ac1324b691f38dbf1f1f32fd8700dee19bc636fd8c
4
+ data.tar.gz: 58ad623a333cc1600e971fdd35b9b2c7d4a381c03a954d99206233758e4562f6
5
5
  SHA512:
6
- metadata.gz: 771b4c6ee4ded81623869e6339b1f3ce56913a0042e82eeef210cba9825e3f0a5b6a2c071a884b7d4ad54e0689eaa4654f916cf797db4de7514dea21de2d2ee0
7
- data.tar.gz: ca7cc8da3dd94f4b3976901f471cb1238813210109e0e05932f58991d353c8bd289ba2633144a1094f41ec14164ab3a04557a0f20ad0f6c07a5d99ad3f53553c
6
+ metadata.gz: 4394983e398e9e4b116f54927b7ad82778ab672b27e41bfc1ef3eb5421f3f3cde7899ce906d86de8862179c0293c1831c0a555553f21c10787dddba22c68fe1e
7
+ data.tar.gz: f8d52d61a493f4c8abfc88a1cfdc415779a4946eeed639b03545574b2a86304d7a560c026391897ab93596280be306a02c24d3dcdbc161c30f625c211d237711
@@ -1,9 +1,9 @@
1
1
  language: ruby
2
2
 
3
3
  rvm:
4
- - "2.3.6"
5
- - "2.4.3"
6
- - "2.5.0"
4
+ - "2.4.7"
5
+ - "2.5"
6
+ - "2.6"
7
7
 
8
8
  gemfile:
9
9
  - Gemfile
data/README.md CHANGED
@@ -42,8 +42,8 @@ See [sample configuration](./misc/fluentd_sample.conf), or try [tutorial](#try-p
42
42
 
43
43
  ### prometheus input plugin
44
44
 
45
- You have to configure this plugin to expose metrics collected by other promtheus plugins.
46
- This plugin provides a metrics HTTP endpoint to be scraped by a prometheus server on 24231/tcp(default).
45
+ You have to configure this plugin to expose metrics collected by other Prometheus plugins.
46
+ This plugin provides a metrics HTTP endpoint to be scraped by a Prometheus server on 24231/tcp(default).
47
47
 
48
48
  With following configuration, you can access http://localhost:24231/metrics on a server where fluentd running.
49
49
 
@@ -56,20 +56,27 @@ With following configuration, you can access http://localhost:24231/metrics on a
56
56
  More configuration parameters:
57
57
 
58
58
  - `bind`: binding interface (default: '0.0.0.0')
59
- - `port`: listen port (defaut: 24231)
59
+ - `port`: listen port (default: 24231)
60
60
  - `metrics_path`: metrics HTTP endpoint (default: /metrics)
61
+ - `aggregated_metrics_path`: metrics HTTP endpoint (default: /aggregated_metrics)
61
62
 
62
63
  When using multiple workers, each worker binds to port + `fluent_worker_id`.
64
+ To scrape metrics from all workers at once, you can access http://localhost:24231/aggregated_metrics.
63
65
 
64
66
  ### prometheus_monitor input plugin
65
67
 
66
- This plugin collects internal metrics in Fluentd. The metrics are similar to/part of [monitor_agent](http://docs.fluentd.org/articles/monitoring#monitoring-agent).
68
+ This plugin collects internal metrics in Fluentd. The metrics are similar to/part of [monitor_agent](https://docs.fluentd.org/input/monitor_agent).
67
69
 
68
- Current exposed metrics:
69
70
 
70
- - `buffere_queue_length` of each BufferedOutput plugins
71
- - `buffer_total_queued_size` of each BufferedOutput plugins
72
- - `retry_count` of each BufferedOutput plugins
71
+ #### Exposed metrics
72
+
73
+ - `fluentd_status_buffer_queue_length`
74
+ - `fluentd_status_buffer_total_queued_size`
75
+ - `fluentd_status_retry_count`
76
+ - `fluentd_status_buffer_newest_timekey` from fluentd v1.4.2
77
+ - `fluentd_status_buffer_oldest_timekey` from fluentd v1.4.2
78
+
79
+ #### Configuration
73
80
 
74
81
  With following configuration, those metrics are collected.
75
82
 
@@ -86,26 +93,35 @@ More configuration parameters:
86
93
 
87
94
  ### prometheus_output_monitor input plugin
88
95
 
89
- **experimental**
90
-
91
96
  This plugin collects internal metrics for output plugin in Fluentd. This is similar to `prometheus_monitor` plugin, but specialized for output plugin. There are Many metrics `prometheus_monitor` does not include, such as `num_errors`, `retry_wait` and so on.
92
97
 
93
- Current exposed metrics:
98
+ #### Exposed metrics
99
+
100
+ Metrics for output
94
101
 
95
- - `fluentd_output_status_buffer_queue_length`
96
- - `fluentd_output_status_buffer_total_bytes`
97
102
  - `fluentd_output_status_retry_count`
98
103
  - `fluentd_output_status_num_errors`
99
104
  - `fluentd_output_status_emit_count`
100
105
  - `fluentd_output_status_retry_wait`
101
106
  - current retry_wait computed from last retry time and next retry time
102
107
  - `fluentd_output_status_emit_records`
103
- - only for v0.14
104
108
  - `fluentd_output_status_write_count`
105
- - only for v0.14
106
109
  - `fluentd_output_status_rollback_count`
107
- - only for v0.14
110
+ - `fluentd_output_status_flush_time_count` from fluentd v1.6.0
111
+ - `fluentd_output_status_slow_flush_count` from fluentd v1.6.0
108
112
 
113
+ Metrics for buffer
114
+
115
+ - `fluentd_output_status_buffer_total_bytes`
116
+ - `fluentd_output_status_buffer_stage_length` from fluentd v1.6.0
117
+ - `fluentd_output_status_buffer_stage_byte_size` from fluentd v1.6.0
118
+ - `fluentd_output_status_buffer_queue_length`
119
+ - `fluentd_output_status_buffer_queue_byte_size` from fluentd v1.6.0
120
+ - `fluentd_output_status_buffer_newest_timekey` from fluentd v1.6.0
121
+ - `fluentd_output_status_buffer_oldest_timekey` from fluentd v1.6.0
122
+ - `fluentd_output_status_buffer_available_space_ratio` from fluentd v1.6.0
123
+
124
+ #### Configuration
109
125
 
110
126
  With following configuration, those metrics are collected.
111
127
 
@@ -122,13 +138,11 @@ More configuration parameters:
122
138
 
123
139
  ### prometheus_tail_monitor input plugin
124
140
 
125
- **experimental**
126
-
127
141
  This plugin collects internal metrics for in_tail plugin in Fluentd. in_tail plugin holds internal state for files that the plugin is watching. The state is sometimes important to monitor plugins work correctly.
128
142
 
129
143
  This plugin uses internal class of Fluentd, so it's easy to break.
130
144
 
131
- Current exposed metrics:
145
+ #### Exposed metrics
132
146
 
133
147
  - `fluentd_tail_file_position`
134
148
  - Current bytes which plugin reads from the file
@@ -141,6 +155,8 @@ Default labels:
141
155
  - `type`: plugin name. `in_tail` only for now.
142
156
  - `path`: file path
143
157
 
158
+ #### Configuration
159
+
144
160
  With following configuration, those metrics are collected.
145
161
 
146
162
  ```
@@ -224,6 +240,8 @@ In output plugin style:
224
240
 
225
241
  With above configuration, the plugin collects a metric named `message_foo_counter` from key `foo` of each records.
226
242
 
243
+ You can access nested keys in records via dot or bracket notation (https://docs.fluentd.org/plugin-helper-overview/api-plugin-helper-record_accessor#syntax), for example: `$.kubernetes.namespace`, `$['key1'][0]['key2']`. The record accessor is enable only if the value starts with `$.` or `$[`.
244
+
227
245
  See Supported Metric Type and Labels for more configuration parameters.
228
246
 
229
247
  ## Supported Metric Types
@@ -339,21 +357,23 @@ You can add labels with static value or dynamic value from records. In `promethe
339
357
 
340
358
  All labels sections has same format. Each lines have key/value for label.
341
359
 
342
- You can use placeholder for label values. The placeholders will be expanded from records or reserved values. If you specify `${foo}`, it will be expanded by value of `foo` in record.
360
+ You can access nested fields in records via dot or bracket notation (https://docs.fluentd.org/plugin-helper-overview/api-plugin-helper-record_accessor#syntax), for example: `$.kubernetes.namespace`, `$['key1'][0]['key2']`. The record accessor is enable only if the value starts with `$.` or `$[`. Other values are handled as raw string as is and may be expanded by placeholder described later.
343
361
 
344
- You can access nested fields in records via dot or bracket notation (https://docs.fluentd.org/v1.0/articles/api-plugin-helper-record_accessor#syntax), for example: `$.kubernetes.namespace`.
362
+ You can use placeholder for label values. The placeholders will be expanded from reserved values and records.
363
+ If you specify `${hostname}`, it will be expanded by value of a hostname where fluentd runs.
364
+ The placeholder for records is deprecated. Use record accessor syntax instead.
345
365
 
346
366
  Reserved placeholders are:
347
367
 
348
368
  - `${hostname}`: hostname
349
369
  - `${worker_id}`: fluent worker id
350
370
  - `${tag}`: tag name
351
- - only availabe in prometheus output/filter plugin
371
+ - only available in Prometheus output/filter plugin
352
372
 
353
373
 
354
374
  ### top-level labels and labels inside metric
355
375
 
356
- Prometheus output/filter plugin can have multiple metric section. Top-level labels section spcifies labels for all metrics. Labels section insede metric section specifis labels for the metric. Both are specified, labels are merged.
376
+ Prometheus output/filter plugin can have multiple metric section. Top-level labels section specifies labels for all metrics. Labels section inside metric section specifies labels for the metric. Both are specified, labels are merged.
357
377
 
358
378
  ```
359
379
  <filter message>
@@ -397,7 +417,7 @@ $ cd fluent-plugin-prometheus
397
417
  $ bundle install --path vendor/bundle
398
418
  ```
399
419
 
400
- Download pre-compiled prometheus binary and start it. It listens on 9090.
420
+ Download pre-compiled Prometheus binary and start it. It listens on 9090.
401
421
 
402
422
  ```
403
423
  $ wget https://github.com/prometheus/prometheus/releases/download/v1.5.2/prometheus-1.5.2.linux-amd64.tar.gz -O - | tar zxf -
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |spec|
2
2
  spec.name = "fluent-plugin-prometheus"
3
- spec.version = "1.2.0"
3
+ spec.version = "1.6.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.}
@@ -4,6 +4,7 @@ require 'fluent/plugin/filter'
4
4
  module Fluent::Plugin
5
5
  class PrometheusFilter < Fluent::Plugin::Filter
6
6
  Fluent::Plugin.register_filter('prometheus', self)
7
+ include Fluent::Plugin::PrometheusLabelParser
7
8
  include Fluent::Plugin::Prometheus
8
9
 
9
10
  def initialize
@@ -11,9 +12,13 @@ module Fluent::Plugin
11
12
  @registry = ::Prometheus::Client.registry
12
13
  end
13
14
 
15
+ def multi_workers_ready?
16
+ true
17
+ end
18
+
14
19
  def configure(conf)
15
20
  super
16
- labels = Fluent::Plugin::Prometheus.parse_labels_elements(conf)
21
+ labels = parse_labels_elements(conf)
17
22
  @metrics = Fluent::Plugin::Prometheus.parse_metrics_elements(conf, @registry, labels)
18
23
  end
19
24
 
@@ -1,5 +1,7 @@
1
1
  require 'fluent/plugin/input'
2
2
  require 'fluent/plugin/prometheus'
3
+ require 'fluent/plugin/prometheus_metrics'
4
+ require 'net/http'
3
5
  require 'webrick'
4
6
 
5
7
  module Fluent::Plugin
@@ -11,6 +13,7 @@ module Fluent::Plugin
11
13
  config_param :bind, :string, default: '0.0.0.0'
12
14
  config_param :port, :integer, default: 24231
13
15
  config_param :metrics_path, :string, default: '/metrics'
16
+ config_param :aggregated_metrics_path, :string, default: '/aggregated_metrics'
14
17
 
15
18
  desc 'Enable ssl configuration for the server'
16
19
  config_section :ssl, required: false, multi: false do
@@ -31,6 +34,10 @@ module Fluent::Plugin
31
34
 
32
35
  attr_reader :registry
33
36
 
37
+ attr_reader :num_workers
38
+ attr_reader :base_port
39
+ attr_reader :metrics_path
40
+
34
41
  def initialize
35
42
  super
36
43
  @registry = ::Prometheus::Client.registry
@@ -38,6 +45,18 @@ module Fluent::Plugin
38
45
 
39
46
  def configure(conf)
40
47
  super
48
+
49
+ # Get how many workers we have
50
+ sysconf = if self.respond_to?(:owner) && owner.respond_to?(:system_config)
51
+ owner.system_config
52
+ elsif self.respond_to?(:system_config)
53
+ self.system_config
54
+ else
55
+ nil
56
+ end
57
+ @num_workers = sysconf && sysconf.workers ? sysconf.workers : 1
58
+
59
+ @base_port = @port
41
60
  @port += fluentd_worker_id
42
61
  end
43
62
 
@@ -82,6 +101,7 @@ module Fluent::Plugin
82
101
 
83
102
  @server = WEBrick::HTTPServer.new(config)
84
103
  @server.mount(@metrics_path, MonitorServlet, self)
104
+ @server.mount(@aggregated_metrics_path, MonitorServletAll, self)
85
105
  thread_create(:in_prometheus) do
86
106
  @server.start
87
107
  end
@@ -110,5 +130,35 @@ module Fluent::Plugin
110
130
  res.body = $!.to_s
111
131
  end
112
132
  end
133
+
134
+ class MonitorServletAll < WEBrick::HTTPServlet::AbstractServlet
135
+ def initialize(server, prometheus)
136
+ @prometheus = prometheus
137
+ end
138
+
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
161
+ end
162
+ end
113
163
  end
114
164
  end
@@ -5,6 +5,7 @@ require 'fluent/plugin/prometheus'
5
5
  module Fluent::Plugin
6
6
  class PrometheusMonitorInput < Fluent::Plugin::Input
7
7
  Fluent::Plugin.register_input('prometheus_monitor', self)
8
+ include Fluent::Plugin::PrometheusLabelParser
8
9
 
9
10
  helpers :timer
10
11
 
@@ -25,8 +26,11 @@ module Fluent::Plugin
25
26
  hostname = Socket.gethostname
26
27
  expander = Fluent::Plugin::Prometheus.placeholder_expander(log)
27
28
  placeholders = expander.prepare_placeholders({'hostname' => hostname, 'worker_id' => fluentd_worker_id})
28
- @base_labels = Fluent::Plugin::Prometheus.parse_labels_elements(conf)
29
+ @base_labels = parse_labels_elements(conf)
29
30
  @base_labels.each do |key, value|
31
+ unless value.is_a?(String)
32
+ raise Fluent::ConfigError, "record accessor syntax is not available in prometheus_monitor"
33
+ end
30
34
  @base_labels[key] = expander.expand(value, placeholders)
31
35
  end
32
36
 
@@ -37,6 +41,17 @@ module Fluent::Plugin
37
41
  @monitor_agent = Fluent::MonitorAgentInput.new
38
42
  end
39
43
 
44
+ end
45
+
46
+ def start
47
+ super
48
+
49
+ @buffer_newest_timekey = @registry.gauge(
50
+ :fluentd_status_buffer_newest_timekey,
51
+ 'Newest timekey in buffer.')
52
+ @buffer_oldest_timekey = @registry.gauge(
53
+ :fluentd_status_buffer_oldest_timekey,
54
+ 'Oldest timekey in buffer.')
40
55
  buffer_queue_length = @registry.gauge(
41
56
  :fluentd_status_buffer_queue_length,
42
57
  'Current buffer queue length.')
@@ -52,20 +67,24 @@ module Fluent::Plugin
52
67
  'buffer_total_queued_size' => buffer_total_queued_size,
53
68
  'retry_count' => retry_counts,
54
69
  }
55
- end
56
-
57
- def start
58
- super
59
70
  timer_execute(:in_prometheus_monitor, @interval, &method(:update_monitor_info))
60
71
  end
61
72
 
62
73
  def update_monitor_info
63
74
  @monitor_agent.plugins_info_all.each do |info|
75
+ label = labels(info)
76
+
64
77
  @monitor_info.each do |name, metric|
65
78
  if info[name]
66
- metric.set(labels(info), info[name])
79
+ metric.set(label, info[name])
67
80
  end
68
81
  end
82
+
83
+ timekeys = info["buffer_timekeys"]
84
+ if timekeys && !timekeys.empty?
85
+ @buffer_newest_timekey.set(label, timekeys.max)
86
+ @buffer_oldest_timekey.set(label, timekeys.min)
87
+ end
69
88
  end
70
89
  end
71
90
 
@@ -5,6 +5,7 @@ require 'fluent/plugin/prometheus'
5
5
  module Fluent::Plugin
6
6
  class PrometheusOutputMonitorInput < Fluent::Input
7
7
  Fluent::Plugin.register_input('prometheus_output_monitor', self)
8
+ include Fluent::Plugin::PrometheusLabelParser
8
9
 
9
10
  helpers :timer
10
11
 
@@ -24,6 +25,10 @@ module Fluent::Plugin
24
25
  :emit_records,
25
26
  :write_count,
26
27
  :rollback_count,
28
+
29
+ # from v1.6.0
30
+ :flush_time_count,
31
+ :slow_flush_count,
27
32
  ]
28
33
 
29
34
  def initialize
@@ -40,8 +45,11 @@ module Fluent::Plugin
40
45
  hostname = Socket.gethostname
41
46
  expander = Fluent::Plugin::Prometheus.placeholder_expander(log)
42
47
  placeholders = expander.prepare_placeholders({'hostname' => hostname, 'worker_id' => fluentd_worker_id})
43
- @base_labels = Fluent::Plugin::Prometheus.parse_labels_elements(conf)
48
+ @base_labels = parse_labels_elements(conf)
44
49
  @base_labels.each do |key, value|
50
+ unless value.is_a?(String)
51
+ raise Fluent::ConfigError, "record accessor syntax is not available in prometheus_output_monitor"
52
+ end
45
53
  @base_labels[key] = expander.expand(value, placeholders)
46
54
  end
47
55
 
@@ -51,14 +59,39 @@ module Fluent::Plugin
51
59
  else
52
60
  @monitor_agent = Fluent::MonitorAgentInput.new
53
61
  end
62
+ end
63
+
64
+ def start
65
+ super
54
66
 
55
67
  @metrics = {
56
- buffer_queue_length: @registry.gauge(
57
- :fluentd_output_status_buffer_queue_length,
58
- 'Current buffer queue length.'),
68
+ # Buffer metrics
59
69
  buffer_total_queued_size: @registry.gauge(
60
70
  :fluentd_output_status_buffer_total_bytes,
61
- 'Current total size of queued buffers.'),
71
+ 'Current total size of stage and queue buffers.'),
72
+ buffer_stage_length: @registry.gauge(
73
+ :fluentd_output_status_buffer_stage_length,
74
+ 'Current length of stage buffers.'),
75
+ buffer_stage_byte_size: @registry.gauge(
76
+ :fluentd_output_status_buffer_stage_byte_size,
77
+ 'Current total size of stage buffers.'),
78
+ buffer_queue_length: @registry.gauge(
79
+ :fluentd_output_status_buffer_queue_length,
80
+ 'Current length of queue buffers.'),
81
+ buffer_queue_byte_size: @registry.gauge(
82
+ :fluentd_output_status_queue_byte_size,
83
+ 'Current total size of queue buffers.'),
84
+ buffer_available_buffer_space_ratios: @registry.gauge(
85
+ :fluentd_output_status_buffer_available_space_ratio,
86
+ 'Ratio of available space in buffer.'),
87
+ buffer_newest_timekey: @registry.gauge(
88
+ :fluentd_output_status_buffer_newest_timekey,
89
+ 'Newest timekey in buffer.'),
90
+ buffer_oldest_timekey: @registry.gauge(
91
+ :fluentd_output_status_buffer_oldest_timekey,
92
+ 'Oldest timekey in buffer.'),
93
+
94
+ # Output metrics
62
95
  retry_counts: @registry.gauge(
63
96
  :fluentd_output_status_retry_count,
64
97
  'Current retry counts.'),
@@ -77,14 +110,16 @@ module Fluent::Plugin
77
110
  rollback_count: @registry.gauge(
78
111
  :fluentd_output_status_rollback_count,
79
112
  'Current rollback counts.'),
113
+ flush_time_count: @registry.gauge(
114
+ :fluentd_output_status_flush_time_count,
115
+ 'Total flush time.'),
116
+ slow_flush_count: @registry.gauge(
117
+ :fluentd_output_status_slow_flush_count,
118
+ 'Current slow flush counts.'),
80
119
  retry_wait: @registry.gauge(
81
120
  :fluentd_output_status_retry_wait,
82
121
  'Current retry wait'),
83
122
  }
84
- end
85
-
86
- def start
87
- super
88
123
  timer_execute(:in_prometheus_output_monitor, @interval, &method(:update_monitor_info))
89
124
  end
90
125
 
@@ -99,8 +134,17 @@ module Fluent::Plugin
99
134
  }
100
135
 
101
136
  monitor_info = {
102
- 'buffer_queue_length' => @metrics[:buffer_queue_length],
137
+ # buffer metrics
103
138
  'buffer_total_queued_size' => @metrics[:buffer_total_queued_size],
139
+ 'buffer_stage_length' => @metrics[:buffer_stage_length],
140
+ 'buffer_stage_byte_size' => @metrics[:buffer_stage_byte_size],
141
+ 'buffer_queue_length' => @metrics[:buffer_queue_length],
142
+ 'buffer_queue_byte_size' => @metrics[:buffer_queue_byte_size],
143
+ 'buffer_available_buffer_space_ratios' => @metrics[:buffer_available_buffer_space_ratios],
144
+ 'buffer_newest_timekey' => @metrics[:buffer_newest_timekey],
145
+ 'buffer_oldest_timekey' => @metrics[:buffer_oldest_timekey],
146
+
147
+ # output metrics
104
148
  'retry_count' => @metrics[:retry_counts],
105
149
  }
106
150
  instance_vars_info = {
@@ -109,6 +153,8 @@ module Fluent::Plugin
109
153
  emit_count: @metrics[:emit_count],
110
154
  emit_records: @metrics[:emit_records],
111
155
  rollback_count: @metrics[:rollback_count],
156
+ flush_time_count: @metrics[:flush_time_count],
157
+ slow_flush_count: @metrics[:slow_flush_count],
112
158
  }
113
159
 
114
160
  agent_info.each do |info|
@@ -5,6 +5,7 @@ require 'fluent/plugin/prometheus'
5
5
  module Fluent::Plugin
6
6
  class PrometheusTailMonitorInput < Fluent::Plugin::Input
7
7
  Fluent::Plugin.register_input('prometheus_tail_monitor', self)
8
+ include Fluent::Plugin::PrometheusLabelParser
8
9
 
9
10
  helpers :timer
10
11
 
@@ -29,8 +30,11 @@ module Fluent::Plugin
29
30
  hostname = Socket.gethostname
30
31
  expander = Fluent::Plugin::Prometheus.placeholder_expander(log)
31
32
  placeholders = expander.prepare_placeholders({'hostname' => hostname, 'worker_id' => fluentd_worker_id})
32
- @base_labels = Fluent::Plugin::Prometheus.parse_labels_elements(conf)
33
+ @base_labels = parse_labels_elements(conf)
33
34
  @base_labels.each do |key, value|
35
+ unless value.is_a?(String)
36
+ raise Fluent::ConfigError, "record accessor syntax is not available in prometheus_tail_monitor"
37
+ end
34
38
  @base_labels[key] = expander.expand(value, placeholders)
35
39
  end
36
40
 
@@ -40,6 +44,10 @@ module Fluent::Plugin
40
44
  else
41
45
  @monitor_agent = Fluent::MonitorAgentInput.new
42
46
  end
47
+ end
48
+
49
+ def start
50
+ super
43
51
 
44
52
  @metrics = {
45
53
  position: @registry.gauge(
@@ -49,10 +57,6 @@ module Fluent::Plugin
49
57
  :fluentd_tail_file_inode,
50
58
  'Current inode of file.'),
51
59
  }
52
- end
53
-
54
- def start
55
- super
56
60
  timer_execute(:in_prometheus_tail_monitor, @interval, &method(:update_monitor_info))
57
61
  end
58
62
 
@@ -4,6 +4,7 @@ require 'fluent/plugin/prometheus'
4
4
  module Fluent::Plugin
5
5
  class PrometheusOutput < Fluent::Plugin::Output
6
6
  Fluent::Plugin.register_output('prometheus', self)
7
+ include Fluent::Plugin::PrometheusLabelParser
7
8
  include Fluent::Plugin::Prometheus
8
9
 
9
10
  def initialize
@@ -11,9 +12,13 @@ module Fluent::Plugin
11
12
  @registry = ::Prometheus::Client.registry
12
13
  end
13
14
 
15
+ def multi_workers_ready?
16
+ true
17
+ end
18
+
14
19
  def configure(conf)
15
20
  super
16
- labels = Fluent::Plugin::Prometheus.parse_labels_elements(conf)
21
+ labels = parse_labels_elements(conf)
17
22
  @metrics = Fluent::Plugin::Prometheus.parse_metrics_elements(conf, @registry, labels)
18
23
  end
19
24
 
@@ -4,6 +4,31 @@ require 'fluent/plugin/filter_record_transformer'
4
4
 
5
5
  module Fluent
6
6
  module Plugin
7
+ module PrometheusLabelParser
8
+ def configure(conf)
9
+ super
10
+ # Check if running with multiple workers
11
+ sysconf = if self.respond_to?(:owner) && owner.respond_to?(:system_config)
12
+ owner.system_config
13
+ elsif self.respond_to?(:system_config)
14
+ self.system_config
15
+ else
16
+ nil
17
+ end
18
+ @multi_worker = sysconf && sysconf.workers ? (sysconf.workers > 1) : false
19
+ end
20
+
21
+ def parse_labels_elements(conf)
22
+ base_labels = Fluent::Plugin::Prometheus.parse_labels_elements(conf)
23
+
24
+ if @multi_worker
25
+ base_labels[:worker_id] = fluentd_worker_id.to_s
26
+ end
27
+
28
+ base_labels
29
+ end
30
+ end
31
+
7
32
  module Prometheus
8
33
  class AlreadyRegisteredError < StandardError; end
9
34
 
@@ -18,7 +43,13 @@ module Fluent
18
43
  labels.first.each do |key, value|
19
44
  labels.first.has_key?(key)
20
45
 
21
- base_labels[key.to_sym] = PluginHelper::RecordAccessor::Accessor.new(value)
46
+ # use RecordAccessor only for $. and $[ syntax
47
+ # otherwise use the value as is or expand the value by RecordTransformer for ${} syntax
48
+ if value.start_with?('$.') || value.start_with?('$[')
49
+ base_labels[key.to_sym] = PluginHelper::RecordAccessor::Accessor.new(value)
50
+ else
51
+ base_labels[key.to_sym] = value
52
+ end
22
53
  end
23
54
  end
24
55
 
@@ -30,6 +61,10 @@ module Fluent
30
61
  conf.elements.select { |element|
31
62
  element.name == 'metric'
32
63
  }.each { |element|
64
+ if element.has_key?('key') && (element['key'].start_with?('$.') || element['key'].start_with?('$['))
65
+ value = element['key']
66
+ element['key'] = PluginHelper::RecordAccessor::Accessor.new(value)
67
+ end
33
68
  case element['type']
34
69
  when 'summary'
35
70
  metrics << Fluent::Plugin::Prometheus::Summary.new(element, registry, labels)
@@ -102,8 +137,11 @@ module Fluent
102
137
  def labels(record, expander, placeholders)
103
138
  label = {}
104
139
  @base_labels.each do |k, v|
105
- accessor_value = v.call(record)
106
- label[k] = accessor_value.nil? ? expander.expand(v.keys, placeholders) : accessor_value
140
+ if v.is_a?(String)
141
+ label[k] = expander.expand(v, placeholders)
142
+ else
143
+ label[k] = v.call(record)
144
+ end
107
145
  end
108
146
  label
109
147
  end
@@ -138,8 +176,13 @@ module Fluent
138
176
  end
139
177
 
140
178
  def instrument(record, expander, placeholders)
141
- if record[@key]
142
- @gauge.set(labels(record, expander, placeholders), record[@key])
179
+ if @key.is_a?(String)
180
+ value = record[@key]
181
+ else
182
+ value = @key.call(record)
183
+ end
184
+ if value
185
+ @gauge.set(labels(record, expander, placeholders), value)
143
186
  end
144
187
  end
145
188
  end
@@ -156,7 +199,13 @@ module Fluent
156
199
 
157
200
  def instrument(record, expander, placeholders)
158
201
  # use record value of the key if key is specified, otherwise just increment
159
- value = @key ? record[@key] : 1
202
+ if @key.nil?
203
+ value = 1
204
+ elsif @key.is_a?(String)
205
+ value = record[@key]
206
+ else
207
+ value = @key.call(record)
208
+ end
160
209
 
161
210
  # ignore if record value is nil
162
211
  return if value.nil?
@@ -180,8 +229,13 @@ module Fluent
180
229
  end
181
230
 
182
231
  def instrument(record, expander, placeholders)
183
- if record[@key]
184
- @summary.observe(labels(record, expander, placeholders), record[@key])
232
+ if @key.is_a?(String)
233
+ value = record[@key]
234
+ else
235
+ value = @key.call(record)
236
+ end
237
+ if value
238
+ @summary.observe(labels(record, expander, placeholders), value)
185
239
  end
186
240
  end
187
241
  end
@@ -208,8 +262,13 @@ module Fluent
208
262
  end
209
263
 
210
264
  def instrument(record, expander, placeholders)
211
- if record[@key]
212
- @histogram.observe(labels(record, expander, placeholders), record[@key])
265
+ if @key.is_a?(String)
266
+ value = record[@key]
267
+ else
268
+ value = @key.call(record)
269
+ end
270
+ if value
271
+ @histogram.observe(labels(record, expander, placeholders), value)
213
272
  end
214
273
  end
215
274
  end
@@ -0,0 +1,77 @@
1
+ module Fluent::Plugin
2
+
3
+ ##
4
+ # PromMetricsAggregator aggregates multiples metrics exposed using Prometheus text-based format
5
+ # see https://github.com/prometheus/docs/blob/master/content/docs/instrumenting/exposition_formats.md
6
+
7
+
8
+ class PrometheusMetrics
9
+ def initialize
10
+ @comments = []
11
+ @metrics = []
12
+ end
13
+
14
+ def to_string
15
+ (@comments + @metrics).join("\n")
16
+ end
17
+
18
+ def add_comment(comment)
19
+ @comments << comment
20
+ end
21
+
22
+ def add_metric_value(value)
23
+ @metrics << value
24
+ end
25
+
26
+ attr_writer :comments, :metrics
27
+ end
28
+
29
+ class PromMetricsAggregator
30
+ def initialize
31
+ @metrics = {}
32
+ end
33
+
34
+ def get_metric_name_from_comment(line)
35
+ tokens = line.split(' ')
36
+ if ['HELP', 'TYPE'].include?(tokens[1])
37
+ tokens[2]
38
+ else
39
+ ''
40
+ end
41
+ end
42
+
43
+ def add_metrics(metrics)
44
+ current_metric = ''
45
+ new_metric = false
46
+ lines = metrics.split("\n")
47
+ for line in lines
48
+ if line[0] == '#'
49
+ # Metric comment (# TYPE, # HELP)
50
+ parsed_metric = get_metric_name_from_comment(line)
51
+ if parsed_metric != ''
52
+ if parsed_metric != current_metric
53
+ # Starting a new metric comment block
54
+ new_metric = !@metrics.key?(parsed_metric)
55
+ if new_metric
56
+ @metrics[parsed_metric] = PrometheusMetrics.new()
57
+ end
58
+ current_metric = parsed_metric
59
+ end
60
+
61
+ if new_metric && parsed_metric == current_metric
62
+ # New metric, inject comments (# TYPE, # HELP)
63
+ @metrics[parsed_metric].add_comment(line)
64
+ end
65
+ end
66
+ else
67
+ # Metric value, simply append line
68
+ @metrics[current_metric].add_metric_value(line)
69
+ end
70
+ end
71
+ end
72
+
73
+ def get_metrics
74
+ @metrics.map{|k,v| v.to_string()}.join("\n") + (@metrics.length ? "\n" : "")
75
+ end
76
+ end
77
+ end
@@ -47,7 +47,7 @@ ALERT FluentdQueueLength
47
47
  }
48
48
 
49
49
  ALERT FluentdRecordsCountsHigh
50
- IF sum(rate(fluentd_record_counts{job="fluentd"}[5m])) BY (instance) > (3 * sum(rate(fluentd_record_counts{job="fluentd"}[15m])) BY (instance))
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
51
  FOR 1m
52
52
  LABELS {
53
53
  service = "fluentd",
@@ -0,0 +1,43 @@
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(:port) { 24231 }
27
+ let(:driver) { Fluent::Test::Driver::Input.new(Fluent::Plugin::PrometheusMonitorInput).configure(config) }
28
+
29
+ describe '#configure' do
30
+ describe 'valid' do
31
+ it 'does not raise error' do
32
+ expect{driver}.not_to raise_error
33
+ end
34
+ end
35
+
36
+ describe 'invalid' do
37
+ let(:config) { INVALID_MONITOR_CONFIG }
38
+ it 'expect raise error' do
39
+ expect{driver}.to raise_error
40
+ end
41
+ end
42
+ end
43
+ 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
@@ -52,6 +52,24 @@ FULL_CONFIG = BASE_CONFIG + %[
52
52
  key foo4
53
53
  </labels>
54
54
  </metric>
55
+ <metric>
56
+ name full_accessor1
57
+ type summary
58
+ desc Something with accessor.
59
+ key $.foo
60
+ <labels>
61
+ key foo5
62
+ </labels>
63
+ </metric>
64
+ <metric>
65
+ name full_accessor2
66
+ type counter
67
+ desc Something with accessor.
68
+ key $.foo
69
+ <labels>
70
+ key foo6
71
+ </labels>
72
+ </metric>
55
73
  <labels>
56
74
  test_key test_value
57
75
  </labels>
@@ -73,6 +91,18 @@ PLACEHOLDER_CONFIG = BASE_CONFIG + %[
73
91
  </labels>
74
92
  ]
75
93
 
94
+ ACCESSOR_CONFIG = BASE_CONFIG + %[
95
+ <metric>
96
+ name accessor_foo
97
+ type counter
98
+ desc Something foo.
99
+ key foo
100
+ <labels>
101
+ foo $.foo
102
+ </labels>
103
+ </metric>
104
+ ]
105
+
76
106
  COUNTER_WITHOUT_KEY_CONFIG = BASE_CONFIG + %[
77
107
  <metric>
78
108
  name without_key_foo
@@ -98,6 +128,8 @@ shared_context 'full_config' do
98
128
  let(:gauge) { registry.get(:full_bar) }
99
129
  let(:summary) { registry.get(:full_baz) }
100
130
  let(:histogram) { registry.get(:full_qux) }
131
+ let(:summary_with_accessor) { registry.get(:full_accessor1) }
132
+ let(:counter_with_accessor) { registry.get(:full_accessor2) }
101
133
  end
102
134
 
103
135
  shared_context 'placeholder_config' do
@@ -107,6 +139,13 @@ shared_context 'placeholder_config' do
107
139
  let(:counter) { registry.get(name) }
108
140
  end
109
141
 
142
+ shared_context 'accessor_config' do
143
+ let(:orig_name) { 'accessor_foo' }
144
+ let(:config) { ACCESSOR_CONFIG.gsub(orig_name, name.to_s) }
145
+ let(:name) { "#{orig_name}_#{gen_time_suffix}".to_sym }
146
+ let(:counter) { registry.get(name) }
147
+ end
148
+
110
149
  shared_context 'counter_without_key_config' do
111
150
  let(:orig_name) { 'without_key_foo' }
112
151
  let(:config) { COUNTER_WITHOUT_KEY_CONFIG.gsub(orig_name, name.to_s) }
@@ -137,6 +176,11 @@ shared_examples_for 'output configuration' do
137
176
  it { expect{driver}.not_to raise_error }
138
177
  end
139
178
 
179
+ describe 'configure accessor configuration' do
180
+ include_context 'accessor_config'
181
+ it { expect{driver}.not_to raise_error }
182
+ end
183
+
140
184
  describe 'configure counter without key configuration' do
141
185
  include_context 'counter_without_key_config'
142
186
  it { expect{driver}.not_to raise_error }
@@ -168,15 +212,20 @@ shared_examples_for 'instruments record' do
168
212
  expect(registry.metrics.map(&:name)).to include(:full_foo)
169
213
  expect(registry.metrics.map(&:name)).to include(:full_bar)
170
214
  expect(registry.metrics.map(&:name)).to include(:full_baz)
215
+ expect(registry.metrics.map(&:name)).to include(:full_accessor1)
216
+ expect(registry.metrics.map(&:name)).to include(:full_accessor2)
171
217
  expect(counter).to be_kind_of(::Prometheus::Client::Metric)
172
218
  expect(gauge).to be_kind_of(::Prometheus::Client::Metric)
173
219
  expect(summary).to be_kind_of(::Prometheus::Client::Metric)
220
+ expect(summary_with_accessor).to be_kind_of(::Prometheus::Client::Metric)
221
+ expect(counter_with_accessor).to be_kind_of(::Prometheus::Client::Metric)
174
222
  expect(histogram).to be_kind_of(::Prometheus::Client::Metric)
175
223
  end
176
224
 
177
225
  it 'instruments counter metric' do
178
226
  expect(counter.type).to eq(:counter)
179
227
  expect(counter.get({test_key: 'test_value', key: 'foo1'})).to be_kind_of(Numeric)
228
+ expect(counter_with_accessor.get({test_key: 'test_value', key: 'foo6'})).to be_kind_of(Numeric)
180
229
  end
181
230
 
182
231
  it 'instruments gauge metric' do
@@ -188,6 +237,7 @@ shared_examples_for 'instruments record' do
188
237
  expect(summary.type).to eq(:summary)
189
238
  expect(summary.get({test_key: 'test_value', key: 'foo3'})).to be_kind_of(Hash)
190
239
  expect(summary.get({test_key: 'test_value', key: 'foo3'})[0.99]).to eq(100)
240
+ expect(summary_with_accessor.get({test_key: 'test_value', key: 'foo5'})[0.99]).to eq(100)
191
241
  end
192
242
 
193
243
  it 'instruments histogram metric' do
@@ -217,6 +267,22 @@ shared_examples_for 'instruments record' do
217
267
  end
218
268
  end
219
269
 
270
+ context 'accessor config' do
271
+ include_context 'accessor_config'
272
+
273
+ before :each do
274
+ es
275
+ end
276
+
277
+ it 'expands accessor with record values' do
278
+ expect(registry.metrics.map(&:name)).to include(name)
279
+ expect(counter).to be_kind_of(::Prometheus::Client::Metric)
280
+ key, _ = counter.values.find {|k,v| v == 100 }
281
+ expect(key).to be_kind_of(Hash)
282
+ expect(key[:foo]).to eq(100)
283
+ end
284
+ end
285
+
220
286
  context 'counter_without config' do
221
287
  include_context 'counter_without_key_config'
222
288
 
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.2.0
4
+ version: 1.6.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-11-01 00:00:00.000000000 Z
11
+ date: 2019-09-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: fluentd
@@ -122,12 +122,15 @@ files:
122
122
  - lib/fluent/plugin/in_prometheus_tail_monitor.rb
123
123
  - lib/fluent/plugin/out_prometheus.rb
124
124
  - lib/fluent/plugin/prometheus.rb
125
+ - lib/fluent/plugin/prometheus_metrics.rb
125
126
  - misc/fluentd_sample.conf
126
127
  - misc/nginx_proxy.conf
127
128
  - misc/prometheus.yaml
128
129
  - misc/prometheus_alerts.yaml
129
130
  - spec/fluent/plugin/filter_prometheus_spec.rb
131
+ - spec/fluent/plugin/in_prometheus_monitor_spec.rb
130
132
  - spec/fluent/plugin/out_prometheus_spec.rb
133
+ - spec/fluent/plugin/prometheus_metrics_spec.rb
131
134
  - spec/fluent/plugin/prometheus_spec.rb
132
135
  - spec/fluent/plugin/shared.rb
133
136
  - spec/spec_helper.rb
@@ -151,13 +154,15 @@ required_rubygems_version: !ruby/object:Gem::Requirement
151
154
  version: '0'
152
155
  requirements: []
153
156
  rubyforge_project:
154
- rubygems_version: 2.6.14.1
157
+ rubygems_version: 2.7.6
155
158
  signing_key:
156
159
  specification_version: 4
157
160
  summary: A fluent plugin that collects metrics and exposes for Prometheus.
158
161
  test_files:
159
162
  - spec/fluent/plugin/filter_prometheus_spec.rb
163
+ - spec/fluent/plugin/in_prometheus_monitor_spec.rb
160
164
  - spec/fluent/plugin/out_prometheus_spec.rb
165
+ - spec/fluent/plugin/prometheus_metrics_spec.rb
161
166
  - spec/fluent/plugin/prometheus_spec.rb
162
167
  - spec/fluent/plugin/shared.rb
163
168
  - spec/spec_helper.rb