mirror of
https://github.com/prometheus/prometheus.git
synced 2024-12-24 21:24:05 -08:00
Merge branch 'main' into nhcb
Signed-off-by: Jeanette Tan <jeanette.tan@grafana.com>
This commit is contained in:
commit
14f8dded39
2
.github/dependabot.yml
vendored
2
.github/dependabot.yml
vendored
|
@ -11,6 +11,7 @@ updates:
|
|||
go.opentelemetry.io:
|
||||
patterns:
|
||||
- "go.opentelemetry.io/*"
|
||||
open-pull-requests-limit: 20
|
||||
- package-ecosystem: "gomod"
|
||||
directory: "/documentation/examples/remote_storage"
|
||||
schedule:
|
||||
|
@ -19,6 +20,7 @@ updates:
|
|||
directory: "/web/ui"
|
||||
schedule:
|
||||
interval: "monthly"
|
||||
open-pull-requests-limit: 20
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
|
|
4
.github/workflows/buf-lint.yml
vendored
4
.github/workflows/buf-lint.yml
vendored
|
@ -12,8 +12,8 @@ jobs:
|
|||
name: lint
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
|
||||
- uses: bufbuild/buf-setup-action@517ee23296d5caf38df31c21945e6a54bbc8a89f # v1.30.0
|
||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
||||
- uses: bufbuild/buf-setup-action@dde0b9351db90fbf78e345f41a57de8514bf1091 # v1.32.2
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
- uses: bufbuild/buf-lint-action@06f9dd823d873146471cfaaf108a993fe00e5325 # v1.1.1
|
||||
|
|
4
.github/workflows/buf.yml
vendored
4
.github/workflows/buf.yml
vendored
|
@ -12,8 +12,8 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
if: github.repository_owner == 'prometheus'
|
||||
steps:
|
||||
- uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
|
||||
- uses: bufbuild/buf-setup-action@517ee23296d5caf38df31c21945e6a54bbc8a89f # v1.30.0
|
||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
||||
- uses: bufbuild/buf-setup-action@dde0b9351db90fbf78e345f41a57de8514bf1091 # v1.32.2
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
- uses: bufbuild/buf-lint-action@06f9dd823d873146471cfaaf108a993fe00e5325 # v1.1.1
|
||||
|
|
37
.github/workflows/ci.yml
vendored
37
.github/workflows/ci.yml
vendored
|
@ -13,7 +13,7 @@ jobs:
|
|||
# should also be updated.
|
||||
image: quay.io/prometheus/golang-builder:1.22-base
|
||||
steps:
|
||||
- uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
|
||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
||||
- uses: prometheus/promci@3cb0c3871f223bd5ce1226995bd52ffb314798b6 # v0.1.0
|
||||
- uses: ./.github/promci/actions/setup_environment
|
||||
- run: make GOOPTS=--tags=stringlabels GO_ONLY=1 SKIP_GOLANGCI_LINT=1
|
||||
|
@ -27,7 +27,7 @@ jobs:
|
|||
container:
|
||||
image: quay.io/prometheus/golang-builder:1.22-base
|
||||
steps:
|
||||
- uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
|
||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
||||
- uses: prometheus/promci@3cb0c3871f223bd5ce1226995bd52ffb314798b6 # v0.1.0
|
||||
- uses: ./.github/promci/actions/setup_environment
|
||||
- run: go test --tags=dedupelabels ./...
|
||||
|
@ -43,7 +43,7 @@ jobs:
|
|||
# The go version in this image should be N-1 wrt test_go.
|
||||
image: quay.io/prometheus/golang-builder:1.21-base
|
||||
steps:
|
||||
- uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
|
||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
||||
- run: make build
|
||||
# Don't run NPM build; don't run race-detector.
|
||||
- run: make test GO_ONLY=1 test-flags=""
|
||||
|
@ -57,7 +57,7 @@ jobs:
|
|||
image: quay.io/prometheus/golang-builder:1.22-base
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
|
||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
||||
- uses: prometheus/promci@3cb0c3871f223bd5ce1226995bd52ffb314798b6 # v0.1.0
|
||||
- uses: ./.github/promci/actions/setup_environment
|
||||
with:
|
||||
|
@ -74,8 +74,8 @@ jobs:
|
|||
name: Go tests on Windows
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
|
||||
- uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0
|
||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
||||
- uses: actions/setup-go@cdcb36043654635271a94b9a6d1392de5bb323a7 # v5.0.1
|
||||
with:
|
||||
go-version: 1.22.x
|
||||
- run: |
|
||||
|
@ -91,7 +91,7 @@ jobs:
|
|||
container:
|
||||
image: quay.io/prometheus/golang-builder:1.22-base
|
||||
steps:
|
||||
- uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
|
||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
||||
- run: go install ./cmd/promtool/.
|
||||
- run: go install github.com/google/go-jsonnet/cmd/jsonnet@latest
|
||||
- run: go install github.com/google/go-jsonnet/cmd/jsonnetfmt@latest
|
||||
|
@ -114,7 +114,7 @@ jobs:
|
|||
matrix:
|
||||
thread: [ 0, 1, 2 ]
|
||||
steps:
|
||||
- uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
|
||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
||||
- uses: prometheus/promci@3cb0c3871f223bd5ce1226995bd52ffb314798b6 # v0.1.0
|
||||
- uses: ./.github/promci/actions/build
|
||||
with:
|
||||
|
@ -137,7 +137,7 @@ jobs:
|
|||
# Whenever the Go version is updated here, .promu.yml
|
||||
# should also be updated.
|
||||
steps:
|
||||
- uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
|
||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
||||
- uses: prometheus/promci@3cb0c3871f223bd5ce1226995bd52ffb314798b6 # v0.1.0
|
||||
- uses: ./.github/promci/actions/build
|
||||
with:
|
||||
|
@ -148,9 +148,9 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
|
||||
uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0
|
||||
uses: actions/setup-go@cdcb36043654635271a94b9a6d1392de5bb323a7 # v5.0.1
|
||||
with:
|
||||
cache: false
|
||||
go-version: 1.22.x
|
||||
|
@ -161,21 +161,20 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
|
||||
uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0
|
||||
uses: actions/setup-go@cdcb36043654635271a94b9a6d1392de5bb323a7 # v5.0.1
|
||||
with:
|
||||
cache: false
|
||||
go-version: 1.22.x
|
||||
- name: Install snmp_exporter/generator dependencies
|
||||
run: sudo apt-get update && sudo apt-get -y install libsnmp-dev
|
||||
if: github.repository == 'prometheus/snmp_exporter'
|
||||
- name: Lint
|
||||
uses: golangci/golangci-lint-action@3cfe3a4abbb849e10058ce4af15d205b6da42804 # v4.0.0
|
||||
uses: golangci/golangci-lint-action@a4f60bb28d35aeee14e6880718e0c85ff1882e64 # v6.0.1
|
||||
with:
|
||||
args: --verbose
|
||||
# Make sure to sync this with Makefile.common and scripts/golangci-lint.yml.
|
||||
version: v1.56.2
|
||||
version: v1.59.0
|
||||
fuzzing:
|
||||
uses: ./.github/workflows/fuzzing.yml
|
||||
if: github.event_name == 'pull_request'
|
||||
|
@ -188,7 +187,7 @@ jobs:
|
|||
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@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
|
||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
||||
- uses: prometheus/promci@3cb0c3871f223bd5ce1226995bd52ffb314798b6 # v0.1.0
|
||||
- uses: ./.github/promci/actions/publish_main
|
||||
with:
|
||||
|
@ -202,7 +201,7 @@ jobs:
|
|||
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.')
|
||||
steps:
|
||||
- uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
|
||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
||||
- uses: prometheus/promci@3cb0c3871f223bd5ce1226995bd52ffb314798b6 # v0.1.0
|
||||
- uses: ./.github/promci/actions/publish_release
|
||||
with:
|
||||
|
@ -217,7 +216,7 @@ jobs:
|
|||
needs: [test_ui, codeql]
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
|
||||
uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
||||
- uses: prometheus/promci@3cb0c3871f223bd5ce1226995bd52ffb314798b6 # v0.1.0
|
||||
- name: Install nodejs
|
||||
uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
|
||||
|
|
8
.github/workflows/codeql-analysis.yml
vendored
8
.github/workflows/codeql-analysis.yml
vendored
|
@ -24,15 +24,15 @@ jobs:
|
|||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
|
||||
uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
||||
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@012739e5082ff0c22ca6d6ab32e07c36df03c4a4 # v3.22.12
|
||||
uses: github/codeql-action/init@2e230e8fe0ad3a14a340ad0815ddb96d599d2aff # v3.25.8
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@012739e5082ff0c22ca6d6ab32e07c36df03c4a4 # v3.22.12
|
||||
uses: github/codeql-action/autobuild@2e230e8fe0ad3a14a340ad0815ddb96d599d2aff # v3.25.8
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@012739e5082ff0c22ca6d6ab32e07c36df03c4a4 # v3.22.12
|
||||
uses: github/codeql-action/analyze@2e230e8fe0ad3a14a340ad0815ddb96d599d2aff # v3.25.8
|
||||
|
|
13
.github/workflows/container_description.yml
vendored
13
.github/workflows/container_description.yml
vendored
|
@ -4,6 +4,7 @@ on:
|
|||
push:
|
||||
paths:
|
||||
- "README.md"
|
||||
- "README-containers.md"
|
||||
- ".github/workflows/container_description.yml"
|
||||
branches: [ main, master ]
|
||||
|
||||
|
@ -17,7 +18,7 @@ jobs:
|
|||
if: github.repository_owner == 'prometheus' || github.repository_owner == 'prometheus-community' # Don't run this workflow on forks.
|
||||
steps:
|
||||
- name: git checkout
|
||||
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
|
||||
uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
||||
- name: Set docker hub repo name
|
||||
run: echo "DOCKER_REPO_NAME=$(make docker-repo-name)" >> $GITHUB_ENV
|
||||
- name: Push README to Dockerhub
|
||||
|
@ -29,7 +30,9 @@ jobs:
|
|||
destination_container_repo: ${{ env.DOCKER_REPO_NAME }}
|
||||
provider: dockerhub
|
||||
short_description: ${{ env.DOCKER_REPO_NAME }}
|
||||
readme_file: 'README.md'
|
||||
# Empty string results in README-containers.md being pushed if it
|
||||
# exists. Otherwise, README.md is pushed.
|
||||
readme_file: ''
|
||||
|
||||
PushQuayIoReadme:
|
||||
runs-on: ubuntu-latest
|
||||
|
@ -37,7 +40,7 @@ jobs:
|
|||
if: github.repository_owner == 'prometheus' || github.repository_owner == 'prometheus-community' # Don't run this workflow on forks.
|
||||
steps:
|
||||
- name: git checkout
|
||||
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
|
||||
uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
||||
- name: Set quay.io org name
|
||||
run: echo "DOCKER_REPO=$(echo quay.io/${GITHUB_REPOSITORY_OWNER} | tr -d '-')" >> $GITHUB_ENV
|
||||
- name: Set quay.io repo name
|
||||
|
@ -49,4 +52,6 @@ jobs:
|
|||
with:
|
||||
destination_container_repo: ${{ env.DOCKER_REPO_NAME }}
|
||||
provider: quay
|
||||
readme_file: 'README.md'
|
||||
# Empty string results in README-containers.md being pushed if it
|
||||
# exists. Otherwise, README.md is pushed.
|
||||
readme_file: ''
|
||||
|
|
2
.github/workflows/repo_sync.yml
vendored
2
.github/workflows/repo_sync.yml
vendored
|
@ -13,7 +13,7 @@ jobs:
|
|||
container:
|
||||
image: quay.io/prometheus/golang-builder
|
||||
steps:
|
||||
- uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
|
||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
||||
- run: ./scripts/sync_repo_files.sh
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.PROMBOT_GITHUB_TOKEN }}
|
||||
|
|
6
.github/workflows/scorecards.yml
vendored
6
.github/workflows/scorecards.yml
vendored
|
@ -21,12 +21,12 @@ jobs:
|
|||
|
||||
steps:
|
||||
- name: "Checkout code"
|
||||
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # tag=v4.1.4
|
||||
uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # tag=v4.1.6
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: "Run analysis"
|
||||
uses: ossf/scorecard-action@0864cf19026789058feabb7e87baa5f140aac736 # tag=v2.3.1
|
||||
uses: ossf/scorecard-action@dc50aa9510b46c811795eb24b2f1ba02a914e534 # tag=v2.3.3
|
||||
with:
|
||||
results_file: results.sarif
|
||||
results_format: 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@012739e5082ff0c22ca6d6ab32e07c36df03c4a4 # tag=v3.22.12
|
||||
uses: github/codeql-action/upload-sarif@2e230e8fe0ad3a14a340ad0815ddb96d599d2aff # tag=v3.25.8
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
|
|
32
.gitpod.Dockerfile
vendored
32
.gitpod.Dockerfile
vendored
|
@ -1,15 +1,33 @@
|
|||
FROM gitpod/workspace-full
|
||||
|
||||
# Set Node.js version as an environment variable.
|
||||
ENV CUSTOM_NODE_VERSION=16
|
||||
ENV CUSTOM_GO_VERSION=1.19
|
||||
ENV GOPATH=$HOME/go-packages
|
||||
ENV GOROOT=$HOME/go
|
||||
ENV PATH=$GOROOT/bin:$GOPATH/bin:$PATH
|
||||
|
||||
# Install and use the specified Node.js version via nvm.
|
||||
RUN bash -c ". .nvm/nvm.sh && nvm install ${CUSTOM_NODE_VERSION} && nvm use ${CUSTOM_NODE_VERSION} && nvm alias default ${CUSTOM_NODE_VERSION}"
|
||||
|
||||
# Ensure nvm uses the default Node.js version in all new shells.
|
||||
RUN echo "nvm use default &>/dev/null" >> ~/.bashrc.d/51-nvm-fix
|
||||
RUN curl -fsSL https://dl.google.com/go/go${GO_VERSION}.linux-amd64.tar.gz | tar xzs \
|
||||
&& printf '%s\n' 'export GOPATH=/workspace/go' \
|
||||
'export PATH=$GOPATH/bin:$PATH' > $HOME/.bashrc.d/300-go
|
||||
|
||||
# Remove any existing Go installation in $HOME path.
|
||||
RUN rm -rf $HOME/go $HOME/go-packages
|
||||
|
||||
# Export go environment variables.
|
||||
RUN echo "export GOPATH=/workspace/go" >> ~/.bashrc.d/300-go && \
|
||||
echo "export GOBIN=\$GOPATH/bin" >> ~/.bashrc.d/300-go && \
|
||||
echo "export GOROOT=${HOME}/go" >> ~/.bashrc.d/300-go && \
|
||||
echo "export PATH=\$GOROOT/bin:\$GOBIN:\$PATH" >> ~/.bashrc
|
||||
|
||||
# Reload the environment variables to ensure go environment variables are
|
||||
# available in subsequent commands.
|
||||
RUN bash -c "source ~/.bashrc && source ~/.bashrc.d/300-go"
|
||||
|
||||
# Fetch the Go version dynamically from the Prometheus go.mod file and Install Go in $HOME path.
|
||||
RUN export CUSTOM_GO_VERSION=$(curl -sSL "https://raw.githubusercontent.com/prometheus/prometheus/main/go.mod" | awk '/^go/{print $2".0"}') && \
|
||||
curl -fsSL "https://dl.google.com/go/go${CUSTOM_GO_VERSION}.linux-amd64.tar.gz" | \
|
||||
tar -xz -C $HOME
|
||||
|
||||
# Fetch the goyacc parser version dynamically from the Prometheus Makefile
|
||||
# and install it globally in $GOBIN path.
|
||||
RUN GOYACC_VERSION=$(curl -fsSL "https://raw.githubusercontent.com/prometheus/prometheus/main/Makefile" | awk -F'=' '/GOYACC_VERSION \?=/{gsub(/ /, "", $2); print $2}') && \
|
||||
go install "golang.org/x/tools/cmd/goyacc@${GOYACC_VERSION}"
|
||||
|
|
|
@ -21,6 +21,7 @@ linters:
|
|||
- goimports
|
||||
- misspell
|
||||
- nolintlint
|
||||
- perfsprint
|
||||
- predeclared
|
||||
- revive
|
||||
- testifylint
|
||||
|
@ -44,7 +45,9 @@ issues:
|
|||
- linters:
|
||||
- godot
|
||||
source: "^// ==="
|
||||
|
||||
- linters:
|
||||
- perfsprint
|
||||
text: "fmt.Sprintf can be replaced with string concatenation"
|
||||
linters-settings:
|
||||
depguard:
|
||||
rules:
|
||||
|
@ -85,6 +88,9 @@ linters-settings:
|
|||
local-prefixes: github.com/prometheus/prometheus
|
||||
gofumpt:
|
||||
extra-rules: true
|
||||
perfsprint:
|
||||
# Optimizes `fmt.Errorf`.
|
||||
errorf: false
|
||||
revive:
|
||||
# By default, revive will enable only the linting rules that are named in the configuration file.
|
||||
# So, it's needed to explicitly set in configuration all required rules.
|
||||
|
|
10
CHANGELOG.md
10
CHANGELOG.md
|
@ -2,18 +2,22 @@
|
|||
|
||||
## unreleased
|
||||
|
||||
This release changes the default for GOGC, the Go runtime control for the trade-off between excess memory use and CPU usage. We have found that Prometheus operates with minimal additional CPU usage, but greatly reduced memory by adjusting the upstream Go default from 100 to 50.
|
||||
|
||||
* [CHANGE] Rules: Execute 1 query instead of N (where N is the number of alerts within alert rule) when restoring alerts. #13980
|
||||
* [CHANGE] Runtime: Change GOGC threshold from 100 to 50 #14176
|
||||
* [FEATURE] Rules: Add new option `query_offset` for each rule group via rule group configuration file and `rule_query_offset` as part of the global configuration to have more resilience for remote write delays. #14061
|
||||
* [ENHANCEMENT] Rules: Add `rule_group_last_restore_duration_seconds` to measure the time it takes to restore a rule group. #13974
|
||||
* [ENHANCEMENT] OTLP: Improve remote write format translation performance by using label set hashes for metric identifiers instead of string based ones. #14006 #13991
|
||||
* [ENHANCEMENT] TSDB: Optimize querying with regexp matchers. #13620
|
||||
* [BUGFIX] OTLP: Don't generate target_info unless at least one identifying label is defined. #13991
|
||||
* [BUGFIX] OTLP: Don't generate target_info unless there are metrics. #13991
|
||||
|
||||
## 2.52.0-rc.1 / 2024-05-03
|
||||
## 2.52.1 / 2024-05-29
|
||||
|
||||
* [BUGFIX] API: Fix missing comma during JSON encoding of API results. #14047
|
||||
* [BUGFIX] Linode SD: Fix partial fetch when discovery would return more than 500 elements. #14141
|
||||
|
||||
## 2.52.0-rc.0 / 2024-04-22
|
||||
## 2.52.0 / 2024-05-07
|
||||
|
||||
* [CHANGE] TSDB: Fix the predicate checking for blocks which are beyond the retention period to include the ones right at the retention boundary. #9633
|
||||
* [FEATURE] Kubernetes SD: Add a new metric `prometheus_sd_kubernetes_failures_total` to track failed requests to Kubernetes API. #13554
|
||||
|
|
|
@ -42,7 +42,12 @@ go build ./cmd/prometheus/
|
|||
make test # Make sure all the tests pass before you commit and push :)
|
||||
```
|
||||
|
||||
We use [`golangci-lint`](https://github.com/golangci/golangci-lint) for linting the code. If it reports an issue and you think that the warning needs to be disregarded or is a false-positive, you can add a special comment `//nolint:linter1[,linter2,...]` before the offending line. Use this sparingly though, fixing the code to comply with the linter's recommendation is in general the preferred course of action.
|
||||
To run a collection of Go linters through [`golangci-lint`](https://github.com/golangci/golangci-lint), do:
|
||||
```bash
|
||||
make lint
|
||||
```
|
||||
|
||||
If it reports an issue and you think that the warning needs to be disregarded or is a false-positive, you can add a special comment `//nolint:linter1[,linter2,...]` before the offending line. Use this sparingly though, fixing the code to comply with the linter's recommendation is in general the preferred course of action. See [this section of the golangci-lint documentation](https://golangci-lint.run/usage/false-positives/#nolint-directive) for more information.
|
||||
|
||||
All our issues are regularly tagged so that you can also filter down the issues involving the components you want to work on. For our labeling policy refer [the wiki page](https://github.com/prometheus/prometheus/wiki/Label-Names-and-Descriptions).
|
||||
|
||||
|
|
|
@ -61,7 +61,7 @@ PROMU_URL := https://github.com/prometheus/promu/releases/download/v$(PROMU_
|
|||
SKIP_GOLANGCI_LINT :=
|
||||
GOLANGCI_LINT :=
|
||||
GOLANGCI_LINT_OPTS ?=
|
||||
GOLANGCI_LINT_VERSION ?= v1.56.2
|
||||
GOLANGCI_LINT_VERSION ?= v1.59.0
|
||||
# golangci-lint only supports linux, darwin and windows platforms on i386/amd64/arm64.
|
||||
# windows isn't included here because of the path separator being different.
|
||||
ifeq ($(GOHOSTOS),$(filter $(GOHOSTOS),linux darwin))
|
||||
|
|
|
@ -28,6 +28,8 @@ import (
|
|||
"os/signal"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"runtime/debug"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
|
@ -42,6 +44,7 @@ import (
|
|||
"github.com/mwitkow/go-conntrack"
|
||||
"github.com/oklog/run"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/collectors"
|
||||
versioncollector "github.com/prometheus/client_golang/prometheus/collectors/version"
|
||||
"github.com/prometheus/common/model"
|
||||
"github.com/prometheus/common/promlog"
|
||||
|
@ -252,6 +255,18 @@ func main() {
|
|||
newFlagRetentionDuration model.Duration
|
||||
)
|
||||
|
||||
// Unregister the default GoCollector, and reregister with our defaults.
|
||||
if prometheus.Unregister(collectors.NewGoCollector()) {
|
||||
prometheus.MustRegister(
|
||||
collectors.NewGoCollector(
|
||||
collectors.WithGoCollectorRuntimeMetrics(
|
||||
collectors.MetricsGC,
|
||||
collectors.MetricsScheduler,
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
cfg := flagConfig{
|
||||
notifier: notifier.Options{
|
||||
Registerer: prometheus.DefaultRegisterer,
|
||||
|
@ -418,7 +433,7 @@ func main() {
|
|||
serverOnlyFlag(a, "rules.alert.resend-delay", "Minimum amount of time to wait before resending an alert to Alertmanager.").
|
||||
Default("1m").SetValue(&cfg.resendDelay)
|
||||
|
||||
serverOnlyFlag(a, "rules.max-concurrent-evals", "Global concurrency limit for independent rules that can run concurrently.").
|
||||
serverOnlyFlag(a, "rules.max-concurrent-evals", "Global concurrency limit for independent rules that can run concurrently. When set, \"query.max-concurrency\" may need to be adjusted accordingly.").
|
||||
Default("4").Int64Var(&cfg.maxConcurrentEvals)
|
||||
|
||||
a.Flag("scrape.adjust-timestamps", "Adjust scrape timestamps by up to `scrape.timestamp-tolerance` to align them to the intended schedule. See https://github.com/prometheus/prometheus/issues/7846 for more context. Experimental. This flag will be removed in a future release.").
|
||||
|
@ -772,6 +787,9 @@ func main() {
|
|||
ResendDelay: time.Duration(cfg.resendDelay),
|
||||
MaxConcurrentEvals: cfg.maxConcurrentEvals,
|
||||
ConcurrentEvalsEnabled: cfg.enableConcurrentRuleEval,
|
||||
DefaultRuleQueryOffset: func() time.Duration {
|
||||
return time.Duration(cfgFile.GlobalConfig.RuleQueryOffset)
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -1368,6 +1386,17 @@ func reloadConfig(filename string, expandExternalLabels, enableExemplarStorage b
|
|||
return fmt.Errorf("one or more errors occurred while applying the new configuration (--config.file=%q)", filename)
|
||||
}
|
||||
|
||||
oldGoGC := debug.SetGCPercent(conf.Runtime.GoGC)
|
||||
if oldGoGC != conf.Runtime.GoGC {
|
||||
level.Info(logger).Log("msg", "updated GOGC", "old", oldGoGC, "new", conf.Runtime.GoGC)
|
||||
}
|
||||
// Write the new setting out to the ENV var for runtime API output.
|
||||
if conf.Runtime.GoGC >= 0 {
|
||||
os.Setenv("GOGC", strconv.Itoa(conf.Runtime.GoGC))
|
||||
} else {
|
||||
os.Setenv("GOGC", "off")
|
||||
}
|
||||
|
||||
noStepSuqueryInterval.Set(conf.GlobalConfig.EvaluationInterval)
|
||||
l := []interface{}{"msg", "Completed loading of configuration file", "filename", filename, "totalDuration", time.Since(start)}
|
||||
level.Info(logger).Log(append(l, timings...)...)
|
||||
|
|
|
@ -24,6 +24,7 @@ import (
|
|||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
"testing"
|
||||
|
@ -189,7 +190,7 @@ func TestSendAlerts(t *testing.T) {
|
|||
|
||||
for i, tc := range testCases {
|
||||
tc := tc
|
||||
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
|
||||
t.Run(strconv.Itoa(i), func(t *testing.T) {
|
||||
senderFunc := senderFunc(func(alerts ...*notifier.Alert) {
|
||||
require.NotEmpty(t, tc.in, "sender called with 0 alert")
|
||||
require.Equal(t, tc.exp, alerts)
|
||||
|
|
|
@ -296,7 +296,7 @@ func (p *queryLogTest) run(t *testing.T) {
|
|||
if p.exactQueryCount() {
|
||||
require.Equal(t, 1, qc)
|
||||
} else {
|
||||
require.Greater(t, qc, 0, "no queries logged")
|
||||
require.Positive(t, qc, "no queries logged")
|
||||
}
|
||||
p.validateLastQuery(t, ql)
|
||||
|
||||
|
@ -366,7 +366,7 @@ func (p *queryLogTest) run(t *testing.T) {
|
|||
if p.exactQueryCount() {
|
||||
require.Equal(t, 1, qc)
|
||||
} else {
|
||||
require.Greater(t, qc, 0, "no queries logged")
|
||||
require.Positive(t, qc, "no queries logged")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -88,7 +88,7 @@ func createBlocks(input []byte, mint, maxt, maxBlockDuration int64, maxSamplesIn
|
|||
blockDuration := getCompatibleBlockDuration(maxBlockDuration)
|
||||
mint = blockDuration * (mint / blockDuration)
|
||||
|
||||
db, err := tsdb.OpenDBReadOnly(outputDir, nil)
|
||||
db, err := tsdb.OpenDBReadOnly(outputDir, "", nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -235,12 +235,14 @@ func main() {
|
|||
|
||||
tsdbDumpCmd := tsdbCmd.Command("dump", "Dump samples from a TSDB.")
|
||||
dumpPath := tsdbDumpCmd.Arg("db path", "Database path (default is "+defaultDBPath+").").Default(defaultDBPath).String()
|
||||
dumpSandboxDirRoot := tsdbDumpCmd.Flag("sandbox-dir-root", "Root directory where a sandbox directory would be created in case WAL replay generates chunks. The sandbox directory is cleaned up at the end.").Default(defaultDBPath).String()
|
||||
dumpMinTime := tsdbDumpCmd.Flag("min-time", "Minimum timestamp to dump.").Default(strconv.FormatInt(math.MinInt64, 10)).Int64()
|
||||
dumpMaxTime := tsdbDumpCmd.Flag("max-time", "Maximum timestamp to dump.").Default(strconv.FormatInt(math.MaxInt64, 10)).Int64()
|
||||
dumpMatch := tsdbDumpCmd.Flag("match", "Series selector. Can be specified multiple times.").Default("{__name__=~'(?s:.*)'}").Strings()
|
||||
|
||||
tsdbDumpOpenMetricsCmd := tsdbCmd.Command("dump-openmetrics", "[Experimental] Dump samples from a TSDB into OpenMetrics format. Native histograms are not dumped.")
|
||||
tsdbDumpOpenMetricsCmd := tsdbCmd.Command("dump-openmetrics", "[Experimental] Dump samples from a TSDB into OpenMetrics text format, excluding native histograms and staleness markers, which are not representable in OpenMetrics.")
|
||||
dumpOpenMetricsPath := tsdbDumpOpenMetricsCmd.Arg("db path", "Database path (default is "+defaultDBPath+").").Default(defaultDBPath).String()
|
||||
dumpOpenMetricsSandboxDirRoot := tsdbDumpOpenMetricsCmd.Flag("sandbox-dir-root", "Root directory where a sandbox directory would be created in case WAL replay generates chunks. The sandbox directory is cleaned up at the end.").Default(defaultDBPath).String()
|
||||
dumpOpenMetricsMinTime := tsdbDumpOpenMetricsCmd.Flag("min-time", "Minimum timestamp to dump.").Default(strconv.FormatInt(math.MinInt64, 10)).Int64()
|
||||
dumpOpenMetricsMaxTime := tsdbDumpOpenMetricsCmd.Flag("max-time", "Maximum timestamp to dump.").Default(strconv.FormatInt(math.MaxInt64, 10)).Int64()
|
||||
dumpOpenMetricsMatch := tsdbDumpOpenMetricsCmd.Flag("match", "Series selector. Can be specified multiple times.").Default("{__name__=~'(?s:.*)'}").Strings()
|
||||
|
@ -396,9 +398,9 @@ func main() {
|
|||
os.Exit(checkErr(listBlocks(*listPath, *listHumanReadable)))
|
||||
|
||||
case tsdbDumpCmd.FullCommand():
|
||||
os.Exit(checkErr(dumpSamples(ctx, *dumpPath, *dumpMinTime, *dumpMaxTime, *dumpMatch, formatSeriesSet)))
|
||||
os.Exit(checkErr(dumpSamples(ctx, *dumpPath, *dumpSandboxDirRoot, *dumpMinTime, *dumpMaxTime, *dumpMatch, formatSeriesSet)))
|
||||
case tsdbDumpOpenMetricsCmd.FullCommand():
|
||||
os.Exit(checkErr(dumpSamples(ctx, *dumpOpenMetricsPath, *dumpOpenMetricsMinTime, *dumpOpenMetricsMaxTime, *dumpOpenMetricsMatch, formatSeriesSetOpenMetrics)))
|
||||
os.Exit(checkErr(dumpSamples(ctx, *dumpOpenMetricsPath, *dumpOpenMetricsSandboxDirRoot, *dumpOpenMetricsMinTime, *dumpOpenMetricsMaxTime, *dumpOpenMetricsMatch, formatSeriesSetOpenMetrics)))
|
||||
// TODO(aSquare14): Work on adding support for custom block size.
|
||||
case openMetricsImportCmd.FullCommand():
|
||||
os.Exit(backfillOpenMetrics(*importFilePath, *importDBPath, *importHumanReadable, *importQuiet, *maxBlockDuration))
|
||||
|
|
|
@ -25,6 +25,7 @@ import (
|
|||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
"testing"
|
||||
|
@ -410,7 +411,7 @@ func TestExitCodes(t *testing.T) {
|
|||
} {
|
||||
t.Run(c.file, func(t *testing.T) {
|
||||
for _, lintFatal := range []bool{true, false} {
|
||||
t.Run(fmt.Sprintf("%t", lintFatal), func(t *testing.T) {
|
||||
t.Run(strconv.FormatBool(lintFatal), func(t *testing.T) {
|
||||
args := []string{"-test.main", "check", "config", "testdata/" + c.file}
|
||||
if lintFatal {
|
||||
args = append(args, "--lint-fatal")
|
||||
|
|
|
@ -338,7 +338,7 @@ func readPrometheusLabels(r io.Reader, n int) ([]labels.Labels, error) {
|
|||
}
|
||||
|
||||
func listBlocks(path string, humanReadable bool) error {
|
||||
db, err := tsdb.OpenDBReadOnly(path, nil)
|
||||
db, err := tsdb.OpenDBReadOnly(path, "", nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -393,7 +393,7 @@ func getFormatedBytes(bytes int64, humanReadable bool) string {
|
|||
}
|
||||
|
||||
func openBlock(path, blockID string) (*tsdb.DBReadOnly, tsdb.BlockReader, error) {
|
||||
db, err := tsdb.OpenDBReadOnly(path, nil)
|
||||
db, err := tsdb.OpenDBReadOnly(path, "", nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
@ -708,8 +708,8 @@ func analyzeCompaction(ctx context.Context, block tsdb.BlockReader, indexr tsdb.
|
|||
|
||||
type SeriesSetFormatter func(series storage.SeriesSet) error
|
||||
|
||||
func dumpSamples(ctx context.Context, path string, mint, maxt int64, match []string, formatter SeriesSetFormatter) (err error) {
|
||||
db, err := tsdb.OpenDBReadOnly(path, nil)
|
||||
func dumpSamples(ctx context.Context, dbDir, sandboxDirRoot string, mint, maxt int64, match []string, formatter SeriesSetFormatter) (err error) {
|
||||
db, err := tsdb.OpenDBReadOnly(dbDir, sandboxDirRoot, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -856,9 +856,9 @@ func displayHistogram(dataType string, datas []int, total int) {
|
|||
}
|
||||
avg := sum / len(datas)
|
||||
fmt.Printf("%s (min/avg/max): %d/%d/%d\n", dataType, datas[0], avg, datas[len(datas)-1])
|
||||
maxLeftLen := strconv.Itoa(len(fmt.Sprintf("%d", end)))
|
||||
maxRightLen := strconv.Itoa(len(fmt.Sprintf("%d", end+step)))
|
||||
maxCountLen := strconv.Itoa(len(fmt.Sprintf("%d", maxCount)))
|
||||
maxLeftLen := strconv.Itoa(len(strconv.Itoa(end)))
|
||||
maxRightLen := strconv.Itoa(len(strconv.Itoa(end + step)))
|
||||
maxCountLen := strconv.Itoa(len(strconv.Itoa(maxCount)))
|
||||
for bucket, count := range buckets {
|
||||
percentage := 100.0 * count / total
|
||||
fmt.Printf("[%"+maxLeftLen+"d, %"+maxRightLen+"d]: %"+maxCountLen+"d %s\n", bucket*step+start+1, (bucket+1)*step+start, count, strings.Repeat("#", percentage))
|
||||
|
|
|
@ -64,6 +64,7 @@ func getDumpedSamples(t *testing.T, path string, mint, maxt int64, match []strin
|
|||
err := dumpSamples(
|
||||
context.Background(),
|
||||
path,
|
||||
t.TempDir(),
|
||||
mint,
|
||||
maxt,
|
||||
match,
|
||||
|
|
|
@ -573,7 +573,7 @@ func (la labelsAndAnnotations) String() string {
|
|||
}
|
||||
s := "[\n0:" + indentLines("\n"+la[0].String(), " ")
|
||||
for i, l := range la[1:] {
|
||||
s += ",\n" + fmt.Sprintf("%d", i+1) + ":" + indentLines("\n"+l.String(), " ")
|
||||
s += ",\n" + strconv.Itoa(i+1) + ":" + indentLines("\n"+l.String(), " ")
|
||||
}
|
||||
s += "\n]"
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ import (
|
|||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
|
@ -145,11 +146,17 @@ var (
|
|||
ScrapeInterval: model.Duration(1 * time.Minute),
|
||||
ScrapeTimeout: model.Duration(10 * time.Second),
|
||||
EvaluationInterval: model.Duration(1 * time.Minute),
|
||||
RuleQueryOffset: model.Duration(0 * time.Minute),
|
||||
// When native histogram feature flag is enabled, ScrapeProtocols default
|
||||
// changes to DefaultNativeHistogramScrapeProtocols.
|
||||
ScrapeProtocols: DefaultScrapeProtocols,
|
||||
}
|
||||
|
||||
DefaultRuntimeConfig = RuntimeConfig{
|
||||
// Go runtime tuning.
|
||||
GoGC: 50,
|
||||
}
|
||||
|
||||
// DefaultScrapeConfig is the default scrape configuration.
|
||||
DefaultScrapeConfig = ScrapeConfig{
|
||||
// ScrapeTimeout, ScrapeInterval and ScrapeProtocols default to the configured globals.
|
||||
|
@ -224,6 +231,7 @@ var (
|
|||
// Config is the top-level configuration for Prometheus's config files.
|
||||
type Config struct {
|
||||
GlobalConfig GlobalConfig `yaml:"global"`
|
||||
Runtime RuntimeConfig `yaml:"runtime,omitempty"`
|
||||
AlertingConfig AlertingConfig `yaml:"alerting,omitempty"`
|
||||
RuleFiles []string `yaml:"rule_files,omitempty"`
|
||||
ScrapeConfigFiles []string `yaml:"scrape_config_files,omitempty"`
|
||||
|
@ -334,6 +342,14 @@ func (c *Config) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
|||
c.GlobalConfig = DefaultGlobalConfig
|
||||
}
|
||||
|
||||
// If a runtime block was open but empty the default runtime config is overwritten.
|
||||
// We have to restore it here.
|
||||
if c.Runtime.isZero() {
|
||||
c.Runtime = DefaultRuntimeConfig
|
||||
// Use the GOGC env var value if the runtime section is empty.
|
||||
c.Runtime.GoGC = getGoGCEnv()
|
||||
}
|
||||
|
||||
for _, rf := range c.RuleFiles {
|
||||
if !patRulePath.MatchString(rf) {
|
||||
return fmt.Errorf("invalid rule file path %q", rf)
|
||||
|
@ -397,6 +413,8 @@ type GlobalConfig struct {
|
|||
ScrapeProtocols []ScrapeProtocol `yaml:"scrape_protocols,omitempty"`
|
||||
// How frequently to evaluate rules by default.
|
||||
EvaluationInterval model.Duration `yaml:"evaluation_interval,omitempty"`
|
||||
// Offset the rule evaluation timestamp of this particular group by the specified duration into the past to ensure the underlying metrics have been received.
|
||||
RuleQueryOffset model.Duration `yaml:"rule_query_offset,omitempty"`
|
||||
// File to which PromQL queries are logged.
|
||||
QueryLogFile string `yaml:"query_log_file,omitempty"`
|
||||
// The labels to add to any timeseries that this Prometheus instance scrapes.
|
||||
|
@ -556,10 +574,22 @@ func (c *GlobalConfig) isZero() bool {
|
|||
c.ScrapeInterval == 0 &&
|
||||
c.ScrapeTimeout == 0 &&
|
||||
c.EvaluationInterval == 0 &&
|
||||
c.RuleQueryOffset == 0 &&
|
||||
c.QueryLogFile == "" &&
|
||||
c.ScrapeProtocols == nil
|
||||
}
|
||||
|
||||
// RuntimeConfig configures the values for the process behavior.
|
||||
type RuntimeConfig struct {
|
||||
// The Go garbage collection target percentage.
|
||||
GoGC int `yaml:"gogc,omitempty"`
|
||||
}
|
||||
|
||||
// isZero returns true iff the global config is the zero value.
|
||||
func (c *RuntimeConfig) isZero() bool {
|
||||
return c.GoGC == 0
|
||||
}
|
||||
|
||||
type ScrapeConfigs struct {
|
||||
ScrapeConfigs []*ScrapeConfig `yaml:"scrape_configs,omitempty"`
|
||||
}
|
||||
|
@ -1207,3 +1237,19 @@ func filePath(filename string) string {
|
|||
func fileErr(filename string, err error) error {
|
||||
return fmt.Errorf("%q: %w", filePath(filename), err)
|
||||
}
|
||||
|
||||
func getGoGCEnv() int {
|
||||
goGCEnv := os.Getenv("GOGC")
|
||||
// If the GOGC env var is set, use the same logic as upstream Go.
|
||||
if goGCEnv != "" {
|
||||
// Special case for GOGC=off.
|
||||
if strings.ToLower(goGCEnv) == "off" {
|
||||
return -1
|
||||
}
|
||||
i, err := strconv.Atoi(goGCEnv)
|
||||
if err == nil {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return DefaultRuntimeConfig.GoGC
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ const ruleFilesConfigFile = "testdata/rules_abs_path.good.yml"
|
|||
|
||||
var ruleFilesExpectedConf = &Config{
|
||||
GlobalConfig: DefaultGlobalConfig,
|
||||
Runtime: DefaultRuntimeConfig,
|
||||
RuleFiles: []string{
|
||||
"testdata/first.rules",
|
||||
"testdata/rules/second.rules",
|
||||
|
|
|
@ -76,6 +76,7 @@ const (
|
|||
globLabelLimit = 30
|
||||
globLabelNameLengthLimit = 200
|
||||
globLabelValueLengthLimit = 200
|
||||
globalGoGC = 42
|
||||
)
|
||||
|
||||
var expectedConf = &Config{
|
||||
|
@ -96,6 +97,10 @@ var expectedConf = &Config{
|
|||
ScrapeProtocols: DefaultGlobalConfig.ScrapeProtocols,
|
||||
},
|
||||
|
||||
Runtime: RuntimeConfig{
|
||||
GoGC: globalGoGC,
|
||||
},
|
||||
|
||||
RuleFiles: []string{
|
||||
filepath.FromSlash("testdata/first.rules"),
|
||||
filepath.FromSlash("testdata/my/*.rules"),
|
||||
|
@ -2081,6 +2086,7 @@ func TestEmptyGlobalBlock(t *testing.T) {
|
|||
c, err := Load("global:\n", false, log.NewNopLogger())
|
||||
require.NoError(t, err)
|
||||
exp := DefaultConfig
|
||||
exp.Runtime = DefaultRuntimeConfig
|
||||
require.Equal(t, exp, *c)
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ const ruleFilesConfigFile = "testdata/rules_abs_path_windows.good.yml"
|
|||
|
||||
var ruleFilesExpectedConf = &Config{
|
||||
GlobalConfig: DefaultGlobalConfig,
|
||||
Runtime: DefaultRuntimeConfig,
|
||||
RuleFiles: []string{
|
||||
"testdata\\first.rules",
|
||||
"testdata\\rules\\second.rules",
|
||||
|
|
3
config/testdata/conf.good.yml
vendored
3
config/testdata/conf.good.yml
vendored
|
@ -14,6 +14,9 @@ global:
|
|||
monitor: codelab
|
||||
foo: bar
|
||||
|
||||
runtime:
|
||||
gogc: 42
|
||||
|
||||
rule_files:
|
||||
- "first.rules"
|
||||
- "my/*.rules"
|
||||
|
|
|
@ -18,6 +18,7 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
|
@ -279,7 +280,7 @@ func (d *EC2Discovery) refresh(ctx context.Context) ([]*targetgroup.Group, error
|
|||
if inst.PrivateDnsName != nil {
|
||||
labels[ec2LabelPrivateDNS] = model.LabelValue(*inst.PrivateDnsName)
|
||||
}
|
||||
addr := net.JoinHostPort(*inst.PrivateIpAddress, fmt.Sprintf("%d", d.cfg.Port))
|
||||
addr := net.JoinHostPort(*inst.PrivateIpAddress, strconv.Itoa(d.cfg.Port))
|
||||
labels[model.AddressLabel] = model.LabelValue(addr)
|
||||
|
||||
if inst.Platform != nil {
|
||||
|
|
|
@ -18,6 +18,7 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
|
@ -229,7 +230,7 @@ func (d *LightsailDiscovery) refresh(ctx context.Context) ([]*targetgroup.Group,
|
|||
lightsailLabelRegion: model.LabelValue(d.cfg.Region),
|
||||
}
|
||||
|
||||
addr := net.JoinHostPort(*inst.PrivateIpAddress, fmt.Sprintf("%d", d.cfg.Port))
|
||||
addr := net.JoinHostPort(*inst.PrivateIpAddress, strconv.Itoa(d.cfg.Port))
|
||||
labels[model.AddressLabel] = model.LabelValue(addr)
|
||||
|
||||
if inst.PublicIpAddress != nil {
|
||||
|
|
|
@ -20,6 +20,7 @@ import (
|
|||
"math/rand"
|
||||
"net"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
@ -492,7 +493,7 @@ func (d *Discovery) vmToLabelSet(ctx context.Context, client client, vm virtualM
|
|||
}
|
||||
if ip.Properties != nil && ip.Properties.PrivateIPAddress != nil {
|
||||
labels[azureLabelMachinePrivateIP] = model.LabelValue(*ip.Properties.PrivateIPAddress)
|
||||
address := net.JoinHostPort(*ip.Properties.PrivateIPAddress, fmt.Sprintf("%d", d.port))
|
||||
address := net.JoinHostPort(*ip.Properties.PrivateIPAddress, strconv.Itoa(d.port))
|
||||
labels[model.AddressLabel] = model.LabelValue(address)
|
||||
return labels, nil
|
||||
}
|
||||
|
|
|
@ -539,9 +539,9 @@ func (srv *consulService) watch(ctx context.Context, ch chan<- []*targetgroup.Gr
|
|||
// since the service may be registered remotely through a different node.
|
||||
var addr string
|
||||
if serviceNode.Service.Address != "" {
|
||||
addr = net.JoinHostPort(serviceNode.Service.Address, fmt.Sprintf("%d", serviceNode.Service.Port))
|
||||
addr = net.JoinHostPort(serviceNode.Service.Address, strconv.Itoa(serviceNode.Service.Port))
|
||||
} else {
|
||||
addr = net.JoinHostPort(serviceNode.Node.Address, fmt.Sprintf("%d", serviceNode.Service.Port))
|
||||
addr = net.JoinHostPort(serviceNode.Node.Address, strconv.Itoa(serviceNode.Service.Port))
|
||||
}
|
||||
|
||||
labels := model.LabelSet{
|
||||
|
|
|
@ -177,7 +177,7 @@ func (d *Discovery) refresh(ctx context.Context) ([]*targetgroup.Group, error) {
|
|||
}
|
||||
|
||||
labels := model.LabelSet{
|
||||
doLabelID: model.LabelValue(fmt.Sprintf("%d", droplet.ID)),
|
||||
doLabelID: model.LabelValue(strconv.Itoa(droplet.ID)),
|
||||
doLabelName: model.LabelValue(droplet.Name),
|
||||
doLabelImage: model.LabelValue(droplet.Image.Slug),
|
||||
doLabelImageName: model.LabelValue(droplet.Image.Name),
|
||||
|
|
|
@ -18,6 +18,7 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
@ -200,7 +201,7 @@ func (d *Discovery) refreshOne(ctx context.Context, name string, ch chan<- *targ
|
|||
|
||||
tg := &targetgroup.Group{}
|
||||
hostPort := func(a string, p int) model.LabelValue {
|
||||
return model.LabelValue(net.JoinHostPort(a, fmt.Sprintf("%d", p)))
|
||||
return model.LabelValue(net.JoinHostPort(a, strconv.Itoa(p)))
|
||||
}
|
||||
|
||||
for _, record := range response.Answer {
|
||||
|
@ -209,7 +210,7 @@ func (d *Discovery) refreshOne(ctx context.Context, name string, ch chan<- *targ
|
|||
switch addr := record.(type) {
|
||||
case *dns.SRV:
|
||||
dnsSrvRecordTarget = model.LabelValue(addr.Target)
|
||||
dnsSrvRecordPort = model.LabelValue(fmt.Sprintf("%d", addr.Port))
|
||||
dnsSrvRecordPort = model.LabelValue(strconv.Itoa(int(addr.Port)))
|
||||
|
||||
// Remove the final dot from rooted DNS names to make them look more usual.
|
||||
addr.Target = strings.TrimRight(addr.Target, ".")
|
||||
|
|
|
@ -15,7 +15,6 @@ package hetzner
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
@ -92,7 +91,7 @@ func (d *hcloudDiscovery) refresh(ctx context.Context) ([]*targetgroup.Group, er
|
|||
for i, server := range servers {
|
||||
labels := model.LabelSet{
|
||||
hetznerLabelRole: model.LabelValue(HetznerRoleHcloud),
|
||||
hetznerLabelServerID: model.LabelValue(fmt.Sprintf("%d", server.ID)),
|
||||
hetznerLabelServerID: model.LabelValue(strconv.FormatInt(server.ID, 10)),
|
||||
hetznerLabelServerName: model.LabelValue(server.Name),
|
||||
hetznerLabelDatacenter: model.LabelValue(server.Datacenter.Name),
|
||||
hetznerLabelPublicIPv4: model.LabelValue(server.PublicNet.IPv4.IP.String()),
|
||||
|
@ -102,10 +101,10 @@ func (d *hcloudDiscovery) refresh(ctx context.Context) ([]*targetgroup.Group, er
|
|||
hetznerLabelHcloudDatacenterLocation: model.LabelValue(server.Datacenter.Location.Name),
|
||||
hetznerLabelHcloudDatacenterLocationNetworkZone: model.LabelValue(server.Datacenter.Location.NetworkZone),
|
||||
hetznerLabelHcloudType: model.LabelValue(server.ServerType.Name),
|
||||
hetznerLabelHcloudCPUCores: model.LabelValue(fmt.Sprintf("%d", server.ServerType.Cores)),
|
||||
hetznerLabelHcloudCPUCores: model.LabelValue(strconv.Itoa(server.ServerType.Cores)),
|
||||
hetznerLabelHcloudCPUType: model.LabelValue(server.ServerType.CPUType),
|
||||
hetznerLabelHcloudMemoryGB: model.LabelValue(fmt.Sprintf("%d", int(server.ServerType.Memory))),
|
||||
hetznerLabelHcloudDiskGB: model.LabelValue(fmt.Sprintf("%d", server.ServerType.Disk)),
|
||||
hetznerLabelHcloudMemoryGB: model.LabelValue(strconv.Itoa(int(server.ServerType.Memory))),
|
||||
hetznerLabelHcloudDiskGB: model.LabelValue(strconv.Itoa(server.ServerType.Disk)),
|
||||
|
||||
model.AddressLabel: model.LabelValue(net.JoinHostPort(server.PublicNet.IPv4.IP.String(), strconv.FormatUint(uint64(d.port), 10))),
|
||||
}
|
||||
|
|
|
@ -112,7 +112,7 @@ func (d *robotDiscovery) refresh(context.Context) ([]*targetgroup.Group, error)
|
|||
hetznerLabelPublicIPv4: model.LabelValue(server.Server.ServerIP),
|
||||
hetznerLabelServerStatus: model.LabelValue(server.Server.Status),
|
||||
hetznerLabelRobotProduct: model.LabelValue(server.Server.Product),
|
||||
hetznerLabelRobotCancelled: model.LabelValue(fmt.Sprintf("%t", server.Server.Canceled)),
|
||||
hetznerLabelRobotCancelled: model.LabelValue(strconv.FormatBool(server.Server.Canceled)),
|
||||
|
||||
model.AddressLabel: model.LabelValue(net.JoinHostPort(server.Server.ServerIP, strconv.FormatUint(uint64(d.port), 10))),
|
||||
}
|
||||
|
|
|
@ -720,7 +720,7 @@ func staticConfig(addrs ...string) discovery.StaticConfig {
|
|||
var cfg discovery.StaticConfig
|
||||
for i, addr := range addrs {
|
||||
cfg = append(cfg, &targetgroup.Group{
|
||||
Source: fmt.Sprint(i),
|
||||
Source: strconv.Itoa(i),
|
||||
Targets: []model.LabelSet{
|
||||
{model.AddressLabel: model.LabelValue(addr)},
|
||||
},
|
||||
|
|
|
@ -186,12 +186,12 @@ func (d *Discovery) refresh(ctx context.Context) ([]*targetgroup.Group, error) {
|
|||
|
||||
if d.lastResults != nil && d.eventPollingEnabled {
|
||||
// Check to see if there have been any events. If so, refresh our data.
|
||||
opts := linodego.ListOptions{
|
||||
eventsOpts := linodego.ListOptions{
|
||||
PageOptions: &linodego.PageOptions{Page: 1},
|
||||
PageSize: 25,
|
||||
Filter: fmt.Sprintf(filterTemplate, d.lastRefreshTimestamp.Format("2006-01-02T15:04:05")),
|
||||
}
|
||||
events, err := d.client.ListEvents(ctx, &opts)
|
||||
events, err := d.client.ListEvents(ctx, &eventsOpts)
|
||||
if err != nil {
|
||||
var e *linodego.Error
|
||||
if errors.As(err, &e) && e.Code == http.StatusUnauthorized {
|
||||
|
@ -232,31 +232,40 @@ func (d *Discovery) refreshData(ctx context.Context) ([]*targetgroup.Group, erro
|
|||
tg := &targetgroup.Group{
|
||||
Source: "Linode",
|
||||
}
|
||||
opts := linodego.ListOptions{
|
||||
// We need 3 of these because Linodego writes into the structure during pagination
|
||||
listInstancesOpts := linodego.ListOptions{
|
||||
PageSize: 500,
|
||||
}
|
||||
listIPAddressesOpts := linodego.ListOptions{
|
||||
PageSize: 500,
|
||||
}
|
||||
listIPv6RangesOpts := linodego.ListOptions{
|
||||
PageSize: 500,
|
||||
}
|
||||
|
||||
// If region filter provided, use it to constrain results.
|
||||
if d.region != "" {
|
||||
opts.Filter = fmt.Sprintf(regionFilterTemplate, d.region)
|
||||
listInstancesOpts.Filter = fmt.Sprintf(regionFilterTemplate, d.region)
|
||||
listIPAddressesOpts.Filter = fmt.Sprintf(regionFilterTemplate, d.region)
|
||||
listIPv6RangesOpts.Filter = fmt.Sprintf(regionFilterTemplate, d.region)
|
||||
}
|
||||
|
||||
// Gather all linode instances.
|
||||
instances, err := d.client.ListInstances(ctx, &opts)
|
||||
instances, err := d.client.ListInstances(ctx, &listInstancesOpts)
|
||||
if err != nil {
|
||||
d.metrics.failuresCount.Inc()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Gather detailed IP address info for all IPs on all linode instances.
|
||||
detailedIPs, err := d.client.ListIPAddresses(ctx, &opts)
|
||||
detailedIPs, err := d.client.ListIPAddresses(ctx, &listIPAddressesOpts)
|
||||
if err != nil {
|
||||
d.metrics.failuresCount.Inc()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Gather detailed IPv6 Range info for all linode instances.
|
||||
ipv6RangeList, err := d.client.ListIPv6Ranges(ctx, &opts)
|
||||
ipv6RangeList, err := d.client.ListIPv6Ranges(ctx, &listIPv6RangesOpts)
|
||||
if err != nil {
|
||||
d.metrics.failuresCount.Inc()
|
||||
return nil, err
|
||||
|
@ -325,7 +334,7 @@ func (d *Discovery) refreshData(ctx context.Context) ([]*targetgroup.Group, erro
|
|||
}
|
||||
|
||||
labels := model.LabelSet{
|
||||
linodeLabelID: model.LabelValue(fmt.Sprintf("%d", instance.ID)),
|
||||
linodeLabelID: model.LabelValue(strconv.Itoa(instance.ID)),
|
||||
linodeLabelName: model.LabelValue(instance.Label),
|
||||
linodeLabelImage: model.LabelValue(instance.Image),
|
||||
linodeLabelPrivateIPv4: model.LabelValue(privateIPv4),
|
||||
|
@ -338,13 +347,13 @@ func (d *Discovery) refreshData(ctx context.Context) ([]*targetgroup.Group, erro
|
|||
linodeLabelType: model.LabelValue(instance.Type),
|
||||
linodeLabelStatus: model.LabelValue(instance.Status),
|
||||
linodeLabelGroup: model.LabelValue(instance.Group),
|
||||
linodeLabelGPUs: model.LabelValue(fmt.Sprintf("%d", instance.Specs.GPUs)),
|
||||
linodeLabelGPUs: model.LabelValue(strconv.Itoa(instance.Specs.GPUs)),
|
||||
linodeLabelHypervisor: model.LabelValue(instance.Hypervisor),
|
||||
linodeLabelBackups: model.LabelValue(backupsStatus),
|
||||
linodeLabelSpecsDiskBytes: model.LabelValue(fmt.Sprintf("%d", int64(instance.Specs.Disk)<<20)),
|
||||
linodeLabelSpecsMemoryBytes: model.LabelValue(fmt.Sprintf("%d", int64(instance.Specs.Memory)<<20)),
|
||||
linodeLabelSpecsVCPUs: model.LabelValue(fmt.Sprintf("%d", instance.Specs.VCPUs)),
|
||||
linodeLabelSpecsTransferBytes: model.LabelValue(fmt.Sprintf("%d", int64(instance.Specs.Transfer)<<20)),
|
||||
linodeLabelSpecsDiskBytes: model.LabelValue(strconv.FormatInt(int64(instance.Specs.Disk)<<20, 10)),
|
||||
linodeLabelSpecsMemoryBytes: model.LabelValue(strconv.FormatInt(int64(instance.Specs.Memory)<<20, 10)),
|
||||
linodeLabelSpecsVCPUs: model.LabelValue(strconv.Itoa(instance.Specs.VCPUs)),
|
||||
linodeLabelSpecsTransferBytes: model.LabelValue(strconv.FormatInt(int64(instance.Specs.Transfer)<<20, 10)),
|
||||
}
|
||||
|
||||
addr := net.JoinHostPort(publicIPv4, strconv.FormatUint(uint64(d.port), 10))
|
||||
|
|
|
@ -720,7 +720,7 @@ func staticConfig(addrs ...string) StaticConfig {
|
|||
var cfg StaticConfig
|
||||
for i, addr := range addrs {
|
||||
cfg = append(cfg, &targetgroup.Group{
|
||||
Source: fmt.Sprint(i),
|
||||
Source: strconv.Itoa(i),
|
||||
Targets: []model.LabelSet{
|
||||
{model.AddressLabel: model.LabelValue(addr)},
|
||||
},
|
||||
|
|
|
@ -505,7 +505,7 @@ func targetEndpoint(task *task, port uint32, containerNet bool) string {
|
|||
host = task.Host
|
||||
}
|
||||
|
||||
return net.JoinHostPort(host, fmt.Sprintf("%d", port))
|
||||
return net.JoinHostPort(host, strconv.Itoa(int(port)))
|
||||
}
|
||||
|
||||
// Get a list of ports and a list of labels from a PortMapping.
|
||||
|
|
|
@ -15,7 +15,7 @@ package moby
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/client"
|
||||
|
@ -44,8 +44,8 @@ func getNetworksLabels(ctx context.Context, client *client.Client, labelPrefix s
|
|||
labelPrefix + labelNetworkID: network.ID,
|
||||
labelPrefix + labelNetworkName: network.Name,
|
||||
labelPrefix + labelNetworkScope: network.Scope,
|
||||
labelPrefix + labelNetworkInternal: fmt.Sprintf("%t", network.Internal),
|
||||
labelPrefix + labelNetworkIngress: fmt.Sprintf("%t", network.Ingress),
|
||||
labelPrefix + labelNetworkInternal: strconv.FormatBool(network.Internal),
|
||||
labelPrefix + labelNetworkIngress: strconv.FormatBool(network.Ingress),
|
||||
}
|
||||
for k, v := range network.Labels {
|
||||
ln := strutil.SanitizeLabelName(k)
|
||||
|
|
|
@ -66,7 +66,7 @@ func (d *Discovery) refreshNodes(ctx context.Context) ([]*targetgroup.Group, err
|
|||
swarmLabelNodeAddress: model.LabelValue(n.Status.Addr),
|
||||
}
|
||||
if n.ManagerStatus != nil {
|
||||
labels[swarmLabelNodeManagerLeader] = model.LabelValue(fmt.Sprintf("%t", n.ManagerStatus.Leader))
|
||||
labels[swarmLabelNodeManagerLeader] = model.LabelValue(strconv.FormatBool(n.ManagerStatus.Leader))
|
||||
labels[swarmLabelNodeManagerReachability] = model.LabelValue(n.ManagerStatus.Reachability)
|
||||
labels[swarmLabelNodeManagerAddr] = model.LabelValue(n.ManagerStatus.Addr)
|
||||
}
|
||||
|
|
|
@ -116,7 +116,7 @@ func (d *Discovery) refreshServices(ctx context.Context) ([]*targetgroup.Group,
|
|||
labels[model.LabelName(k)] = model.LabelValue(v)
|
||||
}
|
||||
|
||||
addr := net.JoinHostPort(ip.String(), fmt.Sprintf("%d", d.port))
|
||||
addr := net.JoinHostPort(ip.String(), strconv.Itoa(d.port))
|
||||
labels[model.AddressLabel] = model.LabelValue(addr)
|
||||
|
||||
tg.Targets = append(tg.Targets, labels)
|
||||
|
|
|
@ -150,7 +150,7 @@ func (d *Discovery) refreshTasks(ctx context.Context) ([]*targetgroup.Group, err
|
|||
labels[model.LabelName(k)] = model.LabelValue(v)
|
||||
}
|
||||
|
||||
addr := net.JoinHostPort(ip.String(), fmt.Sprintf("%d", d.port))
|
||||
addr := net.JoinHostPort(ip.String(), strconv.Itoa(d.port))
|
||||
labels[model.AddressLabel] = model.LabelValue(addr)
|
||||
|
||||
tg.Targets = append(tg.Targets, labels)
|
||||
|
|
|
@ -17,6 +17,7 @@ import (
|
|||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"strconv"
|
||||
|
||||
"github.com/go-kit/log"
|
||||
"github.com/gophercloud/gophercloud"
|
||||
|
@ -72,7 +73,7 @@ func (h *HypervisorDiscovery) refresh(ctx context.Context) ([]*targetgroup.Group
|
|||
}
|
||||
|
||||
tg := &targetgroup.Group{
|
||||
Source: fmt.Sprintf("OS_" + h.region),
|
||||
Source: "OS_" + h.region,
|
||||
}
|
||||
// OpenStack API reference
|
||||
// https://developer.openstack.org/api-ref/compute/#list-hypervisors-details
|
||||
|
@ -84,7 +85,7 @@ func (h *HypervisorDiscovery) refresh(ctx context.Context) ([]*targetgroup.Group
|
|||
}
|
||||
for _, hypervisor := range hypervisorList {
|
||||
labels := model.LabelSet{}
|
||||
addr := net.JoinHostPort(hypervisor.HostIP, fmt.Sprintf("%d", h.port))
|
||||
addr := net.JoinHostPort(hypervisor.HostIP, strconv.Itoa(h.port))
|
||||
labels[model.AddressLabel] = model.LabelValue(addr)
|
||||
labels[openstackLabelHypervisorID] = model.LabelValue(hypervisor.ID)
|
||||
labels[openstackLabelHypervisorHostName] = model.LabelValue(hypervisor.HypervisorHostname)
|
||||
|
|
|
@ -17,6 +17,7 @@ import (
|
|||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"strconv"
|
||||
|
||||
"github.com/go-kit/log"
|
||||
"github.com/go-kit/log/level"
|
||||
|
@ -120,7 +121,7 @@ func (i *InstanceDiscovery) refresh(ctx context.Context) ([]*targetgroup.Group,
|
|||
}
|
||||
pager := servers.List(client, opts)
|
||||
tg := &targetgroup.Group{
|
||||
Source: fmt.Sprintf("OS_" + i.region),
|
||||
Source: "OS_" + i.region,
|
||||
}
|
||||
err = pager.EachPage(func(page pagination.Page) (bool, error) {
|
||||
if ctx.Err() != nil {
|
||||
|
@ -194,7 +195,7 @@ func (i *InstanceDiscovery) refresh(ctx context.Context) ([]*targetgroup.Group,
|
|||
if val, ok := floatingIPList[floatingIPKey{id: s.ID, fixed: addr}]; ok {
|
||||
lbls[openstackLabelPublicIP] = model.LabelValue(val)
|
||||
}
|
||||
addr = net.JoinHostPort(addr, fmt.Sprintf("%d", i.port))
|
||||
addr = net.JoinHostPort(addr, strconv.Itoa(i.port))
|
||||
lbls[model.AddressLabel] = model.LabelValue(addr)
|
||||
|
||||
tg.Targets = append(tg.Targets, lbls)
|
||||
|
|
|
@ -144,12 +144,12 @@ func (d *dedicatedServerDiscovery) refresh(context.Context) ([]*targetgroup.Grou
|
|||
model.InstanceLabel: model.LabelValue(server.Name),
|
||||
dedicatedServerLabelPrefix + "state": model.LabelValue(server.State),
|
||||
dedicatedServerLabelPrefix + "commercial_range": model.LabelValue(server.CommercialRange),
|
||||
dedicatedServerLabelPrefix + "link_speed": model.LabelValue(fmt.Sprintf("%d", server.LinkSpeed)),
|
||||
dedicatedServerLabelPrefix + "link_speed": model.LabelValue(strconv.Itoa(server.LinkSpeed)),
|
||||
dedicatedServerLabelPrefix + "rack": model.LabelValue(server.Rack),
|
||||
dedicatedServerLabelPrefix + "no_intervention": model.LabelValue(strconv.FormatBool(server.NoIntervention)),
|
||||
dedicatedServerLabelPrefix + "os": model.LabelValue(server.Os),
|
||||
dedicatedServerLabelPrefix + "support_level": model.LabelValue(server.SupportLevel),
|
||||
dedicatedServerLabelPrefix + "server_id": model.LabelValue(fmt.Sprintf("%d", server.ServerID)),
|
||||
dedicatedServerLabelPrefix + "server_id": model.LabelValue(strconv.FormatInt(server.ServerID, 10)),
|
||||
dedicatedServerLabelPrefix + "reverse": model.LabelValue(server.Reverse),
|
||||
dedicatedServerLabelPrefix + "datacenter": model.LabelValue(server.Datacenter),
|
||||
dedicatedServerLabelPrefix + "name": model.LabelValue(server.Name),
|
||||
|
|
|
@ -66,7 +66,7 @@ endpoint: %s
|
|||
|
||||
_, err := createClient(&conf)
|
||||
|
||||
require.ErrorContains(t, err, "missing application key")
|
||||
require.ErrorContains(t, err, "missing authentication information")
|
||||
}
|
||||
|
||||
func TestParseIPs(t *testing.T) {
|
||||
|
|
|
@ -19,6 +19,7 @@ import (
|
|||
"net/netip"
|
||||
"net/url"
|
||||
"path"
|
||||
"strconv"
|
||||
|
||||
"github.com/go-kit/log"
|
||||
"github.com/go-kit/log/level"
|
||||
|
@ -161,21 +162,21 @@ func (d *vpsDiscovery) refresh(context.Context) ([]*targetgroup.Group, error) {
|
|||
model.InstanceLabel: model.LabelValue(server.Name),
|
||||
vpsLabelPrefix + "offer": model.LabelValue(server.Model.Offer),
|
||||
vpsLabelPrefix + "datacenter": model.LabelValue(fmt.Sprintf("%+v", server.Model.Datacenter)),
|
||||
vpsLabelPrefix + "model_vcore": model.LabelValue(fmt.Sprintf("%d", server.Model.Vcore)),
|
||||
vpsLabelPrefix + "maximum_additional_ip": model.LabelValue(fmt.Sprintf("%d", server.Model.MaximumAdditionalIP)),
|
||||
vpsLabelPrefix + "model_vcore": model.LabelValue(strconv.Itoa(server.Model.Vcore)),
|
||||
vpsLabelPrefix + "maximum_additional_ip": model.LabelValue(strconv.Itoa(server.Model.MaximumAdditionalIP)),
|
||||
vpsLabelPrefix + "version": model.LabelValue(server.Model.Version),
|
||||
vpsLabelPrefix + "model_name": model.LabelValue(server.Model.Name),
|
||||
vpsLabelPrefix + "disk": model.LabelValue(fmt.Sprintf("%d", server.Model.Disk)),
|
||||
vpsLabelPrefix + "memory": model.LabelValue(fmt.Sprintf("%d", server.Model.Memory)),
|
||||
vpsLabelPrefix + "disk": model.LabelValue(strconv.Itoa(server.Model.Disk)),
|
||||
vpsLabelPrefix + "memory": model.LabelValue(strconv.Itoa(server.Model.Memory)),
|
||||
vpsLabelPrefix + "zone": model.LabelValue(server.Zone),
|
||||
vpsLabelPrefix + "display_name": model.LabelValue(server.DisplayName),
|
||||
vpsLabelPrefix + "cluster": model.LabelValue(server.Cluster),
|
||||
vpsLabelPrefix + "state": model.LabelValue(server.State),
|
||||
vpsLabelPrefix + "name": model.LabelValue(server.Name),
|
||||
vpsLabelPrefix + "netboot_mode": model.LabelValue(server.NetbootMode),
|
||||
vpsLabelPrefix + "memory_limit": model.LabelValue(fmt.Sprintf("%d", server.MemoryLimit)),
|
||||
vpsLabelPrefix + "memory_limit": model.LabelValue(strconv.Itoa(server.MemoryLimit)),
|
||||
vpsLabelPrefix + "offer_type": model.LabelValue(server.OfferType),
|
||||
vpsLabelPrefix + "vcore": model.LabelValue(fmt.Sprintf("%d", server.Vcore)),
|
||||
vpsLabelPrefix + "vcore": model.LabelValue(strconv.Itoa(server.Vcore)),
|
||||
vpsLabelPrefix + "ipv4": model.LabelValue(ipv4),
|
||||
vpsLabelPrefix + "ipv6": model.LabelValue(ipv6),
|
||||
}
|
||||
|
|
|
@ -237,7 +237,7 @@ func (d *Discovery) refresh(ctx context.Context) ([]*targetgroup.Group, error) {
|
|||
pdbLabelResource: model.LabelValue(resource.Resource),
|
||||
pdbLabelType: model.LabelValue(resource.Type),
|
||||
pdbLabelTitle: model.LabelValue(resource.Title),
|
||||
pdbLabelExported: model.LabelValue(fmt.Sprintf("%t", resource.Exported)),
|
||||
pdbLabelExported: model.LabelValue(strconv.FormatBool(resource.Exported)),
|
||||
pdbLabelFile: model.LabelValue(resource.File),
|
||||
pdbLabelEnvironment: model.LabelValue(resource.Environment),
|
||||
}
|
||||
|
|
|
@ -175,14 +175,14 @@ func (d *instanceDiscovery) refresh(ctx context.Context) ([]*targetgroup.Group,
|
|||
}
|
||||
|
||||
addr := ""
|
||||
if server.IPv6 != nil {
|
||||
labels[instancePublicIPv6Label] = model.LabelValue(server.IPv6.Address.String())
|
||||
addr = server.IPv6.Address.String()
|
||||
if server.IPv6 != nil { //nolint:staticcheck
|
||||
labels[instancePublicIPv6Label] = model.LabelValue(server.IPv6.Address.String()) //nolint:staticcheck
|
||||
addr = server.IPv6.Address.String() //nolint:staticcheck
|
||||
}
|
||||
|
||||
if server.PublicIP != nil {
|
||||
labels[instancePublicIPv4Label] = model.LabelValue(server.PublicIP.Address.String())
|
||||
addr = server.PublicIP.Address.String()
|
||||
if server.PublicIP != nil { //nolint:staticcheck
|
||||
labels[instancePublicIPv4Label] = model.LabelValue(server.PublicIP.Address.String()) //nolint:staticcheck
|
||||
addr = server.PublicIP.Address.String() //nolint:staticcheck
|
||||
}
|
||||
|
||||
if server.PrivateIP != nil {
|
||||
|
|
|
@ -20,6 +20,7 @@ import (
|
|||
"net/http"
|
||||
"net/url"
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
|
@ -269,7 +270,7 @@ func (d *Discovery) getEndpointLabels(
|
|||
model.AddressLabel: model.LabelValue(addr),
|
||||
uyuniLabelMinionHostname: model.LabelValue(networkInfo.Hostname),
|
||||
uyuniLabelPrimaryFQDN: model.LabelValue(networkInfo.PrimaryFQDN),
|
||||
uyuniLablelSystemID: model.LabelValue(fmt.Sprintf("%d", endpoint.SystemID)),
|
||||
uyuniLablelSystemID: model.LabelValue(strconv.Itoa(endpoint.SystemID)),
|
||||
uyuniLablelGroups: model.LabelValue(strings.Join(managedGroupNames, d.separator)),
|
||||
uyuniLablelEndpointName: model.LabelValue(endpoint.EndpointName),
|
||||
uyuniLablelExporter: model.LabelValue(endpoint.ExporterName),
|
||||
|
|
|
@ -280,17 +280,17 @@ func parseServersetMember(data []byte, path string) (model.LabelSet, error) {
|
|||
labels := model.LabelSet{}
|
||||
labels[serversetPathLabel] = model.LabelValue(path)
|
||||
labels[model.AddressLabel] = model.LabelValue(
|
||||
net.JoinHostPort(member.ServiceEndpoint.Host, fmt.Sprintf("%d", member.ServiceEndpoint.Port)))
|
||||
net.JoinHostPort(member.ServiceEndpoint.Host, strconv.Itoa(member.ServiceEndpoint.Port)))
|
||||
|
||||
labels[serversetEndpointLabelPrefix+"_host"] = model.LabelValue(member.ServiceEndpoint.Host)
|
||||
labels[serversetEndpointLabelPrefix+"_port"] = model.LabelValue(fmt.Sprintf("%d", member.ServiceEndpoint.Port))
|
||||
labels[serversetEndpointLabelPrefix+"_port"] = model.LabelValue(strconv.Itoa(member.ServiceEndpoint.Port))
|
||||
|
||||
for name, endpoint := range member.AdditionalEndpoints {
|
||||
cleanName := model.LabelName(strutil.SanitizeLabelName(name))
|
||||
labels[serversetEndpointLabelPrefix+"_host_"+cleanName] = model.LabelValue(
|
||||
endpoint.Host)
|
||||
labels[serversetEndpointLabelPrefix+"_port_"+cleanName] = model.LabelValue(
|
||||
fmt.Sprintf("%d", endpoint.Port))
|
||||
strconv.Itoa(endpoint.Port))
|
||||
}
|
||||
|
||||
labels[serversetStatusLabel] = model.LabelValue(member.Status)
|
||||
|
@ -321,10 +321,10 @@ func parseNerveMember(data []byte, path string) (model.LabelSet, error) {
|
|||
labels := model.LabelSet{}
|
||||
labels[nervePathLabel] = model.LabelValue(path)
|
||||
labels[model.AddressLabel] = model.LabelValue(
|
||||
net.JoinHostPort(member.Host, fmt.Sprintf("%d", member.Port)))
|
||||
net.JoinHostPort(member.Host, strconv.Itoa(member.Port)))
|
||||
|
||||
labels[nerveEndpointLabelPrefix+"_host"] = model.LabelValue(member.Host)
|
||||
labels[nerveEndpointLabelPrefix+"_port"] = model.LabelValue(fmt.Sprintf("%d", member.Port))
|
||||
labels[nerveEndpointLabelPrefix+"_port"] = model.LabelValue(strconv.Itoa(member.Port))
|
||||
labels[nerveEndpointLabelPrefix+"_name"] = model.LabelValue(member.Name)
|
||||
|
||||
return labels, nil
|
||||
|
|
|
@ -48,7 +48,7 @@ The Prometheus monitoring server
|
|||
| <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` |
|
||||
| <code class="text-nowrap">--rules.max-concurrent-evals</code> | Global concurrency limit for independent rules that can run concurrently. Use with server mode only. | `4` |
|
||||
| <code class="text-nowrap">--rules.max-concurrent-evals</code> | Global concurrency limit for independent rules that can run concurrently. When set, "query.max-concurrency" may need to be adjusted accordingly. Use with server mode only. | `4` |
|
||||
| <code class="text-nowrap">--alertmanager.notification-queue-capacity</code> | The capacity of the queue for pending Alertmanager notifications. Use with server mode only. | `10000` |
|
||||
| <code class="text-nowrap">--query.lookback-delta</code> | The maximum lookback duration for retrieving metrics during expression evaluations and federation. Use with server mode only. | `5m` |
|
||||
| <code class="text-nowrap">--query.timeout</code> | Maximum time a query may take before being aborted. Use with server mode only. | `2m` |
|
||||
|
|
|
@ -566,6 +566,7 @@ Dump samples from a TSDB.
|
|||
|
||||
| Flag | Description | Default |
|
||||
| --- | --- | --- |
|
||||
| <code class="text-nowrap">--sandbox-dir-root</code> | Root directory where a sandbox directory would be created in case WAL replay generates chunks. The sandbox directory is cleaned up at the end. | `data/` |
|
||||
| <code class="text-nowrap">--min-time</code> | Minimum timestamp to dump. | `-9223372036854775808` |
|
||||
| <code class="text-nowrap">--max-time</code> | Maximum timestamp to dump. | `9223372036854775807` |
|
||||
| <code class="text-nowrap">--match</code> | Series selector. Can be specified multiple times. | `{__name__=~'(?s:.*)'}` |
|
||||
|
@ -584,7 +585,7 @@ Dump samples from a TSDB.
|
|||
|
||||
##### `promtool tsdb dump-openmetrics`
|
||||
|
||||
[Experimental] Dump samples from a TSDB into OpenMetrics format. Native histograms are not dumped.
|
||||
[Experimental] Dump samples from a TSDB into OpenMetrics text format, excluding native histograms and staleness markers, which are not representable in OpenMetrics.
|
||||
|
||||
|
||||
|
||||
|
@ -592,6 +593,7 @@ Dump samples from a TSDB.
|
|||
|
||||
| Flag | Description | Default |
|
||||
| --- | --- | --- |
|
||||
| <code class="text-nowrap">--sandbox-dir-root</code> | Root directory where a sandbox directory would be created in case WAL replay generates chunks. The sandbox directory is cleaned up at the end. | `data/` |
|
||||
| <code class="text-nowrap">--min-time</code> | Minimum timestamp to dump. | `-9223372036854775808` |
|
||||
| <code class="text-nowrap">--max-time</code> | Maximum timestamp to dump. | `9223372036854775807` |
|
||||
| <code class="text-nowrap">--match</code> | Series selector. Can be specified multiple times. | `{__name__=~'(?s:.*)'}` |
|
||||
|
|
|
@ -70,6 +70,10 @@ global:
|
|||
|
||||
# How frequently to evaluate rules.
|
||||
[ evaluation_interval: <duration> | default = 1m ]
|
||||
|
||||
# Offset the rule evaluation timestamp of this particular group by the specified duration into the past to ensure the underlying metrics have been received.
|
||||
# Metric availability delays are more likely to occur when Prometheus is running as a remote write target, but can also occur when there's anomalies with scraping.
|
||||
[ rule_query_offset: <duration> | default = 0s ]
|
||||
|
||||
# The labels to add to any time series or alerts when communicating with
|
||||
# external systems (federation, remote storage, Alertmanager).
|
||||
|
@ -117,6 +121,12 @@ global:
|
|||
# that will be kept in memory. 0 means no limit.
|
||||
[ keep_dropped_targets: <int> | default = 0 ]
|
||||
|
||||
runtime:
|
||||
# Configure the Go garbage collector GOGC parameter
|
||||
# See: https://tip.golang.org/doc/gc-guide#GOGC
|
||||
# Lowering this number increases CPU usage.
|
||||
[ gogc: <int> | default = 50 ]
|
||||
|
||||
# Rule files specifies a list of globs. Rules and alerts are read from
|
||||
# all matching files.
|
||||
rule_files:
|
||||
|
@ -1349,7 +1359,7 @@ interface.
|
|||
The following meta labels are available on targets during [relabeling](#relabel_config):
|
||||
|
||||
* `__meta_openstack_address_pool`: the pool of the private IP.
|
||||
* `__meta_openstack_instance_flavor`: the flavor of the OpenStack instance.
|
||||
* `__meta_openstack_instance_flavor`: the flavor ID of the OpenStack instance.
|
||||
* `__meta_openstack_instance_id`: the OpenStack instance ID.
|
||||
* `__meta_openstack_instance_image`: the ID of the image the OpenStack instance is using.
|
||||
* `__meta_openstack_instance_name`: the OpenStack instance name.
|
||||
|
@ -1357,7 +1367,7 @@ The following meta labels are available on targets during [relabeling](#relabel_
|
|||
* `__meta_openstack_private_ip`: the private IP of the OpenStack instance.
|
||||
* `__meta_openstack_project_id`: the project (tenant) owning this instance.
|
||||
* `__meta_openstack_public_ip`: the public IP of the OpenStack instance.
|
||||
* `__meta_openstack_tag_<tagkey>`: each tag value of the instance.
|
||||
* `__meta_openstack_tag_<key>`: each metadata item of the instance, with any unsupported characters converted to an underscore.
|
||||
* `__meta_openstack_user_id`: the user account owning the tenant.
|
||||
|
||||
See below for the configuration options for OpenStack discovery:
|
||||
|
@ -1467,6 +1477,7 @@ For OVHcloud's [public cloud instances](https://www.ovhcloud.com/en/public-cloud
|
|||
* `__meta_ovhcloud_dedicated_server_ipv6`: the IPv6 of the server
|
||||
* `__meta_ovhcloud_dedicated_server_link_speed`: the link speed of the server
|
||||
* `__meta_ovhcloud_dedicated_server_name`: the name of the server
|
||||
* `__meta_ovhcloud_dedicated_server_no_intervention`: whether datacenter intervention is disabled for the server
|
||||
* `__meta_ovhcloud_dedicated_server_os`: the operating system of the server
|
||||
* `__meta_ovhcloud_dedicated_server_rack`: the rack of the server
|
||||
* `__meta_ovhcloud_dedicated_server_reverse`: the reverse DNS name of the server
|
||||
|
@ -3673,7 +3684,8 @@ queue_config:
|
|||
[ min_shards: <int> | default = 1 ]
|
||||
# Maximum number of samples per send.
|
||||
[ max_samples_per_send: <int> | default = 2000]
|
||||
# Maximum time a sample will wait in buffer.
|
||||
# Maximum time a sample will wait for a send. The sample might wait less
|
||||
# if the buffer is full. Further time might pass due to potential retries.
|
||||
[ batch_send_deadline: <duration> | default = 5s ]
|
||||
# Initial retry delay. Gets doubled for every retry.
|
||||
[ min_backoff: <duration> | default = 30ms ]
|
||||
|
|
|
@ -86,6 +86,9 @@ name: <string>
|
|||
# rule can produce. 0 is no limit.
|
||||
[ limit: <int> | default = 0 ]
|
||||
|
||||
# Offset the rule evaluation timestamp of this particular group by the specified duration into the past.
|
||||
[ query_offset: <duration> | default = global.rule_query_offset ]
|
||||
|
||||
rules:
|
||||
[ - <rule> ... ]
|
||||
```
|
||||
|
@ -148,6 +151,9 @@ the rule, active, pending, or inactive, are cleared as well. The event will be
|
|||
recorded as an error in the evaluation, and as such no stale markers are
|
||||
written.
|
||||
|
||||
# Rule query offset
|
||||
This is useful to ensure the underlying metrics have been received and stored in Prometheus. Metric availability delays are more likely to occur when Prometheus is running as a remote write target due to the nature of distributed systems, but can also occur when there's anomalies with scraping and/or short evaluation intervals.
|
||||
|
||||
# Failed rule evaluations due to slow evaluation
|
||||
|
||||
If a rule group hasn't finished evaluating before its next evaluation is supposed to start (as defined by the `evaluation_interval`), the next evaluation will be skipped. Subsequent evaluations of the rule group will continue to be skipped until the initial evaluation either completes or times out. When this happens, there will be a gap in the metric produced by the recording rule. The `rule_group_iterations_missed_total` metric will be incremented for each missed iteration of the rule group.
|
||||
|
|
|
@ -473,6 +473,9 @@ Range vectors are returned as result type `matrix`. The corresponding
|
|||
Each series could have the `"values"` key, or the `"histograms"` key, or both.
|
||||
For a given timestamp, there will only be one sample of either float or histogram type.
|
||||
|
||||
Series are returned sorted by `metric`. Functions such as [`sort`](functions.md#sort)
|
||||
and [`sort_by_label`](functions.md#sort_by_label) have no effect for range vectors.
|
||||
|
||||
### Instant vectors
|
||||
|
||||
Instant vectors are returned as result type `vector`. The corresponding
|
||||
|
@ -491,6 +494,10 @@ Instant vectors are returned as result type `vector`. The corresponding
|
|||
|
||||
Each series could have the `"value"` key, or the `"histogram"` key, but not both.
|
||||
|
||||
Series are not guaranteed to be returned in any particular order unless a function
|
||||
such as [`sort`](functions.md#sort) or [`sort_by_label`](functions.md#sort_by_label)`
|
||||
is used.
|
||||
|
||||
### Scalars
|
||||
|
||||
Scalar results are returned as result type `scalar`. The corresponding
|
||||
|
|
|
@ -596,10 +596,14 @@ have exactly one element, `scalar` will return `NaN`.
|
|||
`sort(v instant-vector)` returns vector elements sorted by their sample values,
|
||||
in ascending order. Native histograms are sorted by their sum of observations.
|
||||
|
||||
Please note that `sort` only affects the results of instant queries, as range query results always have a fixed output ordering.
|
||||
|
||||
## `sort_desc()`
|
||||
|
||||
Same as `sort`, but sorts in descending order.
|
||||
|
||||
Like `sort`, `sort_desc` only affects the results of instant queries, as range query results always have a fixed output ordering.
|
||||
|
||||
## `sort_by_label()`
|
||||
|
||||
**This function has to be enabled via the [feature flag](../feature_flags/) `--enable-feature=promql-experimental-functions`.**
|
||||
|
|
|
@ -197,6 +197,9 @@ or time-series database to Prometheus. To do so, the user must first convert the
|
|||
source data into [OpenMetrics](https://openmetrics.io/) format, which is the
|
||||
input format for the backfilling as described below.
|
||||
|
||||
Note that native histograms and staleness markers are not supported by this
|
||||
procedure, as they cannot be represented in the OpenMetrics format.
|
||||
|
||||
### Usage
|
||||
|
||||
Backfilling can be used via the Promtool command line. Promtool will write the blocks
|
||||
|
|
|
@ -127,9 +127,9 @@ func (d *discovery) parseServiceNodes(resp *http.Response, name string) (*target
|
|||
// since the service may be registered remotely through a different node.
|
||||
var addr string
|
||||
if node.ServiceAddress != "" {
|
||||
addr = net.JoinHostPort(node.ServiceAddress, fmt.Sprintf("%d", node.ServicePort))
|
||||
addr = net.JoinHostPort(node.ServiceAddress, strconv.Itoa(node.ServicePort))
|
||||
} else {
|
||||
addr = net.JoinHostPort(node.Address, fmt.Sprintf("%d", node.ServicePort))
|
||||
addr = net.JoinHostPort(node.Address, strconv.Itoa(node.ServicePort))
|
||||
}
|
||||
|
||||
target := model.LabelSet{model.AddressLabel: model.LabelValue(addr)}
|
||||
|
|
|
@ -8,36 +8,35 @@ require (
|
|||
github.com/gogo/protobuf v1.3.2
|
||||
github.com/golang/snappy v0.0.4
|
||||
github.com/influxdata/influxdb v1.11.5
|
||||
github.com/prometheus/client_golang v1.19.0
|
||||
github.com/prometheus/common v0.53.0
|
||||
github.com/prometheus/prometheus v0.51.2
|
||||
github.com/prometheus/client_golang v1.19.1
|
||||
github.com/prometheus/common v0.54.0
|
||||
github.com/prometheus/prometheus v0.52.1
|
||||
github.com/stretchr/testify v1.9.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.10.0 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.2 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2 // indirect
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.1 // indirect
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 // indirect
|
||||
github.com/alecthomas/units v0.0.0-20231202071711-9a357b53e9c9 // indirect
|
||||
github.com/aws/aws-sdk-go v1.50.32 // indirect
|
||||
github.com/aws/aws-sdk-go v1.51.25 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.2.0 // 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/felixge/httpsnoop v1.0.4 // indirect
|
||||
github.com/go-logfmt/logfmt v0.6.0 // indirect
|
||||
github.com/go-logr/logr v1.4.1 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/golang-jwt/jwt/v5 v5.2.0 // indirect
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/golang-jwt/jwt/v5 v5.2.1 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/grafana/regexp v0.0.0-20221122212121-6b5c0a4cb7fd // indirect
|
||||
github.com/hashicorp/go-version v1.6.0 // indirect
|
||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||
github.com/jpillora/backoff v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/klauspost/compress v1.17.7 // indirect
|
||||
github.com/klauspost/compress v1.17.8 // indirect
|
||||
github.com/kr/text v0.2.0 // indirect
|
||||
github.com/kylelemons/godebug v1.1.0 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
|
@ -45,33 +44,32 @@ require (
|
|||
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // 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_model v0.6.0 // indirect
|
||||
github.com/prometheus/client_model v0.6.1 // indirect
|
||||
github.com/prometheus/common/sigv4 v0.1.0 // indirect
|
||||
github.com/prometheus/procfs v0.12.0 // indirect
|
||||
github.com/xhit/go-str2duration/v2 v2.1.0 // indirect
|
||||
go.opentelemetry.io/collector/featuregate v1.3.0 // indirect
|
||||
go.opentelemetry.io/collector/pdata v1.3.0 // indirect
|
||||
go.opentelemetry.io/collector/semconv v0.96.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect
|
||||
go.opentelemetry.io/otel v1.24.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.24.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.24.0 // indirect
|
||||
go.opentelemetry.io/collector/featuregate v1.5.0 // indirect
|
||||
go.opentelemetry.io/collector/pdata v1.5.0 // indirect
|
||||
go.opentelemetry.io/collector/semconv v0.98.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.50.0 // indirect
|
||||
go.opentelemetry.io/otel v1.25.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.25.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.25.0 // indirect
|
||||
go.uber.org/atomic v1.11.0 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
golang.org/x/crypto v0.21.0 // indirect
|
||||
golang.org/x/net v0.22.0 // indirect
|
||||
golang.org/x/oauth2 v0.18.0 // indirect
|
||||
golang.org/x/sys v0.18.0 // indirect
|
||||
golang.org/x/crypto v0.22.0 // indirect
|
||||
golang.org/x/net v0.24.0 // indirect
|
||||
golang.org/x/oauth2 v0.19.0 // indirect
|
||||
golang.org/x/sys v0.19.0 // indirect
|
||||
golang.org/x/text v0.14.0 // indirect
|
||||
golang.org/x/time v0.5.0 // indirect
|
||||
google.golang.org/appengine v1.6.8 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240304161311-37d4d3c04a78 // indirect
|
||||
google.golang.org/grpc v1.62.1 // indirect
|
||||
google.golang.org/protobuf v1.33.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240415180920-8c6c420018be // indirect
|
||||
google.golang.org/grpc v1.63.2 // indirect
|
||||
google.golang.org/protobuf v1.34.0 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
k8s.io/apimachinery v0.29.2 // indirect
|
||||
k8s.io/client-go v0.29.2 // indirect
|
||||
k8s.io/apimachinery v0.29.3 // indirect
|
||||
k8s.io/client-go v0.29.3 // indirect
|
||||
k8s.io/klog/v2 v2.120.1 // indirect
|
||||
k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect
|
||||
)
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.10.0 h1:n1DH8TPV4qqPTje2RcUBYwtrTWlabVp4n46+74X2pn4=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.10.0/go.mod h1:HDcZnuGbiyppErN6lB+idp4CKhjbc8gwjto6OPpyggM=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1 h1:sO0/P7g68FrryJzljemN+6GTssUXdANk6aJ7T1ZxnsQ=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1/go.mod h1:h8hyGFDsU5HMivxiS2iYFZsgDbU9OnnJ163x5UGVKYo=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1 h1:E+OJmp2tPvt1W+amx48v1eqbjDYsgN+RzP4q16yV5eM=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1/go.mod h1:a6xsAQUZg+VsS3TJ05SRp524Hs4pZ/AeFSr5ENf0Yjo=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.2 h1:FDif4R1+UUR+00q6wquyX90K7A8dN+R5E8GEadoP7sU=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.2/go.mod h1:aiYBYui4BJ/BJCAIKs92XiPyQfTaBWqvHujDwKb6CBU=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2 h1:LqbJ/WzJUwBf8UiaSzgX7aMclParm9/5Vgp+TY51uBQ=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2/go.mod h1:yInRyqWXAuaPrgI7p70+lDDgh3mlBohis29jGMISnmc=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5 v5.5.0 h1:MxA59PGoCFb+vCwRQi3PhQEwHj4+r2dhuv9HG+vM7iM=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5 v5.5.0/go.mod h1:uYt4CfhkJA9o0FN7jfE5minm/i4nUE4MjGUJkzB6Zs8=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5 v5.6.0 h1:ui3YNbxfW7J3tTFIZMH6LIGRjCngp+J+nIFlnizfNTE=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5 v5.6.0/go.mod h1:gZmgV+qBqygoznvqo2J9oKZAFziqhLZ2xE/WVUmzkHA=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v4 v4.3.0 h1:bXwSugBiSbgtz7rOtbfGf+woewp4f06orW9OP5BjHLA=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v4 v4.3.0/go.mod h1:Y/HgrePTmGy9HjdSGTqZNa+apUpTVIEVKXJyARP2lrk=
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.1 h1:DzHpqpoJVaCgOUdVHxE8QB52S6NiVdDQvGlny1qvPqA=
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.1/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
|
||||
github.com/Code-Hex/go-generics-cache v1.3.1 h1:i8rLwyhoyhaerr7JpjtYjJZUcCbWOdiYO3fZXLiEC4g=
|
||||
github.com/Code-Hex/go-generics-cache v1.3.1/go.mod h1:qxcC9kRVrct9rHeiYpFWSoW1vxyillCVzX13KZG8dl4=
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 h1:XHOnouVk1mxXfQidrMEnLlPk9UMeRtyBTnEFtxkV0kU=
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
|
||||
github.com/Code-Hex/go-generics-cache v1.5.1 h1:6vhZGc5M7Y/YD8cIUcY8kcuQLB4cHR7U+0KMqAA0KcU=
|
||||
github.com/Code-Hex/go-generics-cache v1.5.1/go.mod h1:qxcC9kRVrct9rHeiYpFWSoW1vxyillCVzX13KZG8dl4=
|
||||
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
|
||||
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
|
||||
github.com/alecthomas/kingpin/v2 v2.4.0 h1:f48lwail6p8zpO1bC4TxtqACaGqHYA22qkHjHpqDjYY=
|
||||
|
@ -26,8 +26,8 @@ github.com/alecthomas/units v0.0.0-20231202071711-9a357b53e9c9/go.mod h1:OMCwj8V
|
|||
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 v1.38.35/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
|
||||
github.com/aws/aws-sdk-go v1.50.32 h1:POt81DvegnpQKM4DMDLlHz1CO6OBnEoQ1gRhYFd7QRY=
|
||||
github.com/aws/aws-sdk-go v1.50.32/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk=
|
||||
github.com/aws/aws-sdk-go v1.51.25 h1:DjTT8mtmsachhV6yrXR8+yhnG6120dazr720nopRsls=
|
||||
github.com/aws/aws-sdk-go v1.51.25/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk=
|
||||
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 v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
|
@ -35,8 +35,8 @@ github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+Ce
|
|||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
||||
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
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-20231128003011-0fa0005c9caa h1:jQCWAUqqlij9Pgj2i/PB79y4KOPYVyFYdROxgaCwdTQ=
|
||||
github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa/go.mod h1:x/1Gn8zydmfq8dk6e9PdstVsDgu9RuyIIJqAaF//0IM=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
|
@ -46,14 +46,14 @@ 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.109.0 h1:4W97RJLJSUQ3veRZDNbp1Ol3Rbn6Lmt9bKGvfqYI5SU=
|
||||
github.com/digitalocean/godo v1.109.0/go.mod h1:R6EmmWI8CT1+fCtjWY9UCB+L5uufuZH13wk3YhxycCs=
|
||||
github.com/digitalocean/godo v1.113.0 h1:CLtCxlP4wDAjKIQ+Hshht/UNbgAp8/J/XBH1ZtDCF9Y=
|
||||
github.com/digitalocean/godo v1.113.0/go.mod h1:Z2mTP848Vi3IXXl5YbPekUgr4j4tOePomA+OE1Ag98w=
|
||||
github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0=
|
||||
github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
|
||||
github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI=
|
||||
github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=
|
||||
github.com/docker/docker v25.0.3+incompatible h1:D5fy/lYmY7bvZa0XTZ5/UJPljor41F+vdyJG5luQLfQ=
|
||||
github.com/docker/docker v25.0.3+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker v26.0.1+incompatible h1:t39Hm6lpXuXtgkF0dm1t9a5HkbUfdGy6XbWexmGr+hA=
|
||||
github.com/docker/docker v26.0.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
|
||||
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
|
||||
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
|
||||
|
@ -95,16 +95,16 @@ github.com/go-openapi/jsonreference v0.20.4 h1:bKlDxQxQJgwpUSgOENiMPzCTBVuc7vTdX
|
|||
github.com/go-openapi/jsonreference v0.20.4/go.mod h1:5pZJyJP2MnYCpoeoMAql78cCHauHj0V9Lhc506VOpw4=
|
||||
github.com/go-openapi/swag v0.22.9 h1:XX2DssF+mQKM2DHsbgZK74y/zj4mo9I99+89xUmuZCE=
|
||||
github.com/go-openapi/swag v0.22.9/go.mod h1:3/OXnFfnMAwBD099SwYRk7GD3xOrr1iL7d/XNLXVVwE=
|
||||
github.com/go-resty/resty/v2 v2.11.0 h1:i7jMfNOJYMp69lq7qozJP+bjgzfAzeOhuGlyDrqxT/8=
|
||||
github.com/go-resty/resty/v2 v2.11.0/go.mod h1:iiP/OpA0CkcL3IGt1O0+/SIItFUbkkyw5BGXiVdTu+A=
|
||||
github.com/go-resty/resty/v2 v2.12.0 h1:rsVL8P90LFvkUYq/V5BTVe203WfRIU4gvcf+yfzJzGA=
|
||||
github.com/go-resty/resty/v2 v2.12.0/go.mod h1:o0yGPrkS3lOe1+eFajk6kBW8ScXzwU3hD69/gt2yB/0=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/go-zookeeper/zk v1.0.3 h1:7M2kwOsc//9VeeFiPtf+uSJlVpU66x9Ba5+8XK7/TDg=
|
||||
github.com/go-zookeeper/zk v1.0.3/go.mod h1:nOB03cncLtlp4t+UAkGSV+9beXP/akpekBwL+UX1Qcw=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.0 h1:d/ix8ftRUorsN+5eMIlF4T6J8CAt9rch3My2winC1Jw=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
|
@ -115,10 +115,8 @@ github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:W
|
|||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
||||
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I=
|
||||
|
@ -137,8 +135,8 @@ github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
|
|||
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
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/gophercloud/gophercloud v1.8.0 h1:TM3Jawprb2NrdOnvcHhWJalmKmAmOGgfZElM/3oBYCk=
|
||||
github.com/gophercloud/gophercloud v1.8.0/go.mod h1:aAVqcocTSXh2vYFZ1JTvx4EQmfgzxRcNupUfxZbBNDM=
|
||||
github.com/gophercloud/gophercloud v1.11.0 h1:ls0O747DIq1D8SUHc7r2vI8BFbMLeLFuENaAIfEx7OM=
|
||||
github.com/gophercloud/gophercloud v1.11.0/go.mod h1:aAVqcocTSXh2vYFZ1JTvx4EQmfgzxRcNupUfxZbBNDM=
|
||||
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
|
||||
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/grafana/regexp v0.0.0-20221122212121-6b5c0a4cb7fd h1:PpuIBO5P3e9hpqBD0O/HjhShYuM6XE0i/lbE6J94kww=
|
||||
|
@ -165,12 +163,12 @@ github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mO
|
|||
github.com/hashicorp/go-version v1.6.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-20240306004928-3e7191ccb702 h1:fI1LXuBaS1d9z1kmb++Og6YD8uMRwadXorCwE+xgOFA=
|
||||
github.com/hashicorp/nomad/api v0.0.0-20240306004928-3e7191ccb702/go.mod h1:z71gkJdrkAt/Rl6C7Q79VE7AwJ5lUF+M+fzFTyIHYB0=
|
||||
github.com/hashicorp/nomad/api v0.0.0-20240418183417-ea5f2f6748c7 h1:pjE59CS2C9Bg+Xby0ROrnZSSBWtKwx3Sf9gqsrvIFSA=
|
||||
github.com/hashicorp/nomad/api v0.0.0-20240418183417-ea5f2f6748c7/go.mod h1:svtxn6QnrQ69P23VvIWMR34tg3vmwLz4UdUzm1dSCgE=
|
||||
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.6.0 h1:RJOA2hHZ7rD1pScA4O1NF6qhkHyUdbbxjHgFNot8928=
|
||||
github.com/hetznercloud/hcloud-go/v2 v2.6.0/go.mod h1:4J1cSE57+g0WS93IiHLV7ubTHItcp+awzeBp5bM9mfA=
|
||||
github.com/hetznercloud/hcloud-go/v2 v2.7.2 h1:UlE7n1GQZacCfyjv9tDVUN7HZfOXErPIfM/M039u9A0=
|
||||
github.com/hetznercloud/hcloud-go/v2 v2.7.2/go.mod h1:49tIV+pXRJTUC7fbFZ03s45LKqSQdOPP5y91eOnJo/k=
|
||||
github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4=
|
||||
github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
|
||||
github.com/influxdata/influxdb v1.11.5 h1:+em5VOl6lhAZubXj5o6SobCwvrRs3XDlBx/MUI4schI=
|
||||
|
@ -194,8 +192,8 @@ github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7V
|
|||
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
|
||||
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.17.7 h1:ehO88t2UGzQK66LMdE8tibEd1ErmzZjNEqWkjLAKQQg=
|
||||
github.com/klauspost/compress v1.17.7/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
|
||||
github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU=
|
||||
github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
|
||||
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=
|
||||
|
@ -210,8 +208,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.29.0 h1:gDSQWAbKMAQX8db9FDCXHhodQPrJmLcmthjx6m+PyV4=
|
||||
github.com/linode/linodego v1.29.0/go.mod h1:3k6WvCM10gillgYcnoLqIL23ST27BD9HhMsCJWb3Bpk=
|
||||
github.com/linode/linodego v1.32.0 h1:OmZzB3iON6uu84VtLFf64uKmAQqJJarvmsVguroioPI=
|
||||
github.com/linode/linodego v1.32.0/go.mod h1:y8GDP9uLVH4jTB9qyrgw79qfKdYJmNCGUOJmfuiOcmI=
|
||||
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
||||
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
|
@ -219,12 +217,14 @@ github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovk
|
|||
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
|
||||
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/miekg/dns v1.1.58 h1:ca2Hdkz+cDg/7eNF6V56jjzuZ4aCAE+DbVkILdQWG/4=
|
||||
github.com/miekg/dns v1.1.58/go.mod h1:Ypv+3b/KadlvW9vJfXOTf300O4UqaHFzFCuHz+rPkBY=
|
||||
github.com/miekg/dns v1.1.59 h1:C9EXc/UToRwKLhK5wKU/I4QVsBUc8kE6MkHBkeypWZs=
|
||||
github.com/miekg/dns v1.1.59/go.mod h1:nZpewl5p6IvctfgrckopVx2OlSEHPRO/U4SYkRklrEk=
|
||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
||||
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
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/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=
|
||||
|
@ -258,19 +258,19 @@ github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXP
|
|||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
|
||||
github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
|
||||
github.com/prometheus/client_golang v1.19.0 h1:ygXvpU1AoN1MhdzckN+PyD9QJOSD4x7kmXYlnfbA6JU=
|
||||
github.com/prometheus/client_golang v1.19.0/go.mod h1:ZRM9uEAypZakd+q/x7+gmsvXdURP+DABIEIjnmDdp+k=
|
||||
github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE=
|
||||
github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho=
|
||||
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=
|
||||
github.com/prometheus/client_model v0.6.0 h1:k1v3CzpSRUTrKMppY35TLwPvxHqBu0bYgxZzqGIgaos=
|
||||
github.com/prometheus/client_model v0.6.0/go.mod h1:NTQHnmxFpouOD0DpvP4XujX3CdOAGQPoaGhyTchlyt8=
|
||||
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
|
||||
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
|
||||
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
|
||||
github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
|
||||
github.com/prometheus/common v0.29.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
|
||||
github.com/prometheus/common v0.53.0 h1:U2pL9w9nmJwJDa4qqLQ3ZaePJ6ZTwt7cMD3AG3+aLCE=
|
||||
github.com/prometheus/common v0.53.0/go.mod h1:BrxBKv3FWBIGXw89Mg1AeBq7FSyRzXWI3l3e7W3RN5U=
|
||||
github.com/prometheus/common v0.54.0 h1:ZlZy0BgJhTwVZUn7dLOkwCZHUkrAqd3WYtcFCWnM1D8=
|
||||
github.com/prometheus/common v0.54.0/go.mod h1:/TQgMJP5CuVYveyT7n/0Ix8yLNNXy9yRSkhnLTHPDIQ=
|
||||
github.com/prometheus/common/sigv4 v0.1.0 h1:qoVebwtwwEhS85Czm2dSROY5fTo2PAPEVdDeppTwGX4=
|
||||
github.com/prometheus/common/sigv4 v0.1.0/go.mod h1:2Jkxxk9yYvCkE5G1sQT7GuEXm57JrvHu9k5YwTjsNtI=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
|
@ -279,12 +279,12 @@ github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4O
|
|||
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
||||
github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
|
||||
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
|
||||
github.com/prometheus/prometheus v0.51.2 h1:U0faf1nT4CB9DkBW87XLJCBi2s8nwWXdTbyzRUAkX0w=
|
||||
github.com/prometheus/prometheus v0.51.2/go.mod h1:yv4MwOn3yHMQ6MZGHPg/U7Fcyqf+rxqiZfSur6myVtc=
|
||||
github.com/prometheus/prometheus v0.52.1 h1:BrQ29YG+mzdGh8DgHPirHbeMGNqtL+INe0rqg7ttBJ4=
|
||||
github.com/prometheus/prometheus v0.52.1/go.mod h1:3z74cVsmVH0iXOR5QBjB7Pa6A0KJeEAK5A6UsmAFb1g=
|
||||
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
|
||||
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
|
||||
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.25 h1:/8rfZAdFfafRXOgz+ZpMZZWZ5pYggCY9t7e/BvjaBHM=
|
||||
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.25/go.mod h1:fCa7OJZ/9DRTnOKmxvT6pn+LPWUptQAmHF/SBJUGEcg=
|
||||
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.26 h1:F+GIVtGqCFxPxO46ujf8cEOP574MBoRm3gNbPXECbxs=
|
||||
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.26/go.mod h1:fCa7OJZ/9DRTnOKmxvT6pn+LPWUptQAmHF/SBJUGEcg=
|
||||
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/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||
|
@ -306,21 +306,20 @@ github.com/xhit/go-str2duration/v2 v2.1.0 h1:lxklc02Drh6ynqX+DdPyp5pCKLUQpRT8bp8
|
|||
github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
go.opentelemetry.io/collector/featuregate v1.3.0 h1:nrFSx+zfjdisjE9oCx25Aep3nJ9RaUjeE1qFL6eovoU=
|
||||
go.opentelemetry.io/collector/featuregate v1.3.0/go.mod h1:mm8+xyQfgDmqhyegZRNIQmoKsNnDTwWKFLsdMoXAb7A=
|
||||
go.opentelemetry.io/collector/pdata v1.3.0 h1:JRYN7tVHYFwmtQhIYbxWeiKSa2L1nCohyAs8sYqKFZo=
|
||||
go.opentelemetry.io/collector/pdata v1.3.0/go.mod h1:t7W0Undtes53HODPdSujPLTnfSR5fzT+WpL+RTaaayo=
|
||||
go.opentelemetry.io/collector/semconv v0.96.0 h1:DrZy8BpzJDnN2zFxXRj6BhfGYxNlqpFHBqyuS9fVHRY=
|
||||
go.opentelemetry.io/collector/semconv v0.96.0/go.mod h1:zOm/U3pgMIWcvrcnPbR9Xx2HinoXj46ERMK8PUV9wrs=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw=
|
||||
go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo=
|
||||
go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo=
|
||||
go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI=
|
||||
go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco=
|
||||
go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI=
|
||||
go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU=
|
||||
go.opentelemetry.io/collector/featuregate v1.5.0 h1:uK8qnYQKz1TMkK+FDTFsywg/EybW/gbnOUaPNUkRznM=
|
||||
go.opentelemetry.io/collector/featuregate v1.5.0/go.mod h1:w7nUODKxEi3FLf1HslCiE6YWtMtOOrMnSwsDam8Mg9w=
|
||||
go.opentelemetry.io/collector/pdata v1.5.0 h1:1fKTmUpr0xCOhP/B0VEvtz7bYPQ45luQ8XFyA07j8LE=
|
||||
go.opentelemetry.io/collector/pdata v1.5.0/go.mod h1:TYj8aKRWZyT/KuKQXKyqSEvK/GV+slFaDMEI+Ke64Yw=
|
||||
go.opentelemetry.io/collector/semconv v0.98.0 h1:zO4L4TmlxXoYu8UgPeYElGY19BW7wPjM+quL5CzoOoY=
|
||||
go.opentelemetry.io/collector/semconv v0.98.0/go.mod h1:8ElcRZ8Cdw5JnvhTOQOdYizkJaQ10Z2fS+R6djOnj6A=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.50.0 h1:cEPbyTSEHlQR89XVlyo78gqluF8Y3oMeBkXGWzQsfXY=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.50.0/go.mod h1:DKdbWcT4GH1D0Y3Sqt/PFXt2naRKDWtU+eE6oLdFNA8=
|
||||
go.opentelemetry.io/otel v1.25.0 h1:gldB5FfhRl7OJQbUHt/8s0a7cE8fbsPAtdpRaApKy4k=
|
||||
go.opentelemetry.io/otel v1.25.0/go.mod h1:Wa2ds5NOXEMkCmUou1WA7ZBfLTHWIsp034OVD7AO+Vg=
|
||||
go.opentelemetry.io/otel/metric v1.25.0 h1:LUKbS7ArpFL/I2jJHdJcqMGxkRdxpPHE0VU/D4NuEwA=
|
||||
go.opentelemetry.io/otel/metric v1.25.0/go.mod h1:rkDLUSd2lC5lq2dFNrX9LGAbINP5B7WBkC78RXCpH5s=
|
||||
go.opentelemetry.io/otel/trace v1.25.0 h1:tqukZGLwQYRIFtSQM2u2+yfMVTgGVeqRLPUYx1Dq6RM=
|
||||
go.opentelemetry.io/otel/trace v1.25.0/go.mod h1:hCCs70XM/ljO+BeQkyFnbK28SBIJ/Emuha+ccrCRT7I=
|
||||
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
|
||||
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
|
@ -331,16 +330,14 @@ golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnf
|
|||
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.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
|
||||
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
|
||||
golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=
|
||||
golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
|
||||
golang.org/x/exp v0.0.0-20240119083558-1b970713d09a h1:Q8/wZp0KX97QFTc2ywcOE0YRjZPVIx+MXInMzdvQqcA=
|
||||
golang.org/x/exp v0.0.0-20240119083558-1b970713d09a/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08=
|
||||
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.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic=
|
||||
golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
|
||||
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
|
@ -353,24 +350,21 @@ golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81R
|
|||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc=
|
||||
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
||||
golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w=
|
||||
golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI=
|
||||
golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8=
|
||||
golang.org/x/oauth2 v0.19.0 h1:9+E/EZBCbTLNrbN35fHv/a/d/mOBatymz1zbtQrXpIg=
|
||||
golang.org/x/oauth2 v0.19.0/go.mod h1:vYi7skDa1x015PmRRYZ7+s1cWyPgrPiSYRe4rnsexc8=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
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=
|
||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
|
||||
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
|
||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
|
@ -385,22 +379,16 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
|
||||
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
|
||||
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
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.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8=
|
||||
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
|
||||
golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q=
|
||||
golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk=
|
||||
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=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
|
||||
|
@ -409,24 +397,21 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm
|
|||
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.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.19.0 h1:tfGCXNR1OsFG+sVdLAitlpjAvD/I6dHDKnYrpEZUHkw=
|
||||
golang.org/x/tools v0.19.0/go.mod h1:qoJWxmGSIBmAeriMx19ogtrEPrGtDbPK634QFIcLAhc=
|
||||
golang.org/x/tools v0.20.0 h1:hz/CVckiOxybQvFw6h7b/q80NTr9IUQb4s1IIzW7KNY=
|
||||
golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg=
|
||||
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/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
|
||||
google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
|
||||
google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80 h1:KAeGQVN3M9nD0/bQXnr/ClcEMJ968gUXJQ9pwfSynuQ=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240304212257-790db918fca8 h1:8eadJkXbwDEMNwcB5O0s5Y5eCfyuCLdvaiOIaGTrWmQ=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240304212257-790db918fca8/go.mod h1:O1cOfN1Cy6QEYr7VxtjOyP5AdAuR0aJ/MYZaaof623Y=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240304161311-37d4d3c04a78 h1:Xs9lu+tLXxLIfuci70nG4cpwaRC+mRQPUL7LoIeDJC4=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240304161311-37d4d3c04a78/go.mod h1:UCOku4NytXMJuLQE5VuqA5lX3PcHCBo8pxNyvkf4xBs=
|
||||
google.golang.org/grpc v1.62.1 h1:B4n+nfKzOICUXMgyrNd19h/I9oH0L1pizfk1d4zSgTk=
|
||||
google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE=
|
||||
google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de h1:F6qOa9AZTYJXOUEr4jDysRDLrm4PHePlge4v4TGAlxY=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240415180920-8c6c420018be h1:Zz7rLWqp0ApfsR/l7+zSHhY3PMiH2xqgxlfYfAfNpoU=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240415180920-8c6c420018be/go.mod h1:dvdCTIoAGbkWbcIKBniID56/7XHTt6WfxXNMxuziJ+w=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240415180920-8c6c420018be h1:LG9vZxsWGOmUKieR8wPAUR3u3MpnYFQZROPIMaXh7/A=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240415180920-8c6c420018be/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY=
|
||||
google.golang.org/grpc v1.63.2 h1:MUeiw1B2maTVZthpU5xvASfTh3LDbxHd6IJ6QQVU+xM=
|
||||
google.golang.org/grpc v1.63.2/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
|
@ -434,9 +419,8 @@ google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miE
|
|||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
|
||||
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
google.golang.org/protobuf v1.34.0 h1:Qo/qEd2RZPCf2nKuorzksSknv0d3ERwp1vFG38gSmH4=
|
||||
google.golang.org/protobuf v1.34.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
@ -457,16 +441,16 @@ 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=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
k8s.io/api v0.29.2 h1:hBC7B9+MU+ptchxEqTNW2DkUosJpp1P+Wn6YncZ474A=
|
||||
k8s.io/api v0.29.2/go.mod h1:sdIaaKuU7P44aoyyLlikSLayT6Vb7bvJNCX105xZXY0=
|
||||
k8s.io/apimachinery v0.29.2 h1:EWGpfJ856oj11C52NRCHuU7rFDwxev48z+6DSlGNsV8=
|
||||
k8s.io/apimachinery v0.29.2/go.mod h1:6HVkd1FwxIagpYrHSwJlQqZI3G9LfYWRPAkUvLnXTKU=
|
||||
k8s.io/client-go v0.29.2 h1:FEg85el1TeZp+/vYJM7hkDlSTFZ+c5nnK44DJ4FyoRg=
|
||||
k8s.io/client-go v0.29.2/go.mod h1:knlvFZE58VpqbQpJNbCbctTVXcd35mMyAAwBdpt4jrA=
|
||||
k8s.io/api v0.29.3 h1:2ORfZ7+bGC3YJqGpV0KSDDEVf8hdGQ6A03/50vj8pmw=
|
||||
k8s.io/api v0.29.3/go.mod h1:y2yg2NTyHUUkIoTC+phinTnEa3KFM6RZ3szxt014a80=
|
||||
k8s.io/apimachinery v0.29.3 h1:2tbx+5L7RNvqJjn7RIuIKu9XTsIZ9Z5wX2G22XAa5EU=
|
||||
k8s.io/apimachinery v0.29.3/go.mod h1:hx/S4V2PNW4OMg3WizRrHutyB5la0iCUbZym+W0EQIU=
|
||||
k8s.io/client-go v0.29.3 h1:R/zaZbEAxqComZ9FHeQwOh3Y1ZUs7FaHKZdQtIc2WZg=
|
||||
k8s.io/client-go v0.29.3/go.mod h1:tkDisCvgPfiRpxGnOORfkljmS+UrW+WtXAy2fTvXJB0=
|
||||
k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw=
|
||||
k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
|
||||
k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 h1:aVUu9fTY98ivBPKR9Y5w/AuzbMm96cd3YHRTU83I780=
|
||||
k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00/go.mod h1:AsvuZPBlUDVuCdzJ87iajxtXuR9oktsTctW/R9wwouA=
|
||||
k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7FjZpUb45WallggurYhKGag=
|
||||
k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98=
|
||||
k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI=
|
||||
k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
||||
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
|
||||
|
|
|
@ -44,5 +44,10 @@
|
|||
// The default refresh time for all dashboards, default to 60s
|
||||
refresh: '60s',
|
||||
},
|
||||
|
||||
// Opt-out of multi-cluster dashboards by overriding this.
|
||||
showMultiCluster: true,
|
||||
// The cluster label to infer the cluster name from.
|
||||
clusterLabel: 'cluster',
|
||||
},
|
||||
}
|
||||
|
|
|
@ -10,21 +10,32 @@ local template = grafana.template;
|
|||
{
|
||||
grafanaDashboards+:: {
|
||||
'prometheus.json':
|
||||
g.dashboard(
|
||||
local showMultiCluster = $._config.showMultiCluster;
|
||||
local dashboard = g.dashboard(
|
||||
'%(prefix)sOverview' % $._config.grafanaPrometheus
|
||||
)
|
||||
.addMultiTemplate('cluster', 'prometheus_build_info{%(prometheusSelector)s}' % $._config, 'cluster')
|
||||
.addMultiTemplate('job', 'prometheus_build_info{cluster=~"$cluster"}', 'job')
|
||||
.addMultiTemplate('instance', 'prometheus_build_info{cluster=~"$cluster", job=~"$job"}', 'instance')
|
||||
);
|
||||
local templatedDashboard = if showMultiCluster then
|
||||
dashboard
|
||||
.addMultiTemplate('cluster', 'prometheus_build_info{%(prometheusSelector)s}' % $._config, $._config.clusterLabel)
|
||||
.addMultiTemplate('job', 'prometheus_build_info{cluster=~"$cluster"}', 'job')
|
||||
.addMultiTemplate('instance', 'prometheus_build_info{cluster=~"$cluster", job=~"$job"}', 'instance')
|
||||
else
|
||||
dashboard
|
||||
.addMultiTemplate('job', 'prometheus_build_info{%(prometheusSelector)s}' % $._config, 'job')
|
||||
.addMultiTemplate('instance', 'prometheus_build_info{job=~"$job"}', 'instance');
|
||||
templatedDashboard
|
||||
.addRow(
|
||||
g.row('Prometheus Stats')
|
||||
.addPanel(
|
||||
g.panel('Prometheus Stats') +
|
||||
g.tablePanel([
|
||||
g.tablePanel(if showMultiCluster then [
|
||||
'count by (cluster, job, instance, version) (prometheus_build_info{cluster=~"$cluster", job=~"$job", instance=~"$instance"})',
|
||||
'max by (cluster, job, instance) (time() - process_start_time_seconds{cluster=~"$cluster", job=~"$job", instance=~"$instance"})',
|
||||
] else [
|
||||
'count by (job, instance, version) (prometheus_build_info{job=~"$job", instance=~"$instance"})',
|
||||
'max by (job, instance) (time() - process_start_time_seconds{job=~"$job", instance=~"$instance"})',
|
||||
], {
|
||||
cluster: { alias: 'Cluster' },
|
||||
cluster: { alias: if showMultiCluster then 'Cluster' else '' },
|
||||
job: { alias: 'Job' },
|
||||
instance: { alias: 'Instance' },
|
||||
version: { alias: 'Version' },
|
||||
|
@ -37,12 +48,18 @@ local template = grafana.template;
|
|||
g.row('Discovery')
|
||||
.addPanel(
|
||||
g.panel('Target Sync') +
|
||||
g.queryPanel('sum(rate(prometheus_target_sync_length_seconds_sum{cluster=~"$cluster",job=~"$job",instance=~"$instance"}[5m])) by (cluster, job, scrape_job, instance) * 1e3', '{{cluster}}:{{job}}:{{instance}}:{{scrape_job}}') +
|
||||
g.queryPanel(if showMultiCluster then 'sum(rate(prometheus_target_sync_length_seconds_sum{cluster=~"$cluster",job=~"$job",instance=~"$instance"}[5m])) by (cluster, job, scrape_job, instance) * 1e3'
|
||||
else 'sum(rate(prometheus_target_sync_length_seconds_sum{job=~"$job",instance=~"$instance"}[5m])) by (scrape_job) * 1e3',
|
||||
if showMultiCluster then '{{cluster}}:{{job}}:{{instance}}:{{scrape_job}}'
|
||||
else '{{scrape_job}}') +
|
||||
{ yaxes: g.yaxes('ms') }
|
||||
)
|
||||
.addPanel(
|
||||
g.panel('Targets') +
|
||||
g.queryPanel('sum by (cluster, job, instance) (prometheus_sd_discovered_targets{cluster=~"$cluster", job=~"$job",instance=~"$instance"})', '{{cluster}}:{{job}}:{{instance}}') +
|
||||
g.queryPanel(if showMultiCluster then 'sum by (cluster, job, instance) (prometheus_sd_discovered_targets{cluster=~"$cluster", job=~"$job",instance=~"$instance"})'
|
||||
else 'sum(prometheus_sd_discovered_targets{job=~"$job",instance=~"$instance"})',
|
||||
if showMultiCluster then '{{cluster}}:{{job}}:{{instance}}'
|
||||
else 'Targets') +
|
||||
g.stack
|
||||
)
|
||||
)
|
||||
|
@ -50,29 +67,47 @@ local template = grafana.template;
|
|||
g.row('Retrieval')
|
||||
.addPanel(
|
||||
g.panel('Average Scrape Interval Duration') +
|
||||
g.queryPanel('rate(prometheus_target_interval_length_seconds_sum{cluster=~"$cluster", job=~"$job",instance=~"$instance"}[5m]) / rate(prometheus_target_interval_length_seconds_count{cluster=~"$cluster", job=~"$job",instance=~"$instance"}[5m]) * 1e3', '{{cluster}}:{{job}}:{{instance}} {{interval}} configured') +
|
||||
g.queryPanel(if showMultiCluster then 'rate(prometheus_target_interval_length_seconds_sum{cluster=~"$cluster", job=~"$job",instance=~"$instance"}[5m]) / rate(prometheus_target_interval_length_seconds_count{cluster=~"$cluster", job=~"$job",instance=~"$instance"}[5m]) * 1e3'
|
||||
else 'rate(prometheus_target_interval_length_seconds_sum{job=~"$job",instance=~"$instance"}[5m]) / rate(prometheus_target_interval_length_seconds_count{job=~"$job",instance=~"$instance"}[5m]) * 1e3',
|
||||
if showMultiCluster then '{{cluster}}:{{job}}:{{instance}} {{interval}} configured'
|
||||
else '{{interval}} configured') +
|
||||
{ yaxes: g.yaxes('ms') }
|
||||
)
|
||||
.addPanel(
|
||||
g.panel('Scrape failures') +
|
||||
g.queryPanel([
|
||||
g.queryPanel(if showMultiCluster then [
|
||||
'sum by (cluster, job, instance) (rate(prometheus_target_scrapes_exceeded_body_size_limit_total{cluster=~"$cluster",job=~"$job",instance=~"$instance"}[1m]))',
|
||||
'sum by (cluster, job, instance) (rate(prometheus_target_scrapes_exceeded_sample_limit_total{cluster=~"$cluster",job=~"$job",instance=~"$instance"}[1m]))',
|
||||
'sum by (cluster, job, instance) (rate(prometheus_target_scrapes_sample_duplicate_timestamp_total{cluster=~"$cluster",job=~"$job",instance=~"$instance"}[1m]))',
|
||||
'sum by (cluster, job, instance) (rate(prometheus_target_scrapes_sample_out_of_bounds_total{cluster=~"$cluster",job=~"$job",instance=~"$instance"}[1m]))',
|
||||
'sum by (cluster, job, instance) (rate(prometheus_target_scrapes_sample_out_of_order_total{cluster=~"$cluster",job=~"$job",instance=~"$instance"}[1m]))',
|
||||
], [
|
||||
] else [
|
||||
'sum by (job) (rate(prometheus_target_scrapes_exceeded_body_size_limit_total[1m]))',
|
||||
'sum by (job) (rate(prometheus_target_scrapes_exceeded_sample_limit_total[1m]))',
|
||||
'sum by (job) (rate(prometheus_target_scrapes_sample_duplicate_timestamp_total[1m]))',
|
||||
'sum by (job) (rate(prometheus_target_scrapes_sample_out_of_bounds_total[1m]))',
|
||||
'sum by (job) (rate(prometheus_target_scrapes_sample_out_of_order_total[1m]))',
|
||||
], if showMultiCluster then [
|
||||
'exceeded body size limit: {{cluster}} {{job}} {{instance}}',
|
||||
'exceeded sample limit: {{cluster}} {{job}} {{instance}}',
|
||||
'duplicate timestamp: {{cluster}} {{job}} {{instance}}',
|
||||
'out of bounds: {{cluster}} {{job}} {{instance}}',
|
||||
'out of order: {{cluster}} {{job}} {{instance}}',
|
||||
] else [
|
||||
'exceeded body size limit: {{job}}',
|
||||
'exceeded sample limit: {{job}}',
|
||||
'duplicate timestamp: {{job}}',
|
||||
'out of bounds: {{job}}',
|
||||
'out of order: {{job}}',
|
||||
]) +
|
||||
g.stack
|
||||
)
|
||||
.addPanel(
|
||||
g.panel('Appended Samples') +
|
||||
g.queryPanel('rate(prometheus_tsdb_head_samples_appended_total{cluster=~"$cluster", job=~"$job",instance=~"$instance"}[5m])', '{{cluster}} {{job}} {{instance}}') +
|
||||
g.queryPanel(if showMultiCluster then 'rate(prometheus_tsdb_head_samples_appended_total{cluster=~"$cluster", job=~"$job",instance=~"$instance"}[5m])'
|
||||
else 'rate(prometheus_tsdb_head_samples_appended_total{job=~"$job",instance=~"$instance"}[5m])',
|
||||
if showMultiCluster then '{{cluster}} {{job}} {{instance}}'
|
||||
else '{{job}} {{instance}}') +
|
||||
g.stack
|
||||
)
|
||||
)
|
||||
|
@ -80,12 +115,18 @@ local template = grafana.template;
|
|||
g.row('Storage')
|
||||
.addPanel(
|
||||
g.panel('Head Series') +
|
||||
g.queryPanel('prometheus_tsdb_head_series{cluster=~"$cluster",job=~"$job",instance=~"$instance"}', '{{cluster}} {{job}} {{instance}} head series') +
|
||||
g.queryPanel(if showMultiCluster then 'prometheus_tsdb_head_series{cluster=~"$cluster",job=~"$job",instance=~"$instance"}'
|
||||
else 'prometheus_tsdb_head_series{job=~"$job",instance=~"$instance"}',
|
||||
if showMultiCluster then '{{cluster}} {{job}} {{instance}} head series'
|
||||
else '{{job}} {{instance}} head series') +
|
||||
g.stack
|
||||
)
|
||||
.addPanel(
|
||||
g.panel('Head Chunks') +
|
||||
g.queryPanel('prometheus_tsdb_head_chunks{cluster=~"$cluster",job=~"$job",instance=~"$instance"}', '{{cluster}} {{job}} {{instance}} head chunks') +
|
||||
g.queryPanel(if showMultiCluster then 'prometheus_tsdb_head_chunks{cluster=~"$cluster",job=~"$job",instance=~"$instance"}'
|
||||
else 'prometheus_tsdb_head_chunks{job=~"$job",instance=~"$instance"}',
|
||||
if showMultiCluster then '{{cluster}} {{job}} {{instance}} head chunks'
|
||||
else '{{job}} {{instance}} head chunks') +
|
||||
g.stack
|
||||
)
|
||||
)
|
||||
|
@ -93,12 +134,18 @@ local template = grafana.template;
|
|||
g.row('Query')
|
||||
.addPanel(
|
||||
g.panel('Query Rate') +
|
||||
g.queryPanel('rate(prometheus_engine_query_duration_seconds_count{cluster=~"$cluster",job=~"$job",instance=~"$instance",slice="inner_eval"}[5m])', '{{cluster}} {{job}} {{instance}}') +
|
||||
g.queryPanel(if showMultiCluster then 'rate(prometheus_engine_query_duration_seconds_count{cluster=~"$cluster",job=~"$job",instance=~"$instance",slice="inner_eval"}[5m])'
|
||||
else 'rate(prometheus_engine_query_duration_seconds_count{job=~"$job",instance=~"$instance",slice="inner_eval"}[5m])',
|
||||
if showMultiCluster then '{{cluster}} {{job}} {{instance}}'
|
||||
else '{{job}} {{instance}}') +
|
||||
g.stack,
|
||||
)
|
||||
.addPanel(
|
||||
g.panel('Stage Duration') +
|
||||
g.queryPanel('max by (slice) (prometheus_engine_query_duration_seconds{quantile="0.9",cluster=~"$cluster", job=~"$job",instance=~"$instance"}) * 1e3', '{{slice}}') +
|
||||
g.queryPanel(if showMultiCluster then 'max by (slice) (prometheus_engine_query_duration_seconds{quantile="0.9",cluster=~"$cluster", job=~"$job",instance=~"$instance"}) * 1e3'
|
||||
else 'max by (slice) (prometheus_engine_query_duration_seconds{quantile="0.9",job=~"$job",instance=~"$instance"}) * 1e3',
|
||||
if showMultiCluster then '{{slice}}'
|
||||
else '{{slice}}') +
|
||||
{ yaxes: g.yaxes('ms') } +
|
||||
g.stack,
|
||||
)
|
||||
|
|
96
go.mod
96
go.mod
|
@ -5,18 +5,18 @@ go 1.21
|
|||
require (
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.2
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5 v5.6.0
|
||||
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
|
||||
github.com/Code-Hex/go-generics-cache v1.5.1
|
||||
github.com/KimMachineGun/automemlimit v0.6.0
|
||||
github.com/KimMachineGun/automemlimit v0.6.1
|
||||
github.com/alecthomas/kingpin/v2 v2.4.0
|
||||
github.com/alecthomas/units v0.0.0-20231202071711-9a357b53e9c9
|
||||
github.com/aws/aws-sdk-go v1.51.25
|
||||
github.com/aws/aws-sdk-go v1.53.16
|
||||
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.113.0
|
||||
github.com/docker/docker v26.0.1+incompatible
|
||||
github.com/digitalocean/godo v1.117.0
|
||||
github.com/docker/docker v26.1.3+incompatible
|
||||
github.com/edsrzf/mmap-go v1.1.0
|
||||
github.com/envoyproxy/go-control-plane v0.12.0
|
||||
github.com/envoyproxy/protoc-gen-validate v1.0.4
|
||||
|
@ -29,60 +29,60 @@ require (
|
|||
github.com/gogo/protobuf v1.3.2
|
||||
github.com/golang/snappy v0.0.4
|
||||
github.com/google/go-cmp v0.6.0
|
||||
github.com/google/pprof v0.0.0-20240416155748-26353dc0451f
|
||||
github.com/google/pprof v0.0.0-20240528025155-186aa0362fba
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/gophercloud/gophercloud v1.11.0
|
||||
github.com/grafana/regexp v0.0.0-20221122212121-6b5c0a4cb7fd
|
||||
github.com/gophercloud/gophercloud v1.12.0
|
||||
github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0
|
||||
github.com/hashicorp/consul/api v1.28.2
|
||||
github.com/hashicorp/nomad/api v0.0.0-20240418183417-ea5f2f6748c7
|
||||
github.com/hetznercloud/hcloud-go/v2 v2.7.2
|
||||
github.com/hashicorp/consul/api v1.29.1
|
||||
github.com/hashicorp/nomad/api v0.0.0-20240604134157-e73d8bb1140d
|
||||
github.com/hetznercloud/hcloud-go/v2 v2.9.0
|
||||
github.com/ionos-cloud/sdk-go/v6 v6.1.11
|
||||
github.com/json-iterator/go v1.1.12
|
||||
github.com/klauspost/compress v1.17.8
|
||||
github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b
|
||||
github.com/linode/linodego v1.33.0
|
||||
github.com/linode/linodego v1.35.0
|
||||
github.com/miekg/dns v1.1.59
|
||||
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-20230430225905-43f6cf3098c1
|
||||
github.com/oklog/run v1.1.0
|
||||
github.com/oklog/ulid v1.3.1
|
||||
github.com/ovh/go-ovh v1.4.3
|
||||
github.com/ovh/go-ovh v1.5.1
|
||||
github.com/prometheus/alertmanager v0.27.0
|
||||
github.com/prometheus/client_golang v1.19.0
|
||||
github.com/prometheus/client_golang v1.19.1
|
||||
github.com/prometheus/client_model v0.6.1
|
||||
github.com/prometheus/common v0.53.0
|
||||
github.com/prometheus/common v0.54.0
|
||||
github.com/prometheus/common/assets v0.2.0
|
||||
github.com/prometheus/common/sigv4 v0.1.0
|
||||
github.com/prometheus/exporter-toolkit v0.11.0
|
||||
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.26
|
||||
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.27
|
||||
github.com/shurcooL/httpfs v0.0.0-20230704072500-f1e31cf0ba5c
|
||||
github.com/stretchr/testify v1.9.0
|
||||
github.com/vultr/govultr/v2 v2.17.2
|
||||
go.opentelemetry.io/collector/pdata v1.5.0
|
||||
go.opentelemetry.io/collector/semconv v0.98.0
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.50.0
|
||||
go.opentelemetry.io/otel v1.25.0
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.25.0
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.25.0
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.25.0
|
||||
go.opentelemetry.io/otel/sdk v1.25.0
|
||||
go.opentelemetry.io/otel/trace v1.25.0
|
||||
go.opentelemetry.io/collector/pdata v1.8.0
|
||||
go.opentelemetry.io/collector/semconv v0.101.0
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.52.0
|
||||
go.opentelemetry.io/otel v1.27.0
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.27.0
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.27.0
|
||||
go.opentelemetry.io/otel/sdk v1.27.0
|
||||
go.opentelemetry.io/otel/trace v1.27.0
|
||||
go.uber.org/atomic v1.11.0
|
||||
go.uber.org/automaxprocs v1.5.3
|
||||
go.uber.org/goleak v1.3.0
|
||||
go.uber.org/multierr v1.11.0
|
||||
golang.org/x/net v0.24.0
|
||||
golang.org/x/oauth2 v0.19.0
|
||||
golang.org/x/net v0.26.0
|
||||
golang.org/x/oauth2 v0.21.0
|
||||
golang.org/x/sync v0.7.0
|
||||
golang.org/x/sys v0.19.0
|
||||
golang.org/x/sys v0.21.0
|
||||
golang.org/x/time v0.5.0
|
||||
golang.org/x/tools v0.20.0
|
||||
google.golang.org/api v0.177.0
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240415180920-8c6c420018be
|
||||
google.golang.org/grpc v1.63.2
|
||||
google.golang.org/protobuf v1.34.0
|
||||
golang.org/x/tools v0.22.0
|
||||
google.golang.org/api v0.183.0
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157
|
||||
google.golang.org/grpc v1.64.0
|
||||
google.golang.org/protobuf v1.34.1
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
k8s.io/api v0.29.3
|
||||
|
@ -93,10 +93,10 @@ require (
|
|||
)
|
||||
|
||||
require (
|
||||
cloud.google.com/go/auth v0.3.0 // indirect
|
||||
cloud.google.com/go/auth v0.5.1 // indirect
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.2 // indirect
|
||||
cloud.google.com/go/compute/metadata v0.3.0 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.6.0 // indirect
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 // indirect
|
||||
github.com/Microsoft/go-winio v0.6.1 // indirect
|
||||
github.com/armon/go-metrics v0.4.1 // indirect
|
||||
|
@ -104,7 +104,7 @@ require (
|
|||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
|
||||
github.com/cilium/ebpf v0.11.0 // indirect
|
||||
github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa // indirect
|
||||
github.com/cncf/xds/go v0.0.0-20240318125728-8a4994d93e50 // indirect
|
||||
github.com/containerd/cgroups/v3 v3.0.3 // indirect
|
||||
github.com/containerd/log v0.1.0 // indirect
|
||||
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
|
||||
|
@ -114,7 +114,7 @@ require (
|
|||
github.com/docker/go-units v0.5.0 // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
|
||||
github.com/evanphx/json-patch v5.6.0+incompatible // indirect
|
||||
github.com/fatih/color v1.15.0 // indirect
|
||||
github.com/fatih/color v1.16.0 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||
github.com/ghodss/yaml v1.0.0 // indirect
|
||||
github.com/go-kit/kit v0.12.0 // indirect
|
||||
|
@ -128,7 +128,7 @@ require (
|
|||
github.com/go-openapi/spec v0.20.14 // indirect
|
||||
github.com/go-openapi/swag v0.22.9 // indirect
|
||||
github.com/go-openapi/validate v0.23.0 // indirect
|
||||
github.com/go-resty/resty/v2 v2.12.0 // indirect
|
||||
github.com/go-resty/resty/v2 v2.13.1 // indirect
|
||||
github.com/godbus/dbus/v5 v5.0.4 // indirect
|
||||
github.com/golang-jwt/jwt/v5 v5.2.1 // indirect
|
||||
github.com/golang/glog v1.2.0 // indirect
|
||||
|
@ -139,9 +139,9 @@ require (
|
|||
github.com/google/gofuzz v1.2.0 // indirect
|
||||
github.com/google/s2a-go v0.1.7 // indirect
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
|
||||
github.com/googleapis/gax-go/v2 v2.12.3 // indirect
|
||||
github.com/googleapis/gax-go/v2 v2.12.4 // indirect
|
||||
github.com/gorilla/websocket v1.5.0 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect
|
||||
github.com/hashicorp/cronexpr v1.1.2 // indirect
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||
|
@ -160,7 +160,7 @@ require (
|
|||
github.com/kylelemons/godebug v1.1.0 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.19 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/moby/docker-image-spec v1.3.1 // indirect
|
||||
|
@ -182,14 +182,14 @@ require (
|
|||
github.com/xhit/go-str2duration/v2 v2.1.0 // indirect
|
||||
go.mongodb.org/mongo-driver v1.14.0 // indirect
|
||||
go.opencensus.io v0.24.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.25.0 // indirect
|
||||
go.opentelemetry.io/proto/otlp v1.1.0 // indirect
|
||||
golang.org/x/crypto v0.22.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.27.0 // indirect
|
||||
go.opentelemetry.io/proto/otlp v1.2.0 // indirect
|
||||
golang.org/x/crypto v0.24.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20240119083558-1b970713d09a // indirect
|
||||
golang.org/x/mod v0.17.0 // indirect
|
||||
golang.org/x/term v0.19.0 // indirect
|
||||
golang.org/x/text v0.14.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240429193739-8cf5692501f6 // indirect
|
||||
golang.org/x/mod v0.18.0 // indirect
|
||||
golang.org/x/term v0.21.0 // indirect
|
||||
golang.org/x/text v0.16.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
gotest.tools/v3 v3.0.3 // indirect
|
||||
|
|
210
go.sum
210
go.sum
|
@ -12,8 +12,8 @@ cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bP
|
|||
cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
|
||||
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
|
||||
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
|
||||
cloud.google.com/go/auth v0.3.0 h1:PRyzEpGfx/Z9e8+lHsbkoUVXD0gnu4MNmm7Gp8TQNIs=
|
||||
cloud.google.com/go/auth v0.3.0/go.mod h1:lBv6NKTWp8E3LPzmO1TbiiRKc4drLOfHsgmlH9ogv5w=
|
||||
cloud.google.com/go/auth v0.5.1 h1:0QNO7VThG54LUzKiQxv8C6x1YX7lUrzlAa1nVLF8CIw=
|
||||
cloud.google.com/go/auth v0.5.1/go.mod h1:vbZT8GjzDf3AVqCcQmqeeM32U9HBFc32vVVAbwDsa6s=
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.2 h1:+TTV8aXpjeChS9M+aTtN/TjdQnzJvmzKFt//oWu7HX4=
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.2/go.mod h1:wcYjgpZI9+Yu7LyYBg4pqSiaRkfEK3GQcpb7C/uyF1Q=
|
||||
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
||||
|
@ -40,10 +40,10 @@ github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1 h1:E+OJmp2tPvt1W+amx48v1eqb
|
|||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1/go.mod h1:a6xsAQUZg+VsS3TJ05SRp524Hs4pZ/AeFSr5ENf0Yjo=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.2 h1:FDif4R1+UUR+00q6wquyX90K7A8dN+R5E8GEadoP7sU=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.2/go.mod h1:aiYBYui4BJ/BJCAIKs92XiPyQfTaBWqvHujDwKb6CBU=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2 h1:LqbJ/WzJUwBf8UiaSzgX7aMclParm9/5Vgp+TY51uBQ=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2/go.mod h1:yInRyqWXAuaPrgI7p70+lDDgh3mlBohis29jGMISnmc=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5 v5.6.0 h1:ui3YNbxfW7J3tTFIZMH6LIGRjCngp+J+nIFlnizfNTE=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5 v5.6.0/go.mod h1:gZmgV+qBqygoznvqo2J9oKZAFziqhLZ2xE/WVUmzkHA=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.6.0 h1:sUFnFjzDUie80h24I7mrKtwCKgLY9L8h5Tp2x9+TWqk=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.6.0/go.mod h1:52JbnQTp15qg5mRkMBHwp0j0ZFwHJ42Sx3zVV5RE9p0=
|
||||
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=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal/v2 v2.0.0/go.mod h1:LRr2FzBTQlONPPa5HREE5+RjSCTXl7BwOvYOaWTqCaI=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v4 v4.3.0 h1:bXwSugBiSbgtz7rOtbfGf+woewp4f06orW9OP5BjHLA=
|
||||
|
@ -59,8 +59,8 @@ github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym
|
|||
github.com/Code-Hex/go-generics-cache v1.5.1 h1:6vhZGc5M7Y/YD8cIUcY8kcuQLB4cHR7U+0KMqAA0KcU=
|
||||
github.com/Code-Hex/go-generics-cache v1.5.1/go.mod h1:qxcC9kRVrct9rHeiYpFWSoW1vxyillCVzX13KZG8dl4=
|
||||
github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
|
||||
github.com/KimMachineGun/automemlimit v0.6.0 h1:p/BXkH+K40Hax+PuWWPQ478hPjsp9h1CPDhLlA3Z37E=
|
||||
github.com/KimMachineGun/automemlimit v0.6.0/go.mod h1:T7xYht7B8r6AG/AqFcUdc7fzd2bIdBKmepfP2S1svPY=
|
||||
github.com/KimMachineGun/automemlimit v0.6.1 h1:ILa9j1onAAMadBsyyUJv5cack8Y1WT26yLj/V+ulKp8=
|
||||
github.com/KimMachineGun/automemlimit v0.6.1/go.mod h1:T7xYht7B8r6AG/AqFcUdc7fzd2bIdBKmepfP2S1svPY=
|
||||
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
|
||||
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
|
||||
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
|
||||
|
@ -92,8 +92,8 @@ github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:W
|
|||
github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU=
|
||||
github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
||||
github.com/aws/aws-sdk-go v1.38.35/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
|
||||
github.com/aws/aws-sdk-go v1.51.25 h1:DjTT8mtmsachhV6yrXR8+yhnG6120dazr720nopRsls=
|
||||
github.com/aws/aws-sdk-go v1.51.25/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk=
|
||||
github.com/aws/aws-sdk-go v1.53.16 h1:8oZjKQO/ml1WLUZw5hvF7pvYjPf8o9f57Wldoy/q9Qc=
|
||||
github.com/aws/aws-sdk-go v1.53.16/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk=
|
||||
github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g=
|
||||
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=
|
||||
|
@ -120,8 +120,8 @@ github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp
|
|||
github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa h1:jQCWAUqqlij9Pgj2i/PB79y4KOPYVyFYdROxgaCwdTQ=
|
||||
github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa/go.mod h1:x/1Gn8zydmfq8dk6e9PdstVsDgu9RuyIIJqAaF//0IM=
|
||||
github.com/cncf/xds/go v0.0.0-20240318125728-8a4994d93e50 h1:DBmgJDC9dTfkVyGgipamEh2BpGYxScCH1TOF1LL1cXc=
|
||||
github.com/cncf/xds/go v0.0.0-20240318125728-8a4994d93e50/go.mod h1:5e1+Vvlzido69INQaVO6d87Qn543Xr6nooe9Kz7oBFM=
|
||||
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
|
||||
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
|
||||
github.com/containerd/cgroups/v3 v3.0.3 h1:S5ByHZ/h9PMe5IOQoN7E+nMc2UcLEM/V48DGDJ9kip0=
|
||||
|
@ -143,14 +143,14 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8Yc
|
|||
github.com/dennwc/varint v1.0.0 h1:kGNFFSSw8ToIy3obO/kKr8U9GZYUAxQEVuix4zfDWzE=
|
||||
github.com/dennwc/varint v1.0.0/go.mod h1:hnItb35rvZvJrbTALZtY/iQfDs48JKRG1RPpgziApxA=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/digitalocean/godo v1.113.0 h1:CLtCxlP4wDAjKIQ+Hshht/UNbgAp8/J/XBH1ZtDCF9Y=
|
||||
github.com/digitalocean/godo v1.113.0/go.mod h1:Z2mTP848Vi3IXXl5YbPekUgr4j4tOePomA+OE1Ag98w=
|
||||
github.com/digitalocean/godo v1.117.0 h1:WVlTe09melDYTd7VCVyvHcNWbgB+uI1O115+5LOtdSw=
|
||||
github.com/digitalocean/godo v1.117.0/go.mod h1:Vk0vpCot2HOAJwc5WE8wljZGtJ3ZtWIc8MQ8rF38sdo=
|
||||
github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0=
|
||||
github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
|
||||
github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI=
|
||||
github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=
|
||||
github.com/docker/docker v26.0.1+incompatible h1:t39Hm6lpXuXtgkF0dm1t9a5HkbUfdGy6XbWexmGr+hA=
|
||||
github.com/docker/docker v26.0.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker v26.1.3+incompatible h1:lLCzRbrVZrljpVNobJu1J2FHk8V0s4BawoZippkc+xo=
|
||||
github.com/docker/docker v26.1.3+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
|
||||
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
|
||||
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
|
||||
|
@ -180,8 +180,8 @@ github.com/facette/natsort v0.0.0-20181210072756-2cd4dd1e2dcb/go.mod h1:bH6Xx7IW
|
|||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
|
||||
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
|
||||
github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
|
||||
github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
|
||||
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/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
|
||||
|
@ -232,8 +232,8 @@ github.com/go-openapi/swag v0.22.9 h1:XX2DssF+mQKM2DHsbgZK74y/zj4mo9I99+89xUmuZC
|
|||
github.com/go-openapi/swag v0.22.9/go.mod h1:3/OXnFfnMAwBD099SwYRk7GD3xOrr1iL7d/XNLXVVwE=
|
||||
github.com/go-openapi/validate v0.23.0 h1:2l7PJLzCis4YUGEoW6eoQw3WhyM65WSIcjX6SQnlfDw=
|
||||
github.com/go-openapi/validate v0.23.0/go.mod h1:EeiAZ5bmpSIOJV1WLfyYF9qp/B1ZgSaEpHTJHtN5cbE=
|
||||
github.com/go-resty/resty/v2 v2.12.0 h1:rsVL8P90LFvkUYq/V5BTVe203WfRIU4gvcf+yfzJzGA=
|
||||
github.com/go-resty/resty/v2 v2.12.0/go.mod h1:o0yGPrkS3lOe1+eFajk6kBW8ScXzwU3hD69/gt2yB/0=
|
||||
github.com/go-resty/resty/v2 v2.13.1 h1:x+LHXBI2nMB1vqndymf26quycC4aggYJ7DECYbiz03g=
|
||||
github.com/go-resty/resty/v2 v2.13.1/go.mod h1:GznXlLxkq6Nh4sU59rPmUw3VtgpO3aS96ORAI6Q7d+0=
|
||||
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
|
||||
|
@ -319,8 +319,8 @@ github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hf
|
|||
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20240416155748-26353dc0451f h1:WpZiq8iqvGjJ3m3wzAVKL6+0vz7VkE79iSy9GII00II=
|
||||
github.com/google/pprof v0.0.0-20240416155748-26353dc0451f/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw=
|
||||
github.com/google/pprof v0.0.0-20240528025155-186aa0362fba h1:ql1qNgCyOB7iAEk8JTNM+zJrgIbnyCKX/wdlyPufP5g=
|
||||
github.com/google/pprof v0.0.0-20240528025155-186aa0362fba/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o=
|
||||
github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw=
|
||||
|
@ -332,10 +332,10 @@ github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfF
|
|||
github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/googleapis/gax-go/v2 v2.12.3 h1:5/zPPDvw8Q1SuXjrqrZslrqT7dL/uJT2CQii/cLCKqA=
|
||||
github.com/googleapis/gax-go/v2 v2.12.3/go.mod h1:AKloxT6GtNbaLm8QTNSidHUVsHYcBHwWRvkNFJUQcS4=
|
||||
github.com/gophercloud/gophercloud v1.11.0 h1:ls0O747DIq1D8SUHc7r2vI8BFbMLeLFuENaAIfEx7OM=
|
||||
github.com/gophercloud/gophercloud v1.11.0/go.mod h1:aAVqcocTSXh2vYFZ1JTvx4EQmfgzxRcNupUfxZbBNDM=
|
||||
github.com/googleapis/gax-go/v2 v2.12.4 h1:9gWcmF85Wvq4ryPFvGFaOgPIs1AQX0d0bcbGw4Z96qg=
|
||||
github.com/googleapis/gax-go/v2 v2.12.4/go.mod h1:KYEYLorsnIGDi/rPC8b5TdlB9kbKoFubselGIoBMCwI=
|
||||
github.com/gophercloud/gophercloud v1.12.0 h1:Jrz16vPAL93l80q16fp8NplrTCp93y7rZh2P3Q4Yq7g=
|
||||
github.com/gophercloud/gophercloud v1.12.0/go.mod h1:aAVqcocTSXh2vYFZ1JTvx4EQmfgzxRcNupUfxZbBNDM=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
||||
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
|
@ -343,21 +343,23 @@ github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2z
|
|||
github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
|
||||
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/grafana/regexp v0.0.0-20221122212121-6b5c0a4cb7fd h1:PpuIBO5P3e9hpqBD0O/HjhShYuM6XE0i/lbE6J94kww=
|
||||
github.com/grafana/regexp v0.0.0-20221122212121-6b5c0a4cb7fd/go.mod h1:M5qHK+eWfAv8VR/265dIuEpL3fNfeC21tXXp9itM24A=
|
||||
github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc h1:GN2Lv3MGO7AS6PrRoT6yV5+wkrOpcszoIsO4+4ds248=
|
||||
github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc/go.mod h1:+JKpmjMGhpgPL+rXZ5nsZieVzvarn86asRlBg4uNGnk=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0 h1:Wqo399gCIufwto+VfwCSvsnfGpF/w5E9CNxSwbpD6No=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0/go.mod h1:qmOFXW2epJhM0qSnUUYpldc7gVz2KMQwJ/QYCDIa7XU=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k=
|
||||
github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE=
|
||||
github.com/hashicorp/consul/api v1.28.2 h1:mXfkRHrpHN4YY3RqL09nXU1eHKLNiuAN4kHvDQ16k/8=
|
||||
github.com/hashicorp/consul/api v1.28.2/go.mod h1:KyzqzgMEya+IZPcD65YFoOVAgPpbfERu4I/tzG6/ueE=
|
||||
github.com/hashicorp/consul/api v1.29.1 h1:UEwOjYJrd3lG1x5w7HxDRMGiAUPrb3f103EoeKuuEcc=
|
||||
github.com/hashicorp/consul/api v1.29.1/go.mod h1:lumfRkY/coLuqMICkI7Fh3ylMG31mQSRZyef2c5YvJI=
|
||||
github.com/hashicorp/consul/proto-public v0.6.1 h1:+uzH3olCrksXYWAYHKqK782CtK9scfqH+Unlw3UHhCg=
|
||||
github.com/hashicorp/consul/proto-public v0.6.1/go.mod h1:cXXbOg74KBNGajC+o8RlA502Esf0R9prcoJgiOX/2Tg=
|
||||
github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
|
||||
github.com/hashicorp/consul/sdk v0.16.0 h1:SE9m0W6DEfgIVCJX7xU+iv/hUl4m/nxqMTnCdMxDpJ8=
|
||||
github.com/hashicorp/consul/sdk v0.16.0/go.mod h1:7pxqqhqoaPqnBnzXD1StKed62LqJeClzVsUEy85Zr0A=
|
||||
github.com/hashicorp/consul/sdk v0.16.1 h1:V8TxTnImoPD5cj0U9Spl0TUxcytjcbbJeADFF07KdHg=
|
||||
github.com/hashicorp/consul/sdk v0.16.1/go.mod h1:fSXvwxB2hmh1FMZCNl6PwX0Q/1wdWtHJcZ7Ea5tns0s=
|
||||
github.com/hashicorp/cronexpr v1.1.2 h1:wG/ZYIKT+RT3QkOdgYc+xsKWVRgnxJ1OJtjjy84fJ9A=
|
||||
github.com/hashicorp/cronexpr v1.1.2/go.mod h1:P4wA0KBl9C5q2hABiMO7cp6jcIg96CDh1Efb3g1PWA4=
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
|
@ -408,13 +410,13 @@ github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/
|
|||
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
|
||||
github.com/hashicorp/memberlist v0.5.0 h1:EtYPN8DpAURiapus508I4n9CzHs2W+8NZGbmmR/prTM=
|
||||
github.com/hashicorp/memberlist v0.5.0/go.mod h1:yvyXLpo0QaGE59Y7hDTsTzDD25JYBZ4mHgHUZ8lrOI0=
|
||||
github.com/hashicorp/nomad/api v0.0.0-20240418183417-ea5f2f6748c7 h1:pjE59CS2C9Bg+Xby0ROrnZSSBWtKwx3Sf9gqsrvIFSA=
|
||||
github.com/hashicorp/nomad/api v0.0.0-20240418183417-ea5f2f6748c7/go.mod h1:svtxn6QnrQ69P23VvIWMR34tg3vmwLz4UdUzm1dSCgE=
|
||||
github.com/hashicorp/nomad/api v0.0.0-20240604134157-e73d8bb1140d h1:KHq+mAzWSkumj4PDoXc5VZbycPGcmYu8tohgVLQ6SIc=
|
||||
github.com/hashicorp/nomad/api v0.0.0-20240604134157-e73d8bb1140d/go.mod h1:svtxn6QnrQ69P23VvIWMR34tg3vmwLz4UdUzm1dSCgE=
|
||||
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
|
||||
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.7.2 h1:UlE7n1GQZacCfyjv9tDVUN7HZfOXErPIfM/M039u9A0=
|
||||
github.com/hetznercloud/hcloud-go/v2 v2.7.2/go.mod h1:49tIV+pXRJTUC7fbFZ03s45LKqSQdOPP5y91eOnJo/k=
|
||||
github.com/hetznercloud/hcloud-go/v2 v2.9.0 h1:s0N6R7Zoi2DPfMtUF5o9VeUBzTtHVY6MIkHOQnfu/AY=
|
||||
github.com/hetznercloud/hcloud-go/v2 v2.9.0/go.mod h1:qtW/TuU7Bs16ibXl/ktJarWqU2LwHr7eGlwoilHxtgg=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
|
@ -471,8 +473,8 @@ github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0
|
|||
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||
github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
|
||||
github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
|
||||
github.com/linode/linodego v1.33.0 h1:cX2FYry7r6CA1ujBMsdqiM4VhvIQtnWsOuVblzfBhCw=
|
||||
github.com/linode/linodego v1.33.0/go.mod h1:dSJJgIwqZCF5wnpuC6w5cyIbRtcexAm7uVvuJopGB40=
|
||||
github.com/linode/linodego v1.35.0 h1:rIhUeCHBLEDlkoRnOTwzSGzljQ3ksXwLxacmXnrV+Do=
|
||||
github.com/linode/linodego v1.35.0/go.mod h1:JxuhOEAMfSxun6RU5/MgTKH2GGTmFrhKRj3wL1NFin0=
|
||||
github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
|
||||
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
||||
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
|
@ -490,8 +492,8 @@ github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOA
|
|||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
|
||||
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/maxatome/go-testdeep v1.12.0 h1:Ql7Go8Tg0C1D/uMMX59LAoYK7LffeJQ6X2T04nTH68g=
|
||||
|
@ -572,8 +574,8 @@ github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxS
|
|||
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
|
||||
github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
|
||||
github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
|
||||
github.com/ovh/go-ovh v1.4.3 h1:Gs3V823zwTFpzgGLZNI6ILS4rmxZgJwJCz54Er9LwD0=
|
||||
github.com/ovh/go-ovh v1.4.3/go.mod h1:AkPXVtgwB6xlKblMjRKJJmjRp+ogrE7fz2lVgcQY8SY=
|
||||
github.com/ovh/go-ovh v1.5.1 h1:P8O+7H+NQuFK9P/j4sFW5C0fvSS2DnHYGPwdVCp45wI=
|
||||
github.com/ovh/go-ovh v1.5.1/go.mod h1:cTVDnl94z4tl8pP1uZ/8jlVxntjSIf09bNcQ5TJSC7c=
|
||||
github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM=
|
||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||
github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY=
|
||||
|
@ -607,8 +609,8 @@ github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeD
|
|||
github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU=
|
||||
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
|
||||
github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
|
||||
github.com/prometheus/client_golang v1.19.0 h1:ygXvpU1AoN1MhdzckN+PyD9QJOSD4x7kmXYlnfbA6JU=
|
||||
github.com/prometheus/client_golang v1.19.0/go.mod h1:ZRM9uEAypZakd+q/x7+gmsvXdURP+DABIEIjnmDdp+k=
|
||||
github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE=
|
||||
github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
|
@ -624,8 +626,8 @@ github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8b
|
|||
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
|
||||
github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
|
||||
github.com/prometheus/common v0.29.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
|
||||
github.com/prometheus/common v0.53.0 h1:U2pL9w9nmJwJDa4qqLQ3ZaePJ6ZTwt7cMD3AG3+aLCE=
|
||||
github.com/prometheus/common v0.53.0/go.mod h1:BrxBKv3FWBIGXw89Mg1AeBq7FSyRzXWI3l3e7W3RN5U=
|
||||
github.com/prometheus/common v0.54.0 h1:ZlZy0BgJhTwVZUn7dLOkwCZHUkrAqd3WYtcFCWnM1D8=
|
||||
github.com/prometheus/common v0.54.0/go.mod h1:/TQgMJP5CuVYveyT7n/0Ix8yLNNXy9yRSkhnLTHPDIQ=
|
||||
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/common/sigv4 v0.1.0 h1:qoVebwtwwEhS85Czm2dSROY5fTo2PAPEVdDeppTwGX4=
|
||||
|
@ -644,13 +646,13 @@ github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqn
|
|||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
|
||||
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
|
||||
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
|
||||
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||
github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
|
||||
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.26 h1:F+GIVtGqCFxPxO46ujf8cEOP574MBoRm3gNbPXECbxs=
|
||||
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.26/go.mod h1:fCa7OJZ/9DRTnOKmxvT6pn+LPWUptQAmHF/SBJUGEcg=
|
||||
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.27 h1:yGAraK1uUjlhSXgNMIy8o/J4LFNcy7yeipBqt9N9mVg=
|
||||
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.27/go.mod h1:fCa7OJZ/9DRTnOKmxvT6pn+LPWUptQAmHF/SBJUGEcg=
|
||||
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.7.1 h1:UJcjSAI3aUKx52kfcfhblgyhZceouhvvs3OYdWgn+PY=
|
||||
|
@ -722,28 +724,28 @@ go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
|||
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
|
||||
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
|
||||
go.opentelemetry.io/collector/pdata v1.5.0 h1:1fKTmUpr0xCOhP/B0VEvtz7bYPQ45luQ8XFyA07j8LE=
|
||||
go.opentelemetry.io/collector/pdata v1.5.0/go.mod h1:TYj8aKRWZyT/KuKQXKyqSEvK/GV+slFaDMEI+Ke64Yw=
|
||||
go.opentelemetry.io/collector/semconv v0.98.0 h1:zO4L4TmlxXoYu8UgPeYElGY19BW7wPjM+quL5CzoOoY=
|
||||
go.opentelemetry.io/collector/semconv v0.98.0/go.mod h1:8ElcRZ8Cdw5JnvhTOQOdYizkJaQ10Z2fS+R6djOnj6A=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.50.0 h1:cEPbyTSEHlQR89XVlyo78gqluF8Y3oMeBkXGWzQsfXY=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.50.0/go.mod h1:DKdbWcT4GH1D0Y3Sqt/PFXt2naRKDWtU+eE6oLdFNA8=
|
||||
go.opentelemetry.io/otel v1.25.0 h1:gldB5FfhRl7OJQbUHt/8s0a7cE8fbsPAtdpRaApKy4k=
|
||||
go.opentelemetry.io/otel v1.25.0/go.mod h1:Wa2ds5NOXEMkCmUou1WA7ZBfLTHWIsp034OVD7AO+Vg=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.25.0 h1:dT33yIHtmsqpixFsSQPwNeY5drM9wTcoL8h0FWF4oGM=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.25.0/go.mod h1:h95q0LBGh7hlAC08X2DhSeyIG02YQ0UyioTCVAqRPmc=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.25.0 h1:vOL89uRfOCCNIjkisd0r7SEdJF3ZJFyCNY34fdZs8eU=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.25.0/go.mod h1:8GlBGcDk8KKi7n+2S4BT/CPZQYH3erLu0/k64r1MYgo=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.25.0 h1:Mbi5PKN7u322woPa85d7ebZ+SOvEoPvoiBu+ryHWgfA=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.25.0/go.mod h1:e7ciERRhZaOZXVjx5MiL8TK5+Xv7G5Gv5PA2ZDEJdL8=
|
||||
go.opentelemetry.io/otel/metric v1.25.0 h1:LUKbS7ArpFL/I2jJHdJcqMGxkRdxpPHE0VU/D4NuEwA=
|
||||
go.opentelemetry.io/otel/metric v1.25.0/go.mod h1:rkDLUSd2lC5lq2dFNrX9LGAbINP5B7WBkC78RXCpH5s=
|
||||
go.opentelemetry.io/otel/sdk v1.25.0 h1:PDryEJPC8YJZQSyLY5eqLeafHtG+X7FWnf3aXMtxbqo=
|
||||
go.opentelemetry.io/otel/sdk v1.25.0/go.mod h1:oFgzCM2zdsxKzz6zwpTZYLLQsFwc+K0daArPdIhuxkw=
|
||||
go.opentelemetry.io/otel/trace v1.25.0 h1:tqukZGLwQYRIFtSQM2u2+yfMVTgGVeqRLPUYx1Dq6RM=
|
||||
go.opentelemetry.io/otel/trace v1.25.0/go.mod h1:hCCs70XM/ljO+BeQkyFnbK28SBIJ/Emuha+ccrCRT7I=
|
||||
go.opentelemetry.io/proto/otlp v1.1.0 h1:2Di21piLrCqJ3U3eXGCTPHE9R8Nh+0uglSnOyxikMeI=
|
||||
go.opentelemetry.io/proto/otlp v1.1.0/go.mod h1:GpBHCBWiqvVLDqmHZsoMM3C5ySeKTC7ej/RNTae6MdY=
|
||||
go.opentelemetry.io/collector/pdata v1.8.0 h1:d/QQgZxB4Y+d3mqLVh2ozvzujUhloD3P/fk7X+In764=
|
||||
go.opentelemetry.io/collector/pdata v1.8.0/go.mod h1:/W7clu0wFC4WSRp94Ucn6Vm36Wkrt+tmtlDb1aiNZCY=
|
||||
go.opentelemetry.io/collector/semconv v0.101.0 h1:tOe9iTe9dDCnvz/bqgfNRr4w80kXG8505tQJ5h5v08Q=
|
||||
go.opentelemetry.io/collector/semconv v0.101.0/go.mod h1:8ElcRZ8Cdw5JnvhTOQOdYizkJaQ10Z2fS+R6djOnj6A=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.52.0 h1:9l89oX4ba9kHbBol3Xin3leYJ+252h0zszDtBwyKe2A=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.52.0/go.mod h1:XLZfZboOJWHNKUv7eH0inh0E9VV6eWDFB/9yJyTLPp0=
|
||||
go.opentelemetry.io/otel v1.27.0 h1:9BZoF3yMK/O1AafMiQTVu0YDj5Ea4hPhxCs7sGva+cg=
|
||||
go.opentelemetry.io/otel v1.27.0/go.mod h1:DMpAK8fzYRzs+bi3rS5REupisuqTheUlSZJ1WnZaPAQ=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.27.0 h1:R9DE4kQ4k+YtfLI2ULwX82VtNQ2J8yZmA7ZIF/D+7Mc=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.27.0/go.mod h1:OQFyQVrDlbe+R7xrEyDr/2Wr67Ol0hRUgsfA+V5A95s=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0 h1:qFffATk0X+HD+f1Z8lswGiOQYKHRlzfmdJm0wEaVrFA=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0/go.mod h1:MOiCmryaYtc+V0Ei+Tx9o5S1ZjA7kzLucuVuyzBZloQ=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.27.0 h1:QY7/0NeRPKlzusf40ZE4t1VlMKbqSNT7cJRYzWuja0s=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.27.0/go.mod h1:HVkSiDhTM9BoUJU8qE6j2eSWLLXvi1USXjyd2BXT8PY=
|
||||
go.opentelemetry.io/otel/metric v1.27.0 h1:hvj3vdEKyeCi4YaYfNjv2NUje8FqKqUY8IlF0FxV/ik=
|
||||
go.opentelemetry.io/otel/metric v1.27.0/go.mod h1:mVFgmRlhljgBiuk/MP/oKylr4hs85GZAylncepAX/ak=
|
||||
go.opentelemetry.io/otel/sdk v1.27.0 h1:mlk+/Y1gLPLn84U4tI8d3GNJmGT/eXe3ZuOXN9kTWmI=
|
||||
go.opentelemetry.io/otel/sdk v1.27.0/go.mod h1:Ha9vbLwJE6W86YstIywK2xFfPjbWlCuwPtMkKdz/Y4A=
|
||||
go.opentelemetry.io/otel/trace v1.27.0 h1:IqYb813p7cmbHk0a5y6pD5JPakbVfftRXABGt5/Rscw=
|
||||
go.opentelemetry.io/otel/trace v1.27.0/go.mod h1:6RiD1hkAprV4/q+yd2ln1HG9GoPx39SuvvstaLBl+l4=
|
||||
go.opentelemetry.io/proto/otlp v1.2.0 h1:pVeZGk7nXDC9O2hncA6nHldxEjm6LByfA2aN8IOkz94=
|
||||
go.opentelemetry.io/proto/otlp v1.2.0/go.mod h1:gGpR8txAl5M03pDhMC79G6SdqNV26naRm/KDsgaHD8A=
|
||||
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
|
||||
|
@ -771,9 +773,9 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
|
|||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
|
||||
golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=
|
||||
golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
|
||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||
golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI=
|
||||
golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
|
@ -808,8 +810,8 @@ 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.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
|
||||
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0=
|
||||
golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
|
@ -854,17 +856,17 @@ 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.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
||||
golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w=
|
||||
golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
|
||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ=
|
||||
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.19.0 h1:9+E/EZBCbTLNrbN35fHv/a/d/mOBatymz1zbtQrXpIg=
|
||||
golang.org/x/oauth2 v0.19.0/go.mod h1:vYi7skDa1x015PmRRYZ7+s1cWyPgrPiSYRe4rnsexc8=
|
||||
golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs=
|
||||
golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
|
@ -944,17 +946,17 @@ 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.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
|
||||
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
|
||||
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
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.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
|
||||
golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q=
|
||||
golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk=
|
||||
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
||||
golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA=
|
||||
golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
|
@ -964,8 +966,10 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
|||
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.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
|
||||
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
|
||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
|
@ -1022,8 +1026,8 @@ golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc
|
|||
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.20.0 h1:hz/CVckiOxybQvFw6h7b/q80NTr9IUQb4s1IIzW7KNY=
|
||||
golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg=
|
||||
golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA=
|
||||
golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c=
|
||||
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=
|
||||
|
@ -1043,8 +1047,8 @@ google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/
|
|||
google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
||||
google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
||||
google.golang.org/api v0.177.0 h1:8a0p/BbPa65GlqGWtUKxot4p0TV8OGOfyTjtmkXNXmk=
|
||||
google.golang.org/api v0.177.0/go.mod h1:srbhue4MLjkjbkux5p3dw/ocYOSZTaIEvf7bCOnFQDw=
|
||||
google.golang.org/api v0.183.0 h1:PNMeRDwo1pJdgNcFQ9GstuLe/noWKIc89pRWRLMvLwE=
|
||||
google.golang.org/api v0.183.0/go.mod h1:q43adC5/pHoSZTx5h2mSmdF7NcyfW9JuDyIOJAgS9ZQ=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
|
@ -1081,10 +1085,10 @@ google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1m
|
|||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
|
||||
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240415180920-8c6c420018be h1:Zz7rLWqp0ApfsR/l7+zSHhY3PMiH2xqgxlfYfAfNpoU=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240415180920-8c6c420018be/go.mod h1:dvdCTIoAGbkWbcIKBniID56/7XHTt6WfxXNMxuziJ+w=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240429193739-8cf5692501f6 h1:DujSIu+2tC9Ht0aPNA7jgj23Iq8Ewi5sgkQ++wdvonE=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240429193739-8cf5692501f6/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157 h1:7whR9kGa5LUwFtpLm2ArCEejtnxlGeLbAyjFY8sGNFw=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157/go.mod h1:99sLkeliLXfdj2J75X3Ho+rrVCaJze0uwN7zDDkjPVU=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157 h1:Zy9XzmMEflZ/MAaA7vNcoebnRAld7FsPW1EeBB7V0m8=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0=
|
||||
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM=
|
||||
|
@ -1103,8 +1107,8 @@ google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3Iji
|
|||
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
|
||||
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
||||
google.golang.org/grpc v1.63.2 h1:MUeiw1B2maTVZthpU5xvASfTh3LDbxHd6IJ6QQVU+xM=
|
||||
google.golang.org/grpc v1.63.2/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA=
|
||||
google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY=
|
||||
google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
|
@ -1116,8 +1120,8 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD
|
|||
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.34.0 h1:Qo/qEd2RZPCf2nKuorzksSknv0d3ERwp1vFG38gSmH4=
|
||||
google.golang.org/protobuf v1.34.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
|
||||
google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
|
|
@ -14,9 +14,9 @@
|
|||
package histogram
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"math/rand"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
@ -2788,7 +2788,7 @@ func TestAllFloatBucketIterator(t *testing.T) {
|
|||
}
|
||||
|
||||
for i, c := range cases {
|
||||
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
|
||||
t.Run(strconv.Itoa(i), func(t *testing.T) {
|
||||
var expBuckets, actBuckets []Bucket[float64]
|
||||
|
||||
if c.includeNeg {
|
||||
|
@ -3014,7 +3014,7 @@ func TestAllReverseFloatBucketIterator(t *testing.T) {
|
|||
}
|
||||
|
||||
for i, c := range cases {
|
||||
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
|
||||
t.Run(strconv.Itoa(i), func(t *testing.T) {
|
||||
var expBuckets, actBuckets []Bucket[float64]
|
||||
|
||||
if c.includePos {
|
||||
|
|
|
@ -496,7 +496,7 @@ func getBoundExponential(idx, schema int32) float64 {
|
|||
// bucket results in precisely that. It is either frac=1.0 & exp=1024
|
||||
// (for schema < 0) or frac=0.5 & exp=1025 (for schema >=0). (This is,
|
||||
// by the way, a power of two where the exponent itself is a power of
|
||||
// two, 2¹⁰ in fact, which coinicides with a bucket boundary in all
|
||||
// two, 2¹⁰ in fact, which coincides with a bucket boundary in all
|
||||
// schemas.) So these are the special cases we have to catch below.
|
||||
if schema < 0 {
|
||||
exp := int(idx) << -schema
|
||||
|
|
|
@ -14,8 +14,8 @@
|
|||
package histogram
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
@ -87,7 +87,7 @@ func TestHistogramString(t *testing.T) {
|
|||
}
|
||||
|
||||
for i, c := range cases {
|
||||
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
|
||||
t.Run(strconv.Itoa(i), func(t *testing.T) {
|
||||
actualString := c.histogram.String()
|
||||
require.Equal(t, c.expectedString, actualString)
|
||||
})
|
||||
|
@ -246,7 +246,7 @@ func TestCumulativeBucketIterator(t *testing.T) {
|
|||
}
|
||||
|
||||
for i, c := range cases {
|
||||
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
|
||||
t.Run(strconv.Itoa(i), func(t *testing.T) {
|
||||
it := c.histogram.CumulativeBucketIterator()
|
||||
actualBuckets := make([]Bucket[uint64], 0, len(c.expectedBuckets))
|
||||
for it.Next() {
|
||||
|
@ -462,7 +462,7 @@ func TestRegularBucketIterator(t *testing.T) {
|
|||
}
|
||||
|
||||
for i, c := range cases {
|
||||
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
|
||||
t.Run(strconv.Itoa(i), func(t *testing.T) {
|
||||
it := c.histogram.PositiveBucketIterator()
|
||||
actualPositiveBuckets := make([]Bucket[uint64], 0, len(c.expectedPositiveBuckets))
|
||||
for it.Next() {
|
||||
|
|
|
@ -17,6 +17,7 @@ import (
|
|||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
|
@ -732,7 +733,7 @@ func TestScratchBuilder(t *testing.T) {
|
|||
want: FromStrings("ddd", "444"),
|
||||
},
|
||||
} {
|
||||
t.Run(fmt.Sprint(i), func(t *testing.T) {
|
||||
t.Run(strconv.Itoa(i), func(t *testing.T) {
|
||||
b := NewScratchBuilder(len(tcase.add))
|
||||
for _, lbl := range tcase.add {
|
||||
b.Add(lbl.Name, lbl.Value)
|
||||
|
|
|
@ -14,7 +14,8 @@
|
|||
package labels
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"bytes"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// MatchType is an enum for label matching types.
|
||||
|
@ -78,7 +79,29 @@ func MustNewMatcher(mt MatchType, name, val string) *Matcher {
|
|||
}
|
||||
|
||||
func (m *Matcher) String() string {
|
||||
return fmt.Sprintf("%s%s%q", m.Name, m.Type, m.Value)
|
||||
// Start a buffer with a pre-allocated size on stack to cover most needs.
|
||||
var bytea [1024]byte
|
||||
b := bytes.NewBuffer(bytea[:0])
|
||||
|
||||
if m.shouldQuoteName() {
|
||||
b.Write(strconv.AppendQuote(b.AvailableBuffer(), m.Name))
|
||||
} else {
|
||||
b.WriteString(m.Name)
|
||||
}
|
||||
b.WriteString(m.Type.String())
|
||||
b.Write(strconv.AppendQuote(b.AvailableBuffer(), m.Value))
|
||||
|
||||
return b.String()
|
||||
}
|
||||
|
||||
func (m *Matcher) shouldQuoteName() bool {
|
||||
for i, c := range m.Name {
|
||||
if c == '_' || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (i > 0 && c >= '0' && c <= '9') {
|
||||
continue
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Matches returns whether the matcher matches the given string value.
|
||||
|
|
|
@ -15,6 +15,7 @@ package labels
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
@ -225,3 +226,128 @@ func BenchmarkNewMatcher(b *testing.B) {
|
|||
}
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkMatcher_String(b *testing.B) {
|
||||
type benchCase struct {
|
||||
name string
|
||||
matchers []*Matcher
|
||||
}
|
||||
cases := []benchCase{
|
||||
{
|
||||
name: "short name equal",
|
||||
matchers: []*Matcher{
|
||||
MustNewMatcher(MatchEqual, "foo", "bar"),
|
||||
MustNewMatcher(MatchEqual, "bar", "baz"),
|
||||
MustNewMatcher(MatchEqual, "abc", "def"),
|
||||
MustNewMatcher(MatchEqual, "ghi", "klm"),
|
||||
MustNewMatcher(MatchEqual, "nop", "qrs"),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "short quoted name not equal",
|
||||
matchers: []*Matcher{
|
||||
MustNewMatcher(MatchEqual, "f.o", "bar"),
|
||||
MustNewMatcher(MatchEqual, "b.r", "baz"),
|
||||
MustNewMatcher(MatchEqual, "a.c", "def"),
|
||||
MustNewMatcher(MatchEqual, "g.i", "klm"),
|
||||
MustNewMatcher(MatchEqual, "n.p", "qrs"),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "short quoted name with quotes not equal",
|
||||
matchers: []*Matcher{
|
||||
MustNewMatcher(MatchEqual, `"foo"`, "bar"),
|
||||
MustNewMatcher(MatchEqual, `"foo"`, "baz"),
|
||||
MustNewMatcher(MatchEqual, `"foo"`, "def"),
|
||||
MustNewMatcher(MatchEqual, `"foo"`, "klm"),
|
||||
MustNewMatcher(MatchEqual, `"foo"`, "qrs"),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "short name value with quotes equal",
|
||||
matchers: []*Matcher{
|
||||
MustNewMatcher(MatchEqual, "foo", `"bar"`),
|
||||
MustNewMatcher(MatchEqual, "bar", `"baz"`),
|
||||
MustNewMatcher(MatchEqual, "abc", `"def"`),
|
||||
MustNewMatcher(MatchEqual, "ghi", `"klm"`),
|
||||
MustNewMatcher(MatchEqual, "nop", `"qrs"`),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "short name and long value regexp",
|
||||
matchers: []*Matcher{
|
||||
MustNewMatcher(MatchRegexp, "foo", "five_six_seven_eight_nine_ten_one_two_three_four"),
|
||||
MustNewMatcher(MatchRegexp, "bar", "one_two_three_four_five_six_seven_eight_nine_ten"),
|
||||
MustNewMatcher(MatchRegexp, "abc", "two_three_four_five_six_seven_eight_nine_ten_one"),
|
||||
MustNewMatcher(MatchRegexp, "ghi", "three_four_five_six_seven_eight_nine_ten_one_two"),
|
||||
MustNewMatcher(MatchRegexp, "nop", "four_five_six_seven_eight_nine_ten_one_two_three"),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "short name and long value with quotes equal",
|
||||
matchers: []*Matcher{
|
||||
MustNewMatcher(MatchEqual, "foo", `five_six_seven_eight_nine_ten_"one"_two_three_four`),
|
||||
MustNewMatcher(MatchEqual, "bar", `one_two_three_four_five_six_"seven"_eight_nine_ten`),
|
||||
MustNewMatcher(MatchEqual, "abc", `two_three_four_five_six_seven_"eight"_nine_ten_one`),
|
||||
MustNewMatcher(MatchEqual, "ghi", `three_four_five_six_seven_eight_"nine"_ten_one_two`),
|
||||
MustNewMatcher(MatchEqual, "nop", `four_five_six_seven_eight_nine_"ten"_one_two_three`),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "long name regexp",
|
||||
matchers: []*Matcher{
|
||||
MustNewMatcher(MatchRegexp, "one_two_three_four_five_six_seven_eight_nine_ten", "val"),
|
||||
MustNewMatcher(MatchRegexp, "two_three_four_five_six_seven_eight_nine_ten_one", "val"),
|
||||
MustNewMatcher(MatchRegexp, "three_four_five_six_seven_eight_nine_ten_one_two", "val"),
|
||||
MustNewMatcher(MatchRegexp, "four_five_six_seven_eight_nine_ten_one_two_three", "val"),
|
||||
MustNewMatcher(MatchRegexp, "five_six_seven_eight_nine_ten_one_two_three_four", "val"),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "long quoted name regexp",
|
||||
matchers: []*Matcher{
|
||||
MustNewMatcher(MatchRegexp, "one.two.three.four.five.six.seven.eight.nine.ten", "val"),
|
||||
MustNewMatcher(MatchRegexp, "two.three.four.five.six.seven.eight.nine.ten.one", "val"),
|
||||
MustNewMatcher(MatchRegexp, "three.four.five.six.seven.eight.nine.ten.one.two", "val"),
|
||||
MustNewMatcher(MatchRegexp, "four.five.six.seven.eight.nine.ten.one.two.three", "val"),
|
||||
MustNewMatcher(MatchRegexp, "five.six.seven.eight.nine.ten.one.two.three.four", "val"),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "long name and long value regexp",
|
||||
matchers: []*Matcher{
|
||||
MustNewMatcher(MatchRegexp, "one_two_three_four_five_six_seven_eight_nine_ten", "five_six_seven_eight_nine_ten_one_two_three_four"),
|
||||
MustNewMatcher(MatchRegexp, "two_three_four_five_six_seven_eight_nine_ten_one", "one_two_three_four_five_six_seven_eight_nine_ten"),
|
||||
MustNewMatcher(MatchRegexp, "three_four_five_six_seven_eight_nine_ten_one_two", "two_three_four_five_six_seven_eight_nine_ten_one"),
|
||||
MustNewMatcher(MatchRegexp, "four_five_six_seven_eight_nine_ten_one_two_three", "three_four_five_six_seven_eight_nine_ten_one_two"),
|
||||
MustNewMatcher(MatchRegexp, "five_six_seven_eight_nine_ten_one_two_three_four", "four_five_six_seven_eight_nine_ten_one_two_three"),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "long quoted name and long value regexp",
|
||||
matchers: []*Matcher{
|
||||
MustNewMatcher(MatchRegexp, "one.two.three.four.five.six.seven.eight.nine.ten", "five.six.seven.eight.nine.ten.one.two.three.four"),
|
||||
MustNewMatcher(MatchRegexp, "two.three.four.five.six.seven.eight.nine.ten.one", "one.two.three.four.five.six.seven.eight.nine.ten"),
|
||||
MustNewMatcher(MatchRegexp, "three.four.five.six.seven.eight.nine.ten.one.two", "two.three.four.five.six.seven.eight.nine.ten.one"),
|
||||
MustNewMatcher(MatchRegexp, "four.five.six.seven.eight.nine.ten.one.two.three", "three.four.five.six.seven.eight.nine.ten.one.two"),
|
||||
MustNewMatcher(MatchRegexp, "five.six.seven.eight.nine.ten.one.two.three.four", "four.five.six.seven.eight.nine.ten.one.two.three"),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
var mixed []*Matcher
|
||||
for _, bc := range cases {
|
||||
mixed = append(mixed, bc.matchers...)
|
||||
}
|
||||
rand.Shuffle(len(mixed), func(i, j int) { mixed[i], mixed[j] = mixed[j], mixed[i] })
|
||||
cases = append(cases, benchCase{name: "mixed", matchers: mixed})
|
||||
|
||||
for _, bc := range cases {
|
||||
b.Run(bc.name, func(b *testing.B) {
|
||||
for i := 0; i <= b.N; i++ {
|
||||
m := bc.matchers[i%len(bc.matchers)]
|
||||
_ = m.String()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,7 +42,7 @@ type FastRegexMatcher struct {
|
|||
stringMatcher StringMatcher
|
||||
prefix string
|
||||
suffix string
|
||||
contains string
|
||||
contains []string
|
||||
|
||||
// matchString is the "compiled" function to run by MatchString().
|
||||
matchString func(string) bool
|
||||
|
@ -87,7 +87,7 @@ func NewFastRegexMatcher(v string) (*FastRegexMatcher, error) {
|
|||
// compileMatchStringFunction returns the function to run by MatchString().
|
||||
func (m *FastRegexMatcher) compileMatchStringFunction() func(string) bool {
|
||||
// If the only optimization available is the string matcher, then we can just run it.
|
||||
if len(m.setMatches) == 0 && m.prefix == "" && m.suffix == "" && m.contains == "" && m.stringMatcher != nil {
|
||||
if len(m.setMatches) == 0 && m.prefix == "" && m.suffix == "" && len(m.contains) == 0 && m.stringMatcher != nil {
|
||||
return m.stringMatcher.Matches
|
||||
}
|
||||
|
||||
|
@ -106,7 +106,7 @@ func (m *FastRegexMatcher) compileMatchStringFunction() func(string) bool {
|
|||
if m.suffix != "" && !strings.HasSuffix(s, m.suffix) {
|
||||
return false
|
||||
}
|
||||
if m.contains != "" && !strings.Contains(s, m.contains) {
|
||||
if len(m.contains) > 0 && !containsInOrder(s, m.contains) {
|
||||
return false
|
||||
}
|
||||
if m.stringMatcher != nil {
|
||||
|
@ -119,7 +119,7 @@ func (m *FastRegexMatcher) compileMatchStringFunction() func(string) bool {
|
|||
// IsOptimized returns true if any fast-path optimization is applied to the
|
||||
// regex matcher.
|
||||
func (m *FastRegexMatcher) IsOptimized() bool {
|
||||
return len(m.setMatches) > 0 || m.stringMatcher != nil || m.prefix != "" || m.suffix != "" || m.contains != ""
|
||||
return len(m.setMatches) > 0 || m.stringMatcher != nil || m.prefix != "" || m.suffix != "" || len(m.contains) > 0
|
||||
}
|
||||
|
||||
// findSetMatches extract equality matches from a regexp.
|
||||
|
@ -361,8 +361,9 @@ func optimizeAlternatingLiterals(s string) (StringMatcher, []string) {
|
|||
|
||||
// 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, contains string) {
|
||||
func optimizeConcatRegex(r *syntax.Regexp) (prefix, suffix string, contains []string) {
|
||||
sub := r.Sub
|
||||
clearCapture(sub...)
|
||||
|
||||
// We can safely remove begin and end text matchers respectively
|
||||
// at the beginning and end of the regexp.
|
||||
|
@ -387,13 +388,11 @@ func optimizeConcatRegex(r *syntax.Regexp) (prefix, suffix, contains string) {
|
|||
suffix = string(sub[last].Rune)
|
||||
}
|
||||
|
||||
// If contains any literal which is not a prefix/suffix, we keep the
|
||||
// 1st one. We do not keep the whole list of literals to simplify the
|
||||
// fast path.
|
||||
// If contains any literal which is not a prefix/suffix, we keep track of
|
||||
// all the ones which are case-sensitive.
|
||||
for i := 1; i < len(sub)-1; i++ {
|
||||
if sub[i].Op == syntax.OpLiteral && (sub[i].Flags&syntax.FoldCase) == 0 {
|
||||
contains = string(sub[i].Rune)
|
||||
break
|
||||
contains = append(contains, string(sub[i].Rune))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -828,7 +827,12 @@ type zeroOrOneCharacterStringMatcher struct {
|
|||
}
|
||||
|
||||
func (m *zeroOrOneCharacterStringMatcher) Matches(s string) bool {
|
||||
if moreThanOneRune(s) {
|
||||
// If there's more than one rune in the string, then it can't match.
|
||||
if r, size := utf8.DecodeRuneInString(s); r == utf8.RuneError {
|
||||
// Size is 0 for empty strings, 1 for invalid rune.
|
||||
// Empty string matches, invalid rune matches if there isn't anything else.
|
||||
return size == len(s)
|
||||
} else if size < len(s) {
|
||||
return false
|
||||
}
|
||||
|
||||
|
@ -840,27 +844,6 @@ func (m *zeroOrOneCharacterStringMatcher) Matches(s string) bool {
|
|||
return s[0] != '\n'
|
||||
}
|
||||
|
||||
// moreThanOneRune returns true if there are more than one runes in the string.
|
||||
// It doesn't check whether the string is valid UTF-8.
|
||||
// The return value should be always equal to utf8.RuneCountInString(s) > 1,
|
||||
// but the function is optimized for the common case where the string prefix is ASCII.
|
||||
func moreThanOneRune(s string) bool {
|
||||
// If len(s) is exactly one or zero, there can't be more than one rune.
|
||||
// Exit through this path quickly.
|
||||
if len(s) <= 1 {
|
||||
return false
|
||||
}
|
||||
|
||||
// There's one or more bytes:
|
||||
// If first byte is ASCII then there are multiple runes if there are more bytes after that.
|
||||
if s[0] < utf8.RuneSelf {
|
||||
return len(s) > 1
|
||||
}
|
||||
|
||||
// Less common case: first is a multibyte rune.
|
||||
return utf8.RuneCountInString(s) > 1
|
||||
}
|
||||
|
||||
// trueMatcher is a stringMatcher which matches any string (always returns true).
|
||||
type trueMatcher struct{}
|
||||
|
||||
|
@ -956,3 +939,27 @@ func hasPrefixCaseInsensitive(s, prefix string) bool {
|
|||
func hasSuffixCaseInsensitive(s, suffix string) bool {
|
||||
return len(s) >= len(suffix) && strings.EqualFold(s[len(s)-len(suffix):], suffix)
|
||||
}
|
||||
|
||||
func containsInOrder(s string, contains []string) bool {
|
||||
// Optimization for the case we only have to look for 1 substring.
|
||||
if len(contains) == 1 {
|
||||
return strings.Contains(s, contains[0])
|
||||
}
|
||||
|
||||
return containsInOrderMulti(s, contains)
|
||||
}
|
||||
|
||||
func containsInOrderMulti(s string, contains []string) bool {
|
||||
offset := 0
|
||||
|
||||
for _, substr := range contains {
|
||||
at := strings.Index(s[offset:], substr)
|
||||
if at == -1 {
|
||||
return false
|
||||
}
|
||||
|
||||
offset += at + len(substr)
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ import (
|
|||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/grafana/regexp"
|
||||
"github.com/grafana/regexp/syntax"
|
||||
|
@ -36,6 +37,7 @@ var (
|
|||
".*foo",
|
||||
"^.*foo$",
|
||||
"^.+foo$",
|
||||
".?",
|
||||
".*",
|
||||
".+",
|
||||
"foo.+",
|
||||
|
@ -79,15 +81,26 @@ var (
|
|||
".*foo.?",
|
||||
".?foo.+",
|
||||
"foo.?|bar",
|
||||
// Concat of literals and wildcards.
|
||||
".*-.*-.*-.*-.*",
|
||||
"(.+)-(.+)-(.+)-(.+)-(.+)",
|
||||
"((.*))(?i:f)((.*))o((.*))o((.*))",
|
||||
"((.*))f((.*))(?i:o)((.*))o((.*))",
|
||||
}
|
||||
values = []string{
|
||||
"foo", " foo bar", "bar", "buzz\nbar", "bar foo", "bfoo", "\n", "\nfoo", "foo\n", "hello foo world", "hello foo\n world", "",
|
||||
"FOO", "Foo", "OO", "Oo", "\nfoo\n", strings.Repeat("f", 20), "prometheus", "prometheus_api_v1", "prometheus_api_v1_foo",
|
||||
"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",
|
||||
"foofoo0", "foofoo", "😀foo0",
|
||||
|
||||
// Values matching / not matching the test regexps on long alternations.
|
||||
"zQPbMkNO", "zQPbMkNo", "jyyfj00j0061", "jyyfj00j006", "jyyfj00j00612", "NNSPdvMi", "NNSPdvMiXXX", "NNSPdvMixxx", "nnSPdvMi", "nnSPdvMiXXX",
|
||||
|
||||
// Invalid utf8
|
||||
"\xfefoo",
|
||||
"foo\xfe",
|
||||
"\xfd",
|
||||
"\xff\xff",
|
||||
}
|
||||
)
|
||||
|
||||
|
@ -124,29 +137,29 @@ func TestOptimizeConcatRegex(t *testing.T) {
|
|||
regex string
|
||||
prefix string
|
||||
suffix string
|
||||
contains string
|
||||
contains []string
|
||||
}{
|
||||
{regex: "foo(hello|bar)", prefix: "foo", suffix: "", contains: ""},
|
||||
{regex: "foo(hello|bar)world", prefix: "foo", suffix: "world", contains: ""},
|
||||
{regex: "foo.*", prefix: "foo", suffix: "", contains: ""},
|
||||
{regex: "foo.*hello.*bar", prefix: "foo", suffix: "bar", contains: "hello"},
|
||||
{regex: ".*foo", prefix: "", suffix: "foo", contains: ""},
|
||||
{regex: "^.*foo$", prefix: "", suffix: "foo", contains: ""},
|
||||
{regex: ".*foo.*", prefix: "", suffix: "", contains: "foo"},
|
||||
{regex: ".*foo.*bar.*", prefix: "", suffix: "", contains: "foo"},
|
||||
{regex: ".*(foo|bar).*", prefix: "", suffix: "", contains: ""},
|
||||
{regex: ".*[abc].*", prefix: "", suffix: "", contains: ""},
|
||||
{regex: ".*((?i)abc).*", prefix: "", suffix: "", contains: ""},
|
||||
{regex: ".*(?i:abc).*", prefix: "", suffix: "", contains: ""},
|
||||
{regex: "(?i:abc).*", prefix: "", suffix: "", contains: ""},
|
||||
{regex: ".*(?i:abc)", prefix: "", suffix: "", contains: ""},
|
||||
{regex: ".*(?i:abc)def.*", prefix: "", suffix: "", contains: "def"},
|
||||
{regex: "(?i).*(?-i:abc)def", prefix: "", suffix: "", contains: "abc"},
|
||||
{regex: ".*(?msU:abc).*", prefix: "", suffix: "", contains: "abc"},
|
||||
{regex: "[aA]bc.*", prefix: "", suffix: "", contains: "bc"},
|
||||
{regex: "^5..$", prefix: "5", suffix: "", contains: ""},
|
||||
{regex: "^release.*", prefix: "release", suffix: "", contains: ""},
|
||||
{regex: "^env-[0-9]+laio[1]?[^0-9].*", prefix: "env-", suffix: "", contains: "laio"},
|
||||
{regex: "foo(hello|bar)", prefix: "foo", suffix: "", contains: nil},
|
||||
{regex: "foo(hello|bar)world", prefix: "foo", suffix: "world", contains: nil},
|
||||
{regex: "foo.*", prefix: "foo", suffix: "", contains: nil},
|
||||
{regex: "foo.*hello.*bar", prefix: "foo", suffix: "bar", contains: []string{"hello"}},
|
||||
{regex: ".*foo", prefix: "", suffix: "foo", contains: nil},
|
||||
{regex: "^.*foo$", prefix: "", suffix: "foo", contains: nil},
|
||||
{regex: ".*foo.*", prefix: "", suffix: "", contains: []string{"foo"}},
|
||||
{regex: ".*foo.*bar.*", prefix: "", suffix: "", contains: []string{"foo", "bar"}},
|
||||
{regex: ".*(foo|bar).*", prefix: "", suffix: "", contains: nil},
|
||||
{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: "", 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: "^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"}},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
|
@ -926,19 +939,91 @@ func BenchmarkOptimizeEqualStringMatchers(b *testing.B) {
|
|||
}
|
||||
|
||||
func TestZeroOrOneCharacterStringMatcher(t *testing.T) {
|
||||
matcher := &zeroOrOneCharacterStringMatcher{matchNL: true}
|
||||
require.True(t, matcher.Matches(""))
|
||||
require.True(t, matcher.Matches("x"))
|
||||
require.True(t, matcher.Matches("\n"))
|
||||
require.False(t, matcher.Matches("xx"))
|
||||
require.False(t, matcher.Matches("\n\n"))
|
||||
t.Run("match newline", func(t *testing.T) {
|
||||
matcher := &zeroOrOneCharacterStringMatcher{matchNL: true}
|
||||
require.True(t, matcher.Matches(""))
|
||||
require.True(t, matcher.Matches("x"))
|
||||
require.True(t, matcher.Matches("\n"))
|
||||
require.False(t, matcher.Matches("xx"))
|
||||
require.False(t, matcher.Matches("\n\n"))
|
||||
})
|
||||
|
||||
matcher = &zeroOrOneCharacterStringMatcher{matchNL: false}
|
||||
require.True(t, matcher.Matches(""))
|
||||
require.True(t, matcher.Matches("x"))
|
||||
require.False(t, matcher.Matches("\n"))
|
||||
require.False(t, matcher.Matches("xx"))
|
||||
require.False(t, matcher.Matches("\n\n"))
|
||||
t.Run("do not match newline", func(t *testing.T) {
|
||||
matcher := &zeroOrOneCharacterStringMatcher{matchNL: false}
|
||||
require.True(t, matcher.Matches(""))
|
||||
require.True(t, matcher.Matches("x"))
|
||||
require.False(t, matcher.Matches("\n"))
|
||||
require.False(t, matcher.Matches("xx"))
|
||||
require.False(t, matcher.Matches("\n\n"))
|
||||
})
|
||||
|
||||
t.Run("unicode", func(t *testing.T) {
|
||||
// Just for documentation purposes, emoji1 is 1 rune, emoji2 is 2 runes.
|
||||
// Having this in mind, will make future readers fixing tests easier.
|
||||
emoji1 := "😀"
|
||||
emoji2 := "❤️"
|
||||
require.Equal(t, 1, utf8.RuneCountInString(emoji1))
|
||||
require.Equal(t, 2, utf8.RuneCountInString(emoji2))
|
||||
|
||||
matcher := &zeroOrOneCharacterStringMatcher{matchNL: true}
|
||||
require.True(t, matcher.Matches(emoji1))
|
||||
require.False(t, matcher.Matches(emoji2))
|
||||
require.False(t, matcher.Matches(emoji1+emoji1))
|
||||
require.False(t, matcher.Matches("x"+emoji1))
|
||||
require.False(t, matcher.Matches(emoji1+"x"))
|
||||
require.False(t, matcher.Matches(emoji1+emoji2))
|
||||
})
|
||||
|
||||
t.Run("invalid unicode", func(t *testing.T) {
|
||||
// Just for reference, we also compare to what `^.?$` regular expression matches.
|
||||
re := regexp.MustCompile("^.?$")
|
||||
matcher := &zeroOrOneCharacterStringMatcher{matchNL: true}
|
||||
|
||||
requireMatches := func(s string, expected bool) {
|
||||
t.Helper()
|
||||
require.Equal(t, expected, matcher.Matches(s))
|
||||
require.Equal(t, re.MatchString(s), matcher.Matches(s))
|
||||
}
|
||||
|
||||
requireMatches("\xff", true)
|
||||
requireMatches("x\xff", false)
|
||||
requireMatches("\xffx", false)
|
||||
requireMatches("\xff\xfe", false)
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkZeroOrOneCharacterStringMatcher(b *testing.B) {
|
||||
type benchCase struct {
|
||||
str string
|
||||
matches bool
|
||||
}
|
||||
|
||||
emoji1 := "😀"
|
||||
emoji2 := "❤️"
|
||||
cases := []benchCase{
|
||||
{"", true},
|
||||
{"x", true},
|
||||
{"\n", true},
|
||||
{"xx", false},
|
||||
{"\n\n", false},
|
||||
{emoji1, true},
|
||||
{emoji2, false},
|
||||
{emoji1 + emoji1, false},
|
||||
{strings.Repeat("x", 100), false},
|
||||
{strings.Repeat(emoji1, 100), false},
|
||||
{strings.Repeat(emoji2, 100), false},
|
||||
}
|
||||
|
||||
matcher := &zeroOrOneCharacterStringMatcher{matchNL: true}
|
||||
b.ResetTimer()
|
||||
|
||||
for n := 0; n < b.N; n++ {
|
||||
c := cases[n%len(cases)]
|
||||
got := matcher.Matches(c.str)
|
||||
if got != c.matches {
|
||||
b.Fatalf("unexpected result for %q: got %t, want %t", c.str, got, c.matches)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestLiteralPrefixStringMatcher(t *testing.T) {
|
||||
|
@ -1009,6 +1094,15 @@ func TestHasSuffixCaseInsensitive(t *testing.T) {
|
|||
require.False(t, hasSuffixCaseInsensitive("marco", "abcdefghi"))
|
||||
}
|
||||
|
||||
func TestContainsInOrder(t *testing.T) {
|
||||
require.True(t, containsInOrder("abcdefghilmno", []string{"ab", "cd", "no"}))
|
||||
require.True(t, containsInOrder("abcdefghilmno", []string{"def", "hil"}))
|
||||
|
||||
require.False(t, containsInOrder("abcdefghilmno", []string{"ac"}))
|
||||
require.False(t, containsInOrder("abcdefghilmno", []string{"ab", "cd", "de"}))
|
||||
require.False(t, containsInOrder("abcdefghilmno", []string{"cd", "ab"}))
|
||||
}
|
||||
|
||||
func getTestNameFromRegexp(re string) string {
|
||||
if len(re) > 32 {
|
||||
return re[:32]
|
||||
|
|
|
@ -17,6 +17,7 @@ import (
|
|||
"crypto/md5"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/grafana/regexp"
|
||||
|
@ -290,7 +291,7 @@ func relabel(cfg *Config, lb *labels.Builder) (keep bool) {
|
|||
hash := md5.Sum([]byte(val))
|
||||
// Use only the last 8 bytes of the hash to give the same result as earlier versions of this code.
|
||||
mod := binary.BigEndian.Uint64(hash[8:]) % cfg.Modulus
|
||||
lb.Set(cfg.TargetLabel, fmt.Sprintf("%d", mod))
|
||||
lb.Set(cfg.TargetLabel, strconv.FormatUint(mod, 10))
|
||||
case LabelMap:
|
||||
lb.Range(func(l labels.Label) {
|
||||
if cfg.Regex.MatchString(l.Name) {
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
package relabel
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"github.com/prometheus/common/model"
|
||||
|
@ -657,7 +657,7 @@ func TestRelabelValidate(t *testing.T) {
|
|||
},
|
||||
}
|
||||
for i, test := range tests {
|
||||
t.Run(fmt.Sprint(i), func(t *testing.T) {
|
||||
t.Run(strconv.Itoa(i), func(t *testing.T) {
|
||||
err := test.config.Validate()
|
||||
if test.expected == "" {
|
||||
require.NoError(t, err)
|
||||
|
|
|
@ -136,10 +136,11 @@ func (g *RuleGroups) Validate(node ruleGroups) (errs []error) {
|
|||
|
||||
// RuleGroup is a list of sequentially evaluated recording and alerting rules.
|
||||
type RuleGroup struct {
|
||||
Name string `yaml:"name"`
|
||||
Interval model.Duration `yaml:"interval,omitempty"`
|
||||
Limit int `yaml:"limit,omitempty"`
|
||||
Rules []RuleNode `yaml:"rules"`
|
||||
Name string `yaml:"name"`
|
||||
Interval model.Duration `yaml:"interval,omitempty"`
|
||||
QueryOffset *model.Duration `yaml:"query_offset,omitempty"`
|
||||
Limit int `yaml:"limit,omitempty"`
|
||||
Rules []RuleNode `yaml:"rules"`
|
||||
}
|
||||
|
||||
// Rule describes an alerting or recording rule.
|
||||
|
|
|
@ -74,7 +74,7 @@ func TestHandlerNextBatch(t *testing.T) {
|
|||
|
||||
for i := range make([]struct{}, 2*maxBatchSize+1) {
|
||||
h.queue = append(h.queue, &Alert{
|
||||
Labels: labels.FromStrings("alertname", fmt.Sprintf("%d", i)),
|
||||
Labels: labels.FromStrings("alertname", strconv.Itoa(i)),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -186,10 +186,10 @@ func TestHandlerSendAll(t *testing.T) {
|
|||
|
||||
for i := range make([]struct{}, maxBatchSize) {
|
||||
h.queue = append(h.queue, &Alert{
|
||||
Labels: labels.FromStrings("alertname", fmt.Sprintf("%d", i)),
|
||||
Labels: labels.FromStrings("alertname", strconv.Itoa(i)),
|
||||
})
|
||||
expected = append(expected, &Alert{
|
||||
Labels: labels.FromStrings("alertname", fmt.Sprintf("%d", i)),
|
||||
Labels: labels.FromStrings("alertname", strconv.Itoa(i)),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -297,23 +297,23 @@ func TestHandlerSendAllRemapPerAm(t *testing.T) {
|
|||
for i := range make([]struct{}, maxBatchSize/2) {
|
||||
h.queue = append(h.queue,
|
||||
&Alert{
|
||||
Labels: labels.FromStrings("alertname", fmt.Sprintf("%d", i)),
|
||||
Labels: labels.FromStrings("alertname", strconv.Itoa(i)),
|
||||
},
|
||||
&Alert{
|
||||
Labels: labels.FromStrings("alertname", "test", "alertnamedrop", fmt.Sprintf("%d", i)),
|
||||
Labels: labels.FromStrings("alertname", "test", "alertnamedrop", strconv.Itoa(i)),
|
||||
},
|
||||
)
|
||||
|
||||
expected1 = append(expected1,
|
||||
&Alert{
|
||||
Labels: labels.FromStrings("alertname", fmt.Sprintf("%d", i)),
|
||||
Labels: labels.FromStrings("alertname", strconv.Itoa(i)),
|
||||
}, &Alert{
|
||||
Labels: labels.FromStrings("alertname", "test", "alertnamedrop", fmt.Sprintf("%d", i)),
|
||||
Labels: labels.FromStrings("alertname", "test", "alertnamedrop", strconv.Itoa(i)),
|
||||
},
|
||||
)
|
||||
|
||||
expected2 = append(expected2, &Alert{
|
||||
Labels: labels.FromStrings("alertname", fmt.Sprintf("%d", i)),
|
||||
Labels: labels.FromStrings("alertname", strconv.Itoa(i)),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -502,7 +502,7 @@ func TestHandlerQueuing(t *testing.T) {
|
|||
var alerts []*Alert
|
||||
for i := range make([]struct{}, 20*maxBatchSize) {
|
||||
alerts = append(alerts, &Alert{
|
||||
Labels: labels.FromStrings("alertname", fmt.Sprintf("%d", i)),
|
||||
Labels: labels.FromStrings("alertname", strconv.Itoa(i)),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -762,7 +762,7 @@ func TestHangingNotifier(t *testing.T) {
|
|||
var alerts []*Alert
|
||||
for i := range make([]struct{}, 20*maxBatchSize) {
|
||||
alerts = append(alerts, &Alert{
|
||||
Labels: labels.FromStrings("alertname", fmt.Sprintf("%d", i)),
|
||||
Labels: labels.FromStrings("alertname", strconv.Itoa(i)),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -323,6 +323,14 @@ func BenchmarkNativeHistograms(b *testing.B) {
|
|||
name: "sum rate with long rate interval",
|
||||
query: "sum(rate(native_histogram_series[20m]))",
|
||||
},
|
||||
{
|
||||
name: "histogram_count with short rate interval",
|
||||
query: "histogram_count(sum(rate(native_histogram_series[2m])))",
|
||||
},
|
||||
{
|
||||
name: "histogram_count with long rate interval",
|
||||
query: "histogram_count(sum(rate(native_histogram_series[20m])))",
|
||||
},
|
||||
}
|
||||
|
||||
opts := promql.EngineOpts{
|
||||
|
|
|
@ -752,6 +752,7 @@ func (ng *Engine) execEvalStmt(ctx context.Context, query *query, s *parser.Eval
|
|||
case parser.ValueTypeScalar:
|
||||
return Scalar{V: mat[0].Floats[0].F, T: start}, warnings, nil
|
||||
case parser.ValueTypeMatrix:
|
||||
ng.sortMatrixResult(ctx, query, mat)
|
||||
return mat, warnings, nil
|
||||
default:
|
||||
panic(fmt.Errorf("promql.Engine.exec: unexpected expression type %q", s.Expr.Type()))
|
||||
|
@ -790,11 +791,15 @@ func (ng *Engine) execEvalStmt(ctx context.Context, query *query, s *parser.Eval
|
|||
}
|
||||
|
||||
// TODO(fabxc): where to ensure metric labels are a copy from the storage internals.
|
||||
ng.sortMatrixResult(ctx, query, mat)
|
||||
|
||||
return mat, warnings, nil
|
||||
}
|
||||
|
||||
func (ng *Engine) sortMatrixResult(ctx context.Context, query *query, mat Matrix) {
|
||||
sortSpanTimer, _ := query.stats.GetSpanTimer(ctx, stats.ResultSortTime, ng.metrics.queryResultSort)
|
||||
sort.Sort(mat)
|
||||
sortSpanTimer.Finish()
|
||||
|
||||
return mat, warnings, nil
|
||||
}
|
||||
|
||||
// subqueryTimes returns the sum of offsets and ranges of all subqueries in the path.
|
||||
|
@ -980,6 +985,11 @@ func checkAndExpandSeriesSet(ctx context.Context, expr parser.Expr) (annotations
|
|||
return nil, nil
|
||||
}
|
||||
series, ws, err := expandSeriesSet(ctx, e.UnexpandedSeriesSet)
|
||||
if e.SkipHistogramBuckets {
|
||||
for i := range series {
|
||||
series[i] = newHistogramStatsSeries(series[i])
|
||||
}
|
||||
}
|
||||
e.Series = series
|
||||
return ws, err
|
||||
}
|
||||
|
@ -3232,6 +3242,8 @@ func unwrapStepInvariantExpr(e parser.Expr) parser.Expr {
|
|||
// PreprocessExpr wraps all possible step invariant parts of the given expression with
|
||||
// StepInvariantExpr. It also resolves the preprocessors.
|
||||
func PreprocessExpr(expr parser.Expr, start, end time.Time) parser.Expr {
|
||||
detectHistogramStatsDecoding(expr)
|
||||
|
||||
isStepInvariant := preprocessExprHelper(expr, start, end)
|
||||
if isStepInvariant {
|
||||
return newStepInvariantExpr(expr)
|
||||
|
@ -3366,8 +3378,50 @@ func setOffsetForAtModifier(evalTime int64, expr parser.Expr) {
|
|||
})
|
||||
}
|
||||
|
||||
// detectHistogramStatsDecoding modifies the expression by setting the
|
||||
// SkipHistogramBuckets field in those vector selectors for which it is safe to
|
||||
// return only histogram statistics (sum and count), excluding histogram spans
|
||||
// and buckets. The function can be treated as an optimization and is not
|
||||
// required for correctness.
|
||||
func detectHistogramStatsDecoding(expr parser.Expr) {
|
||||
parser.Inspect(expr, func(node parser.Node, path []parser.Node) error {
|
||||
n, ok := (node).(*parser.VectorSelector)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, p := range path {
|
||||
call, ok := p.(*parser.Call)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if call.Func.Name == "histogram_count" || call.Func.Name == "histogram_sum" {
|
||||
n.SkipHistogramBuckets = true
|
||||
break
|
||||
}
|
||||
if call.Func.Name == "histogram_quantile" || call.Func.Name == "histogram_fraction" {
|
||||
n.SkipHistogramBuckets = false
|
||||
break
|
||||
}
|
||||
}
|
||||
return fmt.Errorf("stop")
|
||||
})
|
||||
}
|
||||
|
||||
func makeInt64Pointer(val int64) *int64 {
|
||||
valp := new(int64)
|
||||
*valp = val
|
||||
return valp
|
||||
}
|
||||
|
||||
type histogramStatsSeries struct {
|
||||
storage.Series
|
||||
}
|
||||
|
||||
func newHistogramStatsSeries(series storage.Series) *histogramStatsSeries {
|
||||
return &histogramStatsSeries{Series: series}
|
||||
}
|
||||
|
||||
func (s histogramStatsSeries) Iterator(it chunkenc.Iterator) chunkenc.Iterator {
|
||||
return NewHistogramStatsIterator(s.Series.Iterator(it))
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
144
promql/histogram_stats_iterator.go
Normal file
144
promql/histogram_stats_iterator.go
Normal file
|
@ -0,0 +1,144 @@
|
|||
// Copyright 2024 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 promql
|
||||
|
||||
import (
|
||||
"github.com/prometheus/prometheus/model/histogram"
|
||||
"github.com/prometheus/prometheus/model/value"
|
||||
"github.com/prometheus/prometheus/tsdb/chunkenc"
|
||||
)
|
||||
|
||||
type histogramStatsIterator struct {
|
||||
chunkenc.Iterator
|
||||
|
||||
currentH *histogram.Histogram
|
||||
lastH *histogram.Histogram
|
||||
|
||||
currentFH *histogram.FloatHistogram
|
||||
lastFH *histogram.FloatHistogram
|
||||
}
|
||||
|
||||
// NewHistogramStatsIterator creates an iterator which returns histogram objects
|
||||
// which have only their sum and count values populated. The iterator handles
|
||||
// counter reset detection internally and sets the counter reset hint accordingly
|
||||
// in each returned histogram objects.
|
||||
func NewHistogramStatsIterator(it chunkenc.Iterator) chunkenc.Iterator {
|
||||
return &histogramStatsIterator{
|
||||
Iterator: it,
|
||||
currentH: &histogram.Histogram{},
|
||||
currentFH: &histogram.FloatHistogram{},
|
||||
}
|
||||
}
|
||||
|
||||
// AtHistogram returns the next timestamp/histogram pair. The counter reset
|
||||
// detection is guaranteed to be correct only when the caller does not switch
|
||||
// between AtHistogram and AtFloatHistogram calls.
|
||||
func (f *histogramStatsIterator) AtHistogram(h *histogram.Histogram) (int64, *histogram.Histogram) {
|
||||
var t int64
|
||||
t, f.currentH = f.Iterator.AtHistogram(f.currentH)
|
||||
if value.IsStaleNaN(f.currentH.Sum) {
|
||||
f.setLastH(f.currentH)
|
||||
h = &histogram.Histogram{Sum: f.currentH.Sum}
|
||||
return t, h
|
||||
}
|
||||
|
||||
if h == nil {
|
||||
h = &histogram.Histogram{
|
||||
CounterResetHint: f.getResetHint(f.currentH),
|
||||
Count: f.currentH.Count,
|
||||
Sum: f.currentH.Sum,
|
||||
}
|
||||
f.setLastH(f.currentH)
|
||||
return t, h
|
||||
}
|
||||
|
||||
h.CounterResetHint = f.getResetHint(f.currentH)
|
||||
h.Count = f.currentH.Count
|
||||
h.Sum = f.currentH.Sum
|
||||
f.setLastH(f.currentH)
|
||||
return t, h
|
||||
}
|
||||
|
||||
// AtFloatHistogram returns the next timestamp/float histogram pair. The counter
|
||||
// reset detection is guaranteed to be correct only when the caller does not
|
||||
// switch between AtHistogram and AtFloatHistogram calls.
|
||||
func (f *histogramStatsIterator) AtFloatHistogram(fh *histogram.FloatHistogram) (int64, *histogram.FloatHistogram) {
|
||||
var t int64
|
||||
t, f.currentFH = f.Iterator.AtFloatHistogram(f.currentFH)
|
||||
if value.IsStaleNaN(f.currentFH.Sum) {
|
||||
f.setLastFH(f.currentFH)
|
||||
return t, &histogram.FloatHistogram{Sum: f.currentFH.Sum}
|
||||
}
|
||||
|
||||
if fh == nil {
|
||||
fh = &histogram.FloatHistogram{
|
||||
CounterResetHint: f.getFloatResetHint(f.currentFH.CounterResetHint),
|
||||
Count: f.currentFH.Count,
|
||||
Sum: f.currentFH.Sum,
|
||||
}
|
||||
f.setLastFH(f.currentFH)
|
||||
return t, fh
|
||||
}
|
||||
|
||||
fh.CounterResetHint = f.getFloatResetHint(f.currentFH.CounterResetHint)
|
||||
fh.Count = f.currentFH.Count
|
||||
fh.Sum = f.currentFH.Sum
|
||||
f.setLastFH(f.currentFH)
|
||||
return t, fh
|
||||
}
|
||||
|
||||
func (f *histogramStatsIterator) setLastH(h *histogram.Histogram) {
|
||||
if f.lastH == nil {
|
||||
f.lastH = h.Copy()
|
||||
} else {
|
||||
h.CopyTo(f.lastH)
|
||||
}
|
||||
}
|
||||
|
||||
func (f *histogramStatsIterator) setLastFH(fh *histogram.FloatHistogram) {
|
||||
if f.lastFH == nil {
|
||||
f.lastFH = fh.Copy()
|
||||
} else {
|
||||
fh.CopyTo(f.lastFH)
|
||||
}
|
||||
}
|
||||
|
||||
func (f *histogramStatsIterator) getFloatResetHint(hint histogram.CounterResetHint) histogram.CounterResetHint {
|
||||
if hint != histogram.UnknownCounterReset {
|
||||
return hint
|
||||
}
|
||||
if f.lastFH == nil {
|
||||
return histogram.NotCounterReset
|
||||
}
|
||||
|
||||
if f.currentFH.DetectReset(f.lastFH) {
|
||||
return histogram.CounterReset
|
||||
}
|
||||
return histogram.NotCounterReset
|
||||
}
|
||||
|
||||
func (f *histogramStatsIterator) getResetHint(h *histogram.Histogram) histogram.CounterResetHint {
|
||||
if h.CounterResetHint != histogram.UnknownCounterReset {
|
||||
return h.CounterResetHint
|
||||
}
|
||||
if f.lastH == nil {
|
||||
return histogram.NotCounterReset
|
||||
}
|
||||
|
||||
fh, prevFH := h.ToFloat(nil), f.lastH.ToFloat(nil)
|
||||
if fh.DetectReset(prevFH) {
|
||||
return histogram.CounterReset
|
||||
}
|
||||
return histogram.NotCounterReset
|
||||
}
|
121
promql/histogram_stats_iterator_test.go
Normal file
121
promql/histogram_stats_iterator_test.go
Normal file
|
@ -0,0 +1,121 @@
|
|||
// Copyright 2015 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 promql
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/prometheus/prometheus/model/histogram"
|
||||
"github.com/prometheus/prometheus/model/labels"
|
||||
"github.com/prometheus/prometheus/tsdb/chunkenc"
|
||||
"github.com/prometheus/prometheus/tsdb/tsdbutil"
|
||||
)
|
||||
|
||||
func TestHistogramStatsDecoding(t *testing.T) {
|
||||
histograms := []*histogram.Histogram{
|
||||
tsdbutil.GenerateTestHistogram(0),
|
||||
tsdbutil.GenerateTestHistogram(1),
|
||||
tsdbutil.GenerateTestHistogram(2),
|
||||
tsdbutil.GenerateTestHistogram(2),
|
||||
}
|
||||
histograms[0].CounterResetHint = histogram.NotCounterReset
|
||||
histograms[1].CounterResetHint = histogram.UnknownCounterReset
|
||||
histograms[2].CounterResetHint = histogram.CounterReset
|
||||
histograms[3].CounterResetHint = histogram.UnknownCounterReset
|
||||
|
||||
expectedHints := []histogram.CounterResetHint{
|
||||
histogram.NotCounterReset,
|
||||
histogram.NotCounterReset,
|
||||
histogram.CounterReset,
|
||||
histogram.NotCounterReset,
|
||||
}
|
||||
|
||||
t.Run("histogram_stats", func(t *testing.T) {
|
||||
decodedStats := make([]*histogram.Histogram, 0)
|
||||
statsIterator := NewHistogramStatsIterator(newHistogramSeries(histograms).Iterator(nil))
|
||||
for statsIterator.Next() != chunkenc.ValNone {
|
||||
_, h := statsIterator.AtHistogram(nil)
|
||||
decodedStats = append(decodedStats, h)
|
||||
}
|
||||
for i := 0; i < len(histograms); i++ {
|
||||
require.Equal(t, expectedHints[i], decodedStats[i].CounterResetHint)
|
||||
require.Equal(t, histograms[i].Count, decodedStats[i].Count)
|
||||
require.Equal(t, histograms[i].Sum, decodedStats[i].Sum)
|
||||
}
|
||||
})
|
||||
t.Run("float_histogram_stats", func(t *testing.T) {
|
||||
decodedStats := make([]*histogram.FloatHistogram, 0)
|
||||
statsIterator := NewHistogramStatsIterator(newHistogramSeries(histograms).Iterator(nil))
|
||||
for statsIterator.Next() != chunkenc.ValNone {
|
||||
_, h := statsIterator.AtFloatHistogram(nil)
|
||||
decodedStats = append(decodedStats, h)
|
||||
}
|
||||
for i := 0; i < len(histograms); i++ {
|
||||
fh := histograms[i].ToFloat(nil)
|
||||
require.Equal(t, expectedHints[i], decodedStats[i].CounterResetHint)
|
||||
require.Equal(t, fh.Count, decodedStats[i].Count)
|
||||
require.Equal(t, fh.Sum, decodedStats[i].Sum)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
type histogramSeries struct {
|
||||
histograms []*histogram.Histogram
|
||||
}
|
||||
|
||||
func newHistogramSeries(histograms []*histogram.Histogram) *histogramSeries {
|
||||
return &histogramSeries{
|
||||
histograms: histograms,
|
||||
}
|
||||
}
|
||||
|
||||
func (m histogramSeries) Labels() labels.Labels { return labels.EmptyLabels() }
|
||||
|
||||
func (m histogramSeries) Iterator(_ chunkenc.Iterator) chunkenc.Iterator {
|
||||
return &histogramIterator{
|
||||
i: -1,
|
||||
histograms: m.histograms,
|
||||
}
|
||||
}
|
||||
|
||||
type histogramIterator struct {
|
||||
i int
|
||||
histograms []*histogram.Histogram
|
||||
}
|
||||
|
||||
func (h *histogramIterator) Next() chunkenc.ValueType {
|
||||
h.i++
|
||||
if h.i < len(h.histograms) {
|
||||
return chunkenc.ValHistogram
|
||||
}
|
||||
return chunkenc.ValNone
|
||||
}
|
||||
|
||||
func (h *histogramIterator) Seek(t int64) chunkenc.ValueType { panic("not implemented") }
|
||||
|
||||
func (h *histogramIterator) At() (int64, float64) { panic("not implemented") }
|
||||
|
||||
func (h *histogramIterator) AtHistogram(_ *histogram.Histogram) (int64, *histogram.Histogram) {
|
||||
return 0, h.histograms[h.i]
|
||||
}
|
||||
|
||||
func (h *histogramIterator) AtFloatHistogram(_ *histogram.FloatHistogram) (int64, *histogram.FloatHistogram) {
|
||||
return 0, h.histograms[h.i].ToFloat(nil)
|
||||
}
|
||||
|
||||
func (h *histogramIterator) AtT() int64 { return 0 }
|
||||
|
||||
func (h *histogramIterator) Err() error { return nil }
|
|
@ -198,10 +198,11 @@ type VectorSelector struct {
|
|||
// Offset is the offset used during the query execution
|
||||
// which is calculated using the original offset, at modifier time,
|
||||
// eval time, and subquery offsets in the AST tree.
|
||||
Offset time.Duration
|
||||
Timestamp *int64
|
||||
StartOrEnd ItemType // Set when @ is used with start() or end()
|
||||
LabelMatchers []*labels.Matcher
|
||||
Offset time.Duration
|
||||
Timestamp *int64
|
||||
SkipHistogramBuckets bool // Set when decoding native histogram buckets is not needed for query evaluation.
|
||||
StartOrEnd ItemType // Set when @ is used with start() or end()
|
||||
LabelMatchers []*labels.Matcher
|
||||
|
||||
// The unexpanded seriesSet populated at query preparation time.
|
||||
UnexpandedSeriesSet storage.SeriesSet
|
||||
|
|
|
@ -138,6 +138,16 @@ func TestExprString(t *testing.T) {
|
|||
{
|
||||
in: `{__name__="",a="x"}`,
|
||||
},
|
||||
{
|
||||
in: `{"a.b"="c"}`,
|
||||
},
|
||||
{
|
||||
in: `{"0"="1"}`,
|
||||
},
|
||||
{
|
||||
in: `{"_0"="1"}`,
|
||||
out: `{_0="1"}`,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range inputs {
|
||||
|
|
128
promql/promqltest/README.md
Normal file
128
promql/promqltest/README.md
Normal file
|
@ -0,0 +1,128 @@
|
|||
# The PromQL test scripting language
|
||||
|
||||
This package contains two things:
|
||||
|
||||
* an implementation of a test scripting language for PromQL engines
|
||||
* a predefined set of tests written in that scripting language
|
||||
|
||||
The predefined set of tests can be run against any PromQL engine implementation by calling `promqltest.RunBuiltinTests()`.
|
||||
Any other test script can be run with `promqltest.RunTest()`.
|
||||
|
||||
The rest of this document explains the test scripting language.
|
||||
|
||||
Each test script is written in plain text.
|
||||
|
||||
Comments can be given by prefixing the comment with a `#`, for example:
|
||||
|
||||
```
|
||||
# This is a comment.
|
||||
```
|
||||
|
||||
Each test file contains a series of commands. There are three kinds of commands:
|
||||
|
||||
* `load`
|
||||
* `clear`
|
||||
* `eval`
|
||||
|
||||
Each command is executed in the order given in the file.
|
||||
|
||||
## `load` command
|
||||
|
||||
`load` adds some data to the test environment.
|
||||
|
||||
The syntax is as follows:
|
||||
|
||||
```
|
||||
load <interval>
|
||||
<series> <points>
|
||||
...
|
||||
<series> <points>
|
||||
```
|
||||
|
||||
* `<interval>` is the step between points (eg. `1m` or `30s`)
|
||||
* `<series>` is a Prometheus series name in the usual `metric{label="value"}` syntax
|
||||
* `<points>` is a specification of the points to add for that series, following the same expanding syntax as for `promtool unittest` documented [here](../../docs/configuration/unit_testing_rules.md#series)
|
||||
|
||||
For example:
|
||||
|
||||
```
|
||||
load 1m
|
||||
my_metric{env="prod"} 5 2+3x2 _ stale {{schema:1 sum:3 count:22 buckets:[5 10 7]}}
|
||||
```
|
||||
|
||||
...will create a single series with labels `my_metric{env="prod"}`, with the following points:
|
||||
|
||||
* t=0: value is 5
|
||||
* t=1m: value is 2
|
||||
* t=2m: value is 5
|
||||
* t=3m: value is 7
|
||||
* t=4m: no point
|
||||
* t=5m: stale marker
|
||||
* t=6m: native histogram with schema 1, sum -3, count 22 and bucket counts 5, 10 and 7
|
||||
|
||||
Each `load` command is additive - it does not replace any data loaded in a previous `load` command.
|
||||
Use `clear` to remove all loaded data.
|
||||
|
||||
## `clear` command
|
||||
|
||||
`clear` removes all data previously loaded with `load` commands.
|
||||
|
||||
## `eval` command
|
||||
|
||||
`eval` runs a query against the test environment and asserts that the result is as expected.
|
||||
|
||||
Both instant and range queries are supported.
|
||||
|
||||
The syntax is as follows:
|
||||
|
||||
```
|
||||
# Instant query
|
||||
eval instant at <time> <query>
|
||||
<series> <points>
|
||||
...
|
||||
<series> <points>
|
||||
|
||||
# Range query
|
||||
eval range from <start> to <end> step <step> <query>
|
||||
<series> <points>
|
||||
...
|
||||
<series> <points>
|
||||
```
|
||||
|
||||
* `<time>` is the timestamp to evaluate the instant query at (eg. `1m`)
|
||||
* `<start>` and `<end>` specify the time range of the range query, and use the same syntax as `<time>`
|
||||
* `<step>` is the step of the range query, and uses the same syntax as `<time>` (eg. `30s`)
|
||||
* `<series>` and `<points>` specify the expected values, and follow the same syntax as for `load` above
|
||||
|
||||
For example:
|
||||
|
||||
```
|
||||
eval instant at 1m sum by (env) (my_metric)
|
||||
{env="prod"} 5
|
||||
{env="test"} 20
|
||||
|
||||
eval range from 0 to 3m step 1m sum by (env) (my_metric)
|
||||
{env="prod"} 2 5 10 20
|
||||
{env="test"} 10 20 30 45
|
||||
```
|
||||
|
||||
Instant queries also support asserting that the series are returned in exactly the order specified: use `eval_ordered instant ...` instead of `eval instant ...`.
|
||||
This is not supported for range queries.
|
||||
|
||||
It is also possible to test that queries fail: use `eval_fail instant ...` or `eval_fail range ...`.
|
||||
`eval_fail` optionally takes an expected error message string or regexp to assert that the error message is as expected.
|
||||
|
||||
For example:
|
||||
|
||||
```
|
||||
# Assert that the query fails for any reason without asserting on the error message.
|
||||
eval_fail instant at 1m ceil({__name__=~'testmetric1|testmetric2'})
|
||||
|
||||
# Assert that the query fails with exactly the provided error message string.
|
||||
eval_fail instant at 1m ceil({__name__=~'testmetric1|testmetric2'})
|
||||
expected_fail_message vector cannot contain metrics with the same labelset
|
||||
|
||||
# Assert that the query fails with an error message matching the regexp provided.
|
||||
eval_fail instant at 1m ceil({__name__=~'testmetric1|testmetric2'})
|
||||
expected_fail_regexp (vector cannot contain metrics .*|something else went wrong)
|
||||
```
|
|
@ -344,6 +344,21 @@ func (t *test) parseEval(lines []string, i int) (int, *evalCmd, error) {
|
|||
i--
|
||||
break
|
||||
}
|
||||
|
||||
if cmd.fail && strings.HasPrefix(defLine, "expected_fail_message") {
|
||||
cmd.expectedFailMessage = strings.TrimSpace(strings.TrimPrefix(defLine, "expected_fail_message"))
|
||||
break
|
||||
}
|
||||
|
||||
if cmd.fail && strings.HasPrefix(defLine, "expected_fail_regexp") {
|
||||
pattern := strings.TrimSpace(strings.TrimPrefix(defLine, "expected_fail_regexp"))
|
||||
cmd.expectedFailRegexp, err = regexp.Compile(pattern)
|
||||
if err != nil {
|
||||
return i, nil, formatErr("invalid regexp '%s' for expected_fail_regexp: %w", pattern, err)
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
if f, err := parseNumber(defLine); err == nil {
|
||||
cmd.expect(0, parser.SequenceValue{Value: f})
|
||||
break
|
||||
|
@ -659,6 +674,8 @@ type evalCmd struct {
|
|||
isRange bool // if false, instant query
|
||||
fail, warn, ordered bool
|
||||
withNHCB bool
|
||||
expectedFailMessage string
|
||||
expectedFailRegexp *regexp.Regexp
|
||||
|
||||
metrics map[uint64]labels.Labels
|
||||
expected map[uint64]entry
|
||||
|
@ -847,6 +864,24 @@ func (ev *evalCmd) compareResult(result parser.Value) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (ev *evalCmd) checkExpectedFailure(actual error) error {
|
||||
if ev.expectedFailMessage != "" {
|
||||
if ev.expectedFailMessage != actual.Error() {
|
||||
return fmt.Errorf("expected error %q evaluating query %q (line %d), but got: %s", ev.expectedFailMessage, ev.expr, ev.line, actual.Error())
|
||||
}
|
||||
}
|
||||
|
||||
if ev.expectedFailRegexp != nil {
|
||||
if !ev.expectedFailRegexp.MatchString(actual.Error()) {
|
||||
return fmt.Errorf("expected error matching pattern %q evaluating query %q (line %d), but got: %s", ev.expectedFailRegexp.String(), ev.expr, ev.line, actual.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// We're not expecting a particular error, or we got the error we expected.
|
||||
// This test passes.
|
||||
return nil
|
||||
}
|
||||
|
||||
func formatSeriesResult(s promql.Series) string {
|
||||
floatPlural := "s"
|
||||
histogramPlural := "s"
|
||||
|
@ -1004,7 +1039,7 @@ func (t *test) execRangeEval(cmd *evalCmd, engine promql.QueryEngine) error {
|
|||
}
|
||||
if res.Err != nil {
|
||||
if cmd.fail {
|
||||
return nil
|
||||
return cmd.checkExpectedFailure(res.Err)
|
||||
}
|
||||
|
||||
return fmt.Errorf("error evaluating query %q (line %d): %w", cmd.expr, cmd.line, res.Err)
|
||||
|
@ -1071,6 +1106,10 @@ func (t *test) runInstantQuery(iq atModifierTestCase, cmd *evalCmd, engine promq
|
|||
}
|
||||
if res.Err != nil {
|
||||
if cmd.fail {
|
||||
if err := cmd.checkExpectedFailure(res.Err); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("error evaluating query %q (line %d): %w", iq.expr, cmd.line, res.Err)
|
||||
|
|
|
@ -263,6 +263,60 @@ eval_fail instant at 0m ceil({__name__=~'testmetric1|testmetric2'})
|
|||
input: `eval_fail instant at 0s vector(0)`,
|
||||
expectedError: `expected error evaluating query "vector(0)" (line 1) but got none`,
|
||||
},
|
||||
"instant query expected to fail with specific error message, and query fails with that error": {
|
||||
input: `
|
||||
load 5m
|
||||
testmetric1{src="a",dst="b"} 0
|
||||
testmetric2{src="a",dst="b"} 1
|
||||
|
||||
eval_fail instant at 0m ceil({__name__=~'testmetric1|testmetric2'})
|
||||
expected_fail_message vector cannot contain metrics with the same labelset
|
||||
`,
|
||||
},
|
||||
"instant query expected to fail with specific error message, and query fails with a different error": {
|
||||
input: `
|
||||
load 5m
|
||||
testmetric1{src="a",dst="b"} 0
|
||||
testmetric2{src="a",dst="b"} 1
|
||||
|
||||
eval_fail instant at 0m ceil({__name__=~'testmetric1|testmetric2'})
|
||||
expected_fail_message something else went wrong
|
||||
`,
|
||||
expectedError: `expected error "something else went wrong" evaluating query "ceil({__name__=~'testmetric1|testmetric2'})" (line 6), but got: vector cannot contain metrics with the same labelset`,
|
||||
},
|
||||
|
||||
"instant query expected to fail with error matching pattern, and query fails with that error": {
|
||||
input: `
|
||||
load 5m
|
||||
testmetric1{src="a",dst="b"} 0
|
||||
testmetric2{src="a",dst="b"} 1
|
||||
|
||||
eval_fail instant at 0m ceil({__name__=~'testmetric1|testmetric2'})
|
||||
expected_fail_regexp vector .* contain metrics
|
||||
`,
|
||||
},
|
||||
"instant query expected to fail with error matching pattern, and query fails with a different error": {
|
||||
input: `
|
||||
load 5m
|
||||
testmetric1{src="a",dst="b"} 0
|
||||
testmetric2{src="a",dst="b"} 1
|
||||
|
||||
eval_fail instant at 0m ceil({__name__=~'testmetric1|testmetric2'})
|
||||
expected_fail_regexp something else went wrong
|
||||
`,
|
||||
expectedError: `expected error matching pattern "something else went wrong" evaluating query "ceil({__name__=~'testmetric1|testmetric2'})" (line 6), but got: vector cannot contain metrics with the same labelset`,
|
||||
},
|
||||
"instant query expected to fail with error matching pattern, and pattern is not a valid regexp": {
|
||||
input: `
|
||||
load 5m
|
||||
testmetric1{src="a",dst="b"} 0
|
||||
testmetric2{src="a",dst="b"} 1
|
||||
|
||||
eval_fail instant at 0m ceil({__name__=~'testmetric1|testmetric2'})
|
||||
expected_fail_regexp [
|
||||
`,
|
||||
expectedError: `error in eval ceil({__name__=~'testmetric1|testmetric2'}) (line 7): invalid regexp '[' for expected_fail_regexp: error parsing regexp: missing closing ]: ` + "`[`",
|
||||
},
|
||||
"instant query with results expected to match provided order, and result is in expected order": {
|
||||
input: testData + `
|
||||
eval_ordered instant at 50m sort(http_requests)
|
||||
|
@ -384,6 +438,59 @@ eval_fail range from 0 to 10m step 5m ceil({__name__=~'testmetric1|testmetric2'}
|
|||
input: `eval_fail range from 0 to 10m step 5m vector(0)`,
|
||||
expectedError: `expected error evaluating query "vector(0)" (line 1) but got none`,
|
||||
},
|
||||
"range query expected to fail with specific error message, and query fails with that error": {
|
||||
input: `
|
||||
load 5m
|
||||
testmetric1{src="a",dst="b"} 0
|
||||
testmetric2{src="a",dst="b"} 1
|
||||
|
||||
eval_fail range from 0 to 10m step 5m ceil({__name__=~'testmetric1|testmetric2'})
|
||||
expected_fail_message vector cannot contain metrics with the same labelset
|
||||
`,
|
||||
},
|
||||
"range query expected to fail with specific error message, and query fails with a different error": {
|
||||
input: `
|
||||
load 5m
|
||||
testmetric1{src="a",dst="b"} 0
|
||||
testmetric2{src="a",dst="b"} 1
|
||||
|
||||
eval_fail range from 0 to 10m step 5m ceil({__name__=~'testmetric1|testmetric2'})
|
||||
expected_fail_message something else went wrong
|
||||
`,
|
||||
expectedError: `expected error "something else went wrong" evaluating query "ceil({__name__=~'testmetric1|testmetric2'})" (line 6), but got: vector cannot contain metrics with the same labelset`,
|
||||
},
|
||||
"range query expected to fail with error matching pattern, and query fails with that error": {
|
||||
input: `
|
||||
load 5m
|
||||
testmetric1{src="a",dst="b"} 0
|
||||
testmetric2{src="a",dst="b"} 1
|
||||
|
||||
eval_fail range from 0 to 10m step 5m ceil({__name__=~'testmetric1|testmetric2'})
|
||||
expected_fail_regexp vector .* contain metrics
|
||||
`,
|
||||
},
|
||||
"range query expected to fail with error matching pattern, and query fails with a different error": {
|
||||
input: `
|
||||
load 5m
|
||||
testmetric1{src="a",dst="b"} 0
|
||||
testmetric2{src="a",dst="b"} 1
|
||||
|
||||
eval_fail range from 0 to 10m step 5m ceil({__name__=~'testmetric1|testmetric2'})
|
||||
expected_fail_regexp something else went wrong
|
||||
`,
|
||||
expectedError: `expected error matching pattern "something else went wrong" evaluating query "ceil({__name__=~'testmetric1|testmetric2'})" (line 6), but got: vector cannot contain metrics with the same labelset`,
|
||||
},
|
||||
"range query expected to fail with error matching pattern, and pattern is not a valid regexp": {
|
||||
input: `
|
||||
load 5m
|
||||
testmetric1{src="a",dst="b"} 0
|
||||
testmetric2{src="a",dst="b"} 1
|
||||
|
||||
eval_fail range from 0 to 10m step 5m ceil({__name__=~'testmetric1|testmetric2'})
|
||||
expected_fail_regexp [
|
||||
`,
|
||||
expectedError: `error in eval ceil({__name__=~'testmetric1|testmetric2'}) (line 7): invalid regexp '[' for expected_fail_regexp: error parsing regexp: missing closing ]: ` + "`[`",
|
||||
},
|
||||
"range query with from and to timestamps in wrong order": {
|
||||
input: `eval range from 10m to 9m step 5m vector(0)`,
|
||||
expectedError: `error in eval vector(0) (line 1): invalid test definition, end timestamp (9m) is before start timestamp (10m)`,
|
||||
|
|
451
promql/promqltest/testdata/native_histograms.test
vendored
451
promql/promqltest/testdata/native_histograms.test
vendored
|
@ -270,17 +270,460 @@ eval instant at 50m histogram_sum(sum(incr_sum_histogram))
|
|||
eval instant at 50m histogram_sum(sum(last_over_time(incr_sum_histogram[5m])))
|
||||
{} 30
|
||||
|
||||
# Apply rate function to histogram.
|
||||
load 15s
|
||||
histogram_rate {{schema:1 count:12 sum:18.4 z_bucket:2 z_bucket_w:0.001 buckets:[1 2 0 1 1] n_buckets:[1 2 0 1 1]}}+{{schema:1 count:9 sum:18.4 z_bucket:1 z_bucket_w:0.001 buckets:[1 1 0 1 1] n_buckets:[1 1 0 1 1]}}x100
|
||||
|
||||
eval instant at 5m rate(histogram_rate[45s])
|
||||
{} {{schema:1 count:0.6 sum:1.2266666666666652 z_bucket:0.06666666666666667 z_bucket_w:0.001 buckets:[0.06666666666666667 0.06666666666666667 0 0.06666666666666667 0.06666666666666667] n_buckets:[0.06666666666666667 0.06666666666666667 0 0.06666666666666667 0.06666666666666667]}}
|
||||
|
||||
eval range from 5m to 5m30s step 30s rate(histogram_rate[45s])
|
||||
{} {{schema:1 count:0.6 sum:1.2266666666666652 z_bucket:0.06666666666666667 z_bucket_w:0.001 buckets:[0.06666666666666667 0.06666666666666667 0 0.06666666666666667 0.06666666666666667] n_buckets:[0.06666666666666667 0.06666666666666667 0 0.06666666666666667 0.06666666666666667]}}x1
|
||||
|
||||
# Apply count and sum function to histogram.
|
||||
load 10m
|
||||
histogram_count_sum_2 {{schema:0 count:24 sum:100 z_bucket:4 z_bucket_w:0.001 buckets:[2 3 0 1 4] n_buckets:[2 3 0 1 4]}}x1
|
||||
|
||||
eval instant at 10m histogram_count(histogram_count_sum_2)
|
||||
{} 24
|
||||
|
||||
eval instant at 10m histogram_sum(histogram_count_sum_2)
|
||||
{} 100
|
||||
|
||||
# Apply stddev and stdvar function to histogram with {1, 2, 3, 4} (low res).
|
||||
load 10m
|
||||
histogram_stddev_stdvar_1 {{schema:2 count:4 sum:10 buckets:[1 0 0 0 1 0 0 1 1]}}x1
|
||||
|
||||
eval instant at 10m histogram_stddev(histogram_stddev_stdvar_1)
|
||||
{} 1.0787993180043811
|
||||
|
||||
eval instant at 10m histogram_stdvar(histogram_stddev_stdvar_1)
|
||||
{} 1.163807968526718
|
||||
|
||||
# Apply stddev and stdvar function to histogram with {1, 1, 1, 1} (high res).
|
||||
load 10m
|
||||
histogram_stddev_stdvar_2 {{schema:8 count:10 sum:10 buckets:[1 2 3 4]}}x1
|
||||
|
||||
eval instant at 10m histogram_stddev(histogram_stddev_stdvar_2)
|
||||
{} 0.0048960313898237465
|
||||
|
||||
eval instant at 10m histogram_stdvar(histogram_stddev_stdvar_2)
|
||||
{} 2.3971123370139447e-05
|
||||
|
||||
# Apply stddev and stdvar function to histogram with {-50, -8, 0, 3, 8, 9}.
|
||||
load 10m
|
||||
histogram_stddev_stdvar_3 {{schema:3 count:7 sum:62 z_bucket:1 buckets:[0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 ] n_buckets:[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 ]}}x1
|
||||
|
||||
eval instant at 10m histogram_stddev(histogram_stddev_stdvar_3)
|
||||
{} 42.947236400258
|
||||
|
||||
eval instant at 10m histogram_stdvar(histogram_stddev_stdvar_3)
|
||||
{} 1844.4651144196398
|
||||
|
||||
# Apply stddev and stdvar function to histogram with {-100000, -10000, -1000, -888, -888, -100, -50, -9, -8, -3}.
|
||||
load 10m
|
||||
histogram_stddev_stdvar_4 {{schema:0 count:10 sum:-112946 z_bucket:0 n_buckets:[0 0 1 1 1 0 1 1 0 0 3 0 0 0 1 0 0 1]}}x1
|
||||
|
||||
eval instant at 10m histogram_stddev(histogram_stddev_stdvar_4)
|
||||
{} 27556.344499842
|
||||
|
||||
eval instant at 10m histogram_stdvar(histogram_stddev_stdvar_4)
|
||||
{} 759352122.1939945
|
||||
|
||||
# Apply stddev and stdvar function to histogram with {-10x10}.
|
||||
load 10m
|
||||
histogram_stddev_stdvar_5 {{schema:0 count:10 sum:-100 z_bucket:0 n_buckets:[0 0 0 0 10]}}x1
|
||||
|
||||
eval instant at 10m histogram_stddev(histogram_stddev_stdvar_5)
|
||||
{} 1.3137084989848
|
||||
|
||||
eval instant at 10m histogram_stdvar(histogram_stddev_stdvar_5)
|
||||
{} 1.725830020304794
|
||||
|
||||
# Apply stddev and stdvar function to histogram with {-50, -8, 0, 3, 8, 9, NaN}.
|
||||
load 10m
|
||||
histogram_stddev_stdvar_6 {{schema:3 count:7 sum:NaN z_bucket:1 buckets:[0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 ] n_buckets:[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 ]}}x1
|
||||
|
||||
eval instant at 10m histogram_stddev(histogram_stddev_stdvar_6)
|
||||
{} NaN
|
||||
|
||||
eval instant at 10m histogram_stdvar(histogram_stddev_stdvar_6)
|
||||
{} NaN
|
||||
|
||||
# Apply stddev and stdvar function to histogram with {-50, -8, 0, 3, 8, 9, Inf}.
|
||||
load 10m
|
||||
histogram_stddev_stdvar_7 {{schema:3 count:7 sum:Inf z_bucket:1 buckets:[0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 ] n_buckets:[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 ]}}x1
|
||||
|
||||
eval instant at 10m histogram_stddev(histogram_stddev_stdvar_7)
|
||||
{} NaN
|
||||
|
||||
eval instant at 10m histogram_stdvar(histogram_stddev_stdvar_7)
|
||||
{} NaN
|
||||
|
||||
# Apply quantile function to histogram with all positive buckets with zero bucket.
|
||||
load 10m
|
||||
histogram_quantile_1 {{schema:0 count:12 sum:100 z_bucket:2 z_bucket_w:0.001 buckets:[2 3 0 1 4]}}x1
|
||||
|
||||
eval_warn instant at 10m histogram_quantile(1.001, histogram_quantile_1)
|
||||
{} Inf
|
||||
|
||||
eval instant at 10m histogram_quantile(1, histogram_quantile_1)
|
||||
{} 16
|
||||
|
||||
eval instant at 10m histogram_quantile(0.99, histogram_quantile_1)
|
||||
{} 15.759999999999998
|
||||
|
||||
eval instant at 10m histogram_quantile(0.9, histogram_quantile_1)
|
||||
{} 13.600000000000001
|
||||
|
||||
eval instant at 10m histogram_quantile(0.6, histogram_quantile_1)
|
||||
{} 4.799999999999997
|
||||
|
||||
eval instant at 10m histogram_quantile(0.5, histogram_quantile_1)
|
||||
{} 1.6666666666666665
|
||||
|
||||
eval instant at 10m histogram_quantile(0.1, histogram_quantile_1)
|
||||
{} 0.0006000000000000001
|
||||
|
||||
eval instant at 10m histogram_quantile(0, histogram_quantile_1)
|
||||
{} 0
|
||||
|
||||
eval_warn instant at 10m histogram_quantile(-1, histogram_quantile_1)
|
||||
{} -Inf
|
||||
|
||||
# Apply quantile function to histogram with all negative buckets with zero bucket.
|
||||
load 10m
|
||||
histogram_quantile_2 {{schema:0 count:12 sum:100 z_bucket:2 z_bucket_w:0.001 n_buckets:[2 3 0 1 4]}}x1
|
||||
|
||||
eval_warn instant at 10m histogram_quantile(1.001, histogram_quantile_2)
|
||||
{} Inf
|
||||
|
||||
eval instant at 10m histogram_quantile(1, histogram_quantile_2)
|
||||
{} 0
|
||||
|
||||
eval instant at 10m histogram_quantile(0.99, histogram_quantile_2)
|
||||
{} -6.000000000000048e-05
|
||||
|
||||
eval instant at 10m histogram_quantile(0.9, histogram_quantile_2)
|
||||
{} -0.0005999999999999996
|
||||
|
||||
eval instant at 10m histogram_quantile(0.5, histogram_quantile_2)
|
||||
{} -1.6666666666666667
|
||||
|
||||
eval instant at 10m histogram_quantile(0.1, histogram_quantile_2)
|
||||
{} -13.6
|
||||
|
||||
eval instant at 10m histogram_quantile(0, histogram_quantile_2)
|
||||
{} -16
|
||||
|
||||
eval_warn instant at 10m histogram_quantile(-1, histogram_quantile_2)
|
||||
{} -Inf
|
||||
|
||||
# Apply quantile function to histogram with both positive and negative buckets with zero bucket.
|
||||
load 10m
|
||||
histogram_quantile_3 {{schema:0 count:24 sum:100 z_bucket:4 z_bucket_w:0.001 buckets:[2 3 0 1 4] n_buckets:[2 3 0 1 4]}}x1
|
||||
|
||||
eval_warn instant at 10m histogram_quantile(1.001, histogram_quantile_3)
|
||||
{} Inf
|
||||
|
||||
eval instant at 10m histogram_quantile(1, histogram_quantile_3)
|
||||
{} 16
|
||||
|
||||
eval instant at 10m histogram_quantile(0.99, histogram_quantile_3)
|
||||
{} 15.519999999999996
|
||||
|
||||
eval instant at 10m histogram_quantile(0.9, histogram_quantile_3)
|
||||
{} 11.200000000000003
|
||||
|
||||
eval instant at 10m histogram_quantile(0.7, histogram_quantile_3)
|
||||
{} 1.2666666666666657
|
||||
|
||||
eval instant at 10m histogram_quantile(0.55, histogram_quantile_3)
|
||||
{} 0.0006000000000000005
|
||||
|
||||
eval instant at 10m histogram_quantile(0.5, histogram_quantile_3)
|
||||
{} 0
|
||||
|
||||
eval instant at 10m histogram_quantile(0.45, histogram_quantile_3)
|
||||
{} -0.0005999999999999996
|
||||
|
||||
eval instant at 10m histogram_quantile(0.3, histogram_quantile_3)
|
||||
{} -1.266666666666667
|
||||
|
||||
eval instant at 10m histogram_quantile(0.1, histogram_quantile_3)
|
||||
{} -11.2
|
||||
|
||||
eval instant at 10m histogram_quantile(0.01, histogram_quantile_3)
|
||||
{} -15.52
|
||||
|
||||
eval instant at 10m histogram_quantile(0, histogram_quantile_3)
|
||||
{} -16
|
||||
|
||||
eval_warn instant at 10m histogram_quantile(-1, histogram_quantile_3)
|
||||
{} -Inf
|
||||
|
||||
# Apply fraction function to empty histogram.
|
||||
load 10m
|
||||
histogram_fraction_1 {{}}x1
|
||||
|
||||
eval instant at 10m histogram_fraction(3.1415, 42, histogram_fraction_1)
|
||||
{} NaN
|
||||
|
||||
# Apply fraction function to histogram with positive and zero buckets.
|
||||
load 10m
|
||||
histogram_fraction_2 {{schema:0 count:12 sum:100 z_bucket:2 z_bucket_w:0.001 buckets:[2 3 0 1 4]}}x1
|
||||
|
||||
eval instant at 10m histogram_fraction(0, +Inf, histogram_fraction_2)
|
||||
{} 1
|
||||
|
||||
eval instant at 10m histogram_fraction(-Inf, 0, histogram_fraction_2)
|
||||
{} 0
|
||||
|
||||
eval instant at 10m histogram_fraction(-0.001, 0, histogram_fraction_2)
|
||||
{} 0
|
||||
|
||||
eval instant at 10m histogram_fraction(0, 0.001, histogram_fraction_2)
|
||||
{} 0.16666666666666666
|
||||
|
||||
eval instant at 10m histogram_fraction(0, 0.0005, histogram_fraction_2)
|
||||
{} 0.08333333333333333
|
||||
|
||||
eval instant at 10m histogram_fraction(0.001, inf, histogram_fraction_2)
|
||||
{} 0.8333333333333334
|
||||
|
||||
eval instant at 10m histogram_fraction(-inf, -0.001, histogram_fraction_2)
|
||||
{} 0
|
||||
|
||||
eval instant at 10m histogram_fraction(1, 2, histogram_fraction_2)
|
||||
{} 0.25
|
||||
|
||||
eval instant at 10m histogram_fraction(1.5, 2, histogram_fraction_2)
|
||||
{} 0.125
|
||||
|
||||
eval instant at 10m histogram_fraction(1, 8, histogram_fraction_2)
|
||||
{} 0.3333333333333333
|
||||
|
||||
eval instant at 10m histogram_fraction(1, 6, histogram_fraction_2)
|
||||
{} 0.2916666666666667
|
||||
|
||||
eval instant at 10m histogram_fraction(1.5, 6, histogram_fraction_2)
|
||||
{} 0.16666666666666666
|
||||
|
||||
eval instant at 10m histogram_fraction(-2, -1, histogram_fraction_2)
|
||||
{} 0
|
||||
|
||||
eval instant at 10m histogram_fraction(-2, -1.5, histogram_fraction_2)
|
||||
{} 0
|
||||
|
||||
eval instant at 10m histogram_fraction(-8, -1, histogram_fraction_2)
|
||||
{} 0
|
||||
|
||||
eval instant at 10m histogram_fraction(-6, -1, histogram_fraction_2)
|
||||
{} 0
|
||||
|
||||
eval instant at 10m histogram_fraction(-6, -1.5, histogram_fraction_2)
|
||||
{} 0
|
||||
|
||||
eval instant at 10m histogram_fraction(42, 3.1415, histogram_fraction_2)
|
||||
{} 0
|
||||
|
||||
eval instant at 10m histogram_fraction(0, 0, histogram_fraction_2)
|
||||
{} 0
|
||||
|
||||
eval instant at 10m histogram_fraction(0.000001, 0.000001, histogram_fraction_2)
|
||||
{} 0
|
||||
|
||||
eval instant at 10m histogram_fraction(42, 42, histogram_fraction_2)
|
||||
{} 0
|
||||
|
||||
eval instant at 10m histogram_fraction(-3.1, -3.1, histogram_fraction_2)
|
||||
{} 0
|
||||
|
||||
eval instant at 10m histogram_fraction(3.1415, NaN, histogram_fraction_2)
|
||||
{} NaN
|
||||
|
||||
eval instant at 10m histogram_fraction(NaN, 42, histogram_fraction_2)
|
||||
{} NaN
|
||||
|
||||
eval instant at 10m histogram_fraction(NaN, NaN, histogram_fraction_2)
|
||||
{} NaN
|
||||
|
||||
eval instant at 10m histogram_fraction(-Inf, +Inf, histogram_fraction_2)
|
||||
{} 1
|
||||
|
||||
# Apply fraction function to histogram with negative and zero buckets.
|
||||
load 10m
|
||||
histogram_fraction_3 {{schema:0 count:12 sum:100 z_bucket:2 z_bucket_w:0.001 n_buckets:[2 3 0 1 4]}}x1
|
||||
|
||||
eval instant at 10m histogram_fraction(0, +Inf, histogram_fraction_3)
|
||||
{} 0
|
||||
|
||||
eval instant at 10m histogram_fraction(-Inf, 0, histogram_fraction_3)
|
||||
{} 1
|
||||
|
||||
eval instant at 10m histogram_fraction(-0.001, 0, histogram_fraction_3)
|
||||
{} 0.16666666666666666
|
||||
|
||||
eval instant at 10m histogram_fraction(0, 0.001, histogram_fraction_3)
|
||||
{} 0
|
||||
|
||||
eval instant at 10m histogram_fraction(-0.0005, 0, histogram_fraction_3)
|
||||
{} 0.08333333333333333
|
||||
|
||||
eval instant at 10m histogram_fraction(0.001, inf, histogram_fraction_3)
|
||||
{} 0
|
||||
|
||||
eval instant at 10m histogram_fraction(-inf, -0.001, histogram_fraction_3)
|
||||
{} 0.8333333333333334
|
||||
|
||||
eval instant at 10m histogram_fraction(1, 2, histogram_fraction_3)
|
||||
{} 0
|
||||
|
||||
eval instant at 10m histogram_fraction(1.5, 2, histogram_fraction_3)
|
||||
{} 0
|
||||
|
||||
eval instant at 10m histogram_fraction(1, 8, histogram_fraction_3)
|
||||
{} 0
|
||||
|
||||
eval instant at 10m histogram_fraction(1, 6, histogram_fraction_3)
|
||||
{} 0
|
||||
|
||||
eval instant at 10m histogram_fraction(1.5, 6, histogram_fraction_3)
|
||||
{} 0
|
||||
|
||||
eval instant at 10m histogram_fraction(-2, -1, histogram_fraction_3)
|
||||
{} 0.25
|
||||
|
||||
eval instant at 10m histogram_fraction(-2, -1.5, histogram_fraction_3)
|
||||
{} 0.125
|
||||
|
||||
eval instant at 10m histogram_fraction(-8, -1, histogram_fraction_3)
|
||||
{} 0.3333333333333333
|
||||
|
||||
eval instant at 10m histogram_fraction(-6, -1, histogram_fraction_3)
|
||||
{} 0.2916666666666667
|
||||
|
||||
eval instant at 10m histogram_fraction(-6, -1.5, histogram_fraction_3)
|
||||
{} 0.16666666666666666
|
||||
|
||||
eval instant at 10m histogram_fraction(42, 3.1415, histogram_fraction_3)
|
||||
{} 0
|
||||
|
||||
eval instant at 10m histogram_fraction(0, 0, histogram_fraction_3)
|
||||
{} 0
|
||||
|
||||
eval instant at 10m histogram_fraction(0.000001, 0.000001, histogram_fraction_3)
|
||||
{} 0
|
||||
|
||||
eval instant at 10m histogram_fraction(42, 42, histogram_fraction_3)
|
||||
{} 0
|
||||
|
||||
eval instant at 10m histogram_fraction(-3.1, -3.1, histogram_fraction_3)
|
||||
{} 0
|
||||
|
||||
eval instant at 10m histogram_fraction(3.1415, NaN, histogram_fraction_3)
|
||||
{} NaN
|
||||
|
||||
eval instant at 10m histogram_fraction(NaN, 42, histogram_fraction_3)
|
||||
{} NaN
|
||||
|
||||
eval instant at 10m histogram_fraction(NaN, NaN, histogram_fraction_3)
|
||||
{} NaN
|
||||
|
||||
eval instant at 10m histogram_fraction(-Inf, +Inf, histogram_fraction_3)
|
||||
{} 1
|
||||
|
||||
# Apply fraction function to histogram with both positive, negative and zero buckets.
|
||||
load 10m
|
||||
histogram_fraction_4 {{schema:0 count:24 sum:100 z_bucket:4 z_bucket_w:0.001 buckets:[2 3 0 1 4] n_buckets:[2 3 0 1 4]}}x1
|
||||
|
||||
eval instant at 10m histogram_fraction(0, +Inf, histogram_fraction_4)
|
||||
{} 0.5
|
||||
|
||||
eval instant at 10m histogram_fraction(-Inf, 0, histogram_fraction_4)
|
||||
{} 0.5
|
||||
|
||||
eval instant at 10m histogram_fraction(-0.001, 0, histogram_fraction_4)
|
||||
{} 0.08333333333333333
|
||||
|
||||
eval instant at 10m histogram_fraction(0, 0.001, histogram_fraction_4)
|
||||
{} 0.08333333333333333
|
||||
|
||||
eval instant at 10m histogram_fraction(-0.0005, 0.0005, histogram_fraction_4)
|
||||
{} 0.08333333333333333
|
||||
|
||||
eval instant at 10m histogram_fraction(0.001, inf, histogram_fraction_4)
|
||||
{} 0.4166666666666667
|
||||
|
||||
eval instant at 10m histogram_fraction(-inf, -0.001, histogram_fraction_4)
|
||||
{} 0.4166666666666667
|
||||
|
||||
eval instant at 10m histogram_fraction(1, 2, histogram_fraction_4)
|
||||
{} 0.125
|
||||
|
||||
eval instant at 10m histogram_fraction(1.5, 2, histogram_fraction_4)
|
||||
{} 0.0625
|
||||
|
||||
eval instant at 10m histogram_fraction(1, 8, histogram_fraction_4)
|
||||
{} 0.16666666666666666
|
||||
|
||||
eval instant at 10m histogram_fraction(1, 6, histogram_fraction_4)
|
||||
{} 0.14583333333333334
|
||||
|
||||
eval instant at 10m histogram_fraction(1.5, 6, histogram_fraction_4)
|
||||
{} 0.08333333333333333
|
||||
|
||||
eval instant at 10m histogram_fraction(-2, -1, histogram_fraction_4)
|
||||
{} 0.125
|
||||
|
||||
eval instant at 10m histogram_fraction(-2, -1.5, histogram_fraction_4)
|
||||
{} 0.0625
|
||||
|
||||
eval instant at 10m histogram_fraction(-8, -1, histogram_fraction_4)
|
||||
{} 0.16666666666666666
|
||||
|
||||
eval instant at 10m histogram_fraction(-6, -1, histogram_fraction_4)
|
||||
{} 0.14583333333333334
|
||||
|
||||
eval instant at 10m histogram_fraction(-6, -1.5, histogram_fraction_4)
|
||||
{} 0.08333333333333333
|
||||
|
||||
eval instant at 10m histogram_fraction(42, 3.1415, histogram_fraction_4)
|
||||
{} 0
|
||||
|
||||
eval instant at 10m histogram_fraction(0, 0, histogram_fraction_4)
|
||||
{} 0
|
||||
|
||||
eval instant at 10m histogram_fraction(0.000001, 0.000001, histogram_fraction_4)
|
||||
{} 0
|
||||
|
||||
eval instant at 10m histogram_fraction(42, 42, histogram_fraction_4)
|
||||
{} 0
|
||||
|
||||
eval instant at 10m histogram_fraction(-3.1, -3.1, histogram_fraction_4)
|
||||
{} 0
|
||||
|
||||
eval instant at 10m histogram_fraction(3.1415, NaN, histogram_fraction_4)
|
||||
{} NaN
|
||||
|
||||
eval instant at 10m histogram_fraction(NaN, 42, histogram_fraction_4)
|
||||
{} NaN
|
||||
|
||||
eval instant at 10m histogram_fraction(NaN, NaN, histogram_fraction_4)
|
||||
{} NaN
|
||||
|
||||
eval instant at 10m histogram_fraction(-Inf, +Inf, histogram_fraction_4)
|
||||
{} 1
|
||||
|
||||
# Test native histograms with custom buckets.
|
||||
load 5m
|
||||
custom_buckets_histogram {{schema:-53 sum:5 count:4 custom_values:[5 10] buckets:[1 2 1]}}x10
|
||||
custom_buckets_histogram {{schema:-53 sum:5 count:4 custom_values:[5 10] buckets:[1 2 1]}}x10
|
||||
|
||||
eval instant at 5m histogram_fraction(5, 10, custom_buckets_histogram)
|
||||
{} 0.5
|
||||
{} 0.5
|
||||
|
||||
eval instant at 5m histogram_quantile(0.5, custom_buckets_histogram)
|
||||
{} 7.5
|
||||
{} 7.5
|
||||
|
||||
eval instant at 5m sum(custom_buckets_histogram)
|
||||
{} {{schema:-53 sum:5 count:4 custom_values:[5 10] buckets:[1 2 1]}}
|
||||
{} {{schema:-53 sum:5 count:4 custom_values:[5 10] buckets:[1 2 1]}}
|
||||
|
|
|
@ -16,6 +16,8 @@ package promql
|
|||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
@ -36,6 +38,8 @@ type ActiveQueryTracker struct {
|
|||
maxConcurrent int
|
||||
}
|
||||
|
||||
var _ io.Closer = &ActiveQueryTracker{}
|
||||
|
||||
type Entry struct {
|
||||
Query string `json:"query"`
|
||||
Timestamp int64 `json:"timestamp_sec"`
|
||||
|
@ -83,6 +87,23 @@ func logUnfinishedQueries(filename string, filesize int, logger log.Logger) {
|
|||
}
|
||||
}
|
||||
|
||||
type mmapedFile struct {
|
||||
f io.Closer
|
||||
m mmap.MMap
|
||||
}
|
||||
|
||||
func (f *mmapedFile) Close() error {
|
||||
err := f.m.Unmap()
|
||||
if err != nil {
|
||||
err = fmt.Errorf("mmapedFile: unmapping: %w", err)
|
||||
}
|
||||
if fErr := f.f.Close(); fErr != nil {
|
||||
return errors.Join(fmt.Errorf("close mmapedFile.f: %w", fErr), err)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func getMMapedFile(filename string, filesize int, logger log.Logger) ([]byte, io.Closer, error) {
|
||||
file, err := os.OpenFile(filename, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0o666)
|
||||
if err != nil {
|
||||
|
@ -108,7 +129,7 @@ func getMMapedFile(filename string, filesize int, logger log.Logger) ([]byte, io
|
|||
return nil, nil, err
|
||||
}
|
||||
|
||||
return fileAsBytes, file, err
|
||||
return fileAsBytes, &mmapedFile{f: file, m: fileAsBytes}, err
|
||||
}
|
||||
|
||||
func NewActiveQueryTracker(localStoragePath string, maxConcurrent int, logger log.Logger) *ActiveQueryTracker {
|
||||
|
@ -204,9 +225,13 @@ func (tracker ActiveQueryTracker) Insert(ctx context.Context, query string) (int
|
|||
}
|
||||
}
|
||||
|
||||
func (tracker *ActiveQueryTracker) Close() {
|
||||
// Close closes tracker.
|
||||
func (tracker *ActiveQueryTracker) Close() error {
|
||||
if tracker == nil || tracker.closer == nil {
|
||||
return
|
||||
return nil
|
||||
}
|
||||
tracker.closer.Close()
|
||||
if err := tracker.closer.Close(); err != nil {
|
||||
return fmt.Errorf("close ActiveQueryTracker.closer: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ package promql
|
|||
import (
|
||||
"context"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/grafana/regexp"
|
||||
|
@ -104,26 +105,26 @@ func TestIndexReuse(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestMMapFile(t *testing.T) {
|
||||
file, err := os.CreateTemp("", "mmapedFile")
|
||||
dir := t.TempDir()
|
||||
fpath := filepath.Join(dir, "mmapedFile")
|
||||
const data = "ab"
|
||||
|
||||
fileAsBytes, closer, err := getMMapedFile(fpath, 2, nil)
|
||||
require.NoError(t, err)
|
||||
copy(fileAsBytes, data)
|
||||
require.NoError(t, closer.Close())
|
||||
|
||||
filename := file.Name()
|
||||
defer os.Remove(filename)
|
||||
|
||||
fileAsBytes, _, err := getMMapedFile(filename, 2, nil)
|
||||
|
||||
require.NoError(t, err)
|
||||
copy(fileAsBytes, "ab")
|
||||
|
||||
f, err := os.Open(filename)
|
||||
f, err := os.Open(fpath)
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() {
|
||||
_ = f.Close()
|
||||
})
|
||||
|
||||
bytes := make([]byte, 4)
|
||||
n, err := f.Read(bytes)
|
||||
require.Equal(t, 2, n)
|
||||
require.NoError(t, err, "Unexpected error while reading file.")
|
||||
|
||||
require.Equal(t, fileAsBytes, bytes[:2], "Mmap failed")
|
||||
require.Equal(t, 2, n)
|
||||
require.Equal(t, []byte(data), bytes[:2], "Mmap failed")
|
||||
}
|
||||
|
||||
func TestParseBrokenJSON(t *testing.T) {
|
||||
|
|
|
@ -338,10 +338,9 @@ const resolvedRetention = 15 * time.Minute
|
|||
|
||||
// Eval evaluates the rule expression and then creates pending alerts and fires
|
||||
// or removes previously pending alerts accordingly.
|
||||
func (r *AlertingRule) Eval(ctx context.Context, ts time.Time, query QueryFunc, externalURL *url.URL, limit int) (promql.Vector, error) {
|
||||
func (r *AlertingRule) Eval(ctx context.Context, queryOffset time.Duration, ts time.Time, query QueryFunc, externalURL *url.URL, limit int) (promql.Vector, error) {
|
||||
ctx = NewOriginContext(ctx, NewRuleDetail(r))
|
||||
|
||||
res, err := query(ctx, r.vector.String(), ts)
|
||||
res, err := query(ctx, r.vector.String(), ts.Add(-queryOffset))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -484,8 +483,8 @@ func (r *AlertingRule) Eval(ctx context.Context, ts time.Time, query QueryFunc,
|
|||
}
|
||||
|
||||
if r.restored.Load() {
|
||||
vec = append(vec, r.sample(a, ts))
|
||||
vec = append(vec, r.forStateSample(a, ts, float64(a.ActiveAt.Unix())))
|
||||
vec = append(vec, r.sample(a, ts.Add(-queryOffset)))
|
||||
vec = append(vec, r.forStateSample(a, ts.Add(-queryOffset), float64(a.ActiveAt.Unix())))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -123,7 +123,7 @@ func TestAlertingRuleTemplateWithHistogram(t *testing.T) {
|
|||
)
|
||||
|
||||
evalTime := time.Now()
|
||||
res, err := rule.Eval(context.TODO(), evalTime, q, nil, 0)
|
||||
res, err := rule.Eval(context.TODO(), 0, evalTime, q, nil, 0)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Len(t, res, 2)
|
||||
|
@ -230,7 +230,7 @@ func TestAlertingRuleLabelsUpdate(t *testing.T) {
|
|||
t.Logf("case %d", i)
|
||||
evalTime := baseTime.Add(time.Duration(i) * time.Minute)
|
||||
result[0].T = timestamp.FromTime(evalTime)
|
||||
res, err := rule.Eval(context.TODO(), evalTime, EngineQueryFunc(testEngine, storage), nil, 0)
|
||||
res, err := rule.Eval(context.TODO(), 0, evalTime, EngineQueryFunc(testEngine, storage), nil, 0)
|
||||
require.NoError(t, err)
|
||||
|
||||
var filteredRes promql.Vector // After removing 'ALERTS_FOR_STATE' samples.
|
||||
|
@ -247,7 +247,7 @@ func TestAlertingRuleLabelsUpdate(t *testing.T) {
|
|||
testutil.RequireEqual(t, result, filteredRes)
|
||||
}
|
||||
evalTime := baseTime.Add(time.Duration(len(results)) * time.Minute)
|
||||
res, err := rule.Eval(context.TODO(), evalTime, EngineQueryFunc(testEngine, storage), nil, 0)
|
||||
res, err := rule.Eval(context.TODO(), 0, evalTime, EngineQueryFunc(testEngine, storage), nil, 0)
|
||||
require.NoError(t, err)
|
||||
require.Empty(t, res)
|
||||
}
|
||||
|
@ -315,7 +315,7 @@ func TestAlertingRuleExternalLabelsInTemplate(t *testing.T) {
|
|||
|
||||
var filteredRes promql.Vector // After removing 'ALERTS_FOR_STATE' samples.
|
||||
res, err := ruleWithoutExternalLabels.Eval(
|
||||
context.TODO(), evalTime, EngineQueryFunc(testEngine, storage), nil, 0,
|
||||
context.TODO(), 0, evalTime, EngineQueryFunc(testEngine, storage), nil, 0,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
for _, smpl := range res {
|
||||
|
@ -329,7 +329,7 @@ func TestAlertingRuleExternalLabelsInTemplate(t *testing.T) {
|
|||
}
|
||||
|
||||
res, err = ruleWithExternalLabels.Eval(
|
||||
context.TODO(), evalTime, EngineQueryFunc(testEngine, storage), nil, 0,
|
||||
context.TODO(), 0, evalTime, EngineQueryFunc(testEngine, storage), nil, 0,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
for _, smpl := range res {
|
||||
|
@ -408,7 +408,7 @@ func TestAlertingRuleExternalURLInTemplate(t *testing.T) {
|
|||
|
||||
var filteredRes promql.Vector // After removing 'ALERTS_FOR_STATE' samples.
|
||||
res, err := ruleWithoutExternalURL.Eval(
|
||||
context.TODO(), evalTime, EngineQueryFunc(testEngine, storage), nil, 0,
|
||||
context.TODO(), 0, evalTime, EngineQueryFunc(testEngine, storage), nil, 0,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
for _, smpl := range res {
|
||||
|
@ -422,7 +422,7 @@ func TestAlertingRuleExternalURLInTemplate(t *testing.T) {
|
|||
}
|
||||
|
||||
res, err = ruleWithExternalURL.Eval(
|
||||
context.TODO(), evalTime, EngineQueryFunc(testEngine, storage), nil, 0,
|
||||
context.TODO(), 0, evalTime, EngineQueryFunc(testEngine, storage), nil, 0,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
for _, smpl := range res {
|
||||
|
@ -477,7 +477,7 @@ func TestAlertingRuleEmptyLabelFromTemplate(t *testing.T) {
|
|||
|
||||
var filteredRes promql.Vector // After removing 'ALERTS_FOR_STATE' samples.
|
||||
res, err := rule.Eval(
|
||||
context.TODO(), evalTime, EngineQueryFunc(testEngine, storage), nil, 0,
|
||||
context.TODO(), 0, evalTime, EngineQueryFunc(testEngine, storage), nil, 0,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
for _, smpl := range res {
|
||||
|
@ -544,7 +544,7 @@ instance: {{ $v.Labels.instance }}, value: {{ printf "%.0f" $v.Value }};
|
|||
close(getDoneCh)
|
||||
}()
|
||||
_, err = ruleWithQueryInTemplate.Eval(
|
||||
context.TODO(), evalTime, slowQueryFunc, nil, 0,
|
||||
context.TODO(), 0, evalTime, slowQueryFunc, nil, 0,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
@ -596,7 +596,7 @@ func TestAlertingRuleDuplicate(t *testing.T) {
|
|||
"",
|
||||
true, log.NewNopLogger(),
|
||||
)
|
||||
_, err := rule.Eval(ctx, now, EngineQueryFunc(engine, storage), nil, 0)
|
||||
_, err := rule.Eval(ctx, 0, now, EngineQueryFunc(engine, storage), nil, 0)
|
||||
require.Error(t, err)
|
||||
require.EqualError(t, err, "vector contains metrics with the same labelset after applying alert labels")
|
||||
}
|
||||
|
@ -644,7 +644,7 @@ func TestAlertingRuleLimit(t *testing.T) {
|
|||
evalTime := time.Unix(0, 0)
|
||||
|
||||
for _, test := range tests {
|
||||
switch _, err := rule.Eval(context.TODO(), evalTime, EngineQueryFunc(testEngine, storage), nil, test.limit); {
|
||||
switch _, err := rule.Eval(context.TODO(), 0, evalTime, EngineQueryFunc(testEngine, storage), nil, test.limit); {
|
||||
case err != nil:
|
||||
require.EqualError(t, err, test.err)
|
||||
case test.err != "":
|
||||
|
@ -871,7 +871,7 @@ func TestKeepFiringFor(t *testing.T) {
|
|||
t.Logf("case %d", i)
|
||||
evalTime := baseTime.Add(time.Duration(i) * time.Minute)
|
||||
result[0].T = timestamp.FromTime(evalTime)
|
||||
res, err := rule.Eval(context.TODO(), evalTime, EngineQueryFunc(testEngine, storage), nil, 0)
|
||||
res, err := rule.Eval(context.TODO(), 0, evalTime, EngineQueryFunc(testEngine, storage), nil, 0)
|
||||
require.NoError(t, err)
|
||||
|
||||
var filteredRes promql.Vector // After removing 'ALERTS_FOR_STATE' samples.
|
||||
|
@ -888,7 +888,7 @@ func TestKeepFiringFor(t *testing.T) {
|
|||
testutil.RequireEqual(t, result, filteredRes)
|
||||
}
|
||||
evalTime := baseTime.Add(time.Duration(len(results)) * time.Minute)
|
||||
res, err := rule.Eval(context.TODO(), evalTime, EngineQueryFunc(testEngine, storage), nil, 0)
|
||||
res, err := rule.Eval(context.TODO(), 0, evalTime, EngineQueryFunc(testEngine, storage), nil, 0)
|
||||
require.NoError(t, err)
|
||||
require.Empty(t, res)
|
||||
}
|
||||
|
@ -925,7 +925,7 @@ func TestPendingAndKeepFiringFor(t *testing.T) {
|
|||
|
||||
baseTime := time.Unix(0, 0)
|
||||
result.T = timestamp.FromTime(baseTime)
|
||||
res, err := rule.Eval(context.TODO(), baseTime, EngineQueryFunc(testEngine, storage), nil, 0)
|
||||
res, err := rule.Eval(context.TODO(), 0, baseTime, EngineQueryFunc(testEngine, storage), nil, 0)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Len(t, res, 2)
|
||||
|
@ -940,7 +940,7 @@ func TestPendingAndKeepFiringFor(t *testing.T) {
|
|||
}
|
||||
|
||||
evalTime := baseTime.Add(time.Minute)
|
||||
res, err = rule.Eval(context.TODO(), evalTime, EngineQueryFunc(testEngine, storage), nil, 0)
|
||||
res, err = rule.Eval(context.TODO(), 0, evalTime, EngineQueryFunc(testEngine, storage), nil, 0)
|
||||
require.NoError(t, err)
|
||||
require.Empty(t, res)
|
||||
}
|
||||
|
@ -974,7 +974,7 @@ func TestAlertingEvalWithOrigin(t *testing.T) {
|
|||
true, log.NewNopLogger(),
|
||||
)
|
||||
|
||||
_, err = rule.Eval(ctx, now, func(ctx context.Context, qs string, _ time.Time) (promql.Vector, error) {
|
||||
_, err = rule.Eval(ctx, 0, now, func(ctx context.Context, qs string, _ time.Time) (promql.Vector, error) {
|
||||
detail = FromOriginContext(ctx)
|
||||
return nil, nil
|
||||
}, nil, 0)
|
||||
|
|
|
@ -47,6 +47,7 @@ type Group struct {
|
|||
name string
|
||||
file string
|
||||
interval time.Duration
|
||||
queryOffset *time.Duration
|
||||
limit int
|
||||
rules []Rule
|
||||
seriesInPreviousEval []map[string]labels.Labels // One per Rule.
|
||||
|
@ -90,6 +91,7 @@ type GroupOptions struct {
|
|||
Rules []Rule
|
||||
ShouldRestore bool
|
||||
Opts *ManagerOptions
|
||||
QueryOffset *time.Duration
|
||||
done chan struct{}
|
||||
EvalIterationFunc GroupEvalIterationFunc
|
||||
}
|
||||
|
@ -126,6 +128,7 @@ func NewGroup(o GroupOptions) *Group {
|
|||
name: o.Name,
|
||||
file: o.File,
|
||||
interval: o.Interval,
|
||||
queryOffset: o.QueryOffset,
|
||||
limit: o.Limit,
|
||||
rules: o.Rules,
|
||||
shouldRestore: o.ShouldRestore,
|
||||
|
@ -443,6 +446,8 @@ func (g *Group) Eval(ctx context.Context, ts time.Time) {
|
|||
wg sync.WaitGroup
|
||||
)
|
||||
|
||||
ruleQueryOffset := g.QueryOffset()
|
||||
|
||||
for i, rule := range g.rules {
|
||||
select {
|
||||
case <-g.done:
|
||||
|
@ -473,7 +478,7 @@ func (g *Group) Eval(ctx context.Context, ts time.Time) {
|
|||
|
||||
g.metrics.EvalTotal.WithLabelValues(GroupKey(g.File(), g.Name())).Inc()
|
||||
|
||||
vector, err := rule.Eval(ctx, ts, g.opts.QueryFunc, g.opts.ExternalURL, g.Limit())
|
||||
vector, err := rule.Eval(ctx, ruleQueryOffset, ts, g.opts.QueryFunc, g.opts.ExternalURL, g.Limit())
|
||||
if err != nil {
|
||||
rule.SetHealth(HealthBad)
|
||||
rule.SetLastError(err)
|
||||
|
@ -562,7 +567,7 @@ func (g *Group) Eval(ctx context.Context, ts time.Time) {
|
|||
for metric, lset := range g.seriesInPreviousEval[i] {
|
||||
if _, ok := seriesReturned[metric]; !ok {
|
||||
// Series no longer exposed, mark it stale.
|
||||
_, err = app.Append(0, lset, timestamp.FromTime(ts), math.Float64frombits(value.StaleNaN))
|
||||
_, err = app.Append(0, lset, timestamp.FromTime(ts.Add(-ruleQueryOffset)), math.Float64frombits(value.StaleNaN))
|
||||
unwrappedErr := errors.Unwrap(err)
|
||||
if unwrappedErr == nil {
|
||||
unwrappedErr = err
|
||||
|
@ -601,14 +606,27 @@ func (g *Group) Eval(ctx context.Context, ts time.Time) {
|
|||
g.cleanupStaleSeries(ctx, ts)
|
||||
}
|
||||
|
||||
func (g *Group) QueryOffset() time.Duration {
|
||||
if g.queryOffset != nil {
|
||||
return *g.queryOffset
|
||||
}
|
||||
|
||||
if g.opts.DefaultRuleQueryOffset != nil {
|
||||
return g.opts.DefaultRuleQueryOffset()
|
||||
}
|
||||
|
||||
return time.Duration(0)
|
||||
}
|
||||
|
||||
func (g *Group) cleanupStaleSeries(ctx context.Context, ts time.Time) {
|
||||
if len(g.staleSeries) == 0 {
|
||||
return
|
||||
}
|
||||
app := g.opts.Appendable.Appender(ctx)
|
||||
queryOffset := g.QueryOffset()
|
||||
for _, s := range g.staleSeries {
|
||||
// Rule that produced series no longer configured, mark it stale.
|
||||
_, err := app.Append(0, s, timestamp.FromTime(ts), math.Float64frombits(value.StaleNaN))
|
||||
_, err := app.Append(0, s, timestamp.FromTime(ts.Add(-queryOffset)), math.Float64frombits(value.StaleNaN))
|
||||
unwrappedErr := errors.Unwrap(err)
|
||||
if unwrappedErr == nil {
|
||||
unwrappedErr = err
|
||||
|
@ -775,6 +793,10 @@ func (g *Group) Equals(ng *Group) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
if ((g.queryOffset == nil) != (ng.queryOffset == nil)) || (g.queryOffset != nil && ng.queryOffset != nil && *g.queryOffset != *ng.queryOffset) {
|
||||
return false
|
||||
}
|
||||
|
||||
if len(g.rules) != len(ng.rules) {
|
||||
return false
|
||||
}
|
||||
|
|
98
rules/group_test.go
Normal file
98
rules/group_test.go
Normal file
|
@ -0,0 +1,98 @@
|
|||
// Copyright 2013 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 rules
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestGroup_Equals(t *testing.T) {
|
||||
tests := map[string]struct {
|
||||
first *Group
|
||||
second *Group
|
||||
expected bool
|
||||
}{
|
||||
"no query offset set on both groups": {
|
||||
first: &Group{
|
||||
name: "group-1",
|
||||
file: "file-1",
|
||||
interval: time.Minute,
|
||||
},
|
||||
second: &Group{
|
||||
name: "group-1",
|
||||
file: "file-1",
|
||||
interval: time.Minute,
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
"query offset set only on the first group": {
|
||||
first: &Group{
|
||||
name: "group-1",
|
||||
file: "file-1",
|
||||
interval: time.Minute,
|
||||
queryOffset: pointerOf[time.Duration](time.Minute),
|
||||
},
|
||||
second: &Group{
|
||||
name: "group-1",
|
||||
file: "file-1",
|
||||
interval: time.Minute,
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
"query offset set on both groups to the same value": {
|
||||
first: &Group{
|
||||
name: "group-1",
|
||||
file: "file-1",
|
||||
interval: time.Minute,
|
||||
queryOffset: pointerOf[time.Duration](time.Minute),
|
||||
},
|
||||
second: &Group{
|
||||
name: "group-1",
|
||||
file: "file-1",
|
||||
interval: time.Minute,
|
||||
queryOffset: pointerOf[time.Duration](time.Minute),
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
"query offset set on both groups to different value": {
|
||||
first: &Group{
|
||||
name: "group-1",
|
||||
file: "file-1",
|
||||
interval: time.Minute,
|
||||
queryOffset: pointerOf[time.Duration](time.Minute),
|
||||
},
|
||||
second: &Group{
|
||||
name: "group-1",
|
||||
file: "file-1",
|
||||
interval: time.Minute,
|
||||
queryOffset: pointerOf[time.Duration](2 * time.Minute),
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
}
|
||||
|
||||
for testName, testData := range tests {
|
||||
t.Run(testName, func(t *testing.T) {
|
||||
require.Equal(t, testData.expected, testData.first.Equals(testData.second))
|
||||
require.Equal(t, testData.expected, testData.second.Equals(testData.first))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func pointerOf[T any](value T) *T {
|
||||
return &value
|
||||
}
|
|
@ -116,6 +116,7 @@ type ManagerOptions struct {
|
|||
ForGracePeriod time.Duration
|
||||
ResendDelay time.Duration
|
||||
GroupLoader GroupLoader
|
||||
DefaultRuleQueryOffset func() time.Duration
|
||||
MaxConcurrentEvals int64
|
||||
ConcurrentEvalsEnabled bool
|
||||
RuleConcurrencyController RuleConcurrencyController
|
||||
|
@ -336,6 +337,7 @@ func (m *Manager) LoadGroups(
|
|||
Rules: rules,
|
||||
ShouldRestore: shouldRestore,
|
||||
Opts: m.opts,
|
||||
QueryOffset: (*time.Duration)(rg.QueryOffset),
|
||||
done: m.done,
|
||||
EvalIterationFunc: groupEvalIterationFunc,
|
||||
})
|
||||
|
|
|
@ -16,9 +16,12 @@ package rules
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"math"
|
||||
"os"
|
||||
"path"
|
||||
"sort"
|
||||
"strconv"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
@ -161,7 +164,7 @@ func TestAlertingRule(t *testing.T) {
|
|||
|
||||
evalTime := baseTime.Add(test.time)
|
||||
|
||||
res, err := rule.Eval(context.TODO(), evalTime, EngineQueryFunc(testEngine, storage), nil, 0)
|
||||
res, err := rule.Eval(context.TODO(), 0, evalTime, EngineQueryFunc(testEngine, storage), nil, 0)
|
||||
require.NoError(t, err)
|
||||
|
||||
var filteredRes promql.Vector // After removing 'ALERTS_FOR_STATE' samples.
|
||||
|
@ -191,152 +194,156 @@ func TestAlertingRule(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestForStateAddSamples(t *testing.T) {
|
||||
storage := promqltest.LoadedStorage(t, `
|
||||
for _, queryOffset := range []time.Duration{0, time.Minute} {
|
||||
t.Run(fmt.Sprintf("queryOffset %s", queryOffset.String()), func(t *testing.T) {
|
||||
storage := promqltest.LoadedStorage(t, `
|
||||
load 5m
|
||||
http_requests{job="app-server", instance="0", group="canary", severity="overwrite-me"} 75 85 95 105 105 95 85
|
||||
http_requests{job="app-server", instance="1", group="canary", severity="overwrite-me"} 80 90 100 110 120 130 140
|
||||
`)
|
||||
t.Cleanup(func() { storage.Close() })
|
||||
t.Cleanup(func() { storage.Close() })
|
||||
|
||||
expr, err := parser.ParseExpr(`http_requests{group="canary", job="app-server"} < 100`)
|
||||
require.NoError(t, err)
|
||||
expr, err := parser.ParseExpr(`http_requests{group="canary", job="app-server"} < 100`)
|
||||
require.NoError(t, err)
|
||||
|
||||
rule := NewAlertingRule(
|
||||
"HTTPRequestRateLow",
|
||||
expr,
|
||||
time.Minute,
|
||||
0,
|
||||
labels.FromStrings("severity", "{{\"c\"}}ritical"),
|
||||
labels.EmptyLabels(), labels.EmptyLabels(), "", true, nil,
|
||||
)
|
||||
result := promql.Vector{
|
||||
promql.Sample{
|
||||
Metric: labels.FromStrings(
|
||||
"__name__", "ALERTS_FOR_STATE",
|
||||
"alertname", "HTTPRequestRateLow",
|
||||
"group", "canary",
|
||||
"instance", "0",
|
||||
"job", "app-server",
|
||||
"severity", "critical",
|
||||
),
|
||||
F: 1,
|
||||
},
|
||||
promql.Sample{
|
||||
Metric: labels.FromStrings(
|
||||
"__name__", "ALERTS_FOR_STATE",
|
||||
"alertname", "HTTPRequestRateLow",
|
||||
"group", "canary",
|
||||
"instance", "1",
|
||||
"job", "app-server",
|
||||
"severity", "critical",
|
||||
),
|
||||
F: 1,
|
||||
},
|
||||
promql.Sample{
|
||||
Metric: labels.FromStrings(
|
||||
"__name__", "ALERTS_FOR_STATE",
|
||||
"alertname", "HTTPRequestRateLow",
|
||||
"group", "canary",
|
||||
"instance", "0",
|
||||
"job", "app-server",
|
||||
"severity", "critical",
|
||||
),
|
||||
F: 1,
|
||||
},
|
||||
promql.Sample{
|
||||
Metric: labels.FromStrings(
|
||||
"__name__", "ALERTS_FOR_STATE",
|
||||
"alertname", "HTTPRequestRateLow",
|
||||
"group", "canary",
|
||||
"instance", "1",
|
||||
"job", "app-server",
|
||||
"severity", "critical",
|
||||
),
|
||||
F: 1,
|
||||
},
|
||||
}
|
||||
|
||||
baseTime := time.Unix(0, 0)
|
||||
|
||||
tests := []struct {
|
||||
time time.Duration
|
||||
result promql.Vector
|
||||
persistThisTime bool // If true, it means this 'time' is persisted for 'for'.
|
||||
}{
|
||||
{
|
||||
time: 0,
|
||||
result: append(promql.Vector{}, result[:2]...),
|
||||
persistThisTime: true,
|
||||
},
|
||||
{
|
||||
time: 5 * time.Minute,
|
||||
result: append(promql.Vector{}, result[2:]...),
|
||||
},
|
||||
{
|
||||
time: 10 * time.Minute,
|
||||
result: append(promql.Vector{}, result[2:3]...),
|
||||
},
|
||||
{
|
||||
time: 15 * time.Minute,
|
||||
result: nil,
|
||||
},
|
||||
{
|
||||
time: 20 * time.Minute,
|
||||
result: nil,
|
||||
},
|
||||
{
|
||||
time: 25 * time.Minute,
|
||||
result: append(promql.Vector{}, result[:1]...),
|
||||
persistThisTime: true,
|
||||
},
|
||||
{
|
||||
time: 30 * time.Minute,
|
||||
result: append(promql.Vector{}, result[2:3]...),
|
||||
},
|
||||
}
|
||||
|
||||
var forState float64
|
||||
for i, test := range tests {
|
||||
t.Logf("case %d", i)
|
||||
evalTime := baseTime.Add(test.time)
|
||||
|
||||
if test.persistThisTime {
|
||||
forState = float64(evalTime.Unix())
|
||||
}
|
||||
if test.result == nil {
|
||||
forState = float64(value.StaleNaN)
|
||||
}
|
||||
|
||||
res, err := rule.Eval(context.TODO(), evalTime, EngineQueryFunc(testEngine, storage), nil, 0)
|
||||
require.NoError(t, err)
|
||||
|
||||
var filteredRes promql.Vector // After removing 'ALERTS' samples.
|
||||
for _, smpl := range res {
|
||||
smplName := smpl.Metric.Get("__name__")
|
||||
if smplName == "ALERTS_FOR_STATE" {
|
||||
filteredRes = append(filteredRes, smpl)
|
||||
} else {
|
||||
// If not 'ALERTS_FOR_STATE', it has to be 'ALERTS'.
|
||||
require.Equal(t, "ALERTS", smplName)
|
||||
rule := NewAlertingRule(
|
||||
"HTTPRequestRateLow",
|
||||
expr,
|
||||
time.Minute,
|
||||
0,
|
||||
labels.FromStrings("severity", "{{\"c\"}}ritical"),
|
||||
labels.EmptyLabels(), labels.EmptyLabels(), "", true, nil,
|
||||
)
|
||||
result := promql.Vector{
|
||||
promql.Sample{
|
||||
Metric: labels.FromStrings(
|
||||
"__name__", "ALERTS_FOR_STATE",
|
||||
"alertname", "HTTPRequestRateLow",
|
||||
"group", "canary",
|
||||
"instance", "0",
|
||||
"job", "app-server",
|
||||
"severity", "critical",
|
||||
),
|
||||
F: 1,
|
||||
},
|
||||
promql.Sample{
|
||||
Metric: labels.FromStrings(
|
||||
"__name__", "ALERTS_FOR_STATE",
|
||||
"alertname", "HTTPRequestRateLow",
|
||||
"group", "canary",
|
||||
"instance", "1",
|
||||
"job", "app-server",
|
||||
"severity", "critical",
|
||||
),
|
||||
F: 1,
|
||||
},
|
||||
promql.Sample{
|
||||
Metric: labels.FromStrings(
|
||||
"__name__", "ALERTS_FOR_STATE",
|
||||
"alertname", "HTTPRequestRateLow",
|
||||
"group", "canary",
|
||||
"instance", "0",
|
||||
"job", "app-server",
|
||||
"severity", "critical",
|
||||
),
|
||||
F: 1,
|
||||
},
|
||||
promql.Sample{
|
||||
Metric: labels.FromStrings(
|
||||
"__name__", "ALERTS_FOR_STATE",
|
||||
"alertname", "HTTPRequestRateLow",
|
||||
"group", "canary",
|
||||
"instance", "1",
|
||||
"job", "app-server",
|
||||
"severity", "critical",
|
||||
),
|
||||
F: 1,
|
||||
},
|
||||
}
|
||||
}
|
||||
for i := range test.result {
|
||||
test.result[i].T = timestamp.FromTime(evalTime)
|
||||
// Updating the expected 'for' state.
|
||||
if test.result[i].F >= 0 {
|
||||
test.result[i].F = forState
|
||||
}
|
||||
}
|
||||
require.Equal(t, len(test.result), len(filteredRes), "%d. Number of samples in expected and actual output don't match (%d vs. %d)", i, len(test.result), len(res))
|
||||
|
||||
sort.Slice(filteredRes, func(i, j int) bool {
|
||||
return labels.Compare(filteredRes[i].Metric, filteredRes[j].Metric) < 0
|
||||
baseTime := time.Unix(0, 0)
|
||||
|
||||
tests := []struct {
|
||||
time time.Duration
|
||||
result promql.Vector
|
||||
persistThisTime bool // If true, it means this 'time' is persisted for 'for'.
|
||||
}{
|
||||
{
|
||||
time: 0,
|
||||
result: append(promql.Vector{}, result[:2]...),
|
||||
persistThisTime: true,
|
||||
},
|
||||
{
|
||||
time: 5 * time.Minute,
|
||||
result: append(promql.Vector{}, result[2:]...),
|
||||
},
|
||||
{
|
||||
time: 10 * time.Minute,
|
||||
result: append(promql.Vector{}, result[2:3]...),
|
||||
},
|
||||
{
|
||||
time: 15 * time.Minute,
|
||||
result: nil,
|
||||
},
|
||||
{
|
||||
time: 20 * time.Minute,
|
||||
result: nil,
|
||||
},
|
||||
{
|
||||
time: 25 * time.Minute,
|
||||
result: append(promql.Vector{}, result[:1]...),
|
||||
persistThisTime: true,
|
||||
},
|
||||
{
|
||||
time: 30 * time.Minute,
|
||||
result: append(promql.Vector{}, result[2:3]...),
|
||||
},
|
||||
}
|
||||
|
||||
var forState float64
|
||||
for i, test := range tests {
|
||||
t.Logf("case %d", i)
|
||||
evalTime := baseTime.Add(test.time).Add(queryOffset)
|
||||
|
||||
if test.persistThisTime {
|
||||
forState = float64(evalTime.Unix())
|
||||
}
|
||||
if test.result == nil {
|
||||
forState = float64(value.StaleNaN)
|
||||
}
|
||||
|
||||
res, err := rule.Eval(context.TODO(), queryOffset, evalTime, EngineQueryFunc(testEngine, storage), nil, 0)
|
||||
require.NoError(t, err)
|
||||
|
||||
var filteredRes promql.Vector // After removing 'ALERTS' samples.
|
||||
for _, smpl := range res {
|
||||
smplName := smpl.Metric.Get("__name__")
|
||||
if smplName == "ALERTS_FOR_STATE" {
|
||||
filteredRes = append(filteredRes, smpl)
|
||||
} else {
|
||||
// If not 'ALERTS_FOR_STATE', it has to be 'ALERTS'.
|
||||
require.Equal(t, "ALERTS", smplName)
|
||||
}
|
||||
}
|
||||
for i := range test.result {
|
||||
test.result[i].T = timestamp.FromTime(evalTime.Add(-queryOffset))
|
||||
// Updating the expected 'for' state.
|
||||
if test.result[i].F >= 0 {
|
||||
test.result[i].F = forState
|
||||
}
|
||||
}
|
||||
require.Equal(t, len(test.result), len(filteredRes), "%d. Number of samples in expected and actual output don't match (%d vs. %d)", i, len(test.result), len(res))
|
||||
|
||||
sort.Slice(filteredRes, func(i, j int) bool {
|
||||
return labels.Compare(filteredRes[i].Metric, filteredRes[j].Metric) < 0
|
||||
})
|
||||
prom_testutil.RequireEqual(t, test.result, filteredRes)
|
||||
|
||||
for _, aa := range rule.ActiveAlerts() {
|
||||
require.Zero(t, aa.Labels.Get(model.MetricNameLabel), "%s label set on active alert: %s", model.MetricNameLabel, aa.Labels)
|
||||
}
|
||||
}
|
||||
})
|
||||
prom_testutil.RequireEqual(t, test.result, filteredRes)
|
||||
|
||||
for _, aa := range rule.ActiveAlerts() {
|
||||
require.Zero(t, aa.Labels.Get(model.MetricNameLabel), "%s label set on active alert: %s", model.MetricNameLabel, aa.Labels)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -348,243 +355,251 @@ func sortAlerts(items []*Alert) {
|
|||
}
|
||||
|
||||
func TestForStateRestore(t *testing.T) {
|
||||
storage := promqltest.LoadedStorage(t, `
|
||||
for _, queryOffset := range []time.Duration{0, time.Minute} {
|
||||
t.Run(fmt.Sprintf("queryOffset %s", queryOffset.String()), func(t *testing.T) {
|
||||
storage := promqltest.LoadedStorage(t, `
|
||||
load 5m
|
||||
http_requests{job="app-server", instance="0", group="canary", severity="overwrite-me"} 75 85 50 0 0 25 0 0 40 0 120
|
||||
http_requests{job="app-server", instance="1", group="canary", severity="overwrite-me"} 125 90 60 0 0 25 0 0 40 0 130
|
||||
`)
|
||||
t.Cleanup(func() { storage.Close() })
|
||||
t.Cleanup(func() { storage.Close() })
|
||||
|
||||
expr, err := parser.ParseExpr(`http_requests{group="canary", job="app-server"} < 100`)
|
||||
require.NoError(t, err)
|
||||
expr, err := parser.ParseExpr(`http_requests{group="canary", job="app-server"} < 100`)
|
||||
require.NoError(t, err)
|
||||
|
||||
opts := &ManagerOptions{
|
||||
QueryFunc: EngineQueryFunc(testEngine, storage),
|
||||
Appendable: storage,
|
||||
Queryable: storage,
|
||||
Context: context.Background(),
|
||||
Logger: log.NewNopLogger(),
|
||||
NotifyFunc: func(ctx context.Context, expr string, alerts ...*Alert) {},
|
||||
OutageTolerance: 30 * time.Minute,
|
||||
ForGracePeriod: 10 * time.Minute,
|
||||
}
|
||||
|
||||
alertForDuration := 25 * time.Minute
|
||||
// Initial run before prometheus goes down.
|
||||
rule := NewAlertingRule(
|
||||
"HTTPRequestRateLow",
|
||||
expr,
|
||||
alertForDuration,
|
||||
0,
|
||||
labels.FromStrings("severity", "critical"),
|
||||
labels.EmptyLabels(), labels.EmptyLabels(), "", true, nil,
|
||||
)
|
||||
|
||||
group := NewGroup(GroupOptions{
|
||||
Name: "default",
|
||||
Interval: time.Second,
|
||||
Rules: []Rule{rule},
|
||||
ShouldRestore: true,
|
||||
Opts: opts,
|
||||
})
|
||||
groups := make(map[string]*Group)
|
||||
groups["default;"] = group
|
||||
|
||||
initialRuns := []time.Duration{0, 5 * time.Minute}
|
||||
|
||||
baseTime := time.Unix(0, 0)
|
||||
for _, duration := range initialRuns {
|
||||
evalTime := baseTime.Add(duration)
|
||||
group.Eval(context.TODO(), evalTime)
|
||||
}
|
||||
|
||||
// Prometheus goes down here. We create new rules and groups.
|
||||
type testInput struct {
|
||||
name string
|
||||
restoreDuration time.Duration
|
||||
expectedAlerts []*Alert
|
||||
|
||||
num int
|
||||
noRestore bool
|
||||
gracePeriod bool
|
||||
downDuration time.Duration
|
||||
before func()
|
||||
}
|
||||
|
||||
tests := []testInput{
|
||||
{
|
||||
name: "normal restore (alerts were not firing)",
|
||||
restoreDuration: 15 * time.Minute,
|
||||
expectedAlerts: rule.ActiveAlerts(),
|
||||
downDuration: 10 * time.Minute,
|
||||
},
|
||||
{
|
||||
name: "outage tolerance",
|
||||
restoreDuration: 40 * time.Minute,
|
||||
noRestore: true,
|
||||
num: 2,
|
||||
},
|
||||
{
|
||||
name: "no active alerts",
|
||||
restoreDuration: 50 * time.Minute,
|
||||
expectedAlerts: []*Alert{},
|
||||
},
|
||||
{
|
||||
name: "test the grace period",
|
||||
restoreDuration: 25 * time.Minute,
|
||||
expectedAlerts: []*Alert{},
|
||||
gracePeriod: true,
|
||||
before: func() {
|
||||
for _, duration := range []time.Duration{10 * time.Minute, 15 * time.Minute, 20 * time.Minute} {
|
||||
evalTime := baseTime.Add(duration)
|
||||
group.Eval(context.TODO(), evalTime)
|
||||
}
|
||||
},
|
||||
num: 2,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if tt.before != nil {
|
||||
tt.before()
|
||||
opts := &ManagerOptions{
|
||||
QueryFunc: EngineQueryFunc(testEngine, storage),
|
||||
Appendable: storage,
|
||||
Queryable: storage,
|
||||
Context: context.Background(),
|
||||
Logger: log.NewNopLogger(),
|
||||
NotifyFunc: func(ctx context.Context, expr string, alerts ...*Alert) {},
|
||||
OutageTolerance: 30 * time.Minute,
|
||||
ForGracePeriod: 10 * time.Minute,
|
||||
}
|
||||
|
||||
newRule := NewAlertingRule(
|
||||
alertForDuration := 25 * time.Minute
|
||||
// Initial run before prometheus goes down.
|
||||
rule := NewAlertingRule(
|
||||
"HTTPRequestRateLow",
|
||||
expr,
|
||||
alertForDuration,
|
||||
0,
|
||||
labels.FromStrings("severity", "critical"),
|
||||
labels.EmptyLabels(), labels.EmptyLabels(), "", false, nil,
|
||||
labels.EmptyLabels(), labels.EmptyLabels(), "", true, nil,
|
||||
)
|
||||
newGroup := NewGroup(GroupOptions{
|
||||
|
||||
group := NewGroup(GroupOptions{
|
||||
Name: "default",
|
||||
Interval: time.Second,
|
||||
Rules: []Rule{newRule},
|
||||
Rules: []Rule{rule},
|
||||
ShouldRestore: true,
|
||||
Opts: opts,
|
||||
})
|
||||
groups := make(map[string]*Group)
|
||||
groups["default;"] = group
|
||||
|
||||
newGroups := make(map[string]*Group)
|
||||
newGroups["default;"] = newGroup
|
||||
initialRuns := []time.Duration{0, 5 * time.Minute}
|
||||
|
||||
restoreTime := baseTime.Add(tt.restoreDuration)
|
||||
// First eval before restoration.
|
||||
newGroup.Eval(context.TODO(), restoreTime)
|
||||
// Restore happens here.
|
||||
newGroup.RestoreForState(restoreTime)
|
||||
|
||||
got := newRule.ActiveAlerts()
|
||||
for _, aa := range got {
|
||||
require.Zero(t, aa.Labels.Get(model.MetricNameLabel), "%s label set on active alert: %s", model.MetricNameLabel, aa.Labels)
|
||||
baseTime := time.Unix(0, 0)
|
||||
for _, duration := range initialRuns {
|
||||
evalTime := baseTime.Add(duration)
|
||||
group.Eval(context.TODO(), evalTime)
|
||||
}
|
||||
sort.Slice(got, func(i, j int) bool {
|
||||
return labels.Compare(got[i].Labels, got[j].Labels) < 0
|
||||
})
|
||||
|
||||
// In all cases, we expect the restoration process to have completed.
|
||||
require.Truef(t, newRule.Restored(), "expected the rule restoration process to have completed")
|
||||
// Prometheus goes down here. We create new rules and groups.
|
||||
type testInput struct {
|
||||
name string
|
||||
restoreDuration time.Duration
|
||||
expectedAlerts []*Alert
|
||||
|
||||
// Checking if we have restored it correctly.
|
||||
switch {
|
||||
case tt.noRestore:
|
||||
require.Len(t, got, tt.num)
|
||||
for _, e := range got {
|
||||
require.Equal(t, e.ActiveAt, restoreTime)
|
||||
}
|
||||
case tt.gracePeriod:
|
||||
num int
|
||||
noRestore bool
|
||||
gracePeriod bool
|
||||
downDuration time.Duration
|
||||
before func()
|
||||
}
|
||||
|
||||
require.Len(t, got, tt.num)
|
||||
for _, e := range got {
|
||||
require.Equal(t, opts.ForGracePeriod, e.ActiveAt.Add(alertForDuration).Sub(restoreTime))
|
||||
}
|
||||
default:
|
||||
exp := tt.expectedAlerts
|
||||
require.Equal(t, len(exp), len(got))
|
||||
sortAlerts(exp)
|
||||
sortAlerts(got)
|
||||
for i, e := range exp {
|
||||
require.Equal(t, e.Labels, got[i].Labels)
|
||||
tests := []testInput{
|
||||
{
|
||||
name: "normal restore (alerts were not firing)",
|
||||
restoreDuration: 15 * time.Minute,
|
||||
expectedAlerts: rule.ActiveAlerts(),
|
||||
downDuration: 10 * time.Minute,
|
||||
},
|
||||
{
|
||||
name: "outage tolerance",
|
||||
restoreDuration: 40 * time.Minute,
|
||||
noRestore: true,
|
||||
num: 2,
|
||||
},
|
||||
{
|
||||
name: "no active alerts",
|
||||
restoreDuration: 50 * time.Minute,
|
||||
expectedAlerts: []*Alert{},
|
||||
},
|
||||
{
|
||||
name: "test the grace period",
|
||||
restoreDuration: 25 * time.Minute,
|
||||
expectedAlerts: []*Alert{},
|
||||
gracePeriod: true,
|
||||
before: func() {
|
||||
for _, duration := range []time.Duration{10 * time.Minute, 15 * time.Minute, 20 * time.Minute} {
|
||||
evalTime := baseTime.Add(duration)
|
||||
group.Eval(context.TODO(), evalTime)
|
||||
}
|
||||
},
|
||||
num: 2,
|
||||
},
|
||||
}
|
||||
|
||||
// Difference in time should be within 1e6 ns, i.e. 1ms
|
||||
// (due to conversion between ns & ms, float64 & int64).
|
||||
activeAtDiff := float64(e.ActiveAt.Unix() + int64(tt.downDuration/time.Second) - got[i].ActiveAt.Unix())
|
||||
require.Equal(t, 0.0, math.Abs(activeAtDiff), "'for' state restored time is wrong")
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if tt.before != nil {
|
||||
tt.before()
|
||||
}
|
||||
|
||||
newRule := NewAlertingRule(
|
||||
"HTTPRequestRateLow",
|
||||
expr,
|
||||
alertForDuration,
|
||||
0,
|
||||
labels.FromStrings("severity", "critical"),
|
||||
labels.EmptyLabels(), labels.EmptyLabels(), "", false, nil,
|
||||
)
|
||||
newGroup := NewGroup(GroupOptions{
|
||||
Name: "default",
|
||||
Interval: time.Second,
|
||||
Rules: []Rule{newRule},
|
||||
ShouldRestore: true,
|
||||
Opts: opts,
|
||||
QueryOffset: &queryOffset,
|
||||
})
|
||||
|
||||
newGroups := make(map[string]*Group)
|
||||
newGroups["default;"] = newGroup
|
||||
|
||||
restoreTime := baseTime.Add(tt.restoreDuration).Add(queryOffset)
|
||||
// First eval before restoration.
|
||||
newGroup.Eval(context.TODO(), restoreTime)
|
||||
// Restore happens here.
|
||||
newGroup.RestoreForState(restoreTime)
|
||||
|
||||
got := newRule.ActiveAlerts()
|
||||
for _, aa := range got {
|
||||
require.Zero(t, aa.Labels.Get(model.MetricNameLabel), "%s label set on active alert: %s", model.MetricNameLabel, aa.Labels)
|
||||
}
|
||||
sort.Slice(got, func(i, j int) bool {
|
||||
return labels.Compare(got[i].Labels, got[j].Labels) < 0
|
||||
})
|
||||
|
||||
// In all cases, we expect the restoration process to have completed.
|
||||
require.Truef(t, newRule.Restored(), "expected the rule restoration process to have completed")
|
||||
|
||||
// Checking if we have restored it correctly.
|
||||
switch {
|
||||
case tt.noRestore:
|
||||
require.Len(t, got, tt.num)
|
||||
for _, e := range got {
|
||||
require.Equal(t, e.ActiveAt, restoreTime)
|
||||
}
|
||||
case tt.gracePeriod:
|
||||
|
||||
require.Len(t, got, tt.num)
|
||||
for _, e := range got {
|
||||
require.Equal(t, opts.ForGracePeriod, e.ActiveAt.Add(alertForDuration).Sub(restoreTime))
|
||||
}
|
||||
default:
|
||||
exp := tt.expectedAlerts
|
||||
require.Equal(t, len(exp), len(got))
|
||||
sortAlerts(exp)
|
||||
sortAlerts(got)
|
||||
for i, e := range exp {
|
||||
require.Equal(t, e.Labels, got[i].Labels)
|
||||
|
||||
// Difference in time should be within 1e6 ns, i.e. 1ms
|
||||
// (due to conversion between ns & ms, float64 & int64).
|
||||
activeAtDiff := queryOffset.Seconds() + float64(e.ActiveAt.Unix()+int64(tt.downDuration/time.Second)-got[i].ActiveAt.Unix())
|
||||
require.Equal(t, 0.0, math.Abs(activeAtDiff), "'for' state restored time is wrong")
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestStaleness(t *testing.T) {
|
||||
st := teststorage.New(t)
|
||||
defer st.Close()
|
||||
engineOpts := promql.EngineOpts{
|
||||
Logger: nil,
|
||||
Reg: nil,
|
||||
MaxSamples: 10,
|
||||
Timeout: 10 * time.Second,
|
||||
for _, queryOffset := range []time.Duration{0, time.Minute} {
|
||||
st := teststorage.New(t)
|
||||
defer st.Close()
|
||||
engineOpts := promql.EngineOpts{
|
||||
Logger: nil,
|
||||
Reg: nil,
|
||||
MaxSamples: 10,
|
||||
Timeout: 10 * time.Second,
|
||||
}
|
||||
engine := promql.NewEngine(engineOpts)
|
||||
opts := &ManagerOptions{
|
||||
QueryFunc: EngineQueryFunc(engine, st),
|
||||
Appendable: st,
|
||||
Queryable: st,
|
||||
Context: context.Background(),
|
||||
Logger: log.NewNopLogger(),
|
||||
}
|
||||
|
||||
expr, err := parser.ParseExpr("a + 1")
|
||||
require.NoError(t, err)
|
||||
rule := NewRecordingRule("a_plus_one", expr, labels.Labels{})
|
||||
group := NewGroup(GroupOptions{
|
||||
Name: "default",
|
||||
Interval: time.Second,
|
||||
Rules: []Rule{rule},
|
||||
ShouldRestore: true,
|
||||
Opts: opts,
|
||||
QueryOffset: &queryOffset,
|
||||
})
|
||||
|
||||
// A time series that has two samples and then goes stale.
|
||||
app := st.Appender(context.Background())
|
||||
app.Append(0, labels.FromStrings(model.MetricNameLabel, "a"), 0, 1)
|
||||
app.Append(0, labels.FromStrings(model.MetricNameLabel, "a"), 1000, 2)
|
||||
app.Append(0, labels.FromStrings(model.MetricNameLabel, "a"), 2000, math.Float64frombits(value.StaleNaN))
|
||||
|
||||
err = app.Commit()
|
||||
require.NoError(t, err)
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
// Execute 3 times, 1 second apart.
|
||||
group.Eval(ctx, time.Unix(0, 0).Add(queryOffset))
|
||||
group.Eval(ctx, time.Unix(1, 0).Add(queryOffset))
|
||||
group.Eval(ctx, time.Unix(2, 0).Add(queryOffset))
|
||||
|
||||
querier, err := st.Querier(0, 2000)
|
||||
require.NoError(t, err)
|
||||
defer querier.Close()
|
||||
|
||||
matcher, err := labels.NewMatcher(labels.MatchEqual, model.MetricNameLabel, "a_plus_one")
|
||||
require.NoError(t, err)
|
||||
|
||||
set := querier.Select(ctx, false, nil, matcher)
|
||||
samples, err := readSeriesSet(set)
|
||||
require.NoError(t, err)
|
||||
|
||||
metric := labels.FromStrings(model.MetricNameLabel, "a_plus_one").String()
|
||||
metricSample, ok := samples[metric]
|
||||
|
||||
require.True(t, ok, "Series %s not returned.", metric)
|
||||
require.True(t, value.IsStaleNaN(metricSample[2].F), "Appended second sample not as expected. Wanted: stale NaN Got: %x", math.Float64bits(metricSample[2].F))
|
||||
metricSample[2].F = 42 // require.Equal cannot handle NaN.
|
||||
|
||||
want := map[string][]promql.FPoint{
|
||||
metric: {{T: 0, F: 2}, {T: 1000, F: 3}, {T: 2000, F: 42}},
|
||||
}
|
||||
|
||||
require.Equal(t, want, samples)
|
||||
}
|
||||
engine := promql.NewEngine(engineOpts)
|
||||
opts := &ManagerOptions{
|
||||
QueryFunc: EngineQueryFunc(engine, st),
|
||||
Appendable: st,
|
||||
Queryable: st,
|
||||
Context: context.Background(),
|
||||
Logger: log.NewNopLogger(),
|
||||
}
|
||||
|
||||
expr, err := parser.ParseExpr("a + 1")
|
||||
require.NoError(t, err)
|
||||
rule := NewRecordingRule("a_plus_one", expr, labels.Labels{})
|
||||
group := NewGroup(GroupOptions{
|
||||
Name: "default",
|
||||
Interval: time.Second,
|
||||
Rules: []Rule{rule},
|
||||
ShouldRestore: true,
|
||||
Opts: opts,
|
||||
})
|
||||
|
||||
// A time series that has two samples and then goes stale.
|
||||
app := st.Appender(context.Background())
|
||||
app.Append(0, labels.FromStrings(model.MetricNameLabel, "a"), 0, 1)
|
||||
app.Append(0, labels.FromStrings(model.MetricNameLabel, "a"), 1000, 2)
|
||||
app.Append(0, labels.FromStrings(model.MetricNameLabel, "a"), 2000, math.Float64frombits(value.StaleNaN))
|
||||
|
||||
err = app.Commit()
|
||||
require.NoError(t, err)
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
// Execute 3 times, 1 second apart.
|
||||
group.Eval(ctx, time.Unix(0, 0))
|
||||
group.Eval(ctx, time.Unix(1, 0))
|
||||
group.Eval(ctx, time.Unix(2, 0))
|
||||
|
||||
querier, err := st.Querier(0, 2000)
|
||||
require.NoError(t, err)
|
||||
defer querier.Close()
|
||||
|
||||
matcher, err := labels.NewMatcher(labels.MatchEqual, model.MetricNameLabel, "a_plus_one")
|
||||
require.NoError(t, err)
|
||||
|
||||
set := querier.Select(ctx, false, nil, matcher)
|
||||
samples, err := readSeriesSet(set)
|
||||
require.NoError(t, err)
|
||||
|
||||
metric := labels.FromStrings(model.MetricNameLabel, "a_plus_one").String()
|
||||
metricSample, ok := samples[metric]
|
||||
|
||||
require.True(t, ok, "Series %s not returned.", metric)
|
||||
require.True(t, value.IsStaleNaN(metricSample[2].F), "Appended second sample not as expected. Wanted: stale NaN Got: %x", math.Float64bits(metricSample[2].F))
|
||||
metricSample[2].F = 42 // require.Equal cannot handle NaN.
|
||||
|
||||
want := map[string][]promql.FPoint{
|
||||
metric: {{T: 0, F: 2}, {T: 1000, F: 3}, {T: 2000, F: 42}},
|
||||
}
|
||||
|
||||
require.Equal(t, want, samples)
|
||||
}
|
||||
|
||||
// Convert a SeriesSet into a form usable with require.Equal.
|
||||
|
@ -608,6 +623,46 @@ func readSeriesSet(ss storage.SeriesSet) (map[string][]promql.FPoint, error) {
|
|||
return result, ss.Err()
|
||||
}
|
||||
|
||||
func TestGroup_QueryOffset(t *testing.T) {
|
||||
config := `
|
||||
groups:
|
||||
- name: group1
|
||||
query_offset: 2m
|
||||
- name: group2
|
||||
query_offset: 0s
|
||||
- name: group3
|
||||
`
|
||||
|
||||
dir := t.TempDir()
|
||||
fname := path.Join(dir, "rules.yaml")
|
||||
err := os.WriteFile(fname, []byte(config), fs.ModePerm)
|
||||
require.NoError(t, err)
|
||||
|
||||
m := NewManager(&ManagerOptions{
|
||||
Logger: log.NewNopLogger(),
|
||||
DefaultRuleQueryOffset: func() time.Duration {
|
||||
return time.Minute
|
||||
},
|
||||
})
|
||||
m.start()
|
||||
err = m.Update(time.Second, []string{fname}, labels.EmptyLabels(), "", nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
rgs := m.RuleGroups()
|
||||
sort.Slice(rgs, func(i, j int) bool {
|
||||
return rgs[i].Name() < rgs[j].Name()
|
||||
})
|
||||
|
||||
// From config.
|
||||
require.Equal(t, 2*time.Minute, rgs[0].QueryOffset())
|
||||
// Setting 0 in config is detected.
|
||||
require.Equal(t, time.Duration(0), rgs[1].QueryOffset())
|
||||
// Default when nothing is set.
|
||||
require.Equal(t, time.Minute, rgs[2].QueryOffset())
|
||||
|
||||
m.Stop()
|
||||
}
|
||||
|
||||
func TestCopyState(t *testing.T) {
|
||||
oldGroup := &Group{
|
||||
rules: []Rule{
|
||||
|
@ -1361,7 +1416,7 @@ func TestNativeHistogramsInRecordingRules(t *testing.T) {
|
|||
ts := time.Now()
|
||||
app := db.Appender(context.Background())
|
||||
for i, h := range hists {
|
||||
l := labels.FromStrings("__name__", "histogram_metric", "idx", fmt.Sprintf("%d", i))
|
||||
l := labels.FromStrings("__name__", "histogram_metric", "idx", strconv.Itoa(i))
|
||||
_, err := app.AppendHistogram(0, l, ts.UnixMilli(), h.Copy(), nil)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
@ -2044,7 +2099,7 @@ func TestBoundedRuleEvalConcurrency(t *testing.T) {
|
|||
require.EqualValues(t, maxInflight.Load(), int32(maxConcurrency)+int32(groupCount))
|
||||
}
|
||||
|
||||
const artificialDelay = 10 * time.Millisecond
|
||||
const artificialDelay = 15 * time.Millisecond
|
||||
|
||||
func optsFactory(storage storage.Storage, maxInflight, inflightQueries *atomic.Int32, maxConcurrent int64) *ManagerOptions {
|
||||
var inflightMu sync.Mutex
|
||||
|
|
|
@ -31,7 +31,7 @@ type unknownRule struct{}
|
|||
|
||||
func (u unknownRule) Name() string { return "" }
|
||||
func (u unknownRule) Labels() labels.Labels { return labels.EmptyLabels() }
|
||||
func (u unknownRule) Eval(context.Context, time.Time, QueryFunc, *url.URL, int) (promql.Vector, error) {
|
||||
func (u unknownRule) Eval(context.Context, time.Duration, time.Time, QueryFunc, *url.URL, int) (promql.Vector, error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (u unknownRule) String() string { return "" }
|
||||
|
|
|
@ -77,10 +77,9 @@ func (rule *RecordingRule) Labels() labels.Labels {
|
|||
}
|
||||
|
||||
// Eval evaluates the rule and then overrides the metric names and labels accordingly.
|
||||
func (rule *RecordingRule) Eval(ctx context.Context, ts time.Time, query QueryFunc, _ *url.URL, limit int) (promql.Vector, error) {
|
||||
func (rule *RecordingRule) Eval(ctx context.Context, queryOffset time.Duration, ts time.Time, query QueryFunc, _ *url.URL, limit int) (promql.Vector, error) {
|
||||
ctx = NewOriginContext(ctx, NewRuleDetail(rule))
|
||||
|
||||
vector, err := query(ctx, rule.vector.String(), ts)
|
||||
vector, err := query(ctx, rule.vector.String(), ts.Add(-queryOffset))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue