Compare commits

...

91 commits

Author SHA1 Message Date
Pedro Tanaka
d9e9dcd39c
Merge pull request #645 from mmorel-35/gofumpt
chore: enable gofumpt with extra rules
2025-08-26 13:41:49 +02:00
Pedro Tanaka
c349fbcb34
Merge pull request #646 from mmorel-35/staticcheck/all
chore: enable all rules from staticcheck
2025-08-26 13:40:58 +02:00
Matthieu MOREL
93a61f6927 chore: enable all rules from staticcheck
Signed-off-by: Matthieu MOREL <matthieu.morel35@gmail.com>
2025-08-25 22:02:26 +00:00
Matthieu MOREL
34fff57424 chore: enable gofumpt with extra rules
Signed-off-by: Matthieu MOREL <matthieu.morel35@gmail.com>
2025-08-25 21:52:29 +00:00
Pedro Tanaka
144bc6bdb5
Merge pull request #629 from mmorel-35/golangci-lint/clean-up
chore: clean up golangci-lint configuration
2025-08-13 21:58:57 +02:00
Matthias Rampke
3eff3c0cc7
Merge pull request #644 from prometheus/repo_sync
Synchronize common files from prometheus/prometheus
2025-08-01 23:59:28 +02:00
prombot
fa4ca034b6 Update common Prometheus files
Signed-off-by: prombot <prometheus-team@googlegroups.com>
2025-08-01 21:48:47 +00:00
Matthieu MOREL
0dbbd7e2a4 chore: clean up golangci-lint configuration
Signed-off-by: Matthieu MOREL <matthieu.morel35@gmail.com>
2025-08-01 23:11:40 +02:00
Matthias Rampke
9fbaeeeaaf
Merge pull request #643 from prometheus/dependabot/go_modules/github.com/prometheus/client_golang-1.23.0
Bump github.com/prometheus/client_golang from 1.22.0 to 1.23.0
2025-08-01 22:35:32 +02:00
Matthias Rampke
848039ff9e
Merge pull request #641 from prometheus/repo_sync
Synchronize common files from prometheus/prometheus
2025-08-01 21:37:09 +02:00
dependabot[bot]
c2c7fb083c
Bump github.com/prometheus/client_golang from 1.22.0 to 1.23.0
Bumps [github.com/prometheus/client_golang](https://github.com/prometheus/client_golang) from 1.22.0 to 1.23.0.
- [Release notes](https://github.com/prometheus/client_golang/releases)
- [Changelog](https://github.com/prometheus/client_golang/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prometheus/client_golang/compare/v1.22.0...v1.23.0)

---
updated-dependencies:
- dependency-name: github.com/prometheus/client_golang
  dependency-version: 1.23.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-01 10:27:24 +00:00
Matthias Rampke
c223653967
Merge pull request #642 from prometheus/mr/modern-starter-config
Extract and modernize starter configuration
2025-07-21 09:39:15 +02:00
Matthias Rampke
eaeb9287f9
summary options are only used with summaries
Signed-off-by: Matthias Rampke <matthias.rampke@googlemail.com>
2025-07-21 07:32:56 +00:00
Matthias Rampke
f1f841310f
comment on observer_type
Signed-off-by: Matthias Rampke <matthias.rampke@googlemail.com>
2025-07-21 07:31:49 +00:00
Matthias Rampke
e8b902793d
note that summaries are not recommended
Co-authored-by: Ben Kochie <superq@gmail.com>
Signed-off-by: Matthias Rampke <matthias.rampke@googlemail.com>
2025-07-21 07:28:07 +00:00
Matthias Rampke
530ac73d7f
Extract and modernize starter configuration
Take the existing starter configuration that we had buried in the middle of the
README. Slightly modernize it: disable glob mapping ordering by default, and set
the default # of native histogram buckets to 160, matching [defaults in
OpenTelemetry and the recommendation in Mimir](https://grafana.com/docs/mimir/latest/configure/configure-native-histograms-ingestion/#configure-native-histograms-per-tenant).

Add an example of overriding the default native histogram bucket factor.

Signed-off-by: Matthias Rampke <matthias@prometheus.io>
2025-07-17 17:33:03 +00:00
prombot
e94c23c18f Update common Prometheus files
Signed-off-by: prombot <prometheus-team@googlegroups.com>
2025-07-09 17:50:44 +00:00
dependabot[bot]
d0fd88fea4
Merge pull request #639 from prometheus/dependabot/go_modules/github.com/prometheus/common-0.65.0 2025-07-01 12:12:25 +00:00
dependabot[bot]
a1eb47f5cb
Bump github.com/prometheus/common from 0.63.0 to 0.65.0
Bumps [github.com/prometheus/common](https://github.com/prometheus/common) from 0.63.0 to 0.65.0.
- [Release notes](https://github.com/prometheus/common/releases)
- [Changelog](https://github.com/prometheus/common/blob/main/RELEASE.md)
- [Commits](https://github.com/prometheus/common/compare/v0.63.0...v0.65.0)

---
updated-dependencies:
- dependency-name: github.com/prometheus/common
  dependency-version: 0.65.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-01 11:55:12 +00:00
Pedro Tanaka
7d00675ec9
Merge pull request #635 from prometheus/repo_sync
Synchronize common files from prometheus/prometheus
2025-05-29 01:14:56 +01:00
prombot
05caab2de4 Update common Prometheus files
Signed-off-by: prombot <prometheus-team@googlegroups.com>
2025-05-26 17:47:53 +00:00
Pedro Tanaka
ab1f7e9fa7
Merge pull request #633 from prometheus/repo_sync
Synchronize common files from prometheus/prometheus
2025-05-19 08:31:17 +01:00
prombot
66b02179b4 Update common Prometheus files
Signed-off-by: prombot <prometheus-team@googlegroups.com>
2025-05-16 17:48:22 +00:00
Pedro Tanaka
3464f277df
Merge pull request #631 from prometheus/repo_sync
Synchronize common files from prometheus/prometheus
2025-05-05 10:04:49 +02:00
prombot
62ccc8c4a4 Update common Prometheus files
Signed-off-by: prombot <prometheus-team@googlegroups.com>
2025-05-04 17:48:16 +00:00
dependabot[bot]
4feb411e09
Merge pull request #630 from prometheus/dependabot/go_modules/github.com/prometheus/client_model-0.6.2 2025-05-02 06:32:20 +00:00
dependabot[bot]
cbadf49755
Bump github.com/prometheus/client_model from 0.6.1 to 0.6.2
Bumps [github.com/prometheus/client_model](https://github.com/prometheus/client_model) from 0.6.1 to 0.6.2.
- [Release notes](https://github.com/prometheus/client_model/releases)
- [Commits](https://github.com/prometheus/client_model/compare/v0.6.1...v0.6.2)

---
updated-dependencies:
- dependency-name: github.com/prometheus/client_model
  dependency-version: 0.6.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-01 10:39:14 +00:00
dependabot[bot]
919fad636f
Merge pull request #628 from prometheus/dependabot/go_modules/golang.org/x/net-0.38.0 2025-04-17 07:20:07 +00:00
dependabot[bot]
58bae426f1
Bump golang.org/x/net from 0.36.0 to 0.38.0
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.36.0 to 0.38.0.
- [Commits](https://github.com/golang/net/compare/v0.36.0...v0.38.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-version: 0.38.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-16 23:24:59 +00:00
Ben Kochie
743c7f91b8
Merge pull request #619 from prometheus/dependabot/go_modules/golang.org/x/net-0.36.0
Bump golang.org/x/net from 0.33.0 to 0.36.0
2025-04-16 07:38:56 +02:00
dependabot[bot]
0fc3a29d69
Bump golang.org/x/net from 0.33.0 to 0.36.0
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.33.0 to 0.36.0.
- [Commits](https://github.com/golang/net/compare/v0.33.0...v0.36.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-15 16:29:43 +00:00
Ben Kochie
8ef8c1e933
Merge pull request #623 from prometheus/dependabot/go_modules/github.com/prometheus/client_golang-1.21.1
Bump github.com/prometheus/client_golang from 1.20.5 to 1.21.1
2025-04-15 18:28:31 +02:00
Ben Kochie
4f0e8416e0
Merge pull request #626 from prometheus/dependabot/go_modules/golang.org/x/crypto-0.35.0
Bump golang.org/x/crypto from 0.32.0 to 0.35.0
2025-04-15 18:28:09 +02:00
dependabot[bot]
c5785482d9
Bump golang.org/x/crypto from 0.32.0 to 0.35.0
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.32.0 to 0.35.0.
- [Commits](https://github.com/golang/crypto/compare/v0.32.0...v0.35.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-version: 0.35.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-15 13:57:21 +00:00
dependabot[bot]
ccc44de63f
Bump github.com/prometheus/client_golang from 1.20.5 to 1.21.1
Bumps [github.com/prometheus/client_golang](https://github.com/prometheus/client_golang) from 1.20.5 to 1.21.1.
- [Release notes](https://github.com/prometheus/client_golang/releases)
- [Changelog](https://github.com/prometheus/client_golang/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prometheus/client_golang/compare/v1.20.5...v1.21.1)

---
updated-dependencies:
- dependency-name: github.com/prometheus/client_golang
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-15 13:43:54 +00:00
Ben Kochie
c2d5d18cdf
Merge pull request #622 from prometheus/dependabot/go_modules/github.com/prometheus/common-0.63.0
Bump github.com/prometheus/common from 0.62.0 to 0.63.0
2025-04-15 15:42:40 +02:00
Ben Kochie
343a50a3d1
Merge pull request #627 from prometheus/superq/go_1.24
Update Go
2025-04-15 15:41:52 +02:00
SuperQ
dbf1dba353
Update Go
* Update Go build to 1.24.
* Update minimum Go to 1.23.0.
* Update golangci-lint to v2.
* Fixup linter issues.

Signed-off-by: SuperQ <superq@gmail.com>
2025-04-15 13:34:19 +02:00
dependabot[bot]
edd97953e3
Bump github.com/prometheus/common from 0.62.0 to 0.63.0
Bumps [github.com/prometheus/common](https://github.com/prometheus/common) from 0.62.0 to 0.63.0.
- [Release notes](https://github.com/prometheus/common/releases)
- [Changelog](https://github.com/prometheus/common/blob/main/RELEASE.md)
- [Commits](https://github.com/prometheus/common/compare/v0.62.0...v0.63.0)

---
updated-dependencies:
- dependency-name: github.com/prometheus/common
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-01 10:52:51 +00:00
Pedro Tanaka
e1cef5e7a7
Merge pull request #621 from prometheus/repo_sync
Synchronize common files from prometheus/prometheus
2025-03-29 11:26:50 +01:00
prombot
c0758e1c1a Update common Prometheus files
Signed-off-by: prombot <prometheus-team@googlegroups.com>
2025-03-28 17:48:19 +00:00
Ben Kochie
267753cdaa
Merge pull request #620 from prometheus/repo_sync
Synchronize common files from prometheus/prometheus
2025-03-23 09:20:29 +01:00
prombot
e1d5b04928 Update common Prometheus files
Signed-off-by: prombot <prometheus-team@googlegroups.com>
2025-03-22 17:47:58 +00:00
Ben Kochie
3b86000e17
Merge pull request #618 from prometheus/repo_sync
Synchronize common files from prometheus/prometheus
2025-03-08 15:12:07 +01:00
prombot
a94ccca200 Update common Prometheus files
Signed-off-by: prombot <prometheus-team@googlegroups.com>
2025-03-07 17:48:36 +00:00
Pedro Tanaka
4d9b92568d
Merge pull request #616 from prometheus/dependabot/go_modules/github.com/prometheus/exporter-toolkit-0.14.0
Bump github.com/prometheus/exporter-toolkit from 0.13.2 to 0.14.0
2025-03-03 09:50:27 +01:00
dependabot[bot]
34a445d689
Bump github.com/prometheus/exporter-toolkit from 0.13.2 to 0.14.0
Bumps [github.com/prometheus/exporter-toolkit](https://github.com/prometheus/exporter-toolkit) from 0.13.2 to 0.14.0.
- [Release notes](https://github.com/prometheus/exporter-toolkit/releases)
- [Changelog](https://github.com/prometheus/exporter-toolkit/blob/master/CHANGELOG.md)
- [Commits](https://github.com/prometheus/exporter-toolkit/compare/v0.13.2...v0.14.0)

---
updated-dependencies:
- dependency-name: github.com/prometheus/exporter-toolkit
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-01 10:16:43 +00:00
Pedro Tanaka
45044cbc48
Merge pull request #602 from prometheus/feat/multi-valued-event
feat(event): Add MultiValueEvent interface and MultiObserverEvent implementation
2025-02-22 14:47:19 +01:00
Pedro Tanaka
cc1fcb45af
Drop Value() method from MultiValueEvent and fixing expansion logic
Signed-off-by: Pedro Tanaka <pedro.stanaka@gmail.com>
2025-02-22 14:05:01 +01:00
Pedro Tanaka
ce77e77d0e
Merge pull request #612 from prometheus/dependabot/go_modules/github.com/prometheus/common-0.62.0
Bump github.com/prometheus/common from 0.61.0 to 0.62.0
2025-02-17 11:53:25 +01:00
Ben Kochie
f37cc2b683
Merge pull request #613 from prometheus/repo_sync
Synchronize common files from prometheus/prometheus
2025-02-09 09:23:25 +01:00
prombot
2f34dcbf06 Update common Prometheus files
Signed-off-by: prombot <prometheus-team@googlegroups.com>
2025-02-08 17:48:05 +00:00
dependabot[bot]
91cc6182b1
Bump github.com/prometheus/common from 0.61.0 to 0.62.0
Bumps [github.com/prometheus/common](https://github.com/prometheus/common) from 0.61.0 to 0.62.0.
- [Release notes](https://github.com/prometheus/common/releases)
- [Changelog](https://github.com/prometheus/common/blob/main/RELEASE.md)
- [Commits](https://github.com/prometheus/common/compare/v0.61.0...v0.62.0)

---
updated-dependencies:
- dependency-name: github.com/prometheus/common
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-01 10:03:36 +00:00
Pedro Tanaka
a7bc1e8652
Merge pull request #605 from pedro-stanaka/feat/clash-metric-name-label
Keep track of metric names on the metric statsd_exporter_events_conflict_total
2025-01-24 10:15:12 +01:00
Ben Kochie
4014d84fff
Merge pull request #610 from prometheus/dependabot/go_modules/golang.org/x/net-0.33.0
Bump golang.org/x/net from 0.32.0 to 0.33.0
2025-01-16 10:09:53 +01:00
dependabot[bot]
0d54d0ed32
Bump golang.org/x/net from 0.32.0 to 0.33.0
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.32.0 to 0.33.0.
- [Commits](https://github.com/golang/net/compare/v0.32.0...v0.33.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-16 08:46:27 +00:00
Pedro Tanaka
493392ecf0
Merge pull request #609 from prometheus/repo_sync
Synchronize common files from prometheus/prometheus
2025-01-16 09:45:39 +01:00
prombot
7f8da59baa Update common Prometheus files
Signed-off-by: prombot <prometheus-team@googlegroups.com>
2025-01-15 17:47:59 +00:00
Ben Kochie
37d4cfa364
Merge pull request #606 from prometheus/repo_sync
Synchronize common files from prometheus/prometheus
2024-12-30 21:22:18 +01:00
prombot
96ed54b157 Update common Prometheus files
Signed-off-by: prombot <prometheus-team@googlegroups.com>
2024-12-29 17:47:51 +00:00
Pedro Tanaka
d45b0e3e36
Keep track of metric names on the metric statsd_exporter_events_conflict_total
Signed-off-by: Pedro Tanaka <pedro.tanaka@shopify.com>
2024-12-23 15:33:27 +01:00
Pedro Tanaka
a125dac85b
Rewording Explode -> Expand
Signed-off-by: Pedro Tanaka <pedro.tanaka@shopify.com>
2024-12-23 11:24:37 +01:00
Pedro Tanaka
e5c2d40581
Make previous events implement MultiValueEvent
and simplify tests;

Signed-off-by: Pedro Tanaka <pedro.tanaka@shopify.com>
2024-12-23 11:20:49 +01:00
Pedro Tanaka
46cb41614e
feat(event): Add MultiValueEvent interface and MultiObserverEvent implementation
This PR introduces the first step in refactoring the event handling system to better
support multiple values in a single event, which will help reduce allocations when
processing events. This is part of a larger effort to improve performance and reduce
memory allocations in the statsd exporter.

Changes:
- Add new `MultiValueEvent` interface that supports multiple values per event
- Add `MultiObserverEvent` implementation for handling multiple observations
- Add `ExplodableEvent` interface for backward compatibility
- Add `Values()` method to existing event types
- Add comprehensive tests for new interfaces and implementations

This change is the foundation for future improvements that will:
1. Move explosion logic to a dedicated package
2. Update the line parser to use multi-value events
3. Modify the exporter to handle multi-value events directly
4. Eventually remove the need for event explosion

The changes in this PR are backward compatible and don't affect existing functionality.

Relates to #577

Signed-off-by: Pedro Tanaka <pedro.tanaka@shopify.com>
2024-12-17 18:19:19 +01:00
Ben Kochie
32fee3f94b
Merge pull request #600 from prometheus/dependabot/go_modules/github.com/prometheus/exporter-toolkit-0.13.2
Bump github.com/prometheus/exporter-toolkit from 0.13.1 to 0.13.2
2024-12-13 19:30:08 +01:00
Ben Kochie
ffbede602e
Merge pull request #601 from prometheus/repo_sync
Synchronize common files from prometheus/prometheus
2024-12-13 19:29:44 +01:00
prombot
1093a661ea Update common Prometheus files
Signed-off-by: prombot <prometheus-team@googlegroups.com>
2024-12-13 17:47:49 +00:00
dependabot[bot]
98de69fdda
Bump github.com/prometheus/exporter-toolkit from 0.13.1 to 0.13.2
Bumps [github.com/prometheus/exporter-toolkit](https://github.com/prometheus/exporter-toolkit) from 0.13.1 to 0.13.2.
- [Release notes](https://github.com/prometheus/exporter-toolkit/releases)
- [Changelog](https://github.com/prometheus/exporter-toolkit/blob/master/CHANGELOG.md)
- [Commits](https://github.com/prometheus/exporter-toolkit/compare/v0.13.1...v0.13.2)

---
updated-dependencies:
- dependency-name: github.com/prometheus/exporter-toolkit
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-13 16:11:47 +00:00
Ben Kochie
fa11c20fd1
Merge pull request #596 from prometheus/repo_sync
Synchronize common files from prometheus/prometheus
2024-12-13 09:38:40 +01:00
prombot
0e8f597c40 Update common Prometheus files
Signed-off-by: prombot <prometheus-team@googlegroups.com>
2024-11-12 17:47:57 +00:00
Matthias Rampke
285293f587
Merge pull request #595 from prometheus/repo_sync
Synchronize common files from prometheus/prometheus
2024-11-09 16:51:24 +01:00
prombot
7b20c1c6b0 Update common Prometheus files
Signed-off-by: prombot <prometheus-team@googlegroups.com>
2024-11-08 17:47:53 +00:00
Matthias Rampke
8cf95221d1
Merge pull request #594 from prometheus/mr/welcome-pedro
Add Pedro Tanaka as co-maintainer
2024-11-08 15:34:09 +01:00
Matthias Rampke
3a4875414b
Add Pedro Tanaka as co-maintainer
Pedro runs [one of the largest statsd-exporter
installations](https://promcon.io/2023-berlin/talks/taming-the-tsunami-low-latency-ingestion-of-push-based-metrics-in-prometheus/)
and is a natural fit for this 😀

Thank you Pedro for agreeing to help out!

Signed-off-by: Matthias Rampke <matthias@prometheus.io>
2024-11-08 14:25:03 +00:00
Matthias Rampke
e103da1d09
Merge pull request #593 from prometheus/repo_sync
Synchronize common files from prometheus/prometheus
2024-11-08 15:22:34 +01:00
Matthias Rampke
3082cf590c
Merge pull request #592 from prometheus/dependabot/go_modules/github.com/prometheus/exporter-toolkit-0.13.1
Bump github.com/prometheus/exporter-toolkit from 0.13.0 to 0.13.1
2024-11-08 15:22:26 +01:00
prombot
5d59712795 Update common Prometheus files
Signed-off-by: prombot <prometheus-team@googlegroups.com>
2024-11-05 17:48:04 +00:00
dependabot[bot]
9803afaa8d
Bump github.com/prometheus/exporter-toolkit from 0.13.0 to 0.13.1
Bumps [github.com/prometheus/exporter-toolkit](https://github.com/prometheus/exporter-toolkit) from 0.13.0 to 0.13.1.
- [Release notes](https://github.com/prometheus/exporter-toolkit/releases)
- [Changelog](https://github.com/prometheus/exporter-toolkit/blob/master/CHANGELOG.md)
- [Commits](https://github.com/prometheus/exporter-toolkit/compare/v0.13.0...v0.13.1)

---
updated-dependencies:
- dependency-name: github.com/prometheus/exporter-toolkit
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-01 10:44:40 +00:00
Matthias Rampke
009fcca35f
Merge pull request #590 from prometheus/repo_sync
Synchronize common files from prometheus/prometheus
2024-10-25 20:58:18 +02:00
prombot
3e8c235b06 Update common Prometheus files
Signed-off-by: prombot <prometheus-team@googlegroups.com>
2024-10-25 17:47:43 +00:00
Matthias Rampke
c0a390a2c4
release 0.28.0
Signed-off-by: Matthias Rampke <matthias@prometheus.io>
2024-10-25 13:47:38 +00:00
Matthias Rampke
9cf8734c97
Merge pull request #589 from prometheus/dependabot/go_modules/github.com/prometheus/client_golang-1.20.5
Bump github.com/prometheus/client_golang from 1.20.4 to 1.20.5
2024-10-25 15:32:57 +02:00
Matthias Rampke
211680b98c
Merge pull request #588 from prometheus/dependabot/go_modules/github.com/prometheus/common-0.60.1
Bump github.com/prometheus/common from 0.60.0 to 0.60.1
2024-10-25 15:32:52 +02:00
Ben Kochie
bcd2cd8862
Merge pull request #581 from prometheus/repo_sync
Synchronize common files from prometheus/prometheus
2024-10-25 15:24:37 +02:00
dependabot[bot]
3cd0545478
Bump github.com/prometheus/client_golang from 1.20.4 to 1.20.5
Bumps [github.com/prometheus/client_golang](https://github.com/prometheus/client_golang) from 1.20.4 to 1.20.5.
- [Release notes](https://github.com/prometheus/client_golang/releases)
- [Changelog](https://github.com/prometheus/client_golang/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prometheus/client_golang/compare/v1.20.4...v1.20.5)

---
updated-dependencies:
- dependency-name: github.com/prometheus/client_golang
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-25 13:24:31 +00:00
dependabot[bot]
64cc00e019
Bump github.com/prometheus/common from 0.60.0 to 0.60.1
Bumps [github.com/prometheus/common](https://github.com/prometheus/common) from 0.60.0 to 0.60.1.
- [Release notes](https://github.com/prometheus/common/releases)
- [Changelog](https://github.com/prometheus/common/blob/main/RELEASE.md)
- [Commits](https://github.com/prometheus/common/compare/v0.60.0...v0.60.1)

---
updated-dependencies:
- dependency-name: github.com/prometheus/common
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-25 13:24:29 +00:00
Matthias Rampke
8aac1cabf3
Merge pull request #586 from prometheus/superq/slog
Update exporter-toolkit
2024-10-25 15:23:18 +02:00
SuperQ
e3378f8027
Update exporter-toolkit
* Update Go to 1.23.
* Replace go-kit/log with slog.

Signed-off-by: SuperQ <superq@gmail.com>
2024-10-11 09:35:20 +02:00
Matthias Rampke
c18857b71b
release 0.27.2
Signed-off-by: Matthias Rampke <matthias@prometheus.io>
2024-10-07 13:28:01 +00:00
Matthias Rampke
a20db6eec6
Merge pull request #579 from prometheus/mr/issue-572/fix-panic
Fix panic when parsing invalid lines
2024-10-07 13:26:40 +00:00
prombot
2a6c1a326b Update common Prometheus files
Signed-off-by: prombot <prometheus-team@googlegroups.com>
2024-09-15 17:47:29 +00:00
35 changed files with 782 additions and 567 deletions

View file

@ -5,7 +5,7 @@ executors:
# Whenever the Go version is updated here, .promu.yml should also be updated.
golang:
docker:
- image: cimg/go:1.22
- image: cimg/go:1.24
jobs:
test:
executor: golang

View file

@ -18,7 +18,9 @@ jobs:
if: github.repository_owner == 'prometheus' || github.repository_owner == 'prometheus-community' # Don't run this workflow on forks.
steps:
- name: git checkout
uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
persist-credentials: false
- name: Set docker hub repo name
run: echo "DOCKER_REPO_NAME=$(make docker-repo-name)" >> $GITHUB_ENV
- name: Push README to Dockerhub
@ -40,7 +42,9 @@ jobs:
if: github.repository_owner == 'prometheus' || github.repository_owner == 'prometheus-community' # Don't run this workflow on forks.
steps:
- name: git checkout
uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
persist-credentials: false
- name: Set quay.io org name
run: echo "DOCKER_REPO=$(echo quay.io/${GITHUB_REPOSITORY_OWNER} | tr -d '-')" >> $GITHUB_ENV
- name: Set quay.io repo name

View file

@ -24,16 +24,18 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
- name: Install Go
uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
go-version: 1.22.x
persist-credentials: false
- name: Install Go
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
with:
go-version: 1.24.x
- name: Install snmp_exporter/generator dependencies
run: sudo apt-get update && sudo apt-get -y install libsnmp-dev
if: github.repository == 'prometheus/snmp_exporter'
- name: Lint
uses: golangci/golangci-lint-action@aaa42aa0628b4ae2578232a66b541047968fac86 # v6.1.0
uses: golangci/golangci-lint-action@4afd733a84b1f43292c63897423277bb7f4313a9 # v8.0.0
with:
args: --verbose
version: v1.60.1
version: v2.2.1

View file

@ -1,26 +1,40 @@
version: "2"
run:
issues-exit-code: 1
tests: true
linters:
disable:
- errcheck
enable:
- goimports
- gosimple
- govet
- ineffassign
- nakedret
- staticcheck
- unused
- whitespace
linters-settings:
govet:
enable-all: true
disable:
- fieldalignment
disable:
- errcheck
settings:
govet:
disable:
- fieldalignment
enable-all: true
staticcheck:
checks:
- all
- -ST1000
- -ST1003
- -ST1020
exclusions:
rules:
- path: (.+)\.go$
text: 'shadow: declaration of "err" shadows declaration at line (\d+)'
warn-unused: true
issues:
exclude-use-default: false
exclude:
- 'shadow: declaration of "err" shadows declaration at line (\d+)'
max-issues-per-linter: 0
max-same-issues: 0
formatters:
enable:
- gofumpt
- goimports
settings:
gofumpt:
extra-rules: true
goimports:
local-prefixes:
- github.com/prometheus/statsd_exporter

View file

@ -1,7 +1,7 @@
go:
# Whenever the Go version is updated here, .circle/config.yml should also
# be updated.
version: 1.22
version: 1.24
repository:
path: github.com/prometheus/statsd_exporter
build:

View file

@ -1,7 +1,7 @@
---
extends: default
ignore: |
ui/react-app/node_modules
**/node_modules
rules:
braces:

View file

@ -1,4 +1,11 @@
## 0.27.2-pr579 / 2024-09-16
## 0.28.0 / 2024-10-25
* [CHANGE] Update exporter-toolkit & switch to slog ([#586](https://github.com/prometheus/statsd_exporter/pull/586))
* [CHANGE] Update client_golang and prometheus-common
This is a breaking change for library users.
## 0.27.2 / 2024-10-07
* [BUGFIX] Fix panic on certain invalid lines ([#579](https://github.com/prometheus/statsd_exporter/pull/579))

View file

@ -1 +1,2 @@
* Matthias Rampke <matthias@prometheus.io>
* Pedro Tanaka [@pedro-stanaka](https://github.com/pedro-stanaka)

View file

@ -61,7 +61,8 @@ PROMU_URL := https://github.com/prometheus/promu/releases/download/v$(PROMU_
SKIP_GOLANGCI_LINT :=
GOLANGCI_LINT :=
GOLANGCI_LINT_OPTS ?=
GOLANGCI_LINT_VERSION ?= v1.60.1
GOLANGCI_LINT_VERSION ?= v2.2.1
GOLANGCI_FMT_OPTS ?=
# golangci-lint only supports linux, darwin and windows platforms on i386/amd64/arm64.
# windows isn't included here because of the path separator being different.
ifeq ($(GOHOSTOS),$(filter $(GOHOSTOS),linux darwin))
@ -138,7 +139,7 @@ common-deps:
update-go-deps:
@echo ">> updating Go dependencies"
@for m in $$($(GO) list -mod=readonly -m -f '{{ if and (not .Indirect) (not .Main)}}{{.Path}}{{end}}' all); do \
$(GO) get -d $$m; \
$(GO) get $$m; \
done
$(GO) mod tidy
@ -156,9 +157,13 @@ $(GOTEST_DIR):
@mkdir -p $@
.PHONY: common-format
common-format:
common-format: $(GOLANGCI_LINT)
@echo ">> formatting code"
$(GO) fmt $(pkgs)
ifdef GOLANGCI_LINT
@echo ">> formatting code with golangci-lint"
$(GOLANGCI_LINT) fmt $(GOLANGCI_FMT_OPTS)
endif
.PHONY: common-vet
common-vet:
@ -248,8 +253,8 @@ $(PROMU):
cp $(PROMU_TMP)/promu-$(PROMU_VERSION).$(GO_BUILD_PLATFORM)/promu $(FIRST_GOPATH)/bin/promu
rm -r $(PROMU_TMP)
.PHONY: proto
proto:
.PHONY: common-proto
common-proto:
@echo ">> generating code from proto files"
@./scripts/genproto.sh
@ -275,3 +280,9 @@ $(1)_precheck:
exit 1; \
fi
endef
govulncheck: install-govulncheck
govulncheck ./...
install-govulncheck:
command -v govulncheck > /dev/null || go install golang.org/x/vuln/cmd/govulncheck@latest

View file

@ -418,46 +418,7 @@ Setting `buckets` or `quantiles` in the defaults is deprecated in favor of `hist
If `summary_options` is present in a mapping config, it will only override the fields set in the mapping. Unset fields in the mapping will take the values from the defaults.
```yaml
defaults:
observer_type: histogram
histogram_options:
buckets: [.005, .01, .025, .05, .1, .25, .5, 1, 2.5 ]
native_histogram_bucket_factor: 1.1
native_histogram_max_buckets: 256
summary_options:
quantiles:
- quantile: 0.99
error: 0.001
- quantile: 0.95
error: 0.01
- quantile: 0.9
error: 0.05
- quantile: 0.5
error: 0.005
max_age: 5m
age_buckets: 2
buf_cap: 1000
match_type: glob
glob_disable_ordering: false
ttl: 0 # metrics do not expire
mappings:
# This will be a histogram using the buckets set in `defaults`.
- match: "test.timing.*.*.*"
name: "my_timer"
labels:
provider: "$2"
outcome: "$3"
job: "${1}_server"
# This will be a summary using the summary_options set in `defaults`
- match: "other.distribution.*.*.*"
observer_type: summary
name: "other_distribution"
labels:
provider: "$2"
outcome: "$3"
job: "${1}_server_other"
```
See [`config.exmple.yml`](config.example.yml) for an annotated example configuration.
### `drop` action

View file

@ -1 +1 @@
0.27.2-pr579
0.28.0

View file

@ -15,14 +15,15 @@ package main
import (
"fmt"
"log/slog"
"net"
"reflect"
"testing"
"time"
"github.com/go-kit/log"
"github.com/prometheus/client_golang/prometheus"
dto "github.com/prometheus/client_model/go"
"github.com/prometheus/common/promslog"
"github.com/prometheus/statsd_exporter/pkg/clock"
"github.com/prometheus/statsd_exporter/pkg/event"
@ -40,7 +41,8 @@ func TestHandlePacket(t *testing.T) {
}{
{
name: "empty",
}, {
},
{
name: "simple counter",
in: "foo:2|c",
out: event.Events{
@ -50,7 +52,8 @@ func TestHandlePacket(t *testing.T) {
CLabels: map[string]string{},
},
},
}, {
},
{
name: "simple gauge",
in: "foo:3|g",
out: event.Events{
@ -60,7 +63,8 @@ func TestHandlePacket(t *testing.T) {
GLabels: map[string]string{},
},
},
}, {
},
{
name: "gauge with sampling",
in: "foo:3|g|@0.2",
out: event.Events{
@ -70,7 +74,8 @@ func TestHandlePacket(t *testing.T) {
GLabels: map[string]string{},
},
},
}, {
},
{
name: "gauge decrement",
in: "foo:-10|g",
out: event.Events{
@ -81,7 +86,8 @@ func TestHandlePacket(t *testing.T) {
GLabels: map[string]string{},
},
},
}, {
},
{
name: "gauge increment",
in: "foo:+10|g",
out: event.Events{
@ -92,7 +98,8 @@ func TestHandlePacket(t *testing.T) {
GLabels: map[string]string{},
},
},
}, {
},
{
name: "gauge set negative",
in: "foo:0|g\nfoo:-1|g",
out: event.Events{
@ -109,7 +116,8 @@ func TestHandlePacket(t *testing.T) {
GLabels: map[string]string{},
},
},
}, {
},
{
// Test the sequence given here https://github.com/statsd/statsd/blob/master/docs/metric_types.md#gauges
name: "gauge up and down",
in: "gaugor:333|g\ngaugor:-10|g\ngaugor:+4|g",
@ -133,7 +141,8 @@ func TestHandlePacket(t *testing.T) {
GLabels: map[string]string{},
},
},
}, {
},
{
name: "simple timer",
in: "foo:200|ms",
out: event.Events{
@ -143,7 +152,8 @@ func TestHandlePacket(t *testing.T) {
OLabels: map[string]string{},
},
},
}, {
},
{
name: "simple histogram",
in: "foo:200|h",
out: event.Events{
@ -153,7 +163,8 @@ func TestHandlePacket(t *testing.T) {
OLabels: map[string]string{},
},
},
}, {
},
{
name: "simple distribution",
in: "foo:200|d",
out: event.Events{
@ -163,7 +174,8 @@ func TestHandlePacket(t *testing.T) {
OLabels: map[string]string{},
},
},
}, {
},
{
name: "distribution with sampling",
in: "foo:0.01|d|@0.2|#tag1:bar,#tag2:baz",
out: event.Events{
@ -193,7 +205,8 @@ func TestHandlePacket(t *testing.T) {
OLabels: map[string]string{"tag1": "bar", "tag2": "baz"},
},
},
}, {
},
{
name: "librato tag extension",
in: "foo#tag1=bar,tag2=baz:100|c",
out: event.Events{
@ -203,7 +216,8 @@ func TestHandlePacket(t *testing.T) {
CLabels: map[string]string{"tag1": "bar", "tag2": "baz"},
},
},
}, {
},
{
name: "librato tag extension with tag keys unsupported by prometheus",
in: "foo#09digits=0,tag.with.dots=1:100|c",
out: event.Events{
@ -213,7 +227,8 @@ func TestHandlePacket(t *testing.T) {
CLabels: map[string]string{"_09digits": "0", "tag_with_dots": "1"},
},
},
}, {
},
{
name: "influxdb tag extension",
in: "foo,tag1=bar,tag2=baz:100|c",
out: event.Events{
@ -223,7 +238,8 @@ func TestHandlePacket(t *testing.T) {
CLabels: map[string]string{"tag1": "bar", "tag2": "baz"},
},
},
}, {
},
{
name: "SignalFx tag extension",
in: "foo.[tag1=bar,tag2=baz]test:100|c",
out: event.Events{
@ -233,7 +249,8 @@ func TestHandlePacket(t *testing.T) {
CLabels: map[string]string{"tag1": "bar", "tag2": "baz"},
},
},
}, {
},
{
name: "SignalFx tag extension, tags at end of name",
in: "foo.test[tag1=bar,tag2=baz]:100|c",
out: event.Events{
@ -243,7 +260,8 @@ func TestHandlePacket(t *testing.T) {
CLabels: map[string]string{"tag1": "bar", "tag2": "baz"},
},
},
}, {
},
{
name: "SignalFx tag extension, tags at beginning of name",
in: "[tag1=bar,tag2=baz]foo.test:100|c",
out: event.Events{
@ -253,7 +271,8 @@ func TestHandlePacket(t *testing.T) {
CLabels: map[string]string{"tag1": "bar", "tag2": "baz"},
},
},
}, {
},
{
name: "SignalFx tag extension, no tags",
in: "foo.[]test:100|c",
out: event.Events{
@ -263,7 +282,8 @@ func TestHandlePacket(t *testing.T) {
CLabels: map[string]string{},
},
},
}, {
},
{
name: "SignalFx tag extension, non-kv tags",
in: "foo.[tag1,tag2]test:100|c",
out: event.Events{
@ -273,7 +293,8 @@ func TestHandlePacket(t *testing.T) {
CLabels: map[string]string{},
},
},
}, {
},
{
name: "SignalFx tag extension, missing closing bracket",
in: "[tag1=bar,tag2=bazfoo.test:100|c",
out: event.Events{
@ -283,7 +304,8 @@ func TestHandlePacket(t *testing.T) {
CLabels: map[string]string{},
},
},
}, {
},
{
name: "SignalFx tag extension, missing opening bracket",
in: "tag1=bar,tag2=baz]foo.test:100|c",
out: event.Events{
@ -293,7 +315,8 @@ func TestHandlePacket(t *testing.T) {
CLabels: map[string]string{},
},
},
}, {
},
{
name: "influxdb tag extension with tag keys unsupported by prometheus",
in: "foo,09digits=0,tag.with.dots=1:100|c",
out: event.Events{
@ -303,7 +326,8 @@ func TestHandlePacket(t *testing.T) {
CLabels: map[string]string{"_09digits": "0", "tag_with_dots": "1"},
},
},
}, {
},
{
name: "datadog tag extension",
in: "foo:100|c|#tag1:bar,tag2:baz",
out: event.Events{
@ -313,7 +337,8 @@ func TestHandlePacket(t *testing.T) {
CLabels: map[string]string{"tag1": "bar", "tag2": "baz"},
},
},
}, {
},
{
name: "datadog tag extension with # in all keys (as sent by datadog php client)",
in: "foo:100|c|#tag1:bar,#tag2:baz",
out: event.Events{
@ -323,7 +348,8 @@ func TestHandlePacket(t *testing.T) {
CLabels: map[string]string{"tag1": "bar", "tag2": "baz"},
},
},
}, {
},
{
name: "datadog tag extension with tag keys unsupported by prometheus",
in: "foo:100|c|#09digits:0,tag.with.dots:1",
out: event.Events{
@ -333,7 +359,8 @@ func TestHandlePacket(t *testing.T) {
CLabels: map[string]string{"_09digits": "0", "tag_with_dots": "1"},
},
},
}, {
},
{
name: "datadog tag extension with valueless tags: ignored",
in: "foo:100|c|#tag_without_a_value",
out: event.Events{
@ -343,7 +370,8 @@ func TestHandlePacket(t *testing.T) {
CLabels: map[string]string{},
},
},
}, {
},
{
name: "datadog tag extension with valueless tags (edge case)",
in: "foo:100|c|#tag_without_a_value,tag:value",
out: event.Events{
@ -353,7 +381,8 @@ func TestHandlePacket(t *testing.T) {
CLabels: map[string]string{"tag": "value"},
},
},
}, {
},
{
name: "datadog tag extension with empty tags (edge case)",
in: "foo:100|c|#tag:value,,",
out: event.Events{
@ -363,7 +392,8 @@ func TestHandlePacket(t *testing.T) {
CLabels: map[string]string{"tag": "value"},
},
},
}, {
},
{
name: "datadog tag extension with sampling",
in: "foo:100|c|@0.1|#tag1:bar,#tag2:baz",
out: event.Events{
@ -373,23 +403,28 @@ func TestHandlePacket(t *testing.T) {
CLabels: map[string]string{"tag1": "bar", "tag2": "baz"},
},
},
}, {
},
{
name: "librato/dogstatsd mixed tag styles without sampling",
in: "foo#tag1=foo,tag3=bing:100|c|#tag1:bar,#tag2:baz",
out: event.Events{},
}, {
},
{
name: "signalfx/dogstatsd mixed tag styles without sampling",
in: "foo[tag1=foo,tag3=bing]:100|c|#tag1:bar,#tag2:baz",
out: event.Events{},
}, {
},
{
name: "influxdb/dogstatsd mixed tag styles without sampling",
in: "foo,tag1=foo,tag3=bing:100|c|#tag1:bar,#tag2:baz",
out: event.Events{},
}, {
},
{
name: "mixed tag styles with sampling",
in: "foo#tag1=foo,tag3=bing:100|c|@0.1|#tag1:bar,#tag2:baz",
out: event.Events{},
}, {
},
{
name: "histogram with sampling",
in: "foo:0.01|h|@0.2|#tag1:bar,#tag2:baz",
out: event.Events{
@ -419,7 +454,8 @@ func TestHandlePacket(t *testing.T) {
OLabels: map[string]string{"tag1": "bar", "tag2": "baz"},
},
},
}, {
},
{
name: "datadog tag extension with multiple colons",
in: "foo:100|c|@0.1|#tag1:foo:bar",
out: event.Events{
@ -429,13 +465,16 @@ func TestHandlePacket(t *testing.T) {
CLabels: map[string]string{"tag1": "foo:bar"},
},
},
}, {
},
{
name: "datadog tag extension with invalid utf8 tag values",
in: "foo:100|c|@0.1|#tag:\xc3\x28invalid",
}, {
},
{
name: "datadog tag extension with both valid and invalid utf8 tag values",
in: "foo:100|c|@0.1|#tag1:valid,tag2:\xc3\x28invalid",
}, {
},
{
name: "multiple metrics with invalid datadog utf8 tag values",
in: "foo:200|c|#tag:value\nfoo:300|c|#tag:\xc3\x28invalid",
out: event.Events{
@ -445,7 +484,8 @@ func TestHandlePacket(t *testing.T) {
CLabels: map[string]string{"tag": "value"},
},
},
}, {
},
{
name: "combined multiline metrics",
in: "foo:200|ms:300|ms:5|c|@0.1:6|g\nbar:1|c:5|ms",
out: event.Events{
@ -480,7 +520,8 @@ func TestHandlePacket(t *testing.T) {
OLabels: map[string]string{},
},
},
}, {
},
{
name: "timings with sampling factor",
in: "foo.timing:0.5|ms|@0.1",
out: event.Events{
@ -495,16 +536,20 @@ func TestHandlePacket(t *testing.T) {
&event.ObserverEvent{OMetricName: "foo.timing", OValue: 0.0005, OLabels: map[string]string{}},
&event.ObserverEvent{OMetricName: "foo.timing", OValue: 0.0005, OLabels: map[string]string{}},
},
}, {
},
{
name: "bad line",
in: "foo",
}, {
},
{
name: "bad component",
in: "foo:1",
}, {
},
{
name: "bad value",
in: "foo:1o|c",
}, {
},
{
name: "illegal sampling factor",
in: "foo:1|c|@bar",
out: event.Events{
@ -514,7 +559,8 @@ func TestHandlePacket(t *testing.T) {
CLabels: map[string]string{},
},
},
}, {
},
{
name: "zero sampling factor",
in: "foo:2|c|@0",
out: event.Events{
@ -524,7 +570,8 @@ func TestHandlePacket(t *testing.T) {
CLabels: map[string]string{},
},
},
}, {
},
{
name: "illegal stat type",
in: "foo:2|t",
},
@ -550,7 +597,8 @@ func TestHandlePacket(t *testing.T) {
CLabels: map[string]string{},
},
},
}, {
},
{
name: "ms timer with conversion to seconds",
in: "foo:200|ms",
out: event.Events{
@ -560,7 +608,8 @@ func TestHandlePacket(t *testing.T) {
OLabels: map[string]string{},
},
},
}, {
},
{
name: "histogram with no unit conversion",
in: "foo:200|h",
out: event.Events{
@ -570,7 +619,8 @@ func TestHandlePacket(t *testing.T) {
OLabels: map[string]string{},
},
},
}, {
},
{
name: "distribution with no unit conversion",
in: "foo:200|d",
out: event.Events{
@ -592,7 +642,7 @@ func TestHandlePacket(t *testing.T) {
for k, l := range []statsDPacketHandler{&listener.StatsDUDPListener{
Conn: nil,
EventHandler: nil,
Logger: log.NewNopLogger(),
Logger: promslog.NewNopLogger(),
LineParser: parser,
UDPPackets: udpPackets,
UDPPacketDrops: udpPacketDrops,
@ -605,7 +655,7 @@ func TestHandlePacket(t *testing.T) {
}, &mockStatsDTCPListener{listener.StatsDTCPListener{
Conn: nil,
EventHandler: nil,
Logger: log.NewNopLogger(),
Logger: promslog.NewNopLogger(),
LineParser: parser,
LinesReceived: linesReceived,
EventsFlushed: eventsFlushed,
@ -616,7 +666,7 @@ func TestHandlePacket(t *testing.T) {
TCPConnections: tcpConnections,
TCPErrors: tcpErrors,
TCPLineTooLong: tcpLineTooLong,
}, log.NewNopLogger()}} {
}, promslog.NewNopLogger()}} {
events := make(chan event.Events, 32)
l.SetEventHandler(&event.UnbufferedEventHandler{C: events})
for i, scenario := range scenarios {
@ -649,7 +699,7 @@ type statsDPacketHandler interface {
type mockStatsDTCPListener struct {
listener.StatsDTCPListener
log.Logger
*slog.Logger
}
func (ml *mockStatsDTCPListener) HandlePacket(packet []byte) {
@ -710,7 +760,7 @@ mappings:
events := make(chan event.Events)
defer close(events)
go func() {
ex := exporter.NewExporter(prometheus.DefaultRegisterer, testMapper, log.NewNopLogger(), eventsActions, eventsUnmapped, errorEventStats, eventStats, conflictingEventStats, metricsCount)
ex := exporter.NewExporter(prometheus.DefaultRegisterer, testMapper, promslog.NewNopLogger(), eventsActions, eventsUnmapped, errorEventStats, eventStats, conflictingEventStats, metricsCount)
ex.Listen(events)
}()

84
config.example.yml Normal file
View file

@ -0,0 +1,84 @@
# This is a modern starter configuration for the statsd_exporter. It uses native
# and classic histograms by default, as well as the fast glob matching without ordering.
defaults:
# Convert timers into histograms, which can be aggregated across instances. See below for an example of using a summary with pre-computed quantiles instead.
observer_type: histogram
histogram_options:
# Expose native histograms.
# A bucket spread factor of 1.1 allows for pretty good precision in
# measuring latencies, as long as they are not spread too widely.
native_histogram_bucket_factor: 1.1
# If latency is spread too widely, the resolution is automatically reduced,
# keeping within the maximum bucket count. 160 is the default maximum bucket
# count in OpenTelemetry, and is a good default for most use cases.
native_histogram_max_buckets: 160
# Also expose classic histograms, with a spread of latency buckets from 5ms to 2.5s.
buckets: [.005, .01, .025, .05, .1, .25, .5, 1, 2.5 ]
# Metric can be optionally exposed as a summary. Set reasonable defaults for
# that case. Only used with `observer_type: summary`.
summary_options:
quantiles:
- quantile: 0.99
error: 0.001
- quantile: 0.95
error: 0.01
- quantile: 0.9
error: 0.05
- quantile: 0.5
error: 0.005
max_age: 5m
age_buckets: 2
buf_cap: 1000
# Match using glob patterns by default, it is much faster than regex.
match_type: glob
# Sepecific matches take precedence over *, ignoring the order of the mapping rules.
# Regex matches are always evaluated after glob matches, and do honor the
# order of mapping rules. Avoid using regex matches where possible.
glob_disable_ordering: true
# Do not expire metrics by default. When deployed as a sidecar, and restarted
# together with application deployments, this matches the behavior of native
# in-application instrumentation. Set a reasonable TTL if the exporter has its
# own lifecycle.
ttl: 0
mappings:
# Example 1: This will be a histogram using the bucket configuration set in `defaults`.
- match: "test.timing.*.*.*"
name: "my_timer"
help: "Latency of the application"
labels:
provider: "$2"
outcome: "$3"
job: "${1}_server"
# Example 2: Use a much tighter bucket spread. Use this to track latencies in a
# relatively narrow range. For classic histograms, we need to set the buckets
# around this band manually; native histograms are sparse and adapt automatically.
- match: "consistent_app.timing.*.*.*"
name: "my_consistent_timer"
help: "Latency of an application with a consistent latency pattern"
histogram_options:
native_histogram_bucket_factor: 1.005
# For the sake of this example, set the buckets for a latency distribution
# tightly clustered around 15ms.
buckets: [0.01, 0.011, 0.012, 0.013, 0.014, 0.015, 0.016, 0.017, 0.018, 0.019, 0.02]
labels:
provider: "$2"
outcome: "$3"
job: "${1}_server"
# Example 3: This will be a summary using the summary_options set in `defaults`
#
# Note: Summary metrics are not recommended because they can not be aggregated over multiple instances.
- match: "other.distribution.*.*.*"
observer_type: summary
name: "other_distribution"
labels:
provider: "$2"
outcome: "$3"
job: "${1}_server_other"
# Optional: drop all unmapped metrics. Keep this as the last mapping rule. Any
# metric not matched otherwise will be dropped because "." matches all metrics.
# Without this rule, all metrics will be exposed, with the metric name
# automatically generated from the statsd metric name.
# - match: "."
# match_type: regex
# action: drop
# name: "dropped"

View file

@ -17,9 +17,8 @@ import (
"fmt"
"testing"
"github.com/go-kit/log"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/common/promslog"
"github.com/prometheus/statsd_exporter/pkg/event"
"github.com/prometheus/statsd_exporter/pkg/exporter"
@ -43,7 +42,7 @@ func benchmarkUDPListener(times int, b *testing.B) {
"some_very_useful_metrics_with_quite_a_log_name:13|c",
}
bytesInput := make([]string, len(input)*times)
logger := log.NewNopLogger()
logger := promslog.NewNopLogger()
for run := 0; run < times; run++ {
for i := 0; i < len(input); i++ {
bytesInput[run*len(input)+i] = fmt.Sprintf("run%d%s", run, input[i])
@ -92,9 +91,11 @@ func benchmarkUDPListener(times int, b *testing.B) {
func BenchmarkUDPListener1(b *testing.B) {
benchmarkUDPListener(1, b)
}
func BenchmarkUDPListener5(b *testing.B) {
benchmarkUDPListener(5, b)
}
func BenchmarkUDPListener50(b *testing.B) {
benchmarkUDPListener(50, b)
}
@ -175,7 +176,7 @@ mappings:
b.Fatalf("Config load error: %s %s", config, err)
}
ex := exporter.NewExporter(prometheus.DefaultRegisterer, testMapper, log.NewNopLogger(), eventsActions, eventsUnmapped, errorEventStats, eventStats, conflictingEventStats, metricsCount)
ex := exporter.NewExporter(prometheus.DefaultRegisterer, testMapper, promslog.NewNopLogger(), eventsActions, eventsUnmapped, errorEventStats, eventStats, conflictingEventStats, metricsCount)
// reset benchmark timer to not measure startup costs
b.ResetTimer()

31
go.mod
View file

@ -1,15 +1,14 @@
module github.com/prometheus/statsd_exporter
go 1.21
go 1.23.0
require (
github.com/alecthomas/kingpin/v2 v2.4.0
github.com/go-kit/log v0.2.1
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da
github.com/prometheus/client_golang v1.20.3
github.com/prometheus/client_model v0.6.1
github.com/prometheus/common v0.57.0
github.com/prometheus/exporter-toolkit v0.11.0
github.com/prometheus/client_golang v1.23.0
github.com/prometheus/client_model v0.6.2
github.com/prometheus/common v0.65.0
github.com/prometheus/exporter-toolkit v0.14.0
github.com/stvp/go-udp-testing v0.0.0-20201019212854-469649b16807
gopkg.in/yaml.v2 v2.4.0
)
@ -19,18 +18,18 @@ require (
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
github.com/go-logfmt/logfmt v0.6.0 // indirect
github.com/jpillora/backoff v1.0.0 // indirect
github.com/klauspost/compress v1.17.9 // indirect
github.com/mdlayher/socket v0.4.1 // indirect
github.com/mdlayher/vsock v1.2.1 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect
github.com/prometheus/procfs v0.15.1 // indirect
github.com/prometheus/procfs v0.16.1 // indirect
github.com/xhit/go-str2duration/v2 v2.1.0 // indirect
golang.org/x/crypto v0.26.0 // indirect
golang.org/x/net v0.28.0 // indirect
golang.org/x/oauth2 v0.22.0 // indirect
golang.org/x/sync v0.8.0 // indirect
golang.org/x/sys v0.24.0 // indirect
golang.org/x/text v0.17.0 // indirect
google.golang.org/protobuf v1.34.2 // indirect
golang.org/x/crypto v0.38.0 // indirect
golang.org/x/net v0.40.0 // indirect
golang.org/x/oauth2 v0.30.0 // indirect
golang.org/x/sync v0.14.0 // indirect
golang.org/x/sys v0.33.0 // indirect
golang.org/x/text v0.25.0 // indirect
google.golang.org/protobuf v1.36.6 // indirect
)

69
go.sum
View file

@ -11,41 +11,41 @@ github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSV
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU=
github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0=
github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4=
github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA=
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U=
github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA=
github.com/mdlayher/vsock v1.2.1 h1:pC1mTJTvjo1r9n9fbm7S1j04rCgCzhCOS5DY0zqHlnQ=
github.com/mdlayher/vsock v1.2.1/go.mod h1:NRfCibel++DgeMD8z/hP+PPTjlNJsdPOmxcnENvE+SE=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU=
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v1.20.3 h1:oPksm4K8B+Vt35tUhw6GbSNSgVlVSBH0qELP/7u83l4=
github.com/prometheus/client_golang v1.20.3/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
github.com/prometheus/common v0.57.0 h1:Ro/rKjwdq9mZn1K5QPctzh+MA4Lp0BuYk5ZZEVhoNcY=
github.com/prometheus/common v0.57.0/go.mod h1:7uRPFSUTbfZWsJ7MHY56sqt7hLQu3bxXHDnNhl8E9qI=
github.com/prometheus/exporter-toolkit v0.11.0 h1:yNTsuZ0aNCNFQ3aFTD2uhPOvr4iD7fdBvKPAEGkNf+g=
github.com/prometheus/exporter-toolkit v0.11.0/go.mod h1:BVnENhnNecpwoTLiABx7mrPB/OLRIgN74qlQbV+FK1Q=
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
github.com/prometheus/client_golang v1.23.0 h1:ust4zpdl9r4trLY/gSjlm07PuiBq2ynaXXlptpfy8Uc=
github.com/prometheus/client_golang v1.23.0/go.mod h1:i/o0R9ByOnHX0McrTMTyhYvKE4haaf2mW08I+jGAjEE=
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
github.com/prometheus/common v0.65.0 h1:QDwzd+G1twt//Kwj/Ww6E9FQq1iVMmODnILtW1t2VzE=
github.com/prometheus/common v0.65.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8=
github.com/prometheus/exporter-toolkit v0.14.0 h1:NMlswfibpcZZ+H0sZBiTjrA3/aBFHkNZqE+iCj5EmRg=
github.com/prometheus/exporter-toolkit v0.14.0/go.mod h1:Gu5LnVvt7Nr/oqTBUC23WILZepW0nffNo10XdhQcwWA=
github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg=
github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is=
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
@ -55,26 +55,29 @@ github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/stvp/go-udp-testing v0.0.0-20201019212854-469649b16807 h1:LUsDduamlucuNnWcaTbXQ6aLILFcLXADpOzeEH3U+OI=
github.com/stvp/go-udp-testing v0.0.0-20201019212854-469649b16807/go.mod h1:7jxmlfBCDBXRzr0eAQJ48XC1hBu1np4CS5+cHEYfwpc=
github.com/xhit/go-str2duration/v2 v2.1.0 h1:lxklc02Drh6ynqX+DdPyp5pCKLUQpRT8bp8Ydu2Bstc=
github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU=
golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
golang.org/x/oauth2 v0.22.0 h1:BzDx2FehcG7jJwgWLELCdmLuxk2i+x9UDpSiss2u0ZA=
golang.org/x/oauth2 v0.22.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg=
golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8=
golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw=
golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=
golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=
golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ=
golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=
golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=

View file

@ -16,7 +16,7 @@ package main
import (
"testing"
"github.com/go-kit/log"
"github.com/prometheus/common/promslog"
"github.com/prometheus/statsd_exporter/pkg/line"
)
@ -36,7 +36,7 @@ var (
"foo15:200|ms:300|ms:5|c|@0.1:6|g\nfoo15a:1|c:5|ms",
"some_very_useful_metrics_with_quite_a_log_name:13|c",
}
nopLogger = log.NewNopLogger()
nopLogger = promslog.NewNopLogger()
)
func benchmarkLinesToEvents(times int, b *testing.B, input []string) {
@ -65,9 +65,11 @@ func benchmarkLinesToEvents(times int, b *testing.B, input []string) {
func BenchmarkLineToEventsMixed1(b *testing.B) {
benchmarkLinesToEvents(1, b, mixedLines)
}
func BenchmarkLineToEventsMixed5(b *testing.B) {
benchmarkLinesToEvents(5, b, mixedLines)
}
func BenchmarkLineToEventsMixed50(b *testing.B) {
benchmarkLinesToEvents(50, b, mixedLines)
}

95
main.go
View file

@ -16,6 +16,7 @@ package main
import (
"bufio"
"fmt"
"log/slog"
"net"
"net/http"
_ "net/http/pprof"
@ -25,20 +26,18 @@ import (
"syscall"
"github.com/alecthomas/kingpin/v2"
"github.com/go-kit/log"
"github.com/prometheus/client_golang/prometheus"
versioncollector "github.com/prometheus/client_golang/prometheus/collectors/version"
"github.com/prometheus/client_golang/prometheus/promauto"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/prometheus/common/promlog"
"github.com/prometheus/common/promlog/flag"
"github.com/prometheus/common/promslog"
"github.com/prometheus/common/promslog/flag"
"github.com/prometheus/common/version"
"github.com/prometheus/exporter-toolkit/web"
"github.com/prometheus/statsd_exporter/pkg/address"
"github.com/prometheus/statsd_exporter/pkg/event"
"github.com/prometheus/statsd_exporter/pkg/exporter"
"github.com/prometheus/statsd_exporter/pkg/level"
"github.com/prometheus/statsd_exporter/pkg/line"
"github.com/prometheus/statsd_exporter/pkg/listener"
"github.com/prometheus/statsd_exporter/pkg/mapper"
@ -149,7 +148,7 @@ var (
Name: "statsd_exporter_events_conflict_total",
Help: "The total number of StatsD events with conflicting names.",
},
[]string{"type"},
[]string{"type", "metric_name"},
)
errorEventStats = promauto.NewCounterVec(
prometheus.CounterOpts{
@ -174,49 +173,49 @@ var (
)
)
func serveHTTP(mux http.Handler, listenAddress string, logger log.Logger) {
level.Error(logger).Log("msg", http.ListenAndServe(listenAddress, mux))
func serveHTTP(mux http.Handler, listenAddress string, logger *slog.Logger) {
logger.Error(http.ListenAndServe(listenAddress, mux).Error())
os.Exit(1)
}
func sighupConfigReloader(fileName string, mapper *mapper.MetricMapper, logger log.Logger) {
func sighupConfigReloader(fileName string, mapper *mapper.MetricMapper, logger *slog.Logger) {
signals := make(chan os.Signal, 1)
signal.Notify(signals, syscall.SIGHUP)
for s := range signals {
if fileName == "" {
level.Warn(logger).Log("msg", "Received signal but no mapping config to reload", "signal", s)
logger.Warn("Received signal but no mapping config to reload", "signal", s)
continue
}
level.Info(logger).Log("msg", "Received signal, attempting reload", "signal", s)
logger.Info("Received signal, attempting reload", "signal", s)
reloadConfig(fileName, mapper, logger)
}
}
func reloadConfig(fileName string, mapper *mapper.MetricMapper, logger log.Logger) {
func reloadConfig(fileName string, mapper *mapper.MetricMapper, logger *slog.Logger) {
err := mapper.InitFromFile(fileName)
if err != nil {
level.Info(logger).Log("msg", "Error reloading config", "error", err)
logger.Info("Error reloading config", "error", err)
configLoads.WithLabelValues("failure").Inc()
} else {
level.Info(logger).Log("msg", "Config reloaded successfully")
logger.Info("Config reloaded successfully")
configLoads.WithLabelValues("success").Inc()
}
}
func dumpFSM(mapper *mapper.MetricMapper, dumpFilename string, logger log.Logger) error {
func dumpFSM(mapper *mapper.MetricMapper, dumpFilename string, logger *slog.Logger) error {
f, err := os.Create(dumpFilename)
if err != nil {
return err
}
level.Info(logger).Log("msg", "Start dumping FSM", "file_name", dumpFilename)
logger.Info("Start dumping FSM", "file_name", dumpFilename)
w := bufio.NewWriter(f)
mapper.FSM.DumpFSM(w)
w.Flush()
f.Close()
level.Info(logger).Log("msg", "Finish dumping FSM")
logger.Info("Finish dumping FSM")
return nil
}
@ -271,17 +270,13 @@ func main() {
udpPacketQueueSize = kingpin.Flag("statsd.udp-packet-queue-size", "Size of internal queue for processing UDP packets.").Default("10000").Int()
)
promlogConfig := &promlog.Config{}
flag.AddFlags(kingpin.CommandLine, promlogConfig)
promslogConfig := &promslog.Config{}
flag.AddFlags(kingpin.CommandLine, promslogConfig)
kingpin.Version(version.Print("statsd_exporter"))
kingpin.CommandLine.UsageWriter(os.Stdout)
kingpin.HelpFlag.Short('h')
kingpin.Parse()
logger := promlog.New(promlogConfig)
if err := level.SetLogLevel(promlogConfig.Level.String()); err != nil {
level.Error(logger).Log("msg", "failed to set log level", "error", err)
os.Exit(1)
}
logger := promslog.New(promslogConfig)
prometheus.MustRegister(versioncollector.NewCollector("statsd_exporter"))
parser := line.NewParser()
@ -298,8 +293,8 @@ func main() {
parser.EnableSignalFXParsing()
}
level.Info(logger).Log("msg", "Starting StatsD -> Prometheus Exporter", "version", version.Info())
level.Info(logger).Log("msg", "Build context", "context", version.BuildContext())
logger.Info("Starting StatsD -> Prometheus Exporter", "version", version.Info())
logger.Info("Build context", "context", version.BuildContext())
events := make(chan event.Events, *eventQueueSize)
defer close(events)
@ -309,7 +304,7 @@ func main() {
cache, err := getCache(*cacheSize, *cacheType, thisMapper.Registerer)
if err != nil {
level.Error(logger).Log("msg", "Unable to setup metric mapper cache", "error", err)
logger.Error("Unable to setup metric mapper cache", "error", err)
os.Exit(1)
}
thisMapper.UseCache(cache)
@ -317,13 +312,13 @@ func main() {
if *mappingConfig != "" {
err := thisMapper.InitFromFile(*mappingConfig)
if err != nil {
level.Error(logger).Log("msg", "error loading config", "error", err)
logger.Error("error loading config", "error", err)
os.Exit(1)
}
if *dumpFSMPath != "" {
err := dumpFSM(thisMapper, *dumpFSMPath, logger)
if err != nil {
level.Error(logger).Log("msg", "error dumping FSM", "error", err)
logger.Error("error dumping FSM", "error", err)
// Failure to dump the FSM is an error (the user asked for it and it
// didn't happen) but not fatal (the exporter is fully functional
// afterwards).
@ -334,7 +329,7 @@ func main() {
exporter := exporter.NewExporter(prometheus.DefaultRegisterer, thisMapper, logger, eventsActions, eventsUnmapped, errorEventStats, eventStats, conflictingEventStats, metricsCount)
if *checkConfig {
level.Info(logger).Log("msg", "Configuration check successful, exiting")
logger.Info("Configuration check successful, exiting")
return
}
@ -343,35 +338,35 @@ func main() {
var err error
relayTarget, err = relay.NewRelay(logger, *relayAddr, *relayPacketLen)
if err != nil {
level.Error(logger).Log("msg", "Unable to create relay", "err", err)
logger.Error("Unable to create relay", "err", err)
os.Exit(1)
}
}
level.Info(logger).Log("msg", "Accepting StatsD Traffic", "udp", *statsdListenUDP, "tcp", *statsdListenTCP, "unixgram", *statsdListenUnixgram)
level.Info(logger).Log("msg", "Accepting Prometheus Requests", "addr", *listenAddress)
logger.Info("Accepting StatsD Traffic", "udp", *statsdListenUDP, "tcp", *statsdListenTCP, "unixgram", *statsdListenUnixgram)
logger.Info("Accepting Prometheus Requests", "addr", *listenAddress)
if *statsdListenUDP == "" && *statsdListenTCP == "" && *statsdListenUnixgram == "" {
level.Error(logger).Log("At least one of UDP/TCP/Unixgram listeners must be specified.")
logger.Error("At least one of UDP/TCP/Unixgram listeners must be specified.")
os.Exit(1)
}
if *statsdListenUDP != "" {
udpListenAddr, err := address.UDPAddrFromString(*statsdListenUDP)
if err != nil {
level.Error(logger).Log("msg", "invalid UDP listen address", "address", *statsdListenUDP, "error", err)
logger.Error("invalid UDP listen address", "address", *statsdListenUDP, "error", err)
os.Exit(1)
}
uconn, err := net.ListenUDP("udp", udpListenAddr)
if err != nil {
level.Error(logger).Log("msg", "failed to start UDP listener", "error", err)
logger.Error("failed to start UDP listener", "error", err)
os.Exit(1)
}
if *readBuffer != 0 {
err = uconn.SetReadBuffer(*readBuffer)
if err != nil {
level.Error(logger).Log("msg", "error setting UDP read buffer", "error", err)
logger.Error("error setting UDP read buffer", "error", err)
os.Exit(1)
}
}
@ -401,12 +396,12 @@ func main() {
if *statsdListenTCP != "" {
tcpListenAddr, err := address.TCPAddrFromString(*statsdListenTCP)
if err != nil {
level.Error(logger).Log("msg", "invalid TCP listen address", "address", *statsdListenUDP, "error", err)
logger.Error("invalid TCP listen address", "address", *statsdListenUDP, "error", err)
os.Exit(1)
}
tconn, err := net.ListenTCP("tcp", tcpListenAddr)
if err != nil {
level.Error(logger).Log("msg", err)
logger.Error("failed to start TCP listener", "err", err)
os.Exit(1)
}
defer tconn.Close()
@ -434,7 +429,7 @@ func main() {
if *statsdListenUnixgram != "" {
var err error
if _, err = os.Stat(*statsdListenUnixgram); !os.IsNotExist(err) {
level.Error(logger).Log("msg", "Unixgram socket already exists", "socket_name", *statsdListenUnixgram)
logger.Error("Unixgram socket already exists", "socket_name", *statsdListenUnixgram)
os.Exit(1)
}
uxgconn, err := net.ListenUnixgram("unixgram", &net.UnixAddr{
@ -442,7 +437,7 @@ func main() {
Name: *statsdListenUnixgram,
})
if err != nil {
level.Error(logger).Log("msg", "failed to listen on Unixgram socket", "error", err)
logger.Error("failed to listen on Unixgram socket", "error", err)
os.Exit(1)
}
@ -451,7 +446,7 @@ func main() {
if *readBuffer != 0 {
err = uxgconn.SetReadBuffer(*readBuffer)
if err != nil {
level.Error(logger).Log("msg", "error setting Unixgram read buffer", "error", err)
logger.Error("error setting Unixgram read buffer", "error", err)
os.Exit(1)
}
}
@ -481,11 +476,11 @@ func main() {
// convert the string to octet
perm, err := strconv.ParseInt("0"+string(*statsdUnixSocketMode), 8, 32)
if err != nil {
level.Warn(logger).Log("Bad permission %s: %v, ignoring\n", *statsdUnixSocketMode, err)
logger.Warn("Bad permission %s: %v, ignoring\n", *statsdUnixSocketMode, err)
} else {
err = os.Chmod(*statsdListenUnixgram, os.FileMode(perm))
if err != nil {
level.Warn(logger).Log("Failed to change unixgram socket permission: %v", err)
logger.Warn("Failed to change unixgram socket permission", "error", err)
}
}
}
@ -507,7 +502,7 @@ func main() {
}
landingPage, err := web.NewLandingPage(landingConfig)
if err != nil {
level.Error(logger).Log("err", err)
logger.Error("error creating landing page", "err", err)
os.Exit(1)
}
mux.Handle("/", landingPage)
@ -520,10 +515,10 @@ func main() {
if r.Method == http.MethodPut || r.Method == http.MethodPost {
fmt.Fprintf(w, "Requesting reload")
if *mappingConfig == "" {
level.Warn(logger).Log("msg", "Received lifecycle api reload but no mapping config to reload")
logger.Warn("Received lifecycle api reload but no mapping config to reload")
return
}
level.Info(logger).Log("msg", "Received lifecycle api reload, attempting reload")
logger.Info("Received lifecycle api reload, attempting reload")
reloadConfig(*mappingConfig, thisMapper, logger)
}
})
@ -537,7 +532,7 @@ func main() {
mux.HandleFunc("/-/healthy", func(w http.ResponseWriter, r *http.Request) {
if r.Method == http.MethodGet {
level.Debug(logger).Log("msg", "Received health check")
logger.Debug("Received health check")
w.WriteHeader(http.StatusOK)
fmt.Fprintf(w, "Statsd Exporter is Healthy.\n")
}
@ -545,7 +540,7 @@ func main() {
mux.HandleFunc("/-/ready", func(w http.ResponseWriter, r *http.Request) {
if r.Method == http.MethodGet {
level.Debug(logger).Log("msg", "Received ready check")
logger.Debug("Received ready check")
w.WriteHeader(http.StatusOK)
fmt.Fprintf(w, "Statsd Exporter is Ready.\n")
}
@ -562,8 +557,8 @@ func main() {
// quit if we get a message on either channel
select {
case sig := <-signals:
level.Info(logger).Log("msg", "Received os signal, exiting", "signal", sig.String())
logger.Info("Received os signal, exiting", "signal", sig.String())
case <-quitChan:
level.Info(logger).Log("msg", "Received lifecycle api quit, exiting")
logger.Info("Received lifecycle api quit, exiting")
}
}

View file

@ -18,6 +18,7 @@ import (
"time"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/statsd_exporter/pkg/clock"
"github.com/prometheus/statsd_exporter/pkg/mapper"
)
@ -39,6 +40,7 @@ func (c *CounterEvent) MetricName() string { return c.CMetricName }
func (c *CounterEvent) Value() float64 { return c.CValue }
func (c *CounterEvent) Labels() map[string]string { return c.CLabels }
func (c *CounterEvent) MetricType() mapper.MetricType { return mapper.MetricTypeCounter }
func (c *CounterEvent) Values() []float64 { return []float64{c.CValue} }
type GaugeEvent struct {
GMetricName string
@ -51,6 +53,7 @@ func (g *GaugeEvent) MetricName() string { return g.GMetricName }
func (g *GaugeEvent) Value() float64 { return g.GValue }
func (g *GaugeEvent) Labels() map[string]string { return g.GLabels }
func (g *GaugeEvent) MetricType() mapper.MetricType { return mapper.MetricTypeGauge }
func (g *GaugeEvent) Values() []float64 { return []float64{g.GValue} }
type ObserverEvent struct {
OMetricName string
@ -62,6 +65,7 @@ func (o *ObserverEvent) MetricName() string { return o.OMetricName }
func (o *ObserverEvent) Value() float64 { return o.OValue }
func (o *ObserverEvent) Labels() map[string]string { return o.OLabels }
func (o *ObserverEvent) MetricType() mapper.MetricType { return mapper.MetricTypeObserver }
func (o *ObserverEvent) Values() []float64 { return []float64{o.OValue} }
type Events []Event
@ -136,3 +140,87 @@ type UnbufferedEventHandler struct {
func (ueh *UnbufferedEventHandler) Queue(events Events) {
ueh.C <- events
}
// MultiValueEvent is an event that contains multiple values, it is going to replace the existing Event interface.
type MultiValueEvent interface {
MetricName() string
Labels() map[string]string
MetricType() mapper.MetricType
Values() []float64
}
type MultiObserverEvent struct {
OMetricName string
OValues []float64 // DataDog extensions allow multiple values in a single sample
OLabels map[string]string
SampleRate float64
}
type ExpandableEvent interface {
Expand() []Event
}
func (m *MultiObserverEvent) MetricName() string { return m.OMetricName }
func (m *MultiObserverEvent) Value() float64 { return m.OValues[0] }
func (m *MultiObserverEvent) Labels() map[string]string { return m.OLabels }
func (m *MultiObserverEvent) MetricType() mapper.MetricType { return mapper.MetricTypeObserver }
func (m *MultiObserverEvent) Values() []float64 { return m.OValues }
// Expand returns a list of events that are the result of expanding the multi-value event.
// This will be used as a middle-step in the pipeline to convert multi-value events to single-value events.
// And keep the exporter code compatible with previous versions.
func (m *MultiObserverEvent) Expand() []Event {
if len(m.OValues) == 1 && m.SampleRate == 0 {
return []Event{
&ObserverEvent{
OMetricName: m.OMetricName,
OValue: m.OValues[0],
OLabels: copyLabels(m.OLabels),
},
}
}
events := make([]Event, 0, len(m.OValues))
for _, value := range m.OValues {
events = append(events, &ObserverEvent{
OMetricName: m.OMetricName,
OValue: value,
OLabels: copyLabels(m.OLabels),
})
}
if m.SampleRate > 0 && m.SampleRate < 1 {
multiplier := int(1 / m.SampleRate)
multipliedEvents := make([]Event, 0, len(events)*multiplier)
for i := 0; i < multiplier; i++ {
for _, event := range events {
e := event.(*ObserverEvent)
multipliedEvents = append(multipliedEvents, &ObserverEvent{
OMetricName: e.OMetricName,
OValue: e.OValue,
OLabels: copyLabels(e.OLabels),
})
}
}
return multipliedEvents
}
return events
}
// Helper function to copy labels map
func copyLabels(labels map[string]string) map[string]string {
newLabels := make(map[string]string, len(labels))
for k, v := range labels {
newLabels[k] = v
}
return newLabels
}
var (
_ ExpandableEvent = &MultiObserverEvent{}
_ MultiValueEvent = &MultiObserverEvent{}
_ MultiValueEvent = &CounterEvent{}
_ MultiValueEvent = &GaugeEvent{}
_ MultiValueEvent = &ObserverEvent{}
)

View file

@ -14,11 +14,15 @@
package event
import (
"fmt"
"reflect"
"testing"
"time"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/statsd_exporter/pkg/clock"
"github.com/prometheus/statsd_exporter/pkg/mapper"
)
var eventsFlushed = prometheus.NewCounter(
@ -85,3 +89,206 @@ func TestEventIntervalFlush(t *testing.T) {
t.Fatal("Expected 10 events in the event channel, but got", len(events))
}
}
func TestMultiValueEvent(t *testing.T) {
tests := []struct {
name string
event MultiValueEvent
wantValues []float64
wantName string
wantType mapper.MetricType
wantLabels map[string]string
}{
{
name: "MultiObserverEvent with single value",
event: &MultiObserverEvent{
OMetricName: "test_metric",
OValues: []float64{1.0},
OLabels: map[string]string{"label": "value"},
SampleRate: 0,
},
wantValues: []float64{1.0},
wantName: "test_metric",
wantType: mapper.MetricTypeObserver,
wantLabels: map[string]string{"label": "value"},
},
{
name: "MultiObserverEvent with multiple values",
event: &MultiObserverEvent{
OMetricName: "test_metric",
OValues: []float64{1.0, 2.0, 3.0},
OLabels: map[string]string{"label": "value"},
SampleRate: 0.5,
},
wantValues: []float64{1.0, 2.0, 3.0},
wantName: "test_metric",
wantType: mapper.MetricTypeObserver,
wantLabels: map[string]string{"label": "value"},
},
{
name: "CounterEvent implements MultiValueEvent",
event: &CounterEvent{
CMetricName: "test_counter",
CValue: 42.0,
CLabels: map[string]string{"label": "value"},
},
wantValues: []float64{42.0},
wantName: "test_counter",
wantType: mapper.MetricTypeCounter,
wantLabels: map[string]string{"label": "value"},
},
{
name: "GaugeEvent implements MultiValueEvent",
event: &GaugeEvent{
GMetricName: "test_gauge",
GValue: 123.0,
GLabels: map[string]string{"label": "value"},
},
wantValues: []float64{123.0},
wantName: "test_gauge",
wantType: mapper.MetricTypeGauge,
wantLabels: map[string]string{"label": "value"},
},
{
name: "ObserverEvent implements MultiValueEvent",
event: &ObserverEvent{
OMetricName: "test_observer",
OValue: 99.0,
OLabels: map[string]string{"label": "value"},
},
wantValues: []float64{99.0},
wantName: "test_observer",
wantType: mapper.MetricTypeObserver,
wantLabels: map[string]string{"label": "value"},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := tt.event.Values(); !reflect.DeepEqual(got, tt.wantValues) {
t.Errorf("MultiValueEvent.Values() = %v, want %v", got, tt.wantValues)
}
if got := tt.event.MetricName(); got != tt.wantName {
t.Errorf("MultiValueEvent.MetricName() = %v, want %v", got, tt.wantName)
}
if got := tt.event.MetricType(); got != tt.wantType {
t.Errorf("MultiValueEvent.MetricType() = %v, want %v", got, tt.wantType)
}
if got := tt.event.Labels(); !reflect.DeepEqual(got, tt.wantLabels) {
t.Errorf("MultiValueEvent.Labels() = %v, want %v", got, tt.wantLabels)
}
})
}
}
func TestMultiObserverEvent_Expand(t *testing.T) {
t.Parallel()
tests := []struct {
name string
event *MultiObserverEvent
wantEvents []Event
}{
{
name: "single value no sampling",
event: &MultiObserverEvent{
OMetricName: "test_metric",
OValues: []float64{1.0},
OLabels: map[string]string{"label": "value"},
SampleRate: 0,
},
wantEvents: []Event{
&ObserverEvent{
OMetricName: "test_metric",
OValue: 1.0,
OLabels: map[string]string{"label": "value"},
},
},
},
{
name: "multiple values no sampling",
event: &MultiObserverEvent{
OMetricName: "test_metric",
OValues: []float64{1.0, 2.0, 3.0},
OLabels: map[string]string{"label": "value"},
SampleRate: 0,
},
wantEvents: []Event{
&ObserverEvent{
OMetricName: "test_metric",
OValue: 1.0,
OLabels: map[string]string{"label": "value"},
},
&ObserverEvent{
OMetricName: "test_metric",
OValue: 2.0,
OLabels: map[string]string{"label": "value"},
},
&ObserverEvent{
OMetricName: "test_metric",
OValue: 3.0,
OLabels: map[string]string{"label": "value"},
},
},
},
{
name: "multiple values with sampling",
event: &MultiObserverEvent{
OMetricName: "test_metric",
OValues: []float64{1.0, 2.0},
OLabels: map[string]string{"label": "value"},
SampleRate: 0.5,
},
wantEvents: []Event{
&ObserverEvent{
OMetricName: "test_metric",
OValue: 1.0,
OLabels: map[string]string{"label": "value"},
},
&ObserverEvent{
OMetricName: "test_metric",
OValue: 2.0,
OLabels: map[string]string{"label": "value"},
},
&ObserverEvent{
OMetricName: "test_metric",
OValue: 1.0,
OLabels: map[string]string{"label": "value"},
},
&ObserverEvent{
OMetricName: "test_metric",
OValue: 2.0,
OLabels: map[string]string{"label": "value"},
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
got := tt.event.Expand()
if len(tt.wantEvents) != len(got) {
t.Fatalf("Expected %d events, but got %d", len(tt.wantEvents), len(got))
}
eventCount := func(events []Event) map[string]int {
counts := make(map[string]int)
for _, event := range events {
oe := event.(*ObserverEvent)
key := fmt.Sprintf("%s%f%v", oe.OMetricName, oe.OValue, oe.OLabels)
counts[key]++
}
return counts
}
wantMap := eventCount(tt.wantEvents)
gotMap := eventCount(got)
for key, count := range wantMap {
if gotMap[key] != count {
t.Fatalf("Event mismatch for key %v: expected %d, got %d", key, count, gotMap[key])
}
}
})
}
}

View file

@ -14,15 +14,14 @@
package exporter
import (
"log/slog"
"os"
"time"
"github.com/go-kit/log"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/statsd_exporter/pkg/clock"
"github.com/prometheus/statsd_exporter/pkg/event"
"github.com/prometheus/statsd_exporter/pkg/level"
"github.com/prometheus/statsd_exporter/pkg/mapper"
"github.com/prometheus/statsd_exporter/pkg/registry"
)
@ -43,7 +42,7 @@ type Registry interface {
type Exporter struct {
Mapper *mapper.MetricMapper
Registry Registry
Logger log.Logger
Logger *slog.Logger
EventsActions *prometheus.CounterVec
EventsUnmapped prometheus.Counter
ErrorEventStats *prometheus.CounterVec
@ -63,7 +62,7 @@ func (b *Exporter) Listen(e <-chan event.Events) {
b.Registry.RemoveStaleMetrics()
case events, ok := <-e:
if !ok {
level.Debug(b.Logger).Log("msg", "Channel is closed. Break out of Exporter.Listener.")
b.Logger.Debug("Channel is closed. Break out of Exporter.Listener.")
removeStaleMetricsTicker.Stop()
return
}
@ -99,7 +98,7 @@ func (b *Exporter) handleEvent(thisEvent event.Event) {
prometheusLabels := thisEvent.Labels()
if present {
if mapping.Name == "" {
level.Debug(b.Logger).Log("msg", "The mapping generates an empty metric name", "metric_name", thisEvent.MetricName(), "match", mapping.Match)
b.Logger.Debug("The mapping generates an empty metric name", "metric_name", thisEvent.MetricName(), "match", mapping.Match)
b.ErrorEventStats.WithLabelValues("empty_metric_name").Inc()
return
}
@ -127,7 +126,7 @@ func (b *Exporter) handleEvent(thisEvent event.Event) {
// We don't accept negative values for counters. Incrementing the counter with a negative number
// will cause the exporter to panic. Instead we will warn and continue to the next event.
if eventValue < 0.0 {
level.Debug(b.Logger).Log("msg", "counter must be non-negative value", "metric", metricName, "event_value", eventValue)
b.Logger.Debug("counter must be non-negative value", "metric", metricName, "event_value", eventValue)
b.ErrorEventStats.WithLabelValues("illegal_negative_counter").Inc()
return
}
@ -137,8 +136,8 @@ func (b *Exporter) handleEvent(thisEvent event.Event) {
counter.Add(eventValue)
b.EventStats.WithLabelValues("counter").Inc()
} else {
level.Debug(b.Logger).Log("msg", regErrF, "metric", metricName, "error", err)
b.ConflictingEventStats.WithLabelValues("counter").Inc()
b.Logger.Debug(regErrF, "metric", metricName, "error", err)
b.ConflictingEventStats.WithLabelValues("counter", metricName).Inc()
}
case *event.GaugeEvent:
@ -152,8 +151,8 @@ func (b *Exporter) handleEvent(thisEvent event.Event) {
}
b.EventStats.WithLabelValues("gauge").Inc()
} else {
level.Debug(b.Logger).Log("msg", regErrF, "metric", metricName, "error", err)
b.ConflictingEventStats.WithLabelValues("gauge").Inc()
b.Logger.Debug(regErrF, "metric", metricName, "error", err)
b.ConflictingEventStats.WithLabelValues("gauge", metricName).Inc()
}
case *event.ObserverEvent:
@ -172,8 +171,8 @@ func (b *Exporter) handleEvent(thisEvent event.Event) {
histogram.Observe(eventValue)
b.EventStats.WithLabelValues("observer").Inc()
} else {
level.Debug(b.Logger).Log("msg", regErrF, "metric", metricName, "error", err)
b.ConflictingEventStats.WithLabelValues("observer").Inc()
b.Logger.Debug(regErrF, "metric", metricName, "error", err)
b.ConflictingEventStats.WithLabelValues("observer", metricName).Inc()
}
case mapper.ObserverTypeDefault, mapper.ObserverTypeSummary:
@ -182,22 +181,22 @@ func (b *Exporter) handleEvent(thisEvent event.Event) {
summary.Observe(eventValue)
b.EventStats.WithLabelValues("observer").Inc()
} else {
level.Debug(b.Logger).Log("msg", regErrF, "metric", metricName, "error", err)
b.ConflictingEventStats.WithLabelValues("observer").Inc()
b.Logger.Debug(regErrF, "metric", metricName, "error", err)
b.ConflictingEventStats.WithLabelValues("observer", metricName).Inc()
}
default:
level.Error(b.Logger).Log("msg", "unknown observer type", "type", t)
b.Logger.Error("unknown observer type", "type", t)
os.Exit(1)
}
default:
level.Debug(b.Logger).Log("msg", "Unsupported event type")
b.Logger.Debug("Unsupported event type")
b.EventStats.WithLabelValues("illegal").Inc()
}
}
func NewExporter(reg prometheus.Registerer, mapper *mapper.MetricMapper, logger log.Logger, eventsActions *prometheus.CounterVec, eventsUnmapped prometheus.Counter, errorEventStats *prometheus.CounterVec, eventStats *prometheus.CounterVec, conflictingEventStats *prometheus.CounterVec, metricsCount *prometheus.GaugeVec) *Exporter {
func NewExporter(reg prometheus.Registerer, mapper *mapper.MetricMapper, logger *slog.Logger, eventsActions *prometheus.CounterVec, eventsUnmapped prometheus.Counter, errorEventStats, eventStats, conflictingEventStats *prometheus.CounterVec, metricsCount *prometheus.GaugeVec) *Exporter {
return &Exporter{
Mapper: mapper,
Registry: registry.NewRegistry(reg, mapper),

View file

@ -15,13 +15,14 @@ package exporter
import (
"fmt"
"log/slog"
"net"
"testing"
"time"
"github.com/go-kit/log"
"github.com/prometheus/client_golang/prometheus"
dto "github.com/prometheus/client_model/go"
"github.com/prometheus/common/promslog"
"github.com/prometheus/statsd_exporter/pkg/clock"
"github.com/prometheus/statsd_exporter/pkg/event"
@ -116,7 +117,7 @@ var (
Name: "statsd_exporter_events_conflict_total",
Help: "The total number of StatsD events with conflicting names.",
},
[]string{"type"},
[]string{"type", "metric_name"},
)
errorEventStats = prometheus.NewCounterVec(
prometheus.CounterOpts{
@ -172,7 +173,7 @@ func TestNegativeCounter(t *testing.T) {
testMapper := mapper.MetricMapper{}
ex := NewExporter(prometheus.DefaultRegisterer, &testMapper, log.NewNopLogger(), eventsActions, eventsUnmapped, errorEventStats, eventStats, conflictingEventStats, metricsCount)
ex := NewExporter(prometheus.DefaultRegisterer, &testMapper, promslog.NewNopLogger(), eventsActions, eventsUnmapped, errorEventStats, eventStats, conflictingEventStats, metricsCount)
ex.Listen(events)
updated := getTelemetryCounterValue(errorCounter)
@ -253,7 +254,7 @@ mappings:
t.Fatalf("Config load error: %s %s", config, err)
}
ex := NewExporter(prometheus.DefaultRegisterer, testMapper, log.NewNopLogger(), eventsActions, eventsUnmapped, errorEventStats, eventStats, conflictingEventStats, metricsCount)
ex := NewExporter(prometheus.DefaultRegisterer, testMapper, promslog.NewNopLogger(), eventsActions, eventsUnmapped, errorEventStats, eventStats, conflictingEventStats, metricsCount)
ex.Listen(events)
metrics, err := prometheus.DefaultGatherer.Gather()
@ -316,7 +317,7 @@ mappings:
t.Fatalf("Config load error: %s %s", config, err)
}
ex := NewExporter(prometheus.DefaultRegisterer, testMapper, log.NewNopLogger(), eventsActions, eventsUnmapped, errorEventStats, eventStats, conflictingEventStats, metricsCount)
ex := NewExporter(prometheus.DefaultRegisterer, testMapper, promslog.NewNopLogger(), eventsActions, eventsUnmapped, errorEventStats, eventStats, conflictingEventStats, metricsCount)
ex.Listen(events)
metrics, err := prometheus.DefaultGatherer.Gather()
@ -359,14 +360,14 @@ mappings:
honor_labels: true
`
testMapper := &mapper.MetricMapper{
Logger: log.NewNopLogger(),
Logger: promslog.NewNopLogger(),
}
err := testMapper.InitFromYAMLString(config)
if err != nil {
t.Fatalf("Config load error: %s %s", config, err)
}
ex := NewExporter(prometheus.DefaultRegisterer, testMapper, log.NewNopLogger(), eventsActions, eventsUnmapped, errorEventStats, eventStats, conflictingEventStats, metricsCount)
ex := NewExporter(prometheus.DefaultRegisterer, testMapper, promslog.NewNopLogger(), eventsActions, eventsUnmapped, errorEventStats, eventStats, conflictingEventStats, metricsCount)
ex.Listen(events)
metrics, err := prometheus.DefaultGatherer.Gather()
@ -647,7 +648,7 @@ mappings:
close(events)
}()
reg := prometheus.NewRegistry()
ex := NewExporter(reg, testMapper, log.NewNopLogger(), eventsActions, eventsUnmapped, errorEventStats, eventStats, conflictingEventStats, metricsCount)
ex := NewExporter(reg, testMapper, promslog.NewNopLogger(), eventsActions, eventsUnmapped, errorEventStats, eventStats, conflictingEventStats, metricsCount)
ex.Listen(events)
metrics, err := reg.Gather()
@ -702,7 +703,7 @@ mappings:
errorCounter := errorEventStats.WithLabelValues("empty_metric_name")
prev := getTelemetryCounterValue(errorCounter)
ex := NewExporter(prometheus.DefaultRegisterer, testMapper, log.NewNopLogger(), eventsActions, eventsUnmapped, errorEventStats, eventStats, conflictingEventStats, metricsCount)
ex := NewExporter(prometheus.DefaultRegisterer, testMapper, promslog.NewNopLogger(), eventsActions, eventsUnmapped, errorEventStats, eventStats, conflictingEventStats, metricsCount)
ex.Listen(events)
updated := getTelemetryCounterValue(errorCounter)
@ -736,7 +737,7 @@ func TestInvalidUtf8InDatadogTagValue(t *testing.T) {
for _, l := range []statsDPacketHandler{&listener.StatsDUDPListener{
Conn: nil,
EventHandler: nil,
Logger: log.NewNopLogger(),
Logger: promslog.NewNopLogger(),
LineParser: parser,
UDPPackets: udpPackets,
UDPPacketDrops: udpPacketDrops,
@ -749,7 +750,7 @@ func TestInvalidUtf8InDatadogTagValue(t *testing.T) {
}, &mockStatsDTCPListener{listener.StatsDTCPListener{
Conn: nil,
EventHandler: nil,
Logger: log.NewNopLogger(),
Logger: promslog.NewNopLogger(),
LineParser: parser,
LinesReceived: linesReceived,
EventsFlushed: eventsFlushed,
@ -760,7 +761,7 @@ func TestInvalidUtf8InDatadogTagValue(t *testing.T) {
TCPConnections: tcpConnections,
TCPErrors: tcpErrors,
TCPLineTooLong: tcpLineTooLong,
}, log.NewNopLogger()}} {
}, promslog.NewNopLogger()}} {
l.SetEventHandler(ueh)
l.HandlePacket([]byte("bar:200|c|#tag:value\nbar:200|c|#tag:\xc3\x28invalid"))
}
@ -769,7 +770,7 @@ func TestInvalidUtf8InDatadogTagValue(t *testing.T) {
testMapper := mapper.MetricMapper{}
ex := NewExporter(prometheus.DefaultRegisterer, &testMapper, log.NewNopLogger(), eventsActions, eventsUnmapped, errorEventStats, eventStats, conflictingEventStats, metricsCount)
ex := NewExporter(prometheus.DefaultRegisterer, &testMapper, promslog.NewNopLogger(), eventsActions, eventsUnmapped, errorEventStats, eventStats, conflictingEventStats, metricsCount)
ex.Listen(events)
}
@ -782,7 +783,7 @@ func TestSummaryWithQuantilesEmptyMapping(t *testing.T) {
go func() {
testMapper := mapper.MetricMapper{}
ex := NewExporter(prometheus.DefaultRegisterer, &testMapper, log.NewNopLogger(), eventsActions, eventsUnmapped, errorEventStats, eventStats, conflictingEventStats, metricsCount)
ex := NewExporter(prometheus.DefaultRegisterer, &testMapper, promslog.NewNopLogger(), eventsActions, eventsUnmapped, errorEventStats, eventStats, conflictingEventStats, metricsCount)
ex.Listen(events)
}()
@ -825,7 +826,7 @@ func TestHistogramUnits(t *testing.T) {
events := make(chan event.Events)
go func() {
testMapper := mapper.MetricMapper{}
ex := NewExporter(prometheus.DefaultRegisterer, &testMapper, log.NewNopLogger(), eventsActions, eventsUnmapped, errorEventStats, eventStats, conflictingEventStats, metricsCount)
ex := NewExporter(prometheus.DefaultRegisterer, &testMapper, promslog.NewNopLogger(), eventsActions, eventsUnmapped, errorEventStats, eventStats, conflictingEventStats, metricsCount)
ex.Mapper.Defaults.ObserverType = mapper.ObserverTypeHistogram
ex.Listen(events)
}()
@ -856,12 +857,13 @@ func TestHistogramUnits(t *testing.T) {
t.Fatalf("Received unexpected value for histogram observation %f != .300", *value)
}
}
func TestCounterIncrement(t *testing.T) {
// Start exporter with a synchronous channel
events := make(chan event.Events)
go func() {
testMapper := mapper.MetricMapper{}
ex := NewExporter(prometheus.DefaultRegisterer, &testMapper, log.NewNopLogger(), eventsActions, eventsUnmapped, errorEventStats, eventStats, conflictingEventStats, metricsCount)
ex := NewExporter(prometheus.DefaultRegisterer, &testMapper, promslog.NewNopLogger(), eventsActions, eventsUnmapped, errorEventStats, eventStats, conflictingEventStats, metricsCount)
ex.Listen(events)
}()
@ -908,7 +910,7 @@ func TestGaugeIncrementDecrement(t *testing.T) {
events := make(chan event.Events)
go func() {
testMapper := mapper.MetricMapper{}
ex := NewExporter(prometheus.DefaultRegisterer, &testMapper, log.NewNopLogger(), eventsActions, eventsUnmapped, errorEventStats, eventStats, conflictingEventStats, metricsCount)
ex := NewExporter(prometheus.DefaultRegisterer, &testMapper, promslog.NewNopLogger(), eventsActions, eventsUnmapped, errorEventStats, eventStats, conflictingEventStats, metricsCount)
ex.Listen(events)
}()
@ -970,7 +972,7 @@ func TestScaledMapping(t *testing.T) {
// Start exporter with a synchronous channel
go func() {
ex := NewExporter(prometheus.DefaultRegisterer, &testMapper, log.NewNopLogger(), eventsActions, eventsUnmapped, errorEventStats, eventStats, conflictingEventStats, metricsCount)
ex := NewExporter(prometheus.DefaultRegisterer, &testMapper, promslog.NewNopLogger(), eventsActions, eventsUnmapped, errorEventStats, eventStats, conflictingEventStats, metricsCount)
ex.Listen(events)
}()
@ -1018,7 +1020,7 @@ type statsDPacketHandler interface {
type mockStatsDTCPListener struct {
listener.StatsDTCPListener
log.Logger
*slog.Logger
}
func (ml *mockStatsDTCPListener) HandlePacket(packet []byte) {
@ -1079,7 +1081,7 @@ mappings:
events := make(chan event.Events)
defer close(events)
go func() {
ex := NewExporter(prometheus.DefaultRegisterer, testMapper, log.NewNopLogger(), eventsActions, eventsUnmapped, errorEventStats, eventStats, conflictingEventStats, metricsCount)
ex := NewExporter(prometheus.DefaultRegisterer, testMapper, promslog.NewNopLogger(), eventsActions, eventsUnmapped, errorEventStats, eventStats, conflictingEventStats, metricsCount)
ex.Listen(events)
}()
@ -1291,7 +1293,7 @@ func BenchmarkParseDogStatsDTags(b *testing.B) {
b.Run(name, func(b *testing.B) {
for n := 0; n < b.N; n++ {
labels := map[string]string{}
parser.ParseDogStatsDTags(tags, labels, tagErrors, log.NewNopLogger())
parser.ParseDogStatsDTags(tags, labels, tagErrors, promslog.NewNopLogger())
}
})
}

View file

@ -1,97 +0,0 @@
// Copyright 2021 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package level
import (
"fmt"
"github.com/go-kit/log"
"github.com/go-kit/log/level"
)
var logLevel = LevelInfo
// A Level is a logging priority. Higher levels are more important.
type Level int
const (
// LevelDebug logs are typically voluminous, and are usually disabled in
// production.
LevelDebug Level = iota
// LevelInfo is the default logging priority.
LevelInfo
// LevelWarn logs are more important than Info, but don't need individual
// human review.
LevelWarn
// LevelError logs are high-priority. If an application is running smoothly,
// it shouldn't generate any error-level logs.
LevelError
)
var emptyLogger = &EmptyLogger{}
type EmptyLogger struct{}
func (l *EmptyLogger) Log(keyvals ...interface{}) error {
return nil
}
// SetLogLevel sets the log level.
func SetLogLevel(level string) error {
switch level {
case "debug":
logLevel = LevelDebug
case "info":
logLevel = LevelInfo
case "warn":
logLevel = LevelWarn
case "error":
logLevel = LevelError
default:
return fmt.Errorf("unrecognized log level %s", level)
}
return nil
}
// Error returns a logger that includes a Key/ErrorValue pair.
func Error(logger log.Logger) log.Logger {
if logLevel <= LevelError {
return level.Error(logger)
}
return emptyLogger
}
// Warn returns a logger that includes a Key/WarnValue pair.
func Warn(logger log.Logger) log.Logger {
if logLevel <= LevelWarn {
return level.Warn(logger)
}
return emptyLogger
}
// Info returns a logger that includes a Key/InfoValue pair.
func Info(logger log.Logger) log.Logger {
if logLevel <= LevelInfo {
return level.Info(logger)
}
return emptyLogger
}
// Debug returns a logger that includes a Key/DebugValue pair.
func Debug(logger log.Logger) log.Logger {
if logLevel <= LevelDebug {
return level.Debug(logger)
}
return emptyLogger
}

View file

@ -1,110 +0,0 @@
// Copyright 2021 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package level
import (
"bytes"
"strings"
"testing"
"github.com/go-kit/log"
)
func TestSetLogLevel(t *testing.T) {
tests := []struct {
name string
level string
logLevel Level
wantErr bool
}{
{"wrong level", "foo", LevelInfo, true},
{"level debug", "debug", LevelDebug, false},
{"level info", "info", LevelInfo, false},
{"level warn", "warn", LevelWarn, false},
{"level error", "error", LevelError, false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if err := SetLogLevel(tt.level); (err != nil) != tt.wantErr {
t.Fatalf("Expected log level to be set successfully, but got %v", err)
}
if tt.logLevel != logLevel {
t.Fatalf("Expected log level %v, but got %v", tt.logLevel, logLevel)
}
})
}
}
func TestVariousLevels(t *testing.T) {
tests := []struct {
name string
level string
want string
}{
{
"level debug",
"debug",
strings.Join([]string{
"level=debug log=debug",
"level=info log=info",
"level=warn log=warn",
"level=error log=error",
}, "\n"),
},
{
"level info",
"info",
strings.Join([]string{
"level=info log=info",
"level=warn log=warn",
"level=error log=error",
}, "\n"),
},
{
"level warn",
"warn",
strings.Join([]string{
"level=warn log=warn",
"level=error log=error",
}, "\n"),
},
{
"level error",
"error",
strings.Join([]string{
"level=error log=error",
}, "\n"),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
var buf bytes.Buffer
logger := log.NewLogfmtLogger(&buf)
if err := SetLogLevel(tt.level); err != nil {
t.Fatalf("Expected log level to be set successfully, but got %v", err)
}
Debug(logger).Log("log", "debug")
Info(logger).Log("log", "info")
Warn(logger).Log("log", "warn")
Error(logger).Log("log", "error")
got := strings.TrimSpace(buf.String())
if tt.want != got {
t.Fatalf("Expected log output %v, but got %v", tt.want, got)
}
})
}
}

View file

@ -15,15 +15,14 @@ package line
import (
"fmt"
"log/slog"
"strconv"
"strings"
"unicode/utf8"
"github.com/go-kit/log"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/statsd_exporter/pkg/event"
"github.com/prometheus/statsd_exporter/pkg/level"
"github.com/prometheus/statsd_exporter/pkg/mapper"
)
@ -95,11 +94,11 @@ func buildEvent(statType, metric string, value float64, relative bool, labels ma
}
}
func parseTag(component, tag string, separator rune, labels map[string]string, tagErrors prometheus.Counter, logger log.Logger) {
func parseTag(component, tag string, separator rune, labels map[string]string, tagErrors prometheus.Counter, logger *slog.Logger) {
// Entirely empty tag is an error
if len(tag) == 0 {
tagErrors.Inc()
level.Debug(logger).Log("msg", "Empty name tag", "component", component)
logger.Debug("Empty name tag", "component", component)
return
}
@ -111,7 +110,7 @@ func parseTag(component, tag string, separator rune, labels map[string]string, t
if len(k) == 0 || len(v) == 0 {
// Empty key or value is an error
tagErrors.Inc()
level.Debug(logger).Log("msg", "Malformed name tag", "k", k, "v", v, "component", component)
logger.Debug("Malformed name tag", "k", k, "v", v, "component", component)
} else {
labels[mapper.EscapeMetricName(k)] = v
}
@ -121,10 +120,10 @@ func parseTag(component, tag string, separator rune, labels map[string]string, t
// Missing separator (no value) is an error
tagErrors.Inc()
level.Debug(logger).Log("msg", "Malformed name tag", "tag", tag, "component", component)
logger.Debug("Malformed name tag", "tag", tag, "component", component)
}
func parseNameTags(component string, labels map[string]string, tagErrors prometheus.Counter, logger log.Logger) {
func parseNameTags(component string, labels map[string]string, tagErrors prometheus.Counter, logger *slog.Logger) {
lastTagEndIndex := 0
for i, c := range component {
if c == ',' {
@ -148,7 +147,7 @@ func trimLeftHash(s string) string {
return s
}
func (p *Parser) ParseDogStatsDTags(component string, labels map[string]string, tagErrors prometheus.Counter, logger log.Logger) {
func (p *Parser) ParseDogStatsDTags(component string, labels map[string]string, tagErrors prometheus.Counter, logger *slog.Logger) {
if p.DogstatsdTagsEnabled {
lastTagEndIndex := 0
for i, c := range component {
@ -167,7 +166,7 @@ func (p *Parser) ParseDogStatsDTags(component string, labels map[string]string,
}
}
func (p *Parser) parseNameAndTags(name string, labels map[string]string, tagErrors prometheus.Counter, logger log.Logger) string {
func (p *Parser) parseNameAndTags(name string, labels map[string]string, tagErrors prometheus.Counter, logger *slog.Logger) string {
if p.SignalFXTagsEnabled {
// check for SignalFx tags first
// `[` delimits start of tags by SignalFx
@ -183,7 +182,7 @@ func (p *Parser) parseNameAndTags(name string, labels map[string]string, tagErro
return name[:startIdx] + name[endIdx+1:]
case (startIdx != -1) != (endIdx != -1):
// only one bracket, return unparsed
level.Debug(logger).Log("msg", "invalid SignalFx tags, not parsing", "metric", name)
logger.Debug("invalid SignalFx tags, not parsing", "metric", name)
tagErrors.Inc()
return name
}
@ -202,7 +201,7 @@ func (p *Parser) parseNameAndTags(name string, labels map[string]string, tagErro
return name
}
func (p *Parser) LineToEvents(line string, sampleErrors prometheus.CounterVec, samplesReceived prometheus.Counter, tagErrors prometheus.Counter, tagsReceived prometheus.Counter, logger log.Logger) event.Events {
func (p *Parser) LineToEvents(line string, sampleErrors prometheus.CounterVec, samplesReceived, tagErrors, tagsReceived prometheus.Counter, logger *slog.Logger) event.Events {
events := event.Events{}
if line == "" {
return events
@ -211,7 +210,7 @@ func (p *Parser) LineToEvents(line string, sampleErrors prometheus.CounterVec, s
elements := strings.SplitN(line, ":", 2)
if len(elements) < 2 || len(elements[0]) == 0 || !utf8.ValidString(line) {
sampleErrors.WithLabelValues("malformed_line").Inc()
level.Debug(logger).Log("msg", "bad line", "line", line)
logger.Debug("bad line", "line", line)
return events
}
@ -223,7 +222,7 @@ func (p *Parser) LineToEvents(line string, sampleErrors prometheus.CounterVec, s
// don't allow mixed tagging styles
sampleErrors.WithLabelValues("mixed_tagging_styles").Inc()
level.Debug(logger).Log("msg", "bad line: multiple tagging styles", "line", line)
logger.Debug("bad line: multiple tagging styles", "line", line)
return events
}
@ -231,7 +230,7 @@ func (p *Parser) LineToEvents(line string, sampleErrors prometheus.CounterVec, s
lineParts := strings.SplitN(elements[1], "|", 3)
if len(lineParts) < 2 {
sampleErrors.WithLabelValues("not_enough_parts_after_colon").Inc()
level.Debug(logger).Log("msg", "bad line: not enough '|'-delimited parts after first ':'", "line", line)
logger.Debug("bad line: not enough '|'-delimited parts after first ':'", "line", line)
return events
}
if strings.Contains(lineParts[0], ":") {
@ -256,7 +255,7 @@ func (p *Parser) LineToEvents(line string, sampleErrors prometheus.CounterVec, s
samples = aggLines
} else {
sampleErrors.WithLabelValues("invalid_extended_aggregate_type").Inc()
level.Debug(logger).Log("msg", "bad line: invalid extended aggregate type", "line", line)
logger.Debug("bad line: invalid extended aggregate type", "line", line)
return events
}
} else if usingDogStatsDTags {
@ -272,19 +271,19 @@ samples:
components := strings.Split(sample, "|")
if len(components) < 2 || len(components) > 4 {
sampleErrors.WithLabelValues("malformed_component").Inc()
level.Debug(logger).Log("msg", "bad component", "line", line)
logger.Debug("bad component", "line", line)
continue
}
valueStr, statType := components[0], components[1]
var relative = false
relative := false
if strings.Index(valueStr, "+") == 0 || strings.Index(valueStr, "-") == 0 {
relative = true
}
value, err := strconv.ParseFloat(valueStr, 64)
if err != nil {
level.Debug(logger).Log("msg", "bad value", "value", valueStr, "line", line)
logger.Debug("bad value", "value", valueStr, "line", line)
sampleErrors.WithLabelValues("malformed_value").Inc()
continue
}
@ -293,7 +292,7 @@ samples:
if len(components) >= 3 {
for _, component := range components[2:] {
if len(component) == 0 {
level.Debug(logger).Log("msg", "Empty component", "line", line)
logger.Debug("Empty component", "line", line)
sampleErrors.WithLabelValues("malformed_component").Inc()
continue samples
}
@ -305,7 +304,7 @@ samples:
samplingFactor, err := strconv.ParseFloat(component[1:], 64)
if err != nil {
level.Debug(logger).Log("msg", "Invalid sampling factor", "component", component[1:], "line", line)
logger.Debug("Invalid sampling factor", "component", component[1:], "line", line)
sampleErrors.WithLabelValues("invalid_sample_factor").Inc()
}
if samplingFactor == 0 {
@ -322,7 +321,7 @@ samples:
case '#':
p.ParseDogStatsDTags(component[1:], labels, tagErrors, logger)
default:
level.Debug(logger).Log("msg", "Invalid sampling factor or tag section", "component", components[2], "line", line)
logger.Debug("Invalid sampling factor or tag section", "component", components[2], "line", line)
sampleErrors.WithLabelValues("invalid_sample_factor").Inc()
continue
}
@ -336,7 +335,7 @@ samples:
for i := 0; i < multiplyEvents; i++ {
event, err := buildEvent(statType, metric, value, relative, labels)
if err != nil {
level.Debug(logger).Log("msg", "Error building event", "line", line, "error", err)
logger.Debug("Error building event", "line", line, "error", err)
sampleErrors.WithLabelValues("illegal_event").Inc()
continue
}

View file

@ -17,8 +17,8 @@ import (
"reflect"
"testing"
"github.com/go-kit/log"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/common/promslog"
"github.com/prometheus/statsd_exporter/pkg/event"
)
@ -49,7 +49,7 @@ var (
Help: "The number of errors parsing DogStatsD tags.",
},
)
nopLogger = log.NewNopLogger()
nopLogger = promslog.NewNopLogger()
)
func TestLineToEvents(t *testing.T) {

View file

@ -16,26 +16,25 @@ package listener
import (
"bufio"
"io"
"log/slog"
"net"
"os"
"strings"
"github.com/go-kit/log"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/statsd_exporter/pkg/event"
"github.com/prometheus/statsd_exporter/pkg/level"
"github.com/prometheus/statsd_exporter/pkg/relay"
)
type Parser interface {
LineToEvents(line string, sampleErrors prometheus.CounterVec, samplesReceived prometheus.Counter, tagErrors prometheus.Counter, tagsReceived prometheus.Counter, logger log.Logger) event.Events
LineToEvents(line string, sampleErrors prometheus.CounterVec, samplesReceived, tagErrors, tagsReceived prometheus.Counter, logger *slog.Logger) event.Events
}
type StatsDUDPListener struct {
Conn *net.UDPConn
EventHandler event.EventHandler
Logger log.Logger
Logger *slog.Logger
LineParser Parser
UDPPackets prometheus.Counter
UDPPacketDrops prometheus.Counter
@ -64,7 +63,7 @@ func (l *StatsDUDPListener) Listen() {
if strings.HasSuffix(err.Error(), "use of closed network connection") {
return
}
level.Error(l.Logger).Log("error", err)
l.Logger.Error("error reading from UDP connection", "err", err)
return
}
@ -94,7 +93,7 @@ func (l *StatsDUDPListener) ProcessUdpPacketQueue() {
func (l *StatsDUDPListener) HandlePacket(packet []byte) {
lines := strings.Split(string(packet), "\n")
for _, line := range lines {
level.Debug(l.Logger).Log("msg", "Incoming line", "proto", "udp", "line", line)
l.Logger.Debug("Incoming line", "proto", "udp", "line", line)
l.LinesReceived.Inc()
if l.Relay != nil && len(line) > 0 {
l.Relay.RelayLine(line)
@ -106,7 +105,7 @@ func (l *StatsDUDPListener) HandlePacket(packet []byte) {
type StatsDTCPListener struct {
Conn *net.TCPListener
EventHandler event.EventHandler
Logger log.Logger
Logger *slog.Logger
LineParser Parser
LinesReceived prometheus.Counter
EventsFlushed prometheus.Counter
@ -133,7 +132,7 @@ func (l *StatsDTCPListener) Listen() {
if strings.HasSuffix(err.Error(), "use of closed network connection") {
return
}
level.Error(l.Logger).Log("msg", "AcceptTCP failed", "error", err)
l.Logger.Error("AcceptTCP failed", "error", err)
os.Exit(1)
}
go l.HandleConn(c)
@ -151,14 +150,14 @@ func (l *StatsDTCPListener) HandleConn(c *net.TCPConn) {
if err != nil {
if err != io.EOF {
l.TCPErrors.Inc()
level.Debug(l.Logger).Log("msg", "Read failed", "addr", c.RemoteAddr(), "error", err)
l.Logger.Debug("Read failed", "addr", c.RemoteAddr(), "error", err)
}
break
}
level.Debug(l.Logger).Log("msg", "Incoming line", "proto", "tcp", "line", string(line))
l.Logger.Debug("Incoming line", "proto", "tcp", "line", string(line))
if isPrefix {
l.TCPLineTooLong.Inc()
level.Debug(l.Logger).Log("msg", "Read failed: line too long", "addr", c.RemoteAddr())
l.Logger.Debug("Read failed: line too long", "addr", c.RemoteAddr())
break
}
l.LinesReceived.Inc()
@ -172,7 +171,7 @@ func (l *StatsDTCPListener) HandleConn(c *net.TCPConn) {
type StatsDUnixgramListener struct {
Conn *net.UnixConn
EventHandler event.EventHandler
Logger log.Logger
Logger *slog.Logger
LineParser Parser
UnixgramPackets prometheus.Counter
LinesReceived prometheus.Counter
@ -198,7 +197,7 @@ func (l *StatsDUnixgramListener) Listen() {
if strings.HasSuffix(err.Error(), "use of closed network connection") {
return
}
level.Error(l.Logger).Log(err)
l.Logger.Error("error reading from unixgram connection", "err", err)
os.Exit(1)
}
l.HandlePacket(buf[:n])
@ -209,7 +208,7 @@ func (l *StatsDUnixgramListener) HandlePacket(packet []byte) {
l.UnixgramPackets.Inc()
lines := strings.Split(string(packet), "\n")
for _, line := range lines {
level.Debug(l.Logger).Log("msg", "Incoming line", "proto", "unixgram", "line", line)
l.Logger.Debug("Incoming line", "proto", "unixgram", "line", line)
l.LinesReceived.Inc()
if l.Relay != nil && len(line) > 0 {
l.Relay.RelayLine(line)

View file

@ -31,18 +31,18 @@ func (f *FSM) DumpFSM(w io.Writer) {
for idx < len(states) {
for field, transition := range states[idx].transitions {
states[len(states)] = transition
w.Write([]byte(fmt.Sprintf("%d -> %d [label = \"%s\"];\n", idx, len(states)-1, field)))
fmt.Fprintf(w, "%d -> %d [label = \"%s\"];\n", idx, len(states)-1, field)
if idx == 0 {
// color for metric types
w.Write([]byte(fmt.Sprintf("%d [color=\"#D6B656\",fillcolor=\"#FFF2CC\"];\n", len(states)-1)))
fmt.Fprintf(w, "%d [color=\"#D6B656\",fillcolor=\"#FFF2CC\"];\n", len(states)-1)
} else if len(transition.transitions) == 0 {
// color for end state
w.Write([]byte(fmt.Sprintf("%d [color=\"#82B366\",fillcolor=\"#D5E8D4\"];\n", len(states)-1)))
fmt.Fprintf(w, "%d [color=\"#82B366\",fillcolor=\"#D5E8D4\"];\n", len(states)-1)
}
}
idx++
}
// color for start state
w.Write([]byte(fmt.Sprintln("0 [color=\"#a94442\",fillcolor=\"#f2dede\"];")))
fmt.Fprintln(w, "0 [color=\"#a94442\",fillcolor=\"#f2dede\"];")
w.Write([]byte("}"))
}

View file

@ -20,9 +20,7 @@ import (
"strings"
)
var (
templateReplaceCaptureRE = regexp.MustCompile(`\$\{?([a-zA-Z0-9_\$]+)\}?`)
)
var templateReplaceCaptureRE = regexp.MustCompile(`\$\{?([a-zA-Z0-9_\$]+)\}?`)
type TemplateFormatter struct {
captureIndexes []int
@ -46,9 +44,9 @@ func NewTemplateFormatter(template string, captureCount int) *TemplateFormatter
if err != nil || idx > captureCount || idx < 1 {
// if index larger than captured count or using unsupported named capture group,
// replace with empty string
valueFormatter = strings.Replace(valueFormatter, match[0], "", -1)
valueFormatter = strings.ReplaceAll(valueFormatter, match[0], "")
} else {
valueFormatter = strings.Replace(valueFormatter, match[0], "%s", -1)
valueFormatter = strings.ReplaceAll(valueFormatter, match[0], "%s")
// note: the regex reference variable $? starts from 1
indexes = append(indexes, idx-1)
}

View file

@ -14,12 +14,9 @@
package fsm
import (
"log/slog"
"regexp"
"strings"
"github.com/go-kit/log"
"github.com/prometheus/statsd_exporter/pkg/level"
)
type mappingState struct {
@ -69,7 +66,7 @@ func NewFSM(metricTypes []string, maxPossibleTransitions int, orderingDisabled b
// AddState adds a mapping rule into the existing FSM.
// The maxPossibleTransitions parameter sets the expected count of transitions left.
// The result parameter sets the generic type to be returned when fsm found a match in GetMapping.
func (f *FSM) AddState(match string, matchMetricType string, maxPossibleTransitions int, result interface{}) int {
func (f *FSM) AddState(match, matchMetricType string, maxPossibleTransitions int, result interface{}) int {
// first split by "."
matchFields := strings.Split(match, ".")
// fill into our FSM
@ -128,7 +125,7 @@ func (f *FSM) AddState(match string, matchMetricType string, maxPossibleTransiti
// GetMapping using the fsm to find matching rules according to given statsdMetric and statsdMetricType.
// If it finds a match, the final state and the captured strings are returned;
// if there's no match found, nil and a empty list will be returned.
func (f *FSM) GetMapping(statsdMetric string, statsdMetricType string) (*mappingState, []string) {
func (f *FSM) GetMapping(statsdMetric, statsdMetricType string) (*mappingState, []string) {
matchFields := strings.Split(statsdMetric, ".")
currentState := f.root.transitions[statsdMetricType]
@ -171,7 +168,8 @@ func (f *FSM) GetMapping(statsdMetric string, statsdMetricType string) (*mapping
if !present || fieldsLeft > altState.maxRemainingLength || fieldsLeft < altState.minRemainingLength {
} else {
// push to backtracking stack
newCursor := fsmBacktrackStackCursor{prev: backtrackCursor, state: altState,
newCursor := fsmBacktrackStackCursor{
prev: backtrackCursor, state: altState,
fieldIndex: i,
captureIndex: captureIdx, currentCapture: field,
}
@ -234,7 +232,7 @@ func (f *FSM) GetMapping(statsdMetric string, statsdMetricType string) (*mapping
// TestIfNeedBacktracking tests if backtrack is needed for given list of mappings
// and whether ordering is disabled.
func TestIfNeedBacktracking(mappings []string, orderingDisabled bool, logger log.Logger) bool {
func TestIfNeedBacktracking(mappings []string, orderingDisabled bool, logger *slog.Logger) bool {
backtrackingNeeded := false
// A has * in rules, but there's other transisitions at the same state,
// this makes A the cause of backtracking
@ -246,11 +244,11 @@ func TestIfNeedBacktracking(mappings []string, orderingDisabled bool, logger log
l := len(strings.Split(mapping, "."))
ruleByLength[l] = append(ruleByLength[l], mapping)
metricRe := strings.Replace(mapping, ".", "\\.", -1)
metricRe = strings.Replace(metricRe, "*", "([^.]*)", -1)
metricRe := strings.ReplaceAll(mapping, ".", "\\.")
metricRe = strings.ReplaceAll(metricRe, "*", "([^.]*)")
regex, err := regexp.Compile("^" + metricRe + "$")
if err != nil {
level.Warn(logger).Log("msg", "Invalid match, cannot compile regex in mapping", "mapping", mapping, "err", err)
logger.Warn("Invalid match, cannot compile regex in mapping", "mapping", mapping, "err", err)
}
// put into array no matter there's error or not, we will skip later if regex is nil
ruleREByLength[l] = append(ruleREByLength[l], regex)
@ -275,8 +273,8 @@ func TestIfNeedBacktracking(mappings []string, orderingDisabled bool, logger log
}
// translate the substring of r1 from 0 to the index of current * into regex
// A.B.C.*.E.* will becomes ^A\.B\.C\. and ^A\.B\.C\.\*\.E\.
reStr := strings.Replace(r1[:index], ".", "\\.", -1)
reStr = strings.Replace(reStr, "*", "\\*", -1)
reStr := strings.ReplaceAll(r1[:index], ".", "\\.")
reStr = strings.ReplaceAll(reStr, "*", "\\*")
re := regexp.MustCompile("^" + reStr)
for i2, r2 := range rules {
if i2 == i1 {
@ -293,7 +291,7 @@ func TestIfNeedBacktracking(mappings []string, orderingDisabled bool, logger log
if i2 != i1 && len(re1.FindStringSubmatchIndex(r2)) > 0 {
// log if we care about ordering and the superset occurs before
if !orderingDisabled && i1 < i2 {
level.Warn(logger).Log("msg", "match is a super set of match but in a lower order, the first will never be matched", "first_match", r1, "second_match", r2)
logger.Warn("match is a super set of match but in a lower order, the first will never be matched", "first_match", r1, "second_match", r2)
}
currentRuleNeedBacktrack = false
}
@ -311,7 +309,7 @@ func TestIfNeedBacktracking(mappings []string, orderingDisabled bool, logger log
}
if currentRuleNeedBacktrack {
level.Warn(logger).Log("msg", "backtracking required because of match. Performance may be degraded", "match", r1)
logger.Warn("backtracking required because of match. Performance may be degraded", "match", r1)
backtrackingNeeded = true
}
}

View file

@ -15,16 +15,16 @@ package mapper
import (
"fmt"
"log/slog"
"os"
"regexp"
"sync"
"time"
"github.com/go-kit/log"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/common/promslog"
"gopkg.in/yaml.v2"
"github.com/prometheus/statsd_exporter/pkg/level"
"github.com/prometheus/statsd_exporter/pkg/mapper/fsm"
)
@ -53,7 +53,7 @@ type MetricMapper struct {
MappingsCount prometheus.Gauge
Logger log.Logger
Logger *slog.Logger
}
type SummaryOptions struct {
@ -174,12 +174,12 @@ func (m *MetricMapper) InitFromYAMLString(fileContents string) error {
if currentMapping.LegacyQuantiles != nil &&
(currentMapping.SummaryOptions == nil || currentMapping.SummaryOptions.Quantiles != nil) {
level.Warn(m.Logger).Log("msg", "using the top level quantiles is deprecated. Please use quantiles in the summary_options hierarchy")
m.Logger.Warn("using the top level quantiles is deprecated. Please use quantiles in the summary_options hierarchy")
}
if currentMapping.LegacyBuckets != nil &&
(currentMapping.HistogramOptions == nil || currentMapping.HistogramOptions.Buckets != nil) {
level.Warn(m.Logger).Log("msg", "using the top level buckets is deprecated. Please use buckets in the histogram_options hierarchy")
m.Logger.Warn("using the top level buckets is deprecated. Please use buckets in the histogram_options hierarchy")
}
if currentMapping.SummaryOptions != nil &&
@ -242,7 +242,7 @@ func (m *MetricMapper) InitFromYAMLString(fileContents string) error {
defer m.mutex.Unlock()
if m.Logger == nil {
m.Logger = log.NewNopLogger()
m.Logger = promslog.NewNopLogger()
}
m.Defaults = n.Defaults

View file

@ -18,7 +18,7 @@ import (
"math/rand"
"testing"
"github.com/go-kit/log"
"github.com/prometheus/common/promslog"
"github.com/prometheus/statsd_exporter/pkg/mappercache/lru"
"github.com/prometheus/statsd_exporter/pkg/mappercache/randomreplacement"
@ -245,7 +245,7 @@ mappings:
}
mapper := MetricMapper{
Logger: log.NewNopLogger(),
Logger: promslog.NewNopLogger(),
}
err := mapper.InitFromYAMLString(config)
if err != nil {

View file

@ -216,7 +216,7 @@ mappings:
},
},
},
//Config with backtracking, the non-matched rule has star(s)
// Config with backtracking, the non-matched rule has star(s)
// A metric like full.name.anothertest will first match full.name.* and then tries
// to match *.dummy.* and then failed.
// This test case makes sure the captures in the non-matched later rule

View file

@ -16,24 +16,22 @@ package relay
import (
"bytes"
"fmt"
"log/slog"
"net"
"strings"
"time"
"github.com/prometheus/statsd_exporter/pkg/clock"
"github.com/go-kit/log"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
"github.com/prometheus/statsd_exporter/pkg/level"
)
type Relay struct {
addr *net.UDPAddr
bufferChannel chan []byte
conn *net.UDPConn
logger log.Logger
logger *slog.Logger
packetLength uint
packetsTotal prometheus.Counter
@ -67,7 +65,7 @@ var (
// NewRelay creates a statsd UDP relay. It can be used to send copies of statsd raw
// lines to a separate service.
func NewRelay(l log.Logger, target string, packetLength uint) (*Relay, error) {
func NewRelay(l *slog.Logger, target string, packetLength uint) (*Relay, error) {
addr, err := net.ResolveUDPAddr("udp", target)
if err != nil {
return nil, fmt.Errorf("unable to resolve target %s, err: %w", target, err)
@ -110,24 +108,24 @@ func (r *Relay) relayOutput() {
case <-relayInterval.C:
err = r.sendPacket(buffer.Bytes())
if err != nil {
level.Error(r.logger).Log("msg", "Error sending UDP packet", "error", err)
r.logger.Error("Error sending UDP packet", "error", err)
return
}
// Clear out the buffer.
buffer.Reset()
case b := <-r.bufferChannel:
if uint(len(b)+buffer.Len()) > r.packetLength {
level.Debug(r.logger).Log("msg", "Buffer full, sending packet", "length", buffer.Len())
r.logger.Debug("Buffer full, sending packet", "length", buffer.Len())
err = r.sendPacket(buffer.Bytes())
if err != nil {
level.Error(r.logger).Log("msg", "Error sending UDP packet", "error", err)
r.logger.Error("Error sending UDP packet", "error", err)
return
}
// Seed the new buffer with the new line.
buffer.Reset()
buffer.Write(b)
} else {
level.Debug(r.logger).Log("msg", "Adding line to buffer", "line", string(b))
r.logger.Debug("Adding line to buffer", "line", string(b))
buffer.Write(b)
}
}
@ -137,10 +135,10 @@ func (r *Relay) relayOutput() {
// sendPacket sends a single relay line to the destination target.
func (r *Relay) sendPacket(buf []byte) error {
if len(buf) == 0 {
level.Debug(r.logger).Log("msg", "Empty buffer, nothing to send")
r.logger.Debug("Empty buffer, nothing to send")
return nil
}
level.Debug(r.logger).Log("msg", "Sending packet", "length", len(buf), "data", string(buf))
r.logger.Debug("Sending packet", "length", len(buf), "data", string(buf))
_, err := r.conn.WriteToUDP(buf, r.addr)
r.packetsTotal.Inc()
return err
@ -150,15 +148,15 @@ func (r *Relay) sendPacket(buf []byte) error {
func (r *Relay) RelayLine(l string) {
lineLength := uint(len(l))
if lineLength == 0 {
level.Debug(r.logger).Log("msg", "Empty line, not relaying")
r.logger.Debug("Empty line, not relaying")
return
}
if lineLength > r.packetLength-1 {
level.Warn(r.logger).Log("msg", "line too long, not relaying", "length", lineLength, "max", r.packetLength)
r.logger.Warn("line too long, not relaying", "length", lineLength, "max", r.packetLength)
r.longLinesTotal.Inc()
return
}
level.Debug(r.logger).Log("msg", "Relaying line", "line", string(l))
r.logger.Debug("Relaying line", "line", string(l))
if !strings.HasSuffix(l, "\n") {
l = l + "\n"
}

View file

@ -19,11 +19,12 @@ import (
"testing"
"time"
"github.com/go-kit/log"
"github.com/prometheus/client_golang/prometheus"
dto "github.com/prometheus/client_model/go"
"github.com/prometheus/statsd_exporter/pkg/clock"
"github.com/prometheus/common/promslog"
"github.com/stvp/go-udp-testing"
"github.com/prometheus/statsd_exporter/pkg/clock"
)
func TestRelay_RelayLine(t *testing.T) {
@ -54,13 +55,12 @@ func TestRelay_RelayLine(t *testing.T) {
}
clock.ClockInstance.Instant = time.Unix(0, 0)
logger := log.NewNopLogger()
logger := promslog.NewNopLogger()
r, err := NewRelay(
logger,
"localhost:1160",
200,
)
if err != nil {
t.Errorf("Did not expect error while creating relay.")
}