fluent-plugin-prometheus 1.2.0 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/.travis.yml +3 -3
- data/README.md +44 -24
- data/fluent-plugin-prometheus.gemspec +1 -1
- data/lib/fluent/plugin/filter_prometheus.rb +6 -1
- data/lib/fluent/plugin/in_prometheus.rb +50 -0
- data/lib/fluent/plugin/in_prometheus_monitor.rb +25 -6
- data/lib/fluent/plugin/in_prometheus_output_monitor.rb +56 -10
- data/lib/fluent/plugin/in_prometheus_tail_monitor.rb +9 -5
- data/lib/fluent/plugin/out_prometheus.rb +6 -1
- data/lib/fluent/plugin/prometheus.rb +69 -10
- data/lib/fluent/plugin/prometheus_metrics.rb +77 -0
- data/misc/prometheus_alerts.yaml +1 -1
- data/spec/fluent/plugin/in_prometheus_monitor_spec.rb +43 -0
- data/spec/fluent/plugin/prometheus_metrics_spec.rb +138 -0
- data/spec/fluent/plugin/shared.rb +66 -0
- metadata +8 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 3f079822fa7231b77912e5ac1324b691f38dbf1f1f32fd8700dee19bc636fd8c
|
4
|
+
data.tar.gz: 58ad623a333cc1600e971fdd35b9b2c7d4a381c03a954d99206233758e4562f6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4394983e398e9e4b116f54927b7ad82778ab672b27e41bfc1ef3eb5421f3f3cde7899ce906d86de8862179c0293c1831c0a555553f21c10787dddba22c68fe1e
|
7
|
+
data.tar.gz: f8d52d61a493f4c8abfc88a1cfdc415779a4946eeed639b03545574b2a86304d7a560c026391897ab93596280be306a02c24d3dcdbc161c30f625c211d237711
|
data/.travis.yml
CHANGED
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
|
46
|
-
This plugin provides a metrics HTTP endpoint to be scraped by a
|
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 (
|
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](
|
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
|
-
|
71
|
-
|
72
|
-
- `
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
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
|
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
|
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
|
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
|
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.
|
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 =
|
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 =
|
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(
|
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 =
|
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
|
-
|
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
|
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
|
-
|
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 =
|
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 =
|
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
|
-
|
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
|
-
|
106
|
-
|
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
|
142
|
-
|
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
|
-
|
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
|
184
|
-
|
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
|
212
|
-
|
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
|
data/misc/prometheus_alerts.yaml
CHANGED
@@ -47,7 +47,7 @@ ALERT FluentdQueueLength
|
|
47
47
|
}
|
48
48
|
|
49
49
|
ALERT FluentdRecordsCountsHigh
|
50
|
-
IF sum(rate(
|
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.
|
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:
|
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
|
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
|