Merge remote-tracking branch 'upstream/main' into improve-config-coverage

Signed-off-by: LorenzoDOrtona <dortonalorenzo@gmail.com>

# Conflicts:
#	config/config_test.go
This commit is contained in:
LorenzoDOrtona 2026-06-05 00:54:13 +02:00
commit 052d8c2d84
204 changed files with 16408 additions and 3057 deletions

View file

@ -20,6 +20,8 @@ jobs:
if: (github.repository_owner == 'prometheus' || github.repository_owner == 'prometheus-community') && github.event.pull_request.user.login != 'dependabot[bot]'
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- env:
PR_DESCRIPTION: ${{ github.event.pull_request.body }}
run: |

View file

@ -42,11 +42,25 @@ jobs:
- run: go test --tags=dedupelabels ./...
- run: go test --tags=slicelabels -race ./cmd/prometheus ./model/textparse ./prompb/...
- run: go test --tags=forcedirectio -race ./tsdb/
- run: GOARCH=386 go test ./...
- run: make protoc
- run: make proto
- run: git diff --exit-code
test_go_386:
name: Go tests for 32-bit x86
runs-on: ubuntu-latest
container:
image: quay.io/prometheus/golang-builder:1.26-base
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- uses: prometheus/promci-setup@5af30ba8c199a91d6c04ebdc3c48e630e355f62d # v0.1.0
# NOTE(bwplotka): We limit concurrency to avoid issues around too many concurrent mmaps
# caused by parallel tests. See context: https://github.com/prometheus/prometheus/pull/18709
# Alternatively we could adjust each relevant test to have 386 aware parallelization setting.
- run: GOARCH=386 go test -parallel=1 ./...
test_version_upgrade:
name: Go tests for Prometheus upgrades and downgrades
runs-on: ubuntu-latest
@ -140,7 +154,7 @@ jobs:
container:
# Whenever the Go version is updated here, .promu.yml
# should also be updated.
image: quay.io/prometheus/golang-builder:1.25-base
image: quay.io/prometheus/golang-builder:1.26-base
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
@ -167,10 +181,7 @@ jobs:
matrix:
thread: [ 0, 1, 2 ]
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- uses: prometheus/promci/build@769ee18070cd21cfc2a24fa912349fd3e48dee58 # v0.6.0
- uses: prometheus/promci/build@d9d4f5688814f0b77bf003d07fb8c00507390634 # v0.8.2
with:
promu_opts: "-p linux/amd64 -p windows/amd64 -p linux/arm64 -p darwin/amd64 -p darwin/arm64 -p linux/386"
parallelism: 3
@ -193,10 +204,7 @@ jobs:
# Whenever the Go version is updated here, .promu.yml
# should also be updated.
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- uses: prometheus/promci/build@769ee18070cd21cfc2a24fa912349fd3e48dee58 # v0.6.0
- uses: prometheus/promci/build@d9d4f5688814f0b77bf003d07fb8c00507390634 # v0.8.2
with:
parallelism: 12
thread: ${{ matrix.thread }}
@ -296,37 +304,38 @@ jobs:
publish_main:
name: Publish main branch artifacts
runs-on: ubuntu-latest
permissions:
packages: write
needs: [test_ui, test_go, test_go_more, test_go_oldest, test_windows, golangci, codeql, build_all]
if: github.event_name == 'push' && github.event.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- uses: prometheus/promci/publish_main@769ee18070cd21cfc2a24fa912349fd3e48dee58 # v0.6.0
- uses: prometheus/promci/publish_main@d9d4f5688814f0b77bf003d07fb8c00507390634 # v0.8.2
with:
docker_hub_login: ${{ secrets.docker_hub_login }}
docker_hub_password: ${{ secrets.docker_hub_password }}
ghcr_io_password: ${{ github.token }}
quay_io_login: ${{ secrets.quay_io_login }}
quay_io_password: ${{ secrets.quay_io_password }}
publish_release:
name: Publish release artefacts
runs-on: ubuntu-latest
permissions:
contents: write
packages: write
needs: [test_ui, test_go, test_go_more, test_go_oldest, test_windows, golangci, codeql, build_all]
if: |
(github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v2.'))
||
(github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v3.'))
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- uses: prometheus/promci/publish_release@769ee18070cd21cfc2a24fa912349fd3e48dee58 # v0.6.0
- uses: prometheus/promci/publish_release@d9d4f5688814f0b77bf003d07fb8c00507390634 # v0.8.2
with:
docker_hub_login: ${{ secrets.docker_hub_login }}
docker_hub_password: ${{ secrets.docker_hub_password }}
ghcr_io_password: ${{ github.token }}
quay_io_login: ${{ secrets.quay_io_login }}
quay_io_password: ${{ secrets.quay_io_password }}
github_token: ${{ secrets.PROMBOT_GITHUB_TOKEN }}
github_token: ${{ github.token }}
publish_ui_release:
name: Publish UI on npm Registry
runs-on: ubuntu-latest
@ -337,11 +346,11 @@ jobs:
with:
persist-credentials: false
- name: Install nodejs
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version-file: "web/ui/.nvmrc"
registry-url: "https://registry.npmjs.org"
- uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3
- uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}

View file

@ -28,12 +28,12 @@ jobs:
persist-credentials: false
- name: Initialize CodeQL
uses: github/codeql-action/init@89a39a4e59826350b863aa6b6252a07ad50cf83e # v4.32.4
uses: github/codeql-action/init@7211b7c8077ea37d8641b6271f6a365a22a5fbfa # v4.36.0
with:
languages: ${{ matrix.language }}
- name: Autobuild
uses: github/codeql-action/autobuild@89a39a4e59826350b863aa6b6252a07ad50cf83e # v4.32.4
uses: github/codeql-action/autobuild@7211b7c8077ea37d8641b6271f6a365a22a5fbfa # v4.36.0
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@89a39a4e59826350b863aa6b6252a07ad50cf83e # v4.32.4
uses: github/codeql-action/analyze@7211b7c8077ea37d8641b6271f6a365a22a5fbfa # v4.36.0

View file

@ -27,7 +27,7 @@ jobs:
done
id: fuzz
- name: Upload Crash Artifacts
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
if: failure()
with:
name: fuzz-artifacts-${{ join(matrix.fuzz_test, '-') }}

View file

@ -2,6 +2,9 @@
name: govulncheck
on:
pull_request:
paths:
- VERSION
- .github/workflows/govulncheck.yml
push:
branches:
- main
@ -18,4 +21,6 @@ jobs:
name: Run govulncheck
steps:
- id: govulncheck
uses: golang/govulncheck-action@31f7c5463448f83528bd771c2d978d940080c9fd # v1.0.4-unreleased
uses: golang/govulncheck-action@b625fbe08f3bccbe446d94fbf87fcc875a4f50ee # v1.0.4
env:
GOOS: ${{ contains(github.repository, 'windows_exporter') && 'windows' || '' }}

View file

@ -19,4 +19,6 @@ jobs:
persist-credentials: false
- run: ./scripts/sync_repo_files.sh
env:
GITHUB_TOKEN: ${{ secrets.PROMBOT_GITHUB_TOKEN }}
GITHUB_TOKEN: ${{ secrets.PROMBOT_REPOSYNC_TOKEN }}
GITHUB_TOKEN_PROMETHEUS: ${{ secrets.PROMBOT_REPOSYNC_TOKEN_PROMETHEUS }}
GITHUB_TOKEN_PROMETHEUS_COMMUNITY: ${{ secrets.PROMBOT_REPOSYNC_TOKEN_PROMETHEUS_COMMUNITY }}

View file

@ -37,7 +37,7 @@ jobs:
# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
# format to the repository Actions tab.
- name: "Upload artifact"
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # tag=v6.0.0
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: SARIF file
path: results.sarif
@ -45,6 +45,6 @@ jobs:
# Upload the results to GitHub's code scanning dashboard.
- name: "Upload to code-scanning"
uses: github/codeql-action/upload-sarif@89a39a4e59826350b863aa6b6252a07ad50cf83e # v4.32.4
uses: github/codeql-action/upload-sarif@7211b7c8077ea37d8641b6271f6a365a22a5fbfa # v4.36.0
with:
sarif_file: results.sarif

View file

@ -11,7 +11,7 @@ jobs:
if: github.repository_owner == 'prometheus' || github.repository_owner == 'prometheus-community' # Don't run this workflow on forks.
runs-on: ubuntu-latest
steps:
- uses: actions/stale@b5d41d4e1d5dceea10e7104786b73624c18a190f # v10.2.0
- uses: actions/stale@eb5cf3af3ac0a1aa4c9c45633dd1ae542a27a899 # v10.3.0
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
# opt out of defaults to avoid marking issues as stale and closing them

View file

@ -1,5 +1,74 @@
# Changelog
## 3.12.0 / 2026-05-28
- [SECURITY] Remote-write: Reject snappy-compressed requests whose declared decoded length exceeds the 32MB. Thanks to @hibrian827 for reporting it. #18642
- [SECURITY] STACKIT SD: Fix secrets being exposed in plaintext via `/-/config` endpoint. Thanks to @August829 and @Phaxma for reporting. GHSA-39j6-789q-qxvh #18649
- [CHANGE] TSDB/Agent: Adds Start Timestamp field to all WAL Histogram samples in memory; used `st-storage` flag is enabled. #18221
- [FEATURE] API: Add `/api/v1/status/self_metrics` endpoint returning the current state of the Prometheus server's own metrics about itself as JSON. #18411
- [FEATURE] Discovery: Add DigitalOcean Managed Databases service discovery #18287
- [FEATURE] Prometheus: Add support for the aix/ppc64 compilation target #18321
- [FEATURE] Discovery: Add Outscale VM service discovery (`outscale_sd_configs`) for discovering scrape targets from the Outscale Cloud API. #18139
- [FEATURE] PromQL: Emit a warning when `sort`, `sort_by_label` or `sort_by_label_desc` is used within range (matrix) queries, as these functions do not have effect in that context. #18498
- [FEATURE] PromQL: Add `start()`, `end()`, `range()`, and `step()` experimental functions #17877
- [FEATURE] PromQL: Update `resets()` function to consider start timestamp resets. Hidden behind `use-start-timestamps` feature flag. #18627
- [FEATURE] Prometheus: Promote auto-reload-config as stable #18620
- [FEATURE] TSDB/Agent: Add `CheckpointFromInMemorySeries` option to `agent.DB` that enables checkpoint based on in-memory series. #17948
- [FEATURE] UI: Add a web interface for deleting time series and cleaning tombstones, accessible from the Status menu. #18390
- [FEATURE] PromQL: Use start timestamps for `rate()`, `irate(), and `increase()` calculations, behind a feature flag `use-start-timestamps`. Doesn't work together with extended range selectors `anchored` and `smoothed`. #18344
- [FEATURE] Scrape: Added a feature flag `st-synthesis` which synthesizes unknown STs for scraped cumulative metrics. Useful when Remote Writing 2.0 with delta or Otel-based backends. #18279
- [FEATURE] promqltest: support `@st` annotation in `load` blocks to specify per-sample start timestamps. #18360
- [ENHANCEMENT] API: reject concurrent fgprof profiles. #18651
- [ENHANCEMENT] AWS SD: Add optional `external_id` field to ECS/MSK/RDS/Elasticache. #18579
- [ENHANCEMENT] AWS SD: Add optional `external_id` field. #17171
- [ENHANCEMENT] Discovery: Propagate SD target updates faster by introducing dynamic backoff interval instead of static 5s interval for throttling. #18187
- [ENHANCEMENT] Promtool: Add `--header` flag to `query instant` command, matching existing `query range` behaviour. #18418
- [ENHANCEMENT]: AWS SD: Allows EC2 service discovery to discover IPv6 addresses to communicate with target endpoints. The private IPv4 address remains the default when both IPv4 and IPv6 addresses are present. #16088
- [PERF] TSDB: Make head chunk lookup in range queries constant time instead of quadratic time #18302
- [PERF] TSDB: Skip entire stripes in mmapHeadChunks when no series need mmapping, reducing CPU utilization significantly at production-relevant scales. #18541
- [PERF] TSDB: Skip clean series during periodic head chunk mmap using cached head chunk count #18272
- [PERF] PromQL: Address FloatHistogram.KahanAdd performance regression on Go 1.26. #18568
- [BUGFIX] PromQL: Fix `info()` function incorrectly handling negated `__name__` matchers #17932
- [BUGFIX] API: Return duration expressions in `/parse_ast`. #18624
- [BUGFIX] API: correctly document formats accepted for duration query request parameters (step, timeout and lookback delta) in OpenAPI spec #18305
- [BUGFIX] Scrape: AppenderV2 now tracks staleness even when OOO/duplicate series errors happen similar to AppenderV1 #18567
- [BUGFIX] Config: Validate remote_write queue_config fields at load time to prevent runtime panic and silent misconfiguration. #18209
- [BUGFIX] Discovery/Consul: Add `health_filter` for Health API filtering, fixing breakage when using Catalog-only fields like `ServiceTags` in `filter`. #18479 #18499
- [BUGFIX] OTLP: limit decompressed body size for gzip-encoded OTLP write requests. #18408
- [BUGFIX] PromQL: Fix `smoothed` rate/increase returning zero instead of no result when all data falls strictly after the query range. #18523
- [BUGFIX] PromQL: Fix metric name not being dropped when last_over_time or first_over_time is applied to subqueries containing name-dropping functions like abs(). #18409
- [BUGFIX] PromQL: Fix missing warning when mixing exponential and custom-bucket histograms in stats queries. #18660
- [BUGFIX] PromQL: Fix parsing of `range()` keyword in duration expressions such as `foo[5m+range()]`. #18623
- [BUGFIX] PromQL: Fix smoothed vector selector returning no results in binary operations when the `@` modifier is used. #18531
- [BUGFIX] PromQL: Reject NaN, infinite, and out-of-range duration expressions instead of silently producing an out-of-range time.Duration. #18639
- [BUGFIX] Scrape: Fix panic when scraping malformed native histograms. #18414
- [BUGFIX] Scrape: fix panic when scraping a target exposing a summary with no quantiles via the protobuf format. #18382
- [BUGFIX] Scrape: fix scrape failure log file occasionally not applied after a configuration reload. #18421
- [BUGFIX] TSDB: Allow retention percentage with new data path. #18628
- [BUGFIX] TSDB: Preserve decimal precision in percentage-based retention #18374
- [BUGFIX] TSDB: fix prometheus_tsdb_head_chunks going negative after WAL replay #18401
- [BUGFIX] TSDB: panic with native histograms during query of overlapping chunks. #18692
- [BUGFIX] Tracing: fix startup failure for insecure OTLP HTTP tracing #18469
- [BUGFIX] UI: Escape label values offered by PromQL autocomplete. #18658
- [BUGFIX] UI: Improve Y-axis tick label precision for graph values over small ranges. #18682
- [BUGFIX] `prometheus_sd_refresh*` and `prometheus_sd_discovered_targets` metrics for specific scrape jobs are deleted when the scrape job is removed. #17614
- [BUGFIX] Remote: fixed validation for received RW2 requests when parsing metadata unit symbols. This fixes a case when request would cause (recovered) handler panic. #18641
- [BUGFIX] TSDB/Agent: fix race in agent appender where concurrent appends for the same label set could produce duplicate in-memory series and duplicate WAL records. #18292
- [BUGFIX] Config: Update `--enable-feature` flag description and sort feature names. #18487
## 3.11.3 / 2026-04-27
This release fixes mutiple security issues.
We would like to thank the following people for the responsible disclosures:
- Shadowbyte (4c1dr3aper) - Charlie Lewis for the Remote-Read snappy decode vulnerability.
- Brett Gervasoni for the AzureAD OAuth `client_secret` vulnerability.
- @iiihaiii and @Ngocnn97 for the Old UI XSS vulnerability.
- [SECURITY] AzureAD remote write: Fix OAuth `client_secret` being exposed in plaintext via `/-/config` endpoint. GHSA-wg65-39gg-5wfj / CVE-2026-42151 #18590
- [SECURITY] Remote-read: Reject snappy-compressed requests whose declared decoded length exceeds the decode limit. GHSA-8rm2-7qqf-34qm / CVE-2026-42154 #18584
- [SECURITY] UI: Fix stored XSS via unescaped `le` label values in old UI heatmap chart tick labels. GHSA-fw8g-cg8f-9j28 #18588
## 3.11.2 / 2026-04-13
This release has a fix for a Stored XSS vulnerability that can be triggered via crafted metric names and label values in Prometheus web UI tooltips and metrics explorer. Thanks to Duc Anh Nguyen from TinyxLab for reporting it.

View file

@ -21,7 +21,9 @@ Please see [the v2.55 RELEASE.md](https://github.com/prometheus/prometheus/blob/
| v3.9 | 2025-12-18 | Bryan Boreham (GitHub: @bboreham) |
| v3.10 | 2026-02-05 | Ganesh Vernekar (Github: @codesome) |
| v3.11 | 2026-03-25 | Julien Pivotto (GitHub: @roidelapluie) |
| v3.12 | 2026-05-06 | **volunteer welcome** |
| v3.12 | 2026-05-06 | Bartek Plotka (GitHub: @bwplotka) |
| v3.13 | 2026-06-17 | **volunteer welcome** |
| v3.14 | 2026-07-29 | **volunteer welcome** |
If you are interested in volunteering please create a pull request against the [prometheus/prometheus](https://github.com/prometheus/prometheus) repository and propose yourself for the release series of your choice.

View file

@ -1 +1 @@
3.11.2
3.12.0

View file

@ -252,10 +252,7 @@ func (c *flagConfig) setFeatureListOptions(logger *slog.Logger) error {
logger.Info("Experimental per-step statistics reporting")
case "auto-reload-config":
c.enableAutoReload = true
if s := time.Duration(c.autoReloadInterval).Seconds(); s > 0 && s < 1 {
c.autoReloadInterval, _ = model.ParseDuration("1s")
}
logger.Info("Enabled automatic configuration file reloading. Checking for configuration changes every", "interval", c.autoReloadInterval)
logger.Warn("This option for --enable-feature is deprecated. Use --config.auto-reload instead.", "option", o)
case "concurrent-rule-eval":
c.enableConcurrentRuleEval = true
logger.Info("Experimental concurrent rule evaluation enabled.")
@ -263,7 +260,8 @@ func (c *flagConfig) setFeatureListOptions(logger *slog.Logger) error {
c.parserOpts.EnableExperimentalFunctions = true
logger.Info("Experimental PromQL functions enabled.")
case "promql-duration-expr":
logger.Warn("This option for --enable-feature is now permanently enabled and therefore a no-op.", "option", o)
c.parserOpts.ExperimentalDurationExpr = true
logger.Info("Experimental duration expression parsing enabled.")
case "native-histograms":
logger.Warn("This option for --enable-feature is a no-op. To scrape native histograms, set the scrape_native_histograms scrape config setting to true.", "option", o)
case "ooo-native-histograms":
@ -284,6 +282,11 @@ func (c *flagConfig) setFeatureListOptions(logger *slog.Logger) error {
case "xor2-encoding":
c.tsdb.EnableXOR2Encoding = true
logger.Info("Experimental XOR2 chunk encoding enabled.")
case "st-synthesis":
// TODO(ridwanmsharif): Move this to scrape configuration once stable.
c.scrape.SynthesizeST = true
features.Enable(features.Scrape, "st-synthesis")
logger.Info("Experimental start timestamp synthesis enabled.")
case "st-storage":
c.scrape.ParseST = true
c.tsdb.EnableSTStorage = true
@ -334,6 +337,9 @@ func (c *flagConfig) setFeatureListOptions(logger *slog.Logger) error {
case "fast-startup":
c.tsdb.EnableFastStartup = true
logger.Info("Experimental fast startup is enabled.")
case "search-api":
c.web.EnableSearch = true
logger.Info("Experimental search API enabled.")
default:
logger.Warn("Unknown option for --enable-feature", "option", o)
}
@ -398,7 +404,10 @@ func main() {
a.Flag("config.file", "Prometheus configuration file path.").
Default("prometheus.yml").StringVar(&cfg.configFile)
a.Flag("config.auto-reload-interval", "Specifies the interval for checking and automatically reloading the Prometheus configuration file upon detecting changes.").
a.Flag("config.auto-reload", "Enable automatic configuration file reloading. See also --config.auto-reload-interval.").
Default("false").BoolVar(&cfg.enableAutoReload)
a.Flag("config.auto-reload-interval", "Specifies the interval for checking and automatically reloading the Prometheus configuration file upon detecting changes. Only used when --config.auto-reload is set.").
Default("30s").SetValue(&cfg.autoReloadInterval)
a.Flag("web.listen-address", "Address to listen on for UI, API, and telemetry. Can be repeated.").
@ -577,6 +586,9 @@ func main() {
serverOnlyFlag(a, "storage.remote.read-max-bytes-in-frame", "Maximum number of bytes in a single frame for streaming remote read response types before marshalling. Note that client might have limit on frame size as well. 1MB as recommended by protobuf by default.").
Default("1048576").IntVar(&cfg.web.RemoteReadBytesInFrame)
serverOnlyFlag(a, "web.search.max-limit", "Hard upper bound on the \"limit\" query parameter accepted by the experimental search API (--enable-feature=search-api). Requests with a higher limit are rejected with HTTP 400. 0 disables the cap.").
Default("10000").IntVar(&cfg.web.MaxSearchLimit)
serverOnlyFlag(a, "rules.alert.for-outage-tolerance", "Max time to tolerate prometheus outage for restoring \"for\" state of alert.").
Default("1h").SetValue(&cfg.outageTolerance)
@ -619,7 +631,7 @@ func main() {
a.Flag("scrape.discovery-reload-interval", "Interval used by scrape manager to throttle target groups updates.").
Hidden().Default("5s").SetValue(&cfg.scrape.DiscoveryReloadInterval)
a.Flag("enable-feature", "Comma separated feature names to enable. Valid options: auto-reload-config, concurrent-rule-eval, created-timestamp-zero-ingestion, delayed-compaction, exemplar-storage, extra-scrape-metrics, memory-snapshot-on-shutdown, metadata-wal-records, old-ui, otlp-deltatocumulative, otlp-native-delta-ingestion, promql-binop-fill-modifiers, promql-delayed-name-removal, promql-experimental-functions, promql-extended-range-selectors, promql-per-step-stats, st-storage, type-and-unit-labels, use-start-timestamps, use-uncached-io, xor2-encoding. See https://prometheus.io/docs/prometheus/latest/feature_flags/ for more details.").
a.Flag("enable-feature", "Comma separated feature names to enable. Valid options: concurrent-rule-eval, created-timestamp-zero-ingestion, delayed-compaction, exemplar-storage, extra-scrape-metrics, memory-snapshot-on-shutdown, metadata-wal-records, old-ui, otlp-deltatocumulative, otlp-native-delta-ingestion, promql-binop-fill-modifiers, promql-delayed-name-removal, promql-duration-expr, promql-experimental-functions, promql-extended-range-selectors, promql-per-step-stats, search-api, st-storage, st-synthesis, type-and-unit-labels, use-start-timestamps, use-uncached-io, xor2-encoding. See https://prometheus.io/docs/prometheus/latest/feature_flags/ for more details.").
StringsVar(&cfg.featureList)
a.Flag("agent", "Run Prometheus in 'Agent mode'.").BoolVar(&agentMode)
@ -655,6 +667,18 @@ func main() {
os.Exit(1)
}
if cfg.enableAutoReload {
if s := time.Duration(cfg.autoReloadInterval).Seconds(); s < 1 {
cfg.autoReloadInterval, _ = model.ParseDuration("1s")
}
logger.Info("Automatic configuration file reloading enabled", "interval", cfg.autoReloadInterval)
}
if cfg.web.MaxSearchLimit < 0 {
fmt.Fprintf(os.Stderr, "--web.search.max-limit must be non-negative; got %d (use 0 to disable the cap)\n", cfg.web.MaxSearchLimit)
os.Exit(1)
}
promqlParser := parser.NewParser(cfg.parserOpts)
if agentMode && len(serverOnlyFlags) > 0 {
@ -817,7 +841,7 @@ func main() {
if cfg.tsdb.MaxBytes > 0 {
logger.Warn("storage.tsdb.retention.size is ignored, because storage.tsdb.retention.percentage is specified")
}
if prom_runtime.FsSize(localStoragePath) == 0 {
if storagePathFsSize(localStoragePath) == 0 {
fmt.Fprintln(os.Stderr, fmt.Errorf("unable to detect total capacity of metric storage at %s, please disable retention percentage (%g%%)", localStoragePath, cfg.tsdb.MaxPercentage))
os.Exit(2)
}
@ -1749,6 +1773,25 @@ func computeExternalURL(u, listenAddr string) (*url.URL, error) {
return eu, nil
}
// storagePathFsSize returns the filesystem size for path or its closest existing parent.
func storagePathFsSize(path string) uint64 {
for {
if size := prom_runtime.FsSize(path); size > 0 {
return size
}
if _, err := os.Stat(path); !errors.Is(err, os.ErrNotExist) {
return 0
}
parent := filepath.Dir(path)
if parent == path {
return 0
}
path = parent
}
}
// readyStorage implements the Storage interface while allowing to set the actual
// storage at a later point in time.
type readyStorage struct {

View file

@ -148,6 +148,47 @@ func TestFailedStartupExitCode(t *testing.T) {
require.Equal(t, expectedExitStatus, status.ExitStatus())
}
func TestRetentionPercentageStartsWithMissingStoragePath(t *testing.T) {
if testing.Short() {
t.Skip("skipping test in short mode.")
}
t.Parallel()
tmpDir := t.TempDir()
if storagePathFsSize(tmpDir) == 0 {
t.Skip("skipping test because filesystem size detection is unavailable.")
}
configFile := filepath.Join(tmpDir, "prometheus.yml")
storagePath := filepath.Join(tmpDir, "missing", "data")
require.NoError(t, os.WriteFile(configFile, []byte(`
storage:
tsdb:
retention:
percentage: 1.5
`), 0o777))
port := testutil.RandomUnprivilegedPort(t)
prom := prometheusCommandWithLogging(
t,
configFile,
port,
"--storage.tsdb.path="+storagePath,
)
require.NoError(t, prom.Start())
require.Eventually(t, func() bool {
r, err := http.Get(fmt.Sprintf("http://127.0.0.1:%d/metrics", port))
if err != nil {
return false
}
defer r.Body.Close()
return r.StatusCode == http.StatusOK
}, startupTime, 100*time.Millisecond)
require.DirExists(t, storagePath)
}
type senderFunc func(alerts ...*notifier.Alert)
func (s senderFunc) Send(alerts ...*notifier.Alert) {

View file

@ -119,7 +119,7 @@ func runTestSteps(t *testing.T, steps []struct {
require.NoError(t, os.WriteFile(configFilePath, []byte(steps[0].configText), 0o644), "Failed to write initial config file")
port := testutil.RandomUnprivilegedPort(t)
prom := prometheusCommandWithLogging(t, configFilePath, port, "--enable-feature=auto-reload-config", "--config.auto-reload-interval=1s")
prom := prometheusCommandWithLogging(t, configFilePath, port, "--config.auto-reload", "--config.auto-reload-interval=1s")
require.NoError(t, prom.Start())
baseURL := "http://localhost:" + strconv.Itoa(port)

View file

@ -10,6 +10,9 @@
"query_stats": true,
"query_warnings": true,
"remote_write_receiver": false,
"search": false,
"search_fuzz_alg_jarowinkler": true,
"search_fuzz_alg_subsequence": true,
"time_range_labels": true,
"time_range_series": true
},
@ -29,7 +32,7 @@
"bool": true,
"by": true,
"delayed_name_removal": false,
"duration_expr": true,
"duration_expr": false,
"fill": false,
"fill_left": false,
"fill_right": false,
@ -97,7 +100,9 @@
"log10": true,
"log2": true,
"mad_over_time": false,
"max_of": false,
"max_over_time": true,
"min_of": false,
"min_over_time": true,
"minute": true,
"month": true,

View file

@ -320,7 +320,7 @@ func main() {
promQLLabelsDeleteQuery := promQLLabelsDeleteCmd.Arg("query", "PromQL query.").Required().String()
promQLLabelsDeleteName := promQLLabelsDeleteCmd.Arg("name", "Name of the label to delete.").Required().String()
featureList := app.Flag("enable-feature", "Comma separated feature names to enable. Valid options: promql-experimental-functions, promql-delayed-name-removal, promql-extended-range-selectors. See https://prometheus.io/docs/prometheus/latest/feature_flags/ for more details").Default("").Strings()
featureList := app.Flag("enable-feature", "Comma separated feature names to enable. Valid options: promql-experimental-functions, promql-delayed-name-removal, promql-duration-expr, promql-extended-range-selectors. See https://prometheus.io/docs/prometheus/latest/feature_flags/ for more details").Default("").Strings()
documentationCmd := app.Command("write-documentation", "Generate command line documentation. Internal use.").Hidden()
@ -358,7 +358,7 @@ func main() {
case "promql-delayed-name-removal":
promqlEnableDelayedNameRemoval = true
case "promql-duration-expr":
fmt.Printf(" WARNING: promql-duration-expr is now permanently enabled and therefore a no-op")
promtoolParserOpts.ExperimentalDurationExpr = true
case "promql-extended-range-selectors":
promtoolParserOpts.EnableExtendedRangeSelectors = true
case "":

View file

@ -55,12 +55,14 @@ func TestSDCheckResult(t *testing.T) {
{
DiscoveredLabels: labels.FromStrings(
"__address__", "localhost:8080",
"__convert_classic_histograms_to_nhcb__", "false",
"__scrape_interval__", "1m",
"__scrape_timeout__", "10s",
"foo", "bar",
),
Labels: labels.FromStrings(
"__address__", "localhost:8080",
"__convert_classic_histograms_to_nhcb__", "false",
"__scrape_interval__", "1m",
"__scrape_timeout__", "10s",
"foo", "bar",

View file

@ -10,18 +10,18 @@ require (
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/snappy v1.0.0 // indirect
github.com/grafana/regexp v0.0.0-20250905093917-f7b3be9d1853 // indirect
github.com/klauspost/compress v1.18.5 // indirect
github.com/klauspost/compress v1.18.6 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/oklog/run v1.2.0 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/prometheus/client_golang/exp v0.0.0-20260325093428-d8591d0db856 // indirect
github.com/prometheus/client_golang/exp v0.0.0-20260518105423-c9d5bc4c50a9 // indirect
github.com/prometheus/client_model v0.6.2 // indirect
github.com/prometheus/common v0.67.5 // indirect
github.com/prometheus/prometheus v0.307.4-0.20251119130332-1174b0ce4f1f // indirect
github.com/rogpeppe/go-internal v1.14.1 // indirect
github.com/stretchr/testify v1.11.1 // indirect
go.yaml.in/yaml/v2 v2.4.4 // indirect
golang.org/x/text v0.35.0 // indirect
golang.org/x/text v0.37.0 // indirect
google.golang.org/protobuf v1.36.11 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

View file

@ -13,8 +13,8 @@ github.com/grafana/regexp v0.0.0-20250905093917-f7b3be9d1853 h1:cLN4IBkmkYZNnk7E
github.com/grafana/regexp v0.0.0-20250905093917-f7b3be9d1853/go.mod h1:+JKpmjMGhpgPL+rXZ5nsZieVzvarn86asRlBg4uNGnk=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.18.5 h1:/h1gH5Ce+VWNLSWqPzOVn6XBO+vJbCNGvjoaGBFW2IE=
github.com/klauspost/compress v1.18.5/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ=
github.com/klauspost/compress v1.18.6 h1:2jupLlAwFm95+YDR+NwD2MEfFO9d4z4Prjl1XXDjuao=
github.com/klauspost/compress v1.18.6/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ=
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=
@ -23,8 +23,8 @@ github.com/oklog/run v1.2.0 h1:O8x3yXwah4A73hJdlrwo/2X6J62gE5qTMusH0dvz60E=
github.com/oklog/run v1.2.0/go.mod h1:mgDbKRSwPhJfesJ4PntqFUbKQRZ50NgmZTSPlFA0YFk=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang/exp v0.0.0-20260325093428-d8591d0db856 h1:1Y6bmpZb8peQCy1IpctnAhIFuyhrdtMaDnETChhSNns=
github.com/prometheus/client_golang/exp v0.0.0-20260325093428-d8591d0db856/go.mod h1:Vf0QcmVhGqpjLxZOaWrFSep86vchQtJmbztFaMM4f6Q=
github.com/prometheus/client_golang/exp v0.0.0-20260518105423-c9d5bc4c50a9 h1:e33IfrrwrJkylWwAGcQ2jMvbWVv13lv0suTXjGNeiqY=
github.com/prometheus/client_golang/exp v0.0.0-20260518105423-c9d5bc4c50a9/go.mod h1:vW/EVguzbNw6xMRmozJQWbY60/+Zsg0TgVJOSXGx2iI=
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.67.5 h1:pIgK94WWlQt1WLwAC5j2ynLaBRDiinoAb86HZHTUGI4=
@ -58,8 +58,8 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8=
golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA=
golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc=
golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=

View file

@ -1512,6 +1512,10 @@ func (c *RemoteWriteConfig) UnmarshalYAML(unmarshal func(any) error) error {
return err
}
if err := c.QueueConfig.Validate(); err != nil {
return err
}
return validateAuthConfigs(c)
}
@ -1604,6 +1608,29 @@ type QueueConfig struct {
SampleAgeLimit model.Duration `yaml:"sample_age_limit,omitempty"`
}
// Validate checks QueueConfig fields for invalid values.
func (c *QueueConfig) Validate() error {
if c.MaxShards <= 0 {
return errors.New("remote write queue max_shards must be positive")
}
if c.MinShards <= 0 {
return errors.New("remote write queue min_shards must be positive")
}
if c.MinShards > c.MaxShards {
return errors.New("remote write queue min_shards must not be greater than max_shards")
}
if c.MaxSamplesPerSend <= 0 {
return errors.New("remote write queue max_samples_per_send must be positive")
}
if c.Capacity <= 0 {
return errors.New("remote write queue capacity must be positive")
}
if c.MaxBackoff < c.MinBackoff {
return errors.New("remote write queue max_backoff must not be less than min_backoff")
}
return nil
}
// MetadataConfig is the configuration for sending metadata to remote
// storage.
type MetadataConfig struct {

View file

@ -1579,8 +1579,10 @@ var expectedConf = &Config{
HTTPClientConfig: config.DefaultHTTPClientConfig,
ServiceDiscoveryConfigs: discovery.Configs{
&stackit.SDConfig{
Project: "11111111-1111-1111-1111-111111111111",
Region: "eu01",
Project: "11111111-1111-1111-1111-111111111111",
ServiceAccountKey: "mysecret_sa_key",
PrivateKey: "mysecret_private_key",
Region: "eu01",
HTTPClientConfig: config.HTTPClientConfig{
Authorization: &config.Authorization{
Type: "Bearer",
@ -2157,7 +2159,7 @@ func TestElideSecrets(t *testing.T) {
yamlConfig := string(config)
matches := secretRe.FindAllStringIndex(yamlConfig, -1)
require.Len(t, matches, 26, "wrong number of secret matches found")
require.Len(t, matches, 28, "wrong number of secret matches found")
require.NotContains(t, yamlConfig, "mysecret",
"yaml marshal reveals authentication credentials.")
}
@ -2460,6 +2462,30 @@ var expectedErrors = []struct {
filename: "remote_write_auth_exclusive.bad.yml",
errMsg: "at most one of basic_auth, authorization, oauth2, sigv4, azuread or google_iam must be configured",
},
{
filename: "remote_write_queue_max_samples_per_send_zero.bad.yml",
errMsg: `remote write queue max_samples_per_send must be positive`,
},
{
filename: "remote_write_queue_max_shards_zero.bad.yml",
errMsg: `remote write queue max_shards must be positive`,
},
{
filename: "remote_write_queue_min_shards_zero.bad.yml",
errMsg: `remote write queue min_shards must be positive`,
},
{
filename: "remote_write_queue_capacity_zero.bad.yml",
errMsg: `remote write queue capacity must be positive`,
},
{
filename: "remote_write_queue_min_shards_greater_than_max.bad.yml",
errMsg: `remote write queue min_shards must not be greater than max_shards`,
},
{
filename: "remote_write_queue_max_backoff_less_than_min.bad.yml",
errMsg: `remote write queue max_backoff must not be less than min_backoff`,
},
{
filename: "remote_read_dup.bad.yml",
errMsg: `found multiple remote read configs with job name "queue1"`,

View file

@ -422,6 +422,8 @@ scrape_configs:
- job_name: stackit-servers
stackit_sd_configs:
- project: 11111111-1111-1111-1111-111111111111
service_account_key: mysecret_sa_key
private_key: mysecret_private_key
authorization:
credentials: abcdef

View file

@ -0,0 +1,4 @@
remote_write:
- url: http://localhost:9090/api/v1/write
queue_config:
capacity: 0

View file

@ -0,0 +1,5 @@
remote_write:
- url: http://localhost:9090/api/v1/write
queue_config:
min_backoff: 10s
max_backoff: 1s

View file

@ -0,0 +1,4 @@
remote_write:
- url: http://localhost:9090/api/v1/write
queue_config:
max_samples_per_send: 0

View file

@ -0,0 +1,4 @@
remote_write:
- url: http://localhost:9090/api/v1/write
queue_config:
max_shards: 0

View file

@ -0,0 +1,5 @@
remote_write:
- url: http://localhost:9090/api/v1/write
queue_config:
min_shards: 100
max_shards: 10

View file

@ -0,0 +1,4 @@
remote_write:
- url: http://localhost:9090/api/v1/write
queue_config:
min_shards: 0

View file

@ -30,6 +30,7 @@ import (
)
func TestRoleUnmarshalYAML(t *testing.T) {
t.Parallel()
tests := []struct {
name string
input string
@ -84,6 +85,7 @@ func TestRoleUnmarshalYAML(t *testing.T) {
}
func TestRoleString(t *testing.T) {
t.Parallel()
tests := []struct {
name string
role Role
@ -114,16 +116,19 @@ func TestRoleString(t *testing.T) {
}
func TestSDConfigName(t *testing.T) {
t.Parallel()
cfg := &SDConfig{}
require.Equal(t, "aws", cfg.Name())
}
func TestDefaultSDConfig(t *testing.T) {
t.Parallel()
require.Equal(t, Role(""), DefaultSDConfig.Role)
require.Equal(t, model.Duration(60*time.Second), DefaultSDConfig.RefreshInterval)
}
func TestSDConfigUnmarshalYAML(t *testing.T) {
t.Parallel()
tests := []struct {
name string
yaml string
@ -189,6 +194,7 @@ port: 9300`,
// all configs pointed to the same global default, causing port and other
// settings from one job to overwrite settings in another job.
func TestMultipleSDConfigsDoNotShareState(t *testing.T) {
t.Parallel()
tests := []struct {
name string
yaml string
@ -489,6 +495,7 @@ region = ` + randomRegion + `
}
func TestSDConfigSetDirectory(t *testing.T) {
t.Parallel()
tmpDir := t.TempDir()
tests := []struct {
name string

View file

@ -55,6 +55,7 @@ const (
ec2LabelInstanceType = ec2Label + "instance_type"
ec2LabelOwnerID = ec2Label + "owner_id"
ec2LabelPlatform = ec2Label + "platform"
ec2LabelDefaultIPv6Address = ec2Label + "default_ipv6_address"
ec2LabelPrimaryIPv6Addresses = ec2Label + "primary_ipv6_addresses"
ec2LabelPrimarySubnetID = ec2Label + "primary_subnet_id"
ec2LabelPrivateDNS = ec2Label + "private_dns_name"
@ -149,6 +150,47 @@ type ec2Client interface {
DescribeInstances(ctx context.Context, params *ec2.DescribeInstancesInput, optFns ...func(*ec2.Options)) (*ec2.DescribeInstancesOutput, error)
}
// ec2ClientAdapter holds the EC2 API calls that AWS discovery actually uses as
// method-value closures over the concrete *ec2.Client.
//
// It exists purely to keep the binary small. The Go linker, once reflection
// (reflect.Value.Method/Call plus struct-field traversal, both reachable via
// the YAML/config machinery) is live, conservatively retains every exported
// method of any concrete type that is reachable through an interface — and a
// type stored as a field of an interface-boxed struct counts. *ec2.Client has
// ~470 operation methods; retaining all of them pulls in ~1,500 serializers and
// roughly 21 MB. By capturing only the needed methods as func values, the
// concrete *ec2.Client is hidden inside closure contexts (which reflection
// cannot traverse) and never appears as a field of a boxed type, so dead-code
// elimination drops the unused operations.
type ec2ClientAdapter struct {
describeAvailabilityZones func(ctx context.Context, params *ec2.DescribeAvailabilityZonesInput, optFns ...func(*ec2.Options)) (*ec2.DescribeAvailabilityZonesOutput, error)
describeInstances func(ctx context.Context, params *ec2.DescribeInstancesInput, optFns ...func(*ec2.Options)) (*ec2.DescribeInstancesOutput, error)
describeNetworkInterfaces func(ctx context.Context, params *ec2.DescribeNetworkInterfacesInput, optFns ...func(*ec2.Options)) (*ec2.DescribeNetworkInterfacesOutput, error)
}
// newEC2ClientAdapter wraps a concrete *ec2.Client, capturing only the API
// calls AWS discovery needs. See the ec2ClientAdapter doc comment for why.
func newEC2ClientAdapter(c *ec2.Client) ec2ClientAdapter {
return ec2ClientAdapter{
describeAvailabilityZones: c.DescribeAvailabilityZones,
describeInstances: c.DescribeInstances,
describeNetworkInterfaces: c.DescribeNetworkInterfaces,
}
}
func (a ec2ClientAdapter) DescribeAvailabilityZones(ctx context.Context, params *ec2.DescribeAvailabilityZonesInput, optFns ...func(*ec2.Options)) (*ec2.DescribeAvailabilityZonesOutput, error) {
return a.describeAvailabilityZones(ctx, params, optFns...)
}
func (a ec2ClientAdapter) DescribeInstances(ctx context.Context, params *ec2.DescribeInstancesInput, optFns ...func(*ec2.Options)) (*ec2.DescribeInstancesOutput, error) {
return a.describeInstances(ctx, params, optFns...)
}
func (a ec2ClientAdapter) DescribeNetworkInterfaces(ctx context.Context, params *ec2.DescribeNetworkInterfacesInput, optFns ...func(*ec2.Options)) (*ec2.DescribeNetworkInterfacesOutput, error) {
return a.describeNetworkInterfaces(ctx, params, optFns...)
}
// EC2Discovery periodically performs EC2-SD requests. It implements
// the Discoverer interface.
type EC2Discovery struct {
@ -234,12 +276,12 @@ func (d *EC2Discovery) ec2Client(ctx context.Context) (ec2Client, error) {
cfg.Credentials = aws.NewCredentialsCache(assumeProvider)
}
d.ec2 = ec2.NewFromConfig(cfg, func(options *ec2.Options) {
d.ec2 = newEC2ClientAdapter(ec2.NewFromConfig(cfg, func(options *ec2.Options) {
if d.cfg.Endpoint != "" {
options.BaseEndpoint = &d.cfg.Endpoint
}
options.HTTPClient = httpClient
})
}))
return d.ec2, nil
}
@ -306,7 +348,9 @@ func (d *EC2Discovery) refresh(ctx context.Context) ([]*targetgroup.Group, error
for _, r := range p.Reservations {
for _, inst := range r.Instances {
if inst.PrivateIpAddress == nil {
defaultIPv6Addr, primaryIPv6Addrs, ipv6Addrs := getInstanceIPv6Addresses(&inst)
if inst.PrivateIpAddress == nil && defaultIPv6Addr == nil {
continue
}
@ -319,12 +363,20 @@ func (d *EC2Discovery) refresh(ctx context.Context) ([]*targetgroup.Group, error
labels[ec2LabelOwnerID] = model.LabelValue(*r.OwnerId)
}
labels[ec2LabelPrivateIP] = model.LabelValue(*inst.PrivateIpAddress)
if defaultIPv6Addr != nil {
labels[ec2LabelDefaultIPv6Address] = model.LabelValue(*defaultIPv6Addr)
}
if inst.PrivateIpAddress != nil {
labels[ec2LabelPrivateIP] = model.LabelValue(*inst.PrivateIpAddress)
labels[model.AddressLabel] = model.LabelValue(net.JoinHostPort(*inst.PrivateIpAddress, strconv.Itoa(d.cfg.Port)))
} else {
labels[model.AddressLabel] = model.LabelValue(net.JoinHostPort(*defaultIPv6Addr, strconv.Itoa(d.cfg.Port)))
}
if inst.PrivateDnsName != nil {
labels[ec2LabelPrivateDNS] = model.LabelValue(*inst.PrivateDnsName)
}
addr := net.JoinHostPort(*inst.PrivateIpAddress, strconv.Itoa(d.cfg.Port))
labels[model.AddressLabel] = model.LabelValue(addr)
if inst.Platform != "" {
labels[ec2LabelPlatform] = model.LabelValue(inst.Platform)
@ -334,6 +386,21 @@ func (d *EC2Discovery) refresh(ctx context.Context) ([]*targetgroup.Group, error
labels[ec2LabelPublicIP] = model.LabelValue(*inst.PublicIpAddress)
labels[ec2LabelPublicDNS] = model.LabelValue(*inst.PublicDnsName)
}
if primaryIPv6Addrs != nil {
labels[ec2LabelPrimaryIPv6Addresses] = model.LabelValue(
ec2LabelSeparator +
strings.Join(primaryIPv6Addrs, ec2LabelSeparator) +
ec2LabelSeparator)
}
if ipv6Addrs != nil {
labels[ec2LabelIPv6Addresses] = model.LabelValue(
ec2LabelSeparator +
strings.Join(ipv6Addrs, ec2LabelSeparator) +
ec2LabelSeparator)
}
labels[ec2LabelAMI] = model.LabelValue(*inst.ImageId)
labels[ec2LabelAZ] = model.LabelValue(*inst.Placement.AvailabilityZone)
azID, ok := d.azToAZID[*inst.Placement.AvailabilityZone]
@ -359,8 +426,6 @@ func (d *EC2Discovery) refresh(ctx context.Context) ([]*targetgroup.Group, error
labels[ec2LabelPrimarySubnetID] = model.LabelValue(*inst.SubnetId)
var subnets []string
var ipv6addrs []string
var primaryipv6addrs []string
subnetsMap := make(map[string]struct{})
for _, eni := range inst.NetworkInterfaces {
if eni.SubnetId == nil {
@ -371,36 +436,11 @@ func (d *EC2Discovery) refresh(ctx context.Context) ([]*targetgroup.Group, error
subnetsMap[*eni.SubnetId] = struct{}{}
subnets = append(subnets, *eni.SubnetId)
}
for _, ipv6addr := range eni.Ipv6Addresses {
ipv6addrs = append(ipv6addrs, *ipv6addr.Ipv6Address)
if *ipv6addr.IsPrimaryIpv6 {
// we might have to extend the slice with more than one element
// that could leave empty strings in the list which is intentional
// to keep the position/device index information
for int32(len(primaryipv6addrs)) <= *eni.Attachment.DeviceIndex {
primaryipv6addrs = append(primaryipv6addrs, "")
}
primaryipv6addrs[*eni.Attachment.DeviceIndex] = *ipv6addr.Ipv6Address
}
}
}
labels[ec2LabelSubnetID] = model.LabelValue(
ec2LabelSeparator +
strings.Join(subnets, ec2LabelSeparator) +
ec2LabelSeparator)
if len(ipv6addrs) > 0 {
labels[ec2LabelIPv6Addresses] = model.LabelValue(
ec2LabelSeparator +
strings.Join(ipv6addrs, ec2LabelSeparator) +
ec2LabelSeparator)
}
if len(primaryipv6addrs) > 0 {
labels[ec2LabelPrimaryIPv6Addresses] = model.LabelValue(
ec2LabelSeparator +
strings.Join(primaryipv6addrs, ec2LabelSeparator) +
ec2LabelSeparator)
}
}
for _, t := range inst.Tags {
@ -417,3 +457,39 @@ func (d *EC2Discovery) refresh(ctx context.Context) ([]*targetgroup.Group, error
return []*targetgroup.Group{tg}, nil
}
func getInstanceIPv6Addresses(i *ec2Types.Instance) (*string, []string, []string) {
var primaryIPv6Addrs []string
var ipv6Addrs []string
if i.VpcId != nil {
for _, eni := range i.NetworkInterfaces {
if eni.SubnetId == nil {
continue
}
for _, ipv6addr := range eni.Ipv6Addresses {
ipv6Addrs = append(ipv6Addrs, *ipv6addr.Ipv6Address)
if *ipv6addr.IsPrimaryIpv6 {
// we might have to extend the slice with more than one element
// that could leave empty strings in the list which is intentional
// to keep the position/device index information
for int32(len(primaryIPv6Addrs)) <= *eni.Attachment.DeviceIndex {
primaryIPv6Addrs = append(primaryIPv6Addrs, "")
}
primaryIPv6Addrs[*eni.Attachment.DeviceIndex] = *ipv6addr.Ipv6Address
}
}
}
// Find an IPv6 address we can use by default. Pick the first primary one if
// there is any available, if not then pick the first non-primary address.
for _, ipv6addr := range append(primaryIPv6Addrs, ipv6Addrs...) {
if ipv6addr != "" {
return &ipv6addr, primaryIPv6Addrs, ipv6Addrs
}
}
}
return nil, primaryIPv6Addrs, ipv6Addrs
}

View file

@ -55,6 +55,7 @@ func TestMain(m *testing.M) {
}
func TestEC2DiscoveryRefreshAZIDs(t *testing.T) {
t.Parallel()
ctx := context.Background()
// iterate through the test cases
@ -99,6 +100,7 @@ func TestEC2DiscoveryRefreshAZIDs(t *testing.T) {
}
func TestEC2DiscoveryRefresh(t *testing.T) {
t.Parallel()
ctx := context.Background()
// iterate through the test cases
@ -108,7 +110,7 @@ func TestEC2DiscoveryRefresh(t *testing.T) {
expected []*targetgroup.Group
}{
{
name: "NoPrivateIp",
name: "NoPrivateIpOrIpv6",
ec2Data: &ec2DataStore{
region: "region-noprivateip",
azToAZID: map[string]string{
@ -351,6 +353,7 @@ func TestEC2DiscoveryRefresh(t *testing.T) {
"__meta_ec2_instance_type": model.LabelValue("instance-type-ipv6"),
"__meta_ec2_ipv6_addresses": model.LabelValue(",2001:db8:2::1:1,2001:db8:2::2:1,2001:db8:2::2:2,2001:db8:2::3:1,"),
"__meta_ec2_owner_id": model.LabelValue(""),
"__meta_ec2_default_ipv6_address": model.LabelValue("2001:db8:2::2:2"),
"__meta_ec2_primary_ipv6_addresses": model.LabelValue(",,2001:db8:2::2:2,,2001:db8:2::3:1,"),
"__meta_ec2_primary_subnet_id": model.LabelValue("azid-2"),
"__meta_ec2_private_ip": model.LabelValue("9.10.11.12"),
@ -362,6 +365,69 @@ func TestEC2DiscoveryRefresh(t *testing.T) {
},
},
},
{
name: "Ipv6-Only",
ec2Data: &ec2DataStore{
region: "region-ipv6-only",
azToAZID: map[string]string{
"azname-a": "azid-1",
"azname-b": "azid-2",
"azname-c": "azid-3",
},
instances: []ec2Types.Instance{
{
// just the minimum needed for the refresh work
ImageId: strptr("ami-ipv6-only"),
InstanceId: strptr("instance-id-ipv6-only"),
InstanceType: "instance-type-ipv6-only",
Placement: &ec2Types.Placement{AvailabilityZone: strptr("azname-b")},
State: &ec2Types.InstanceState{Name: "running"},
SubnetId: strptr("azid-2"),
VpcId: strptr("vpc-ipv6-only"),
// network interfaces
NetworkInterfaces: []ec2Types.InstanceNetworkInterface{
// interface without primary IPv6, index 0
{
Attachment: &ec2Types.InstanceNetworkInterfaceAttachment{
DeviceIndex: aws.Int32(0),
},
Ipv6Addresses: []ec2Types.InstanceIpv6Address{
{
Ipv6Address: strptr("2001:db8:2::1:1"),
IsPrimaryIpv6: boolptr(false),
},
},
SubnetId: strptr("azid-2"),
},
},
},
},
},
expected: []*targetgroup.Group{
{
Source: "region-ipv6-only",
Targets: []model.LabelSet{
{
"__address__": model.LabelValue("[2001:db8:2::1:1]:4242"),
"__meta_ec2_ami": model.LabelValue("ami-ipv6-only"),
"__meta_ec2_availability_zone": model.LabelValue("azname-b"),
"__meta_ec2_availability_zone_id": model.LabelValue("azid-2"),
"__meta_ec2_instance_id": model.LabelValue("instance-id-ipv6-only"),
"__meta_ec2_instance_state": model.LabelValue("running"),
"__meta_ec2_instance_type": model.LabelValue("instance-type-ipv6-only"),
"__meta_ec2_ipv6_addresses": model.LabelValue(",2001:db8:2::1:1,"),
"__meta_ec2_owner_id": model.LabelValue(""),
"__meta_ec2_default_ipv6_address": model.LabelValue("2001:db8:2::1:1"),
"__meta_ec2_primary_subnet_id": model.LabelValue("azid-2"),
"__meta_ec2_region": model.LabelValue("region-ipv6-only"),
"__meta_ec2_subnet_id": model.LabelValue(",azid-2,"),
"__meta_ec2_vpc_id": model.LabelValue("vpc-ipv6-only"),
},
},
},
},
},
} {
t.Run(tt.name, func(t *testing.T) {
client := newMockEC2Client(tt.ec2Data)

View file

@ -162,6 +162,60 @@ type ecsClient interface {
DescribeContainerInstances(context.Context, *ecs.DescribeContainerInstancesInput, ...func(*ecs.Options)) (*ecs.DescribeContainerInstancesOutput, error)
}
// ecsClientAdapter captures only the ECS API calls AWS discovery uses as
// method-value closures, keeping the concrete *ecs.Client out of any
// interface-boxed struct field. See ec2ClientAdapter for the full rationale:
// this stops the linker from retaining the entire ECS API surface (~2 MB).
type ecsClientAdapter struct {
listClusters func(context.Context, *ecs.ListClustersInput, ...func(*ecs.Options)) (*ecs.ListClustersOutput, error)
describeClusters func(context.Context, *ecs.DescribeClustersInput, ...func(*ecs.Options)) (*ecs.DescribeClustersOutput, error)
listServices func(context.Context, *ecs.ListServicesInput, ...func(*ecs.Options)) (*ecs.ListServicesOutput, error)
describeServices func(context.Context, *ecs.DescribeServicesInput, ...func(*ecs.Options)) (*ecs.DescribeServicesOutput, error)
listTasks func(context.Context, *ecs.ListTasksInput, ...func(*ecs.Options)) (*ecs.ListTasksOutput, error)
describeTasks func(context.Context, *ecs.DescribeTasksInput, ...func(*ecs.Options)) (*ecs.DescribeTasksOutput, error)
describeContainerInstances func(context.Context, *ecs.DescribeContainerInstancesInput, ...func(*ecs.Options)) (*ecs.DescribeContainerInstancesOutput, error)
}
func newECSClientAdapter(c *ecs.Client) ecsClientAdapter {
return ecsClientAdapter{
listClusters: c.ListClusters,
describeClusters: c.DescribeClusters,
listServices: c.ListServices,
describeServices: c.DescribeServices,
listTasks: c.ListTasks,
describeTasks: c.DescribeTasks,
describeContainerInstances: c.DescribeContainerInstances,
}
}
func (a ecsClientAdapter) ListClusters(ctx context.Context, params *ecs.ListClustersInput, optFns ...func(*ecs.Options)) (*ecs.ListClustersOutput, error) {
return a.listClusters(ctx, params, optFns...)
}
func (a ecsClientAdapter) DescribeClusters(ctx context.Context, params *ecs.DescribeClustersInput, optFns ...func(*ecs.Options)) (*ecs.DescribeClustersOutput, error) {
return a.describeClusters(ctx, params, optFns...)
}
func (a ecsClientAdapter) ListServices(ctx context.Context, params *ecs.ListServicesInput, optFns ...func(*ecs.Options)) (*ecs.ListServicesOutput, error) {
return a.listServices(ctx, params, optFns...)
}
func (a ecsClientAdapter) DescribeServices(ctx context.Context, params *ecs.DescribeServicesInput, optFns ...func(*ecs.Options)) (*ecs.DescribeServicesOutput, error) {
return a.describeServices(ctx, params, optFns...)
}
func (a ecsClientAdapter) ListTasks(ctx context.Context, params *ecs.ListTasksInput, optFns ...func(*ecs.Options)) (*ecs.ListTasksOutput, error) {
return a.listTasks(ctx, params, optFns...)
}
func (a ecsClientAdapter) DescribeTasks(ctx context.Context, params *ecs.DescribeTasksInput, optFns ...func(*ecs.Options)) (*ecs.DescribeTasksOutput, error) {
return a.describeTasks(ctx, params, optFns...)
}
func (a ecsClientAdapter) DescribeContainerInstances(ctx context.Context, params *ecs.DescribeContainerInstancesInput, optFns ...func(*ecs.Options)) (*ecs.DescribeContainerInstancesOutput, error) {
return a.describeContainerInstances(ctx, params, optFns...)
}
type ecsEC2Client interface {
DescribeInstances(context.Context, *ec2.DescribeInstancesInput, ...func(*ec2.Options)) (*ec2.DescribeInstancesOutput, error)
DescribeNetworkInterfaces(context.Context, *ec2.DescribeNetworkInterfacesInput, ...func(*ec2.Options)) (*ec2.DescribeNetworkInterfacesOutput, error)
@ -250,16 +304,16 @@ func (d *ECSDiscovery) initEcsClient(ctx context.Context) error {
cfg.Credentials = aws.NewCredentialsCache(assumeProvider)
}
d.ecs = ecs.NewFromConfig(cfg, func(options *ecs.Options) {
d.ecs = newECSClientAdapter(ecs.NewFromConfig(cfg, func(options *ecs.Options) {
if d.cfg.Endpoint != "" {
options.BaseEndpoint = &d.cfg.Endpoint
}
options.HTTPClient = client
})
}))
d.ec2 = ec2.NewFromConfig(cfg, func(options *ec2.Options) {
d.ec2 = newEC2ClientAdapter(ec2.NewFromConfig(cfg, func(options *ec2.Options) {
options.HTTPClient = client
})
}))
// Test credentials by making a simple API call
testCtx, cancel := context.WithTimeout(ctx, 10*time.Second)

View file

@ -40,6 +40,7 @@ type ecsDataStore struct {
}
func TestECSDiscoveryListClusterARNs(t *testing.T) {
t.Parallel()
ctx := context.Background()
// iterate through the test cases
@ -114,6 +115,7 @@ func TestECSDiscoveryListClusterARNs(t *testing.T) {
}
func TestECSDiscoveryDescribeClusters(t *testing.T) {
t.Parallel()
ctx := context.Background()
// iterate through the test cases
@ -212,6 +214,7 @@ func TestECSDiscoveryDescribeClusters(t *testing.T) {
}
func TestECSDiscoveryListServiceARNs(t *testing.T) {
t.Parallel()
ctx := context.Background()
for _, tt := range []struct {
@ -310,6 +313,7 @@ func TestECSDiscoveryListServiceARNs(t *testing.T) {
}
func TestECSDiscoveryDescribeServices(t *testing.T) {
t.Parallel()
ctx := context.Background()
for _, tt := range []struct {
@ -402,6 +406,7 @@ func TestECSDiscoveryDescribeServices(t *testing.T) {
}
func TestECSDiscoveryDescribeContainerInstances(t *testing.T) {
t.Parallel()
ctx := context.Background()
for _, tt := range []struct {
@ -506,6 +511,7 @@ func TestECSDiscoveryDescribeContainerInstances(t *testing.T) {
}
func TestECSDiscoveryDescribeEC2Instances(t *testing.T) {
t.Parallel()
ctx := context.Background()
for _, tt := range []struct {
@ -619,6 +625,7 @@ func TestECSDiscoveryDescribeEC2Instances(t *testing.T) {
}
func TestECSDiscoveryDescribeNetworkInterfaces(t *testing.T) {
t.Parallel()
ctx := context.Background()
for _, tt := range []struct {
@ -760,6 +767,7 @@ func TestECSDiscoveryDescribeNetworkInterfaces(t *testing.T) {
}
func TestECSDiscoveryListTaskARNs(t *testing.T) {
t.Parallel()
ctx := context.Background()
// iterate through the test cases
@ -834,6 +842,7 @@ func TestECSDiscoveryListTaskARNs(t *testing.T) {
}
func TestECSDiscoveryDescribeTasks(t *testing.T) {
t.Parallel()
ctx := context.Background()
// iterate through the test cases
@ -923,6 +932,7 @@ func TestECSDiscoveryDescribeTasks(t *testing.T) {
}
func TestECSDiscoveryRefresh(t *testing.T) {
t.Parallel()
ctx := context.Background()
tests := []struct {
@ -1712,6 +1722,7 @@ func (m *mockECSEC2Client) DescribeNetworkInterfaces(_ context.Context, input *e
}
func TestIsStandaloneTask(t *testing.T) {
t.Parallel()
tests := []struct {
name string
task ecsTypes.Task
@ -1763,6 +1774,7 @@ func TestIsStandaloneTask(t *testing.T) {
}
func TestGetServiceNameFromTaskGroup(t *testing.T) {
t.Parallel()
tests := []struct {
name string
task ecsTypes.Task

View file

@ -246,6 +246,37 @@ type elasticacheClient interface {
ListTagsForResource(ctx context.Context, params *elasticache.ListTagsForResourceInput, optFns ...func(*elasticache.Options)) (*elasticache.ListTagsForResourceOutput, error)
}
// elasticacheClientAdapter captures only the ElastiCache API calls AWS
// discovery uses as method-value closures, keeping the concrete
// *elasticache.Client out of any interface-boxed struct field. See
// ec2ClientAdapter for the full rationale: this stops the linker from retaining
// the entire ElastiCache API surface (~2.5 MB).
type elasticacheClientAdapter struct {
describeServerlessCaches func(ctx context.Context, params *elasticache.DescribeServerlessCachesInput, optFns ...func(*elasticache.Options)) (*elasticache.DescribeServerlessCachesOutput, error)
describeCacheClusters func(ctx context.Context, params *elasticache.DescribeCacheClustersInput, optFns ...func(*elasticache.Options)) (*elasticache.DescribeCacheClustersOutput, error)
listTagsForResource func(ctx context.Context, params *elasticache.ListTagsForResourceInput, optFns ...func(*elasticache.Options)) (*elasticache.ListTagsForResourceOutput, error)
}
func newElastiCacheClientAdapter(c *elasticache.Client) elasticacheClientAdapter {
return elasticacheClientAdapter{
describeServerlessCaches: c.DescribeServerlessCaches,
describeCacheClusters: c.DescribeCacheClusters,
listTagsForResource: c.ListTagsForResource,
}
}
func (a elasticacheClientAdapter) DescribeServerlessCaches(ctx context.Context, params *elasticache.DescribeServerlessCachesInput, optFns ...func(*elasticache.Options)) (*elasticache.DescribeServerlessCachesOutput, error) {
return a.describeServerlessCaches(ctx, params, optFns...)
}
func (a elasticacheClientAdapter) DescribeCacheClusters(ctx context.Context, params *elasticache.DescribeCacheClustersInput, optFns ...func(*elasticache.Options)) (*elasticache.DescribeCacheClustersOutput, error) {
return a.describeCacheClusters(ctx, params, optFns...)
}
func (a elasticacheClientAdapter) ListTagsForResource(ctx context.Context, params *elasticache.ListTagsForResourceInput, optFns ...func(*elasticache.Options)) (*elasticache.ListTagsForResourceOutput, error) {
return a.listTagsForResource(ctx, params, optFns...)
}
// ElasticacheDiscovery periodically performs Elasticache-SD requests.
// It implements the Discoverer interface.
type ElasticacheDiscovery struct {
@ -328,12 +359,12 @@ func (d *ElasticacheDiscovery) initElasticacheClient(ctx context.Context) error
cfg.Credentials = aws.NewCredentialsCache(assumeProvider)
}
d.elasticacheClient = elasticache.NewFromConfig(cfg, func(options *elasticache.Options) {
d.elasticacheClient = newElastiCacheClientAdapter(elasticache.NewFromConfig(cfg, func(options *elasticache.Options) {
if d.cfg.Endpoint != "" {
options.BaseEndpoint = &d.cfg.Endpoint
}
options.HTTPClient = client
})
}))
// Test credentials by making a simple API call
testCtx, cancel := context.WithTimeout(ctx, 10*time.Second)

View file

@ -36,6 +36,7 @@ type elasticacheDataStore struct {
}
func TestElasticacheDiscoveryDescribeServerlessCaches(t *testing.T) {
t.Parallel()
ctx := context.Background()
for _, tt := range []struct {
@ -125,6 +126,7 @@ func TestElasticacheDiscoveryDescribeServerlessCaches(t *testing.T) {
}
func TestElasticacheDiscoveryDescribeCacheClusters(t *testing.T) {
t.Parallel()
ctx := context.Background()
for _, tt := range []struct {
@ -184,6 +186,7 @@ func TestElasticacheDiscoveryDescribeCacheClusters(t *testing.T) {
}
func TestAddServerlessCacheTargets(t *testing.T) {
t.Parallel()
testTime := time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC)
tests := []struct {
@ -269,6 +272,7 @@ func TestAddServerlessCacheTargets(t *testing.T) {
}
func TestAddCacheClusterTargets(t *testing.T) {
t.Parallel()
testTime := time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC)
tests := []struct {
@ -532,6 +536,7 @@ func (m *mockElasticacheClient) ListTagsForResource(_ context.Context, input *el
}
func TestSplitCacheDeploymentOptions(t *testing.T) {
t.Parallel()
tests := []struct {
name string
caches []string

View file

@ -119,12 +119,29 @@ func (c *LightsailSDConfig) UnmarshalYAML(unmarshal func(any) error) error {
return c.HTTPClientConfig.Validate()
}
// lightsailClientAdapter captures only the Lightsail API calls AWS discovery
// uses as method-value closures, keeping the concrete *lightsail.Client out of
// any interface-boxed struct field. See ec2ClientAdapter for the full
// rationale: this stops the linker from retaining the entire Lightsail API
// surface (~3.4 MB).
type lightsailClientAdapter struct {
getInstances func(ctx context.Context, params *lightsail.GetInstancesInput, optFns ...func(*lightsail.Options)) (*lightsail.GetInstancesOutput, error)
}
func newLightsailClientAdapter(c *lightsail.Client) *lightsailClientAdapter {
return &lightsailClientAdapter{getInstances: c.GetInstances}
}
func (a *lightsailClientAdapter) GetInstances(ctx context.Context, params *lightsail.GetInstancesInput, optFns ...func(*lightsail.Options)) (*lightsail.GetInstancesOutput, error) {
return a.getInstances(ctx, params, optFns...)
}
// LightsailDiscovery periodically performs Lightsail-SD requests. It implements
// the Discoverer interface.
type LightsailDiscovery struct {
*refresh.Discovery
cfg *LightsailSDConfig
lightsail *lightsail.Client
lightsail *lightsailClientAdapter
}
// NewLightsailDiscovery returns a new LightsailDiscovery which periodically refreshes its targets.
@ -154,7 +171,7 @@ func NewLightsailDiscovery(conf *LightsailSDConfig, opts discovery.DiscovererOpt
return d, nil
}
func (d *LightsailDiscovery) lightsailClient(ctx context.Context) (*lightsail.Client, error) {
func (d *LightsailDiscovery) lightsailClient(ctx context.Context) (*lightsailClientAdapter, error) {
if d.lightsail != nil {
return d.lightsail, nil
}
@ -198,12 +215,12 @@ func (d *LightsailDiscovery) lightsailClient(ctx context.Context) (*lightsail.Cl
cfg.Credentials = aws.NewCredentialsCache(assumeProvider)
}
d.lightsail = lightsail.NewFromConfig(cfg, func(options *lightsail.Options) {
d.lightsail = newLightsailClientAdapter(lightsail.NewFromConfig(cfg, func(options *lightsail.Options) {
if d.cfg.Endpoint != "" {
options.BaseEndpoint = &d.cfg.Endpoint
}
options.HTTPClient = httpClient
})
}))
return d.lightsail, nil
}

View file

@ -158,6 +158,36 @@ type mskClient interface {
ListNodes(context.Context, *kafka.ListNodesInput, ...func(*kafka.Options)) (*kafka.ListNodesOutput, error)
}
// mskClientAdapter captures only the MSK (Kafka) API calls AWS discovery uses
// as method-value closures, keeping the concrete *kafka.Client out of any
// interface-boxed struct field. See ec2ClientAdapter for the full rationale:
// this stops the linker from retaining the entire MSK API surface (~1.4 MB).
type mskClientAdapter struct {
describeClusterV2 func(context.Context, *kafka.DescribeClusterV2Input, ...func(*kafka.Options)) (*kafka.DescribeClusterV2Output, error)
listClustersV2 func(context.Context, *kafka.ListClustersV2Input, ...func(*kafka.Options)) (*kafka.ListClustersV2Output, error)
listNodes func(context.Context, *kafka.ListNodesInput, ...func(*kafka.Options)) (*kafka.ListNodesOutput, error)
}
func newMSKClientAdapter(c *kafka.Client) mskClientAdapter {
return mskClientAdapter{
describeClusterV2: c.DescribeClusterV2,
listClustersV2: c.ListClustersV2,
listNodes: c.ListNodes,
}
}
func (a mskClientAdapter) DescribeClusterV2(ctx context.Context, params *kafka.DescribeClusterV2Input, optFns ...func(*kafka.Options)) (*kafka.DescribeClusterV2Output, error) {
return a.describeClusterV2(ctx, params, optFns...)
}
func (a mskClientAdapter) ListClustersV2(ctx context.Context, params *kafka.ListClustersV2Input, optFns ...func(*kafka.Options)) (*kafka.ListClustersV2Output, error) {
return a.listClustersV2(ctx, params, optFns...)
}
func (a mskClientAdapter) ListNodes(ctx context.Context, params *kafka.ListNodesInput, optFns ...func(*kafka.Options)) (*kafka.ListNodesOutput, error) {
return a.listNodes(ctx, params, optFns...)
}
// MSKDiscovery periodically performs MSK-SD requests. It implements
// the Discoverer interface.
type MSKDiscovery struct {
@ -240,12 +270,12 @@ func (d *MSKDiscovery) initMskClient(ctx context.Context) error {
cfg.Credentials = aws.NewCredentialsCache(assumeProvider)
}
d.msk = kafka.NewFromConfig(cfg, func(options *kafka.Options) {
d.msk = newMSKClientAdapter(kafka.NewFromConfig(cfg, func(options *kafka.Options) {
if d.cfg.Endpoint != "" {
options.BaseEndpoint = &d.cfg.Endpoint
}
options.HTTPClient = client
})
}))
// Test credentials by making a simple API call
testCtx, cancel := context.WithTimeout(ctx, 10*time.Second)

View file

@ -36,6 +36,7 @@ type mskDataStore struct {
}
func TestMSKDiscoveryListClusters(t *testing.T) {
t.Parallel()
ctx := context.Background()
for _, tt := range []struct {
@ -126,6 +127,7 @@ func TestMSKDiscoveryListClusters(t *testing.T) {
}
func TestMSKDiscoveryDescribeClusters(t *testing.T) {
t.Parallel()
ctx := context.Background()
for _, tt := range []struct {
@ -240,6 +242,7 @@ func TestMSKDiscoveryDescribeClusters(t *testing.T) {
}
func TestMSKDiscoveryListNodes(t *testing.T) {
t.Parallel()
ctx := context.Background()
for _, tt := range []struct {
@ -406,6 +409,7 @@ func TestMSKDiscoveryListNodes(t *testing.T) {
}
func TestMSKDiscoveryRefresh(t *testing.T) {
t.Parallel()
ctx := context.Background()
tests := []struct {
@ -1031,6 +1035,7 @@ func TestMSKDiscoveryRefresh(t *testing.T) {
}
func TestNodeType(t *testing.T) {
t.Parallel()
tests := []struct {
name string
node types.NodeInfo

View file

@ -276,6 +276,30 @@ type rdsClient interface {
DescribeDBInstances(context.Context, *rds.DescribeDBInstancesInput, ...func(*rds.Options)) (*rds.DescribeDBInstancesOutput, error)
}
// rdsClientAdapter captures only the RDS API calls AWS discovery uses as
// method-value closures, keeping the concrete *rds.Client out of any
// interface-boxed struct field. See ec2ClientAdapter for the full rationale:
// this stops the linker from retaining the entire RDS API surface (~5 MB).
type rdsClientAdapter struct {
describeDBClusters func(context.Context, *rds.DescribeDBClustersInput, ...func(*rds.Options)) (*rds.DescribeDBClustersOutput, error)
describeDBInstances func(context.Context, *rds.DescribeDBInstancesInput, ...func(*rds.Options)) (*rds.DescribeDBInstancesOutput, error)
}
func newRDSClientAdapter(c *rds.Client) rdsClientAdapter {
return rdsClientAdapter{
describeDBClusters: c.DescribeDBClusters,
describeDBInstances: c.DescribeDBInstances,
}
}
func (a rdsClientAdapter) DescribeDBClusters(ctx context.Context, params *rds.DescribeDBClustersInput, optFns ...func(*rds.Options)) (*rds.DescribeDBClustersOutput, error) {
return a.describeDBClusters(ctx, params, optFns...)
}
func (a rdsClientAdapter) DescribeDBInstances(ctx context.Context, params *rds.DescribeDBInstancesInput, optFns ...func(*rds.Options)) (*rds.DescribeDBInstancesOutput, error) {
return a.describeDBInstances(ctx, params, optFns...)
}
// RDSDiscovery periodically performs RDS-SD requests. It implements
// the Discoverer interface.
type RDSDiscovery struct {
@ -358,12 +382,12 @@ func (d *RDSDiscovery) initRdsClient(ctx context.Context) error {
cfg.Credentials = aws.NewCredentialsCache(assumeProvider)
}
d.rds = rds.NewFromConfig(cfg, func(options *rds.Options) {
d.rds = newRDSClientAdapter(rds.NewFromConfig(cfg, func(options *rds.Options) {
if d.cfg.Endpoint != "" {
options.BaseEndpoint = &d.cfg.Endpoint
}
options.HTTPClient = client
})
}))
// Test credentials by making a simple API call
testCtx, cancel := context.WithTimeout(ctx, 10*time.Second)
@ -462,9 +486,6 @@ func (d *RDSDiscovery) describeDBInstances(ctx context.Context, dbClusterARN str
if err != nil {
return nil, fmt.Errorf("failed to describe DB instances for cluster ARN %s: %w", dbClusterARN, err)
}
if len(output.DBInstances) == 0 {
return nil, fmt.Errorf("no DB instances found for cluster ARN %s", dbClusterARN)
}
for _, dbInstance := range output.DBInstances {
mu.Lock()

View file

@ -82,6 +82,7 @@ func (m *mockRDSClient) DescribeDBInstances(_ context.Context, input *rds.Descri
}
func TestRDSDiscoveryRefresh(t *testing.T) {
t.Parallel()
testTime := time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC)
tests := []struct {
@ -249,6 +250,21 @@ func TestRDSDiscoveryRefresh(t *testing.T) {
},
},
},
{
name: "NoInstancesInCluster",
clusters: map[string]types.DBCluster{
"arn:aws:rds:us-west-2:123456789012:cluster:prod-cluster": {
DBClusterArn: aws.String("arn:aws:rds:us-west-2:123456789012:cluster:prod-cluster"),
DBClusterIdentifier: aws.String("prod-cluster"),
Engine: aws.String("aurora-mysql"),
EngineVersion: aws.String("8.0.mysql_aurora.3.04.0"),
Status: aws.String("available"),
DBClusterMembers: []types.DBClusterMember{},
},
},
instances: map[string][]types.DBInstance{},
expectedLabels: []model.LabelSet{},
},
}
for _, tt := range tests {
@ -421,6 +437,7 @@ func TestRDSDiscoveryRefresh(t *testing.T) {
}
func TestDescribeAllDBClusters(t *testing.T) {
t.Parallel()
mockClient := &mockRDSClient{
clusters: map[string]types.DBCluster{
"arn:aws:rds:us-east-1:123456789012:cluster:cluster-1": {

View file

@ -30,6 +30,7 @@ import (
"github.com/Azure/azure-sdk-for-go/sdk/azcore/arm"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/cloud"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/to"
"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5"
@ -221,15 +222,105 @@ type client interface {
// azureClient represents multiple Azure Resource Manager providers.
type azureClient struct {
nic *armnetwork.InterfacesClient
vm *armcompute.VirtualMachinesClient
vmss *armcompute.VirtualMachineScaleSetsClient
vmssvm *armcompute.VirtualMachineScaleSetVMsClient
nic interfacesClientAdapter
vm virtualMachinesClientAdapter
vmss virtualMachineScaleSetsClientAdapter
vmssvm virtualMachineScaleSetVMsClientAdapter
logger *slog.Logger
}
var _ client = &azureClient{}
// The *ClientAdapter types below capture only the operations discovery uses as
// closures, hiding the concrete SDK clients from reflection so dead-code
// elimination can drop the unused operations and shrink the binary.
// virtualMachinesClientAdapter adapts *armcompute.VirtualMachinesClient.
type virtualMachinesClientAdapter struct {
newListAllPager func(options *armcompute.VirtualMachinesClientListAllOptions) *runtime.Pager[armcompute.VirtualMachinesClientListAllResponse]
newListPager func(resourceGroupName string, options *armcompute.VirtualMachinesClientListOptions) *runtime.Pager[armcompute.VirtualMachinesClientListResponse]
}
func newVirtualMachinesClientAdapter(c *armcompute.VirtualMachinesClient) virtualMachinesClientAdapter {
return virtualMachinesClientAdapter{
newListAllPager: c.NewListAllPager,
newListPager: c.NewListPager,
}
}
// NewListAllPager lists all virtual machines in the subscription.
func (a virtualMachinesClientAdapter) NewListAllPager(options *armcompute.VirtualMachinesClientListAllOptions) *runtime.Pager[armcompute.VirtualMachinesClientListAllResponse] {
return a.newListAllPager(options)
}
// NewListPager lists the virtual machines in a resource group.
func (a virtualMachinesClientAdapter) NewListPager(resourceGroupName string, options *armcompute.VirtualMachinesClientListOptions) *runtime.Pager[armcompute.VirtualMachinesClientListResponse] {
return a.newListPager(resourceGroupName, options)
}
// virtualMachineScaleSetsClientAdapter adapts *armcompute.VirtualMachineScaleSetsClient.
type virtualMachineScaleSetsClientAdapter struct {
newListAllPager func(options *armcompute.VirtualMachineScaleSetsClientListAllOptions) *runtime.Pager[armcompute.VirtualMachineScaleSetsClientListAllResponse]
newListPager func(resourceGroupName string, options *armcompute.VirtualMachineScaleSetsClientListOptions) *runtime.Pager[armcompute.VirtualMachineScaleSetsClientListResponse]
}
func newVirtualMachineScaleSetsClientAdapter(c *armcompute.VirtualMachineScaleSetsClient) virtualMachineScaleSetsClientAdapter {
return virtualMachineScaleSetsClientAdapter{
newListAllPager: c.NewListAllPager,
newListPager: c.NewListPager,
}
}
// NewListAllPager lists all scale sets in the subscription.
func (a virtualMachineScaleSetsClientAdapter) NewListAllPager(options *armcompute.VirtualMachineScaleSetsClientListAllOptions) *runtime.Pager[armcompute.VirtualMachineScaleSetsClientListAllResponse] {
return a.newListAllPager(options)
}
// NewListPager lists the scale sets in a resource group.
func (a virtualMachineScaleSetsClientAdapter) NewListPager(resourceGroupName string, options *armcompute.VirtualMachineScaleSetsClientListOptions) *runtime.Pager[armcompute.VirtualMachineScaleSetsClientListResponse] {
return a.newListPager(resourceGroupName, options)
}
// virtualMachineScaleSetVMsClientAdapter adapts *armcompute.VirtualMachineScaleSetVMsClient.
type virtualMachineScaleSetVMsClientAdapter struct {
newListPager func(resourceGroupName, virtualMachineScaleSetName string, options *armcompute.VirtualMachineScaleSetVMsClientListOptions) *runtime.Pager[armcompute.VirtualMachineScaleSetVMsClientListResponse]
}
func newVirtualMachineScaleSetVMsClientAdapter(c *armcompute.VirtualMachineScaleSetVMsClient) virtualMachineScaleSetVMsClientAdapter {
return virtualMachineScaleSetVMsClientAdapter{
newListPager: c.NewListPager,
}
}
// NewListPager lists the virtual machines of a scale set.
func (a virtualMachineScaleSetVMsClientAdapter) NewListPager(resourceGroupName, virtualMachineScaleSetName string, options *armcompute.VirtualMachineScaleSetVMsClientListOptions) *runtime.Pager[armcompute.VirtualMachineScaleSetVMsClientListResponse] {
return a.newListPager(resourceGroupName, virtualMachineScaleSetName, options)
}
// interfacesClientAdapter adapts *armnetwork.InterfacesClient.
type interfacesClientAdapter struct {
get func(ctx context.Context, resourceGroupName, networkInterfaceName string, options *armnetwork.InterfacesClientGetOptions) (armnetwork.InterfacesClientGetResponse, error)
getVirtualMachineScaleSetNetworkInterface func(ctx context.Context, resourceGroupName, virtualMachineScaleSetName, virtualMachineIndex, networkInterfaceName string, options *armnetwork.InterfacesClientGetVirtualMachineScaleSetNetworkInterfaceOptions) (armnetwork.InterfacesClientGetVirtualMachineScaleSetNetworkInterfaceResponse, error)
}
func newInterfacesClientAdapter(c *armnetwork.InterfacesClient) interfacesClientAdapter {
return interfacesClientAdapter{
get: c.Get,
getVirtualMachineScaleSetNetworkInterface: c.GetVirtualMachineScaleSetNetworkInterface,
}
}
// Get retrieves a network interface.
func (a interfacesClientAdapter) Get(ctx context.Context, resourceGroupName, networkInterfaceName string, options *armnetwork.InterfacesClientGetOptions) (armnetwork.InterfacesClientGetResponse, error) {
return a.get(ctx, resourceGroupName, networkInterfaceName, options)
}
// GetVirtualMachineScaleSetNetworkInterface retrieves a scale set VM network interface.
func (a interfacesClientAdapter) GetVirtualMachineScaleSetNetworkInterface(ctx context.Context, resourceGroupName, virtualMachineScaleSetName, virtualMachineIndex, networkInterfaceName string, options *armnetwork.InterfacesClientGetVirtualMachineScaleSetNetworkInterfaceOptions) (armnetwork.InterfacesClientGetVirtualMachineScaleSetNetworkInterfaceResponse, error) {
return a.getVirtualMachineScaleSetNetworkInterface(ctx, resourceGroupName, virtualMachineScaleSetName, virtualMachineIndex, networkInterfaceName, options)
}
// createAzureClient is a helper method for creating an Azure compute client to ARM.
func (d *Discovery) createAzureClient() (client, error) {
cloudConfiguration, err := CloudConfigurationFromName(d.cfg.Environment)
@ -264,25 +355,29 @@ func (d *Discovery) createAzureClient() (client, error) {
},
}
c.vm, err = armcompute.NewVirtualMachinesClient(d.cfg.SubscriptionID, credential, options)
vmClient, err := armcompute.NewVirtualMachinesClient(d.cfg.SubscriptionID, credential, options)
if err != nil {
return &azureClient{}, err
}
c.vm = newVirtualMachinesClientAdapter(vmClient)
c.nic, err = armnetwork.NewInterfacesClient(d.cfg.SubscriptionID, credential, options)
nicClient, err := armnetwork.NewInterfacesClient(d.cfg.SubscriptionID, credential, options)
if err != nil {
return &azureClient{}, err
}
c.nic = newInterfacesClientAdapter(nicClient)
c.vmss, err = armcompute.NewVirtualMachineScaleSetsClient(d.cfg.SubscriptionID, credential, options)
vmssClient, err := armcompute.NewVirtualMachineScaleSetsClient(d.cfg.SubscriptionID, credential, options)
if err != nil {
return &azureClient{}, err
}
c.vmss = newVirtualMachineScaleSetsClientAdapter(vmssClient)
c.vmssvm, err = armcompute.NewVirtualMachineScaleSetVMsClient(d.cfg.SubscriptionID, credential, options)
vmssvmClient, err := armcompute.NewVirtualMachineScaleSetVMsClient(d.cfg.SubscriptionID, credential, options)
if err != nil {
return &azureClient{}, err
}
c.vmssvm = newVirtualMachineScaleSetVMsClientAdapter(vmssvmClient)
return &c, nil
}

View file

@ -738,10 +738,10 @@ func createMockAzureClient(t *testing.T, vmResp []armcompute.VirtualMachinesClie
return &mockAzureClient{
azureClient: azureClient{
vm: vmClient,
vmss: vmssClient,
vmssvm: vmssvmClient,
nic: interfacesClient,
vm: newVirtualMachinesClientAdapter(vmClient),
vmss: newVirtualMachineScaleSetsClientAdapter(vmssClient),
vmssvm: newVirtualMachineScaleSetVMsClientAdapter(vmssvmClient),
nic: newInterfacesClientAdapter(interfacesClient),
logger: logger,
},
}

View file

@ -49,6 +49,7 @@ func NewTestMetrics(t *testing.T, conf discovery.Config, reg prometheus.Register
}
func TestConfiguredService(t *testing.T) {
t.Parallel()
conf := &SDConfig{
Services: []string{"configuredServiceName"},
}
@ -64,6 +65,7 @@ func TestConfiguredService(t *testing.T) {
}
func TestConfiguredServiceWithTag(t *testing.T) {
t.Parallel()
conf := &SDConfig{
Services: []string{"configuredServiceName"},
ServiceTags: []string{"http"},
@ -87,6 +89,7 @@ func TestConfiguredServiceWithTag(t *testing.T) {
}
func TestConfiguredServiceWithTags(t *testing.T) {
t.Parallel()
type testcase struct {
// What we've configured to watch.
conf *SDConfig
@ -174,6 +177,7 @@ func TestConfiguredServiceWithTags(t *testing.T) {
}
func TestNonConfiguredService(t *testing.T) {
t.Parallel()
conf := &SDConfig{}
metrics := NewTestMetrics(t, conf, prometheus.NewRegistry())
@ -294,6 +298,7 @@ func checkOneTarget(t *testing.T, tg []*targetgroup.Group) {
// Watch all the services in the catalog.
func TestAllServices(t *testing.T) {
t.Parallel()
stub, config := newServer(t)
t.Cleanup(stub.Close)
@ -313,6 +318,7 @@ func TestAllServices(t *testing.T) {
// targetgroup with no targets is emitted if no services were discovered.
func TestNoTargets(t *testing.T) {
t.Parallel()
stub, config := newServer(t)
t.Cleanup(stub.Close)
config.ServiceTags = []string{"missing"}
@ -334,6 +340,7 @@ func TestNoTargets(t *testing.T) {
// Watch only the test service.
func TestOneService(t *testing.T) {
t.Parallel()
stub, config := newServer(t)
t.Cleanup(stub.Close)
@ -349,6 +356,7 @@ func TestOneService(t *testing.T) {
// Watch the test service with a specific tag and node-meta.
func TestAllOptions(t *testing.T) {
t.Parallel()
stub, config := newServer(t)
t.Cleanup(stub.Close)
@ -374,6 +382,7 @@ func TestAllOptions(t *testing.T) {
// TestFilterOption verifies that when services and filter are both configured, the Catalog API
// is still called and receives the filter parameter, while the Health API does not.
func TestFilterOption(t *testing.T) {
t.Parallel()
var (
catalogCalled bool
catalogFilter string
@ -432,6 +441,7 @@ func TestFilterOption(t *testing.T) {
// TestHealthFilterOption verifies that health_filter is passed to the Health API and not to
// the Catalog API.
func TestHealthFilterOption(t *testing.T) {
t.Parallel()
var (
catalogCalled bool
catalogFilter string
@ -491,6 +501,7 @@ func TestHealthFilterOption(t *testing.T) {
// TestBothFiltersOption verifies that when both filter and health_filter are configured,
// each filter is sent exclusively to its respective API endpoint.
func TestBothFiltersOption(t *testing.T) {
t.Parallel()
var (
catalogCalled bool
catalogFilter string
@ -548,6 +559,7 @@ func TestBothFiltersOption(t *testing.T) {
}
func TestGetDatacenterShouldReturnError(t *testing.T) {
t.Parallel()
for _, tc := range []struct {
handler func(http.ResponseWriter, *http.Request)
errMessage string
@ -592,6 +604,7 @@ func TestGetDatacenterShouldReturnError(t *testing.T) {
}
func TestUnmarshalConfig(t *testing.T) {
t.Parallel()
unmarshal := func(d []byte) func(any) error {
return func(o any) error {
return yaml.Unmarshal(d, o)
@ -663,6 +676,7 @@ oauth2:
for _, test := range cases {
t.Run(test.name, func(t *testing.T) {
t.Parallel()
var config SDConfig
err := config.UnmarshalYAML(unmarshal([]byte(test.config)))
if err != nil {

View file

@ -17,7 +17,6 @@ import (
"context"
"errors"
"fmt"
"net/http"
"strconv"
"strings"
"time"
@ -113,18 +112,34 @@ func (c *SDConfig) UnmarshalYAML(unmarshal func(any) error) error {
return nil
}
// instancesLister lists the instances of a project/zone, paging through the
// results and invoking f for each page.
type instancesLister func(ctx context.Context, f func(*compute.InstanceList) error) error
// newInstancesLister captures *compute.Service in a closure instead of storing
// it on the interface-boxed Discovery struct. This keeps the binary smaller:
// otherwise reflection keeps every Compute method live, defeating dead-code
// elimination.
func newInstancesLister(svc *compute.Service, project, zone, filter string) instancesLister {
isvc := compute.NewInstancesService(svc)
return func(ctx context.Context, f func(*compute.InstanceList) error) error {
ilc := isvc.List(project, zone)
if filter != "" {
ilc = ilc.Filter(filter)
}
return ilc.Pages(ctx, f)
}
}
// Discovery periodically performs GCE-SD requests. It implements
// the Discoverer interface.
type Discovery struct {
*refresh.Discovery
project string
zone string
filter string
client *http.Client
svc *compute.Service
isvc *compute.InstancesService
port int
tagSeparator string
project string
zone string
listInstances instancesLister
port int
tagSeparator string
}
// NewDiscovery returns a new Discovery which periodically refreshes its targets.
@ -137,20 +152,18 @@ func NewDiscovery(conf SDConfig, opts discovery.DiscovererOptions) (*Discovery,
d := &Discovery{
project: conf.Project,
zone: conf.Zone,
filter: conf.Filter,
port: conf.Port,
tagSeparator: conf.TagSeparator,
}
var err error
d.client, err = google.DefaultClient(context.Background(), compute.ComputeReadonlyScope)
client, err := google.DefaultClient(context.Background(), compute.ComputeReadonlyScope)
if err != nil {
return nil, fmt.Errorf("error setting up communication with GCE service: %w", err)
}
d.svc, err = compute.NewService(context.Background(), option.WithHTTPClient(d.client))
svc, err := compute.NewService(context.Background(), option.WithHTTPClient(client))
if err != nil {
return nil, fmt.Errorf("error setting up communication with GCE service: %w", err)
}
d.isvc = compute.NewInstancesService(d.svc)
d.listInstances = newInstancesLister(svc, conf.Project, conf.Zone, conf.Filter)
d.Discovery = refresh.NewDiscovery(
refresh.Options{
@ -170,11 +183,7 @@ func (d *Discovery) refresh(ctx context.Context) ([]*targetgroup.Group, error) {
Source: fmt.Sprintf("GCE_%s_%s", d.project, d.zone),
}
ilc := d.isvc.List(d.project, d.zone)
if d.filter != "" {
ilc = ilc.Filter(d.filter)
}
err := ilc.Pages(ctx, func(l *compute.InstanceList) error {
err := d.listInstances(ctx, func(l *compute.InstanceList) error {
for _, inst := range l.Items {
if len(inst.NetworkInterfaces) == 0 {
continue

View file

@ -0,0 +1,76 @@
// Copyright 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 kubernetes
import (
"k8s.io/client-go/kubernetes"
appsv1client "k8s.io/client-go/kubernetes/typed/apps/v1"
batchv1client "k8s.io/client-go/kubernetes/typed/batch/v1"
corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
discoveryv1client "k8s.io/client-go/kubernetes/typed/discovery/v1"
networkingv1client "k8s.io/client-go/kubernetes/typed/networking/v1"
)
// k8sClient exposes only the API-group accessors discovery uses. It is
// satisfied by both clientAdapter and the fake clientset used in tests.
type k8sClient interface {
CoreV1() corev1client.CoreV1Interface
AppsV1() appsv1client.AppsV1Interface
BatchV1() batchv1client.BatchV1Interface
DiscoveryV1() discoveryv1client.DiscoveryV1Interface
NetworkingV1() networkingv1client.NetworkingV1Interface
}
// clientAdapter captures the used API-group accessors as method-value closures.
// Keeping the concrete clientset out of an interface-typed field avoids forcing
// the linker, via reflection, to retain every API group and resource client,
// which reduces the binary size.
type clientAdapter struct {
coreV1 func() corev1client.CoreV1Interface
appsV1 func() appsv1client.AppsV1Interface
batchV1 func() batchv1client.BatchV1Interface
discoveryV1 func() discoveryv1client.DiscoveryV1Interface
networkingV1 func() networkingv1client.NetworkingV1Interface
}
// newClientAdapter wraps a concrete clientset, exposing only the API groups
// discovery uses.
func newClientAdapter(c *kubernetes.Clientset) *clientAdapter {
return &clientAdapter{
coreV1: c.CoreV1,
appsV1: c.AppsV1,
batchV1: c.BatchV1,
discoveryV1: c.DiscoveryV1,
networkingV1: c.NetworkingV1,
}
}
// CoreV1 returns the core/v1 API-group client.
func (a *clientAdapter) CoreV1() corev1client.CoreV1Interface { return a.coreV1() }
// AppsV1 returns the apps/v1 API-group client.
func (a *clientAdapter) AppsV1() appsv1client.AppsV1Interface { return a.appsV1() }
// BatchV1 returns the batch/v1 API-group client.
func (a *clientAdapter) BatchV1() batchv1client.BatchV1Interface { return a.batchV1() }
// DiscoveryV1 returns the discovery/v1 API-group client.
func (a *clientAdapter) DiscoveryV1() discoveryv1client.DiscoveryV1Interface {
return a.discoveryV1()
}
// NetworkingV1 returns the networking/v1 API-group client.
func (a *clientAdapter) NetworkingV1() networkingv1client.NetworkingV1Interface {
return a.networkingV1()
}

View file

@ -254,7 +254,7 @@ func (c *NamespaceDiscovery) UnmarshalYAML(unmarshal func(any) error) error {
// targets from Kubernetes.
type Discovery struct {
sync.RWMutex
client kubernetes.Interface
client k8sClient
role Role
logger *slog.Logger
namespaceDiscovery *NamespaceDiscovery
@ -341,7 +341,7 @@ func New(l *slog.Logger, metrics discovery.DiscovererMetrics, conf *SDConfig) (*
}
d := &Discovery{
client: c,
client: newClientAdapter(c),
logger: l,
role: conf.Role,
namespaceDiscovery: &conf.NamespaceDiscovery,

View file

@ -66,6 +66,7 @@ func testUpdateServices(client appListClient) ([]*targetgroup.Group, error) {
}
func TestMarathonSDHandleError(t *testing.T) {
t.Parallel()
var (
errTesting = errors.New("testing failure")
client = func(context.Context, *http.Client, string) (*appList, error) {
@ -78,6 +79,7 @@ func TestMarathonSDHandleError(t *testing.T) {
}
func TestMarathonSDEmptyList(t *testing.T) {
t.Parallel()
client := func(context.Context, *http.Client, string) (*appList, error) { return &appList{}, nil }
tgs, err := testUpdateServices(client)
require.NoError(t, err)
@ -111,6 +113,7 @@ func marathonTestAppList(labels map[string]string, runningTasks int) *appList {
}
func TestMarathonSDSendGroup(t *testing.T) {
t.Parallel()
client := func(context.Context, *http.Client, string) (*appList, error) {
return marathonTestAppList(marathonValidLabel, 1), nil
}
@ -128,6 +131,7 @@ func TestMarathonSDSendGroup(t *testing.T) {
}
func TestMarathonSDRemoveApp(t *testing.T) {
t.Parallel()
cfg := testConfig()
reg := prometheus.NewRegistry()
refreshMetrics := discovery.NewRefreshMetrics(reg)
@ -192,6 +196,7 @@ func marathonTestAppListWithMultiplePorts(labels map[string]string, runningTasks
}
func TestMarathonSDSendGroupWithMultiplePort(t *testing.T) {
t.Parallel()
client := func(context.Context, *http.Client, string) (*appList, error) {
return marathonTestAppListWithMultiplePorts(marathonValidLabel, 1), nil
}
@ -237,6 +242,7 @@ func marathonTestZeroTaskPortAppList(labels map[string]string, runningTasks int)
}
func TestMarathonZeroTaskPorts(t *testing.T) {
t.Parallel()
client := func(context.Context, *http.Client, string) (*appList, error) {
return marathonTestZeroTaskPortAppList(marathonValidLabel, 1), nil
}
@ -250,6 +256,7 @@ func TestMarathonZeroTaskPorts(t *testing.T) {
}
func Test500ErrorHttpResponseWithValidJSONBody(t *testing.T) {
t.Parallel()
// Simulate 500 error with a valid JSON response.
respHandler := func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusInternalServerError)
@ -295,6 +302,7 @@ func marathonTestAppListWithPortDefinitions(labels map[string]string, runningTas
}
func TestMarathonSDSendGroupWithPortDefinitions(t *testing.T) {
t.Parallel()
client := func(context.Context, *http.Client, string) (*appList, error) {
return marathonTestAppListWithPortDefinitions(marathonValidLabel, 1), nil
}
@ -349,6 +357,7 @@ func marathonTestAppListWithPortDefinitionsRequirePorts(labels map[string]string
}
func TestMarathonSDSendGroupWithPortDefinitionsRequirePorts(t *testing.T) {
t.Parallel()
client := func(context.Context, *http.Client, string) (*appList, error) {
return marathonTestAppListWithPortDefinitionsRequirePorts(marathonValidLabel, 1), nil
}
@ -396,6 +405,7 @@ func marathonTestAppListWithPorts(labels map[string]string, runningTasks int) *a
}
func TestMarathonSDSendGroupWithPorts(t *testing.T) {
t.Parallel()
client := func(context.Context, *http.Client, string) (*appList, error) {
return marathonTestAppListWithPorts(marathonValidLabel, 1), nil
}
@ -452,6 +462,7 @@ func marathonTestAppListWithContainerPortMappings(labels map[string]string, runn
}
func TestMarathonSDSendGroupWithContainerPortMappings(t *testing.T) {
t.Parallel()
client := func(context.Context, *http.Client, string) (*appList, error) {
return marathonTestAppListWithContainerPortMappings(marathonValidLabel, 1), nil
}
@ -508,6 +519,7 @@ func marathonTestAppListWithDockerContainerPortMappings(labels map[string]string
}
func TestMarathonSDSendGroupWithDockerContainerPortMappings(t *testing.T) {
t.Parallel()
client := func(context.Context, *http.Client, string) (*appList, error) {
return marathonTestAppListWithDockerContainerPortMappings(marathonValidLabel, 1), nil
}
@ -568,6 +580,7 @@ func marathonTestAppListWithContainerNetworkAndPortMappings(labels map[string]st
}
func TestMarathonSDSendGroupWithContainerNetworkAndPortMapping(t *testing.T) {
t.Parallel()
client := func(context.Context, *http.Client, string) (*appList, error) {
return marathonTestAppListWithContainerNetworkAndPortMappings(marathonValidLabel, 1), nil
}

View file

@ -23,6 +23,7 @@ import (
"github.com/prometheus/common/model"
"github.com/prometheus/common/version"
"github.com/scaleway/scaleway-sdk-go/api/instance/v1"
ipam "github.com/scaleway/scaleway-sdk-go/api/ipam/v1"
"github.com/scaleway/scaleway-sdk-go/scw"
"github.com/prometheus/prometheus/discovery/refresh"
@ -104,7 +105,8 @@ func newInstanceDiscovery(conf *SDConfig) (*instanceDiscovery, error) {
}
func (d *instanceDiscovery) refresh(ctx context.Context) ([]*targetgroup.Group, error) {
api := instance.NewAPI(d.client)
instanceAPI := instance.NewAPI(d.client)
ipamAPI := ipam.NewAPI(d.client)
req := &instance.ListServersRequest{}
@ -116,7 +118,12 @@ func (d *instanceDiscovery) refresh(ctx context.Context) ([]*targetgroup.Group,
req.Tags = d.tagsFilter
}
servers, err := api.ListServers(req, scw.WithAllPages(), scw.WithContext(ctx))
servers, err := instanceAPI.ListServers(req, scw.WithAllPages(), scw.WithContext(ctx))
if err != nil {
return nil, err
}
privateNICIPByID, err := privateNICIPs(ctx, ipamAPI, servers.Servers)
if err != nil {
return nil, err
}
@ -208,6 +215,19 @@ func (d *instanceDiscovery) refresh(ctx context.Context) ([]*targetgroup.Group,
addr = *server.PrivateIP
}
if addr == "" {
for _, privateNIC := range server.PrivateNics {
if privateNIC == nil {
continue
}
if privateIP := privateNICIPByID[privateNIC.ID]; privateIP != "" {
labels[instancePrivateIPv4Label] = model.LabelValue(privateIP)
addr = privateIP
break
}
}
}
if addr != "" {
addr := net.JoinHostPort(addr, strconv.FormatUint(uint64(d.port), 10))
labels[model.AddressLabel] = model.LabelValue(addr)
@ -217,3 +237,43 @@ func (d *instanceDiscovery) refresh(ctx context.Context) ([]*targetgroup.Group,
return []*targetgroup.Group{{Source: "scaleway", Targets: targets}}, nil
}
func privateNICIPs(ctx context.Context, api *ipam.API, servers []*instance.Server) (map[string]string, error) {
privateNICIDsByRegion := map[scw.Region][]string{}
for _, server := range servers {
if server.PrivateIP != nil || server.PublicIP != nil || server.IPv6 != nil { //nolint:staticcheck
continue
}
region, err := server.Zone.Region()
if err != nil {
return nil, err
}
for _, privateNIC := range server.PrivateNics {
if privateNIC != nil && privateNIC.ID != "" {
privateNICIDsByRegion[region] = append(privateNICIDsByRegion[region], privateNIC.ID)
}
}
}
privateNICIPs := map[string]string{}
for region, privateNICIDs := range privateNICIDsByRegion {
ips, err := api.ListIPs(&ipam.ListIPsRequest{
Region: region,
ResourceIDs: privateNICIDs,
ResourceTypes: []ipam.ResourceType{ipam.ResourceTypeInstancePrivateNic},
}, scw.WithAllPages(), scw.WithContext(ctx))
if err != nil {
return nil, err
}
for _, ip := range ips.IPs {
if ip != nil && ip.Resource != nil && !ip.IsIPv6 && ip.Address.IP != nil {
privateNICIPs[ip.Resource.ID] = ip.Address.IP.String()
}
}
}
return privateNICIPs, nil
}

View file

@ -187,6 +187,95 @@ func mockScalewayInstance(w http.ResponseWriter, r *http.Request) {
}
}
func TestScalewayInstanceRefreshIPAMPrivateNIC(t *testing.T) {
mock := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Header.Get("X-Auth-Token") != testSecretKey {
http.Error(w, "bad token id", http.StatusUnauthorized)
return
}
w.Header().Set("Content-Type", "application/json")
switch r.URL.Path {
case "/instance/v1/zones/fr-par-1/servers":
_, err := w.Write([]byte(`{
"servers": [
{
"id": "78d6aa69-6a5f-47bd-9f1a-3cdde6973d96",
"name": "ipam-only",
"organization": "cb334986-b054-4725-9d3a-40850fdc6015",
"project": "cb334986-b054-4725-9d5a-30850fdc6015",
"commercial_type": "DEV1-S",
"hostname": "ipam-only",
"state": "running",
"boot_type": "local",
"routed_ip_enabled": true,
"public_ip": null,
"public_ips": [],
"private_ip": null,
"private_nics": [
{
"id": "2d17a5a0-f8e5-4e7f-a029-f7c8d182af53",
"server_id": "78d6aa69-6a5f-47bd-9f1a-3cdde6973d96",
"private_network_id": "18ba4ed4-d194-4b5d-9083-447325234a71",
"mac_address": "02:00:00:00:31:90",
"state": "available",
"zone": "fr-par-1"
}
],
"zone": "fr-par-1"
}
]
}`))
require.NoError(t, err)
case "/ipam/v1/regions/fr-par/ips":
require.Equal(t, "2d17a5a0-f8e5-4e7f-a029-f7c8d182af53", r.URL.Query().Get("resource_ids"))
require.Equal(t, "instance_private_nic", r.URL.Query().Get("resource_types"))
_, err := w.Write([]byte(`{
"ips": [
{
"id": "b50244c4-b0b1-4cc9-a78c-26034b4967d3",
"address": "10.0.0.7/32",
"project_id": "cb334986-b054-4725-9d5a-30850fdc6015",
"is_ipv6": false,
"resource": {
"type": "instance_private_nic",
"id": "2d17a5a0-f8e5-4e7f-a029-f7c8d182af53"
},
"region": "fr-par"
}
],
"total_count": 1
}`))
require.NoError(t, err)
default:
http.Error(w, "bad url", http.StatusNotFound)
}
}))
defer mock.Close()
cfgString := fmt.Sprintf(`
---
role: instance
project_id: %s
secret_key: %s
access_key: %s
api_url: %s
`, testProjectID, testSecretKey, testAccessKey, mock.URL)
var cfg SDConfig
require.NoError(t, yaml.UnmarshalStrict([]byte(cfgString), &cfg))
d, err := newRefresher(&cfg)
require.NoError(t, err)
tgs, err := d.refresh(context.Background())
require.NoError(t, err)
require.Len(t, tgs, 1)
require.Len(t, tgs[0].Targets, 1)
require.Equal(t, model.LabelValue("10.0.0.7:80"), tgs[0].Targets[0][model.AddressLabel])
require.Equal(t, model.LabelValue("10.0.0.7"), tgs[0].Targets[0][instancePrivateIPv4Label])
}
func TestScalewayInstanceAuthToken(t *testing.T) {
mock := httptest.NewServer(http.HandlerFunc(mockScalewayInstance))
defer mock.Close()

View file

@ -90,8 +90,8 @@ func newServerDiscovery(conf *SDConfig, logger *slog.Logger) (*iaasDiscovery, er
Servers: servers,
NoAuth: conf.ServiceAccountKey == "" && conf.ServiceAccountKeyPath == "",
ServiceAccountKey: conf.ServiceAccountKey,
PrivateKey: conf.PrivateKey,
ServiceAccountKey: string(conf.ServiceAccountKey),
PrivateKey: string(conf.PrivateKey),
ServiceAccountKeyPath: conf.ServiceAccountKeyPath,
PrivateKeyPath: conf.PrivateKeyPath,
CredentialsFilePath: conf.CredentialsFilePath,

View file

@ -21,6 +21,7 @@ import (
"encoding/pem"
"testing"
"github.com/prometheus/common/config"
"github.com/prometheus/common/model"
"github.com/prometheus/common/promslog"
"github.com/stretchr/testify/require"
@ -59,12 +60,12 @@ func TestServerSDRefresh(t *testing.T) {
require.NoError(t, err)
cfg := DefaultSDConfig
cfg.PrivateKey = string(pem.EncodeToMemory(&pem.Block{
cfg.PrivateKey = config.Secret(pem.EncodeToMemory(&pem.Block{
Type: "RSA PRIVATE KEY",
Bytes: x509.MarshalPKCS1PrivateKey(key),
}))
cfg.ServiceAccountKey = `{
cfg.ServiceAccountKey = config.Secret(`{
"Active": true,
"CreatedAt": "2025-04-05T12:34:56Z",
"Credentials": {
@ -79,7 +80,7 @@ func TestServerSDRefresh(t *testing.T) {
"KeyType": "USER_MANAGED",
"PublicKey": "...",
"ValidUntil": "2025-04-05T13:34:56Z"
}`
}`)
return cfg
}(),

View file

@ -65,8 +65,8 @@ type SDConfig struct {
Port int `yaml:"port,omitempty"`
Region string `yaml:"region,omitempty"`
Endpoint string `yaml:"endpoint,omitempty"`
ServiceAccountKey string `yaml:"service_account_key,omitempty"`
PrivateKey string `yaml:"private_key,omitempty"`
ServiceAccountKey config.Secret `yaml:"service_account_key,omitempty"`
PrivateKey config.Secret `yaml:"private_key,omitempty"`
ServiceAccountKeyPath string `yaml:"service_account_key_path,omitempty"`
PrivateKeyPath string `yaml:"private_key_path,omitempty"`
CredentialsFilePath string `yaml:"credentials_file_path,omitempty"`

View file

@ -12,8 +12,9 @@ The Prometheus monitoring server
| <code class="text-nowrap">-h</code>, <code class="text-nowrap">--help</code> | Show context-sensitive help (also try --help-long and --help-man). | |
| <code class="text-nowrap">--version</code> | Show application version. | |
| <code class="text-nowrap">--config.file</code> | Prometheus configuration file path. | `prometheus.yml` |
| <code class="text-nowrap">--config.auto-reload-interval</code> | Specifies the interval for checking and automatically reloading the Prometheus configuration file upon detecting changes. | `30s` |
| <code class="text-nowrap">--web.listen-address</code> <code class="text-nowrap">...<code class="text-nowrap"> | Address to listen on for UI, API, and telemetry. Can be repeated. | `0.0.0.0:9090` |
| <code class="text-nowrap">--config.auto-reload</code> | Enable automatic configuration file reloading. See also --config.auto-reload-interval. | `false` |
| <code class="text-nowrap">--config.auto-reload-interval</code> | Specifies the interval for checking and automatically reloading the Prometheus configuration file upon detecting changes. Only used when --config.auto-reload is set. | `30s` |
| <code class="text-nowrap">--web.listen-address</code> <code class="text-nowrap">...</code> | Address to listen on for UI, API, and telemetry. Can be repeated. | `0.0.0.0:9090` |
| <code class="text-nowrap">--auto-gomaxprocs</code> | Automatically set GOMAXPROCS to match Linux container CPU quota | `true` |
| <code class="text-nowrap">--auto-gomemlimit</code> | Automatically set GOMEMLIMIT to match Linux container or system memory limit | `true` |
| <code class="text-nowrap">--auto-gomemlimit.ratio</code> | The ratio of reserved GOMEMLIMIT memory to the detected maximum container or system memory | `0.9` |
@ -50,6 +51,7 @@ The Prometheus monitoring server
| <code class="text-nowrap">--storage.remote.read-sample-limit</code> | Maximum overall number of samples to return via the remote read interface, in a single query. 0 means no limit. This limit is ignored for streamed response types. Use with server mode only. | `5e7` |
| <code class="text-nowrap">--storage.remote.read-concurrent-limit</code> | Maximum number of concurrent remote read calls. 0 means no limit. Use with server mode only. | `10` |
| <code class="text-nowrap">--storage.remote.read-max-bytes-in-frame</code> | Maximum number of bytes in a single frame for streaming remote read response types before marshalling. Note that client might have limit on frame size as well. 1MB as recommended by protobuf by default. Use with server mode only. | `1048576` |
| <code class="text-nowrap">--web.search.max-limit</code> | Hard upper bound on the "limit" query parameter accepted by the experimental search API (--enable-feature=search-api). Requests with a higher limit are rejected with HTTP 400. 0 disables the cap. Use with server mode only. | `10000` |
| <code class="text-nowrap">--rules.alert.for-outage-tolerance</code> | Max time to tolerate prometheus outage for restoring "for" state of alert. Use with server mode only. | `1h` |
| <code class="text-nowrap">--rules.alert.for-grace-period</code> | Minimum duration between alert and restored "for" state. This is maintained only for alerts with configured "for" time greater than grace period. Use with server mode only. | `10m` |
| <code class="text-nowrap">--rules.alert.resend-delay</code> | Minimum amount of time to wait before resending an alert to Alertmanager. Use with server mode only. | `1m` |
@ -61,7 +63,7 @@ The Prometheus monitoring server
| <code class="text-nowrap">--query.timeout</code> | Maximum time a query may take before being aborted. Use with server mode only. | `2m` |
| <code class="text-nowrap">--query.max-concurrency</code> | Maximum number of queries executed concurrently. Use with server mode only. | `20` |
| <code class="text-nowrap">--query.max-samples</code> | Maximum number of samples a single query can load into memory. Note that queries will fail if they try to load more samples than this into memory, so this also limits the number of samples a query can return. Use with server mode only. | `50000000` |
| <code class="text-nowrap">--enable-feature</code> <code class="text-nowrap">...<code class="text-nowrap"> | Comma separated feature names to enable. Valid options: auto-reload-config, concurrent-rule-eval, created-timestamp-zero-ingestion, delayed-compaction, exemplar-storage, extra-scrape-metrics, memory-snapshot-on-shutdown, metadata-wal-records, old-ui, otlp-deltatocumulative, otlp-native-delta-ingestion, promql-binop-fill-modifiers, promql-delayed-name-removal, promql-experimental-functions, promql-extended-range-selectors, promql-per-step-stats, st-storage, type-and-unit-labels, use-start-timestamps, use-uncached-io, xor2-encoding. See https://prometheus.io/docs/prometheus/latest/feature_flags/ for more details. | |
| <code class="text-nowrap">--enable-feature</code> <code class="text-nowrap">...</code> | Comma separated feature names to enable. Valid options: concurrent-rule-eval, created-timestamp-zero-ingestion, delayed-compaction, exemplar-storage, extra-scrape-metrics, memory-snapshot-on-shutdown, metadata-wal-records, old-ui, otlp-deltatocumulative, otlp-native-delta-ingestion, promql-binop-fill-modifiers, promql-delayed-name-removal, promql-duration-expr, promql-experimental-functions, promql-extended-range-selectors, promql-per-step-stats, search-api, st-storage, st-synthesis, type-and-unit-labels, use-start-timestamps, use-uncached-io, xor2-encoding. See https://prometheus.io/docs/prometheus/latest/feature_flags/ for more details. | |
| <code class="text-nowrap">--agent</code> | Run Prometheus in 'Agent mode'. | |
| <code class="text-nowrap">--log.level</code> | Only log messages with the given severity or above. One of: [debug, info, warn, error] | `info` |
| <code class="text-nowrap">--log.format</code> | Output format of log messages. One of: [logfmt, json] | `logfmt` |

View file

@ -12,7 +12,7 @@ Tooling for the Prometheus monitoring system.
| <code class="text-nowrap">-h</code>, <code class="text-nowrap">--help</code> | Show context-sensitive help (also try --help-long and --help-man). |
| <code class="text-nowrap">--version</code> | Show application version. |
| <code class="text-nowrap">--experimental</code> | Enable experimental commands. |
| <code class="text-nowrap">--enable-feature</code> <code class="text-nowrap">...<code class="text-nowrap"> | Comma separated feature names to enable. Valid options: promql-experimental-functions, promql-delayed-name-removal, promql-extended-range-selectors. See https://prometheus.io/docs/prometheus/latest/feature_flags/ for more details |
| <code class="text-nowrap">--enable-feature</code> <code class="text-nowrap">...</code> | Comma separated feature names to enable. Valid options: promql-experimental-functions, promql-delayed-name-removal, promql-duration-expr, promql-extended-range-selectors. See https://prometheus.io/docs/prometheus/latest/feature_flags/ for more details |
@ -293,7 +293,7 @@ Run series query.
| Flag | Description |
| --- | --- |
| <code class="text-nowrap">--match</code> <code class="text-nowrap">...<code class="text-nowrap"> | Series selector. Can be specified multiple times. |
| <code class="text-nowrap">--match</code> <code class="text-nowrap">...</code> | Series selector. Can be specified multiple times. |
| <code class="text-nowrap">--start</code> | Start time (RFC3339 or Unix timestamp). |
| <code class="text-nowrap">--end</code> | End time (RFC3339 or Unix timestamp). |
@ -321,7 +321,7 @@ Run labels query.
| --- | --- |
| <code class="text-nowrap">--start</code> | Start time (RFC3339 or Unix timestamp). |
| <code class="text-nowrap">--end</code> | End time (RFC3339 or Unix timestamp). |
| <code class="text-nowrap">--match</code> <code class="text-nowrap">...<code class="text-nowrap"> | Series selector. Can be specified multiple times. |
| <code class="text-nowrap">--match</code> <code class="text-nowrap">...</code> | Series selector. Can be specified multiple times. |
@ -350,7 +350,7 @@ Run queries against your Prometheus to analyze the usage pattern of certain metr
| <code class="text-nowrap">--type</code> | Type of metric: histogram. | |
| <code class="text-nowrap">--duration</code> | Time frame to analyze. | `1h` |
| <code class="text-nowrap">--time</code> | Query time (RFC3339 or Unix timestamp), defaults to now. | |
| <code class="text-nowrap">--match</code> <code class="text-nowrap">...<code class="text-nowrap"> | Series selector. Can be specified multiple times. | |
| <code class="text-nowrap">--match</code> <code class="text-nowrap">...</code> | Series selector. Can be specified multiple times. | |
@ -474,7 +474,7 @@ Unit tests for rules.
| Flag | Description | Default |
| --- | --- | --- |
| <code class="text-nowrap">--run</code> <code class="text-nowrap">...<code class="text-nowrap"> | If set, will only run test groups whose names match the regular expression. Can be specified multiple times. | |
| <code class="text-nowrap">--run</code> <code class="text-nowrap">...</code> | If set, will only run test groups whose names match the regular expression. Can be specified multiple times. | |
| <code class="text-nowrap">--debug</code> | Enable unit test debugging. | `false` |
| <code class="text-nowrap">--diff</code> | [Experimental] Print colored differential output between expected & received output. | `false` |
| <code class="text-nowrap">--ignore-unknown-fields</code> | Ignore unknown fields in the test files. This is useful when you want to extend rule files with custom metadata. Ensure that those fields are removed before loading them into the Prometheus server as it performs strict checks by default. | `false` |
@ -593,7 +593,7 @@ Dump data (series+samples or optionally just series) from a TSDB.
| <code class="text-nowrap">--sandbox-dir-root</code> | Root directory where a sandbox directory will be created, this sandbox is used in case WAL replay generates chunks (default is the database path). The sandbox is cleaned up at the end. | |
| <code class="text-nowrap">--min-time</code> | Minimum timestamp to dump, in milliseconds since the Unix epoch. | `-9223372036854775808` |
| <code class="text-nowrap">--max-time</code> | Maximum timestamp to dump, in milliseconds since the Unix epoch. | `9223372036854775807` |
| <code class="text-nowrap">--match</code> <code class="text-nowrap">...<code class="text-nowrap"> | Series selector. Can be specified multiple times. | `{__name__=~'(?s:.*)'}` |
| <code class="text-nowrap">--match</code> <code class="text-nowrap">...</code> | Series selector. Can be specified multiple times. | `{__name__=~'(?s:.*)'}` |
| <code class="text-nowrap">--format</code> | Output format of the dump (prom (default) or seriesjson). | `prom` |
@ -621,7 +621,7 @@ Dump data (series+samples or optionally just series) from a TSDB.
| <code class="text-nowrap">--sandbox-dir-root</code> | Root directory where a sandbox directory will be created, this sandbox is used in case WAL replay generates chunks (default is the database path). The sandbox is cleaned up at the end. | |
| <code class="text-nowrap">--min-time</code> | Minimum timestamp to dump, in milliseconds since the Unix epoch. | `-9223372036854775808` |
| <code class="text-nowrap">--max-time</code> | Maximum timestamp to dump, in milliseconds since the Unix epoch. | `9223372036854775807` |
| <code class="text-nowrap">--match</code> <code class="text-nowrap">...<code class="text-nowrap"> | Series selector. Can be specified multiple times. | `{__name__=~'(?s:.*)'}` |
| <code class="text-nowrap">--match</code> <code class="text-nowrap">...</code> | Series selector. Can be specified multiple times. | `{__name__=~'(?s:.*)'}` |

View file

@ -902,6 +902,7 @@ The following meta labels are available on targets during [relabeling](#relabel_
* `__meta_ec2_ipv6_addresses`: comma separated list of IPv6 addresses assigned to the instance's network interfaces, if present
* `__meta_ec2_owner_id`: the ID of the AWS account that owns the EC2 instance
* `__meta_ec2_platform`: the Operating System platform, set to 'windows' on Windows servers, absent otherwise
* `__meta_ec2_default_ipv6_address`: the first primary IPv6 address found if present, otherwise first non-primary IPv6 address, if present
* `__meta_ec2_primary_ipv6_addresses`: comma separated list of the Primary IPv6 addresses of the instance, if present. The list is ordered based on the position of each corresponding network interface in the attachment order.
* `__meta_ec2_primary_subnet_id`: the subnet ID of the primary network interface, if available
* `__meta_ec2_private_dns_name`: the private DNS name of the instance, if available
@ -1832,6 +1833,7 @@ The following meta labels are available on targets during [relabeling](#relabel_
* `__meta_ec2_ipv6_addresses`: comma separated list of IPv6 addresses assigned to the instance's network interfaces, if present
* `__meta_ec2_owner_id`: the ID of the AWS account that owns the EC2 instance
* `__meta_ec2_platform`: the Operating System platform, set to 'windows' on Windows servers, absent otherwise
* `__meta_ec2_default_ipv6_address`: the first primary IPv6 address found if present, otherwise first non-primary IPv6 address, if present
* `__meta_ec2_primary_ipv6_addresses`: comma separated list of the Primary IPv6 addresses of the instance, if present. The list is ordered based on the position of each corresponding network interface in the attachment order.
* `__meta_ec2_primary_subnet_id`: the subnet ID of the primary network interface, if available
* `__meta_ec2_private_dns_name`: the private DNS name of the instance, if available
@ -3425,7 +3427,8 @@ Initially, aside from the configured per-target labels, a target's `job`
label is set to the `job_name` value of the respective scrape configuration.
You can also use special labels like `__address__`, `__scheme__`, `__metrics_path__`,
`__scrape_interval__`, `__scrape_timeout__` to customize the defined targets. These will
`__scrape_interval__`, `__scrape_timeout__`, `__convert_classic_histograms_to_nhcb__`
to customize the defined targets. These will
override the respective settings in the scrape configuration.
The `__address__` label is set to the `<host>:<port>` address of the target.
@ -3441,6 +3444,13 @@ label is set to the value of the first passed URL parameter called `<name>`, as
The `__scrape_interval__` and `__scrape_timeout__` labels are set to the target's
interval and timeout, as specified in `scrape_config`.
The `__convert_classic_histograms_to_nhcb__` label is set to the target's
`convert_classic_histograms_to_nhcb` value, as specified in `scrape_config`
(defaulting to the configured global). Setting it during relabeling overrides,
per target, whether classic histograms are converted to native histograms with
custom buckets. Its value must parse as a boolean; a target with an invalid
value is dropped.
Additional labels prefixed with `__meta_` may be available during the
relabeling phase. They are set by the service discovery mechanism that provided
the target and vary between mechanisms.

View file

@ -107,6 +107,19 @@ Besides enabling this feature in Prometheus, start timestamps need to be exposed
Enables the use of start timestamps (ST) in PromQL functions such as `rate()`, `irate()`, and `increase()`. This feature doesn't currently work with extended range selectors (`promql-extended-range-selectors`).
## Start timestamp (ST) synthesis
`--enable-feature=st-synthesis`
Enables the synthesis of start timestamps (ST) for cumulative metrics (Counters, Classic Histograms, Native Histograms) when they are not provided by the source. Similar to [the official OpenTelemetry metricstarttimeprocessor](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/processor/metricstarttimeprocessor#strategy-subtract-initial-point), it tracks previous values to detect resets and subtracts the initial reference point to synthesize a zero-based timeline from the first sample.
> NOTE: This is an experimental feature.
> * The first sample is dropped when this feature is turned on to establish the start timestamp reference point. As a result, if a series has only a single point reported, turning this feature on may result in no points being ingested for that series.
> * Synthesis yields accurate Start Timestamp while maintaining accurate counter rates. However, the raw counter values will be different that what's scraped. This is because the first point is dropped and its timestamp is used as the start timestamp for all subsequent points. All subsequent points are normalized against that dropped point (i.e. subtracted by it). Effectively, synthesis create new counter streams with the known start timestamp from the original data.
> * Synthesis works only with scraped data (RW and Otel receiver are not implemented).
> * Synthesis requires ordered samples. As a result, cumulative samples without ST that are out of order will be rejected despite the `tsdb. out_of_order_time_window` setting.
> * If an append fails for a series (e.g., due to out-of-order samples being rejected), the synthesis state for that series is cleared. As a result, the next sample received after the failure will be treated as the first sample again and will be dropped to establish a new reference point.
## Concurrent evaluation of independent rules
`--enable-feature=concurrent-rule-eval`
@ -170,19 +183,6 @@ fixes the possible problem with the feature flag.)
It is possible to craft a query that aggregates by `__name__` and puts samples with and without delayed name removal into the same group. In that case, the name is removed from the affected group. Note that this case hardly occurs in queries that fulfill a practical purpose.
## Auto Reload Config
`--enable-feature=auto-reload-config`
When enabled, Prometheus will automatically reload its configuration file at a
specified interval. The interval is defined by the
`--config.auto-reload-interval` flag, which defaults to `30s`.
Configuration reloads are triggered by detecting changes in the checksum of the
main configuration file or any referenced files, such as rule and scrape
configurations. To ensure consistency and avoid issues during reloads, it's
recommended to update these files atomically.
## OTLP Delta Conversion
`--enable-feature=otlp-deltatocumulative`
@ -205,6 +205,66 @@ state is mutex guarded. Cumulative-only OTLP requests are not affected.
[d2c]: https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/processor/deltatocumulativeprocessor
## PromQL arithmetic expressions in time durations
`--enable-feature=promql-duration-expr`
With this flag, arithmetic expressions can be used in time durations in range queries and offset durations.
In range queries:
```
rate(http_requests_total[5m * 2]) # 10 minute range
rate(http_requests_total[(5+2) * 1m]) # 7 minute range
```
In offset durations:
```
http_requests_total offset (1h / 2) # 30 minute offset
http_requests_total offset ((2 ^ 3) * 1m) # 8 minute offset
```
When using offset with duration expressions, you must wrap the expression in
parentheses. Without parentheses, only the first duration value will be used in
the offset calculation.
`step()` can be used in duration expressions.
For a **range query**, it resolves to the step width of the range query.
For an **instant query**, it resolves to `0s`.
`range()` can be used in duration expressions.
For a **range query**, it resolves to the full range of the query (end time - start time).
For an **instant query**, it resolves to `0s`.
This is particularly useful in combination with `@end()` to look back over the entire query range, e.g., `max_over_time(metric[range()] @ end())`.
`min_of(<duration>, <duration>)` and `max_of(<duration>, <duration>)` select between two duration expressions.
`min_of` returns the smaller of the two, which is useful for capping a duration at a maximum value.
`max_of` returns the larger of the two, which is useful for enforcing a minimum value.
For example, `max_of(step(), 5s)` ensures the duration is never shorter than `5s`, while `min_of(range(), 1h)` caps the duration at `1h`.
**Note**: Duration expressions are not supported in the @ timestamp operator.
The following operators are supported:
* `+` - addition
* `-` - subtraction
* `*` - multiplication
* `/` - division
* `%` - modulo
* `^` - exponentiation
Examples of equivalent durations:
* `5m * 2` is equivalent to `10m` or `600s`
* `10m - 1m` is equivalent to `9m` or `540s`
* `(5+2) * 1m` is equivalent to `7m` or `420s`
* `1h / 2` is equivalent to `30m` or `1800s`
* `4h % 3h` is equivalent to `1h` or `3600s`
* `(2 ^ 3) * 1m` is equivalent to `8m` or `480s`
* `step() + 1` is equivalent to the query step width increased by 1s.
* `max_of(step(), 5s)` is equivalent to the larger of the query step width and `5s`.
* `min_of(2 * step() + 5s, 5m)` is equivalent to the smaller of twice the query step increased by `5s` and `5m`.
## OTLP Native Delta Support
`--enable-feature=otlp-native-delta-ingestion`
@ -344,3 +404,21 @@ Example query:
```
See [the fill modifiers documentation](querying/operators.md#filling-in-missing-matches) for more details and examples.
## Search API
`--enable-feature=search-api`
Enables the experimental search API endpoints for discovering metric names,
label names, and label values with fuzzy matching and filtering support. See
[the search API documentation](querying/api.md#searching-metric-names-label-names-and-label-values)
for details.
The `--web.search.max-limit` flag (default `10000`) bounds the `limit` query
parameter accepted by the search endpoints. Requests with a higher `limit` are
rejected with HTTP 400. The default response limit (100) is silently clamped
to this maximum, so an operator setting a smaller cap does not break
no-`limit` requests. Setting the flag to `0` disables the cap entirely; this
is **not recommended** for endpoints exposed beyond a trusted network because a
single client can then request the entire index in one response.

View file

@ -101,7 +101,7 @@ URL query parameters:
- `timeout=<duration>`: Evaluation timeout. Optional. Defaults to and
is capped by the value of the `-query.timeout` flag.
- `limit=<number>`: Maximum number of returned series. Doesn't affect scalars or strings but truncates the number of series for matrices and vectors. Optional. 0 means disabled.
- `lookback_delta=<duration | float>`: Override the the [lookback period](#staleness) just for this query in `duration` format or float number of seconds. Optional.
- `lookback_delta=<duration | float>`: Override the [lookback period](#staleness) just for this query in `duration` format or float number of seconds. Optional.
- `stats=<string>`: Include query statistics in the response. If set to `all`, includes detailed statistics. Optional.
The current server time is used if the `time` parameter is omitted.
@ -175,7 +175,7 @@ URL query parameters:
- `timeout=<duration>`: Evaluation timeout. Optional. Defaults to and
is capped by the value of the `-query.timeout` flag.
- `limit=<number>`: Maximum number of returned series. Optional. 0 means disabled.
- `lookback_delta=<duration | float>`: Override the the [lookback period](#staleness) just for this query in `duration` format or float number of seconds. Optional.
- `lookback_delta=<duration | float>`: Override the [lookback period](#staleness) just for this query in `duration` format or float number of seconds. Optional.
- `stats=<string>`: Include query statistics in the response. If set to `all`, includes detailed statistics. Optional.
You can URL-encode these parameters directly in the request body by using the `POST` method and
@ -521,6 +521,114 @@ curl http://localhost:9090/api/v1/label/U__http_2e_status_code/values
}
```
### Searching metric names, label names, and label values
These endpoints are experimental and must be enabled with
`--enable-feature=search-api`.
The following endpoints provide streamed discovery results for metric names,
label names, and label values:
```
GET /api/v1/search/metric_names
POST /api/v1/search/metric_names
GET /api/v1/search/label_names
POST /api/v1/search/label_names
GET /api/v1/search/label_values
POST /api/v1/search/label_values
```
These endpoints return newline-delimited JSON with content type
`application/x-ndjson`. The stream contract is:
- Zero or more **batch lines**, each with a `results` array and an optional
`warnings` array.
- The stream then ends with **either** a **trailer line** (`status`, `has_more`,
optional `warnings`) **or** an **error line** (`status`, `errorType`, `error`)
if iteration failed mid-stream after the first batch was sent.
```json
{"results":[{"name":"http_requests_total","type":"counter","help":"Total HTTP requests."}]}
{"status":"success","has_more":false}
```
If an error occurs **before** streaming starts, the API returns the usual
Prometheus JSON error object with a 4xx/5xx status code. If an error occurs
**after** streaming starts, the stream ends with an NDJSON error line in place
of the trailer.
Clients must tolerate an abrupt EOF without a trailer (for example, on
transport failure or server shutdown) and must ignore unknown fields in the
trailer for forward compatibility.
The `has_more` field in the trailer is informational only: this version of
the API does not provide a pagination cursor. To retrieve more results, raise
`limit` (subject to the operator-configured `--web.search.max-limit`) or narrow
the request via `match[]`. A future version of the API may add a cursor.
Common URL query parameters:
- `match[]=<series_selector>`: Repeated series selector used to scope the
search. Optional.
- `search[]=<string>`: Repeated search string matched against names or values.
Multiple values use OR semantics. Optional.
- `fuzz_threshold=<number>`: Fuzzy threshold from 0 to 100. Optional. A value
of 0 is the lowest fuzzy threshold.
- `fuzz_alg=<subsequence | jarowinkler>`: Matching algorithm. Optional. Default
is `subsequence`.
- `case_sensitive=<bool>`: Toggle case-sensitive matching. Optional.
- `sort_by=<string>`: Sort mode. Supported values depend on the endpoint.
- `sort_dir=<asc | dsc>`: Sort direction. Optional. Only valid with
`sort_by=alpha`.
- `include_score=<bool>`: Include the relevance score in each result. Optional.
- `start=<rfc3339 | unix_timestamp>`: Start timestamp. Optional.
- `end=<rfc3339 | unix_timestamp>`: End timestamp. Optional.
- `limit=<number>`: Maximum number of returned results. Optional. Default is
100.
- `batch_size=<number>`: Preferred number of results per NDJSON batch.
Optional. Default is 100.
The `start` and `end` parameters narrow results to the selected time window.
Results may include values from series active slightly outside that window,
because Prometheus stores data in fixed-size blocks (typically 2 hours each).
Additional parameters for `/api/v1/search/metric_names`:
- `include_metadata=<bool>`: Include metric metadata in each result.
- `sort_by=<alpha | score>`
Additional parameters for `/api/v1/search/label_names`:
- `sort_by=<alpha | score>`
Additional parameters for `/api/v1/search/label_values`:
- `label=<label_name>`: Label name whose values should be searched. Required.
- `sort_by=<alpha | score>`
This example searches metric names for autocomplete:
```bash
curl -g 'http://localhost:9090/api/v1/search/metric_names?search[]=http_req&sort_by=score&include_metadata=true&limit=5'
```
```json
{"results":[{"name":"http_requests_total","type":"counter","help":"Total HTTP requests."}]}
{"status":"success","has_more":false}
```
This example searches label values for the `instance` label within the `up`
metric:
```bash
curl -g 'http://localhost:9090/api/v1/search/label_values?label=instance&match[]=up&search[]=909&sort_by=score'
```
```json
{"results":[{"value":"localhost:9090"},{"value":"localhost:9091"}]}
{"status":"success","has_more":true}
```
## Querying exemplars
This is **experimental** and might change in the future.
@ -766,6 +874,7 @@ curl http://localhost:9090/api/v1/targets
{
"discoveredLabels": {
"__address__": "127.0.0.1:9100",
"__convert_classic_histograms_to_nhcb__": "false",
"__metrics_path__": "/metrics",
"__scheme__": "http",
"__scrape_interval__": "1m",

View file

@ -174,57 +174,6 @@ Examples:
12h34m56s # Equivalent to 45296s and thus 45296.
54s321ms # Equivalent to 54.321.
#### Duration expressions
Duration expressions can be used in range selectors, subquery range and
resolution fields, and offset durations.
Examples:
rate(http_requests_total[5m * 2]) # 10 minute range.
rate(http_requests_total[(5 + 2) * 1m]) # 7 minute range.
http_requests_total offset (1h / 2) # 30 minute offset.
http_requests_total offset ((2 ^ 3) * 1m) # 8 minute offset.
When using offset with duration expressions, you must wrap the expression in
parentheses. Without parentheses, only the first duration value will be used in
the offset calculation.
`step()` can be used in duration expressions. For a range query, it resolves to
the step width of the range query. For an instant query, it resolves to `0s`.
`range()` can be used in duration expressions. For a range query, it resolves to
the full range of the query (end time minus start time). For an instant query,
it resolves to `0s`. This is particularly useful in combination with `@ end()`
to look back over the entire query range, e.g.,
`max_over_time(metric[range()] @ end())`.
`min(<duration>, <duration>)` and `max(<duration>, <duration>)` can be used to
find the minimum or maximum of two duration expressions.
Duration expressions are not supported in the @ timestamp operator.
The following operators are supported:
* `+` - addition.
* `-` - subtraction.
* `*` - multiplication.
* `/` - division.
* `%` - modulo.
* `^` - exponentiation.
Examples of equivalent durations:
* `5m * 2` is equivalent to `10m` or `600s`.
* `10m - 1m` is equivalent to `9m` or `540s`.
* `(5 + 2) * 1m` is equivalent to `7m` or `420s`.
* `1h / 2` is equivalent to `30m` or `1800s`.
* `4h % 3h` is equivalent to `1h` or `3600s`.
* `(2 ^ 3) * 1m` is equivalent to `8m` or `480s`.
* `step() + 1` is equivalent to the query step width increased by 1s.
* `max(step(), 5s)` is equivalent to the larger of the query step width and `5s`.
* `min(2 * step() + 5s, 5m)` is equivalent to the smaller of twice the query step increased by `5s` and `5m`.
## Time series selectors
These are the basic building-blocks that instruct PromQL what data to fetch.
@ -333,13 +282,14 @@ A workaround for this restriction is to use the `__name__` label:
Range vector literals work like instant vector literals, except that they
select a range of samples back from the current instant. Syntactically, a
[duration](#float-literals-and-time-durations) is appended in square brackets
(`[]`) at the end of a vector selector to specify how far back in time values
should be fetched for each resulting range vector element. Commonly, this uses
one or more time units, e.g. `[5m]`. The range is a left-open and right-closed
interval, i.e. samples with timestamps coinciding with the left boundary of the
range are excluded from the selection, while samples coinciding with the right
boundary of the range are included in the selection.
[float literal](#float-literals-and-time-durations) is appended in square
brackets (`[]`) at the end of a vector selector to specify for how many seconds
back in time values should be fetched for each resulting range vector element.
Commonly, the float literal uses the syntax with one or more time units, e.g.
`[5m]`. The range is a left-open and right-closed interval, i.e. samples with
timestamps coinciding with the left boundary of the range are excluded from the
selection, while samples coinciding with the right boundary of the range are
included in the selection.
In this example, we select all the values recorded less than 5m ago for all
time series that have the metric name `http_requests_total` and a `job` label
@ -429,9 +379,8 @@ Note that the `@` modifier allows a query to look ahead of its evaluation time.
Subquery allows you to run an instant query for a given range and resolution. The result of a subquery is a range vector.
Syntax: `<instant_query> '[' <range> ':' [<resolution>] ']' [ @ <float_literal> ] [ offset <duration> ]`
Syntax: `<instant_query> '[' <range> ':' [<resolution>] ']' [ @ <float_literal> ] [ offset <float_literal> ]`
* `<range>`, `<resolution>`, and `offset` support duration expressions.
* `<resolution>` is optional. Default is the global evaluation interval.
## Operators

View file

@ -693,6 +693,24 @@ This second example has the same effect than the first example, and illustrates
label_replace(up{job="api-server",service="a:c"}, "foo", "$name", "service", "(?P<name>.*):(?P<version>.*)")
```
## `max_of()`
**This function has to be enabled via the [feature
flag](../feature_flags.md#experimental-promql-functions)
`--enable-feature=promql-experimental-functions`.**
`max_of(a scalar, b scalar)` returns the larger of the two scalar values `a`
and `b`.
## `min_of()`
**This function has to be enabled via the [feature
flag](../feature_flags.md#experimental-promql-functions)
`--enable-feature=promql-experimental-functions`.**
`min_of(a scalar, b scalar)` returns the smaller of the two scalar values `a`
and `b`.
## `ln()`
`ln(v instant-vector)` calculates the natural logarithm for all float samples
@ -961,7 +979,8 @@ These functions act on histograms in the following way:
select the first sample of `m` _within_ the 1m range, where `m offset 1m` will
select the most recent sample within the lookback interval _outside and prior
to_ the 1m offset. This is particularly useful with `first_over_time(m[step()])`
in range queries to ensure that the sample selected is within the range step.
in range queries (available when `--enable-feature=promql-duration-expr` is set)
to ensure that the sample selected is within the range step.
## Trigonometric Functions

View file

@ -104,7 +104,10 @@ func printV2(req *writev2.Request) error {
if err != nil {
return err
}
m := ts.ToMetadata(req.Symbols)
m, err := ts.ToMetadata(req.Symbols)
if err != nil {
return err
}
fmt.Println(l, m)
for _, s := range ts.Samples {

View file

@ -14,72 +14,72 @@ require (
)
require (
cloud.google.com/go/auth v0.18.2 // indirect
cloud.google.com/go/auth v0.20.0 // indirect
cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect
cloud.google.com/go/compute/metadata v0.9.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.21.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.21.1 // indirect
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.1 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.12.0 // indirect
github.com/AzureAD/microsoft-authentication-library-for-go v1.6.0 // indirect
github.com/Microsoft/go-winio v0.6.2 // indirect
github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b // indirect
github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect
github.com/aws/aws-sdk-go-v2 v1.41.4 // indirect
github.com/aws/aws-sdk-go-v2/config v1.32.12 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.19.12 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.20 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.20 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.20 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.6 // indirect
github.com/aws/aws-sdk-go-v2/service/ec2 v1.296.0 // indirect
github.com/aws/aws-sdk-go-v2/service/ecs v1.74.0 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.7 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.20 // indirect
github.com/aws/aws-sdk-go-v2/service/lightsail v1.51.0 // indirect
github.com/aws/aws-sdk-go-v2/service/signin v1.0.8 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.30.13 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.17 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.41.9 // indirect
github.com/aws/smithy-go v1.24.2 // indirect
github.com/aws/aws-sdk-go-v2 v1.41.7 // indirect
github.com/aws/aws-sdk-go-v2/config v1.32.18 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.19.17 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.23 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.23 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.23 // indirect
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.24 // indirect
github.com/aws/aws-sdk-go-v2/service/ec2 v1.304.0 // indirect
github.com/aws/aws-sdk-go-v2/service/ecs v1.81.0 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.9 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.23 // indirect
github.com/aws/aws-sdk-go-v2/service/lightsail v1.54.0 // indirect
github.com/aws/aws-sdk-go-v2/service/signin v1.0.11 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.30.17 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.36.0 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.42.1 // indirect
github.com/aws/smithy-go v1.26.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/dennwc/varint v1.0.0 // indirect
github.com/digitalocean/godo v1.178.0 // indirect
github.com/digitalocean/godo v1.193.0 // indirect
github.com/distribution/reference v0.6.0 // indirect
github.com/docker/go-connections v0.6.0 // indirect
github.com/envoyproxy/go-control-plane/envoy v1.37.0 // indirect
github.com/envoyproxy/protoc-gen-validate v1.3.3 // indirect
github.com/docker/go-connections v0.7.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fsnotify/fsnotify v1.10.1 // indirect
github.com/go-logr/logr v1.4.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-openapi/jsonpointer v0.22.5 // indirect
github.com/go-openapi/jsonreference v0.21.4 // indirect
github.com/go-openapi/swag v0.25.4 // indirect
github.com/go-openapi/swag/jsonname v0.25.5 // indirect
github.com/go-openapi/jsonpointer v0.23.1 // indirect
github.com/go-openapi/jsonreference v0.21.5 // indirect
github.com/go-openapi/swag v0.25.5 // indirect
github.com/go-openapi/swag/jsonname v0.26.0 // indirect
github.com/go-viper/mapstructure/v2 v2.5.0 // indirect
github.com/gobwas/glob v0.2.3 // indirect
github.com/golang-jwt/jwt/v5 v5.3.1 // indirect
github.com/google/s2a-go v0.1.9 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.14 // indirect
github.com/googleapis/gax-go/v2 v2.18.0 // indirect
github.com/gophercloud/gophercloud/v2 v2.11.1 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.15 // indirect
github.com/googleapis/gax-go/v2 v2.22.0 // indirect
github.com/gophercloud/gophercloud/v2 v2.12.0 // indirect
github.com/grafana/regexp v0.0.0-20250905093917-f7b3be9d1853 // indirect
github.com/hashicorp/consul/api v1.32.1 // indirect
github.com/hashicorp/go-version v1.8.0 // indirect
github.com/hashicorp/nomad/api v0.0.0-20260324203407-b27b0c2e019a // indirect
github.com/hetznercloud/hcloud-go/v2 v2.36.0 // indirect
github.com/hashicorp/go-retryablehttp v0.7.8 // indirect
github.com/hashicorp/go-version v1.9.0 // indirect
github.com/hashicorp/nomad/api v0.0.0-20260528135333-5b027732945f // indirect
github.com/hetznercloud/hcloud-go/v2 v2.41.2 // indirect
github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839 // indirect
github.com/ionos-cloud/sdk-go/v6 v6.3.6 // indirect
github.com/ionos-cloud/sdk-go/v6 v6.3.7 // indirect
github.com/jpillora/backoff v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/compress v1.18.5 // indirect
github.com/klauspost/compress v1.18.6 // indirect
github.com/knadh/koanf/maps v0.1.2 // indirect
github.com/knadh/koanf/providers/confmap v1.0.0 // indirect
github.com/knadh/koanf/v2 v2.3.3 // indirect
github.com/knadh/koanf/v2 v2.3.4 // indirect
github.com/kylelemons/godebug v1.1.0 // indirect
github.com/linode/linodego v1.66.0 // indirect
github.com/linode/linodego v1.69.1 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect
github.com/miekg/dns v1.1.72 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
@ -89,53 +89,54 @@ require (
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect
github.com/oapi-codegen/runtime v1.0.0 // indirect
github.com/open-telemetry/opentelemetry-collector-contrib/internal/exp/metrics v0.148.0 // indirect
github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatautil v0.148.0 // indirect
github.com/open-telemetry/opentelemetry-collector-contrib/processor/deltatocumulativeprocessor v0.148.0 // indirect
github.com/open-telemetry/opentelemetry-collector-contrib/internal/exp/metrics v0.153.0 // indirect
github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatautil v0.153.0 // indirect
github.com/open-telemetry/opentelemetry-collector-contrib/processor/deltatocumulativeprocessor v0.153.0 // indirect
github.com/opencontainers/image-spec v1.1.1 // indirect
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/prometheus/client_golang/exp v0.0.0-20260325093428-d8591d0db856 // indirect
github.com/prometheus/client_golang/exp v0.0.0-20260518105423-c9d5bc4c50a9 // indirect
github.com/prometheus/client_model v0.6.2 // indirect
github.com/prometheus/otlptranslator v1.0.0 // indirect
github.com/prometheus/procfs v0.16.1 // indirect
github.com/prometheus/sigv4 v0.4.1 // indirect
github.com/puzpuzpuz/xsync/v4 v4.4.0 // indirect
github.com/puzpuzpuz/xsync/v4 v4.5.0 // indirect
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.36 // indirect
github.com/spf13/pflag v1.0.10 // indirect
github.com/stackitcloud/stackit-sdk-go/core v0.23.0 // indirect
github.com/stackitcloud/stackit-sdk-go/core v0.26.0 // indirect
github.com/xhit/go-str2duration/v2 v2.1.0 // indirect
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
go.opentelemetry.io/collector/component v1.54.0 // indirect
go.opentelemetry.io/collector/confmap v1.54.0 // indirect
go.opentelemetry.io/collector/confmap/xconfmap v0.148.0 // indirect
go.opentelemetry.io/collector/consumer v1.54.0 // indirect
go.opentelemetry.io/collector/featuregate v1.54.0 // indirect
go.opentelemetry.io/collector/internal/componentalias v0.148.0 // indirect
go.opentelemetry.io/collector/pdata v1.54.0 // indirect
go.opentelemetry.io/collector/pipeline v1.54.0 // indirect
go.opentelemetry.io/collector/processor v1.54.0 // indirect
go.opentelemetry.io/collector/component v1.59.0 // indirect
go.opentelemetry.io/collector/confmap v1.59.0 // indirect
go.opentelemetry.io/collector/confmap/xconfmap v0.153.0 // indirect
go.opentelemetry.io/collector/consumer v1.59.0 // indirect
go.opentelemetry.io/collector/featuregate v1.59.0 // indirect
go.opentelemetry.io/collector/internal/componentalias v0.153.0 // indirect
go.opentelemetry.io/collector/pdata v1.59.0 // indirect
go.opentelemetry.io/collector/pipeline v1.59.0 // indirect
go.opentelemetry.io/collector/processor v1.59.0 // indirect
go.opentelemetry.io/collector/semconv v0.128.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.67.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.67.0 // indirect
go.opentelemetry.io/otel v1.42.0 // indirect
go.opentelemetry.io/otel/metric v1.42.0 // indirect
go.opentelemetry.io/otel/trace v1.42.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.69.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0 // indirect
go.opentelemetry.io/otel v1.44.0 // indirect
go.opentelemetry.io/otel/metric v1.44.0 // indirect
go.opentelemetry.io/otel/trace v1.44.0 // indirect
go.uber.org/atomic v1.11.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.27.1 // indirect
go.uber.org/zap v1.28.0 // indirect
go.yaml.in/yaml/v2 v2.4.4 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect
golang.org/x/crypto v0.49.0 // indirect
golang.org/x/net v0.52.0 // indirect
golang.org/x/crypto v0.51.0 // indirect
golang.org/x/mod v0.36.0 // indirect
golang.org/x/net v0.55.0 // indirect
golang.org/x/oauth2 v0.36.0 // indirect
golang.org/x/sys v0.42.0 // indirect
golang.org/x/text v0.35.0 // indirect
golang.org/x/sys v0.45.0 // indirect
golang.org/x/text v0.37.0 // indirect
golang.org/x/time v0.15.0 // indirect
google.golang.org/api v0.272.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20260319201613-d00831a3d3e7 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20260311181403-84a4fc48630c // indirect
google.golang.org/grpc v1.79.3 // indirect
google.golang.org/api v0.278.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa // indirect
google.golang.org/grpc v1.81.1 // indirect
google.golang.org/protobuf v1.36.11 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/apimachinery v0.35.3 // indirect

View file

@ -1,17 +1,17 @@
cloud.google.com/go/auth v0.18.2 h1:+Nbt5Ev0xEqxlNjd6c+yYUeosQ5TtEUaNcN/3FozlaM=
cloud.google.com/go/auth v0.18.2/go.mod h1:xD+oY7gcahcu7G2SG2DsBerfFxgPAJz17zz2joOFF3M=
cloud.google.com/go/auth v0.20.0 h1:kXTssoVb4azsVDoUiF8KvxAqrsQcQtB53DcSgta74CA=
cloud.google.com/go/auth v0.20.0/go.mod h1:942/yi/itH1SsmpyrbnTMDgGfdy2BUqIKyd0cyYLc5Q=
cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc=
cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c=
cloud.google.com/go/compute/metadata v0.9.0 h1:pDUj4QMoPejqq20dK0Pg2N4yG9zIkYGdBtwLoEkH9Zs=
cloud.google.com/go/compute/metadata v0.9.0/go.mod h1:E0bWwX5wTnLPedCKqk3pJmVgCBSM6qQI1yTBdEb3C10=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.21.0 h1:fou+2+WFTib47nS+nz/ozhEBnvU96bKHy6LjRsY4E28=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.21.0/go.mod h1:t76Ruy8AHvUAC8GfMWJMa0ElSbuIcO03NLpynfbgsPA=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.21.1 h1:jHb/wfvRikGdxMXYV3QG/SzUOPYN9KEUUuC0Yd0/vC0=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.21.1/go.mod h1:pzBXCYn05zvYIrwLgtK8Ap8QcjRg+0i76tMQdWN6wOk=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.1 h1:Hk5QBxZQC1jb2Fwj6mpzme37xbCDdNTxU7O9eb5+LB4=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.1/go.mod h1:IYus9qsFobWIc2YVwe/WPjcnyCkPKtnHAqUYeebc8z0=
github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2 h1:yz1bePFlP5Vws5+8ez6T3HWXPmwOK7Yvq8QxDBD3SKY=
github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2/go.mod h1:Pa9ZNPuoNu/GztvBSKk9J1cDJW6vk/n0zLtV4mgd8N8=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2 h1:9iefClla7iYpfYWdzPCRDozdmndjTm8DXdpCzPajMgA=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2/go.mod h1:XtLgD3ZD34DAaVIIAyG3objl5DynM3CQ/vMcbBNJZGI=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.12.0 h1:fhqpLE3UEXi9lPaBRpQ6XuRW0nU7hgg4zlmZZa+a9q4=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.12.0/go.mod h1:7dCRMLwisfRH3dBupKeNCioWYUZ4SS09Z14H+7i8ZoY=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5 v5.7.0 h1:LkHbJbgF3YyvC53aqYGR+wWQDn2Rdp9AQdGndf9QvY4=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5 v5.7.0/go.mod h1:QyiQdW4f4/BIfB8ZutZ2s+28RAgfa/pT+zS++ZHyM1I=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v4 v4.3.0 h1:bXwSugBiSbgtz7rOtbfGf+woewp4f06orW9OP5BjHLA=
@ -33,40 +33,40 @@ github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7D
github.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP2+08jFMw88y4klk=
github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA=
github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4=
github.com/aws/aws-sdk-go-v2 v1.41.4 h1:10f50G7WyU02T56ox1wWXq+zTX9I1zxG46HYuG1hH/k=
github.com/aws/aws-sdk-go-v2 v1.41.4/go.mod h1:mwsPRE8ceUUpiTgF7QmQIJ7lgsKUPQOUl3o72QBrE1o=
github.com/aws/aws-sdk-go-v2/config v1.32.12 h1:O3csC7HUGn2895eNrLytOJQdoL2xyJy0iYXhoZ1OmP0=
github.com/aws/aws-sdk-go-v2/config v1.32.12/go.mod h1:96zTvoOFR4FURjI+/5wY1vc1ABceROO4lWgWJuxgy0g=
github.com/aws/aws-sdk-go-v2/credentials v1.19.12 h1:oqtA6v+y5fZg//tcTWahyN9PEn5eDU/Wpvc2+kJ4aY8=
github.com/aws/aws-sdk-go-v2/credentials v1.19.12/go.mod h1:U3R1RtSHx6NB0DvEQFGyf/0sbrpJrluENHdPy1j/3TE=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.20 h1:zOgq3uezl5nznfoK3ODuqbhVg1JzAGDUhXOsU0IDCAo=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.20/go.mod h1:z/MVwUARehy6GAg/yQ1GO2IMl0k++cu1ohP9zo887wE=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.20 h1:CNXO7mvgThFGqOFgbNAP2nol2qAWBOGfqR/7tQlvLmc=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.20/go.mod h1:oydPDJKcfMhgfcgBUZaG+toBbwy8yPWubJXBVERtI4o=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.20 h1:tN6W/hg+pkM+tf9XDkWUbDEjGLb+raoBMFsTodcoYKw=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.20/go.mod h1:YJ898MhD067hSHA6xYCx5ts/jEd8BSOLtQDL3iZsvbc=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.6 h1:qYQ4pzQ2Oz6WpQ8T3HvGHnZydA72MnLuFK9tJwmrbHw=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.6/go.mod h1:O3h0IK87yXci+kg6flUKzJnWeziQUKciKrLjcatSNcY=
github.com/aws/aws-sdk-go-v2/service/ec2 v1.296.0 h1:98Miqj16un1WLNyM1RjVDhXYumhqZrQfAeG8i4jPG6o=
github.com/aws/aws-sdk-go-v2/service/ec2 v1.296.0/go.mod h1:T6ndRfdhnXLIY5oKBHjYZDVj706los2zGdpThppquvA=
github.com/aws/aws-sdk-go-v2/service/ecs v1.74.0 h1:YS5TXaEvzDb+sV+wdQFUtuCAk0GeFR9Ai6HFdxpz6q8=
github.com/aws/aws-sdk-go-v2/service/ecs v1.74.0/go.mod h1:10kBgdaNJz0FO/+JWDUH+0rtSjkn5yafgavDDmmhFzs=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.7 h1:5EniKhLZe4xzL7a+fU3C2tfUN4nWIqlLesfrjkuPFTY=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.7/go.mod h1:x0nZssQ3qZSnIcePWLvcoFisRXJzcTVvYpAAdYX8+GI=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.20 h1:2HvVAIq+YqgGotK6EkMf+KIEqTISmTYh5zLpYyeTo1Y=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.20/go.mod h1:V4X406Y666khGa8ghKmphma/7C0DAtEQYhkq9z4vpbk=
github.com/aws/aws-sdk-go-v2/service/lightsail v1.51.0 h1:cg6PxzoIide2wiEyLfikOFN+XwHafwR8p5+L9U1E8dQ=
github.com/aws/aws-sdk-go-v2/service/lightsail v1.51.0/go.mod h1:YvX7hjUWecrKX8fBkbEncyddEW85xjNH+u5JHioITOw=
github.com/aws/aws-sdk-go-v2/service/signin v1.0.8 h1:0GFOLzEbOyZABS3PhYfBIx2rNBACYcKty+XGkTgw1ow=
github.com/aws/aws-sdk-go-v2/service/signin v1.0.8/go.mod h1:LXypKvk85AROkKhOG6/YEcHFPoX+prKTowKnVdcaIxE=
github.com/aws/aws-sdk-go-v2/service/sso v1.30.13 h1:kiIDLZ005EcKomYYITtfsjn7dtOwHDOFy7IbPXKek2o=
github.com/aws/aws-sdk-go-v2/service/sso v1.30.13/go.mod h1:2h/xGEowcW/g38g06g3KpRWDlT+OTfxxI0o1KqayAB8=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.17 h1:jzKAXIlhZhJbnYwHbvUQZEB8KfgAEuG0dc08Bkda7NU=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.17/go.mod h1:Al9fFsXjv4KfbzQHGe6V4NZSZQXecFcvaIF4e70FoRA=
github.com/aws/aws-sdk-go-v2/service/sts v1.41.9 h1:Cng+OOwCHmFljXIxpEVXAGMnBia8MSU6Ch5i9PgBkcU=
github.com/aws/aws-sdk-go-v2/service/sts v1.41.9/go.mod h1:LrlIndBDdjA/EeXeyNBle+gyCwTlizzW5ycgWnvIxkk=
github.com/aws/smithy-go v1.24.2 h1:FzA3bu/nt/vDvmnkg+R8Xl46gmzEDam6mZ1hzmwXFng=
github.com/aws/smithy-go v1.24.2/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc=
github.com/aws/aws-sdk-go-v2 v1.41.7 h1:DWpAJt66FmnnaRIOT/8ASTucrvuDPZASqhhLey6tLY8=
github.com/aws/aws-sdk-go-v2 v1.41.7/go.mod h1:4LAfZOPHNVNQEckOACQx60Y8pSRjIkNZQz1w92xpMJc=
github.com/aws/aws-sdk-go-v2/config v1.32.18 h1:Hcia46bxhGgF3BaSnG8nSNCWmqTK6bj9xN9/FJ3WK6Q=
github.com/aws/aws-sdk-go-v2/config v1.32.18/go.mod h1:zEjCAYmxqDadH1WX8CdBvmLKhUEUVFgKRQG38zjDmrY=
github.com/aws/aws-sdk-go-v2/credentials v1.19.17 h1:gP2nkGsS+KMvF/jfFz2Vv2qiiOqWKyPACSzPsqHgoW8=
github.com/aws/aws-sdk-go-v2/credentials v1.19.17/go.mod h1:Bsew3S/moG5iT77giPj1q8wb/s0RE5/QfH+ASjYtuQc=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.23 h1:UuSfcORqNSz/ey3VPRS8TcVH2Ikf0/sC+Hdj400QI6U=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.23/go.mod h1:+G/OSGiOFnSOkYloKj/9M35s74LgVAdJBSD5lsFfqKg=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.23 h1:GpT/TrnBYuE5gan2cZbTtvP+JlHsutdmlV2YfEyNde0=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.23/go.mod h1:xYWD6BS9ywC5bS3sz9Xh04whO/hzK2plt2Zkyrp4JuA=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.23 h1:bpd8vxhlQi2r1hiueOw02f/duEPTMK59Q4QMAoTTtTo=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.23/go.mod h1:15DfR2nw+CRHIk0tqNyifu3G1YdAOy68RftkhMDDwYk=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.24 h1:OQqn11BtaYv1WLUowvcA30MpzIu8Ti4pcLPIIyoKZrA=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.24/go.mod h1:X5ZJyfwVrWA96GzPmUCWFQaEARPR7gCrpq2E92PJwAE=
github.com/aws/aws-sdk-go-v2/service/ec2 v1.304.0 h1:wZthLlYdKxBo7NpWLbl0A/8DB/QNDB+8RJa9WboK9Q0=
github.com/aws/aws-sdk-go-v2/service/ec2 v1.304.0/go.mod h1:Y95W0Hm6FYLPa6o0hbnJ+sWgmdc4ifcLFjGkdobWVhY=
github.com/aws/aws-sdk-go-v2/service/ecs v1.81.0 h1:2Sp9EwK7giQpJnQ54k0zdUh6aykmmbpEurEEygr104c=
github.com/aws/aws-sdk-go-v2/service/ecs v1.81.0/go.mod h1:TIKZ9zIFS6W2k9FeW+r5sGVnlxp+aUt9oQ/St3Suj1o=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.9 h1:FLudkZLt5ci0ozzgkVo8BJGwvqNaZbTWb3UcucAateA=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.9/go.mod h1:w7wZ/s9qK7c8g4al+UyoF1Sp/Z45UwMGcqIzLWVQHWk=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.23 h1:pbrxO/kuIwgEsOPLkaHu0O+m4fNgLU8B3vxQ+72jTPw=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.23/go.mod h1:/CMNUqoj46HpS3MNRDEDIwcgEnrtZlKRaHNaHxIFpNA=
github.com/aws/aws-sdk-go-v2/service/lightsail v1.54.0 h1:07DKnL5eKSel3XEM2UxlD/z9zUZZ6XMHLGDXkAdY4u8=
github.com/aws/aws-sdk-go-v2/service/lightsail v1.54.0/go.mod h1:Etcg8xorq1b0g0V2KMNgFjubYITZseJv08qtX/3szko=
github.com/aws/aws-sdk-go-v2/service/signin v1.0.11 h1:TdJ+HdzOBhU8+iVAOGUTU63VXopcumCOF1paFulHWZc=
github.com/aws/aws-sdk-go-v2/service/signin v1.0.11/go.mod h1:R82ZRExE/nheo0N+T8zHPcLRTcH8MGsnR3BiVGX0TwI=
github.com/aws/aws-sdk-go-v2/service/sso v1.30.17 h1:7byT8HUWrgoRp6sXjxtZwgOKfhss5fW6SkLBtqzgRoE=
github.com/aws/aws-sdk-go-v2/service/sso v1.30.17/go.mod h1:xNWknVi4Ezm1vg1QsB/5EWpAJURq22uqd38U8qKvOJc=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.36.0 h1:nDARhv/oF55bcxF7rCI/4PDxOKnVXVWwDuDwCs2I2SQ=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.36.0/go.mod h1:4vIRDq+CJB2xFAXZ+YgGUTiEft7oAQlhIs71xcSeuVg=
github.com/aws/aws-sdk-go-v2/service/sts v1.42.1 h1:F/M5Y9I3nwr2IEpshZgh1GeHpOItExNM9L1euNuh/fk=
github.com/aws/aws-sdk-go-v2/service/sts v1.42.1/go.mod h1:mTNxImtovCOEEuD65mKW7DCsL+2gjEH+RPEAexAzAio=
github.com/aws/smithy-go v1.26.0 h1:9ouqbi+NyKP7fV3Te7UElCwdAb6Y8uk7LGwPE5tVe/s=
github.com/aws/smithy-go v1.26.0/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc=
github.com/bboreham/go-loser v0.0.0-20230920113527-fcc2c21820a3 h1:6df1vn4bBlDDo4tARvBm7l6KA9iVMnE3NWizDeWSrps=
github.com/bboreham/go-loser v0.0.0-20230920113527-fcc2c21820a3/go.mod h1:CIWtjkly68+yqLPbvwwR/fjNJA/idrtULjZWh2v1ys0=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
@ -74,8 +74,8 @@ github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6r
github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cncf/xds/go v0.0.0-20251210132809-ee656c7534f5 h1:6xNmx7iTtyBRev0+D/Tv1FZd4SCg8axKApyNyRsAt/w=
github.com/cncf/xds/go v0.0.0-20251210132809-ee656c7534f5/go.mod h1:KdCmV+x/BuvyMxRnYBlmVaq4OLiKW6iRQfvC62cvdkI=
github.com/cncf/xds/go v0.0.0-20260202195803-dba9d589def2 h1:aBangftG7EVZoUb69Os8IaYg++6uMOdKK83QtkkvJik=
github.com/cncf/xds/go v0.0.0-20260202195803-dba9d589def2/go.mod h1:qwXFYgsP6T7XnJtbKlf1HP8AjxZZyzxMmc+Lq5GjlU4=
github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI=
github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M=
github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE=
@ -86,20 +86,21 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dennwc/varint v1.0.0 h1:kGNFFSSw8ToIy3obO/kKr8U9GZYUAxQEVuix4zfDWzE=
github.com/dennwc/varint v1.0.0/go.mod h1:hnItb35rvZvJrbTALZtY/iQfDs48JKRG1RPpgziApxA=
github.com/digitalocean/godo v1.178.0 h1:+B4xGOaoFwwwpM7TKhoyGHdmFg5eF9zDB1YfOLvNJ2E=
github.com/digitalocean/godo v1.178.0/go.mod h1:xQsWpVCCbkDrWisHA72hPzPlnC+4W5w/McZY5ij9uvU=
github.com/digitalocean/godo v1.193.0 h1:CSbbUl5LufT75KPNvex3vDnBYjY2RfJWs7T3Ac7dHpA=
github.com/digitalocean/godo v1.193.0/go.mod h1:xQsWpVCCbkDrWisHA72hPzPlnC+4W5w/McZY5ij9uvU=
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
github.com/docker/docker v28.5.2+incompatible h1:DBX0Y0zAjZbSrm1uzOkdr1onVghKaftjlSWt4AFexzM=
github.com/docker/docker v28.5.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/go-connections v0.6.0 h1:LlMG9azAe1TqfR7sO+NJttz1gy6KO7VJBh+pMmjSD94=
github.com/docker/go-connections v0.6.0/go.mod h1:AahvXYshr6JgfUJGdDCs2b5EZG/vmaMAntpSFH5BFKE=
github.com/docker/go-connections v0.7.0 h1:6SsRfJddP22WMrCkj19x9WKjEDTB+ahsdiGYf0mN39c=
github.com/docker/go-connections v0.7.0/go.mod h1:no1qkHdjq7kLMGUXYAduOhYPSJxxvgWBh7ogVvptn3Q=
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/edsrzf/mmap-go v1.2.0 h1:hXLYlkbaPzt1SaQk+anYwKSRNhufIDCchSPkUD6dD84=
github.com/edsrzf/mmap-go v1.2.0/go.mod h1:19H/e8pUPLicwkyNgOykDXkJ9F0MHE+Z52B8EIth78Q=
github.com/emicklei/go-restful/v3 v3.12.2 h1:DhwDP0vY3k8ZzE0RunuJy8GhNpPL6zqLkDf9B/a0/xU=
github.com/emicklei/go-restful/v3 v3.12.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
github.com/envoyproxy/go-control-plane v0.14.0 h1:hbG2kr4RuFj222B6+7T83thSPqLjwBIfQawTkC++2HA=
github.com/envoyproxy/go-control-plane/envoy v1.37.0 h1:u3riX6BoYRfF4Dr7dwSOroNfdSbEPe9Yyl09/B6wBrQ=
github.com/envoyproxy/go-control-plane/envoy v1.37.0/go.mod h1:DReE9MMrmecPy+YvQOAOHNYMALuowAnbjjEMkkWOi6A=
github.com/envoyproxy/protoc-gen-validate v1.3.3 h1:MVQghNeW+LZcmXe7SY1V36Z+WFMDjpqGAGacLe2T0ds=
@ -110,8 +111,8 @@ github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
github.com/fsnotify/fsnotify v1.10.1 h1:b0/UzAf9yR5rhf3RPm9gf3ehBPpf0oZKIjtpKrx59Ho=
github.com/fsnotify/fsnotify v1.10.1/go.mod h1:TLheqan6HD6GBK6PrDWyDPBaEV8LspOxvPSjC+bVfgo=
github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM=
github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
@ -119,34 +120,34 @@ github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-openapi/jsonpointer v0.22.5 h1:8on/0Yp4uTb9f4XvTrM2+1CPrV05QPZXu+rvu2o9jcA=
github.com/go-openapi/jsonpointer v0.22.5/go.mod h1:gyUR3sCvGSWchA2sUBJGluYMbe1zazrYWIkWPjjMUY0=
github.com/go-openapi/jsonreference v0.21.4 h1:24qaE2y9bx/q3uRK/qN+TDwbok1NhbSmGjjySRCHtC8=
github.com/go-openapi/jsonreference v0.21.4/go.mod h1:rIENPTjDbLpzQmQWCj5kKj3ZlmEh+EFVbz3RTUh30/4=
github.com/go-openapi/swag v0.25.4 h1:OyUPUFYDPDBMkqyxOTkqDYFnrhuhi9NR6QVUvIochMU=
github.com/go-openapi/swag v0.25.4/go.mod h1:zNfJ9WZABGHCFg2RnY0S4IOkAcVTzJ6z2Bi+Q4i6qFQ=
github.com/go-openapi/swag/cmdutils v0.25.4 h1:8rYhB5n6WawR192/BfUu2iVlxqVR9aRgGJP6WaBoW+4=
github.com/go-openapi/swag/cmdutils v0.25.4/go.mod h1:pdae/AFo6WxLl5L0rq87eRzVPm/XRHM3MoYgRMvG4A0=
github.com/go-openapi/swag/conv v0.25.4 h1:/Dd7p0LZXczgUcC/Ikm1+YqVzkEeCc9LnOWjfkpkfe4=
github.com/go-openapi/swag/conv v0.25.4/go.mod h1:3LXfie/lwoAv0NHoEuY1hjoFAYkvlqI/Bn5EQDD3PPU=
github.com/go-openapi/swag/fileutils v0.25.4 h1:2oI0XNW5y6UWZTC7vAxC8hmsK/tOkWXHJQH4lKjqw+Y=
github.com/go-openapi/swag/fileutils v0.25.4/go.mod h1:cdOT/PKbwcysVQ9Tpr0q20lQKH7MGhOEb6EwmHOirUk=
github.com/go-openapi/swag/jsonname v0.25.5 h1:8p150i44rv/Drip4vWI3kGi9+4W9TdI3US3uUYSFhSo=
github.com/go-openapi/swag/jsonname v0.25.5/go.mod h1:jNqqikyiAK56uS7n8sLkdaNY/uq6+D2m2LANat09pKU=
github.com/go-openapi/swag/jsonutils v0.25.4 h1:VSchfbGhD4UTf4vCdR2F4TLBdLwHyUDTd1/q4i+jGZA=
github.com/go-openapi/swag/jsonutils v0.25.4/go.mod h1:7OYGXpvVFPn4PpaSdPHJBtF0iGnbEaTk8AvBkoWnaAY=
github.com/go-openapi/swag/loading v0.25.4 h1:jN4MvLj0X6yhCDduRsxDDw1aHe+ZWoLjW+9ZQWIKn2s=
github.com/go-openapi/swag/loading v0.25.4/go.mod h1:rpUM1ZiyEP9+mNLIQUdMiD7dCETXvkkC30z53i+ftTE=
github.com/go-openapi/swag/mangling v0.25.4 h1:2b9kBJk9JvPgxr36V23FxJLdwBrpijI26Bx5JH4Hp48=
github.com/go-openapi/swag/mangling v0.25.4/go.mod h1:6dxwu6QyORHpIIApsdZgb6wBk/DPU15MdyYj/ikn0Hg=
github.com/go-openapi/swag/netutils v0.25.4 h1:Gqe6K71bGRb3ZQLusdI8p/y1KLgV4M/k+/HzVSqT8H0=
github.com/go-openapi/swag/netutils v0.25.4/go.mod h1:m2W8dtdaoX7oj9rEttLyTeEFFEBvnAx9qHd5nJEBzYg=
github.com/go-openapi/swag/stringutils v0.25.4 h1:O6dU1Rd8bej4HPA3/CLPciNBBDwZj9HiEpdVsb8B5A8=
github.com/go-openapi/swag/stringutils v0.25.4/go.mod h1:GTsRvhJW5xM5gkgiFe0fV3PUlFm0dr8vki6/VSRaZK0=
github.com/go-openapi/swag/typeutils v0.25.4 h1:1/fbZOUN472NTc39zpa+YGHn3jzHWhv42wAJSN91wRw=
github.com/go-openapi/swag/typeutils v0.25.4/go.mod h1:Ou7g//Wx8tTLS9vG0UmzfCsjZjKhpjxayRKTHXf2pTE=
github.com/go-openapi/swag/yamlutils v0.25.4 h1:6jdaeSItEUb7ioS9lFoCZ65Cne1/RZtPBZ9A56h92Sw=
github.com/go-openapi/swag/yamlutils v0.25.4/go.mod h1:MNzq1ulQu+yd8Kl7wPOut/YHAAU/H6hL91fF+E2RFwc=
github.com/go-openapi/jsonpointer v0.23.1 h1:1HBACs7XIwR2RcmItfdSFlALhGbe6S92p0ry4d1GWg4=
github.com/go-openapi/jsonpointer v0.23.1/go.mod h1:iWRmZTrGn7XwYhtPt/fvdSFj1OfNBngqRT2UG3BxSqY=
github.com/go-openapi/jsonreference v0.21.5 h1:6uCGVXU/aNF13AQNggxfysJ+5ZcU4nEAe+pJyVWRdiE=
github.com/go-openapi/jsonreference v0.21.5/go.mod h1:u25Bw85sX4E2jzFodh1FOKMTZLcfifd1Q+iKKOUxExw=
github.com/go-openapi/swag v0.25.5 h1:pNkwbUEeGwMtcgxDr+2GBPAk4kT+kJ+AaB+TMKAg+TU=
github.com/go-openapi/swag v0.25.5/go.mod h1:B3RT6l8q7X803JRxa2e59tHOiZlX1t8viplOcs9CwTA=
github.com/go-openapi/swag/cmdutils v0.25.5 h1:yh5hHrpgsw4NwM9KAEtaDTXILYzdXh/I8Whhx9hKj7c=
github.com/go-openapi/swag/cmdutils v0.25.5/go.mod h1:pdae/AFo6WxLl5L0rq87eRzVPm/XRHM3MoYgRMvG4A0=
github.com/go-openapi/swag/conv v0.25.5 h1:wAXBYEXJjoKwE5+vc9YHhpQOFj2JYBMF2DUi+tGu97g=
github.com/go-openapi/swag/conv v0.25.5/go.mod h1:CuJ1eWvh1c4ORKx7unQnFGyvBbNlRKbnRyAvDvzWA4k=
github.com/go-openapi/swag/fileutils v0.25.5 h1:B6JTdOcs2c0dBIs9HnkyTW+5gC+8NIhVBUwERkFhMWk=
github.com/go-openapi/swag/fileutils v0.25.5/go.mod h1:V3cT9UdMQIaH4WiTrUc9EPtVA4txS0TOmRURmhGF4kc=
github.com/go-openapi/swag/jsonname v0.26.0 h1:gV1NFX9M8avo0YSpmWogqfQISigCmpaiNci8cGECU5w=
github.com/go-openapi/swag/jsonname v0.26.0/go.mod h1:urBBR8bZNoDYGr653ynhIx+gTeIz0ARZxHkAPktJK2M=
github.com/go-openapi/swag/jsonutils v0.25.5 h1:XUZF8awQr75MXeC+/iaw5usY/iM7nXPDwdG3Jbl9vYo=
github.com/go-openapi/swag/jsonutils v0.25.5/go.mod h1:48FXUaz8YsDAA9s5AnaUvAmry1UcLcNVWUjY42XkrN4=
github.com/go-openapi/swag/loading v0.25.5 h1:odQ/umlIZ1ZVRteI6ckSrvP6e2w9UTF5qgNdemJHjuU=
github.com/go-openapi/swag/loading v0.25.5/go.mod h1:I8A8RaaQ4DApxhPSWLNYWh9NvmX2YKMoB9nwvv6oW6g=
github.com/go-openapi/swag/mangling v0.25.5 h1:hyrnvbQRS7vKePQPHHDso+k6CGn5ZBs5232UqWZmJZw=
github.com/go-openapi/swag/mangling v0.25.5/go.mod h1:6hadXM/o312N/h98RwByLg088U61TPGiltQn71Iw0NY=
github.com/go-openapi/swag/netutils v0.25.5 h1:LZq2Xc2QI8+7838elRAaPCeqJnHODfSyOa7ZGfxDKlU=
github.com/go-openapi/swag/netutils v0.25.5/go.mod h1:lHbtmj4m57APG/8H7ZcMMSWzNqIQcu0RFiXrPUara14=
github.com/go-openapi/swag/stringutils v0.25.5 h1:NVkoDOA8YBgtAR/zvCx5rhJKtZF3IzXcDdwOsYzrB6M=
github.com/go-openapi/swag/stringutils v0.25.5/go.mod h1:PKK8EZdu4QJq8iezt17HM8RXnLAzY7gW0O1KKarrZII=
github.com/go-openapi/swag/typeutils v0.25.5 h1:EFJ+PCga2HfHGdo8s8VJXEVbeXRCYwzzr9u4rJk7L7E=
github.com/go-openapi/swag/typeutils v0.25.5/go.mod h1:itmFmScAYE1bSD8C4rS0W+0InZUBrB2xSPbWt6DLGuc=
github.com/go-openapi/swag/yamlutils v0.25.5 h1:kASCIS+oIeoc55j28T4o8KwlV2S4ZLPT6G0iq2SSbVQ=
github.com/go-openapi/swag/yamlutils v0.25.5/go.mod h1:Gek1/SjjfbYvM+Iq4QGwa/2lEXde9n2j4a3wI3pNuOQ=
github.com/go-resty/resty/v2 v2.17.2 h1:FQW5oHYcIlkCNrMD2lloGScxcHJ0gkjshV3qcQAyHQk=
github.com/go-resty/resty/v2 v2.17.2/go.mod h1:kCKZ3wWmwJaNc7S29BRtUhJwy7iqmn+2mLtQrOyQlVA=
github.com/go-viper/mapstructure/v2 v2.5.0 h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPEgAXnvj1Ro=
@ -174,12 +175,12 @@ github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0=
github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/enterprise-certificate-proxy v0.3.14 h1:yh8ncqsbUY4shRD5dA6RlzjJaT4hi3kII+zYw8wmLb8=
github.com/googleapis/enterprise-certificate-proxy v0.3.14/go.mod h1:vqVt9yG9480NtzREnTlmGSBmFrA+bzb0yl0TxoBQXOg=
github.com/googleapis/gax-go/v2 v2.18.0 h1:jxP5Uuo3bxm3M6gGtV94P4lliVetoCB4Wk2x8QA86LI=
github.com/googleapis/gax-go/v2 v2.18.0/go.mod h1:uSzZN4a356eRG985CzJ3WfbFSpqkLTjsnhWGJR6EwrE=
github.com/gophercloud/gophercloud/v2 v2.11.1 h1:jCs4vLH8sJgRqrPzqVfWgl7uI6JnIIlsgeIRM0uHjxY=
github.com/gophercloud/gophercloud/v2 v2.11.1/go.mod h1:Rm0YvKQ4QYX2rY9XaDKnjRzSGwlG5ge4h6ABYnmkKQM=
github.com/googleapis/enterprise-certificate-proxy v0.3.15 h1:xolVQTEXusUcAA5UgtyRLjelpFFHWlPQ4XfWGc7MBas=
github.com/googleapis/enterprise-certificate-proxy v0.3.15/go.mod h1:vqVt9yG9480NtzREnTlmGSBmFrA+bzb0yl0TxoBQXOg=
github.com/googleapis/gax-go/v2 v2.22.0 h1:PjIWBpgGIVKGoCXuiCoP64altEJCj3/Ei+kSU5vlZD4=
github.com/googleapis/gax-go/v2 v2.22.0/go.mod h1:irWBbALSr0Sk3qlqb9SyJ1h68WjgeFuiOzI4Rqw5+aY=
github.com/gophercloud/gophercloud/v2 v2.12.0 h1:Gxmc/Bog1UDKkxTcQW7MSPTDviJXpLeEgVeN5KrxoCo=
github.com/gophercloud/gophercloud/v2 v2.12.0/go.mod h1:H7TTOxbLy8RIaHSNhI2GCrWIzw4Xpw8Xn2mBhCUT5kA=
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 h1:JeSE6pjso5THxAzdVpqr6/geYxZytqFMBCOtn/ujyeo=
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674/go.mod h1:r4w70xmWCQKmi1ONH4KIaBptdivuRPyosB9RmPlGEwA=
github.com/grafana/regexp v0.0.0-20250905093917-f7b3be9d1853 h1:cLN4IBkmkYZNnk7EAJ0BHIethd+J6LqxFNw5mSiI2bM=
@ -198,26 +199,26 @@ github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJ
github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU=
github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk=
github.com/hashicorp/go-retryablehttp v0.7.8 h1:ylXZWnqa7Lhqpk0L1P1LzDtGcCR0rPVUrx/c8Unxc48=
github.com/hashicorp/go-retryablehttp v0.7.8/go.mod h1:rjiScheydd+CxvumBsIrFKlx3iS0jrZ7LvzFGFmuKbw=
github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc=
github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
github.com/hashicorp/go-version v1.8.0 h1:KAkNb1HAiZd1ukkxDFGmokVZe1Xy9HG6NUp+bPle2i4=
github.com/hashicorp/go-version v1.8.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/go-version v1.9.0 h1:CeOIz6k+LoN3qX9Z0tyQrPtiB1DFYRPfCIBtaXPSCnA=
github.com/hashicorp/go-version v1.9.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/golang-lru v0.6.0 h1:uL2shRDx7RTrOrTCUZEGP/wJUFiUI8QT6E7z5o8jga4=
github.com/hashicorp/golang-lru v0.6.0/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
github.com/hashicorp/nomad/api v0.0.0-20260324203407-b27b0c2e019a h1:HGwfgBNl90YBiHdbzZ/+8aMxO1UL9B/yNTAXa8iB8z8=
github.com/hashicorp/nomad/api v0.0.0-20260324203407-b27b0c2e019a/go.mod h1:KkLNLU0Nyfh5jWsFoF/PsmMbKpRIAoIV4lmQoJWgKCk=
github.com/hashicorp/nomad/api v0.0.0-20260528135333-5b027732945f h1:sdf4a6FF3tC1/c0buuizLAwZa/xLu4gWD87qWrzQLvo=
github.com/hashicorp/nomad/api v0.0.0-20260528135333-5b027732945f/go.mod h1:Kr8imJwigbQ/50BqVae2+JL+AyX+FnzbnuCoIFb6iYg=
github.com/hashicorp/serf v0.10.1 h1:Z1H2J60yRKvfDYAOZLd2MU0ND4AH/WDz7xYHDWQsIPY=
github.com/hashicorp/serf v0.10.1/go.mod h1:yL2t6BqATOLGc5HF7qbFkTfXoPIY0WZdWHfEvMqbG+4=
github.com/hetznercloud/hcloud-go/v2 v2.36.0 h1:HlLL/aaVXUulqe+rsjoJmrxKhPi1MflL5O9iq5QEtvo=
github.com/hetznercloud/hcloud-go/v2 v2.36.0/go.mod h1:MnN/QJEa/RYNQiiVoJjNHPntM7Z1wlYPgJ2HA40/cDE=
github.com/hetznercloud/hcloud-go/v2 v2.41.2 h1:fO5zsMgp5oejrtnFj8mYuqlp+iMuirpaKv4b5FYNRdQ=
github.com/hetznercloud/hcloud-go/v2 v2.41.2/go.mod h1:9OGvC//jbHE4sv2Oyo0bQ2vEWuUMKYoNMyj9Qxz2qcc=
github.com/influxdata/influxdb-client-go/v2 v2.14.0 h1:AjbBfJuq+QoaXNcrova8smSjwJdUHnwvfjMF71M1iI4=
github.com/influxdata/influxdb-client-go/v2 v2.14.0/go.mod h1:Ahpm3QXKMJslpXl3IftVLVezreAUtBOTZssDrjZEFHI=
github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839 h1:W9WBk7wlPfJLvMCdtV4zPulc4uCPrlywQOmbFOhgQNU=
github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo=
github.com/ionos-cloud/sdk-go/v6 v6.3.6 h1:l/TtKgdQ1wUH3DDe2SfFD78AW+TJWdEbDpQhHkWd6CM=
github.com/ionos-cloud/sdk-go/v6 v6.3.6/go.mod h1:nUGHP4kZHAZngCVr4v6C8nuargFrtvt7GrzH/hqn7c4=
github.com/ionos-cloud/sdk-go/v6 v6.3.7 h1:t773JkC/asnyVqeQ+OvN9WCRZuosSoPtJfyM82EFCWY=
github.com/ionos-cloud/sdk-go/v6 v6.3.7/go.mod h1:nUGHP4kZHAZngCVr4v6C8nuargFrtvt7GrzH/hqn7c4=
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/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
@ -227,14 +228,14 @@ github.com/keybase/go-keychain v0.0.1 h1:way+bWYa6lDppZoZcgMbYsvC7GxljxrskdNInRt
github.com/keybase/go-keychain v0.0.1/go.mod h1:PdEILRW3i9D8JcdM+FmY6RwkHGnhHxXwkPPMeUgOK1k=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.18.5 h1:/h1gH5Ce+VWNLSWqPzOVn6XBO+vJbCNGvjoaGBFW2IE=
github.com/klauspost/compress v1.18.5/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ=
github.com/klauspost/compress v1.18.6 h1:2jupLlAwFm95+YDR+NwD2MEfFO9d4z4Prjl1XXDjuao=
github.com/klauspost/compress v1.18.6/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ=
github.com/knadh/koanf/maps v0.1.2 h1:RBfmAW5CnZT+PJ1CVc1QSJKf4Xu9kxfQgYVQSu8hpbo=
github.com/knadh/koanf/maps v0.1.2/go.mod h1:npD/QZY3V6ghQDdcQzl1W4ICNVTkohC8E73eI2xW4yI=
github.com/knadh/koanf/providers/confmap v1.0.0 h1:mHKLJTE7iXEys6deO5p6olAiZdG5zwp8Aebir+/EaRE=
github.com/knadh/koanf/providers/confmap v1.0.0/go.mod h1:txHYHiI2hAtF0/0sCmcuol4IDcuQbKTybiB1nOcUo1A=
github.com/knadh/koanf/v2 v2.3.3 h1:jLJC8XCRfLC7n4F+ZKKdBsbq1bfXTpuFhf4L7t94D94=
github.com/knadh/koanf/v2 v2.3.3/go.mod h1:gRb40VRAbd4iJMYYD5IxZ6hfuopFcXBpc9bbQpZwo28=
github.com/knadh/koanf/v2 v2.3.4 h1:fnynNSDlujWE+v83hAp8wKr/cdoxHLO0629SN+U8Urc=
github.com/knadh/koanf/v2 v2.3.4/go.mod h1:gRb40VRAbd4iJMYYD5IxZ6hfuopFcXBpc9bbQpZwo28=
github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b h1:udzkj9S/zlT5X367kqJis0QP7YMxobob6zhzq6Yre00=
github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b/go.mod h1:pcaDhQK0/NJZEvtCO0qQPPropqV0sJOJ6YW7X+9kRwM=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
@ -243,8 +244,8 @@ 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/linode/linodego v1.66.0 h1:rK8QJFaV53LWOEJvb/evhTg/dP5ElvtuZmx4iv4RJds=
github.com/linode/linodego v1.66.0/go.mod h1:12ykGs9qsvxE+OU3SXuW2w+DTruWF35FPlXC7gGk2tU=
github.com/linode/linodego v1.69.1 h1:f45N2MHR/oece2/ktTTCYmrlfse4//k3NgwcF5zbGZ0=
github.com/linode/linodego v1.69.1/go.mod h1:Fha0NYsQSx5VZK1HQNJY/z/dIxxkFp+vb5veawbmAUw=
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
@ -276,12 +277,12 @@ github.com/oapi-codegen/runtime v1.0.0/go.mod h1:LmCUMQuPB4M/nLXilQXhHw+BLZdDb18
github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4=
github.com/oklog/ulid/v2 v2.1.1 h1:suPZ4ARWLOJLegGFiZZ1dFAkqzhMjL3J1TzI+5wHz8s=
github.com/oklog/ulid/v2 v2.1.1/go.mod h1:rcEKHmBBKfef9DhnvX7y1HZBYxjXb0cP5ExxNsTT1QQ=
github.com/open-telemetry/opentelemetry-collector-contrib/internal/exp/metrics v0.148.0 h1:CiTjQE/Hh5xK2t56ogrDK4nl0+tJPNmASCs4zEYZ/xU=
github.com/open-telemetry/opentelemetry-collector-contrib/internal/exp/metrics v0.148.0/go.mod h1:WUFkzTiOpt7EYyL67gv1GOf3RD8qKWGtin3lY9LYzW4=
github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatautil v0.148.0 h1:1TLg6YrS3Au6F7xw3ws2Njbwj13IMqPplvGFi+18fWs=
github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatautil v0.148.0/go.mod h1:P8hZEDIQk4REgUWyLhSVRHwTxK6KkifKfg36BmmQ/DI=
github.com/open-telemetry/opentelemetry-collector-contrib/processor/deltatocumulativeprocessor v0.148.0 h1:xgD/kNGp/wWY+bwY599Pc01OamYN17phRiTP934bM5Y=
github.com/open-telemetry/opentelemetry-collector-contrib/processor/deltatocumulativeprocessor v0.148.0/go.mod h1:ZK7wvaefla9lB3bAW0rNKt7IzRPcTRQoOFqr4sZy/XM=
github.com/open-telemetry/opentelemetry-collector-contrib/internal/exp/metrics v0.153.0 h1:hrLQLVZ4YXs35G9QvPO+xcu6qMnUpCt3WOpBDM7dR+E=
github.com/open-telemetry/opentelemetry-collector-contrib/internal/exp/metrics v0.153.0/go.mod h1:+qlIXDaBLIX+egj/okymUG88KSdAD8nIEHY8+tXt8+M=
github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatautil v0.153.0 h1:kPPv0sQQH2R2CitTPYXDfq1z1ekStnmk39C8RkOrsbI=
github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatautil v0.153.0/go.mod h1:wFACQmv2KfJyvyiRtMrI/DmcOWKEk6SxY0nLduWFMC4=
github.com/open-telemetry/opentelemetry-collector-contrib/processor/deltatocumulativeprocessor v0.153.0 h1:3MR2JvG1KB4GUiMi5asE6K0Ln5cjWPEfVAIpUwf55Sk=
github.com/open-telemetry/opentelemetry-collector-contrib/processor/deltatocumulativeprocessor v0.153.0/go.mod h1:0lEaZGCEjzb4R5J6F0NR1jF1KKc18IkvPRwLpQuyyjY=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040=
@ -299,8 +300,8 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o=
github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg=
github.com/prometheus/client_golang/exp v0.0.0-20260325093428-d8591d0db856 h1:1Y6bmpZb8peQCy1IpctnAhIFuyhrdtMaDnETChhSNns=
github.com/prometheus/client_golang/exp v0.0.0-20260325093428-d8591d0db856/go.mod h1:Vf0QcmVhGqpjLxZOaWrFSep86vchQtJmbztFaMM4f6Q=
github.com/prometheus/client_golang/exp v0.0.0-20260518105423-c9d5bc4c50a9 h1:e33IfrrwrJkylWwAGcQ2jMvbWVv13lv0suTXjGNeiqY=
github.com/prometheus/client_golang/exp v0.0.0-20260518105423-c9d5bc4c50a9/go.mod h1:vW/EVguzbNw6xMRmozJQWbY60/+Zsg0TgVJOSXGx2iI=
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.67.5 h1:pIgK94WWlQt1WLwAC5j2ynLaBRDiinoAb86HZHTUGI4=
@ -313,8 +314,8 @@ github.com/prometheus/prometheus v0.308.1 h1:ApMNI/3/es3Ze90Z7CMb+wwU2BsSYur0m5V
github.com/prometheus/prometheus v0.308.1/go.mod h1:aHjYCDz9zKRyoUXvMWvu13K9XHOkBB12XrEqibs3e0A=
github.com/prometheus/sigv4 v0.4.1 h1:EIc3j+8NBea9u1iV6O5ZAN8uvPq2xOIUPcqCTivHuXs=
github.com/prometheus/sigv4 v0.4.1/go.mod h1:eu+ZbRvsc5TPiHwqh77OWuCnWK73IdkETYY46P4dXOU=
github.com/puzpuzpuz/xsync/v4 v4.4.0 h1:vlSN6/CkEY0pY8KaB0yqo/pCLZvp9nhdbBdjipT4gWo=
github.com/puzpuzpuz/xsync/v4 v4.4.0/go.mod h1:VJDmTCJMBt8igNxnkQd86r+8KUeN1quSfNKu5bLYFQo=
github.com/puzpuzpuz/xsync/v4 v4.5.0 h1:vOSWu6b57/emh+L/Cw0BeQfvxa/cogFywXHeGUxQxAg=
github.com/puzpuzpuz/xsync/v4 v4.5.0/go.mod h1:VJDmTCJMBt8igNxnkQd86r+8KUeN1quSfNKu5bLYFQo=
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.36 h1:ObX9hZmK+VmijreZO/8x9pQ8/P/ToHD/bdSb4Eg4tUo=
@ -322,8 +323,8 @@ github.com/scaleway/scaleway-sdk-go v1.0.0-beta.36/go.mod h1:LEsDu4BubxK7/cWhtlQ
github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0=
github.com/stackitcloud/stackit-sdk-go/core v0.23.0 h1:zPrOhf3Xe47rKRs1fg/AqKYUiJJRYjdcv+3qsS50mEs=
github.com/stackitcloud/stackit-sdk-go/core v0.23.0/go.mod h1:osMglDby4csGZ5sIfhNyYq1bS1TxIdPY88+skE/kkmI=
github.com/stackitcloud/stackit-sdk-go/core v0.26.0 h1:jQEb9gkehfp6VCP6TcYk7BI10cz4l0KM2L6hqYBH2QA=
github.com/stackitcloud/stackit-sdk-go/core v0.26.0/go.mod h1:WU1hhxnjXw2EV7CYa1nlEvNpMiRY6CvmIOaHuL3pOaA=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
@ -346,58 +347,58 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
go.opentelemetry.io/collector/component v1.54.0 h1:LvtX0Tzz18n44OrUFVk77N1FNsejfWJqztB28hrmDM8=
go.opentelemetry.io/collector/component v1.54.0/go.mod h1:yUMBYsySY/sDcXm8kOzEoZxt+JLdala6hxzSW0npOxY=
go.opentelemetry.io/collector/component/componentstatus v0.148.0 h1:sCGRaXNQolHFhPjrNJEwQ1WZOf96iL99tzm9GxuZsvg=
go.opentelemetry.io/collector/component/componentstatus v0.148.0/go.mod h1:yqg3SpGQc22W3wGICdnb+2kZVW9daBr3+LrGUCHkKfc=
go.opentelemetry.io/collector/component/componenttest v0.148.0 h1:tBXJWmy2X6KD8S0QU2YZa2zYBqP+IycSM4iOtwDD2pA=
go.opentelemetry.io/collector/component/componenttest v0.148.0/go.mod h1:1c1+6mZOmI0raoya5vA/X0F+fawEjNS6tCEs5xLATtA=
go.opentelemetry.io/collector/confmap v1.54.0 h1:RUoxQ4uAYHTI57GfHh61D00tTQsXm9T88ozrAiicByc=
go.opentelemetry.io/collector/confmap v1.54.0/go.mod h1:mQxG8bk0IWIt9gbWMvzE+cRkOuCuzbzkNGBq2YJ4wNM=
go.opentelemetry.io/collector/confmap/xconfmap v0.148.0 h1:UW8MX5VlKJf67x4Et7J9kPwP9Rv4VSmJ+UUpgRcb//c=
go.opentelemetry.io/collector/confmap/xconfmap v0.148.0/go.mod h1:4qTMr3V0uSXXac9wVs/UD5fIqRKw5yIl58+Vjsc6RHM=
go.opentelemetry.io/collector/consumer v1.54.0 h1:RGGtUN+GbkV1px3T6XdUHmgJ+ldJ1hAHdesFzW/wgL0=
go.opentelemetry.io/collector/consumer v1.54.0/go.mod h1:1PC6XINTL9DdT1bwvfMdHE72EB4RWU/WcPemUrhqKN8=
go.opentelemetry.io/collector/consumer/consumertest v0.148.0 h1:ms0HtWMj17tI1Yds0hSuUI5QYpNEqd11AAhwIoUY2HE=
go.opentelemetry.io/collector/consumer/consumertest v0.148.0/go.mod h1:wScw/OzKkf/ZzJn4ToI30OoI1kJiY16WNrcFToXSzK0=
go.opentelemetry.io/collector/consumer/xconsumer v0.148.0 h1:m3b9rY7CLD5Pcge6sSKHIT3OlcPN6xqYsdtVs9oJ528=
go.opentelemetry.io/collector/consumer/xconsumer v0.148.0/go.mod h1:bG+Wz6xmIBl/gHzq1sqvksWXqTLuTX17Wo//zIsdZpw=
go.opentelemetry.io/collector/featuregate v1.54.0 h1:ufo5Hy4Co9pcHVg24hyanm8qFG3TkkYbVyQXPVAbwDc=
go.opentelemetry.io/collector/featuregate v1.54.0/go.mod h1:PS7zY/zaCb28EqciePVwRHVhc3oKortTFXsi3I6ee4g=
go.opentelemetry.io/collector/internal/componentalias v0.148.0 h1:Y6MftNIZSzOr47TTj6A2z2UR3IwbeG46sAQshicGtDg=
go.opentelemetry.io/collector/internal/componentalias v0.148.0/go.mod h1:uwKzfehzwRgHxdHgFXYSBHNBeWSSqsqQYGWr5fk08G0=
go.opentelemetry.io/collector/internal/testutil v0.148.0 h1:3Z9hperte3vSmbBTYeNndoEUICICrNz8hzx+v0FYXBQ=
go.opentelemetry.io/collector/internal/testutil v0.148.0/go.mod h1:Jkjs6rkqs973LqgZ0Fe3zrokQRKULYXPIf4HuqStiEE=
go.opentelemetry.io/collector/pdata v1.54.0 h1:3LharKb792cQ3VrUGxd3IcpWwfu3ST+GSTU382jVz1s=
go.opentelemetry.io/collector/pdata v1.54.0/go.mod h1:+MqC3VVOv/EX9YVFUo+mI4F0YmwJ+fXBYwjmu+mRiZ8=
go.opentelemetry.io/collector/pdata/pprofile v0.148.0 h1:MgrNZmqwhZGfiYwcKKtM/iXgTZqqvG5dUphriRXMZHU=
go.opentelemetry.io/collector/pdata/pprofile v0.148.0/go.mod h1:MTTMnZPqWX1S/rBDatU0W19udlycBkWuzVV5qnemHdc=
go.opentelemetry.io/collector/pdata/testdata v0.148.0 h1:yzakPuFgoKK8WcrlhyYHLMLA/kLScQKGsXkIgwieAQ8=
go.opentelemetry.io/collector/pdata/testdata v0.148.0/go.mod h1:2rFvxm8qwd3nlO90FtJw6ZGAjt+bLndxmQuJaMO9kfQ=
go.opentelemetry.io/collector/pipeline v1.54.0 h1:jYlCkdFLITVBdeB+IGS07zXWywEgvT3Ky46vdKKT+Ks=
go.opentelemetry.io/collector/pipeline v1.54.0/go.mod h1:RD90NG3Jbk965Xaqym3JyHkuol4uZJjQVUkD9ddXJIs=
go.opentelemetry.io/collector/processor v1.54.0 h1:zmHBFiEFmU9ZYuHhVP3lHIkbfy+ueapzGpTdXVMcWBg=
go.opentelemetry.io/collector/processor v1.54.0/go.mod h1:L0lA6DZ0VbrtQBg44cmYfSpRlgm4zxW1I6QfBnRizPw=
go.opentelemetry.io/collector/processor/processortest v0.148.0 h1:p0k59frZxy/Z4fXe82i5eOJv/UyOH75XhI8nFD1ZWCE=
go.opentelemetry.io/collector/processor/processortest v0.148.0/go.mod h1:E2Li2gnkUXgvApvGyEtn3Eq5KyzV05ljfbFRsZ7sTC4=
go.opentelemetry.io/collector/processor/xprocessor v0.148.0 h1:v7Qv6k2b2cvgGWuTO5KN5QYDLl1r5sznt7Le4Fhpa4c=
go.opentelemetry.io/collector/processor/xprocessor v0.148.0/go.mod h1:r7ADpSX2nf0rZR9STxh956Qw1740QOWMXLnEM/ZiaF8=
go.opentelemetry.io/collector/component v1.59.0 h1:WtulkwzsdAOM/LE0cH/IiudUgiyb2ueVDDeEh5HsXzo=
go.opentelemetry.io/collector/component v1.59.0/go.mod h1:5eQCM0tS6qbG2XJ6Bt67kgCxuhCbg4csVv6SywyHZ6w=
go.opentelemetry.io/collector/component/componentstatus v0.153.0 h1:bZu1Qs1eHw5ZY2UEKq0f5IcctDgc6zjUYwCE1T22Tmw=
go.opentelemetry.io/collector/component/componentstatus v0.153.0/go.mod h1:SfYWwh6pA9jJUcjuX+zIJ9kyn+2Z9SSLMM3xYOBsVW4=
go.opentelemetry.io/collector/component/componenttest v0.153.0 h1:u6O1l+9PUNnI22k8q4sF9wgLAUyt+y2Ov7xi1yZ+wE4=
go.opentelemetry.io/collector/component/componenttest v0.153.0/go.mod h1:Ym/d5UxnoHmrCI5LsVANBicikNiqtwjk8uWBM+Z4jDM=
go.opentelemetry.io/collector/confmap v1.59.0 h1:asxEEiWwNuGfmTVSctYArOTF8jcxYpS4NmPtvvFhNNI=
go.opentelemetry.io/collector/confmap v1.59.0/go.mod h1:X5SjFINrF0cb0hcM8PwnW2z+0L/pHA1H1yPPtm2j0tY=
go.opentelemetry.io/collector/confmap/xconfmap v0.153.0 h1:RSn7C87eBp1iuWip3hX8v9AR8adMze1usJxwumefkq4=
go.opentelemetry.io/collector/confmap/xconfmap v0.153.0/go.mod h1:4SuPyutUiirRqQoPeY+13lLYkOQ2opMQgKvKACnXh1k=
go.opentelemetry.io/collector/consumer v1.59.0 h1:EFDQ8ZTWwHEratWusKgW26W20LeAWdXj235iD9MxpuA=
go.opentelemetry.io/collector/consumer v1.59.0/go.mod h1:wrOSfXkKjzEeHYxhKGukuB9+NFV/CboWwEH1oEXhMtw=
go.opentelemetry.io/collector/consumer/consumertest v0.153.0 h1:fCqkOWNVK/qipg4SX60zICs3jhKDjcrtF1oxJR6msCk=
go.opentelemetry.io/collector/consumer/consumertest v0.153.0/go.mod h1:YfVqyCrvEfvsbbrpfiH97fITh4vmIBzZT112tUluqx0=
go.opentelemetry.io/collector/consumer/xconsumer v0.153.0 h1:Jt1Aiiq9zDILzppRTEdZXaA830KBjjP1i2kWL+h5br0=
go.opentelemetry.io/collector/consumer/xconsumer v0.153.0/go.mod h1:IzJ/dTOtEUMjY0DYu6kO946u5jbiDDUG8+sLaLhJ+HY=
go.opentelemetry.io/collector/featuregate v1.59.0 h1:pu70/9eWRjAjzGnr3VmqwY+k6fmU3esLp15AqxfBBz0=
go.opentelemetry.io/collector/featuregate v1.59.0/go.mod h1:4ga1QBMPEejXXmpyJS8lmaRpknJ3Lb9Bvk6e420bUFU=
go.opentelemetry.io/collector/internal/componentalias v0.153.0 h1:tr5I5hsJPJBbVPGjvOVVPPK4dLR5ZLqVEckuOfnzzMs=
go.opentelemetry.io/collector/internal/componentalias v0.153.0/go.mod h1:tFSKiuWKJJgfxANyVnbKPVZkOF7N0bFXvCxCEgqMKuo=
go.opentelemetry.io/collector/internal/testutil v0.153.0 h1:GJEaPLohao+7wtm08yGf73RGi1rpIHvqzxOb7Xn8sP0=
go.opentelemetry.io/collector/internal/testutil v0.153.0/go.mod h1:Jkjs6rkqs973LqgZ0Fe3zrokQRKULYXPIf4HuqStiEE=
go.opentelemetry.io/collector/pdata v1.59.0 h1:lO1IcaO9+HUVdFh+RATCUG3oTP+uCZzsE7HJ0MjmzRc=
go.opentelemetry.io/collector/pdata v1.59.0/go.mod h1:AH6M14C6qhesnUpcvigkvFMiX9KtdSWQENMBNyNhe7I=
go.opentelemetry.io/collector/pdata/pprofile v0.153.0 h1:IurcS9g28cVrtIvc1oUVN8vSm5j0t79Pd8GZgd1PV28=
go.opentelemetry.io/collector/pdata/pprofile v0.153.0/go.mod h1:nX33dLKrwdoz/FQeIs6JKPeZcS1KbU2VIOwH7K0F05c=
go.opentelemetry.io/collector/pdata/testdata v0.153.0 h1:pO/+b8Rz5PG0G+TskdYdQEjhXnNG2bQoiRRMwic6X0I=
go.opentelemetry.io/collector/pdata/testdata v0.153.0/go.mod h1:JVjUfJv9YFL3JUhisxMdLe2DX7we227Ry9JiTgwlEro=
go.opentelemetry.io/collector/pipeline v1.59.0 h1:AyEcAPy5ZuUFpqis9i97WEIAcFh/mEEo90+1wr4urNU=
go.opentelemetry.io/collector/pipeline v1.59.0/go.mod h1:RD90NG3Jbk965Xaqym3JyHkuol4uZJjQVUkD9ddXJIs=
go.opentelemetry.io/collector/processor v1.59.0 h1:uSIMwLaKLzHNiv8625LP3BLUMCqRaBc1ay2o7uW19PQ=
go.opentelemetry.io/collector/processor v1.59.0/go.mod h1:IrCFcSdmqIWfNeTWOxncNcdQGVOf0LlKY6A3pHEpGiw=
go.opentelemetry.io/collector/processor/processortest v0.153.0 h1:aMH8+omUXs2iCKL4Cphmzzrn4lB4jm6ZgWRvKKV+B/c=
go.opentelemetry.io/collector/processor/processortest v0.153.0/go.mod h1:LAPHps5FhQyd0MnNd1ZHmoykG/EWsIpJLs7fivFf5Mc=
go.opentelemetry.io/collector/processor/xprocessor v0.153.0 h1:mXtOAwZAXcHgAgVRzAk4NRoyj7yHV88LVFrn0CCedog=
go.opentelemetry.io/collector/processor/xprocessor v0.153.0/go.mod h1:yGFU58TvheCedrVkdqU8jW/vnCFqcyYElf+5lidn0nA=
go.opentelemetry.io/collector/semconv v0.128.0 h1:MzYOz7Vgb3Kf5D7b49pqqgeUhEmOCuT10bIXb/Cc+k4=
go.opentelemetry.io/collector/semconv v0.128.0/go.mod h1:OPXer4l43X23cnjLXIZnRj/qQOjSuq4TgBLI76P9hns=
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.67.0 h1:c9r/G1CSw4dPI1jaNNG9RnQP+q4SvZnHciDQJVIvchU=
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.67.0/go.mod h1:gO9smoZe9KnZcJCqcB0lMmQ4Z5VEifYmjMTpnwtTSuQ=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.67.0 h1:OyrsyzuttWTSur2qN/Lm0m2a8yqyIjUVBZcxFPuXq2o=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.67.0/go.mod h1:C2NGBr+kAB4bk3xtMXfZ94gqFDtg/GkI7e9zqGh5Beg=
go.opentelemetry.io/otel v1.42.0 h1:lSQGzTgVR3+sgJDAU/7/ZMjN9Z+vUip7leaqBKy4sho=
go.opentelemetry.io/otel v1.42.0/go.mod h1:lJNsdRMxCUIWuMlVJWzecSMuNjE7dOYyWlqOXWkdqCc=
go.opentelemetry.io/otel/metric v1.42.0 h1:2jXG+3oZLNXEPfNmnpxKDeZsFI5o4J+nz6xUlaFdF/4=
go.opentelemetry.io/otel/metric v1.42.0/go.mod h1:RlUN/7vTU7Ao/diDkEpQpnz3/92J9ko05BIwxYa2SSI=
go.opentelemetry.io/otel/sdk v1.42.0 h1:LyC8+jqk6UJwdrI/8VydAq/hvkFKNHZVIWuslJXYsDo=
go.opentelemetry.io/otel/sdk v1.42.0/go.mod h1:rGHCAxd9DAph0joO4W6OPwxjNTYWghRWmkHuGbayMts=
go.opentelemetry.io/otel/sdk/metric v1.42.0 h1:D/1QR46Clz6ajyZ3G8SgNlTJKBdGp84q9RKCAZ3YGuA=
go.opentelemetry.io/otel/sdk/metric v1.42.0/go.mod h1:Ua6AAlDKdZ7tdvaQKfSmnFTdHx37+J4ba8MwVCYM5hc=
go.opentelemetry.io/otel/trace v1.42.0 h1:OUCgIPt+mzOnaUTpOQcBiM/PLQ/Op7oq6g4LenLmOYY=
go.opentelemetry.io/otel/trace v1.42.0/go.mod h1:f3K9S+IFqnumBkKhRJMeaZeNk9epyhnCmQh/EysQCdc=
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.69.0 h1:MCcYL7J6Vt/X0kjqbMZkekCmwsurbQRbL69vkiye2lk=
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.69.0/go.mod h1:3jnStNwSufK+f5ktjL4EPcwtig4rtd81NS70lqHuXl8=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0 h1:8tvICD4vSTOOsNrsI4Ljf6C+6UKvpTEH5XY3JMoyPoo=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0/go.mod h1:z9+yiacE0IHRqM4qFfkbt/JYlmYXgss8GY/jXoNuPJI=
go.opentelemetry.io/otel v1.44.0 h1:JjwHmHpA4iZ3wBxluu2fbbE7j4kqlE8jXyAyPXH7HqU=
go.opentelemetry.io/otel v1.44.0/go.mod h1:BMgjTHL9WPRlRjL2oZCBTL4whCGtXch2H4BhOPIAyYc=
go.opentelemetry.io/otel/metric v1.44.0 h1:1w0gILTcHdr3YI+ixLyjemwrVnsMURbTZFrSYCdDdmc=
go.opentelemetry.io/otel/metric v1.44.0/go.mod h1:8O7hanEPBNgEMmybD3s2VBKcgWOCsA6tzHBPODAiquo=
go.opentelemetry.io/otel/sdk v1.44.0 h1:nHYwb9lK+fJPU/dnT6s7W7Z8itMWyqrnVfbheVYrZ58=
go.opentelemetry.io/otel/sdk v1.44.0/go.mod h1:Osuydd3Se74nqjAKxid74N5eC+jfEqfTegHRnq58oK0=
go.opentelemetry.io/otel/sdk/metric v1.44.0 h1:3LlKgI+VjbVsjNRFZJZAJ30WjXC5VkNRks6si09iEfI=
go.opentelemetry.io/otel/sdk/metric v1.44.0/go.mod h1:5B5pMARnXxKhltooO4xUuCBorl65a4EpnTalObqOigA=
go.opentelemetry.io/otel/trace v1.44.0 h1:jxF5CsGYCe74MCRx2X4g7WsY/VBKRqqpNvXlX/6gtIk=
go.opentelemetry.io/otel/trace v1.44.0/go.mod h1:oLl1jrMQAVo6v3GAggN+1VH9VIz9iUSvW53sW1Q8PIE=
go.opentelemetry.io/proto/slim/otlp v1.10.0 h1:iR97Vs/ZDR+y9TfuP9b1XBtdPWeC+OMslIBmhcLU7jM=
go.opentelemetry.io/proto/slim/otlp v1.10.0/go.mod h1:lV9250stpjYLPNA5viFabIgP2QlUGRT1GdTgAf8SIUk=
go.opentelemetry.io/proto/slim/otlp/collector/profiles/v1development v0.3.0 h1:RUF5rO0hAlgiJt1fzQVzcVs3vZVNHIcMLgOgG4rWNcQ=
@ -410,8 +411,8 @@ go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc=
go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
go.uber.org/zap v1.28.0 h1:IZzaP1Fv73/T/pBMLk4VutPl36uNC+OSUh3JLG3FIjo=
go.uber.org/zap v1.28.0/go.mod h1:rDLpOi171uODNm/mxFcuYWxDsqWSAVkFdX4XojSKg/Q=
go.yaml.in/yaml/v2 v2.4.4 h1:tuyd0P+2Ont/d6e2rl3be67goVK4R6deVxCUX5vyPaQ=
go.yaml.in/yaml/v2 v2.4.4/go.mod h1:gMZqIpDtDqOfM0uNfy0SkpRhvUryYH0Z6wdMYcacYXQ=
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
@ -419,20 +420,20 @@ go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4=
golang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA=
golang.org/x/crypto v0.51.0 h1:IBPXwPfKxY7cWQZ38ZCIRPI50YLeevDLlLnyC5wRGTI=
golang.org/x/crypto v0.51.0/go.mod h1:8AdwkbraGNABw2kOX6YFPs3WM22XqI4EXEd8g+x7Oc8=
golang.org/x/exp v0.0.0-20250808145144-a408d31f581a h1:Y+7uR/b1Mw2iSXZ3G//1haIiSElDQZ8KWh0h+sZPG90=
golang.org/x/exp v0.0.0-20250808145144-a408d31f581a/go.mod h1:rT6SFzZ7oxADUDx58pcaKFTcZ+inxAa9fTrYx/uVYwg=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8=
golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w=
golang.org/x/mod v0.36.0 h1:JJjpVx6myfUsUdAzZuOSTTmRE0PfZeNWzzvKrP7amb4=
golang.org/x/mod v0.36.0/go.mod h1:moc6ELqsWcOw5Ef3xVprK5ul/MvtVvkIXLziUOICjUQ=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0=
golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw=
golang.org/x/net v0.55.0 h1:bcvxaJn3e1U6InsFWt1JUq1aSjnRxLzT2rtD2KfkDF8=
golang.org/x/net v0.55.0/go.mod h1:L5U2KuzuOe1lY7Z+aWVIKK6qEeJXnXV9yzGA+WCHJww=
golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs=
golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -444,36 +445,38 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo=
golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
golang.org/x/term v0.41.0 h1:QCgPso/Q3RTJx2Th4bDLqML4W6iJiaXFq2/ftQF13YU=
golang.org/x/term v0.41.0/go.mod h1:3pfBgksrReYfZ5lvYM0kSO0LIkAl4Yl2bXOkKP7Ec2A=
golang.org/x/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY=
golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
golang.org/x/term v0.43.0 h1:S4RLU2sB31O/NCl+zFN9Aru9A/Cq2aqKpTZJ6B+DwT4=
golang.org/x/term v0.43.0/go.mod h1:lrhlHNdQJHO+1qVYiHfFKVuVioJIheAc3fBSMFYEIsk=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8=
golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA=
golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc=
golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38=
golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U=
golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k=
golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0=
golang.org/x/tools v0.45.0 h1:18qN3FAooORvApf5XjCXgsuayZOEtXf6JK18I3+ONa8=
golang.org/x/tools v0.45.0/go.mod h1:LuUGqqaXcXMEFEruIVJVm5mgDD8vww/z/SR1gQ4uE/0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
google.golang.org/api v0.272.0 h1:eLUQZGnAS3OHn31URRf9sAmRk3w2JjMx37d2k8AjJmA=
google.golang.org/api v0.272.0/go.mod h1:wKjowi5LNJc5qarNvDCvNQBn3rVK8nSy6jg2SwRwzIA=
google.golang.org/genproto/googleapis/api v0.0.0-20260319201613-d00831a3d3e7 h1:41r6JMbpzBMen0R/4TZeeAmGXSJC7DftGINUodzTkPI=
google.golang.org/genproto/googleapis/api v0.0.0-20260319201613-d00831a3d3e7/go.mod h1:EIQZ5bFCfRQDV4MhRle7+OgjNtZ6P1PiZBgAKuxXu/Y=
google.golang.org/genproto/googleapis/rpc v0.0.0-20260311181403-84a4fc48630c h1:xgCzyF2LFIO/0X2UAoVRiXKU5Xg6VjToG4i2/ecSswk=
google.golang.org/genproto/googleapis/rpc v0.0.0-20260311181403-84a4fc48630c/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
google.golang.org/grpc v1.79.3 h1:sybAEdRIEtvcD68Gx7dmnwjZKlyfuc61Dyo9pGXXkKE=
google.golang.org/grpc v1.79.3/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4=
gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E=
google.golang.org/api v0.278.0 h1:W7jiRvRi53VYFfZ/HoZjQBtJk7gOFbHD8ot1RzVZU6E=
google.golang.org/api v0.278.0/go.mod h1:B9TqLBwJqVjp1mtt7WeoQwWRwvu/400y5lETOql+giQ=
google.golang.org/genproto v0.0.0-20260319201613-d00831a3d3e7 h1:XzmzkmB14QhVhgnawEVsOn6OFsnpyxNPRY9QV01dNB0=
google.golang.org/genproto v0.0.0-20260319201613-d00831a3d3e7/go.mod h1:L43LFes82YgSonw6iTXTxXUX1OlULt4AQtkik4ULL/I=
google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa h1:Kjn0N0tCrDgiAFW+lGO4JZ3ck44CehvJQMAwj9QF0G8=
google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa/go.mod h1:q4lMZS6kskjT5HvCPrnnypcDPVJqT/f4nfxmkE7gryY=
google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa h1:mZHHdPZl0dbGHCflZgAq/Q468DWVFcU2whhB2KAo8fk=
google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
google.golang.org/grpc v1.81.1 h1:VnnIIZ88UzOOKLukQi+ImGz8O1Wdp8nAGGnvOfEIWQQ=
google.golang.org/grpc v1.81.1/go.mod h1:xGH9GfzOyMTGIOXBJmXt+BX/V0kcdQbdcuwQ/zNw42I=
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@ -483,8 +486,8 @@ gopkg.in/evanphx/json-patch.v4 v4.13.0 h1:czT3CmqEaQ1aanPc5SdlgQrrEIb8w/wwCvWWnf
gopkg.in/evanphx/json-patch.v4 v4.13.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M=
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/ini.v1 v1.67.1 h1:tVBILHy0R6e4wkYOn3XmiITt/hEVH4TFMYvAX2Ytz6k=
gopkg.in/ini.v1 v1.67.1/go.mod h1:x/cyOwCgZqOkJoDIJ3c1KNHMo10+nLGAhh+kn3Zizss=
gopkg.in/ini.v1 v1.67.2 h1:JtOSMb9OuaCZKr7h5D/h6iii14sK0hLbplTc6frx4Ss=
gopkg.in/ini.v1 v1.67.2/go.mod h1:x/cyOwCgZqOkJoDIJ3c1KNHMo10+nLGAhh+kn3Zizss=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

181
go.mod
View file

@ -3,7 +3,7 @@ module github.com/prometheus/prometheus
go 1.25.0
require (
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.21.0
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.21.1
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.1
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5 v5.7.0
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v4 v4.3.0
@ -11,83 +11,83 @@ require (
github.com/KimMachineGun/automemlimit v0.7.5
github.com/alecthomas/kingpin/v2 v2.4.0
github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b
github.com/aws/aws-sdk-go-v2 v1.41.4
github.com/aws/aws-sdk-go-v2/config v1.32.12
github.com/aws/aws-sdk-go-v2/credentials v1.19.12
github.com/aws/aws-sdk-go-v2/service/ec2 v1.296.0
github.com/aws/aws-sdk-go-v2/service/ecs v1.74.0
github.com/aws/aws-sdk-go-v2/service/elasticache v1.51.12
github.com/aws/aws-sdk-go-v2/service/kafka v1.49.1
github.com/aws/aws-sdk-go-v2/service/lightsail v1.51.0
github.com/aws/aws-sdk-go-v2/service/rds v1.117.0
github.com/aws/aws-sdk-go-v2/service/sts v1.41.9
github.com/aws/smithy-go v1.24.2
github.com/aws/aws-sdk-go-v2 v1.41.7
github.com/aws/aws-sdk-go-v2/config v1.32.18
github.com/aws/aws-sdk-go-v2/credentials v1.19.17
github.com/aws/aws-sdk-go-v2/service/ec2 v1.304.0
github.com/aws/aws-sdk-go-v2/service/ecs v1.81.0
github.com/aws/aws-sdk-go-v2/service/elasticache v1.52.2
github.com/aws/aws-sdk-go-v2/service/kafka v1.52.0
github.com/aws/aws-sdk-go-v2/service/lightsail v1.54.0
github.com/aws/aws-sdk-go-v2/service/rds v1.118.2
github.com/aws/aws-sdk-go-v2/service/sts v1.42.1
github.com/aws/smithy-go v1.26.0
github.com/bboreham/go-loser v0.0.0-20230920113527-fcc2c21820a3
github.com/cespare/xxhash/v2 v2.3.0
github.com/dennwc/varint v1.0.0
github.com/digitalocean/godo v1.178.0
github.com/digitalocean/godo v1.193.0
github.com/edsrzf/mmap-go v1.2.1-0.20241212181136-fad1cd13edbd
github.com/envoyproxy/go-control-plane/envoy v1.37.0
github.com/envoyproxy/protoc-gen-validate v1.3.3
github.com/facette/natsort v0.0.0-20181210072756-2cd4dd1e2dcb
github.com/felixge/fgprof v0.9.5
github.com/fsnotify/fsnotify v1.9.0
github.com/go-openapi/strfmt v0.26.1
github.com/fsnotify/fsnotify v1.10.1
github.com/go-openapi/strfmt v0.26.2
github.com/go-zookeeper/zk v1.0.4
github.com/gogo/protobuf v1.3.2
github.com/golang/snappy v1.0.0
github.com/google/go-cmp v0.7.0
github.com/google/pprof v0.0.0-20260302011040-a15ffb7f9dcc
github.com/google/pprof v0.0.0-20260507013755-92041b743c96
github.com/google/uuid v1.6.0
github.com/gophercloud/gophercloud/v2 v2.11.1
github.com/gophercloud/gophercloud/v2 v2.12.0
github.com/grafana/regexp v0.0.0-20250905093917-f7b3be9d1853
github.com/hashicorp/consul/api v1.32.1
github.com/hashicorp/nomad/api v0.0.0-20260324203407-b27b0c2e019a
github.com/hetznercloud/hcloud-go/v2 v2.36.0
github.com/ionos-cloud/sdk-go/v6 v6.3.6
github.com/hashicorp/nomad/api v0.0.0-20260528135333-5b027732945f
github.com/hetznercloud/hcloud-go/v2 v2.41.2
github.com/ionos-cloud/sdk-go/v6 v6.3.7
github.com/json-iterator/go v1.1.12
github.com/klauspost/compress v1.18.5
github.com/klauspost/compress v1.18.6
github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b
github.com/linode/linodego v1.66.0
github.com/linode/linodego v1.69.1
github.com/miekg/dns v1.1.72
github.com/moby/moby/api v1.54.0
github.com/moby/moby/client v0.3.0
github.com/moby/moby/api v1.54.2
github.com/moby/moby/client v0.4.1
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f
github.com/nsf/jsondiff v0.0.0-20260207060731-8e8d90c4c0ac
github.com/oklog/run v1.2.0
github.com/oklog/ulid/v2 v2.1.1
github.com/open-telemetry/opentelemetry-collector-contrib/processor/deltatocumulativeprocessor v0.148.0
github.com/outscale/osc-sdk-go/v2 v2.32.0
github.com/open-telemetry/opentelemetry-collector-contrib/processor/deltatocumulativeprocessor v0.153.0
github.com/outscale/osc-sdk-go/v2 v2.34.0
github.com/ovh/go-ovh v1.9.0
github.com/pb33f/libopenapi v0.34.4
github.com/pb33f/libopenapi-validator v0.13.3
github.com/prometheus/alertmanager v0.31.1
github.com/pb33f/libopenapi v0.37.2
github.com/pb33f/libopenapi-validator v0.13.8
github.com/prometheus/alertmanager v0.32.1
github.com/prometheus/client_golang v1.23.2
github.com/prometheus/client_golang/exp v0.0.0-20260325093428-d8591d0db856
github.com/prometheus/client_golang/exp v0.0.0-20260518105423-c9d5bc4c50a9
github.com/prometheus/client_model v0.6.2
github.com/prometheus/common v0.67.5
github.com/prometheus/common/assets v0.2.0
github.com/prometheus/exporter-toolkit v0.15.1
github.com/prometheus/exporter-toolkit v0.16.0
github.com/prometheus/sigv4 v0.4.1
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.36
github.com/shurcooL/httpfs v0.0.0-20230704072500-f1e31cf0ba5c
github.com/stackitcloud/stackit-sdk-go/core v0.23.0
github.com/stackitcloud/stackit-sdk-go/core v0.26.0
github.com/stretchr/testify v1.11.1
github.com/vultr/govultr/v3 v3.28.1
go.opentelemetry.io/collector/component v1.54.0
go.opentelemetry.io/collector/consumer v1.54.0
go.opentelemetry.io/collector/pdata v1.54.0
go.opentelemetry.io/collector/processor v1.54.0
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.67.0
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.67.0
go.opentelemetry.io/otel v1.42.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.42.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.42.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.42.0
go.opentelemetry.io/otel/metric v1.42.0
go.opentelemetry.io/otel/sdk v1.42.0
go.opentelemetry.io/otel/trace v1.42.0
github.com/vultr/govultr/v3 v3.31.2
go.opentelemetry.io/collector/component v1.59.0
go.opentelemetry.io/collector/consumer v1.59.0
go.opentelemetry.io/collector/pdata v1.59.0
go.opentelemetry.io/collector/processor v1.59.0
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.69.0
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0
go.opentelemetry.io/otel v1.44.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.44.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.44.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.44.0
go.opentelemetry.io/otel/metric v1.44.0
go.opentelemetry.io/otel/sdk v1.44.0
go.opentelemetry.io/otel/trace v1.44.0
go.uber.org/atomic v1.11.0
go.uber.org/automaxprocs v1.6.0
go.uber.org/goleak v1.3.0
@ -96,11 +96,11 @@ require (
go.yaml.in/yaml/v4 v4.0.0-rc.4
golang.org/x/oauth2 v0.36.0
golang.org/x/sync v0.20.0
golang.org/x/sys v0.42.0
golang.org/x/text v0.35.0
google.golang.org/api v0.272.0
google.golang.org/genproto/googleapis/api v0.0.0-20260319201613-d00831a3d3e7
google.golang.org/grpc v1.79.3
golang.org/x/sys v0.45.0
golang.org/x/text v0.37.0
google.golang.org/api v0.278.0
google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa
google.golang.org/grpc v1.81.1
google.golang.org/protobuf v1.36.11
k8s.io/api v0.35.3
k8s.io/apimachinery v0.35.3
@ -111,14 +111,15 @@ require (
require (
github.com/aws/aws-sdk-go v1.55.8 // indirect
github.com/aws/aws-sdk-go-v2/service/signin v1.0.8 // indirect
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.24 // indirect
github.com/aws/aws-sdk-go-v2/service/signin v1.0.11 // indirect
github.com/bahlo/generic-list-go v0.2.0 // indirect
github.com/basgys/goxml2json v1.1.1-0.20231018121955-e66ee54ceaad // indirect
github.com/buger/jsonparser v1.1.2 // indirect
github.com/go-openapi/swag/cmdutils v0.25.5 // indirect
github.com/go-openapi/swag/conv v0.25.5 // indirect
github.com/go-openapi/swag/fileutils v0.25.5 // indirect
github.com/go-openapi/swag/jsonname v0.25.5 // indirect
github.com/go-openapi/swag/jsonname v0.26.0 // indirect
github.com/go-openapi/swag/jsonutils v0.25.5 // indirect
github.com/go-openapi/swag/loading v0.25.5 // indirect
github.com/go-openapi/swag/mangling v0.25.5 // indirect
@ -130,40 +131,40 @@ require (
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/pb33f/jsonpath v0.8.2 // indirect
github.com/pb33f/ordered-map/v2 v2.3.1 // indirect
github.com/puzpuzpuz/xsync/v4 v4.4.0 // indirect
github.com/puzpuzpuz/xsync/v4 v4.5.0 // indirect
github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 // indirect
go.opentelemetry.io/collector/internal/componentalias v0.148.0 // indirect
go.opentelemetry.io/collector/internal/componentalias v0.153.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/tools/godoc v0.1.0-deprecated // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
sigs.k8s.io/structured-merge-diff/v6 v6.3.0 // indirect
)
require (
cloud.google.com/go/auth v0.18.2 // indirect
cloud.google.com/go/auth v0.20.0 // indirect
cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect
cloud.google.com/go/compute/metadata v0.9.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.12.0 // indirect
github.com/AzureAD/microsoft-authentication-library-for-go v1.6.0 // indirect
github.com/Microsoft/go-winio v0.6.2 // indirect
github.com/armon/go-metrics v0.4.1 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.20
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.20 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.20 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.6 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.7 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.20 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.30.13 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.17 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.23
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.23 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.23 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.9 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.23 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.30.17 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.36.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/cenkalti/backoff/v5 v5.0.3
github.com/cncf/xds/go v0.0.0-20251210132809-ee656c7534f5 // indirect
github.com/cncf/xds/go v0.0.0-20260202195803-dba9d589def2 // indirect
github.com/containerd/errdefs v1.0.0 // indirect
github.com/containerd/errdefs/pkg v0.3.0 // indirect
github.com/coreos/go-systemd/v22 v22.6.0 // indirect
github.com/coreos/go-systemd/v22 v22.7.0 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/distribution/reference v0.6.0 // indirect
github.com/docker/go-connections v0.6.0 // indirect
github.com/docker/go-connections v0.7.0 // indirect
github.com/docker/go-units v0.5.0 // indirect
github.com/emicklei/go-restful/v3 v3.12.2 // indirect
github.com/fatih/color v1.18.0 // indirect
@ -171,9 +172,9 @@ require (
github.com/fxamacker/cbor/v2 v2.9.0 // indirect
github.com/go-logr/logr v1.4.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-openapi/analysis v0.24.3 // indirect
github.com/go-openapi/analysis v0.25.0 // indirect
github.com/go-openapi/errors v0.22.7 // indirect
github.com/go-openapi/jsonpointer v0.22.5 // indirect
github.com/go-openapi/jsonpointer v0.23.1 // indirect
github.com/go-openapi/jsonreference v0.21.5 // indirect
github.com/go-openapi/loads v0.23.3 // indirect
github.com/go-openapi/spec v0.22.4 // indirect
@ -186,10 +187,10 @@ require (
github.com/google/gnostic-models v0.7.0 // indirect
github.com/google/go-querystring v1.2.0 // indirect
github.com/google/s2a-go v0.1.9 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.14 // indirect
github.com/googleapis/gax-go/v2 v2.18.0 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.15 // indirect
github.com/googleapis/gax-go/v2 v2.22.0 // indirect
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0 // indirect
github.com/hashicorp/cronexpr v1.1.3 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
@ -198,14 +199,14 @@ require (
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hashicorp/go-retryablehttp v0.7.8 // indirect
github.com/hashicorp/go-rootcerts v1.0.2 // indirect
github.com/hashicorp/go-version v1.8.0 // indirect
github.com/hashicorp/go-version v1.9.0 // indirect
github.com/hashicorp/golang-lru v0.6.0 // indirect
github.com/hashicorp/serf v0.10.1 // indirect
github.com/jpillora/backoff v1.0.0 // indirect
github.com/julienschmidt/httprouter v1.3.0 // indirect
github.com/knadh/koanf/maps v0.1.2 // indirect
github.com/knadh/koanf/providers/confmap v1.0.0 // indirect
github.com/knadh/koanf/v2 v2.3.3 // indirect
github.com/knadh/koanf/v2 v2.3.4 // indirect
github.com/kylelemons/godebug v1.1.0 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
@ -217,8 +218,8 @@ require (
github.com/moby/docker-image-spec v1.3.1 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect
github.com/open-telemetry/opentelemetry-collector-contrib/internal/exp/metrics v0.148.0 // indirect
github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatautil v0.148.0 // indirect
github.com/open-telemetry/opentelemetry-collector-contrib/internal/exp/metrics v0.153.0 // indirect
github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatautil v0.153.0 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.1.1 // indirect
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect
@ -232,23 +233,23 @@ require (
github.com/x448/float16 v0.8.4 // indirect
github.com/xhit/go-str2duration/v2 v2.1.0 // indirect
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
go.opentelemetry.io/collector/confmap v1.54.0 // indirect
go.opentelemetry.io/collector/confmap/xconfmap v0.148.0 // indirect
go.opentelemetry.io/collector/featuregate v1.54.0 // indirect
go.opentelemetry.io/collector/pipeline v1.54.0 // indirect
go.opentelemetry.io/proto/otlp v1.9.0 // indirect
go.uber.org/zap v1.27.1 // indirect
golang.org/x/crypto v0.49.0 // indirect
go.opentelemetry.io/collector/confmap v1.59.0 // indirect
go.opentelemetry.io/collector/confmap/xconfmap v0.153.0 // indirect
go.opentelemetry.io/collector/featuregate v1.59.0 // indirect
go.opentelemetry.io/collector/pipeline v1.59.0 // indirect
go.opentelemetry.io/proto/otlp v1.10.0 // indirect
go.uber.org/zap v1.28.0 // indirect
golang.org/x/crypto v0.52.0 // indirect
golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa // indirect
golang.org/x/mod v0.33.0 // indirect
golang.org/x/net v0.52.0 // indirect
golang.org/x/term v0.41.0 // indirect
golang.org/x/mod v0.36.0 // indirect
golang.org/x/net v0.55.0 // indirect
golang.org/x/term v0.43.0 // indirect
golang.org/x/time v0.15.0 // indirect
golang.org/x/tools v0.42.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20260311181403-84a4fc48630c // indirect
golang.org/x/tools v0.45.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa // indirect
gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/ini.v1 v1.67.1 // indirect
gopkg.in/ini.v1 v1.67.2 // indirect
k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 // indirect
k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 // indirect
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect

420
go.sum
View file

@ -1,17 +1,17 @@
cloud.google.com/go/auth v0.18.2 h1:+Nbt5Ev0xEqxlNjd6c+yYUeosQ5TtEUaNcN/3FozlaM=
cloud.google.com/go/auth v0.18.2/go.mod h1:xD+oY7gcahcu7G2SG2DsBerfFxgPAJz17zz2joOFF3M=
cloud.google.com/go/auth v0.20.0 h1:kXTssoVb4azsVDoUiF8KvxAqrsQcQtB53DcSgta74CA=
cloud.google.com/go/auth v0.20.0/go.mod h1:942/yi/itH1SsmpyrbnTMDgGfdy2BUqIKyd0cyYLc5Q=
cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc=
cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c=
cloud.google.com/go/compute/metadata v0.9.0 h1:pDUj4QMoPejqq20dK0Pg2N4yG9zIkYGdBtwLoEkH9Zs=
cloud.google.com/go/compute/metadata v0.9.0/go.mod h1:E0bWwX5wTnLPedCKqk3pJmVgCBSM6qQI1yTBdEb3C10=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.21.0 h1:fou+2+WFTib47nS+nz/ozhEBnvU96bKHy6LjRsY4E28=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.21.0/go.mod h1:t76Ruy8AHvUAC8GfMWJMa0ElSbuIcO03NLpynfbgsPA=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.21.1 h1:jHb/wfvRikGdxMXYV3QG/SzUOPYN9KEUUuC0Yd0/vC0=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.21.1/go.mod h1:pzBXCYn05zvYIrwLgtK8Ap8QcjRg+0i76tMQdWN6wOk=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.1 h1:Hk5QBxZQC1jb2Fwj6mpzme37xbCDdNTxU7O9eb5+LB4=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.1/go.mod h1:IYus9qsFobWIc2YVwe/WPjcnyCkPKtnHAqUYeebc8z0=
github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2 h1:yz1bePFlP5Vws5+8ez6T3HWXPmwOK7Yvq8QxDBD3SKY=
github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2/go.mod h1:Pa9ZNPuoNu/GztvBSKk9J1cDJW6vk/n0zLtV4mgd8N8=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2 h1:9iefClla7iYpfYWdzPCRDozdmndjTm8DXdpCzPajMgA=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2/go.mod h1:XtLgD3ZD34DAaVIIAyG3objl5DynM3CQ/vMcbBNJZGI=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.12.0 h1:fhqpLE3UEXi9lPaBRpQ6XuRW0nU7hgg4zlmZZa+a9q4=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.12.0/go.mod h1:7dCRMLwisfRH3dBupKeNCioWYUZ4SS09Z14H+7i8ZoY=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5 v5.7.0 h1:LkHbJbgF3YyvC53aqYGR+wWQDn2Rdp9AQdGndf9QvY4=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5 v5.7.0/go.mod h1:QyiQdW4f4/BIfB8ZutZ2s+28RAgfa/pT+zS++ZHyM1I=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal/v2 v2.0.0 h1:PTFGRSlMKCQelWwxUyYVEUqseBJVemLyqWJjvMyt0do=
@ -49,46 +49,46 @@ github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj
github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/aws/aws-sdk-go v1.55.8 h1:JRmEUbU52aJQZ2AjX4q4Wu7t4uZjOu71uyNmaWlUkJQ=
github.com/aws/aws-sdk-go v1.55.8/go.mod h1:ZkViS9AqA6otK+JBBNH2++sx1sgxrPKcSzPPvQkUtXk=
github.com/aws/aws-sdk-go-v2 v1.41.4 h1:10f50G7WyU02T56ox1wWXq+zTX9I1zxG46HYuG1hH/k=
github.com/aws/aws-sdk-go-v2 v1.41.4/go.mod h1:mwsPRE8ceUUpiTgF7QmQIJ7lgsKUPQOUl3o72QBrE1o=
github.com/aws/aws-sdk-go-v2/config v1.32.12 h1:O3csC7HUGn2895eNrLytOJQdoL2xyJy0iYXhoZ1OmP0=
github.com/aws/aws-sdk-go-v2/config v1.32.12/go.mod h1:96zTvoOFR4FURjI+/5wY1vc1ABceROO4lWgWJuxgy0g=
github.com/aws/aws-sdk-go-v2/credentials v1.19.12 h1:oqtA6v+y5fZg//tcTWahyN9PEn5eDU/Wpvc2+kJ4aY8=
github.com/aws/aws-sdk-go-v2/credentials v1.19.12/go.mod h1:U3R1RtSHx6NB0DvEQFGyf/0sbrpJrluENHdPy1j/3TE=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.20 h1:zOgq3uezl5nznfoK3ODuqbhVg1JzAGDUhXOsU0IDCAo=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.20/go.mod h1:z/MVwUARehy6GAg/yQ1GO2IMl0k++cu1ohP9zo887wE=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.20 h1:CNXO7mvgThFGqOFgbNAP2nol2qAWBOGfqR/7tQlvLmc=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.20/go.mod h1:oydPDJKcfMhgfcgBUZaG+toBbwy8yPWubJXBVERtI4o=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.20 h1:tN6W/hg+pkM+tf9XDkWUbDEjGLb+raoBMFsTodcoYKw=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.20/go.mod h1:YJ898MhD067hSHA6xYCx5ts/jEd8BSOLtQDL3iZsvbc=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.6 h1:qYQ4pzQ2Oz6WpQ8T3HvGHnZydA72MnLuFK9tJwmrbHw=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.6/go.mod h1:O3h0IK87yXci+kg6flUKzJnWeziQUKciKrLjcatSNcY=
github.com/aws/aws-sdk-go-v2/service/ec2 v1.296.0 h1:98Miqj16un1WLNyM1RjVDhXYumhqZrQfAeG8i4jPG6o=
github.com/aws/aws-sdk-go-v2/service/ec2 v1.296.0/go.mod h1:T6ndRfdhnXLIY5oKBHjYZDVj706los2zGdpThppquvA=
github.com/aws/aws-sdk-go-v2/service/ecs v1.74.0 h1:YS5TXaEvzDb+sV+wdQFUtuCAk0GeFR9Ai6HFdxpz6q8=
github.com/aws/aws-sdk-go-v2/service/ecs v1.74.0/go.mod h1:10kBgdaNJz0FO/+JWDUH+0rtSjkn5yafgavDDmmhFzs=
github.com/aws/aws-sdk-go-v2/service/elasticache v1.51.12 h1:S066ajzfPRCSW4lsSHOYglne6SNi2CHt1u5omzW1RBg=
github.com/aws/aws-sdk-go-v2/service/elasticache v1.51.12/go.mod h1:86SE4NcXxbxr8KTG3yOyDmd4HyiFmKl8TexXnhYJ+Bw=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.7 h1:5EniKhLZe4xzL7a+fU3C2tfUN4nWIqlLesfrjkuPFTY=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.7/go.mod h1:x0nZssQ3qZSnIcePWLvcoFisRXJzcTVvYpAAdYX8+GI=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.20 h1:2HvVAIq+YqgGotK6EkMf+KIEqTISmTYh5zLpYyeTo1Y=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.20/go.mod h1:V4X406Y666khGa8ghKmphma/7C0DAtEQYhkq9z4vpbk=
github.com/aws/aws-sdk-go-v2/service/kafka v1.49.1 h1:BgBatWcQIFqF1l6KGHjv66V0d/ISnWrTwxDx/Jf6EJM=
github.com/aws/aws-sdk-go-v2/service/kafka v1.49.1/go.mod h1:pMpys+PlrN//vj8j5s0oOAMJjauj81VkHzIZxPVWOro=
github.com/aws/aws-sdk-go-v2/service/lightsail v1.51.0 h1:cg6PxzoIide2wiEyLfikOFN+XwHafwR8p5+L9U1E8dQ=
github.com/aws/aws-sdk-go-v2/service/lightsail v1.51.0/go.mod h1:YvX7hjUWecrKX8fBkbEncyddEW85xjNH+u5JHioITOw=
github.com/aws/aws-sdk-go-v2/service/rds v1.117.0 h1:T1Xe9sYxSUUQOvd1RsFeVk/IXFPdqSiN0atXu/Hy/8A=
github.com/aws/aws-sdk-go-v2/service/rds v1.117.0/go.mod h1:QbXW4coAMakHQhf1qhE0eVVCen9gwB/Kvn+HHHKhpGY=
github.com/aws/aws-sdk-go-v2/service/signin v1.0.8 h1:0GFOLzEbOyZABS3PhYfBIx2rNBACYcKty+XGkTgw1ow=
github.com/aws/aws-sdk-go-v2/service/signin v1.0.8/go.mod h1:LXypKvk85AROkKhOG6/YEcHFPoX+prKTowKnVdcaIxE=
github.com/aws/aws-sdk-go-v2/service/sso v1.30.13 h1:kiIDLZ005EcKomYYITtfsjn7dtOwHDOFy7IbPXKek2o=
github.com/aws/aws-sdk-go-v2/service/sso v1.30.13/go.mod h1:2h/xGEowcW/g38g06g3KpRWDlT+OTfxxI0o1KqayAB8=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.17 h1:jzKAXIlhZhJbnYwHbvUQZEB8KfgAEuG0dc08Bkda7NU=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.17/go.mod h1:Al9fFsXjv4KfbzQHGe6V4NZSZQXecFcvaIF4e70FoRA=
github.com/aws/aws-sdk-go-v2/service/sts v1.41.9 h1:Cng+OOwCHmFljXIxpEVXAGMnBia8MSU6Ch5i9PgBkcU=
github.com/aws/aws-sdk-go-v2/service/sts v1.41.9/go.mod h1:LrlIndBDdjA/EeXeyNBle+gyCwTlizzW5ycgWnvIxkk=
github.com/aws/smithy-go v1.24.2 h1:FzA3bu/nt/vDvmnkg+R8Xl46gmzEDam6mZ1hzmwXFng=
github.com/aws/smithy-go v1.24.2/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc=
github.com/aws/aws-sdk-go-v2 v1.41.7 h1:DWpAJt66FmnnaRIOT/8ASTucrvuDPZASqhhLey6tLY8=
github.com/aws/aws-sdk-go-v2 v1.41.7/go.mod h1:4LAfZOPHNVNQEckOACQx60Y8pSRjIkNZQz1w92xpMJc=
github.com/aws/aws-sdk-go-v2/config v1.32.18 h1:Hcia46bxhGgF3BaSnG8nSNCWmqTK6bj9xN9/FJ3WK6Q=
github.com/aws/aws-sdk-go-v2/config v1.32.18/go.mod h1:zEjCAYmxqDadH1WX8CdBvmLKhUEUVFgKRQG38zjDmrY=
github.com/aws/aws-sdk-go-v2/credentials v1.19.17 h1:gP2nkGsS+KMvF/jfFz2Vv2qiiOqWKyPACSzPsqHgoW8=
github.com/aws/aws-sdk-go-v2/credentials v1.19.17/go.mod h1:Bsew3S/moG5iT77giPj1q8wb/s0RE5/QfH+ASjYtuQc=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.23 h1:UuSfcORqNSz/ey3VPRS8TcVH2Ikf0/sC+Hdj400QI6U=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.23/go.mod h1:+G/OSGiOFnSOkYloKj/9M35s74LgVAdJBSD5lsFfqKg=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.23 h1:GpT/TrnBYuE5gan2cZbTtvP+JlHsutdmlV2YfEyNde0=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.23/go.mod h1:xYWD6BS9ywC5bS3sz9Xh04whO/hzK2plt2Zkyrp4JuA=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.23 h1:bpd8vxhlQi2r1hiueOw02f/duEPTMK59Q4QMAoTTtTo=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.23/go.mod h1:15DfR2nw+CRHIk0tqNyifu3G1YdAOy68RftkhMDDwYk=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.24 h1:OQqn11BtaYv1WLUowvcA30MpzIu8Ti4pcLPIIyoKZrA=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.24/go.mod h1:X5ZJyfwVrWA96GzPmUCWFQaEARPR7gCrpq2E92PJwAE=
github.com/aws/aws-sdk-go-v2/service/ec2 v1.304.0 h1:wZthLlYdKxBo7NpWLbl0A/8DB/QNDB+8RJa9WboK9Q0=
github.com/aws/aws-sdk-go-v2/service/ec2 v1.304.0/go.mod h1:Y95W0Hm6FYLPa6o0hbnJ+sWgmdc4ifcLFjGkdobWVhY=
github.com/aws/aws-sdk-go-v2/service/ecs v1.81.0 h1:2Sp9EwK7giQpJnQ54k0zdUh6aykmmbpEurEEygr104c=
github.com/aws/aws-sdk-go-v2/service/ecs v1.81.0/go.mod h1:TIKZ9zIFS6W2k9FeW+r5sGVnlxp+aUt9oQ/St3Suj1o=
github.com/aws/aws-sdk-go-v2/service/elasticache v1.52.2 h1:5wbCUfyxXcjIqesyVfJBBJs0bDMyejthtHyy48mfZCI=
github.com/aws/aws-sdk-go-v2/service/elasticache v1.52.2/go.mod h1:o4vQxDt6oteknUjkXIEskp0ccy+93NRTPKXw3HlVMFE=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.9 h1:FLudkZLt5ci0ozzgkVo8BJGwvqNaZbTWb3UcucAateA=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.9/go.mod h1:w7wZ/s9qK7c8g4al+UyoF1Sp/Z45UwMGcqIzLWVQHWk=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.23 h1:pbrxO/kuIwgEsOPLkaHu0O+m4fNgLU8B3vxQ+72jTPw=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.23/go.mod h1:/CMNUqoj46HpS3MNRDEDIwcgEnrtZlKRaHNaHxIFpNA=
github.com/aws/aws-sdk-go-v2/service/kafka v1.52.0 h1:jalIJqKvZMvJRvs6ABLX+FhHz8E9pjU03Pyml4D9r3k=
github.com/aws/aws-sdk-go-v2/service/kafka v1.52.0/go.mod h1:pW4pYNuVeScl13yqwsjLY0F/7g2YD8E0AvR6SOQsJZE=
github.com/aws/aws-sdk-go-v2/service/lightsail v1.54.0 h1:07DKnL5eKSel3XEM2UxlD/z9zUZZ6XMHLGDXkAdY4u8=
github.com/aws/aws-sdk-go-v2/service/lightsail v1.54.0/go.mod h1:Etcg8xorq1b0g0V2KMNgFjubYITZseJv08qtX/3szko=
github.com/aws/aws-sdk-go-v2/service/rds v1.118.2 h1:pkEeQneYFpTAnGhyqSbyp/DlCPPJTGt0GkWahlLYzMA=
github.com/aws/aws-sdk-go-v2/service/rds v1.118.2/go.mod h1:7gS+cGrKF0mH253QHFlStmx79ws+DlNk+04ZRfmw3U0=
github.com/aws/aws-sdk-go-v2/service/signin v1.0.11 h1:TdJ+HdzOBhU8+iVAOGUTU63VXopcumCOF1paFulHWZc=
github.com/aws/aws-sdk-go-v2/service/signin v1.0.11/go.mod h1:R82ZRExE/nheo0N+T8zHPcLRTcH8MGsnR3BiVGX0TwI=
github.com/aws/aws-sdk-go-v2/service/sso v1.30.17 h1:7byT8HUWrgoRp6sXjxtZwgOKfhss5fW6SkLBtqzgRoE=
github.com/aws/aws-sdk-go-v2/service/sso v1.30.17/go.mod h1:xNWknVi4Ezm1vg1QsB/5EWpAJURq22uqd38U8qKvOJc=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.36.0 h1:nDARhv/oF55bcxF7rCI/4PDxOKnVXVWwDuDwCs2I2SQ=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.36.0/go.mod h1:4vIRDq+CJB2xFAXZ+YgGUTiEft7oAQlhIs71xcSeuVg=
github.com/aws/aws-sdk-go-v2/service/sts v1.42.1 h1:F/M5Y9I3nwr2IEpshZgh1GeHpOItExNM9L1euNuh/fk=
github.com/aws/aws-sdk-go-v2/service/sts v1.42.1/go.mod h1:mTNxImtovCOEEuD65mKW7DCsL+2gjEH+RPEAexAzAio=
github.com/aws/smithy-go v1.26.0 h1:9ouqbi+NyKP7fV3Te7UElCwdAb6Y8uk7LGwPE5tVe/s=
github.com/aws/smithy-go v1.26.0/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc=
github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk=
github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg=
github.com/basgys/goxml2json v1.1.1-0.20231018121955-e66ee54ceaad h1:3swAvbzgfaI6nKuDDU7BiKfZRdF+h2ZwKgMHd8Ha4t8=
@ -117,28 +117,28 @@ github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObk
github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8=
github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag=
github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=
github.com/cncf/xds/go v0.0.0-20251210132809-ee656c7534f5 h1:6xNmx7iTtyBRev0+D/Tv1FZd4SCg8axKApyNyRsAt/w=
github.com/cncf/xds/go v0.0.0-20251210132809-ee656c7534f5/go.mod h1:KdCmV+x/BuvyMxRnYBlmVaq4OLiKW6iRQfvC62cvdkI=
github.com/cncf/xds/go v0.0.0-20260202195803-dba9d589def2 h1:aBangftG7EVZoUb69Os8IaYg++6uMOdKK83QtkkvJik=
github.com/cncf/xds/go v0.0.0-20260202195803-dba9d589def2/go.mod h1:qwXFYgsP6T7XnJtbKlf1HP8AjxZZyzxMmc+Lq5GjlU4=
github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI=
github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M=
github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE=
github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk=
github.com/coreos/go-systemd/v22 v22.6.0 h1:aGVa/v8B7hpb0TKl0MWoAavPDmHvobFe5R5zn0bCJWo=
github.com/coreos/go-systemd/v22 v22.6.0/go.mod h1:iG+pp635Fo7ZmV/j14KUcmEyWF+0X7Lua8rrTWzYgWU=
github.com/coreos/go-systemd/v22 v22.7.0 h1:LAEzFkke61DFROc7zNLX/WA2i5J8gYqe0rSj9KI28KA=
github.com/coreos/go-systemd/v22 v22.7.0/go.mod h1:xNUYtjHu2EDXbsxz1i41wouACIwT7Ybq9o0BQhMwD0w=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dennwc/varint v1.0.0 h1:kGNFFSSw8ToIy3obO/kKr8U9GZYUAxQEVuix4zfDWzE=
github.com/dennwc/varint v1.0.0/go.mod h1:hnItb35rvZvJrbTALZtY/iQfDs48JKRG1RPpgziApxA=
github.com/digitalocean/godo v1.178.0 h1:+B4xGOaoFwwwpM7TKhoyGHdmFg5eF9zDB1YfOLvNJ2E=
github.com/digitalocean/godo v1.178.0/go.mod h1:xQsWpVCCbkDrWisHA72hPzPlnC+4W5w/McZY5ij9uvU=
github.com/digitalocean/godo v1.193.0 h1:CSbbUl5LufT75KPNvex3vDnBYjY2RfJWs7T3Ac7dHpA=
github.com/digitalocean/godo v1.193.0/go.mod h1:xQsWpVCCbkDrWisHA72hPzPlnC+4W5w/McZY5ij9uvU=
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZQ=
github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/docker/go-connections v0.6.0 h1:LlMG9azAe1TqfR7sO+NJttz1gy6KO7VJBh+pMmjSD94=
github.com/docker/go-connections v0.6.0/go.mod h1:AahvXYshr6JgfUJGdDCs2b5EZG/vmaMAntpSFH5BFKE=
github.com/dlclark/regexp2 v1.12.0 h1:0j4c5qQmnC6XOWNjP3PIXURXN2gWx76rd3KvgdPkCz8=
github.com/dlclark/regexp2 v1.12.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/docker/go-connections v0.7.0 h1:6SsRfJddP22WMrCkj19x9WKjEDTB+ahsdiGYf0mN39c=
github.com/docker/go-connections v0.7.0/go.mod h1:no1qkHdjq7kLMGUXYAduOhYPSJxxvgWBh7ogVvptn3Q=
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/edsrzf/mmap-go v1.2.1-0.20241212181136-fad1cd13edbd h1:I4PrRZuNMeDP3VbFrak4QsqwO5tWkQf0tqrrr1L2DsU=
@ -160,8 +160,8 @@ github.com/felixge/fgprof v0.9.5 h1:8+vR6yu2vvSKn08urWyEuxx75NWPEvybbkBirEpsbVY=
github.com/felixge/fgprof v0.9.5/go.mod h1:yKl+ERSa++RYOs32d8K6WEXCB4uXdLls4ZaZPpayhMM=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
github.com/fsnotify/fsnotify v1.10.1 h1:b0/UzAf9yR5rhf3RPm9gf3ehBPpf0oZKIjtpKrx59Ho=
github.com/fsnotify/fsnotify v1.10.1/go.mod h1:TLheqan6HD6GBK6PrDWyDPBaEV8LspOxvPSjC+bVfgo=
github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM=
github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
@ -174,20 +174,20 @@ github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-openapi/analysis v0.24.3 h1:a1hrvMr8X0Xt69KP5uVTu5jH62DscmDifrLzNglAayk=
github.com/go-openapi/analysis v0.24.3/go.mod h1:Nc+dWJ/FxZbhSow5Yh3ozg5CLJioB+XXT6MdLvJUsUw=
github.com/go-openapi/analysis v0.25.0 h1:EnjAq1yO8wEO9HbPmY8vLPEIkdZuuFhCAKBPvCB7bCs=
github.com/go-openapi/analysis v0.25.0/go.mod h1:5WFTRE43WLkPG9r9OtlMfqkkvUTYLVVCIxLlEpyF8kE=
github.com/go-openapi/errors v0.22.7 h1:JLFBGC0Apwdzw3484MmBqspjPbwa2SHvpDm0u5aGhUA=
github.com/go-openapi/errors v0.22.7/go.mod h1://QW6SD9OsWtH6gHllUCddOXDL0tk0ZGNYHwsw4sW3w=
github.com/go-openapi/jsonpointer v0.22.5 h1:8on/0Yp4uTb9f4XvTrM2+1CPrV05QPZXu+rvu2o9jcA=
github.com/go-openapi/jsonpointer v0.22.5/go.mod h1:gyUR3sCvGSWchA2sUBJGluYMbe1zazrYWIkWPjjMUY0=
github.com/go-openapi/jsonpointer v0.23.1 h1:1HBACs7XIwR2RcmItfdSFlALhGbe6S92p0ry4d1GWg4=
github.com/go-openapi/jsonpointer v0.23.1/go.mod h1:iWRmZTrGn7XwYhtPt/fvdSFj1OfNBngqRT2UG3BxSqY=
github.com/go-openapi/jsonreference v0.21.5 h1:6uCGVXU/aNF13AQNggxfysJ+5ZcU4nEAe+pJyVWRdiE=
github.com/go-openapi/jsonreference v0.21.5/go.mod h1:u25Bw85sX4E2jzFodh1FOKMTZLcfifd1Q+iKKOUxExw=
github.com/go-openapi/loads v0.23.3 h1:g5Xap1JfwKkUnZdn+S0L3SzBDpcTIYzZ5Qaag0YDkKQ=
github.com/go-openapi/loads v0.23.3/go.mod h1:NOH07zLajXo8y55hom0omlHWDVVvCwBM/S+csCK8LqA=
github.com/go-openapi/spec v0.22.4 h1:4pxGjipMKu0FzFiu/DPwN3CTBRlVM2yLf/YTWorYfDQ=
github.com/go-openapi/spec v0.22.4/go.mod h1:WQ6Ai0VPWMZgMT4XySjlRIE6GP1bGQOtEThn3gcWLtQ=
github.com/go-openapi/strfmt v0.26.1 h1:7zGCHji7zSYDC2tCXIusoxYQz/48jAf2q+sF6wXTG+c=
github.com/go-openapi/strfmt v0.26.1/go.mod h1:Zslk5VZPOISLwmWTMBIS7oiVFem1o1EI6zULY8Uer7Y=
github.com/go-openapi/strfmt v0.26.2 h1:ysjheCh4i1rmFEo2LanhELDNucNzfWTZhUDKgWWPaFM=
github.com/go-openapi/strfmt v0.26.2/go.mod h1:fXh1e449cyUn2NYuz+wb3wARBUdMl7qPEZwX00nqivY=
github.com/go-openapi/swag v0.25.5 h1:pNkwbUEeGwMtcgxDr+2GBPAk4kT+kJ+AaB+TMKAg+TU=
github.com/go-openapi/swag v0.25.5/go.mod h1:B3RT6l8q7X803JRxa2e59tHOiZlX1t8viplOcs9CwTA=
github.com/go-openapi/swag/cmdutils v0.25.5 h1:yh5hHrpgsw4NwM9KAEtaDTXILYzdXh/I8Whhx9hKj7c=
@ -196,8 +196,8 @@ github.com/go-openapi/swag/conv v0.25.5 h1:wAXBYEXJjoKwE5+vc9YHhpQOFj2JYBMF2DUi+
github.com/go-openapi/swag/conv v0.25.5/go.mod h1:CuJ1eWvh1c4ORKx7unQnFGyvBbNlRKbnRyAvDvzWA4k=
github.com/go-openapi/swag/fileutils v0.25.5 h1:B6JTdOcs2c0dBIs9HnkyTW+5gC+8NIhVBUwERkFhMWk=
github.com/go-openapi/swag/fileutils v0.25.5/go.mod h1:V3cT9UdMQIaH4WiTrUc9EPtVA4txS0TOmRURmhGF4kc=
github.com/go-openapi/swag/jsonname v0.25.5 h1:8p150i44rv/Drip4vWI3kGi9+4W9TdI3US3uUYSFhSo=
github.com/go-openapi/swag/jsonname v0.25.5/go.mod h1:jNqqikyiAK56uS7n8sLkdaNY/uq6+D2m2LANat09pKU=
github.com/go-openapi/swag/jsonname v0.26.0 h1:gV1NFX9M8avo0YSpmWogqfQISigCmpaiNci8cGECU5w=
github.com/go-openapi/swag/jsonname v0.26.0/go.mod h1:urBBR8bZNoDYGr653ynhIx+gTeIz0ARZxHkAPktJK2M=
github.com/go-openapi/swag/jsonutils v0.25.5 h1:XUZF8awQr75MXeC+/iaw5usY/iM7nXPDwdG3Jbl9vYo=
github.com/go-openapi/swag/jsonutils v0.25.5/go.mod h1:48FXUaz8YsDAA9s5AnaUvAmry1UcLcNVWUjY42XkrN4=
github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.5 h1:SX6sE4FrGb4sEnnxbFL/25yZBb5Hcg1inLeErd86Y1U=
@ -216,8 +216,8 @@ github.com/go-openapi/swag/yamlutils v0.25.5 h1:kASCIS+oIeoc55j28T4o8KwlV2S4ZLPT
github.com/go-openapi/swag/yamlutils v0.25.5/go.mod h1:Gek1/SjjfbYvM+Iq4QGwa/2lEXde9n2j4a3wI3pNuOQ=
github.com/go-openapi/testify/enable/yaml/v2 v2.4.1 h1:NZOrZmIb6PTv5LTFxr5/mKV/FjbUzGE7E6gLz7vFoOQ=
github.com/go-openapi/testify/enable/yaml/v2 v2.4.1/go.mod h1:r7dwsujEHawapMsxA69i+XMGZrQ5tRauhLAjV/sxg3Q=
github.com/go-openapi/testify/v2 v2.4.1 h1:zB34HDKj4tHwyUQHrUkpV0Q0iXQ6dUCOQtIqn8hE6Iw=
github.com/go-openapi/testify/v2 v2.4.1/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54=
github.com/go-openapi/testify/v2 v2.4.2 h1:tiByHpvE9uHrrKjOszax7ZvKB7QOgizBWGBLuq0ePx4=
github.com/go-openapi/testify/v2 v2.4.2/go.mod h1:SgsVHtfooshd0tublTtJ50FPKhujf47YRqauXXOUxfw=
github.com/go-openapi/validate v0.25.2 h1:12NsfLAwGegqbGWr2CnvT65X/Q2USJipmJ9b7xDJZz0=
github.com/go-openapi/validate v0.25.2/go.mod h1:Pgl1LpPPGFnZ+ys4/hTlDiRYQdI1ocKypgE+8Q8BLfY=
github.com/go-resty/resty/v2 v2.17.2 h1:FQW5oHYcIlkCNrMD2lloGScxcHJ0gkjshV3qcQAyHQk=
@ -260,24 +260,24 @@ github.com/google/go-querystring v1.2.0 h1:yhqkPbu2/OH+V9BfpCVPZkNmUXhb2gBxJArfh
github.com/google/go-querystring v1.2.0/go.mod h1:8IFJqpSRITyJ8QhQ13bmbeMBDfmeEJZD5A0egEOmkqU=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/pprof v0.0.0-20240227163752-401108e1b7e7/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
github.com/google/pprof v0.0.0-20260302011040-a15ffb7f9dcc h1:VBbFa1lDYWEeV5FZKUiYKYT0VxCp9twUmmaq9eb8sXw=
github.com/google/pprof v0.0.0-20260302011040-a15ffb7f9dcc/go.mod h1:MxpfABSjhmINe3F1It9d+8exIHFvUqtLIRCdOGNXqiI=
github.com/google/pprof v0.0.0-20260507013755-92041b743c96 h1:YDDnaZ9afWajDboPMt9Vikqca/yWAX7KAxVzb4lJU1M=
github.com/google/pprof v0.0.0-20260507013755-92041b743c96/go.mod h1:MxpfABSjhmINe3F1It9d+8exIHFvUqtLIRCdOGNXqiI=
github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0=
github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/enterprise-certificate-proxy v0.3.14 h1:yh8ncqsbUY4shRD5dA6RlzjJaT4hi3kII+zYw8wmLb8=
github.com/googleapis/enterprise-certificate-proxy v0.3.14/go.mod h1:vqVt9yG9480NtzREnTlmGSBmFrA+bzb0yl0TxoBQXOg=
github.com/googleapis/gax-go/v2 v2.18.0 h1:jxP5Uuo3bxm3M6gGtV94P4lliVetoCB4Wk2x8QA86LI=
github.com/googleapis/gax-go/v2 v2.18.0/go.mod h1:uSzZN4a356eRG985CzJ3WfbFSpqkLTjsnhWGJR6EwrE=
github.com/gophercloud/gophercloud/v2 v2.11.1 h1:jCs4vLH8sJgRqrPzqVfWgl7uI6JnIIlsgeIRM0uHjxY=
github.com/gophercloud/gophercloud/v2 v2.11.1/go.mod h1:Rm0YvKQ4QYX2rY9XaDKnjRzSGwlG5ge4h6ABYnmkKQM=
github.com/googleapis/enterprise-certificate-proxy v0.3.15 h1:xolVQTEXusUcAA5UgtyRLjelpFFHWlPQ4XfWGc7MBas=
github.com/googleapis/enterprise-certificate-proxy v0.3.15/go.mod h1:vqVt9yG9480NtzREnTlmGSBmFrA+bzb0yl0TxoBQXOg=
github.com/googleapis/gax-go/v2 v2.22.0 h1:PjIWBpgGIVKGoCXuiCoP64altEJCj3/Ei+kSU5vlZD4=
github.com/googleapis/gax-go/v2 v2.22.0/go.mod h1:irWBbALSr0Sk3qlqb9SyJ1h68WjgeFuiOzI4Rqw5+aY=
github.com/gophercloud/gophercloud/v2 v2.12.0 h1:Gxmc/Bog1UDKkxTcQW7MSPTDviJXpLeEgVeN5KrxoCo=
github.com/gophercloud/gophercloud/v2 v2.12.0/go.mod h1:H7TTOxbLy8RIaHSNhI2GCrWIzw4Xpw8Xn2mBhCUT5kA=
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 h1:JeSE6pjso5THxAzdVpqr6/geYxZytqFMBCOtn/ujyeo=
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674/go.mod h1:r4w70xmWCQKmi1ONH4KIaBptdivuRPyosB9RmPlGEwA=
github.com/grafana/regexp v0.0.0-20250905093917-f7b3be9d1853 h1:cLN4IBkmkYZNnk7EAJ0BHIethd+J6LqxFNw5mSiI2bM=
github.com/grafana/regexp v0.0.0-20250905093917-f7b3be9d1853/go.mod h1:+JKpmjMGhpgPL+rXZ5nsZieVzvarn86asRlBg4uNGnk=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 h1:HWRh5R2+9EifMyIHV7ZV+MIZqgz+PMpZ14Jynv3O2Zs=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0/go.mod h1:JfhWUomR1baixubs02l85lZYYOm7LV6om4ceouMv45c=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0 h1:5VipnvEpbqr2gA2VbM+nYVbkIF28c5ZQfqCBQ5g2xfk=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0/go.mod h1:Hyl3n6Twe1hvtd9XUXDec4pTvgMSEixRuQKPTMH2bNs=
github.com/hashicorp/consul/api v1.32.1 h1:0+osr/3t/aZNAdJX558crU3PEjVrG4x6715aZHRgceE=
github.com/hashicorp/consul/api v1.32.1/go.mod h1:mXUWLnxftwTmDv4W3lzxYCPD199iNLLUyLfLGFJbtl4=
github.com/hashicorp/consul/sdk v0.16.1 h1:V8TxTnImoPD5cj0U9Spl0TUxcytjcbbJeADFF07KdHg=
@ -319,8 +319,8 @@ github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/b
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-version v1.8.0 h1:KAkNb1HAiZd1ukkxDFGmokVZe1Xy9HG6NUp+bPle2i4=
github.com/hashicorp/go-version v1.8.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/go-version v1.9.0 h1:CeOIz6k+LoN3qX9Z0tyQrPtiB1DFYRPfCIBtaXPSCnA=
github.com/hashicorp/go-version v1.9.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.6.0 h1:uL2shRDx7RTrOrTCUZEGP/wJUFiUI8QT6E7z5o8jga4=
github.com/hashicorp/golang-lru v0.6.0/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
@ -329,15 +329,15 @@ github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/
github.com/hashicorp/memberlist v0.5.0/go.mod h1:yvyXLpo0QaGE59Y7hDTsTzDD25JYBZ4mHgHUZ8lrOI0=
github.com/hashicorp/memberlist v0.5.4 h1:40YY+3qq2tAUhZIMEK8kqusKZBBjdwJ3NUjvYkcxh74=
github.com/hashicorp/memberlist v0.5.4/go.mod h1:OgN6xiIo6RlHUWk+ALjP9e32xWCoQrsOCmHrWCm2MWA=
github.com/hashicorp/nomad/api v0.0.0-20260324203407-b27b0c2e019a h1:HGwfgBNl90YBiHdbzZ/+8aMxO1UL9B/yNTAXa8iB8z8=
github.com/hashicorp/nomad/api v0.0.0-20260324203407-b27b0c2e019a/go.mod h1:KkLNLU0Nyfh5jWsFoF/PsmMbKpRIAoIV4lmQoJWgKCk=
github.com/hashicorp/nomad/api v0.0.0-20260528135333-5b027732945f h1:sdf4a6FF3tC1/c0buuizLAwZa/xLu4gWD87qWrzQLvo=
github.com/hashicorp/nomad/api v0.0.0-20260528135333-5b027732945f/go.mod h1:Kr8imJwigbQ/50BqVae2+JL+AyX+FnzbnuCoIFb6iYg=
github.com/hashicorp/serf v0.10.1 h1:Z1H2J60yRKvfDYAOZLd2MU0ND4AH/WDz7xYHDWQsIPY=
github.com/hashicorp/serf v0.10.1/go.mod h1:yL2t6BqATOLGc5HF7qbFkTfXoPIY0WZdWHfEvMqbG+4=
github.com/hetznercloud/hcloud-go/v2 v2.36.0 h1:HlLL/aaVXUulqe+rsjoJmrxKhPi1MflL5O9iq5QEtvo=
github.com/hetznercloud/hcloud-go/v2 v2.36.0/go.mod h1:MnN/QJEa/RYNQiiVoJjNHPntM7Z1wlYPgJ2HA40/cDE=
github.com/hetznercloud/hcloud-go/v2 v2.41.2 h1:fO5zsMgp5oejrtnFj8mYuqlp+iMuirpaKv4b5FYNRdQ=
github.com/hetznercloud/hcloud-go/v2 v2.41.2/go.mod h1:9OGvC//jbHE4sv2Oyo0bQ2vEWuUMKYoNMyj9Qxz2qcc=
github.com/ianlancetaylor/demangle v0.0.0-20230524184225-eabc099b10ab/go.mod h1:gx7rwoVhcfuVKG5uya9Hs3Sxj7EIvldVofAWIUtGouw=
github.com/ionos-cloud/sdk-go/v6 v6.3.6 h1:l/TtKgdQ1wUH3DDe2SfFD78AW+TJWdEbDpQhHkWd6CM=
github.com/ionos-cloud/sdk-go/v6 v6.3.6/go.mod h1:nUGHP4kZHAZngCVr4v6C8nuargFrtvt7GrzH/hqn7c4=
github.com/ionos-cloud/sdk-go/v6 v6.3.7 h1:t773JkC/asnyVqeQ+OvN9WCRZuosSoPtJfyM82EFCWY=
github.com/ionos-cloud/sdk-go/v6 v6.3.7/go.mod h1:nUGHP4kZHAZngCVr4v6C8nuargFrtvt7GrzH/hqn7c4=
github.com/jarcoal/httpmock v1.4.1 h1:0Ju+VCFuARfFlhVXFc2HxlcQkfB+Xq12/EotHko+x2A=
github.com/jarcoal/httpmock v1.4.1/go.mod h1:ftW1xULwo+j0R0JJkJIIi7UKigZUXCLLanykgjwBXL0=
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
@ -358,14 +358,14 @@ github.com/keybase/go-keychain v0.0.1 h1:way+bWYa6lDppZoZcgMbYsvC7GxljxrskdNInRt
github.com/keybase/go-keychain v0.0.1/go.mod h1:PdEILRW3i9D8JcdM+FmY6RwkHGnhHxXwkPPMeUgOK1k=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.18.5 h1:/h1gH5Ce+VWNLSWqPzOVn6XBO+vJbCNGvjoaGBFW2IE=
github.com/klauspost/compress v1.18.5/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ=
github.com/klauspost/compress v1.18.6 h1:2jupLlAwFm95+YDR+NwD2MEfFO9d4z4Prjl1XXDjuao=
github.com/klauspost/compress v1.18.6/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ=
github.com/knadh/koanf/maps v0.1.2 h1:RBfmAW5CnZT+PJ1CVc1QSJKf4Xu9kxfQgYVQSu8hpbo=
github.com/knadh/koanf/maps v0.1.2/go.mod h1:npD/QZY3V6ghQDdcQzl1W4ICNVTkohC8E73eI2xW4yI=
github.com/knadh/koanf/providers/confmap v1.0.0 h1:mHKLJTE7iXEys6deO5p6olAiZdG5zwp8Aebir+/EaRE=
github.com/knadh/koanf/providers/confmap v1.0.0/go.mod h1:txHYHiI2hAtF0/0sCmcuol4IDcuQbKTybiB1nOcUo1A=
github.com/knadh/koanf/v2 v2.3.3 h1:jLJC8XCRfLC7n4F+ZKKdBsbq1bfXTpuFhf4L7t94D94=
github.com/knadh/koanf/v2 v2.3.3/go.mod h1:gRb40VRAbd4iJMYYD5IxZ6hfuopFcXBpc9bbQpZwo28=
github.com/knadh/koanf/v2 v2.3.4 h1:fnynNSDlujWE+v83hAp8wKr/cdoxHLO0629SN+U8Urc=
github.com/knadh/koanf/v2 v2.3.4/go.mod h1:gRb40VRAbd4iJMYYD5IxZ6hfuopFcXBpc9bbQpZwo28=
github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b h1:udzkj9S/zlT5X367kqJis0QP7YMxobob6zhzq6Yre00=
github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b/go.mod h1:pcaDhQK0/NJZEvtCO0qQPPropqV0sJOJ6YW7X+9kRwM=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
@ -380,8 +380,8 @@ 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/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80/go.mod h1:imJHygn/1yfhB7XSJJKlFZKl/J+dCPAknuiaGOshXAs=
github.com/linode/linodego v1.66.0 h1:rK8QJFaV53LWOEJvb/evhTg/dP5ElvtuZmx4iv4RJds=
github.com/linode/linodego v1.66.0/go.mod h1:12ykGs9qsvxE+OU3SXuW2w+DTruWF35FPlXC7gGk2tU=
github.com/linode/linodego v1.69.1 h1:f45N2MHR/oece2/ktTTCYmrlfse4//k3NgwcF5zbGZ0=
github.com/linode/linodego v1.69.1/go.mod h1:Fha0NYsQSx5VZK1HQNJY/z/dIxxkFp+vb5veawbmAUw=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
@ -420,10 +420,10 @@ github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zx
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
github.com/moby/moby/api v1.54.0 h1:7kbUgyiKcoBhm0UrWbdrMs7RX8dnwzURKVbZGy2GnL0=
github.com/moby/moby/api v1.54.0/go.mod h1:8mb+ReTlisw4pS6BRzCMts5M49W5M7bKt1cJy/YbAqc=
github.com/moby/moby/client v0.3.0 h1:UUGL5okry+Aomj3WhGt9Aigl3ZOxZGqR7XPo+RLPlKs=
github.com/moby/moby/client v0.3.0/go.mod h1:HJgFbJRvogDQjbM8fqc1MCEm4mIAGMLjXbgwoZp6jCQ=
github.com/moby/moby/api v1.54.2 h1:wiat9QAhnDQjA7wk1kh/TqHz2I1uUA7M7t9SAl/JNXg=
github.com/moby/moby/api v1.54.2/go.mod h1:+RQ6wluLwtYaTd1WnPLykIDPekkuyD/ROWQClE83pzs=
github.com/moby/moby/client v0.4.1 h1:DMQgisVoMkmMs7fp3ROSdiBnoAu8+vo3GggFl06M/wY=
github.com/moby/moby/client v0.4.1/go.mod h1:z52C9O2POPOsnxZAy//WtKcQ32P+jT/NGeXu/7nfjGQ=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@ -447,19 +447,19 @@ github.com/onsi/ginkgo/v2 v2.27.2 h1:LzwLj0b89qtIy6SSASkzlNvX6WktqurSHwkk2ipF/Ns
github.com/onsi/ginkgo/v2 v2.27.2/go.mod h1:ArE1D/XhNXBXCBkKOLkbsb2c81dQHCRcF5zwn/ykDRo=
github.com/onsi/gomega v1.38.2 h1:eZCjf2xjZAqe+LeWvKb5weQ+NcPwX84kqJ0cZNxok2A=
github.com/onsi/gomega v1.38.2/go.mod h1:W2MJcYxRGV63b418Ai34Ud0hEdTVXq9NW9+Sx6uXf3k=
github.com/open-telemetry/opentelemetry-collector-contrib/internal/exp/metrics v0.148.0 h1:CiTjQE/Hh5xK2t56ogrDK4nl0+tJPNmASCs4zEYZ/xU=
github.com/open-telemetry/opentelemetry-collector-contrib/internal/exp/metrics v0.148.0/go.mod h1:WUFkzTiOpt7EYyL67gv1GOf3RD8qKWGtin3lY9LYzW4=
github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatautil v0.148.0 h1:1TLg6YrS3Au6F7xw3ws2Njbwj13IMqPplvGFi+18fWs=
github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatautil v0.148.0/go.mod h1:P8hZEDIQk4REgUWyLhSVRHwTxK6KkifKfg36BmmQ/DI=
github.com/open-telemetry/opentelemetry-collector-contrib/processor/deltatocumulativeprocessor v0.148.0 h1:xgD/kNGp/wWY+bwY599Pc01OamYN17phRiTP934bM5Y=
github.com/open-telemetry/opentelemetry-collector-contrib/processor/deltatocumulativeprocessor v0.148.0/go.mod h1:ZK7wvaefla9lB3bAW0rNKt7IzRPcTRQoOFqr4sZy/XM=
github.com/open-telemetry/opentelemetry-collector-contrib/internal/exp/metrics v0.153.0 h1:hrLQLVZ4YXs35G9QvPO+xcu6qMnUpCt3WOpBDM7dR+E=
github.com/open-telemetry/opentelemetry-collector-contrib/internal/exp/metrics v0.153.0/go.mod h1:+qlIXDaBLIX+egj/okymUG88KSdAD8nIEHY8+tXt8+M=
github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatautil v0.153.0 h1:kPPv0sQQH2R2CitTPYXDfq1z1ekStnmk39C8RkOrsbI=
github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatautil v0.153.0/go.mod h1:wFACQmv2KfJyvyiRtMrI/DmcOWKEk6SxY0nLduWFMC4=
github.com/open-telemetry/opentelemetry-collector-contrib/processor/deltatocumulativeprocessor v0.153.0 h1:3MR2JvG1KB4GUiMi5asE6K0Ln5cjWPEfVAIpUwf55Sk=
github.com/open-telemetry/opentelemetry-collector-contrib/processor/deltatocumulativeprocessor v0.153.0/go.mod h1:0lEaZGCEjzb4R5J6F0NR1jF1KKc18IkvPRwLpQuyyjY=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040=
github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M=
github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0=
github.com/outscale/osc-sdk-go/v2 v2.32.0 h1:twcX7/YF32aowN0khwK3fPKXGujRi7oOCLLzWcLTX+M=
github.com/outscale/osc-sdk-go/v2 v2.32.0/go.mod h1:fl+1NvnHptNVE0N57dkDa+H4fyBhlrFaRA+lYiUT44s=
github.com/outscale/osc-sdk-go/v2 v2.34.0 h1:hHH5W9Fmgt6b8nGUmDyu4vVP+zqJ+W0zflzjgsGEGUQ=
github.com/outscale/osc-sdk-go/v2 v2.34.0/go.mod h1:6J8WRznaSIEXXVHhhTXisGJQgvE5fYzbf8hAw7YIGfQ=
github.com/ovh/go-ovh v1.9.0 h1:6K8VoL3BYjVV3In9tPJUdT7qMx9h0GExN9EXx1r2kKE=
github.com/ovh/go-ovh v1.9.0/go.mod h1:cTVDnl94z4tl8pP1uZ/8jlVxntjSIf09bNcQ5TJSC7c=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
@ -467,10 +467,10 @@ github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0Mw
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pb33f/jsonpath v0.8.2 h1:Ou4C7zjYClBm97dfZjDCjdZGusJoynv/vrtiEKNfj2Y=
github.com/pb33f/jsonpath v0.8.2/go.mod h1:zBV5LJW4OQOPatmQE2QdKpGQJvhDTlE5IEj6ASaRNTo=
github.com/pb33f/libopenapi v0.34.4 h1:BWWXA3U4SlsHEvfczk+DJHu2O38ktgKw+zBEYaDZ2uI=
github.com/pb33f/libopenapi v0.34.4/go.mod h1:MsDdUlQ1CdrIDO5v26JfgBxQs7kcaOUEpMP3EqU6bI4=
github.com/pb33f/libopenapi-validator v0.13.3 h1:5KW4Y/mMoQvt6d89rLiNmW1zSfln7Oua2A0BqPXpjro=
github.com/pb33f/libopenapi-validator v0.13.3/go.mod h1:X58CRsmj/7l0iXethEMfq3OJIzQ5hces7EbJ071z6WI=
github.com/pb33f/libopenapi v0.37.2 h1:4Kb4w/h2BVKb099oYIZqeDxEBhUioWA+z6WJhBOk2r8=
github.com/pb33f/libopenapi v0.37.2/go.mod h1:MsDdUlQ1CdrIDO5v26JfgBxQs7kcaOUEpMP3EqU6bI4=
github.com/pb33f/libopenapi-validator v0.13.8 h1:3t/5hUq8EYIWe6Uwj5RA7xFSWkleDbqsueA78/tIAo8=
github.com/pb33f/libopenapi-validator v0.13.8/go.mod h1:mWwedExRS1L8gjK6BGE1oDA5wXLuxgU7EheNz703MCg=
github.com/pb33f/ordered-map/v2 v2.3.1 h1:5319HDO0aw4DA4gzi+zv4FXU9UlSs3xGZ40wcP1nBjY=
github.com/pb33f/ordered-map/v2 v2.3.1/go.mod h1:qxFQgd0PkVUtOMCkTapqotNgzRhMPL7VvaHKbd1HnmQ=
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0=
@ -491,15 +491,15 @@ github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndr
github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s=
github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g=
github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U=
github.com/prometheus/alertmanager v0.31.1 h1:eAmIC42lzbWslHkMt693T36qdxfyZULswiHr681YS3Q=
github.com/prometheus/alertmanager v0.31.1/go.mod h1:zWPQwhbLt2ybee8rL921UONeQ59Oncash+m/hGP17tU=
github.com/prometheus/alertmanager v0.32.1 h1:BQ3jHXNq2A7VSD9Kh0Qx+kXbifNbHSDuKVbMmdRHHJ0=
github.com/prometheus/alertmanager v0.32.1/go.mod h1:0Dy9faTtMgpVYxJVxV0o65elTxHnSRCF/7gy5BKGZiE=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU=
github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o=
github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg=
github.com/prometheus/client_golang/exp v0.0.0-20260325093428-d8591d0db856 h1:1Y6bmpZb8peQCy1IpctnAhIFuyhrdtMaDnETChhSNns=
github.com/prometheus/client_golang/exp v0.0.0-20260325093428-d8591d0db856/go.mod h1:Vf0QcmVhGqpjLxZOaWrFSep86vchQtJmbztFaMM4f6Q=
github.com/prometheus/client_golang/exp v0.0.0-20260518105423-c9d5bc4c50a9 h1:e33IfrrwrJkylWwAGcQ2jMvbWVv13lv0suTXjGNeiqY=
github.com/prometheus/client_golang/exp v0.0.0-20260518105423-c9d5bc4c50a9/go.mod h1:vW/EVguzbNw6xMRmozJQWbY60/+Zsg0TgVJOSXGx2iI=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
@ -511,8 +511,8 @@ github.com/prometheus/common v0.67.5 h1:pIgK94WWlQt1WLwAC5j2ynLaBRDiinoAb86HZHTU
github.com/prometheus/common v0.67.5/go.mod h1:SjE/0MzDEEAyrdr5Gqc6G+sXI67maCxzaT3A2+HqjUw=
github.com/prometheus/common/assets v0.2.0 h1:0P5OrzoHrYBOSM1OigWL3mY8ZvV2N4zIE/5AahrSrfM=
github.com/prometheus/common/assets v0.2.0/go.mod h1:D17UVUE12bHbim7HzwUvtqm6gwBEaDQ0F+hIGbFbccI=
github.com/prometheus/exporter-toolkit v0.15.1 h1:XrGGr/qWl8Gd+pqJqTkNLww9eG8vR/CoRk0FubOKfLE=
github.com/prometheus/exporter-toolkit v0.15.1/go.mod h1:P/NR9qFRGbCFgpklyhix9F6v6fFr/VQB/CVsrMDGKo4=
github.com/prometheus/exporter-toolkit v0.16.0 h1:xT/j7L2XKF+VJd6B4fpUw6xWabHrSmsUf6mYmFqyu0s=
github.com/prometheus/exporter-toolkit v0.16.0/go.mod h1:d1EL8Z9674xQe/iWhwP2wDyCEoBPbXVeqDbqAUsgJWY=
github.com/prometheus/otlptranslator v1.0.0 h1:s0LJW/iN9dkIH+EnhiD3BlkkP5QVIUVEoIwkU+A6qos=
github.com/prometheus/otlptranslator v1.0.0/go.mod h1:vRYWnXvI6aWGpsdY/mOT/cbeVRBlPWtBNDb7kGR3uKM=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
@ -522,8 +522,8 @@ github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzM
github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is=
github.com/prometheus/sigv4 v0.4.1 h1:EIc3j+8NBea9u1iV6O5ZAN8uvPq2xOIUPcqCTivHuXs=
github.com/prometheus/sigv4 v0.4.1/go.mod h1:eu+ZbRvsc5TPiHwqh77OWuCnWK73IdkETYY46P4dXOU=
github.com/puzpuzpuz/xsync/v4 v4.4.0 h1:vlSN6/CkEY0pY8KaB0yqo/pCLZvp9nhdbBdjipT4gWo=
github.com/puzpuzpuz/xsync/v4 v4.4.0/go.mod h1:VJDmTCJMBt8igNxnkQd86r+8KUeN1quSfNKu5bLYFQo=
github.com/puzpuzpuz/xsync/v4 v4.5.0 h1:vOSWu6b57/emh+L/Cw0BeQfvxa/cogFywXHeGUxQxAg=
github.com/puzpuzpuz/xsync/v4 v4.5.0/go.mod h1:VJDmTCJMBt8igNxnkQd86r+8KUeN1quSfNKu5bLYFQo=
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
@ -533,16 +533,16 @@ github.com/scaleway/scaleway-sdk-go v1.0.0-beta.36 h1:ObX9hZmK+VmijreZO/8x9pQ8/P
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.36/go.mod h1:LEsDu4BubxK7/cWhtlQWfuxwL4rf/2UEpxXz1o1EMtM=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/shoenig/test v1.12.2 h1:ZVT8NeIUwGWpZcKaepPmFMoNQ3sVpxvqUh/MAqwFiJI=
github.com/shoenig/test v1.12.2/go.mod h1:UxJ6u/x2v/TNs/LoLxBNJRV9DiwBBKYxXSyczsBHFoI=
github.com/shoenig/test v1.13.2 h1:SaGxHxg7xkRuKuNtuFmHf0LgNGaAgcBT7HN4WHCKfqU=
github.com/shoenig/test v1.13.2/go.mod h1:MKmiRyEeuFl8y9PCoThaRDgYQZeWBhRQlH99poXz5LI=
github.com/shurcooL/httpfs v0.0.0-20230704072500-f1e31cf0ba5c h1:aqg5Vm5dwtvL+YgDpBcK1ITf3o96N/K7/wsRXQnUTEs=
github.com/shurcooL/httpfs v0.0.0-20230704072500-f1e31cf0ba5c/go.mod h1:owqhoLW1qZoYLZzLnBw+QkPP9WZnjlSWihhxAJC1+/M=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stackitcloud/stackit-sdk-go/core v0.23.0 h1:zPrOhf3Xe47rKRs1fg/AqKYUiJJRYjdcv+3qsS50mEs=
github.com/stackitcloud/stackit-sdk-go/core v0.23.0/go.mod h1:osMglDby4csGZ5sIfhNyYq1bS1TxIdPY88+skE/kkmI=
github.com/stackitcloud/stackit-sdk-go/core v0.26.0 h1:jQEb9gkehfp6VCP6TcYk7BI10cz4l0KM2L6hqYBH2QA=
github.com/stackitcloud/stackit-sdk-go/core v0.26.0/go.mod h1:WU1hhxnjXw2EV7CYa1nlEvNpMiRY6CvmIOaHuL3pOaA=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
@ -561,8 +561,8 @@ github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
github.com/vultr/govultr/v3 v3.28.1 h1:KR3LhppYARlBujY7+dcrE7YKL0Yo9qXL+msxykKQrLI=
github.com/vultr/govultr/v3 v3.28.1/go.mod h1:2zyUw9yADQaGwKnwDesmIOlBNLrm7edsCfWHFJpWKf8=
github.com/vultr/govultr/v3 v3.31.2 h1:2l3/KDvfemG+4azw4LLquJoh9mFOAVEdBXtPPzix3ac=
github.com/vultr/govultr/v3 v3.31.2/go.mod h1:2zyUw9yADQaGwKnwDesmIOlBNLrm7edsCfWHFJpWKf8=
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
github.com/xhit/go-str2duration/v2 v2.1.0 h1:lxklc02Drh6ynqX+DdPyp5pCKLUQpRT8bp8Ydu2Bstc=
@ -572,64 +572,64 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
go.opentelemetry.io/collector/component v1.54.0 h1:LvtX0Tzz18n44OrUFVk77N1FNsejfWJqztB28hrmDM8=
go.opentelemetry.io/collector/component v1.54.0/go.mod h1:yUMBYsySY/sDcXm8kOzEoZxt+JLdala6hxzSW0npOxY=
go.opentelemetry.io/collector/component/componentstatus v0.148.0 h1:sCGRaXNQolHFhPjrNJEwQ1WZOf96iL99tzm9GxuZsvg=
go.opentelemetry.io/collector/component/componentstatus v0.148.0/go.mod h1:yqg3SpGQc22W3wGICdnb+2kZVW9daBr3+LrGUCHkKfc=
go.opentelemetry.io/collector/component/componenttest v0.148.0 h1:tBXJWmy2X6KD8S0QU2YZa2zYBqP+IycSM4iOtwDD2pA=
go.opentelemetry.io/collector/component/componenttest v0.148.0/go.mod h1:1c1+6mZOmI0raoya5vA/X0F+fawEjNS6tCEs5xLATtA=
go.opentelemetry.io/collector/confmap v1.54.0 h1:RUoxQ4uAYHTI57GfHh61D00tTQsXm9T88ozrAiicByc=
go.opentelemetry.io/collector/confmap v1.54.0/go.mod h1:mQxG8bk0IWIt9gbWMvzE+cRkOuCuzbzkNGBq2YJ4wNM=
go.opentelemetry.io/collector/confmap/xconfmap v0.148.0 h1:UW8MX5VlKJf67x4Et7J9kPwP9Rv4VSmJ+UUpgRcb//c=
go.opentelemetry.io/collector/confmap/xconfmap v0.148.0/go.mod h1:4qTMr3V0uSXXac9wVs/UD5fIqRKw5yIl58+Vjsc6RHM=
go.opentelemetry.io/collector/consumer v1.54.0 h1:RGGtUN+GbkV1px3T6XdUHmgJ+ldJ1hAHdesFzW/wgL0=
go.opentelemetry.io/collector/consumer v1.54.0/go.mod h1:1PC6XINTL9DdT1bwvfMdHE72EB4RWU/WcPemUrhqKN8=
go.opentelemetry.io/collector/consumer/consumertest v0.148.0 h1:ms0HtWMj17tI1Yds0hSuUI5QYpNEqd11AAhwIoUY2HE=
go.opentelemetry.io/collector/consumer/consumertest v0.148.0/go.mod h1:wScw/OzKkf/ZzJn4ToI30OoI1kJiY16WNrcFToXSzK0=
go.opentelemetry.io/collector/consumer/xconsumer v0.148.0 h1:m3b9rY7CLD5Pcge6sSKHIT3OlcPN6xqYsdtVs9oJ528=
go.opentelemetry.io/collector/consumer/xconsumer v0.148.0/go.mod h1:bG+Wz6xmIBl/gHzq1sqvksWXqTLuTX17Wo//zIsdZpw=
go.opentelemetry.io/collector/featuregate v1.54.0 h1:ufo5Hy4Co9pcHVg24hyanm8qFG3TkkYbVyQXPVAbwDc=
go.opentelemetry.io/collector/featuregate v1.54.0/go.mod h1:PS7zY/zaCb28EqciePVwRHVhc3oKortTFXsi3I6ee4g=
go.opentelemetry.io/collector/internal/componentalias v0.148.0 h1:Y6MftNIZSzOr47TTj6A2z2UR3IwbeG46sAQshicGtDg=
go.opentelemetry.io/collector/internal/componentalias v0.148.0/go.mod h1:uwKzfehzwRgHxdHgFXYSBHNBeWSSqsqQYGWr5fk08G0=
go.opentelemetry.io/collector/internal/testutil v0.148.0 h1:3Z9hperte3vSmbBTYeNndoEUICICrNz8hzx+v0FYXBQ=
go.opentelemetry.io/collector/internal/testutil v0.148.0/go.mod h1:Jkjs6rkqs973LqgZ0Fe3zrokQRKULYXPIf4HuqStiEE=
go.opentelemetry.io/collector/pdata v1.54.0 h1:3LharKb792cQ3VrUGxd3IcpWwfu3ST+GSTU382jVz1s=
go.opentelemetry.io/collector/pdata v1.54.0/go.mod h1:+MqC3VVOv/EX9YVFUo+mI4F0YmwJ+fXBYwjmu+mRiZ8=
go.opentelemetry.io/collector/pdata/pprofile v0.148.0 h1:MgrNZmqwhZGfiYwcKKtM/iXgTZqqvG5dUphriRXMZHU=
go.opentelemetry.io/collector/pdata/pprofile v0.148.0/go.mod h1:MTTMnZPqWX1S/rBDatU0W19udlycBkWuzVV5qnemHdc=
go.opentelemetry.io/collector/pdata/testdata v0.148.0 h1:yzakPuFgoKK8WcrlhyYHLMLA/kLScQKGsXkIgwieAQ8=
go.opentelemetry.io/collector/pdata/testdata v0.148.0/go.mod h1:2rFvxm8qwd3nlO90FtJw6ZGAjt+bLndxmQuJaMO9kfQ=
go.opentelemetry.io/collector/pipeline v1.54.0 h1:jYlCkdFLITVBdeB+IGS07zXWywEgvT3Ky46vdKKT+Ks=
go.opentelemetry.io/collector/pipeline v1.54.0/go.mod h1:RD90NG3Jbk965Xaqym3JyHkuol4uZJjQVUkD9ddXJIs=
go.opentelemetry.io/collector/processor v1.54.0 h1:zmHBFiEFmU9ZYuHhVP3lHIkbfy+ueapzGpTdXVMcWBg=
go.opentelemetry.io/collector/processor v1.54.0/go.mod h1:L0lA6DZ0VbrtQBg44cmYfSpRlgm4zxW1I6QfBnRizPw=
go.opentelemetry.io/collector/processor/processortest v0.148.0 h1:p0k59frZxy/Z4fXe82i5eOJv/UyOH75XhI8nFD1ZWCE=
go.opentelemetry.io/collector/processor/processortest v0.148.0/go.mod h1:E2Li2gnkUXgvApvGyEtn3Eq5KyzV05ljfbFRsZ7sTC4=
go.opentelemetry.io/collector/processor/xprocessor v0.148.0 h1:v7Qv6k2b2cvgGWuTO5KN5QYDLl1r5sznt7Le4Fhpa4c=
go.opentelemetry.io/collector/processor/xprocessor v0.148.0/go.mod h1:r7ADpSX2nf0rZR9STxh956Qw1740QOWMXLnEM/ZiaF8=
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.67.0 h1:c9r/G1CSw4dPI1jaNNG9RnQP+q4SvZnHciDQJVIvchU=
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.67.0/go.mod h1:gO9smoZe9KnZcJCqcB0lMmQ4Z5VEifYmjMTpnwtTSuQ=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.67.0 h1:OyrsyzuttWTSur2qN/Lm0m2a8yqyIjUVBZcxFPuXq2o=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.67.0/go.mod h1:C2NGBr+kAB4bk3xtMXfZ94gqFDtg/GkI7e9zqGh5Beg=
go.opentelemetry.io/otel v1.42.0 h1:lSQGzTgVR3+sgJDAU/7/ZMjN9Z+vUip7leaqBKy4sho=
go.opentelemetry.io/otel v1.42.0/go.mod h1:lJNsdRMxCUIWuMlVJWzecSMuNjE7dOYyWlqOXWkdqCc=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.42.0 h1:THuZiwpQZuHPul65w4WcwEnkX2QIuMT+UFoOrygtoJw=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.42.0/go.mod h1:J2pvYM5NGHofZ2/Ru6zw/TNWnEQp5crgyDeSrYpXkAw=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.42.0 h1:zWWrB1U6nqhS/k6zYB74CjRpuiitRtLLi68VcgmOEto=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.42.0/go.mod h1:2qXPNBX1OVRC0IwOnfo1ljoid+RD0QK3443EaqVlsOU=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.42.0 h1:uLXP+3mghfMf7XmV4PkGfFhFKuNWoCvvx5wP/wOXo0o=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.42.0/go.mod h1:v0Tj04armyT59mnURNUJf7RCKcKzq+lgJs6QSjHjaTc=
go.opentelemetry.io/otel/metric v1.42.0 h1:2jXG+3oZLNXEPfNmnpxKDeZsFI5o4J+nz6xUlaFdF/4=
go.opentelemetry.io/otel/metric v1.42.0/go.mod h1:RlUN/7vTU7Ao/diDkEpQpnz3/92J9ko05BIwxYa2SSI=
go.opentelemetry.io/otel/sdk v1.42.0 h1:LyC8+jqk6UJwdrI/8VydAq/hvkFKNHZVIWuslJXYsDo=
go.opentelemetry.io/otel/sdk v1.42.0/go.mod h1:rGHCAxd9DAph0joO4W6OPwxjNTYWghRWmkHuGbayMts=
go.opentelemetry.io/otel/sdk/metric v1.42.0 h1:D/1QR46Clz6ajyZ3G8SgNlTJKBdGp84q9RKCAZ3YGuA=
go.opentelemetry.io/otel/sdk/metric v1.42.0/go.mod h1:Ua6AAlDKdZ7tdvaQKfSmnFTdHx37+J4ba8MwVCYM5hc=
go.opentelemetry.io/otel/trace v1.42.0 h1:OUCgIPt+mzOnaUTpOQcBiM/PLQ/Op7oq6g4LenLmOYY=
go.opentelemetry.io/otel/trace v1.42.0/go.mod h1:f3K9S+IFqnumBkKhRJMeaZeNk9epyhnCmQh/EysQCdc=
go.opentelemetry.io/proto/otlp v1.9.0 h1:l706jCMITVouPOqEnii2fIAuO3IVGBRPV5ICjceRb/A=
go.opentelemetry.io/proto/otlp v1.9.0/go.mod h1:xE+Cx5E/eEHw+ISFkwPLwCZefwVjY+pqKg1qcK03+/4=
go.opentelemetry.io/collector/component v1.59.0 h1:WtulkwzsdAOM/LE0cH/IiudUgiyb2ueVDDeEh5HsXzo=
go.opentelemetry.io/collector/component v1.59.0/go.mod h1:5eQCM0tS6qbG2XJ6Bt67kgCxuhCbg4csVv6SywyHZ6w=
go.opentelemetry.io/collector/component/componentstatus v0.153.0 h1:bZu1Qs1eHw5ZY2UEKq0f5IcctDgc6zjUYwCE1T22Tmw=
go.opentelemetry.io/collector/component/componentstatus v0.153.0/go.mod h1:SfYWwh6pA9jJUcjuX+zIJ9kyn+2Z9SSLMM3xYOBsVW4=
go.opentelemetry.io/collector/component/componenttest v0.153.0 h1:u6O1l+9PUNnI22k8q4sF9wgLAUyt+y2Ov7xi1yZ+wE4=
go.opentelemetry.io/collector/component/componenttest v0.153.0/go.mod h1:Ym/d5UxnoHmrCI5LsVANBicikNiqtwjk8uWBM+Z4jDM=
go.opentelemetry.io/collector/confmap v1.59.0 h1:asxEEiWwNuGfmTVSctYArOTF8jcxYpS4NmPtvvFhNNI=
go.opentelemetry.io/collector/confmap v1.59.0/go.mod h1:X5SjFINrF0cb0hcM8PwnW2z+0L/pHA1H1yPPtm2j0tY=
go.opentelemetry.io/collector/confmap/xconfmap v0.153.0 h1:RSn7C87eBp1iuWip3hX8v9AR8adMze1usJxwumefkq4=
go.opentelemetry.io/collector/confmap/xconfmap v0.153.0/go.mod h1:4SuPyutUiirRqQoPeY+13lLYkOQ2opMQgKvKACnXh1k=
go.opentelemetry.io/collector/consumer v1.59.0 h1:EFDQ8ZTWwHEratWusKgW26W20LeAWdXj235iD9MxpuA=
go.opentelemetry.io/collector/consumer v1.59.0/go.mod h1:wrOSfXkKjzEeHYxhKGukuB9+NFV/CboWwEH1oEXhMtw=
go.opentelemetry.io/collector/consumer/consumertest v0.153.0 h1:fCqkOWNVK/qipg4SX60zICs3jhKDjcrtF1oxJR6msCk=
go.opentelemetry.io/collector/consumer/consumertest v0.153.0/go.mod h1:YfVqyCrvEfvsbbrpfiH97fITh4vmIBzZT112tUluqx0=
go.opentelemetry.io/collector/consumer/xconsumer v0.153.0 h1:Jt1Aiiq9zDILzppRTEdZXaA830KBjjP1i2kWL+h5br0=
go.opentelemetry.io/collector/consumer/xconsumer v0.153.0/go.mod h1:IzJ/dTOtEUMjY0DYu6kO946u5jbiDDUG8+sLaLhJ+HY=
go.opentelemetry.io/collector/featuregate v1.59.0 h1:pu70/9eWRjAjzGnr3VmqwY+k6fmU3esLp15AqxfBBz0=
go.opentelemetry.io/collector/featuregate v1.59.0/go.mod h1:4ga1QBMPEejXXmpyJS8lmaRpknJ3Lb9Bvk6e420bUFU=
go.opentelemetry.io/collector/internal/componentalias v0.153.0 h1:tr5I5hsJPJBbVPGjvOVVPPK4dLR5ZLqVEckuOfnzzMs=
go.opentelemetry.io/collector/internal/componentalias v0.153.0/go.mod h1:tFSKiuWKJJgfxANyVnbKPVZkOF7N0bFXvCxCEgqMKuo=
go.opentelemetry.io/collector/internal/testutil v0.153.0 h1:GJEaPLohao+7wtm08yGf73RGi1rpIHvqzxOb7Xn8sP0=
go.opentelemetry.io/collector/internal/testutil v0.153.0/go.mod h1:Jkjs6rkqs973LqgZ0Fe3zrokQRKULYXPIf4HuqStiEE=
go.opentelemetry.io/collector/pdata v1.59.0 h1:lO1IcaO9+HUVdFh+RATCUG3oTP+uCZzsE7HJ0MjmzRc=
go.opentelemetry.io/collector/pdata v1.59.0/go.mod h1:AH6M14C6qhesnUpcvigkvFMiX9KtdSWQENMBNyNhe7I=
go.opentelemetry.io/collector/pdata/pprofile v0.153.0 h1:IurcS9g28cVrtIvc1oUVN8vSm5j0t79Pd8GZgd1PV28=
go.opentelemetry.io/collector/pdata/pprofile v0.153.0/go.mod h1:nX33dLKrwdoz/FQeIs6JKPeZcS1KbU2VIOwH7K0F05c=
go.opentelemetry.io/collector/pdata/testdata v0.153.0 h1:pO/+b8Rz5PG0G+TskdYdQEjhXnNG2bQoiRRMwic6X0I=
go.opentelemetry.io/collector/pdata/testdata v0.153.0/go.mod h1:JVjUfJv9YFL3JUhisxMdLe2DX7we227Ry9JiTgwlEro=
go.opentelemetry.io/collector/pipeline v1.59.0 h1:AyEcAPy5ZuUFpqis9i97WEIAcFh/mEEo90+1wr4urNU=
go.opentelemetry.io/collector/pipeline v1.59.0/go.mod h1:RD90NG3Jbk965Xaqym3JyHkuol4uZJjQVUkD9ddXJIs=
go.opentelemetry.io/collector/processor v1.59.0 h1:uSIMwLaKLzHNiv8625LP3BLUMCqRaBc1ay2o7uW19PQ=
go.opentelemetry.io/collector/processor v1.59.0/go.mod h1:IrCFcSdmqIWfNeTWOxncNcdQGVOf0LlKY6A3pHEpGiw=
go.opentelemetry.io/collector/processor/processortest v0.153.0 h1:aMH8+omUXs2iCKL4Cphmzzrn4lB4jm6ZgWRvKKV+B/c=
go.opentelemetry.io/collector/processor/processortest v0.153.0/go.mod h1:LAPHps5FhQyd0MnNd1ZHmoykG/EWsIpJLs7fivFf5Mc=
go.opentelemetry.io/collector/processor/xprocessor v0.153.0 h1:mXtOAwZAXcHgAgVRzAk4NRoyj7yHV88LVFrn0CCedog=
go.opentelemetry.io/collector/processor/xprocessor v0.153.0/go.mod h1:yGFU58TvheCedrVkdqU8jW/vnCFqcyYElf+5lidn0nA=
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.69.0 h1:MCcYL7J6Vt/X0kjqbMZkekCmwsurbQRbL69vkiye2lk=
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.69.0/go.mod h1:3jnStNwSufK+f5ktjL4EPcwtig4rtd81NS70lqHuXl8=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0 h1:8tvICD4vSTOOsNrsI4Ljf6C+6UKvpTEH5XY3JMoyPoo=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0/go.mod h1:z9+yiacE0IHRqM4qFfkbt/JYlmYXgss8GY/jXoNuPJI=
go.opentelemetry.io/otel v1.44.0 h1:JjwHmHpA4iZ3wBxluu2fbbE7j4kqlE8jXyAyPXH7HqU=
go.opentelemetry.io/otel v1.44.0/go.mod h1:BMgjTHL9WPRlRjL2oZCBTL4whCGtXch2H4BhOPIAyYc=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.44.0 h1:4YsVu3B8+3qtWYYrsUYgn0OG78pN0rnNPRGX4SbokQI=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.44.0/go.mod h1:+wnlSn0mD1ADVMe3v9Z/WIaiz6q6gL2J/ejaAmdmv80=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.44.0 h1:qazEJlUOQzhCpzQpFETGby7EdqjI1wsd0W+6Gg1SCTU=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.44.0/go.mod h1:fOD2Yefuxixkx3ahVNf0O/PERb6r4OlbxfATVnYvzCo=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.44.0 h1:lgh3PiVrRUWMLOVSkQicxzZll5NjF1r+AtsX1XRIHw0=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.44.0/go.mod h1:5Cnhth3m/AgOeTgE3ex12pPmiu/gGtZit03kSzx9X7s=
go.opentelemetry.io/otel/metric v1.44.0 h1:1w0gILTcHdr3YI+ixLyjemwrVnsMURbTZFrSYCdDdmc=
go.opentelemetry.io/otel/metric v1.44.0/go.mod h1:8O7hanEPBNgEMmybD3s2VBKcgWOCsA6tzHBPODAiquo=
go.opentelemetry.io/otel/sdk v1.44.0 h1:nHYwb9lK+fJPU/dnT6s7W7Z8itMWyqrnVfbheVYrZ58=
go.opentelemetry.io/otel/sdk v1.44.0/go.mod h1:Osuydd3Se74nqjAKxid74N5eC+jfEqfTegHRnq58oK0=
go.opentelemetry.io/otel/sdk/metric v1.44.0 h1:3LlKgI+VjbVsjNRFZJZAJ30WjXC5VkNRks6si09iEfI=
go.opentelemetry.io/otel/sdk/metric v1.44.0/go.mod h1:5B5pMARnXxKhltooO4xUuCBorl65a4EpnTalObqOigA=
go.opentelemetry.io/otel/trace v1.44.0 h1:jxF5CsGYCe74MCRx2X4g7WsY/VBKRqqpNvXlX/6gtIk=
go.opentelemetry.io/otel/trace v1.44.0/go.mod h1:oLl1jrMQAVo6v3GAggN+1VH9VIz9iUSvW53sW1Q8PIE=
go.opentelemetry.io/proto/otlp v1.10.0 h1:IQRWgT5srOCYfiWnpqUYz9CVmbO8bFmKcwYxpuCSL2g=
go.opentelemetry.io/proto/otlp v1.10.0/go.mod h1:/CV4QoCR/S9yaPj8utp3lvQPoqMtxXdzn7ozvvozVqk=
go.opentelemetry.io/proto/slim/otlp v1.10.0 h1:iR97Vs/ZDR+y9TfuP9b1XBtdPWeC+OMslIBmhcLU7jM=
go.opentelemetry.io/proto/slim/otlp v1.10.0/go.mod h1:lV9250stpjYLPNA5viFabIgP2QlUGRT1GdTgAf8SIUk=
go.opentelemetry.io/proto/slim/otlp/collector/profiles/v1development v0.3.0 h1:RUF5rO0hAlgiJt1fzQVzcVs3vZVNHIcMLgOgG4rWNcQ=
@ -644,8 +644,8 @@ go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc=
go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
go.uber.org/zap v1.28.0 h1:IZzaP1Fv73/T/pBMLk4VutPl36uNC+OSUh3JLG3FIjo=
go.uber.org/zap v1.28.0/go.mod h1:rDLpOi171uODNm/mxFcuYWxDsqWSAVkFdX4XojSKg/Q=
go.yaml.in/yaml/v2 v2.4.4 h1:tuyd0P+2Ont/d6e2rl3be67goVK4R6deVxCUX5vyPaQ=
go.yaml.in/yaml/v2 v2.4.4/go.mod h1:gMZqIpDtDqOfM0uNfy0SkpRhvUryYH0Z6wdMYcacYXQ=
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
@ -659,16 +659,16 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio=
golang.org/x/crypto v0.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4=
golang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA=
golang.org/x/crypto v0.52.0 h1:RMs7fP2rXdep0CftQlK8Uf+kibLm7qkCcradZWYz988=
golang.org/x/crypto v0.52.0/go.mod h1:1QgfPxDqh0T2M/elOJtp9RvuR95kVjir0e6/BvEmGbc=
golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa h1:Zt3DZoOFFYkKhDT3v7Lm9FDMEV06GpzjG2jrqW+QTE0=
golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa/go.mod h1:K79w1Vqn7PoiZn+TkNpx3BUWUQksGO3JcVX6qIjytmA=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8=
golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w=
golang.org/x/mod v0.36.0 h1:JJjpVx6myfUsUdAzZuOSTTmRE0PfZeNWzzvKrP7amb4=
golang.org/x/mod v0.36.0/go.mod h1:moc6ELqsWcOw5Ef3xVprK5ul/MvtVvkIXLziUOICjUQ=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
@ -682,8 +682,8 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.13.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA=
golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0=
golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw=
golang.org/x/net v0.55.0 h1:bcvxaJn3e1U6InsFWt1JUq1aSjnRxLzT2rtD2KfkDF8=
golang.org/x/net v0.55.0/go.mod h1:L5U2KuzuOe1lY7Z+aWVIKK6qEeJXnXV9yzGA+WCHJww=
golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs=
golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -726,15 +726,15 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo=
golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
golang.org/x/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY=
golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o=
golang.org/x/term v0.41.0 h1:QCgPso/Q3RTJx2Th4bDLqML4W6iJiaXFq2/ftQF13YU=
golang.org/x/term v0.41.0/go.mod h1:3pfBgksrReYfZ5lvYM0kSO0LIkAl4Yl2bXOkKP7Ec2A=
golang.org/x/term v0.43.0 h1:S4RLU2sB31O/NCl+zFN9Aru9A/Cq2aqKpTZJ6B+DwT4=
golang.org/x/term v0.43.0/go.mod h1:lrhlHNdQJHO+1qVYiHfFKVuVioJIheAc3fBSMFYEIsk=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
@ -743,8 +743,8 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8=
golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA=
golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc=
golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38=
golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U=
golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@ -754,26 +754,26 @@ golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roY
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k=
golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0=
golang.org/x/tools v0.45.0 h1:18qN3FAooORvApf5XjCXgsuayZOEtXf6JK18I3+ONa8=
golang.org/x/tools v0.45.0/go.mod h1:LuUGqqaXcXMEFEruIVJVm5mgDD8vww/z/SR1gQ4uE/0=
golang.org/x/tools/godoc v0.1.0-deprecated h1:o+aZ1BOj6Hsx/GBdJO/s815sqftjSnrZZwyYTHODvtk=
golang.org/x/tools/godoc v0.1.0-deprecated/go.mod h1:qM63CriJ961IHWmnWa9CjZnBndniPt4a3CK0PVB9bIg=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
google.golang.org/api v0.272.0 h1:eLUQZGnAS3OHn31URRf9sAmRk3w2JjMx37d2k8AjJmA=
google.golang.org/api v0.272.0/go.mod h1:wKjowi5LNJc5qarNvDCvNQBn3rVK8nSy6jg2SwRwzIA=
google.golang.org/genproto v0.0.0-20260217215200-42d3e9bedb6d h1:vsOm753cOAMkt76efriTCDKjpCbK18XGHMJHo0JUKhc=
google.golang.org/genproto v0.0.0-20260217215200-42d3e9bedb6d/go.mod h1:0oz9d7g9QLSdv9/lgbIjowW1JoxMbxmBVNe8i6tORJI=
google.golang.org/genproto/googleapis/api v0.0.0-20260319201613-d00831a3d3e7 h1:41r6JMbpzBMen0R/4TZeeAmGXSJC7DftGINUodzTkPI=
google.golang.org/genproto/googleapis/api v0.0.0-20260319201613-d00831a3d3e7/go.mod h1:EIQZ5bFCfRQDV4MhRle7+OgjNtZ6P1PiZBgAKuxXu/Y=
google.golang.org/genproto/googleapis/rpc v0.0.0-20260311181403-84a4fc48630c h1:xgCzyF2LFIO/0X2UAoVRiXKU5Xg6VjToG4i2/ecSswk=
google.golang.org/genproto/googleapis/rpc v0.0.0-20260311181403-84a4fc48630c/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
google.golang.org/grpc v1.79.3 h1:sybAEdRIEtvcD68Gx7dmnwjZKlyfuc61Dyo9pGXXkKE=
google.golang.org/grpc v1.79.3/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4=
gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E=
google.golang.org/api v0.278.0 h1:W7jiRvRi53VYFfZ/HoZjQBtJk7gOFbHD8ot1RzVZU6E=
google.golang.org/api v0.278.0/go.mod h1:B9TqLBwJqVjp1mtt7WeoQwWRwvu/400y5lETOql+giQ=
google.golang.org/genproto v0.0.0-20260319201613-d00831a3d3e7 h1:XzmzkmB14QhVhgnawEVsOn6OFsnpyxNPRY9QV01dNB0=
google.golang.org/genproto v0.0.0-20260319201613-d00831a3d3e7/go.mod h1:L43LFes82YgSonw6iTXTxXUX1OlULt4AQtkik4ULL/I=
google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa h1:Kjn0N0tCrDgiAFW+lGO4JZ3ck44CehvJQMAwj9QF0G8=
google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa/go.mod h1:q4lMZS6kskjT5HvCPrnnypcDPVJqT/f4nfxmkE7gryY=
google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa h1:mZHHdPZl0dbGHCflZgAq/Q468DWVFcU2whhB2KAo8fk=
google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
google.golang.org/grpc v1.81.1 h1:VnnIIZ88UzOOKLukQi+ImGz8O1Wdp8nAGGnvOfEIWQQ=
google.golang.org/grpc v1.81.1/go.mod h1:xGH9GfzOyMTGIOXBJmXt+BX/V0kcdQbdcuwQ/zNw42I=
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
@ -787,8 +787,8 @@ gopkg.in/evanphx/json-patch.v4 v4.13.0 h1:czT3CmqEaQ1aanPc5SdlgQrrEIb8w/wwCvWWnf
gopkg.in/evanphx/json-patch.v4 v4.13.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M=
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/ini.v1 v1.67.1 h1:tVBILHy0R6e4wkYOn3XmiITt/hEVH4TFMYvAX2Ytz6k=
gopkg.in/ini.v1 v1.67.1/go.mod h1:x/cyOwCgZqOkJoDIJ3c1KNHMo10+nLGAhh+kn3Zizss=
gopkg.in/ini.v1 v1.67.2 h1:JtOSMb9OuaCZKr7h5D/h6iii14sK0hLbplTc6frx4Ss=
gopkg.in/ini.v1 v1.67.2/go.mod h1:x/cyOwCgZqOkJoDIJ3c1KNHMo10+nLGAhh+kn3Zizss=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

View file

@ -6,7 +6,7 @@ require (
github.com/bufbuild/buf v1.65.0
github.com/daixiang0/gci v0.14.0
github.com/gogo/protobuf v1.3.2
github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0
github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0
)
require (
@ -37,13 +37,14 @@ require (
github.com/containerd/errdefs/pkg v0.3.0 // indirect
github.com/containerd/stargz-snapshotter/estargz v0.18.2 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect
github.com/creack/pty v1.1.24 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/distribution/reference v0.6.0 // indirect
github.com/docker/cli v29.3.0+incompatible // indirect
github.com/docker/distribution v2.8.3+incompatible // indirect
github.com/docker/docker v28.5.2+incompatible // indirect
github.com/docker/docker-credential-helpers v0.9.5 // indirect
github.com/docker/go-connections v0.6.0 // indirect
github.com/docker/go-connections v0.7.0 // indirect
github.com/docker/go-units v0.5.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/go-chi/chi/v5 v5.2.4 // indirect
@ -56,7 +57,7 @@ require (
github.com/hexops/gotextdiff v1.0.3 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jdx/go-netrc v1.0.0 // indirect
github.com/klauspost/compress v1.18.5 // indirect
github.com/klauspost/compress v1.18.6 // indirect
github.com/klauspost/pgzip v1.2.6 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
@ -70,7 +71,7 @@ require (
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/quic-go/qpack v0.6.0 // indirect
github.com/quic-go/quic-go v0.59.0 // indirect
github.com/quic-go/quic-go v0.59.1 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/rs/cors v1.11.1 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
@ -87,30 +88,31 @@ require (
go.lsp.dev/protocol v0.12.0 // indirect
go.lsp.dev/uri v0.3.0 // indirect
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.67.0 // indirect
go.opentelemetry.io/otel v1.42.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.42.0 // indirect
go.opentelemetry.io/otel/metric v1.42.0 // indirect
go.opentelemetry.io/otel/trace v1.42.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0 // indirect
go.opentelemetry.io/otel v1.44.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.44.0 // indirect
go.opentelemetry.io/otel/metric v1.44.0 // indirect
go.opentelemetry.io/otel/trace v1.44.0 // indirect
go.uber.org/mock v0.6.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.27.1 // indirect
go.uber.org/zap v1.28.0 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect
golang.org/x/crypto v0.49.0 // indirect
golang.org/x/crypto v0.52.0 // indirect
golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa // indirect
golang.org/x/mod v0.33.0 // indirect
golang.org/x/net v0.52.0 // indirect
golang.org/x/mod v0.36.0 // indirect
golang.org/x/net v0.55.0 // indirect
golang.org/x/sync v0.20.0 // indirect
golang.org/x/sys v0.42.0 // indirect
golang.org/x/term v0.41.0 // indirect
golang.org/x/text v0.35.0 // indirect
golang.org/x/sys v0.45.0 // indirect
golang.org/x/term v0.43.0 // indirect
golang.org/x/text v0.37.0 // indirect
golang.org/x/time v0.15.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20260319201613-d00831a3d3e7 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20260311181403-84a4fc48630c // indirect
google.golang.org/grpc v1.79.3 // indirect
golang.org/x/tools v0.45.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa // indirect
google.golang.org/grpc v1.81.1 // indirect
google.golang.org/protobuf v1.36.11 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
gotest.tools/v3 v3.5.1 // indirect
gotest.tools/v3 v3.5.2 // indirect
mvdan.cc/xurls/v2 v2.6.0 // indirect
pluginrpc.com/pluginrpc v0.5.0 // indirect
)

View file

@ -65,8 +65,8 @@ github.com/containerd/stargz-snapshotter/estargz v0.18.2/go.mod h1:XyVU5tcJ3PRpk
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
github.com/cpuguy83/go-md2man/v2 v2.0.7 h1:zbFlGlXEAKlwXpmvle3d8Oe3YnkKIK4xSRTd3sHPnBo=
github.com/cpuguy83/go-md2man/v2 v2.0.7/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s=
github.com/creack/pty v1.1.24/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE=
github.com/daixiang0/gci v0.14.0 h1:h6AcLqmjIOBgojhtzY2CvBnA6RawPTkBHgtMvYD5YZ8=
github.com/daixiang0/gci v0.14.0/go.mod h1:w9E+SWQ4aPQ+xYPUdqitGDoXpT4mayqOfk7Szz2U6wQ=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
@ -81,8 +81,8 @@ github.com/docker/docker v28.5.2+incompatible h1:DBX0Y0zAjZbSrm1uzOkdr1onVghKaft
github.com/docker/docker v28.5.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker-credential-helpers v0.9.5 h1:EFNN8DHvaiK8zVqFA2DT6BjXE0GzfLOZ38ggPTKePkY=
github.com/docker/docker-credential-helpers v0.9.5/go.mod h1:v1S+hepowrQXITkEfw6o4+BMbGot02wiKpzWhGUZK6c=
github.com/docker/go-connections v0.6.0 h1:LlMG9azAe1TqfR7sO+NJttz1gy6KO7VJBh+pMmjSD94=
github.com/docker/go-connections v0.6.0/go.mod h1:AahvXYshr6JgfUJGdDCs2b5EZG/vmaMAntpSFH5BFKE=
github.com/docker/go-connections v0.7.0 h1:6SsRfJddP22WMrCkj19x9WKjEDTB+ahsdiGYf0mN39c=
github.com/docker/go-connections v0.7.0/go.mod h1:no1qkHdjq7kLMGUXYAduOhYPSJxxvgWBh7ogVvptn3Q=
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
@ -107,8 +107,8 @@ github.com/google/go-containerregistry v0.20.7 h1:24VGNpS0IwrOZ2ms2P1QE3Xa5X9p4p
github.com/google/go-containerregistry v0.20.7/go.mod h1:Lx5LCZQjLH1QBaMPeGwsME9biPeo1lPx6lbGj/UmzgM=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 h1:HWRh5R2+9EifMyIHV7ZV+MIZqgz+PMpZ14Jynv3O2Zs=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0/go.mod h1:JfhWUomR1baixubs02l85lZYYOm7LV6om4ceouMv45c=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0 h1:5VipnvEpbqr2gA2VbM+nYVbkIF28c5ZQfqCBQ5g2xfk=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0/go.mod h1:Hyl3n6Twe1hvtd9XUXDec4pTvgMSEixRuQKPTMH2bNs=
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
@ -119,8 +119,8 @@ github.com/jhump/protoreflect/v2 v2.0.0-beta.2 h1:qZU+rEZUOYTz1Bnhi3xbwn+VxdXkLV
github.com/jhump/protoreflect/v2 v2.0.0-beta.2/go.mod h1:4tnOYkB/mq7QTyS3YKtVtNrJv4Psqout8HA1U+hZtgM=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.18.5 h1:/h1gH5Ce+VWNLSWqPzOVn6XBO+vJbCNGvjoaGBFW2IE=
github.com/klauspost/compress v1.18.5/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ=
github.com/klauspost/compress v1.18.6 h1:2jupLlAwFm95+YDR+NwD2MEfFO9d4z4Prjl1XXDjuao=
github.com/klauspost/compress v1.18.6/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ=
github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU=
github.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
@ -157,8 +157,8 @@ github.com/protocolbuffers/protoscope v0.0.0-20221109213918-8e7a6aafa2c9 h1:arwj
github.com/protocolbuffers/protoscope v0.0.0-20221109213918-8e7a6aafa2c9/go.mod h1:SKZx6stCn03JN3BOWTwvVIO2ajMkb/zQdTceXYhKw/4=
github.com/quic-go/qpack v0.6.0 h1:g7W+BMYynC1LbYLSqRt8PBg5Tgwxn214ZZR34VIOjz8=
github.com/quic-go/qpack v0.6.0/go.mod h1:lUpLKChi8njB4ty2bFLX2x4gzDqXwUpaO1DP9qMDZII=
github.com/quic-go/quic-go v0.59.0 h1:OLJkp1Mlm/aS7dpKgTc6cnpynnD2Xg7C1pwL6vy/SAw=
github.com/quic-go/quic-go v0.59.0/go.mod h1:upnsH4Ju1YkqpLXC305eW3yDZ4NfnNbmQRCMWS58IKU=
github.com/quic-go/quic-go v0.59.1 h1:0Gmua0HW1Tv7ANR7hUYwRyD0MG5OJfgvYSZasGZzBic=
github.com/quic-go/quic-go v0.59.1/go.mod h1:upnsH4Ju1YkqpLXC305eW3yDZ4NfnNbmQRCMWS58IKU=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rodaine/protogofakeit v0.1.1 h1:ZKouljuRM3A+TArppfBqnH8tGZHOwM/pjvtXe9DaXH8=
@ -200,51 +200,51 @@ go.lsp.dev/uri v0.3.0 h1:KcZJmh6nFIBeJzTugn5JTU6OOyG0lDOo3R9KwTxTYbo=
go.lsp.dev/uri v0.3.0/go.mod h1:P5sbO1IQR+qySTWOCnhnK7phBx+W3zbLqSMDJNTw88I=
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.67.0 h1:OyrsyzuttWTSur2qN/Lm0m2a8yqyIjUVBZcxFPuXq2o=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.67.0/go.mod h1:C2NGBr+kAB4bk3xtMXfZ94gqFDtg/GkI7e9zqGh5Beg=
go.opentelemetry.io/otel v1.42.0 h1:lSQGzTgVR3+sgJDAU/7/ZMjN9Z+vUip7leaqBKy4sho=
go.opentelemetry.io/otel v1.42.0/go.mod h1:lJNsdRMxCUIWuMlVJWzecSMuNjE7dOYyWlqOXWkdqCc=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.42.0 h1:THuZiwpQZuHPul65w4WcwEnkX2QIuMT+UFoOrygtoJw=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.42.0/go.mod h1:J2pvYM5NGHofZ2/Ru6zw/TNWnEQp5crgyDeSrYpXkAw=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.42.0 h1:uLXP+3mghfMf7XmV4PkGfFhFKuNWoCvvx5wP/wOXo0o=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.42.0/go.mod h1:v0Tj04armyT59mnURNUJf7RCKcKzq+lgJs6QSjHjaTc=
go.opentelemetry.io/otel/metric v1.42.0 h1:2jXG+3oZLNXEPfNmnpxKDeZsFI5o4J+nz6xUlaFdF/4=
go.opentelemetry.io/otel/metric v1.42.0/go.mod h1:RlUN/7vTU7Ao/diDkEpQpnz3/92J9ko05BIwxYa2SSI=
go.opentelemetry.io/otel/sdk v1.42.0 h1:LyC8+jqk6UJwdrI/8VydAq/hvkFKNHZVIWuslJXYsDo=
go.opentelemetry.io/otel/sdk v1.42.0/go.mod h1:rGHCAxd9DAph0joO4W6OPwxjNTYWghRWmkHuGbayMts=
go.opentelemetry.io/otel/sdk/metric v1.42.0 h1:D/1QR46Clz6ajyZ3G8SgNlTJKBdGp84q9RKCAZ3YGuA=
go.opentelemetry.io/otel/sdk/metric v1.42.0/go.mod h1:Ua6AAlDKdZ7tdvaQKfSmnFTdHx37+J4ba8MwVCYM5hc=
go.opentelemetry.io/otel/trace v1.42.0 h1:OUCgIPt+mzOnaUTpOQcBiM/PLQ/Op7oq6g4LenLmOYY=
go.opentelemetry.io/otel/trace v1.42.0/go.mod h1:f3K9S+IFqnumBkKhRJMeaZeNk9epyhnCmQh/EysQCdc=
go.opentelemetry.io/proto/otlp v1.9.0 h1:l706jCMITVouPOqEnii2fIAuO3IVGBRPV5ICjceRb/A=
go.opentelemetry.io/proto/otlp v1.9.0/go.mod h1:xE+Cx5E/eEHw+ISFkwPLwCZefwVjY+pqKg1qcK03+/4=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0 h1:8tvICD4vSTOOsNrsI4Ljf6C+6UKvpTEH5XY3JMoyPoo=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0/go.mod h1:z9+yiacE0IHRqM4qFfkbt/JYlmYXgss8GY/jXoNuPJI=
go.opentelemetry.io/otel v1.44.0 h1:JjwHmHpA4iZ3wBxluu2fbbE7j4kqlE8jXyAyPXH7HqU=
go.opentelemetry.io/otel v1.44.0/go.mod h1:BMgjTHL9WPRlRjL2oZCBTL4whCGtXch2H4BhOPIAyYc=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.44.0 h1:4YsVu3B8+3qtWYYrsUYgn0OG78pN0rnNPRGX4SbokQI=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.44.0/go.mod h1:+wnlSn0mD1ADVMe3v9Z/WIaiz6q6gL2J/ejaAmdmv80=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.44.0 h1:lgh3PiVrRUWMLOVSkQicxzZll5NjF1r+AtsX1XRIHw0=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.44.0/go.mod h1:5Cnhth3m/AgOeTgE3ex12pPmiu/gGtZit03kSzx9X7s=
go.opentelemetry.io/otel/metric v1.44.0 h1:1w0gILTcHdr3YI+ixLyjemwrVnsMURbTZFrSYCdDdmc=
go.opentelemetry.io/otel/metric v1.44.0/go.mod h1:8O7hanEPBNgEMmybD3s2VBKcgWOCsA6tzHBPODAiquo=
go.opentelemetry.io/otel/sdk v1.44.0 h1:nHYwb9lK+fJPU/dnT6s7W7Z8itMWyqrnVfbheVYrZ58=
go.opentelemetry.io/otel/sdk v1.44.0/go.mod h1:Osuydd3Se74nqjAKxid74N5eC+jfEqfTegHRnq58oK0=
go.opentelemetry.io/otel/sdk/metric v1.44.0 h1:3LlKgI+VjbVsjNRFZJZAJ30WjXC5VkNRks6si09iEfI=
go.opentelemetry.io/otel/sdk/metric v1.44.0/go.mod h1:5B5pMARnXxKhltooO4xUuCBorl65a4EpnTalObqOigA=
go.opentelemetry.io/otel/trace v1.44.0 h1:jxF5CsGYCe74MCRx2X4g7WsY/VBKRqqpNvXlX/6gtIk=
go.opentelemetry.io/otel/trace v1.44.0/go.mod h1:oLl1jrMQAVo6v3GAggN+1VH9VIz9iUSvW53sW1Q8PIE=
go.opentelemetry.io/proto/otlp v1.10.0 h1:IQRWgT5srOCYfiWnpqUYz9CVmbO8bFmKcwYxpuCSL2g=
go.opentelemetry.io/proto/otlp v1.10.0/go.mod h1:/CV4QoCR/S9yaPj8utp3lvQPoqMtxXdzn7ozvvozVqk=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y=
go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc=
go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
go.uber.org/zap v1.28.0 h1:IZzaP1Fv73/T/pBMLk4VutPl36uNC+OSUh3JLG3FIjo=
go.uber.org/zap v1.28.0/go.mod h1:rDLpOi171uODNm/mxFcuYWxDsqWSAVkFdX4XojSKg/Q=
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4=
golang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA=
golang.org/x/crypto v0.52.0 h1:RMs7fP2rXdep0CftQlK8Uf+kibLm7qkCcradZWYz988=
golang.org/x/crypto v0.52.0/go.mod h1:1QgfPxDqh0T2M/elOJtp9RvuR95kVjir0e6/BvEmGbc=
golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa h1:Zt3DZoOFFYkKhDT3v7Lm9FDMEV06GpzjG2jrqW+QTE0=
golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa/go.mod h1:K79w1Vqn7PoiZn+TkNpx3BUWUQksGO3JcVX6qIjytmA=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8=
golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w=
golang.org/x/mod v0.36.0 h1:JJjpVx6myfUsUdAzZuOSTTmRE0PfZeNWzzvKrP7amb4=
golang.org/x/mod v0.36.0/go.mod h1:moc6ELqsWcOw5Ef3xVprK5ul/MvtVvkIXLziUOICjUQ=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0=
golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw=
golang.org/x/net v0.55.0 h1:bcvxaJn3e1U6InsFWt1JUq1aSjnRxLzT2rtD2KfkDF8=
golang.org/x/net v0.55.0/go.mod h1:L5U2KuzuOe1lY7Z+aWVIKK6qEeJXnXV9yzGA+WCHJww=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -255,32 +255,32 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo=
golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
golang.org/x/term v0.41.0 h1:QCgPso/Q3RTJx2Th4bDLqML4W6iJiaXFq2/ftQF13YU=
golang.org/x/term v0.41.0/go.mod h1:3pfBgksrReYfZ5lvYM0kSO0LIkAl4Yl2bXOkKP7Ec2A=
golang.org/x/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY=
golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
golang.org/x/term v0.43.0 h1:S4RLU2sB31O/NCl+zFN9Aru9A/Cq2aqKpTZJ6B+DwT4=
golang.org/x/term v0.43.0/go.mod h1:lrhlHNdQJHO+1qVYiHfFKVuVioJIheAc3fBSMFYEIsk=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8=
golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA=
golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc=
golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38=
golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U=
golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k=
golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0=
golang.org/x/tools v0.45.0 h1:18qN3FAooORvApf5XjCXgsuayZOEtXf6JK18I3+ONa8=
golang.org/x/tools v0.45.0/go.mod h1:LuUGqqaXcXMEFEruIVJVm5mgDD8vww/z/SR1gQ4uE/0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/genproto/googleapis/api v0.0.0-20260319201613-d00831a3d3e7 h1:41r6JMbpzBMen0R/4TZeeAmGXSJC7DftGINUodzTkPI=
google.golang.org/genproto/googleapis/api v0.0.0-20260319201613-d00831a3d3e7/go.mod h1:EIQZ5bFCfRQDV4MhRle7+OgjNtZ6P1PiZBgAKuxXu/Y=
google.golang.org/genproto/googleapis/rpc v0.0.0-20260311181403-84a4fc48630c h1:xgCzyF2LFIO/0X2UAoVRiXKU5Xg6VjToG4i2/ecSswk=
google.golang.org/genproto/googleapis/rpc v0.0.0-20260311181403-84a4fc48630c/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
google.golang.org/grpc v1.79.3 h1:sybAEdRIEtvcD68Gx7dmnwjZKlyfuc61Dyo9pGXXkKE=
google.golang.org/grpc v1.79.3/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa h1:Kjn0N0tCrDgiAFW+lGO4JZ3ck44CehvJQMAwj9QF0G8=
google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa/go.mod h1:q4lMZS6kskjT5HvCPrnnypcDPVJqT/f4nfxmkE7gryY=
google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa h1:mZHHdPZl0dbGHCflZgAq/Q468DWVFcU2whhB2KAo8fk=
google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
google.golang.org/grpc v1.81.1 h1:VnnIIZ88UzOOKLukQi+ImGz8O1Wdp8nAGGnvOfEIWQQ=
google.golang.org/grpc v1.81.1/go.mod h1:xGH9GfzOyMTGIOXBJmXt+BX/V0kcdQbdcuwQ/zNw42I=
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@ -288,8 +288,8 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntN
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU=
gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU=
gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q=
gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA=
mvdan.cc/xurls/v2 v2.6.0 h1:3NTZpeTxYVWNSokW3MKeyVkz/j7uYXYiMtXRUfmjbgI=
mvdan.cc/xurls/v2 v2.6.0/go.mod h1:bCvEZ1XvdA6wDnxY7jPPjEmigDtvtvPXAD/Exa9IMSk=
pluginrpc.com/pluginrpc v0.5.0 h1:tOQj2D35hOmvHyPu8e7ohW2/QvAnEtKscy2IJYWQ2yo=

View file

@ -27,6 +27,13 @@ func mustNewMatcher(t *testing.T, mType MatchType, value string) *Matcher {
return m
}
func (m *Matcher) hasCaseInsensitivePrefix() bool {
if m.re == nil {
return false
}
return m.re.caseInsensitivePrefix
}
func TestMatcher(t *testing.T) {
tests := []struct {
matcher *Matcher
@ -137,8 +144,9 @@ func TestInverse(t *testing.T) {
func TestPrefix(t *testing.T) {
for i, tc := range []struct {
matcher *Matcher
prefix string
matcher *Matcher
prefix string
caseInsensitivePrefix bool
}{
{
matcher: mustNewMatcher(t, MatchEqual, "abc"),
@ -180,9 +188,15 @@ func TestPrefix(t *testing.T) {
matcher: mustNewMatcher(t, MatchRegexp, ".+def"),
prefix: "",
},
{
matcher: mustNewMatcher(t, MatchNotRegexp, "(?i)abc.+"),
prefix: "ABC",
caseInsensitivePrefix: true,
},
} {
t.Run(fmt.Sprintf("%d: %s", i, tc.matcher), func(t *testing.T) {
require.Equal(t, tc.prefix, tc.matcher.Prefix())
require.Equal(t, tc.caseInsensitivePrefix, tc.matcher.hasCaseInsensitivePrefix())
})
}
}

View file

@ -46,6 +46,9 @@ type FastRegexMatcher struct {
suffix string
contains []string
// caseInsensitivePrefix is true if prefix exists and should be matched case-insensitively
caseInsensitivePrefix bool
// matchString is the "compiled" function to run by MatchString().
matchString func(string) bool
}
@ -79,7 +82,7 @@ func NewFastRegexMatcher(v string) (*FastRegexMatcher, error) {
clearCapture(parsed)
if parsed.Op == syntax.OpConcat {
m.prefix, m.suffix, m.contains = optimizeConcatRegex(parsed)
m.caseInsensitivePrefix, m.prefix, m.suffix, m.contains = optimizeConcatRegex(parsed)
}
if matches, caseSensitive := findSetMatches(parsed); caseSensitive {
m.setMatches = matches
@ -109,6 +112,15 @@ func (m *FastRegexMatcher) compileMatchStringFunction() func(string) bool {
return m.stringMatcher.Matches
}
if m.caseInsensitivePrefix && m.prefix != "" {
return func(s string) bool {
if !hasPrefixCaseInsensitive(s, m.prefix) {
return false
}
return m.re.MatchString(s)
}
}
return func(s string) bool {
if len(m.setMatches) != 0 {
return slices.Contains(m.setMatches, s)
@ -411,7 +423,7 @@ func optimizeAlternatingSimpleContains(r *syntax.Regexp) *syntax.Regexp {
// optimizeConcatRegex returns literal prefix/suffix text that can be safely
// checked against the label value before running the regexp matcher.
func optimizeConcatRegex(r *syntax.Regexp) (prefix, suffix string, contains []string) {
func optimizeConcatRegex(r *syntax.Regexp) (caseInsensitivePrefix bool, prefix, suffix string, contains []string) {
sub := r.Sub
clearCapture(sub...)
@ -425,14 +437,15 @@ func optimizeConcatRegex(r *syntax.Regexp) (prefix, suffix string, contains []st
}
if len(sub) == 0 {
return prefix, suffix, contains
return caseInsensitivePrefix, prefix, suffix, contains
}
// Given Prometheus regex matchers are always anchored to the begin/end
// of the text, if the first/last operations are literals, we can safely
// treat them as prefix/suffix.
if sub[0].Op == syntax.OpLiteral && (sub[0].Flags&syntax.FoldCase) == 0 {
if sub[0].Op == syntax.OpLiteral {
prefix = string(sub[0].Rune)
caseInsensitivePrefix = (sub[0].Flags & syntax.FoldCase) != 0
}
if last := len(sub) - 1; sub[last].Op == syntax.OpLiteral && (sub[last].Flags&syntax.FoldCase) == 0 {
suffix = string(sub[last].Rune)
@ -446,7 +459,7 @@ func optimizeConcatRegex(r *syntax.Regexp) (prefix, suffix string, contains []st
}
}
return prefix, suffix, contains
return caseInsensitivePrefix, prefix, suffix, contains
}
// StringMatcher is a matcher that matches a string in place of a regular expression.

View file

@ -47,6 +47,7 @@ var (
".*foo.*",
".+foo.+",
".*foo.*|",
"(?i).*foo.*",
".*foo.*|bar.*",
"foo.*|.*bar.*",
".*foo.*|.*bar.*",
@ -67,6 +68,8 @@ var (
"10\\.0\\.(1|2)\\.+",
"10\\.0\\.(1|2).+",
"((fo(bar))|.+foo)",
"(?i)report.scheduled.job_runscheduledreports",
"report.scheduled.job_runscheduledreports",
// A long case sensitive alternation.
"zQPbMkNO|NNSPdvMi|iWuuSoAl|qbvKMimS|IecrXtPa|seTckYqt|NxnyHkgB|fIDlOgKb|UhlWIygH|OtNoJxHG|cUTkFVIV|mTgFIHjr|jQkoIDtE|PPMKxRXl|AwMfwVkQ|CQyMrTQJ|BzrqxVSi|nTpcWuhF|PertdywG|ZZDgCtXN|WWdDPyyE|uVtNQsKk|BdeCHvPZ|wshRnFlH|aOUIitIp|RxZeCdXT|CFZMslCj|AVBZRDxl|IzIGCnhw|ythYuWiz|oztXVXhl|VbLkwqQx|qvaUgyVC|VawUjPWC|ecloYJuj|boCLTdSU|uPrKeAZx|hrMWLWBq|JOnUNHRM|rYnujkPq|dDEdZhIj|DRrfvugG|yEGfDxVV|YMYdJWuP|PHUQZNWM|AmKNrLis|zTxndVfn|FPsHoJnc|EIulZTua|KlAPhdzg|ScHJJCLt|NtTfMzME|eMCwuFdo|SEpJVJbR|cdhXZeCx|sAVtBwRh|kVFEVcMI|jzJrxraA|tGLHTell|NNWoeSaw|DcOKSetX|UXZAJyka|THpMphDP|rizheevl|kDCBRidd|pCZZRqyu|pSygkitl|SwZGkAaW|wILOrfNX|QkwVOerj|kHOMxPDr|EwOVycJv|AJvtzQFS|yEOjKYYB|LizIINLL|JBRSsfcG|YPiUqqNl|IsdEbvee|MjEpGcBm|OxXZVgEQ|xClXGuxa|UzRCGFEb|buJbvfvA|IPZQxRet|oFYShsMc|oBHffuHO|bzzKrcBR|KAjzrGCl|IPUsAVls|OGMUMbIU|gyDccHuR|bjlalnDd|ZLWjeMna|fdsuIlxQ|dVXtiomV|XxedTjNg|XWMHlNoA|nnyqArQX|opfkWGhb|wYtnhdYb",
// An extremely long case sensitive alternation. This is a special
@ -108,6 +111,7 @@ var (
"foo", " foo bar", "bar", "buzz\nbar", "bar foo", "bfoo", "\n", "\nfoo", "foo\n", "hello foo world", "hello foo\n world", "",
"FOO", "Foo", "fOo", "foO", "OO", "Oo", "\nfoo\n", strings.Repeat("f", 20), "prometheus", "prometheus_api_v1", "prometheus_api_v1_foo",
"10.0.1.20", "10.0.2.10", "10.0.3.30", "10.0.4.40",
"report.scheduled.job_runscheduledreports", "Report.Scheduled.JobRunScheduledReports", "Report.Scheduled.Job_RunScheduledReports",
"foofoo0", "foofoo", "😀foo0", "ſſs", "ſſS", "AAAAAAAAAAAAAAAAAAAAAAAA", "BBBBBBBBBBBBBBBBBBBBBBBB", "cccccccccccccccccccccccC", "ſſſſſſſſſſſſſſſſſſſſſſſſS", "SSSSSSSSSSSSSSSSSSSSSSSSſ",
"a-b-c-d-e",
"aaaaaa-bbbbbb-cccccc-dddddd-eeeeee",
@ -154,10 +158,11 @@ func readable(s string) string {
func TestOptimizeConcatRegex(t *testing.T) {
cases := []struct {
regex string
prefix string
suffix string
contains []string
regex string
prefix string
isCaseInsensitivePrefix bool
suffix string
contains []string
}{
{regex: "foo(hello|bar)", prefix: "foo", suffix: "", contains: nil},
{regex: "foo(hello|bar)world", prefix: "foo", suffix: "world", contains: nil},
@ -171,12 +176,12 @@ func TestOptimizeConcatRegex(t *testing.T) {
{regex: ".*[abc].*", prefix: "", suffix: "", contains: nil},
{regex: ".*((?i)abc).*", prefix: "", suffix: "", contains: nil},
{regex: ".*(?i:abc).*", prefix: "", suffix: "", contains: nil},
{regex: "(?i:abc).*", prefix: "", suffix: "", contains: nil},
{regex: "(?i:abc).*", prefix: "ABC", isCaseInsensitivePrefix: true, suffix: "", contains: nil},
{regex: ".*(?i:abc)", prefix: "", suffix: "", contains: nil},
{regex: ".*(?i:abc)def.*", prefix: "", suffix: "", contains: []string{"def"}},
{regex: "(?i).*(?-i:abc)def", prefix: "", suffix: "", contains: []string{"abc"}},
{regex: ".*(?msU:abc).*", prefix: "", suffix: "", contains: []string{"abc"}},
{regex: "[aA]bc.*", prefix: "", suffix: "", contains: []string{"bc"}},
{regex: "[aA]bc.*", prefix: "A", isCaseInsensitivePrefix: true, suffix: "", contains: []string{"bc"}},
{regex: "^5..$", prefix: "5", suffix: "", contains: nil},
{regex: "^release.*", prefix: "release", suffix: "", contains: nil},
{regex: "^env-[0-9]+laio[1]?[^0-9].*", prefix: "env-", suffix: "", contains: []string{"laio"}},
@ -184,13 +189,16 @@ func TestOptimizeConcatRegex(t *testing.T) {
}
for _, c := range cases {
parsed, err := syntax.Parse(c.regex, syntax.Perl|syntax.DotNL)
require.NoError(t, err)
t.Run(c.regex, func(t *testing.T) {
parsed, err := syntax.Parse(c.regex, syntax.Perl|syntax.DotNL)
require.NoError(t, err)
prefix, suffix, contains := optimizeConcatRegex(parsed)
require.Equal(t, c.prefix, prefix)
require.Equal(t, c.suffix, suffix)
require.Equal(t, c.contains, contains)
caseInsensitivePrefix, prefix, suffix, contains := optimizeConcatRegex(parsed)
require.Equal(t, c.prefix, prefix)
require.Equal(t, c.isCaseInsensitivePrefix, caseInsensitivePrefix)
require.Equal(t, c.suffix, suffix)
require.Equal(t, c.contains, contains)
})
}
}
@ -432,6 +440,8 @@ func TestNewFastRegexMatcher(t *testing.T) {
{"foo.?", &literalPrefixSensitiveStringMatcher{prefix: "foo", right: &zeroOrOneCharacterStringMatcher{matchNL: true}}},
{"f.?o", nil},
{".*foo.*|.*bar.*|.*baz.*", &containsStringMatcher{left: trueMatcher{}, substrings: []string{"foo", "bar", "baz"}, right: trueMatcher{}}},
{"(?i)report.scheduled.job_runscheduledreports", nil},
{"report.scheduled.job_runscheduledreports", nil},
} {
t.Run(c.pattern, func(t *testing.T) {
t.Parallel()

View file

@ -222,6 +222,7 @@ func requireEntries(t *testing.T, exp, got []parsedEntry) {
_, yIsLabels := y.(labels.Labels)
return !xIsLabels && !yIsLabels
}, cmpopts.EquateEmpty()),
cmpopts.EquateNaNs(),
cmp.AllowUnexported(parsedEntry{}),
})
}

View file

@ -763,7 +763,7 @@ func (p *OpenMetricsParser) getFloatValue(t token, after string) (float64, error
return 0, fmt.Errorf("%w while parsing: %q", err, p.l.b[p.start:p.l.i])
}
// Ensure canonical NaN value.
if math.IsNaN(p.exemplarVal) {
if math.IsNaN(val) {
val = math.Float64frombits(value.NormalNaN)
}
return val, nil

View file

@ -16,6 +16,7 @@ package textparse
import (
"fmt"
"io"
"math"
"testing"
"github.com/prometheus/common/model"
@ -23,6 +24,7 @@ import (
"github.com/prometheus/prometheus/model/exemplar"
"github.com/prometheus/prometheus/model/labels"
"github.com/prometheus/prometheus/model/value"
)
func int64p(x int64) *int64 { return &x }
@ -113,7 +115,13 @@ foobar_count 21
foobar_created 1520430004
foobar_sum 324789.6
foobar{quantile="0.95"} 123.8
foobar{quantile="0.99"} 150.1`
foobar{quantile="0.99"} 150.1
# HELP nansum Summary with NaN value
# TYPE nansum summary
nansum_count 0
nansum_sum 0.0
nansum{quantile="0.95"} nan
nansum{quantile="0.99"} NaN`
input += "\n# HELP metric foo\x00bar"
input += "\nnull_byte_metric{a=\"abc\x00\"} 1"
@ -631,6 +639,42 @@ foobar{quantile="0.99"} 150.1`
labels.FromStrings("__name__", "foobar", "quantile", "0.99"),
),
st: 1520430004000,
}, {
m: "nansum",
help: "Summary with NaN value",
}, {
m: "nansum",
typ: model.MetricTypeSummary,
}, {
m: "nansum_count",
lset: typeAndUnitLabels(
typeAndUnitEnabled,
labels.FromStrings("__name__", "nansum_count", "__type__", string(model.MetricTypeSummary)),
labels.FromStrings("__name__", "nansum_count"),
),
}, {
m: "nansum_sum",
lset: typeAndUnitLabels(
typeAndUnitEnabled,
labels.FromStrings("__name__", "nansum_sum", "__type__", string(model.MetricTypeSummary)),
labels.FromStrings("__name__", "nansum_sum"),
),
}, {
m: `nansum{quantile="0.95"}`,
v: math.Float64frombits(value.NormalNaN),
lset: typeAndUnitLabels(
typeAndUnitEnabled,
labels.FromStrings("__name__", "nansum", "__type__", string(model.MetricTypeSummary), "quantile", "0.95"),
labels.FromStrings("__name__", "nansum", "quantile", "0.95"),
),
}, {
m: `nansum{quantile="0.99"}`,
v: math.Float64frombits(value.NormalNaN),
lset: typeAndUnitLabels(
typeAndUnitEnabled,
labels.FromStrings("__name__", "nansum", "__type__", string(model.MetricTypeSummary), "quantile", "0.99"),
labels.FromStrings("__name__", "nansum", "quantile", "0.99"),
),
}, {
m: "metric",
help: "foo\x00bar",

View file

@ -14,6 +14,8 @@
package writev2
import (
"fmt"
"github.com/prometheus/common/model"
"github.com/prometheus/prometheus/model/exemplar"
@ -29,8 +31,8 @@ func (m TimeSeries) ToLabels(b *labels.ScratchBuilder, symbols []string) (labels
return desymbolizeLabels(b, m.GetLabelsRefs(), symbols)
}
// ToMetadata return model metadata from timeseries' remote metadata.
func (m TimeSeries) ToMetadata(symbols []string) metadata.Metadata {
// ToMetadata returns model metadata from timeseries' remote metadata.
func (m TimeSeries) ToMetadata(symbols []string) (metadata.Metadata, error) {
typ := model.MetricTypeUnknown
switch m.Metadata.Type {
case Metadata_METRIC_TYPE_COUNTER:
@ -48,11 +50,17 @@ func (m TimeSeries) ToMetadata(symbols []string) metadata.Metadata {
case Metadata_METRIC_TYPE_STATESET:
typ = model.MetricTypeStateset
}
if int(m.Metadata.UnitRef) >= len(symbols) {
return metadata.Metadata{}, fmt.Errorf("metadata unit_ref %d outside of symbols table (size %d)", m.Metadata.UnitRef, len(symbols))
}
if int(m.Metadata.HelpRef) >= len(symbols) {
return metadata.Metadata{}, fmt.Errorf("metadata help_ref %d outside of symbols table (size %d)", m.Metadata.HelpRef, len(symbols))
}
return metadata.Metadata{
Type: typ,
Unit: symbols[m.Metadata.UnitRef],
Help: symbols[m.Metadata.HelpRef],
}
}, nil
}
// FromMetadataType transforms a Prometheus metricType into writev2 metricType.

View file

@ -130,9 +130,31 @@ func TestToMetadata(t *testing.T) {
} {
t.Run("", func(t *testing.T) {
ts := writev2.TimeSeries{Metadata: tc.input}
require.Equal(t, tc.expected, ts.ToMetadata(sym.Symbols()))
meta, err := ts.ToMetadata(sym.Symbols())
require.NoError(t, err)
require.Equal(t, tc.expected, meta)
})
}
t.Run("out of bounds unit ref", func(t *testing.T) {
ts := writev2.TimeSeries{Metadata: writev2.Metadata{UnitRef: 999}}
_, err := ts.ToMetadata(sym.Symbols())
require.Error(t, err)
require.Contains(t, err.Error(), "metadata unit_ref 999 outside of symbols table")
})
t.Run("out of bounds help ref", func(t *testing.T) {
ts := writev2.TimeSeries{Metadata: writev2.Metadata{HelpRef: 999}}
_, err := ts.ToMetadata(sym.Symbols())
require.Error(t, err)
require.Contains(t, err.Error(), "metadata help_ref 999 outside of symbols table")
})
t.Run("empty symbols table", func(t *testing.T) {
ts := writev2.TimeSeries{Metadata: writev2.Metadata{}}
_, err := ts.ToMetadata([]string{})
require.Error(t, err)
})
}
func TestToHistogram_Empty(t *testing.T) {

View file

@ -87,10 +87,21 @@ func (v *durationVisitor) calculateDuration(expr parser.Expr, allowedNegative bo
if err != nil {
return 0, err
}
// Reject NaN and infinities up front. NaN compares false against everything,
// so without this guard a NaN duration would slip past the bounds check
// below and produce an implementation-defined int64 in the time.Duration
// conversion at the end of this function.
if math.IsNaN(duration) || math.IsInf(duration, 0) {
return 0, fmt.Errorf("%d:%d: duration is NaN or infinite", expr.PositionRange().Start, expr.PositionRange().End)
}
if duration <= 0 && !allowedNegative {
return 0, fmt.Errorf("%d:%d: duration must be greater than 0", expr.PositionRange().Start, expr.PositionRange().End)
}
if duration > 1<<63-1 || duration < -1<<63 {
// duration is in seconds; the conversion below produces nanoseconds in an
// int64, so the safe input range is +/- math.MaxInt64 / 1e9 seconds. Match
// the bound used by the parser for duration literals (see
// offset_duration_expr in generated_parser.y).
if duration > 1<<63/1e9 || duration < -(1<<63)/1e9 {
return 0, fmt.Errorf("%d:%d: duration is out of range", expr.PositionRange().Start, expr.PositionRange().End)
}
return time.Duration(duration*1000) * time.Millisecond, nil
@ -124,9 +135,9 @@ func (v *durationVisitor) evaluateDurationExpr(expr parser.Expr) (float64, error
return float64(v.step.Seconds()), nil
case parser.RANGE:
return float64(v.queryRange.Seconds()), nil
case parser.MIN:
case parser.MIN_OF:
return math.Min(lhs, rhs), nil
case parser.MAX:
case parser.MAX_OF:
return math.Max(lhs, rhs), nil
case parser.ADD:
if n.LHS == nil {

View file

@ -23,7 +23,7 @@ import (
)
func TestDurationVisitor(t *testing.T) {
p := parser.NewParser(parser.Options{})
p := parser.NewParser(parser.Options{ExperimentalDurationExpr: true})
complexExpr := `sum_over_time(
rate(metric[5m] offset 1h)[10m:30s] offset 2h
) +
@ -228,7 +228,7 @@ func TestCalculateDuration(t *testing.T) {
expected: 150 * time.Second,
},
{
name: "max of step and range",
name: "max_of of step and range",
expr: &parser.DurationExpr{
LHS: &parser.DurationExpr{
Op: parser.STEP,
@ -236,7 +236,7 @@ func TestCalculateDuration(t *testing.T) {
RHS: &parser.DurationExpr{
Op: parser.RANGE,
},
Op: parser.MAX,
Op: parser.MAX_OF,
},
expected: 5 * time.Minute,
},
@ -266,6 +266,37 @@ func TestCalculateDuration(t *testing.T) {
},
errorMessage: "modulo by zero",
},
{
name: "NaN from negative base raised to fractional power",
expr: &parser.DurationExpr{
LHS: &parser.NumberLiteral{Val: -1},
RHS: &parser.NumberLiteral{Val: 0.5},
Op: parser.POW,
},
errorMessage: "duration is NaN or infinite",
allowedNegative: true,
},
{
name: "infinity from huge power",
expr: &parser.DurationExpr{
LHS: &parser.NumberLiteral{Val: 2},
RHS: &parser.NumberLiteral{Val: 1e10},
Op: parser.POW,
},
errorMessage: "duration is NaN or infinite",
},
{
name: "duration exceeds time.Duration range",
expr: &parser.NumberLiteral{Val: 1e10},
errorMessage: "duration is out of range",
},
{
name: "duration just below the upper bound is accepted",
expr: &parser.NumberLiteral{Val: 1e9},
// 1e9 seconds is below 1<<63/1e9 seconds (~9.22e9), so it is
// representable as a time.Duration. The exact value is preserved.
expected: time.Duration(1e9) * time.Second,
},
}
for _, tt := range tests {

View file

@ -1717,7 +1717,7 @@ func (ev *evaluator) rangeEvalAgg(ctx context.Context, aggExpr *parser.Aggregate
// smoothSeries is a helper function that smooths the series by interpolating the values
// based on values before and after the timestamp.
func (ev *evaluator) smoothSeries(series []storage.Series, offset time.Duration) Matrix {
func (ev *evaluator) smoothSeries(series []storage.Series, offset time.Duration, pos posrange.PositionRange) (Matrix, annotations.Annotations) {
dur := ev.endTimestamp - ev.startTimestamp
it := storage.NewBuffer(dur + 2*durationMilliseconds(ev.lookbackDelta))
@ -1728,6 +1728,7 @@ func (ev *evaluator) smoothSeries(series []storage.Series, offset time.Duration)
var chkIter chunkenc.Iterator
mat := make(Matrix, 0, len(series))
var annos annotations.Annotations
for _, s := range series {
ss := Series{Metric: s.Labels()}
@ -1737,6 +1738,7 @@ func (ev *evaluator) smoothSeries(series []storage.Series, offset time.Duration)
var floats []FPoint
var hists []HPoint
metricName := s.Labels().Get(labels.MetricName)
for evalTS := ev.startTimestamp; evalTS <= ev.endTimestamp; evalTS += step {
// Apply offset to get the data timestamp.
@ -1749,40 +1751,80 @@ func (ev *evaluator) smoothSeries(series []storage.Series, offset time.Duration)
continue
}
if len(hists) > 0 {
// TODO: support native histograms.
ev.errorf("smoothed and anchored modifiers do not work with native histograms")
if len(hists) > 0 && len(floats) > 0 {
annos.Add(annotations.NewMixedFloatsHistogramsWarning(metricName, pos))
continue
}
// Binary search for the first index with T >= dataTS.
i := sort.Search(len(floats), func(i int) bool { return floats[i].T >= dataTS })
if len(hists) > 0 {
// Binary search for the first histogram index with T >= dataTS.
i := sort.Search(len(hists), func(i int) bool { return hists[i].T >= dataTS })
switch {
case i < len(floats) && floats[i].T == dataTS:
// Exact match.
ss.Floats = append(ss.Floats, FPoint{F: floats[i].F, T: evalTS})
switch {
case i < len(hists) && hists[i].T == dataTS:
// Exact match.
ss.Histograms = append(ss.Histograms, HPoint{H: hists[i].H.Copy(), T: evalTS})
case i > 0 && i < len(floats):
// Interpolate between prev and next.
// TODO: detect if the sample is a counter, based on __type__ or metadata.
prev, next := floats[i-1], floats[i]
val := interpolate(prev, next, dataTS, false)
ss.Floats = append(ss.Floats, FPoint{F: val, T: evalTS})
case i > 0 && i < len(hists):
// Interpolate between prev and next.
// Use CounterResetHint to determine counter vs gauge: treat as counter
// unless both samples explicitly carry the gauge hint.
prev, next := hists[i-1], hists[i]
if prev.H.UsesCustomBuckets() != next.H.UsesCustomBuckets() {
annos.Add(annotations.NewMixedExponentialCustomHistogramsWarning(metricName, pos))
continue
}
isCounter := prev.H.CounterResetHint != histogram.GaugeType || next.H.CounterResetHint != histogram.GaugeType
h, err := interpolateHistograms(prev.H, prev.T, next.H, next.T, dataTS, isCounter, &annos, pos)
if err != nil {
annosFromInterpolationError(&annos, err, metricName, pos)
continue
}
ss.Histograms = append(ss.Histograms, HPoint{H: h, T: evalTS})
case i > 0:
// No next point yet; carry forward previous value.
prev := floats[i-1]
ss.Floats = append(ss.Floats, FPoint{F: prev.F, T: evalTS})
case i > 0:
// No next point yet; carry forward previous value.
// CounterResetHint is reset to UnknownCounterReset because the hint
// describes the relationship between consecutive samples, not the value.
prev := hists[i-1]
h := prev.H.Copy()
h.CounterResetHint = histogram.UnknownCounterReset
ss.Histograms = append(ss.Histograms, HPoint{H: h, T: evalTS})
default:
// i == 0 and floats[0].T > dataTS: there is no previous data yet; skip.
default:
// i == 0 and hists[0].T > dataTS: there is no previous data yet; skip.
}
} else {
// Binary search for the first index with T >= dataTS.
i := sort.Search(len(floats), func(i int) bool { return floats[i].T >= dataTS })
switch {
case i < len(floats) && floats[i].T == dataTS:
// Exact match.
ss.Floats = append(ss.Floats, FPoint{F: floats[i].F, T: evalTS})
case i > 0 && i < len(floats):
// Interpolate between prev and next.
// TODO: detect if the sample is a counter, based on __type__ or metadata.
prev, next := floats[i-1], floats[i]
val := interpolate(prev, next, dataTS, false)
ss.Floats = append(ss.Floats, FPoint{F: val, T: evalTS})
case i > 0:
// No next point yet; carry forward previous value.
prev := floats[i-1]
ss.Floats = append(ss.Floats, FPoint{F: prev.F, T: evalTS})
default:
// i == 0 and floats[0].T > dataTS: there is no previous data yet; skip.
}
}
}
mat = append(mat, ss)
}
return mat
return mat, annos
}
// evalSeries generates a Matrix between ev.startTimestamp and ev.endTimestamp (inclusive), each point spaced ev.interval apart, from series given offset.
@ -2021,6 +2063,11 @@ func (ev *evaluator) eval(ctx context.Context, expr parser.Expr) (parser.Value,
return ev.evalInfo(ctx, e.Args)
}
// Functions with nil entries in FunctionCalls should have been handled before reaching this point.
if call == nil {
panic(fmt.Errorf("unexpected nil implementation for function %q", e.Func.Name))
}
// Emit a warning when sort is used for range queries.
if (e.Func.Name == "sort" || e.Func.Name == "sort_desc" || e.Func.Name == "sort_by_label" || e.Func.Name == "sort_by_label_desc") && ev.startTimestamp != ev.endTimestamp {
warnings.Add(annotations.NewSortInRangeQueryWarning(e.PositionRange()))
@ -2100,7 +2147,7 @@ func (ev *evaluator) eval(ctx context.Context, expr parser.Expr) (parser.Value,
var chkIter chunkenc.Iterator
var startTimestamps *StartTimestamps
if ev.useStartTimestamps && (e.Func.Name == "rate" || e.Func.Name == "irate" || e.Func.Name == "increase") {
if ev.useStartTimestamps && (e.Func.Name == "rate" || e.Func.Name == "irate" || e.Func.Name == "increase" || e.Func.Name == "resets") {
// TODO: consider pooling this.
startTimestamps = &StartTimestamps{}
}
@ -2178,12 +2225,6 @@ func (ev *evaluator) eval(ctx context.Context, expr parser.Expr) (parser.Value,
if len(floats)+len(histograms) == 0 {
continue
}
if selVS.Anchored || selVS.Smoothed {
if len(histograms) > 0 {
// TODO: support native histograms.
ev.errorf("smoothed and anchored modifiers do not work with native histograms")
}
}
inMatrix[0].Floats = floats
inMatrix[0].Histograms = histograms
enh.Ts = ts
@ -2378,7 +2419,8 @@ func (ev *evaluator) eval(ctx context.Context, expr parser.Expr) (parser.Value,
ev.error(errWithWarnings{fmt.Errorf("expanding series: %w", err), ws})
}
if e.Smoothed {
mat := ev.smoothSeries(e.Series, e.Offset)
mat, smoothAnnos := ev.smoothSeries(e.Series, e.Offset, e.PositionRange())
ws.Merge(smoothAnnos)
return mat, ws
}
mat := ev.evalSeries(ctx, e.Series, e.Offset, false)
@ -2722,7 +2764,7 @@ func (ev *evaluator) matrixSelector(ctx context.Context, node *parser.MatrixSele
ss.Floats = extendFloats(ss.Floats, matrixMint, matrixMaxt, false)
case vs.Smoothed:
if ss.Histograms != nil {
ev.errorf("anchored modifier is not supported with histograms")
ev.errorf("smoothed modifier is not supported with histograms")
}
ss.Floats = extendFloats(ss.Floats, matrixMint, matrixMaxt, true)
}
@ -3179,7 +3221,7 @@ func (ev *evaluator) VectorBinop(op parser.ItemType, lhs, rhs Vector, matching *
sigOrd := rhsh[i].sigOrdinal
if (matching.Card == parser.CardOneToOne && matchedSigsPresent[sigOrd]) ||
(matching.Card != parser.CardOneToOne && matchedSigs[sigOrd] != nil) {
(matching.Card != parser.CardOneToOne && len(matchedSigs[sigOrd]) > 0) {
continue // Already matched.
}
ls := Sample{

View file

@ -59,13 +59,6 @@ import (
// Scalar results should be returned as the value of a sample in a Vector.
type FunctionCall func(vectorVals []Vector, matrixVals Matrix, args parser.Expressions, enh *EvalNodeHelper) (Vector, annotations.Annotations)
// funcQueryContext is a placeholder for start(), end(), range(), and step() functions.
// These are folded into NumberLiteral nodes by foldQueryContextFunctions during query
// preprocessing and must never reach the evaluator.
func funcQueryContext(_ []Vector, _ Matrix, _ parser.Expressions, _ *EvalNodeHelper) (Vector, annotations.Annotations) {
panic("query context functions must be folded during preprocessing and must never be evaluated")
}
// === time() float64 ===
func funcTime(_ []Vector, _ Matrix, _ parser.Expressions, enh *EvalNodeHelper) (Vector, annotations.Annotations) {
return Vector{Sample{
@ -107,6 +100,66 @@ func interpolate(p1, p2 FPoint, t int64, isCounter bool) float64 {
return y1 + (y2-y1)*float64(t-p1.T)/float64(p2.T-p1.T)
}
// interpolateHistograms performs linear interpolation between two histogram points.
// If isCounter is true and there is a counter reset, it models the counter
// as starting from 0 (post-reset) by returning h2 scaled by the fraction.
// It returns an error if the histograms are incompatible (e.g. mixing
// exponential and custom-bucket schemas). NHCB bucket-bounds reconciliation
// warnings are collected into annos.
func interpolateHistograms(h1 *histogram.FloatHistogram, t1 int64, h2 *histogram.FloatHistogram, t2, t int64, isCounter bool, annos *annotations.Annotations, pos posrange.PositionRange) (*histogram.FloatHistogram, error) {
if t == t1 {
return h1.Copy(), nil
}
if t == t2 {
return h2.Copy(), nil
}
fraction := float64(t-t1) / float64(t2-t1)
if isCounter && h2.DetectReset(h1) {
// Counter reset: model as starting from zero.
return h2.Copy().Mul(fraction), nil
}
// Result = H1 + (H2 - H1) * fraction.
result := h2.Copy()
_, _, nhcbReconciled, err := result.Sub(h1)
if err != nil {
return nil, err
}
if nhcbReconciled {
annos.Add(annotations.NewMismatchedCustomBucketsHistogramsInfo(pos, annotations.HistogramSub))
}
result.Mul(fraction)
_, _, nhcbReconciled, err = result.Add(h1)
if err != nil {
return nil, err
}
if nhcbReconciled {
annos.Add(annotations.NewMismatchedCustomBucketsHistogramsInfo(pos, annotations.HistogramAdd))
}
return result, nil
}
// pickOrInterpolateLeftHistogram returns the histogram at the left boundary of the range.
// If interpolation is needed (when smoothed is true and the first sample is before the range start),
// it returns the interpolated histogram at the left boundary; otherwise, it returns a copy of the first sample's histogram.
func pickOrInterpolateLeftHistogram(hists []HPoint, first int, rangeStart int64, smoothed, isCounter bool, annos *annotations.Annotations, pos posrange.PositionRange) (*histogram.FloatHistogram, error) {
if smoothed && hists[first].T < rangeStart {
return interpolateHistograms(hists[first].H, hists[first].T, hists[first+1].H, hists[first+1].T, rangeStart, isCounter, annos, pos)
}
return hists[first].H.Copy(), nil
}
// pickOrInterpolateRightHistogram returns the histogram at the right boundary of the range.
// If interpolation is needed (when smoothed is true and the last sample is after the range end),
// it returns the interpolated histogram at the right boundary; otherwise, it returns a copy of the last sample's histogram.
func pickOrInterpolateRightHistogram(hists []HPoint, last int, rangeEnd int64, smoothed, isCounter bool, annos *annotations.Annotations, pos posrange.PositionRange) (*histogram.FloatHistogram, error) {
if smoothed && last > 0 && hists[last].T > rangeEnd {
return interpolateHistograms(hists[last-1].H, hists[last-1].T, hists[last].H, hists[last].T, rangeEnd, isCounter, annos, pos)
}
return hists[last].H.Copy(), nil
}
// correctForCounterResets calculates the correction for counter resets.
// This function is only used for extendedRate functions with smoothed or anchored rates.
func correctForCounterResets(left, right float64, points []FPoint) float64 {
@ -124,9 +177,134 @@ func correctForCounterResets(left, right float64, points []FPoint) float64 {
return correction
}
// annosFromInterpolationError classifies an error returned by
// interpolateHistograms (via pickOrInterpolate*Histogram) into the appropriate
// annotation. If the error is not recognised, annos is left unchanged.
func annosFromInterpolationError(annos *annotations.Annotations, err error, metricName string, pos posrange.PositionRange) {
if errors.Is(err, histogram.ErrHistogramsIncompatibleSchema) {
annos.Add(annotations.NewMixedExponentialCustomHistogramsWarning(metricName, pos))
}
}
// addHistogramWithAnnotations adds other into base in place, translating
// histogram errors and bucket-bounds reconciliations into annotations.
// It returns false if the operation failed.
func addHistogramWithAnnotations(base, other *histogram.FloatHistogram, annos *annotations.Annotations, metricName string, pos posrange.PositionRange) bool {
_, _, nhcbBoundsReconciled, err := base.Add(other)
if err != nil {
if errors.Is(err, histogram.ErrHistogramsIncompatibleSchema) {
annos.Add(annotations.NewMixedExponentialCustomHistogramsWarning(metricName, pos))
}
return false
}
if nhcbBoundsReconciled {
annos.Add(annotations.NewMismatchedCustomBucketsHistogramsInfo(pos, annotations.HistogramAdd))
}
return true
}
// subHistogramWithAnnotations subtracts other from base in place, translating
// histogram errors and bucket-bounds reconciliations into annotations.
// It returns false if the operation failed.
func subHistogramWithAnnotations(base, other *histogram.FloatHistogram, annos *annotations.Annotations, metricName string, pos posrange.PositionRange) bool {
_, _, nhcbBoundsReconciled, err := base.Sub(other)
if err != nil {
if errors.Is(err, histogram.ErrHistogramsIncompatibleSchema) {
annos.Add(annotations.NewMixedExponentialCustomHistogramsWarning(metricName, pos))
}
return false
}
if nhcbBoundsReconciled {
annos.Add(annotations.NewMismatchedCustomBucketsHistogramsInfo(pos, annotations.HistogramSub))
}
return true
}
// validateHistogramRange checks all histogram samples in h for schema
// consistency and counter-type hints. It returns false (and adds an annotation
// to annos) when exponential and custom buckets are mixed. It adds a
// NativeHistogramNotCounterWarning for any sample carrying a gauge hint while
// isCounter is true.
func validateHistogramRange(h []HPoint, isCounter bool, annos *annotations.Annotations, metricName string, pos posrange.PositionRange) bool {
usingCustomBuckets := h[0].H.UsesCustomBuckets()
for _, p := range h {
if p.H.UsesCustomBuckets() != usingCustomBuckets {
annos.Add(annotations.NewMixedExponentialCustomHistogramsWarning(metricName, pos))
return false
}
if isCounter && p.H.CounterResetHint == histogram.GaugeType {
annos.Add(annotations.NewNativeHistogramNotCounterWarning(metricName, pos))
}
}
return true
}
// correctForCounterResetsHistogram calculates the histogram correction for
// counter resets between firstSampleIndex and lastSampleIndex in h, using
// left and right as the boundary values. It mirrors correctForCounterResets
// for float samples. It returns the accumulated correction (nil if none),
// any annotations, and false if combining histograms failed.
func correctForCounterResetsHistogram(h []HPoint, firstSampleIndex, lastSampleIndex int, left, right *histogram.FloatHistogram, rangeStart int64, smoothed bool, metricName string, pos posrange.PositionRange) (*histogram.FloatHistogram, annotations.Annotations, bool) {
// firstSampleIndex is represented by left, so the loop starts one beyond.
first := firstSampleIndex + 1
prev := left
if smoothed && h[firstSampleIndex].T < rangeStart && h[firstSampleIndex+1].H.DetectReset(h[firstSampleIndex].H) {
// The left interpolation spanned the reset between h[firstSampleIndex]
// and h[firstSampleIndex+1]. That reset is already accounted for, so
// skip h[firstSampleIndex+1] from the loop and use it as the comparison
// anchor for any reset that immediately follows.
prev = h[firstSampleIndex+1].H
first++
}
// lastSampleIndex is always excluded: right is either a direct copy of
// h[lastSampleIndex] or an interpolation that inherits its CounterResetHint.
// Including h[lastSampleIndex] in the loop would make right.DetectReset
// self-detect on the same hint. The final right.DetectReset(prev) below
// handles the right-boundary reset safely once h[lastSampleIndex] is not prev.
last := lastSampleIndex - 1
// first > last+1 when there is nothing between the two boundary samples to
// check. This happens when firstSampleIndex == lastSampleIndex (single-sample
// window), or when the smoothed left interpolation already spanned the only
// reset interval (lastSampleIndex == firstSampleIndex+1 and first was
// incremented above). Both boundaries were interpolated from the same reset
// segment, so there is nothing more to correct.
if first > last+1 {
return nil, nil, true
}
var (
correction *histogram.FloatHistogram
annos annotations.Annotations
)
addCorrection := func(h *histogram.FloatHistogram) bool {
if correction == nil {
correction = h.Copy()
return true
}
return addHistogramWithAnnotations(correction, h, &annos, metricName, pos)
}
for _, p := range h[first : last+1] {
if p.H.DetectReset(prev) {
if !addCorrection(prev) {
return nil, annos, false
}
}
prev = p.H
}
if right.DetectReset(prev) {
if !addCorrection(prev) {
return nil, annos, false
}
}
return correction, annos, true
}
// extendedRate is a utility function for anchored/smoothed rate/increase/delta.
// It calculates the rate (allowing for counter resets if isCounter is true),
// extrapolates if the first/last sample if needed, and returns
// interpolates at the first/last sample boundary if needed, and returns
// the result as either per-second (if isRate is true) or overall.
func extendedRate(vals Matrix, args parser.Expressions, enh *EvalNodeHelper, isCounter, isRate bool) (Vector, annotations.Annotations) {
var (
@ -178,18 +356,116 @@ func extendedRate(vals Matrix, args parser.Expressions, enh *EvalNodeHelper, isC
return append(enh.Out, Sample{F: resultFloat}), annos
}
// extendedHistogramRate is a utility function for anchored/smoothed rate/increase/delta
// with native histograms. It calculates the rate (allowing for counter resets if
// isCounter is true), interpolates at the range boundaries if needed, and returns
// the result as either per-second (if isRate is true) or overall.
//
// TODO: histogramRate pre-computes the minimum exponential schema across all
// samples and reduces every sample to that schema before doing arithmetic, so
// the schema is reduced at most once. extendedHistogramRate reduces schema on
// the fly during pairwise Sub/Add operations. In the common constant-schema
// case both produce identical results. In mixed-schema cases the final schema
// is also the same (global minimum wins either way), but intermediate values
// may briefly sit at a higher resolution before being pulled down when the
// correction is added. Aligning the two approaches requires a min-schema
// pre-scan followed by CopyToSchema on the interpolated boundaries, which is
// a non-trivial change and warrants its own PR.
func extendedHistogramRate(vals Matrix, args parser.Expressions, enh *EvalNodeHelper, isCounter, isRate bool) (Vector, annotations.Annotations) {
var (
ms = args[0].(*parser.MatrixSelector)
vs = ms.VectorSelector.(*parser.VectorSelector)
samples = vals[0]
h = samples.Histograms
lastSampleIndex = len(h) - 1
rangeStart = enh.Ts - durationMilliseconds(ms.Range+vs.Offset)
rangeEnd = enh.Ts - durationMilliseconds(vs.Offset)
annos annotations.Annotations
metricName = getMetricName(samples.Metric)
pos = args[0].PositionRange()
smoothed = vs.Smoothed
)
firstSampleIndex := max(0, sort.Search(lastSampleIndex, func(i int) bool { return h[i].T > rangeStart })-1)
if smoothed {
lastSampleIndex = sort.Search(lastSampleIndex, func(i int) bool { return h[i].T >= rangeEnd })
}
if h[lastSampleIndex].T <= rangeStart {
return enh.Out, annos
}
if smoothed && h[firstSampleIndex].T > rangeEnd {
return enh.Out, annos
}
if !validateHistogramRange(h[firstSampleIndex:lastSampleIndex+1], isCounter, &annos, metricName, pos) {
return enh.Out, annos
}
left, err := pickOrInterpolateLeftHistogram(h, firstSampleIndex, rangeStart, smoothed, isCounter, &annos, pos)
if err != nil {
annosFromInterpolationError(&annos, err, metricName, pos)
return enh.Out, annos
}
right, err := pickOrInterpolateRightHistogram(h, lastSampleIndex, rangeEnd, smoothed, isCounter, &annos, pos)
if err != nil {
annosFromInterpolationError(&annos, err, metricName, pos)
return enh.Out, annos
}
if !isCounter && (left.CounterResetHint != histogram.GaugeType || right.CounterResetHint != histogram.GaugeType) {
annos.Add(annotations.NewNativeHistogramNotGaugeWarning(metricName, pos))
}
// Copy right so that correctForCounterResetsHistogram can still call
// right.DetectReset without observing mutations from subHistogramWithAnnotations.
resultHistogram := right.Copy()
if !subHistogramWithAnnotations(resultHistogram, left, &annos, metricName, pos) {
return enh.Out, annos
}
if isCounter {
correction, newAnnos, ok := correctForCounterResetsHistogram(h, firstSampleIndex, lastSampleIndex, left, right, rangeStart, smoothed, metricName, pos)
annos.Merge(newAnnos)
if !ok {
return enh.Out, annos
}
if correction != nil && !addHistogramWithAnnotations(resultHistogram, correction, &annos, metricName, pos) {
return enh.Out, annos
}
}
if isRate {
resultHistogram.Div(ms.Range.Seconds())
}
resultHistogram.CounterResetHint = histogram.GaugeType
return append(enh.Out, Sample{H: resultHistogram.Compact(0)}), annos
}
// extrapolatedRate is a utility function for rate/increase/delta.
// It calculates the rate (allowing for counter resets if isCounter is true),
// extrapolates if the first/last sample is close to the boundary, and returns
// the result as either per-second (if isRate is true) or overall.
//
// Note: If the vector selector is smoothed or anchored, it will use the
// extendedRate function instead.
// extendedRate or extendedHistogramRate function instead.
func extrapolatedRate(vals Matrix, args parser.Expressions, enh *EvalNodeHelper, isCounter, isRate bool) (Vector, annotations.Annotations) {
ms := args[0].(*parser.MatrixSelector)
vs := ms.VectorSelector.(*parser.VectorSelector)
if vs.Anchored || vs.Smoothed {
return extendedRate(vals, args, enh, isCounter, isRate)
samples := vals[0]
if len(samples.Histograms) > 0 && len(samples.Floats) > 0 {
var annos annotations.Annotations
return enh.Out, annos.Add(annotations.NewMixedFloatsHistogramsWarning(getMetricName(samples.Metric), args[0].PositionRange()))
}
if len(samples.Histograms) > 0 {
return extendedHistogramRate(vals, args, enh, isCounter, isRate)
}
if len(samples.Floats) > 0 {
return extendedRate(vals, args, enh, isCounter, isRate)
}
// Not enough samples.
return enh.Out, nil
}
var (
@ -1432,6 +1708,16 @@ func funcSqrt(vectorVals []Vector, _ Matrix, _ parser.Expressions, enh *EvalNode
return simpleFloatFunc(vectorVals, enh, math.Sqrt), nil
}
// === max_of(a, b parser.ValueTypeScalar) Scalar ===
func funcMaxOf(vectorVals []Vector, _ Matrix, _ parser.Expressions, enh *EvalNodeHelper) (Vector, annotations.Annotations) {
return append(enh.Out, Sample{F: math.Max(vectorVals[0][0].F, vectorVals[1][0].F)}), nil
}
// === min_of(a, b parser.ValueTypeScalar) Scalar ===
func funcMinOf(vectorVals []Vector, _ Matrix, _ parser.Expressions, enh *EvalNodeHelper) (Vector, annotations.Annotations) {
return append(enh.Out, Sample{F: math.Min(vectorVals[0][0].F, vectorVals[1][0].F)}), nil
}
// === ln(Vector parser.ValueTypeVector) (Vector, Annotations) ===
func funcLn(vectorVals []Vector, _ Matrix, _ parser.Expressions, enh *EvalNodeHelper) (Vector, annotations.Annotations) {
return simpleFloatFunc(vectorVals, enh, math.Log), nil
@ -1957,41 +2243,61 @@ func funcResets(_ []Vector, matrixVal Matrix, args parser.Expressions, enh *Eval
return enh.Out, nil
}
var prevSample, curSample Sample
var (
prevSample, curSample Sample
prevST int64
floatSTs, histogramSTs []int64
)
if sts := enh.StartTimestamps; sts != nil {
floatSTs = sts.Floats
histogramSTs = sts.Histograms
}
firstSampleIndex, found := pickFirstSampleIndex(floats, args, enh)
if !found {
return enh.Out, nil
}
for iFloat, iHistogram := firstSampleIndex, 0; iFloat < len(floats) || iHistogram < len(histograms); {
var curST int64
switch {
// Process a float sample if no histogram sample remains or its timestamp is earlier.
// Process a histogram sample if no float sample remains or its timestamp is earlier.
case iHistogram >= len(histograms) || iFloat < len(floats) && floats[iFloat].T < histograms[iHistogram].T:
curSample.T = floats[iFloat].T
curSample.F = floats[iFloat].F
curSample.H = nil
if iFloat < len(floatSTs) {
curST = floatSTs[iFloat]
}
iFloat++
case iFloat >= len(floats) || iHistogram < len(histograms) && floats[iFloat].T > histograms[iHistogram].T:
curSample.T = histograms[iHistogram].T
curSample.H = histograms[iHistogram].H
if iHistogram < len(histogramSTs) {
curST = histogramSTs[iHistogram]
}
iHistogram++
}
// Skip the comparison for the first sample, just initialize prevSample.
if iFloat+iHistogram == 1+firstSampleIndex {
prevSample = curSample
prevST = curST
continue
}
switch {
case prevSample.H == nil && curSample.H == nil:
if curSample.F < prevSample.F {
if curSample.F < prevSample.F || isStartTimestampReset(prevST, prevSample.T, curST, curSample.T) {
resets++
}
case prevSample.H != nil && curSample.H == nil, prevSample.H == nil && curSample.H != nil:
resets++
case prevSample.H != nil && curSample.H != nil:
if curSample.H.DetectReset(prevSample.H) {
if isStartTimestampReset(prevST, prevSample.T, curST, curSample.T) || curSample.H.DetectReset(prevSample.H) {
resets++
}
}
prevSample = curSample
prevST = curST
}
return append(enh.Out, Sample{F: float64(resets)}), nil
@ -2249,7 +2555,7 @@ var FunctionCalls = map[string]FunctionCall{
"day_of_week": funcDayOfWeek,
"day_of_year": funcDayOfYear,
"deg": funcDeg,
"end": funcQueryContext,
"end": nil, // Folded into NumberLiteral by foldQueryContextFunctions.
"delta": funcDelta,
"deriv": funcDeriv,
"exp": funcExp,
@ -2269,8 +2575,10 @@ var FunctionCalls = map[string]FunctionCall{
"increase": funcIncrease,
"info": nil,
"irate": funcIrate,
"max_of": funcMaxOf,
"label_replace": nil, // evalLabelReplace not called via this map.
"label_join": nil, // evalLabelJoin not called via this map.
"min_of": funcMinOf,
"ln": funcLn,
"log10": funcLog10,
"log2": funcLog2,
@ -2289,7 +2597,7 @@ var FunctionCalls = map[string]FunctionCall{
"present_over_time": funcPresentOverTime,
"quantile_over_time": funcQuantileOverTime,
"rad": funcRad,
"range": funcQueryContext,
"range": nil, // Folded into NumberLiteral by foldQueryContextFunctions.
"rate": funcRate,
"resets": funcResets,
"round": funcRound,
@ -2301,8 +2609,8 @@ var FunctionCalls = map[string]FunctionCall{
"sort_desc": funcSortDesc,
"sort_by_label": funcSortByLabel,
"sort_by_label_desc": funcSortByLabelDesc,
"start": funcQueryContext,
"step": funcQueryContext,
"start": nil, // Folded into NumberLiteral by foldQueryContextFunctions.
"step": nil, // Folded into NumberLiteral by foldQueryContextFunctions.
"sqrt": funcSqrt,
"stddev_over_time": funcStddevOverTime,
"stdvar_over_time": funcStdvarOverTime,

View file

@ -24,6 +24,7 @@ import (
"github.com/prometheus/prometheus/model/histogram"
"github.com/prometheus/prometheus/model/labels"
"github.com/prometheus/prometheus/promql/parser/posrange"
"github.com/prometheus/prometheus/util/annotations"
"github.com/prometheus/prometheus/util/kahansum"
)
@ -119,3 +120,59 @@ func TestInterpolate(t *testing.T) {
require.Equal(t, test.expected, result)
}
}
func TestInterpolateHistograms(t *testing.T) {
h1 := &histogram.FloatHistogram{Count: 1, Sum: 1, CounterResetHint: histogram.UnknownCounterReset}
h2 := &histogram.FloatHistogram{Count: 3, Sum: 3, CounterResetHint: histogram.UnknownCounterReset}
h2Reset := &histogram.FloatHistogram{Count: 1, Sum: 1, CounterResetHint: histogram.CounterReset}
pos := posrange.PositionRange{}
tests := []struct {
name string
h1, h2 *histogram.FloatHistogram
t1, t2, t int64
isCounter bool
wantCount float64
}{
{
name: "exact match t1",
h1: h1, h2: h2, t1: 0, t2: 20, t: 0,
isCounter: false, wantCount: 1,
},
{
name: "exact match t2",
h1: h1, h2: h2, t1: 0, t2: 20, t: 20,
isCounter: false, wantCount: 3,
},
{
name: "midpoint no reset",
h1: h1, h2: h2, t1: 0, t2: 20, t: 10,
isCounter: false, wantCount: 2,
},
{
name: "counter midpoint no reset",
h1: h1, h2: h2, t1: 0, t2: 20, t: 10,
isCounter: true, wantCount: 2,
},
{
name: "counter midpoint with reset: scale from zero",
h1: h1, h2: h2Reset, t1: 0, t2: 20, t: 10,
// h2Reset * (10/20) = count:1 * 0.5 = 0.5.
isCounter: true, wantCount: 0.5,
},
{
name: "quarter point",
h1: h1, h2: h2, t1: 0, t2: 20, t: 5,
// h1 + (h2-h1)*0.25 = 1 + 2*0.25 = 1.5.
isCounter: false, wantCount: 1.5,
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
var annos annotations.Annotations
result, err := interpolateHistograms(tc.h1, tc.t1, tc.h2, tc.t2, tc.t, tc.isCounter, &annos, pos)
require.NoError(t, err)
require.Equal(t, tc.wantCount, result.Count)
})
}
}

View file

@ -86,10 +86,14 @@ func (*HistogramStatsIterator) AtHistogram(*histogram.Histogram) (int64, *histog
// performs a counter reset detection on the fly. It will return an explicit
// hint (not UnknownCounterReset) if the previous sample has been accessed with
// the same iterator.
//
// The returned histogram contains only Count, Sum, CounterResetHint, and Schema.
// Bucket data is intentionally omitted.
func (hsi *HistogramStatsIterator) AtFloatHistogram(fh *histogram.FloatHistogram) (int64, *histogram.FloatHistogram) {
populateFH := func(src *histogram.FloatHistogram, detectReset bool) {
h := histogram.FloatHistogram{
CounterResetHint: src.CounterResetHint,
Schema: src.Schema,
Count: src.Count,
Sum: src.Sum,
}

View file

@ -487,7 +487,7 @@ func (e *BinaryExpr) PositionRange() posrange.PositionRange {
}
func (e *DurationExpr) PositionRange() posrange.PositionRange {
if e.Op == STEP || e.Op == RANGE {
if e.RHS == nil && e.LHS == nil {
return posrange.PositionRange{
Start: e.StartPos,
End: e.EndPos,
@ -496,7 +496,7 @@ func (e *DurationExpr) PositionRange() posrange.PositionRange {
if e.RHS == nil {
return posrange.PositionRange{
Start: e.StartPos,
End: e.RHS.PositionRange().End,
End: e.LHS.PositionRange().End,
}
}
if e.LHS == nil {

View file

@ -53,6 +53,6 @@ func (pql *promQLParser) RegisterFeatures(r features.Collector) {
r.Set(features.PromQLFunctions, f, !fc.Experimental || pql.options.EnableExperimentalFunctions)
}
// Register parser features.
r.Enable(features.PromQL, "duration_expr")
// Register experimental parser features.
r.Set(features.PromQL, "duration_expr", pql.options.ExperimentalDurationExpr)
}

View file

@ -263,11 +263,23 @@ var Functions = map[string]*Function{
Variadic: -1,
ReturnType: ValueTypeVector,
},
"max_of": {
Name: "max_of",
ArgTypes: []ValueType{ValueTypeScalar, ValueTypeScalar},
ReturnType: ValueTypeScalar,
Experimental: true,
},
"last_over_time": {
Name: "last_over_time",
ArgTypes: []ValueType{ValueTypeMatrix},
ReturnType: ValueTypeVector,
},
"min_of": {
Name: "min_of",
ArgTypes: []ValueType{ValueTypeScalar, ValueTypeScalar},
ReturnType: ValueTypeScalar,
Experimental: true,
},
"ln": {
Name: "ln",
ArgTypes: []ValueType{ValueTypeVector},

View file

@ -159,6 +159,8 @@ START
END
STEP
RANGE
MAX_OF
MIN_OF
%token preprocessorEnd
// Counter reset hints.
@ -183,7 +185,7 @@ START_METRIC_SELECTOR
// Type definitions for grammar rules.
%type <matchers> label_match_list
%type <matcher> label_matcher
%type <item> aggregate_op grouping_label match_op maybe_label metric_identifier unary_op at_modifier_preprocessors string_identifier counter_reset_hint min_max
%type <item> aggregate_op grouping_label match_op maybe_label metric_identifier unary_op at_modifier_preprocessors string_identifier counter_reset_hint max_of_min_of
%type <labels> label_set metric
%type <lblList> label_set_list
%type <label> label_set_item
@ -526,6 +528,24 @@ function_call : IDENTIFIER function_call_body
},
}
}
| max_of_min_of function_call_body
{
fn, exist := getFunction($1.Val, yylex.(*parser).functions)
if !exist{
yylex.(*parser).addParseErrf($1.PositionRange(),"unknown function with name %q", $1.Val)
}
if fn != nil && fn.Experimental && !yylex.(*parser).options.EnableExperimentalFunctions {
yylex.(*parser).addParseErrf($1.PositionRange(),"function %q is not enabled", $1.Val)
}
$$ = &Call{
Func: fn,
Args: $2.(Expressions),
PosRange: posrange.PositionRange{
Start: $1.PositionRange().Start,
End: yylex.(*parser).lastClosing,
},
}
}
;
function_call_body: LEFT_PAREN function_call_args RIGHT_PAREN
@ -814,7 +834,7 @@ metric : metric_identifier label_set
;
metric_identifier: AVG | BOTTOMK | BY | COUNT | COUNT_VALUES | FILL | FILL_LEFT | FILL_RIGHT | GROUP | IDENTIFIER | LAND | LOR | LUNLESS | MAX | METRIC_IDENTIFIER | MIN | OFFSET | QUANTILE | STDDEV | STDVAR | SUM | TOPK | WITHOUT | START | END | LIMITK | LIMIT_RATIO | STEP | RANGE | ANCHORED | SMOOTHED;
metric_identifier: AVG | BOTTOMK | BY | COUNT | COUNT_VALUES | FILL | FILL_LEFT | FILL_RIGHT | GROUP | IDENTIFIER | LAND | LOR | LUNLESS | MAX | METRIC_IDENTIFIER | MIN | OFFSET | QUANTILE | STDDEV | STDVAR | SUM | TOPK | WITHOUT | START | END | LIMITK | LIMIT_RATIO | STEP | RANGE | ANCHORED | SMOOTHED | MAX_OF | MIN_OF;
label_set : LEFT_BRACE label_set_list RIGHT_BRACE
{ $$ = labels.New($2...) }
@ -1072,7 +1092,7 @@ counter_reset_hint : UNKNOWN_COUNTER_RESET | COUNTER_RESET | NOT_COUNTER_RESET |
aggregate_op : AVG | BOTTOMK | COUNT | COUNT_VALUES | GROUP | MAX | MIN | QUANTILE | STDDEV | STDVAR | SUM | TOPK | LIMITK | LIMIT_RATIO;
// Inside of grouping options label names can be recognized as keywords by the lexer. This is a list of keywords that could also be a label name.
maybe_label : AVG | BOOL | BOTTOMK | BY | COUNT | COUNT_VALUES | GROUP | GROUP_LEFT | GROUP_RIGHT | FILL | FILL_LEFT | FILL_RIGHT | IDENTIFIER | IGNORING | LAND | LOR | LUNLESS | MAX | METRIC_IDENTIFIER | MIN | OFFSET | ON | QUANTILE | STDDEV | STDVAR | SUM | TOPK | START | END | ATAN2 | LIMITK | LIMIT_RATIO | STEP | RANGE | ANCHORED | SMOOTHED;
maybe_label : AVG | BOOL | BOTTOMK | BY | COUNT | COUNT_VALUES | GROUP | GROUP_LEFT | GROUP_RIGHT | FILL | FILL_LEFT | FILL_RIGHT | IDENTIFIER | IGNORING | LAND | LOR | LUNLESS | MAX | METRIC_IDENTIFIER | MIN | OFFSET | ON | QUANTILE | STDDEV | STDVAR | SUM | TOPK | START | END | ATAN2 | LIMITK | LIMIT_RATIO | STEP | RANGE | ANCHORED | SMOOTHED | MAX_OF | MIN_OF;
unary_op : ADD | SUB;
@ -1178,7 +1198,7 @@ maybe_grouping_labels: /* empty */ { $$ = nil }
offset_duration_expr : number_duration_literal
{
nl := $1.(*NumberLiteral)
if nl.Val > 1<<63/1e9 || nl.Val < -(1<<63)/1e9 {
if durationLiteralOutOfRange(nl.Val) {
yylex.(*parser).addParseErrf(nl.PosRange, "duration out of range")
$$ = &NumberLiteral{Val: 0}
break
@ -1191,7 +1211,7 @@ offset_duration_expr : number_duration_literal
if $1.Typ == SUB {
nl.Val *= -1
}
if nl.Val > 1<<63/1e9 || nl.Val < -(1<<63)/1e9 {
if durationLiteralOutOfRange(nl.Val) {
yylex.(*parser).addParseErrf($1.PositionRange(), "duration out of range")
$$ = &NumberLiteral{Val: 0}
break
@ -1201,23 +1221,27 @@ offset_duration_expr : number_duration_literal
}
| STEP LEFT_PAREN RIGHT_PAREN
{
$$ = &DurationExpr{
Op: STEP,
de := &DurationExpr{
Op: STEP,
StartPos: $1.PositionRange().Start,
EndPos: $3.PositionRange().End,
EndPos: $3.PositionRange().End,
}
yylex.(*parser).experimentalDurationExpr(de)
$$ = de
}
| RANGE LEFT_PAREN RIGHT_PAREN
{
$$ = &DurationExpr{
Op: RANGE,
de := &DurationExpr{
Op: RANGE,
StartPos: $1.PositionRange().Start,
EndPos: $3.PositionRange().End,
EndPos: $3.PositionRange().End,
}
yylex.(*parser).experimentalDurationExpr(de)
$$ = de
}
| unary_op STEP LEFT_PAREN RIGHT_PAREN
{
$$ = &DurationExpr{
de := &DurationExpr{
Op: $1.Typ,
RHS: &DurationExpr{
Op: STEP,
@ -1226,10 +1250,12 @@ offset_duration_expr : number_duration_literal
},
StartPos: $1.Pos,
}
yylex.(*parser).experimentalDurationExpr(de)
$$ = de
}
| unary_op RANGE LEFT_PAREN RIGHT_PAREN
{
$$ = &DurationExpr{
de := &DurationExpr{
Op: $1.Typ,
RHS: &DurationExpr{
Op: RANGE,
@ -1238,20 +1264,24 @@ offset_duration_expr : number_duration_literal
},
StartPos: $1.Pos,
}
yylex.(*parser).experimentalDurationExpr(de)
$$ = de
}
| min_max LEFT_PAREN duration_expr COMMA duration_expr RIGHT_PAREN
| max_of_min_of LEFT_PAREN duration_expr COMMA duration_expr RIGHT_PAREN
{
$$ = &DurationExpr{
de := &DurationExpr{
Op: $1.Typ,
StartPos: $1.PositionRange().Start,
EndPos: $6.PositionRange().End,
LHS: $3.(Expr),
RHS: $5.(Expr),
}
yylex.(*parser).experimentalDurationExpr(de)
$$ = de
}
| unary_op min_max LEFT_PAREN duration_expr COMMA duration_expr RIGHT_PAREN
| unary_op max_of_min_of LEFT_PAREN duration_expr COMMA duration_expr RIGHT_PAREN
{
$$ = &DurationExpr{
de := &DurationExpr{
Op: $1.Typ,
StartPos: $1.Pos,
EndPos: $6.PositionRange().End,
@ -1263,30 +1293,22 @@ offset_duration_expr : number_duration_literal
RHS: $6.(Expr),
},
}
yylex.(*parser).experimentalDurationExpr(de)
$$ = de
}
| unary_op LEFT_PAREN duration_expr RIGHT_PAREN %prec MUL
{
de := $3.(*DurationExpr)
de.Wrapped = true
if $1.Typ == SUB {
$$ = &DurationExpr{
Op: SUB,
RHS: de,
StartPos: $1.Pos,
}
break
}
$$ = $3
$$ = yylex.(*parser).applyUnaryOpToDurationExpr($1, $3.(Node), true)
}
| duration_expr
;
min_max: MIN | MAX ;
max_of_min_of: MAX_OF | MIN_OF ;
duration_expr : number_duration_literal
{
nl := $1.(*NumberLiteral)
if nl.Val > 1<<63/1e9 || nl.Val < -(1<<63)/1e9 {
if durationLiteralOutOfRange(nl.Val) {
yylex.(*parser).addParseErrf(nl.PosRange, "duration out of range")
$$ = &NumberLiteral{Val: 0}
break
@ -1295,50 +1317,26 @@ duration_expr : number_duration_literal
}
| unary_op duration_expr %prec MUL
{
switch expr := $2.(type) {
case *NumberLiteral:
if $1.Typ == SUB {
expr.Val *= -1
}
if expr.Val > 1<<63/1e9 || expr.Val < -(1<<63)/1e9 {
yylex.(*parser).addParseErrf($1.PositionRange(), "duration out of range")
$$ = &NumberLiteral{Val: 0}
break
}
expr.PosRange.Start = $1.Pos
$$ = expr
break
case *DurationExpr:
if $1.Typ == SUB {
$$ = &DurationExpr{
Op: SUB,
RHS: expr,
StartPos: $1.Pos,
}
break
}
$$ = expr
break
default:
yylex.(*parser).addParseErrf($1.PositionRange(), "expected number literal or duration expression")
$$ = &NumberLiteral{Val: 0}
break
$$ = yylex.(*parser).applyUnaryOpToDurationExpr($1, $2.(Node), false)
}
}
| duration_expr ADD duration_expr
{
yylex.(*parser).experimentalDurationExpr($1.(Expr))
$$ = &DurationExpr{Op: ADD, LHS: $1.(Expr), RHS: $3.(Expr)}
}
| duration_expr SUB duration_expr
{
yylex.(*parser).experimentalDurationExpr($1.(Expr))
$$ = &DurationExpr{Op: SUB, LHS: $1.(Expr), RHS: $3.(Expr)}
}
| duration_expr MUL duration_expr
{
yylex.(*parser).experimentalDurationExpr($1.(Expr))
$$ = &DurationExpr{Op: MUL, LHS: $1.(Expr), RHS: $3.(Expr)}
}
| duration_expr DIV duration_expr
{
yylex.(*parser).experimentalDurationExpr($1.(Expr))
if nl, ok := $3.(*NumberLiteral); ok && nl.Val == 0 {
yylex.(*parser).addParseErrf($2.PositionRange(), "division by zero")
$$ = &NumberLiteral{Val: 0}
@ -1348,6 +1346,7 @@ duration_expr : number_duration_literal
}
| duration_expr MOD duration_expr
{
yylex.(*parser).experimentalDurationExpr($1.(Expr))
if nl, ok := $3.(*NumberLiteral); ok && nl.Val == 0 {
yylex.(*parser).addParseErrf($2.PositionRange(), "modulo by zero")
$$ = &NumberLiteral{Val: 0}
@ -1357,39 +1356,47 @@ duration_expr : number_duration_literal
}
| duration_expr POW duration_expr
{
yylex.(*parser).experimentalDurationExpr($1.(Expr))
$$ = &DurationExpr{Op: POW, LHS: $1.(Expr), RHS: $3.(Expr)}
}
| STEP LEFT_PAREN RIGHT_PAREN
{
$$ = &DurationExpr{
de := &DurationExpr{
Op: STEP,
StartPos: $1.PositionRange().Start,
EndPos: $3.PositionRange().End,
}
yylex.(*parser).experimentalDurationExpr(de)
$$ = de
}
| RANGE LEFT_PAREN RIGHT_PAREN
{
$$ = &DurationExpr{
de := &DurationExpr{
Op: RANGE,
StartPos: $1.PositionRange().Start,
EndPos: $3.PositionRange().End,
}
yylex.(*parser).experimentalDurationExpr(de)
$$ = de
}
| min_max LEFT_PAREN duration_expr COMMA duration_expr RIGHT_PAREN
| max_of_min_of LEFT_PAREN duration_expr COMMA duration_expr RIGHT_PAREN
{
$$ = &DurationExpr{
de := &DurationExpr{
Op: $1.Typ,
StartPos: $1.PositionRange().Start,
EndPos: $6.PositionRange().End,
LHS: $3.(Expr),
RHS: $5.(Expr),
}
yylex.(*parser).experimentalDurationExpr(de)
$$ = de
}
| paren_duration_expr
;
paren_duration_expr : LEFT_PAREN duration_expr RIGHT_PAREN
{
yylex.(*parser).experimentalDurationExpr($2.(Expr))
if durationExpr, ok := $2.(*DurationExpr); ok {
durationExpr.Wrapped = true
$$ = durationExpr

File diff suppressed because it is too large Load diff

View file

@ -143,10 +143,12 @@ var key = map[string]ItemType{
"bool": BOOL,
// Preprocessors.
"start": START,
"end": END,
"step": STEP,
"range": RANGE,
"start": START,
"end": END,
"step": STEP,
"range": RANGE,
"max_of": MAX_OF,
"min_of": MIN_OF,
}
var histogramDesc = map[string]ItemType{
@ -499,15 +501,15 @@ func lexStatements(l *Lexer) stateFn {
l.backup()
return lexKeywordOrIdentifier
}
switch r {
case ':':
switch {
case r == ':':
if l.gotColon {
return l.errorf("unexpected colon %q", r)
}
l.emit(COLON)
l.gotColon = true
return lexStatements
case 's', 'S', 'm', 'M':
case isDurationKeywordStartChar(r):
if l.scanDurationKeyword() {
return lexStatements
}
@ -935,6 +937,32 @@ func lexNumber(l *Lexer) stateFn {
return lexStatements
}
// durationKeywordTokens maps lowercase duration keyword names to their token types.
var durationKeywordTokens = map[string]ItemType{
"step": STEP,
"range": RANGE,
"max_of": MAX_OF,
"min_of": MIN_OF,
}
// durationKeywordStartChars is the set of lowercase runes that can start a duration keyword,
// derived from durationKeywordTokens.
var durationKeywordStartChars = makeDurationKeywordStartChars()
func makeDurationKeywordStartChars() map[rune]struct{} {
m := make(map[rune]struct{}, len(durationKeywordTokens))
for kw := range durationKeywordTokens {
m[rune(kw[0])] = struct{}{}
}
return m
}
// isDurationKeywordStartChar reports whether r can be the first character of a duration keyword.
func isDurationKeywordStartChar(r rune) bool {
_, ok := durationKeywordStartChars[unicode.ToLower(r)]
return ok
}
func (l *Lexer) scanDurationKeyword() bool {
for {
switch r := l.next(); {
@ -942,24 +970,12 @@ func (l *Lexer) scanDurationKeyword() bool {
// absorb.
default:
l.backup()
word := l.input[l.start:l.pos]
kw := strings.ToLower(word)
switch kw {
case "step":
l.emit(STEP)
word := strings.ToLower(l.input[l.start:l.pos])
if tok, ok := durationKeywordTokens[word]; ok {
l.emit(tok)
return true
case "range":
l.emit(RANGE)
return true
case "min":
l.emit(MIN)
return true
case "max":
l.emit(MAX)
return true
default:
return false
}
return false
}
}
}
@ -1239,7 +1255,7 @@ func lexDurationExpr(l *Lexer) stateFn {
case r == ',':
l.emit(COMMA)
return lexDurationExpr
case r == 's' || r == 'S' || r == 'm' || r == 'M' || r == 'r' || r == 'R':
case isDurationKeywordStartChar(r):
if l.scanDurationKeyword() {
return lexDurationExpr
}

View file

@ -43,6 +43,7 @@ var parserPool = sync.Pool{
// Options holds the configuration for the PromQL parser.
type Options struct {
EnableExperimentalFunctions bool
ExperimentalDurationExpr bool
EnableExtendedRangeSelectors bool
EnableBinopFillModifiers bool
}
@ -336,7 +337,8 @@ func (p *parser) unexpected(context, expected string) {
p.addParseErr(p.yyParser.lval.item.PositionRange(), errors.New(errMsg.String()))
}
var errUnexpected = errors.New("unexpected error")
// ErrUnexpected is returned when the parser recovers from a runtime panic.
var ErrUnexpected = errors.New("unexpected error")
// recover is the handler that turns panics into returns from the top level of Parse.
func (*parser) recover(errp *error) {
@ -348,7 +350,7 @@ func (*parser) recover(errp *error) {
buf = buf[:runtime.Stack(buf, false)]
fmt.Fprintf(os.Stderr, "parser panic: %v\n%s", e, buf)
*errp = errUnexpected
*errp = ErrUnexpected
case e != nil:
*errp = e.(error)
}
@ -1085,8 +1087,12 @@ func (p *parser) setAnchored(e Node) {
p.addParseErrf(e.PositionRange(), "anchored and smoothed modifiers cannot be used together")
}
case *MatrixSelector:
s.VectorSelector.(*VectorSelector).Anchored = true
if s.VectorSelector.(*VectorSelector).Smoothed {
vs, ok := s.VectorSelector.(*VectorSelector)
if !ok {
return
}
vs.Anchored = true
if vs.Smoothed {
p.addParseErrf(e.PositionRange(), "anchored and smoothed modifiers cannot be used together")
}
case *SubqueryExpr:
@ -1108,8 +1114,12 @@ func (p *parser) setSmoothed(e Node) {
p.addParseErrf(e.PositionRange(), "anchored and smoothed modifiers cannot be used together")
}
case *MatrixSelector:
s.VectorSelector.(*VectorSelector).Smoothed = true
if s.VectorSelector.(*VectorSelector).Anchored {
vs, ok := s.VectorSelector.(*VectorSelector)
if !ok {
return
}
vs.Smoothed = true
if vs.Anchored {
p.addParseErrf(e.PositionRange(), "anchored and smoothed modifiers cannot be used together")
}
case *SubqueryExpr:
@ -1192,6 +1202,51 @@ func (p *parser) getAtModifierVars(e Node) (**int64, *ItemType, *posrange.Pos, b
return timestampp, preprocp, endPosp, true
}
// durationLiteralOutOfRange reports whether val, interpreted as seconds, would
// overflow a time.Duration (int64 nanoseconds).
func durationLiteralOutOfRange(val float64) bool {
return val > 1<<63/1e9 || val < -(1<<63)/1e9
}
func (p *parser) experimentalDurationExpr(e Expr) {
if !p.options.ExperimentalDurationExpr {
p.addParseErrf(e.PositionRange(), "experimental duration expression is not enabled")
}
}
// applyUnaryOpToDurationExpr applies a unary operator to a duration expression
// node, which may be a *DurationExpr or a *NumberLiteral. When wrapped is true
// (parenthesised form), the Wrapped flag is set on *DurationExpr nodes.
func (p *parser) applyUnaryOpToDurationExpr(op Item, expr Node, wrapped bool) Node {
switch e := expr.(type) {
case *DurationExpr:
if wrapped {
e.Wrapped = true
}
if op.Typ == SUB {
return &DurationExpr{
Op: SUB,
RHS: e,
StartPos: op.Pos,
}
}
return e
case *NumberLiteral:
if op.Typ == SUB {
e.Val *= -1
}
if durationLiteralOutOfRange(e.Val) {
p.addParseErrf(op.PositionRange(), "duration out of range")
return &NumberLiteral{Val: 0}
}
e.PosRange.Start = op.Pos
return e
default:
p.addParseErrf(op.PositionRange(), "expected number literal or duration expression")
return &NumberLiteral{Val: 0}
}
}
func MustLabelMatcher(mt labels.MatchType, name, val string) *labels.Matcher {
m, err := labels.NewMatcher(mt, name, val)
if err != nil {

View file

@ -1713,6 +1713,28 @@ var testExpr = []struct {
PosRange: posrange.PositionRange{Start: 0, End: 14},
},
},
{
input: "foo offset +(5)",
expected: &VectorSelector{
Name: "foo",
OriginalOffset: 5 * time.Second,
LabelMatchers: []*labels.Matcher{
MustLabelMatcher(labels.MatchEqual, model.MetricNameLabel, "foo"),
},
PosRange: posrange.PositionRange{Start: 0, End: 15},
},
},
{
input: "foo offset -(5)",
expected: &VectorSelector{
Name: "foo",
OriginalOffset: -5 * time.Second,
LabelMatchers: []*labels.Matcher{
MustLabelMatcher(labels.MatchEqual, model.MetricNameLabel, "foo"),
},
PosRange: posrange.PositionRange{Start: 0, End: 15},
},
},
{
input: `http_requests{group="production"} + on(instance) group_left(job,instance) cpu_count{type="smp"}`,
fail: true,
@ -4610,7 +4632,7 @@ var testExpr = []struct {
},
},
{
input: `foo[max(step(),5s)]`,
input: `foo[max_of(step(),5s)]`,
expected: &MatrixSelector{
VectorSelector: &VectorSelector{
Name: "foo",
@ -4620,83 +4642,83 @@ var testExpr = []struct {
PosRange: posrange.PositionRange{Start: 0, End: 3},
},
RangeExpr: &DurationExpr{
Op: MAX,
Op: MAX_OF,
LHS: &DurationExpr{
Op: STEP,
StartPos: 8,
EndPos: 14,
StartPos: 11,
EndPos: 17,
},
RHS: &NumberLiteral{
Val: 5,
Duration: true,
PosRange: posrange.PositionRange{Start: 15, End: 17},
PosRange: posrange.PositionRange{Start: 18, End: 20},
},
StartPos: 4,
EndPos: 18,
EndPos: 21,
},
EndPos: 19,
EndPos: 22,
},
},
{
input: `foo offset max(step(),5s)`,
input: `foo offset max_of(step(),5s)`,
expected: &VectorSelector{
Name: "foo",
LabelMatchers: []*labels.Matcher{
MustLabelMatcher(labels.MatchEqual, model.MetricNameLabel, "foo"),
},
PosRange: posrange.PositionRange{Start: 0, End: 25},
PosRange: posrange.PositionRange{Start: 0, End: 28},
OriginalOffsetExpr: &DurationExpr{
Op: MAX,
Op: MAX_OF,
LHS: &DurationExpr{
Op: STEP,
StartPos: 15,
EndPos: 21,
StartPos: 18,
EndPos: 24,
},
RHS: &NumberLiteral{
Val: 5,
Duration: true,
PosRange: posrange.PositionRange{Start: 22, End: 24},
PosRange: posrange.PositionRange{Start: 25, End: 27},
},
StartPos: 11,
EndPos: 25,
EndPos: 28,
},
},
},
{
input: `foo offset -min(5s,step()+8s)`,
input: `foo offset -min_of(5s,step()+8s)`,
expected: &VectorSelector{
Name: "foo",
LabelMatchers: []*labels.Matcher{
MustLabelMatcher(labels.MatchEqual, model.MetricNameLabel, "foo"),
},
PosRange: posrange.PositionRange{Start: 0, End: 29},
PosRange: posrange.PositionRange{Start: 0, End: 32},
OriginalOffsetExpr: &DurationExpr{
Op: SUB,
RHS: &DurationExpr{
Op: MIN,
Op: MIN_OF,
LHS: &NumberLiteral{
Val: 5,
Duration: true,
PosRange: posrange.PositionRange{Start: 16, End: 18},
PosRange: posrange.PositionRange{Start: 19, End: 21},
},
RHS: &DurationExpr{
Op: ADD,
LHS: &DurationExpr{
Op: STEP,
StartPos: 19,
EndPos: 25,
StartPos: 22,
EndPos: 28,
},
RHS: &NumberLiteral{
Val: 8,
Duration: true,
PosRange: posrange.PositionRange{Start: 26, End: 28},
PosRange: posrange.PositionRange{Start: 29, End: 31},
},
},
StartPos: 12,
EndPos: 28,
EndPos: 31,
},
StartPos: 11,
EndPos: 28,
EndPos: 31,
},
},
},
@ -4718,6 +4740,32 @@ var testExpr = []struct {
EndPos: 12,
},
},
{
input: `foo[2m/range()]`,
expected: &MatrixSelector{
VectorSelector: &VectorSelector{
Name: "foo",
LabelMatchers: []*labels.Matcher{
MustLabelMatcher(labels.MatchEqual, model.MetricNameLabel, "foo"),
},
PosRange: posrange.PositionRange{Start: 0, End: 3},
},
RangeExpr: &DurationExpr{
Op: DIV,
LHS: &NumberLiteral{
Val: 120,
Duration: true,
PosRange: posrange.PositionRange{Start: 4, End: 6},
},
RHS: &DurationExpr{
Op: RANGE,
StartPos: 7,
EndPos: 14,
},
},
EndPos: 15,
},
},
{
input: `foo[-range()]`,
expected: &MatrixSelector{
@ -4767,7 +4815,7 @@ var testExpr = []struct {
},
},
{
input: `foo[max(range(),5s)]`,
input: `foo[max_of(range(),5s)]`,
expected: &MatrixSelector{
VectorSelector: &VectorSelector{
Name: "foo",
@ -4777,21 +4825,21 @@ var testExpr = []struct {
PosRange: posrange.PositionRange{Start: 0, End: 3},
},
RangeExpr: &DurationExpr{
Op: MAX,
Op: MAX_OF,
LHS: &DurationExpr{
Op: RANGE,
StartPos: 8,
EndPos: 15,
StartPos: 11,
EndPos: 18,
},
RHS: &NumberLiteral{
Val: 5,
Duration: true,
PosRange: posrange.PositionRange{Start: 16, End: 18},
PosRange: posrange.PositionRange{Start: 19, End: 21},
},
StartPos: 4,
EndPos: 19,
EndPos: 22,
},
EndPos: 20,
EndPos: 23,
},
},
{
@ -5282,6 +5330,29 @@ var testExpr = []struct {
},
},
},
// Anchored/smoothed on non-selector range must not panic.
{
input: "1[5m] smoothed",
fail: true,
errors: ParseErrors{
{
PositionRange: posrange.PositionRange{Start: 1, End: 5},
Err: errors.New("ranges only allowed for vector selectors"),
Query: "1[5m] smoothed",
},
},
},
{
input: "1[5m] anchored",
fail: true,
errors: ParseErrors{
{
PositionRange: posrange.PositionRange{Start: 1, End: 5},
Err: errors.New("ranges only allowed for vector selectors"),
Query: "1[5m] anchored",
},
},
},
}
func makeInt64Pointer(val int64) *int64 {
@ -5300,7 +5371,9 @@ func readable(s string) string {
func TestParseExpressions(t *testing.T) {
optsParser := NewParser(Options{
EnableExperimentalFunctions: true,
EnableExperimentalFunctions: true,
ExperimentalDurationExpr: true,
EnableExtendedRangeSelectors: true,
})
for _, test := range testExpr {
@ -5308,7 +5381,7 @@ func TestParseExpressions(t *testing.T) {
expr, err := optsParser.ParseExpr(test.input)
// Unexpected errors are always caused by a bug.
require.NotEqual(t, err, errUnexpected, "unexpected error occurred")
require.NotEqual(t, err, ErrUnexpected, "unexpected error occurred")
if !test.fail {
require.NoError(t, err)
@ -5962,7 +6035,7 @@ func TestParseSeries(t *testing.T) {
metric, vals, err := testParser.ParseSeriesDesc(test.input)
// Unexpected errors are always caused by a bug.
require.NotEqual(t, err, errUnexpected, "unexpected error occurred")
require.NotEqual(t, err, ErrUnexpected, "unexpected error occurred")
if !test.fail {
require.NoError(t, err)
@ -5979,7 +6052,7 @@ func TestRecoverParserRuntime(t *testing.T) {
var err error
defer func() {
require.Equal(t, errUnexpected, err)
require.Equal(t, ErrUnexpected, err)
}()
defer p.recover(&err)
// Cause a runtime panic.
@ -6057,6 +6130,7 @@ func TestParseCustomFunctions(t *testing.T) {
func TestNewParser(t *testing.T) {
p := NewParser(Options{
EnableExperimentalFunctions: true,
ExperimentalDurationExpr: true,
})
// ParseExpr should work.

View file

@ -81,8 +81,6 @@ func (e *BinaryExpr) Pretty(level int) string {
func (e *DurationExpr) Pretty(int) string {
var s string
fmt.Println("e.LHS", e.LHS)
fmt.Println("e.RHS", e.RHS)
if e.LHS == nil {
// This is a unary duration expression.
s = fmt.Sprintf("%s%s", e.Op, e.RHS.Pretty(0))

View file

@ -670,7 +670,7 @@ func TestUnaryPretty(t *testing.T) {
}
func TestDurationExprPretty(t *testing.T) {
optsParser := NewParser(Options{})
optsParser := NewParser(Options{ExperimentalDurationExpr: true})
maxCharactersPerLine = 10
inputs := []struct {
in, out string

View file

@ -174,7 +174,7 @@ func (node *BinaryExpr) getMatchingStr() string {
}
if vm.FillValues.LHS != nil || vm.FillValues.RHS != nil {
if vm.FillValues.LHS == vm.FillValues.RHS {
if vm.FillValues.LHS != nil && vm.FillValues.RHS != nil && *vm.FillValues.LHS == *vm.FillValues.RHS {
matching += fmt.Sprintf(" fill (%v)", *vm.FillValues.LHS)
} else {
if vm.FillValues.LHS != nil {
@ -205,14 +205,14 @@ func (node *DurationExpr) writeTo(b *bytes.Buffer) {
b.WriteString("step()")
case node.Op == RANGE:
b.WriteString("range()")
case node.Op == MIN:
b.WriteString("min(")
case node.Op == MIN_OF:
b.WriteString("min_of(")
b.WriteString(node.LHS.String())
b.WriteString(", ")
b.WriteString(node.RHS.String())
b.WriteByte(')')
case node.Op == MAX:
b.WriteString("max(")
case node.Op == MAX_OF:
b.WriteString("max_of(")
b.WriteString(node.LHS.String())
b.WriteString(", ")
b.WriteString(node.RHS.String())

View file

@ -23,6 +23,7 @@ import (
func TestExprString(t *testing.T) {
optsParser := NewParser(Options{
ExperimentalDurationExpr: true,
EnableExtendedRangeSelectors: true,
EnableBinopFillModifiers: true,
})
@ -129,6 +130,10 @@ func TestExprString(t *testing.T) {
in: `a + fill_left(-23) fill_right(42) b`,
out: `a + fill_left (-23) fill_right (42) b`,
},
{
in: `a + fill_left(5) fill_right(5) b`,
out: `a + fill (5) b`,
},
{
in: `a + on(b) group_left fill(-23) c`,
out: `a + on (b) group_left () fill (-23) c`,
@ -269,22 +274,22 @@ func TestExprString(t *testing.T) {
out: "foo offset (5 * 2)",
},
{
in: "foo offset +min(10s, 20s)",
out: "foo offset min(10s, 20s)",
in: "foo offset +min_of(10s, 20s)",
out: "foo offset min_of(10s, 20s)",
},
{
in: "foo offset -min(10s, 20s)",
in: "foo offset -min_of(10s, 20s)",
},
{
in: "foo offset -min(10s, +max(step() ^ 2, 2))",
out: "foo offset -min(10s, max(step() ^ 2, 2))",
in: "foo offset -min_of(10s, +max_of(step() ^ 2, 2))",
out: "foo offset -min_of(10s, max_of(step() ^ 2, 2))",
},
{
in: "foo[200-min(-step()^+step(),1)]",
out: "foo[200 - min(-step() ^ step(), 1)]",
in: "foo[200-min_of(-step()^+step(),1)]",
out: "foo[200 - min_of(-step() ^ step(), 1)]",
},
{
in: "foo[200 - min(step() + 10s, -max(step() ^ 2, 3))]",
in: "foo[200 - min_of(step() + 10s, -max_of(step() ^ 2, 3))]",
},
{
in: "foo[range()]",
@ -299,7 +304,7 @@ func TestExprString(t *testing.T) {
in: "foo offset -range()",
},
{
in: "foo[max(range(), 5s)]",
in: "foo[max_of(range(), 5s)]",
},
{
in: `predict_linear(foo[1h], 3000)`,

View file

@ -90,6 +90,7 @@ func LoadedStorage(t testing.TB, input string) *teststorage.TestStorage {
// TestParserOpts are the parser options used for all built-in test engines.
var TestParserOpts = parser.Options{
EnableExperimentalFunctions: true,
ExperimentalDurationExpr: true,
EnableExtendedRangeSelectors: true,
EnableBinopFillModifiers: true,
}

View file

@ -167,13 +167,13 @@ eval range from 50s to 60s step 10s count_over_time(metric1_total[1+(STep()-5)*2
eval range from 50s to 60s step 5s count_over_time(metric1_total[step()+1])
{} 6 6 6
eval range from 50s to 60s step 5s count_over_time(metric1_total[min(step()+1,1h)])
eval range from 50s to 60s step 5s count_over_time(metric1_total[min_of(step()+1,1h)])
{} 6 6 6
eval range from 50s to 60s step 5s count_over_time(metric1_total[max(min(step()+1,1h),1ms)])
eval range from 50s to 60s step 5s count_over_time(metric1_total[max_of(min_of(step()+1,1h),1ms)])
{} 6 6 6
eval range from 50s to 60s step 5s count_over_time(metric1_total[((max(min((step()+1),((1h))),1ms)))])
eval range from 50s to 60s step 5s count_over_time(metric1_total[((max_of(min_of((step()+1),((1h))),1ms)))])
{} 6 6 6
eval range from 50s to 60s step 5s metric1_total offset STEP()
@ -200,31 +200,31 @@ eval range from 50s to 60s step 5s metric1_total offset (STEP()/10)
eval range from 50s to 60s step 5s metric1_total offset (step())
metric1_total{} 45 50 55
eval range from 50s to 60s step 5s metric1_total offset min(step(), 1s)
eval range from 50s to 60s step 5s metric1_total offset min_of(step(), 1s)
metric1_total{} 49 54 59
eval range from 50s to 60s step 5s metric1_total offset min(step(), 1s)+8000
eval range from 50s to 60s step 5s metric1_total offset min_of(step(), 1s)+8000
{} 8049 8054 8059
eval range from 50s to 60s step 5s metric1_total offset -min(step(), 1s)+8000
eval range from 50s to 60s step 5s metric1_total offset -min_of(step(), 1s)+8000
{} 8051 8056 8061
eval range from 50s to 60s step 5s metric1_total offset -(min(step(), 1s))+8000
eval range from 50s to 60s step 5s metric1_total offset -(min_of(step(), 1s))+8000
{} 8051 8056 8061
eval range from 50s to 60s step 5s metric1_total offset -min(step(), 1s)^0
eval range from 50s to 60s step 5s metric1_total offset -min_of(step(), 1s)^0
{} 1 1 1
eval range from 50s to 60s step 5s metric1_total offset +min(step(), 1s)^0
eval range from 50s to 60s step 5s metric1_total offset +min_of(step(), 1s)^0
{} 1 1 1
eval range from 50s to 60s step 5s metric1_total offset min(step(), 1s)^0
eval range from 50s to 60s step 5s metric1_total offset min_of(step(), 1s)^0
{} 1 1 1
eval range from 50s to 60s step 5s metric1_total offset max(3s,min(step(), 1s))+8000
eval range from 50s to 60s step 5s metric1_total offset max_of(3s,min_of(step(), 1s))+8000
{} 8047 8052 8057
eval range from 50s to 60s step 5s metric1_total offset -(min(step(), 2s)-5)+8000
eval range from 50s to 60s step 5s metric1_total offset -(min_of(step(), 2s)-5)+8000
{} 8047 8052 8057
# Test range() function - resolves to query range (end - start).
@ -238,7 +238,7 @@ eval range from 50s to 60s step 5s count_over_time(metric1_total[range()])
eval range from 50s to 60s step 5s metric1_total offset range()
metric1_total{} 40 45 50
eval range from 50s to 60s step 5s metric1_total offset min(range(), 8s)
eval range from 50s to 60s step 5s metric1_total offset min_of(range(), 8s)
metric1_total{} 42 47 52
clear

View file

@ -457,3 +457,257 @@ eval range from 0s to 60s step 15s metric offset -100 smoothed
eval range from 0s to 60s step 15s metric offset -100 smoothed + 0
{} 10 11.5 13 14.5 16
# Native histogram tests for smoothed/anchored modifiers.
# Simple histogram counter incrementing by count:1, sum:1, buckets:[1] every 15s.
clear
load 15s
hist_counter {{schema:0 count:1 sum:1 buckets:[1] offset:1}}+{{count:1 sum:1 buckets:[1] offset:1}}x7
# Standard (non-smoothed/anchored) rate and increase at 50s for reference.
eval instant at 50s histogram_count(rate(hist_counter[1m]))
{} 0.06666666666666667
eval instant at 50s histogram_count(increase(hist_counter[1m]))
{} 4
# Anchored increase at 50s: left=count:1 (t=0), right=count:4 (t=45), increase=3.
eval instant at 50s histogram_count(increase(hist_counter[1m] anchored))
{} 3
eval instant at 50s histogram_sum(increase(hist_counter[1m] anchored))
{} 3
# Smoothed increase at 50s: left=count:1 (t=0), right interpolated at t=50
# between count:4 (t=45) and count:5 (t=60), fraction=1/3, right=count:4.333...,
# increase=3.333...
eval instant at 50s histogram_count(increase(hist_counter[1m] smoothed))
{} 3.333333333333333
eval instant at 50s histogram_sum(increase(hist_counter[1m] smoothed))
{} 3.333333333333333
# Smoothed increase at 5s: left=count:1 (t=0, not before rangeStart=-55s),
# right interpolated at t=5 between count:1 (t=0) and count:2 (t=15),
# fraction=1/3, right=count:1.333..., increase=0.333...
eval instant at 5s histogram_count(increase(hist_counter[1m] smoothed))
{} 0.3333333333333333
# Smoothed rate at 50s: increase / 60s.
eval instant at 50s histogram_count(rate(hist_counter[1m] smoothed))
{} 0.05555555555555555
# Anchored increase at 5s: only one sample (t=0) in range, increase from itself is 0.
eval instant at 5s histogram_count(increase(hist_counter[1m] anchored))
{} 0
eval instant at 5s histogram_sum(increase(hist_counter[1m] anchored))
{} 0
# Smoothed delta (non-counter) at 50s: same values as smoothed increase
# for a monotonic series (no counter reset correction needed).
# hist_counter samples have no GaugeType hint so a not-a-gauge warning is emitted.
eval instant at 50s histogram_count(delta(hist_counter[1m] smoothed))
expect warn msg: PromQL warning: this native histogram metric is not a gauge: "hist_counter"
{} 3.333333333333333
# Anchored rate at 50s: left=count:1 (t=0), right=count:4 (t=45), rate=3/60.
eval instant at 50s histogram_count(rate(hist_counter[1m] anchored))
{} 0.05
# Anchored delta (non-counter) at 50s: same result as anchored increase but
# hist_counter samples have no GaugeType hint so a not-a-gauge warning is emitted.
eval instant at 50s histogram_count(delta(hist_counter[1m] anchored))
expect warn msg: PromQL warning: this native histogram metric is not a gauge: "hist_counter"
{} 3
# Smoothed vector selector interpolation for native histograms.
# At t=7s, interpolate between t=0 (count:1) and t=15 (count:2), fraction=7/15.
eval instant at 7s histogram_count(hist_counter smoothed)
{} 1.4666666666666668
# At t=15s, exact match: count:2.
eval instant at 15s histogram_count(hist_counter smoothed)
{} 2
# At t=110s, no next sample; carry forward the last value (count:8 at t=105).
eval instant at 110s histogram_count(hist_counter smoothed)
{} 8
# Range eval for smoothed rate: verify per-step boundary handling.
# hist_counter increments count:1 and sum:1 every 15s starting at t=0.
# rate(hist_counter[1m] smoothed) at each step computes increase/60.
# t=0: left=right=count:1, increase=0, rate=0.
# t=15: left=count:1, right=count:2 (exact), increase=1, rate=1/60.
# t=30: left=count:1, right=count:3 (exact), increase=2, rate=2/60.
# t=45: left=count:1, right=count:4 (exact), increase=3, rate=3/60.
# t=60: left=count:1, right=count:5 (exact), increase=4, rate=4/60.
eval range from 0s to 60s step 15s histogram_count(rate(hist_counter[1m] smoothed))
{} 0 0.016666666666666666 0.03333333333333333 0.05 0.06666666666666667
# Anchored and smoothed native histogram modifiers with custom buckets.
clear
load 30s
mixed_hist {{schema:0 sum:1 count:1 buckets:[1]}} {{schema:-53 sum:1 count:1 custom_values:[5 10] buckets:[1]}} {{schema:0 sum:5 count:4 buckets:[1 2 1]}} {{schema:-53 sum:1 count:1 custom_values:[5 10] buckets:[1]}}
# Anchored rate should warn and return no result when the range mixes exponential
# and custom buckets at the boundaries.
eval instant at 1m rate(mixed_hist[1m] anchored)
expect warn msg: PromQL warning: vector contains a mix of histograms with exponential and custom buckets schemas for metric name "mixed_hist"
# Should produce no results.
# Smoothed rate should warn and return no result when interpolation would cross
# exponential and custom buckets.
eval instant at 45s rate(mixed_hist[1m] smoothed)
expect warn msg: PromQL warning: vector contains a mix of histograms with exponential and custom buckets schemas for metric name "mixed_hist"
# Should produce no results.
# Anchored increase should still account for resets for custom-bucket histograms.
clear
load 30s
reset_custom_hist {{schema:-53 sum:1 count:1 custom_values:[5 10] buckets:[1]}} {{schema:-53 sum:4 count:4 custom_values:[5 10] buckets:[4]}} {{schema:-53 sum:1 count:1 custom_values:[5 10] buckets:[1] counter_reset_hint:reset}} {{schema:-53 sum:3 count:3 custom_values:[5 10] buckets:[3]}}
eval instant at 90s histogram_count(increase(reset_custom_hist[90s]))
{} 4.5
eval instant at 90s histogram_sum(increase(reset_custom_hist[90s]))
{} 4.5
eval instant at 90s histogram_count(increase(reset_custom_hist[90s] anchored))
{} 6
eval instant at 90s histogram_sum(increase(reset_custom_hist[90s] anchored))
{} 6
# A gauge-hint on a middle (non-boundary) sample must trigger the "not a counter"
# warning for rate/increase, matching the behaviour of the non-extended path.
clear
load 30s
mid_gauge_hist {{schema:0 sum:1 count:1 buckets:[1]}} {{schema:0 sum:2 count:2 buckets:[2] counter_reset_hint:gauge}} {{schema:0 sum:3 count:3 buckets:[3]}}
eval instant at 90s histogram_count(rate(mid_gauge_hist[90s] anchored))
expect warn msg: PromQL warning: this native histogram metric is not a counter: "mid_gauge_hist"
{} 0.022222222222222223
eval instant at 90s histogram_count(increase(mid_gauge_hist[90s] smoothed))
expect warn msg: PromQL warning: this native histogram metric is not a counter: "mid_gauge_hist"
{} 2
# Gauge op on a counter-typed series must warn when a boundary sample lacks the
# gauge hint.
eval instant at 90s histogram_count(delta(mid_gauge_hist[90s] anchored))
expect warn msg: PromQL warning: this native histogram metric is not a gauge: "mid_gauge_hist"
{} 2
# Smoothed rate on a custom-bucket-only series interpolates cleanly.
clear
load 15s
custom_only {{schema:-53 sum:1 count:1 custom_values:[5 10] buckets:[1]}}+{{schema:-53 sum:1 count:1 custom_values:[5 10] buckets:[1]}}x7
eval instant at 50s histogram_count(increase(custom_only[1m] smoothed))
{} 3.333333333333333
eval instant at 50s histogram_sum(increase(custom_only[1m] smoothed))
{} 3.333333333333333
# Smoothed vector-selector interpolation for a histogram counter crossing a
# reset. isCounter=true (CounterResetHint != GaugeType), so the reset between
# h[1]=count:10 and h[2]=count:2 (counter_reset_hint:reset) is detected and
# the interpolation models the counter as restarting from zero:
# h[2].Mul(fraction) = count:2 * (5/15) = 0.666...
clear
load 15s
reset_middle {{schema:0 sum:5 count:5 buckets:[5]}} {{schema:0 sum:10 count:10 buckets:[10]}} {{schema:0 sum:2 count:2 buckets:[2] counter_reset_hint:reset}} {{schema:0 sum:6 count:6 buckets:[6]}}
eval instant at 20s histogram_count(reset_middle smoothed)
{} 0.6666666666666666
# Smoothed histogram rate must not double-count the first post-reset sample when
# the left range boundary is interpolated across the reset.
clear
load 10s
reset_boundary _ {{schema:0 sum:396 count:396 buckets:[396] counter_reset_hint:not_reset}} {{schema:0 sum:110 count:110 buckets:[110] counter_reset_hint:reset}} {{schema:0 sum:194 count:194 buckets:[194] counter_reset_hint:not_reset}}
eval instant at 20s500ms histogram_count(rate(reset_boundary[1s] smoothed))
{} 9.7
# Anchored increase with reset at last sample (T < rangeEnd): the reset hint on
# h[2] must not self-detect when right is a direct copy of h[2].
# Float reference (5 10 3): increase = 10 - 5 + 10 - 3? No: right - left + correction.
# left=5 right=3 correction=h[1]=10 → 8. Bug returns 11 (adds h[2]=3 twice).
clear
load 30s
anchored_reset_at_end {{schema:0 sum:5 count:5 buckets:[5]}} {{schema:0 sum:10 count:10 buckets:[10]}} {{schema:0 sum:3 count:3 buckets:[3] counter_reset_hint:reset}}
eval instant at 70s histogram_count(increase(anchored_reset_at_end[70s] anchored))
{} 8
# Anchored increase with only two samples, second is a reset at rangeEnd.
# The two-sample case must still apply the reset correction even though the
# inner slice is empty after excluding both boundary samples.
# Float reference: right - left + correction = 3 - 5 + 5 = 3.
clear
load 30s
anchored_two_sample_reset {{schema:0 sum:5 count:5 buckets:[5]}} {{schema:0 sum:3 count:3 buckets:[3] counter_reset_hint:reset}}
eval instant at 30s histogram_count(increase(anchored_two_sample_reset[30s] anchored))
{} 3
# Smoothed increase where the left interpolation crosses the first reset and a
# second reset immediately follows the skipped sample. The correction must be
# taken against h[firstSampleIndex+1] (count=5), not the interpolated left
# (count=0.5). Float reference: 5.5.
clear
load 10s
smoothed_double_reset {{schema:0 sum:10 count:10 buckets:[10]}} {{schema:0 sum:5 count:5 buckets:[5] counter_reset_hint:reset}} {{schema:0 sum:2 count:2 buckets:[2] counter_reset_hint:reset}} {{schema:0 sum:4 count:4 buckets:[4]}}
eval instant at 15s histogram_count(increase(smoothed_double_reset[14s] smoothed))
{} 5.5
# Two-sample smoothed window where both left and right are interpolated from the
# same reset. The left interpolation already accounts for the reset, so no
# correction should be applied. Float reference: right-left = h[1].Mul(0.75) -
# h[1].Mul(0.25) = h[1].Mul(0.5) = count 2.5. The first > last+1 early-return
# in correctForCounterResetsHistogram prevents double-counting this case.
clear
load 20s
smoothed_two_sample_both_interp {{schema:0 sum:10 count:10 buckets:[10]}} {{schema:0 sum:5 count:5 buckets:[5] counter_reset_hint:reset}}
eval instant at 15s histogram_count(increase(smoothed_two_sample_both_interp[10s] smoothed))
{} 2.5
# Smoothed vector selector emits MixedExponentialCustomHistogramsWarning and
# produces no result when interpolating between exponential and custom-bucket
# histograms. At t=45s: prev=t=30 (custom), next=t=60 (exp) → skip + warn.
clear
load 30s
smoothed_mix {{schema:0 sum:1 count:1 buckets:[1]}} {{schema:-53 sum:1 count:1 custom_values:[5 10] buckets:[1]}} {{schema:0 sum:5 count:4 buckets:[1 2 1]}} {{schema:-53 sum:1 count:1 custom_values:[5 10] buckets:[1]}}
eval instant at 45s histogram_count(smoothed_mix smoothed)
expect warn msg: PromQL warning: vector contains a mix of histograms with exponential and custom buckets schemas for metric name "smoothed_mix"
# Smoothed vector selector must emit a warning and produce no result when the
# lookback window mixes floats and histograms.
clear
load 30s
mixed_types 1 2 {{schema:0 sum:3 count:3 buckets:[3]}} {{schema:0 sum:4 count:4 buckets:[4]}}
eval instant at 45s sort(mixed_types smoothed)
expect warn msg: PromQL warning: encountered a mix of histograms and floats for metric name "mixed_types"
# Smoothed rate where the RIGHT boundary interpolation crosses a counter reset.
# Samples: t=0 count:5, t=10 count:10, t=20 count:3 (reset).
# At t=15s, range=10s: rangeStart=5s, rangeEnd=15s.
# left: interpolate(t=0 count:5, t=10 count:10, t=5s) = count:5+(count:5*0.5) = count:7.5.
# right: interpolate(t=10 count:10, t=20 count:3 reset, t=15s) → reset path →
# count:3 * 0.5 = count:1.5 (CounterResetHint=reset inherited).
# Inner samples: h[t=10 count:10]. h[10].DetectReset(left=7.5)? no (10>7.5).
# right.DetectReset(prev=count:10)? yes (reset hint). correction=count:10.
# increase = count:1.5 - count:7.5 + count:10 = count:4.
# rate = count:4/10 = 0.4.
clear
load 10s
right_boundary_reset {{schema:0 sum:5 count:5 buckets:[5]}} {{schema:0 sum:10 count:10 buckets:[10]}} {{schema:0 sum:3 count:3 buckets:[3] counter_reset_hint:reset}}
eval instant at 15s histogram_count(rate(right_boundary_reset[10s] smoothed))
{} 0.4

View file

@ -309,6 +309,21 @@ eval range from 0 to 20m step 5m intermittent_left + fill_left(0) intermittent_r
{label="b"} 100 _ 300 _ 500
{label="c"} 1000 _ _ 4000 5000
# Regression test: group_left fill_left in a range query must apply fill values
# at every timestep, even when the RHS sigOrd was matched at a previous timestep.
# resetMatchedSigs previously used clear() which left non-nil empty maps, causing
# the fill-LHS path to incorrectly skip unmatched RHS samples on subsequent timesteps.
clear
load 5m
matched_lhs{key="a"} 1 _ 3
matched_rhs{key="a"} 10 20 30
matched_rhs{key="b"} 100 200 300
eval range from 0 to 10m step 5m matched_lhs + on(key) group_left fill_left(0) matched_rhs
{key="a"} 11 20 33
{key="b"} 100 200 300
# ---------- fill with vectors where one side is empty ----------
clear

View file

@ -2187,3 +2187,55 @@ eval range from 0s to 9s step 3s metric_for_at @ start()
eval range from 1s to 9s step 2s metric_for_at @ end()
{__name__="metric_for_at"} 10 10 10 10 10
# Tests for min_of() and max_of() scalar functions.
# min_of(a, b) returns math.Min(a, b).
# max_of(a, b) returns math.Max(a, b).
# Basic literal comparisons.
eval instant at 0s min_of(3, 5)
3
eval instant at 0s min_of(5, 3)
3
eval instant at 0s max_of(3, 5)
5
eval instant at 0s max_of(5, 3)
5
# Equal values.
eval instant at 0s min_of(4, 4)
4
eval instant at 0s max_of(4, 4)
4
# Negative values.
eval instant at 0s min_of(-2, -5)
-5
eval instant at 0s max_of(-2, -5)
-2
# Zero and positive.
eval instant at 0s min_of(0, 1)
0
eval instant at 0s max_of(0, 1)
1
# NaN propagation: any NaN input yields NaN.
eval instant at 0s min_of(NaN, 3)
NaN
eval instant at 0s min_of(3, NaN)
NaN
eval instant at 0s max_of(NaN, 3)
NaN
eval instant at 0s max_of(3, NaN)
NaN

View file

@ -1118,6 +1118,13 @@ eval instant at 1m30s rate(some_metric[1m30s])
expect warn msg: PromQL warning: vector contains a mix of histograms with exponential and custom buckets schemas for metric name "some_metric"
# Should produce no results.
# histogram_count(rate()) must also warn when the schema mix falls inside the stats-only
# path (HistogramStatsIterator). Without Schema being set in that iterator, all histograms
# appear as Schema=0 and the custom-bucket mismatch is silently missed.
eval instant at 1m histogram_count(rate(some_metric[1m30s]))
expect warn msg: PromQL warning: vector contains a mix of histograms with exponential and custom buckets schemas for metric name "some_metric"
# Should produce no results.
# Start with custom, end with exponential. Return the exponential histogram divided by 48.
# (The 1st sample is the NHCB with count:1. It is mostly ignored with the exception of the
# count, which means the rate calculation extrapolates until the count hits 0.)

View file

@ -38,6 +38,12 @@ eval range from 7m to 15m step 1m increase(cumulative[5m:1m])
{type="st_resets"} 300x8
{type="normalized_resets"} 420 780 675 675 1275 900 900 1725 1125
# Resets function also considers start timestamp resets.
eval range from 7m to 15m step 1m resets(cumulative[5m])
{type="no_st"} 0x8
{type="st_resets"} 1 2 1 1 2 1 1 2 1
{type="normalized_resets"} 0x8
clear
# Tests for rate(), irate() and increase() on deltas. Includes various approaches for start timestamps:
@ -131,6 +137,10 @@ eval range from 7m to 15m step 1m rate(cumulative[5m])
eval range from 7m to 15m step 1m irate(cumulative[5m])
{} {{count:1 sum:1}}x8
# Resets function also considers start timestamp resets.
eval range from 7m to 15m step 1m resets(cumulative[5m])
{} 0x8
clear
# Tests for rate(), irate() and increase() on delta histograms.

View file

@ -505,7 +505,7 @@ func (ssi *storageSeriesIterator) AtT() int64 {
return ssi.currT
}
// TODO(krajorama): implement AtST.
// TODO(krajorama,ywwg): implement AtST.
func (*storageSeriesIterator) AtST() int64 {
return 0
}

Some files were not shown because too many files have changed in this diff Show more