fluent-plugin-prometheus 2.2.2 → 2.3.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 +4 -4
- data/.github/ISSUE_TEMPLATE/bug_report.yaml +72 -0
- data/.github/ISSUE_TEMPLATE/config.yml +5 -0
- data/.github/ISSUE_TEMPLATE/feature_request.yaml +38 -0
- data/.github/dependabot.yml +18 -1
- data/.github/workflows/add-to-project.yml +24 -0
- data/.github/workflows/linux.yml +2 -2
- data/ChangeLog +13 -0
- data/README.md +128 -1
- data/fluent-plugin-prometheus.gemspec +1 -1
- data/lib/fluent/plugin/filter_prometheus.rb +1 -1
- data/lib/fluent/plugin/in_prometheus.rb +23 -3
- data/lib/fluent/plugin/out_prometheus.rb +3 -1
- data/lib/fluent/plugin/prometheus/log_throttle.rb +45 -0
- data/lib/fluent/plugin/prometheus/placeholder_expander.rb +15 -1
- data/lib/fluent/plugin/prometheus.rb +299 -15
- data/spec/fluent/plugin/filter_prometheus_spec.rb +141 -0
- data/spec/fluent/plugin/in_prometheus_spec.rb +204 -1
- data/spec/fluent/plugin/out_prometheus_spec.rb +29 -1
- data/spec/fluent/plugin/prometheus/log_throttle_spec.rb +127 -0
- data/spec/fluent/plugin/prometheus/placeholder_expander_spec.rb +96 -0
- data/spec/fluent/plugin/prometheus/series_limit_spec.rb +469 -0
- data/spec/fluent/plugin/shared.rb +107 -0
- metadata +11 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c10a2e202128626380ce6fd1003ca82baa6f1ae55bd41642b8f6c0bc44670abc
|
|
4
|
+
data.tar.gz: 34a77887e5da8f4bb4dc08018478a1592d7dec51411e338b4773ab41ec281e06
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 131d844af8a45deb00d2ee53dba0928534a104193aec9a26f5d0760600ffefa2c11cb284fa6e49ae81f1cb4e17520db1b62a2a1acc6af295b964bdfa4c35aa5c
|
|
7
|
+
data.tar.gz: b9da9de5e2019b290ccd45bfca81ad59cdf7942109e961f8919d1121596e00bc63661cf76825251e4f0a9b796929830a6a7a7dade75ddcc00785f0c901317476
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
name: Bug Report
|
|
2
|
+
description: Create a report with a procedure for reproducing the bug
|
|
3
|
+
labels: "waiting-for-triage"
|
|
4
|
+
body:
|
|
5
|
+
- type: markdown
|
|
6
|
+
attributes:
|
|
7
|
+
value: |
|
|
8
|
+
Please check the [README](https://github.com/fluent/fluent-plugin-prometheus/blob/master/README.md) first. To help us investigate the problem, please provide the following information.
|
|
9
|
+
- type: textarea
|
|
10
|
+
id: description
|
|
11
|
+
attributes:
|
|
12
|
+
label: Describe the bug
|
|
13
|
+
description: A clear and concise description of what the bug is
|
|
14
|
+
validations:
|
|
15
|
+
required: true
|
|
16
|
+
- type: textarea
|
|
17
|
+
id: reproduce
|
|
18
|
+
attributes:
|
|
19
|
+
label: To Reproduce
|
|
20
|
+
description: Steps to reproduce the behavior
|
|
21
|
+
validations:
|
|
22
|
+
required: true
|
|
23
|
+
- type: textarea
|
|
24
|
+
id: expected
|
|
25
|
+
attributes:
|
|
26
|
+
label: Expected behavior
|
|
27
|
+
description: A clear and concise description of what you expected to happen
|
|
28
|
+
validations:
|
|
29
|
+
required: true
|
|
30
|
+
- type: textarea
|
|
31
|
+
id: environment
|
|
32
|
+
attributes:
|
|
33
|
+
label: Your Environment
|
|
34
|
+
description: |
|
|
35
|
+
- Fluentd or td-agent version: `fluentd --version` or `td-agent --version`
|
|
36
|
+
- Operating system: `cat /etc/os-release`
|
|
37
|
+
- Kernel version: `uname -r`
|
|
38
|
+
|
|
39
|
+
Tip: If you hit the problem with older fluentd version, try latest version first.
|
|
40
|
+
value: |
|
|
41
|
+
- Fluentd version:
|
|
42
|
+
- TD Agent/Fluent Package version:
|
|
43
|
+
- fluent-plugin-prometheus version:
|
|
44
|
+
- prometheus-client version:
|
|
45
|
+
- Operating system:
|
|
46
|
+
- Kernel version:
|
|
47
|
+
render: markdown
|
|
48
|
+
validations:
|
|
49
|
+
required: true
|
|
50
|
+
- type: textarea
|
|
51
|
+
id: configuration
|
|
52
|
+
attributes:
|
|
53
|
+
label: Your Configuration
|
|
54
|
+
description: |
|
|
55
|
+
Write your configuration here. Minimum reproducible fluentd.conf is recommended.
|
|
56
|
+
validations:
|
|
57
|
+
required: true
|
|
58
|
+
- type: textarea
|
|
59
|
+
id: logs
|
|
60
|
+
attributes:
|
|
61
|
+
label: Your Error Log
|
|
62
|
+
description: Write your ALL error log here
|
|
63
|
+
render: shell
|
|
64
|
+
validations:
|
|
65
|
+
required: true
|
|
66
|
+
- type: textarea
|
|
67
|
+
id: addtional-context
|
|
68
|
+
attributes:
|
|
69
|
+
label: Additional context
|
|
70
|
+
description: Add any other context about the problem here.
|
|
71
|
+
validations:
|
|
72
|
+
required: false
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
name: Feature request
|
|
2
|
+
description: Suggest an idea for this project
|
|
3
|
+
labels: "waiting-for-triage"
|
|
4
|
+
body:
|
|
5
|
+
- type: markdown
|
|
6
|
+
attributes:
|
|
7
|
+
value: |
|
|
8
|
+
Please check the [README](https://github.com/fluent/fluent-plugin-prometheus/blob/master/README.md) first. To help us understand the request, please provide the following information.
|
|
9
|
+
- type: textarea
|
|
10
|
+
id: description
|
|
11
|
+
attributes:
|
|
12
|
+
label: Is your feature request related to a problem? Please describe.
|
|
13
|
+
description: |
|
|
14
|
+
A clear and concise description of what the problem is.
|
|
15
|
+
Ex. I'm always frustrated when [...]
|
|
16
|
+
validations:
|
|
17
|
+
required: true
|
|
18
|
+
- type: textarea
|
|
19
|
+
id: solution
|
|
20
|
+
attributes:
|
|
21
|
+
label: Describe the solution you'd like
|
|
22
|
+
description: A clear and concise description of what you want to happen.
|
|
23
|
+
validations:
|
|
24
|
+
required: true
|
|
25
|
+
- type: textarea
|
|
26
|
+
id: alternative
|
|
27
|
+
attributes:
|
|
28
|
+
label: Describe alternatives you've considered
|
|
29
|
+
description: A clear and concise description of any alternative solutions or features you've considered.
|
|
30
|
+
validations:
|
|
31
|
+
required: true
|
|
32
|
+
- type: textarea
|
|
33
|
+
id: addtional-context
|
|
34
|
+
attributes:
|
|
35
|
+
label: Additional context
|
|
36
|
+
description: Add any other context or screenshots about the feature request here.
|
|
37
|
+
validations:
|
|
38
|
+
required: false
|
data/.github/dependabot.yml
CHANGED
|
@@ -3,4 +3,21 @@ updates:
|
|
|
3
3
|
- package-ecosystem: 'github-actions'
|
|
4
4
|
directory: '/'
|
|
5
5
|
schedule:
|
|
6
|
-
interval: '
|
|
6
|
+
interval: 'monthly'
|
|
7
|
+
groups:
|
|
8
|
+
# PR: "Security update [package] from [old] to [new]"
|
|
9
|
+
# This PR should be merged in hurry
|
|
10
|
+
security-updates:
|
|
11
|
+
applies-to: security-updates
|
|
12
|
+
patterns:
|
|
13
|
+
- '*'
|
|
14
|
+
|
|
15
|
+
# PR: "Bump [package] from [old] to [new]"
|
|
16
|
+
# No need to be merged this PR in hurry. It is enough to merge
|
|
17
|
+
# once in a month.
|
|
18
|
+
monthly-updates:
|
|
19
|
+
applies-to: version-updates
|
|
20
|
+
patterns:
|
|
21
|
+
- '*'
|
|
22
|
+
# Allow to create PR both of security and normal updates.
|
|
23
|
+
open-pull-requests-limit: 1
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
name: Add bugs to fluent project
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
issues:
|
|
5
|
+
types:
|
|
6
|
+
- opened
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
add-to-project:
|
|
10
|
+
name: Add issue to project
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
steps:
|
|
13
|
+
- name: Generate token
|
|
14
|
+
id: generate_token
|
|
15
|
+
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
|
|
16
|
+
with:
|
|
17
|
+
app-id: ${{ secrets.PROJECT_APP_ID }}
|
|
18
|
+
private-key: ${{ secrets.PROJECT_APP_PRIVATE_KEY }}
|
|
19
|
+
owner: fluent
|
|
20
|
+
- uses: actions/add-to-project@5afcf98fcd03f1c2f92c3c83f58ae24323cc57fd # v2.0.0
|
|
21
|
+
with:
|
|
22
|
+
project-url: https://github.com/orgs/fluent/projects/4
|
|
23
|
+
github-token: ${{ steps.generate_token.outputs.token }}
|
|
24
|
+
labeled: waiting-for-triage
|
data/.github/workflows/linux.yml
CHANGED
|
@@ -27,8 +27,8 @@ jobs:
|
|
|
27
27
|
experimental: [false]
|
|
28
28
|
name: Ruby ${{ matrix.ruby }} unit testing on ${{ matrix.os }}
|
|
29
29
|
steps:
|
|
30
|
-
- uses: actions/checkout@
|
|
31
|
-
- uses: ruby/setup-ruby@v1
|
|
30
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
31
|
+
- uses: ruby/setup-ruby@95ef2b042f9d7a56d8268cba8559e2842e2ad01b # v1.321.0
|
|
32
32
|
with:
|
|
33
33
|
ruby-version: ${{ matrix.ruby }}
|
|
34
34
|
- name: unit testing
|
data/ChangeLog
CHANGED
|
@@ -1,3 +1,16 @@
|
|
|
1
|
+
Release 2.3.0 - 2026/09/02
|
|
2
|
+
|
|
3
|
+
* in_prometheus: Change default bind address to 127.0.0.1. (#258)
|
|
4
|
+
This is incompatible behavior change.
|
|
5
|
+
* in_prometheus: Do not disclosure error details for client (#259)
|
|
6
|
+
* in_prometheus: Add `ignore_error_log_interval` parameter to suppress repeated error logs (#259,#264)
|
|
7
|
+
This introduces the log throttling feature.
|
|
8
|
+
* filter_prometheus: Do not let placeholders built from records override the tag ones (#262)
|
|
9
|
+
* out_prometheus: Fix a bug that a failing record never reached to @ERROR (#263)
|
|
10
|
+
* Support `max_series_per_metric` to limit label sets cardinarity. (#265)
|
|
11
|
+
* Refuse wrong <initlabels> which cannot fit into `max_series_per_metric` (#266,#267)
|
|
12
|
+
This blocks `max_series_per_metric` mis-configuration on startup.
|
|
13
|
+
|
|
1
14
|
Release 2.2.2 - 2026/03/27
|
|
2
15
|
|
|
3
16
|
* in_prometheus: fix: Add IPv6 support for bind parameter (#240)
|
data/README.md
CHANGED
|
@@ -59,11 +59,12 @@ With following configuration, you can access http://localhost:24231/metrics on a
|
|
|
59
59
|
|
|
60
60
|
More configuration parameters:
|
|
61
61
|
|
|
62
|
-
- `bind`: binding interface (default: '
|
|
62
|
+
- `bind`: binding interface (default: '127.0.0.1')
|
|
63
63
|
- `port`: listen port (default: 24231)
|
|
64
64
|
- `metrics_path`: metrics HTTP endpoint (default: /metrics)
|
|
65
65
|
- `aggregated_metrics_path`: metrics HTTP endpoint (default: /aggregated_metrics)
|
|
66
66
|
- `content_encoding`: encoding format for the exposed metrics (default: identity). Supported formats are {identity, gzip}
|
|
67
|
+
- `ignore_error_log_interval`: Suppress repeated error logs in a certain period of time or until message was changed (default: 1h)
|
|
67
68
|
|
|
68
69
|
When using multiple workers, each worker binds to port + `fluent_worker_id`.
|
|
69
70
|
To scrape metrics from all workers at once, you can access http://localhost:24231/aggregated_metrics.
|
|
@@ -265,6 +266,132 @@ You can access nested keys in records via dot or bracket notation (https://docs.
|
|
|
265
266
|
|
|
266
267
|
See Supported Metric Type and Labels for more configuration parameters.
|
|
267
268
|
|
|
269
|
+
#### Limiting label expansion
|
|
270
|
+
|
|
271
|
+
Label values come from records, so a metric grows unboundedly when a label is
|
|
272
|
+
bound to a field with many distinct values. Both plugins can bound it with
|
|
273
|
+
`max_series_per_metric`: once a metric holds that many label sets, a record
|
|
274
|
+
which brings a new one is dropped, while the label sets already known keep
|
|
275
|
+
being instrumented.
|
|
276
|
+
|
|
277
|
+
|parameter|description|default|
|
|
278
|
+
|---|---|---|
|
|
279
|
+
|max_series_per_metric|The maximum number of label sets a metric can hold. `0` means unlimited.|0|
|
|
280
|
+
|ignore_error_log_interval|The interval in seconds to suppress the repeated warning about the drops. `0` logs every occurrence.|3600|
|
|
281
|
+
|
|
282
|
+
**The limit is disabled by default and must be enabled explicitly**, since a
|
|
283
|
+
dropped record is lost and cannot be recovered. A `<metric>` section overrides
|
|
284
|
+
the value given to the plugin, so that a metric which expands faster than the
|
|
285
|
+
others is bound on its own, while one whose labels are known to be bounded
|
|
286
|
+
stays unlimited with `0`:
|
|
287
|
+
|
|
288
|
+
```
|
|
289
|
+
<filter message>
|
|
290
|
+
@type prometheus
|
|
291
|
+
max_series_per_metric 1000
|
|
292
|
+
<metric>
|
|
293
|
+
name message_foo_counter
|
|
294
|
+
type counter
|
|
295
|
+
desc The total number of foo in message.
|
|
296
|
+
key foo
|
|
297
|
+
max_series_per_metric 10
|
|
298
|
+
<labels>
|
|
299
|
+
path $.kubernetes.pod_name
|
|
300
|
+
</labels>
|
|
301
|
+
</metric>
|
|
302
|
+
</filter>
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
The label sets are counted per metric name, not per `<metric>` section: sections
|
|
306
|
+
with the same `name`, in one plugin or in two, share one count. Each of them
|
|
307
|
+
refuses a new label set once that shared count reaches its own limit, so a
|
|
308
|
+
section which stays at `0` adds label sets without counting them. Its
|
|
309
|
+
`<initlabels>` are counted anyway. They come from the configuration and their
|
|
310
|
+
number is fixed. The metric holds them in every section.
|
|
311
|
+
|
|
312
|
+
The count is per worker process as well, since a worker has its own registry and
|
|
313
|
+
exposes the metrics it holds itself. With `workers N`, a metric can hold up to N
|
|
314
|
+
times `max_series_per_metric` label sets in total, so divide the number of label
|
|
315
|
+
sets the metric may reach by the number of workers.
|
|
316
|
+
|
|
317
|
+
A record which fails to be instrumented, for example when the value of `key` is
|
|
318
|
+
not a number, does not consume the limit. A pre-initialized label set
|
|
319
|
+
(`initialized` and `<initlabels>`) consumes it from the start, since the metric
|
|
320
|
+
holds it before any record arrives.
|
|
321
|
+
|
|
322
|
+
A `<metric>` section is refused at startup with a configuration error when the
|
|
323
|
+
`<initlabels>` label sets already fill its limit. The limit is exceeded before
|
|
324
|
+
any record arrives, and the section can never take a new label set.
|
|
325
|
+
|
|
326
|
+
These label sets are shared by every section with the same `name`. A section can
|
|
327
|
+
be refused because of another section:
|
|
328
|
+
|
|
329
|
+
```
|
|
330
|
+
<metric>
|
|
331
|
+
name shared
|
|
332
|
+
type counter
|
|
333
|
+
desc Something foo.
|
|
334
|
+
max_series_per_metric 2
|
|
335
|
+
initialized true
|
|
336
|
+
<labels>
|
|
337
|
+
path $.path
|
|
338
|
+
</labels>
|
|
339
|
+
<initlabels>
|
|
340
|
+
path /a
|
|
341
|
+
</initlabels>
|
|
342
|
+
<initlabels>
|
|
343
|
+
path /b
|
|
344
|
+
</initlabels>
|
|
345
|
+
</metric>
|
|
346
|
+
<metric>
|
|
347
|
+
name shared # the same name, so the 2 label sets count here too
|
|
348
|
+
type counter
|
|
349
|
+
desc Something foo.
|
|
350
|
+
max_series_per_metric 1 # refused: 2 label sets do not fit into 1
|
|
351
|
+
<labels>
|
|
352
|
+
path $.path
|
|
353
|
+
</labels>
|
|
354
|
+
</metric>
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
The second section is refused even though it declares no `<initlabels>` of its
|
|
358
|
+
own. The same happens when the first section sets `max_series_per_metric 0`.
|
|
359
|
+
The metric holds its label sets in both cases. A limit equal to their number is
|
|
360
|
+
fine because all label sets of the metric are known in advance.
|
|
361
|
+
|
|
362
|
+
The check runs after every `<metric>` section of a plugin is read. It does not
|
|
363
|
+
depend on the order of the sections. Sections that share a `name` across two
|
|
364
|
+
plugins are only checked against the sections read before them.
|
|
365
|
+
|
|
366
|
+
The check runs again when Fluentd reloads the configuration. It counts only the
|
|
367
|
+
label sets from `<initlabels>`. It does not count the label sets that records
|
|
368
|
+
brought, so the metric does not make the reload fail with the label sets it took
|
|
369
|
+
while it was running.
|
|
370
|
+
|
|
371
|
+
A reload does not clear the registry. The metric still holds the label sets from
|
|
372
|
+
the `<initlabels>` of the old configuration, and the check counts them too. So
|
|
373
|
+
it can refuse a new configuration which has fewer `<initlabels>` than the old
|
|
374
|
+
one. Restart the worker to drop them.
|
|
375
|
+
|
|
376
|
+
##### Observing what the limit leaves out
|
|
377
|
+
|
|
378
|
+
A dropped label set is not routed to `@ERROR`, because it is what the
|
|
379
|
+
configuration asks for. It is reported in two ways instead:
|
|
380
|
+
|
|
381
|
+
* a warning in the Fluentd log, throttled per metric: it is suppressed for
|
|
382
|
+
`ignore_error_log_interval` seconds and reports how many warnings were
|
|
383
|
+
suppressed in the meantime.
|
|
384
|
+
* `fluentd_prometheus_dropped_label_sets_total{name}`, which counts the records
|
|
385
|
+
the metric `name` did not instrument. It is registered on the first drop, so
|
|
386
|
+
it does not show up as long as nothing is dropped, and its label comes from
|
|
387
|
+
the configuration and not from a record, so it cannot expand on its own.
|
|
388
|
+
|
|
389
|
+
Alert on the counter to notice that a metric is losing records:
|
|
390
|
+
|
|
391
|
+
```
|
|
392
|
+
rate(fluentd_prometheus_dropped_label_sets_total[5m]) > 0
|
|
393
|
+
```
|
|
394
|
+
|
|
268
395
|
## Supported Metric Types
|
|
269
396
|
|
|
270
397
|
For details of each metric type, see [Prometheus documentation](http://prometheus.io/docs/concepts/metric_types/). Also see [metric name guide](http://prometheus.io/docs/practices/naming/).
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Gem::Specification.new do |spec|
|
|
2
2
|
spec.name = "fluent-plugin-prometheus"
|
|
3
|
-
spec.version = "2.
|
|
3
|
+
spec.version = "2.3.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.}
|
|
@@ -19,7 +19,7 @@ module Fluent::Plugin
|
|
|
19
19
|
def configure(conf)
|
|
20
20
|
super
|
|
21
21
|
labels = parse_labels_elements(conf)
|
|
22
|
-
@metrics = Fluent::Plugin::Prometheus.parse_metrics_elements(conf, @registry, labels)
|
|
22
|
+
@metrics = Fluent::Plugin::Prometheus.parse_metrics_elements(conf, @registry, labels, metric_options)
|
|
23
23
|
end
|
|
24
24
|
|
|
25
25
|
def filter(tag, time, record)
|
|
@@ -11,7 +11,7 @@ module Fluent::Plugin
|
|
|
11
11
|
|
|
12
12
|
helpers :thread, :http_server
|
|
13
13
|
|
|
14
|
-
config_param :bind, :string, default: '
|
|
14
|
+
config_param :bind, :string, default: '127.0.0.1'
|
|
15
15
|
config_param :port, :integer, default: 24231
|
|
16
16
|
config_param :metrics_path, :string, default: '/metrics'
|
|
17
17
|
config_param :aggregated_metrics_path, :string, default: '/aggregated_metrics'
|
|
@@ -36,10 +36,14 @@ module Fluent::Plugin
|
|
|
36
36
|
desc 'Content encoding of the exposed metrics, Currently supported encoding is identity, gzip. Ref: https://prometheus.io/docs/instrumenting/exposition_formats/#basic-info'
|
|
37
37
|
config_param :content_encoding, :enum, list: [:identity, :gzip], default: :identity
|
|
38
38
|
|
|
39
|
+
desc 'Suppress repeated error logs in a certain period of time (1h) or until message was changed'
|
|
40
|
+
config_param :ignore_error_log_interval, :time, default: 3600
|
|
41
|
+
|
|
39
42
|
def initialize
|
|
40
43
|
super
|
|
41
44
|
@registry = ::Prometheus::Client.registry
|
|
42
45
|
@secure = nil
|
|
46
|
+
@error_log_throttle = nil
|
|
43
47
|
end
|
|
44
48
|
|
|
45
49
|
def configure(conf)
|
|
@@ -58,6 +62,8 @@ module Fluent::Plugin
|
|
|
58
62
|
|
|
59
63
|
@base_port = @port
|
|
60
64
|
@port += fluentd_worker_id
|
|
65
|
+
|
|
66
|
+
@error_log_throttle = Fluent::Plugin::Prometheus::LogThrottle.new(@ignore_error_log_interval)
|
|
61
67
|
end
|
|
62
68
|
|
|
63
69
|
def multi_workers_ready?
|
|
@@ -210,7 +216,8 @@ module Fluent::Plugin
|
|
|
210
216
|
def all_metrics
|
|
211
217
|
response(::Prometheus::Client::Formats::Text.marshal(@registry))
|
|
212
218
|
rescue => e
|
|
213
|
-
|
|
219
|
+
log_error_throttled(:metrics, "in_prometheus: failed to render metrics", error: e)
|
|
220
|
+
[500, { 'Content-Type' => 'text/plain' }, "in_prometheus server error: <#{e.class}>"]
|
|
214
221
|
end
|
|
215
222
|
|
|
216
223
|
def all_workers_metrics
|
|
@@ -223,7 +230,8 @@ module Fluent::Plugin
|
|
|
223
230
|
end
|
|
224
231
|
response(full_result.get_metrics)
|
|
225
232
|
rescue => e
|
|
226
|
-
|
|
233
|
+
log_error_throttled(:workers_metrics, "in_prometheus: failed to render workers metrics", error: e)
|
|
234
|
+
[500, { 'Content-Type' => 'text/plain' }, "in_prometheus server error: <#{e.class}>"]
|
|
227
235
|
end
|
|
228
236
|
|
|
229
237
|
def send_request_to_each_worker
|
|
@@ -271,5 +279,17 @@ module Fluent::Plugin
|
|
|
271
279
|
end
|
|
272
280
|
[200, { 'Content-Type' => ::Prometheus::Client::Formats::Text::CONTENT_TYPE, 'Content-Encoding' => @content_encoding.to_s }, body]
|
|
273
281
|
end
|
|
282
|
+
|
|
283
|
+
def log_error_throttled(scope, message, error:)
|
|
284
|
+
fingerprint = [error.class, error.message]
|
|
285
|
+
emit, suppressed = @error_log_throttle.check(scope, fingerprint)
|
|
286
|
+
return unless emit
|
|
287
|
+
|
|
288
|
+
if suppressed > 0
|
|
289
|
+
log.error message, error_class: error.class, error: error, suppressed_log_count: suppressed
|
|
290
|
+
else
|
|
291
|
+
log.error message, error_class: error.class, error: error
|
|
292
|
+
end
|
|
293
|
+
end
|
|
274
294
|
end
|
|
275
295
|
end
|
|
@@ -7,6 +7,8 @@ module Fluent::Plugin
|
|
|
7
7
|
include Fluent::Plugin::PrometheusLabelParser
|
|
8
8
|
include Fluent::Plugin::Prometheus
|
|
9
9
|
|
|
10
|
+
helpers :event_emitter
|
|
11
|
+
|
|
10
12
|
def initialize
|
|
11
13
|
super
|
|
12
14
|
@registry = ::Prometheus::Client.registry
|
|
@@ -19,7 +21,7 @@ module Fluent::Plugin
|
|
|
19
21
|
def configure(conf)
|
|
20
22
|
super
|
|
21
23
|
labels = parse_labels_elements(conf)
|
|
22
|
-
@metrics = Fluent::Plugin::Prometheus.parse_metrics_elements(conf, @registry, labels)
|
|
24
|
+
@metrics = Fluent::Plugin::Prometheus.parse_metrics_elements(conf, @registry, labels, metric_options)
|
|
23
25
|
end
|
|
24
26
|
|
|
25
27
|
def process(tag, es)
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
require 'fluent/clock'
|
|
2
|
+
|
|
3
|
+
module Fluent
|
|
4
|
+
module Plugin
|
|
5
|
+
module Prometheus
|
|
6
|
+
# Suppresses the repeated log for the same key within the interval.
|
|
7
|
+
# in_prometheus and filter/out_prometheus use it, each with its own
|
|
8
|
+
# instance. The key decides what is throttled: an error scope or a
|
|
9
|
+
# metric. When a fingerprint is given, a log whose fingerprint differs
|
|
10
|
+
# from the last one is not suppressed.
|
|
11
|
+
class LogThrottle
|
|
12
|
+
Entry = Struct.new(:time, :fingerprint, :suppressed)
|
|
13
|
+
|
|
14
|
+
def initialize(interval)
|
|
15
|
+
@interval = interval
|
|
16
|
+
@mutex = Mutex.new
|
|
17
|
+
# one entry per key, so this does not grow without a limit
|
|
18
|
+
@entries = {}
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Returns [emit, suppressed_count]. emit is true for the first log of a
|
|
22
|
+
# key, for a new fingerprint, and after the interval has passed.
|
|
23
|
+
# suppressed_count is how many logs were suppressed since the last one
|
|
24
|
+
# was emitted. Without a fingerprint, a key is throttled by the
|
|
25
|
+
# interval alone.
|
|
26
|
+
def check(key, fingerprint = nil)
|
|
27
|
+
return [true, 0] if @interval <= 0
|
|
28
|
+
|
|
29
|
+
@mutex.synchronize do
|
|
30
|
+
now = Fluent::Clock.now
|
|
31
|
+
last = @entries[key]
|
|
32
|
+
if last.nil? || last.fingerprint != fingerprint || (now - last.time) >= @interval
|
|
33
|
+
suppressed = (last && last.fingerprint == fingerprint) ? last.suppressed : 0
|
|
34
|
+
@entries[key] = Entry.new(now, fingerprint, 0)
|
|
35
|
+
[true, suppressed]
|
|
36
|
+
else
|
|
37
|
+
last.suppressed += 1
|
|
38
|
+
[false, 0]
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -2,6 +2,10 @@ module Fluent
|
|
|
2
2
|
module Plugin
|
|
3
3
|
module Prometheus
|
|
4
4
|
class ExpandBuilder
|
|
5
|
+
# ${tag}, ${tag_parts[...]}, ${tag_prefix[...]} and ${tag_suffix[...]}
|
|
6
|
+
# must be built from the tag only.
|
|
7
|
+
TAG_DERIVED_PLACEHOLDER = /\A\$\{tag(_parts|_prefix|_suffix)?(\[[^\]]*\])?\}\z/.freeze
|
|
8
|
+
|
|
5
9
|
def self.build(placeholder, log:)
|
|
6
10
|
new(log: log).build(placeholder)
|
|
7
11
|
end
|
|
@@ -12,6 +16,7 @@ module Fluent
|
|
|
12
16
|
|
|
13
17
|
def build(placeholder_values)
|
|
14
18
|
placeholders = {}
|
|
19
|
+
tag_placeholders = {}
|
|
15
20
|
placeholder_values.each do |key, value|
|
|
16
21
|
case value
|
|
17
22
|
when Array
|
|
@@ -26,13 +31,22 @@ module Fluent
|
|
|
26
31
|
end
|
|
27
32
|
else
|
|
28
33
|
if key == 'tag'
|
|
29
|
-
|
|
34
|
+
tag_placeholders = build_tag(value)
|
|
30
35
|
else
|
|
31
36
|
placeholders["${#{key}}"] = value
|
|
32
37
|
end
|
|
33
38
|
end
|
|
34
39
|
end
|
|
35
40
|
|
|
41
|
+
# A record may have an array named "tag_parts", or a key named
|
|
42
|
+
# "tag_parts[0]". Both make the same placeholder as the tag does.
|
|
43
|
+
# merge! is not enough here, because a record can also use an index
|
|
44
|
+
# which build_tag does not make, such as ${tag_parts[3]} for a tag
|
|
45
|
+
# of 3 parts, or ${tag_prefix[-1]}. So remove them first, then such
|
|
46
|
+
# a placeholder stays unknown.
|
|
47
|
+
placeholders.delete_if { |k, _| TAG_DERIVED_PLACEHOLDER.match?(k) }
|
|
48
|
+
placeholders.merge!(tag_placeholders)
|
|
49
|
+
|
|
36
50
|
Fluent::Plugin::Prometheus::ExpandBuilder::PlaceholderExpander.new(@log, placeholders)
|
|
37
51
|
end
|
|
38
52
|
|