diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 1ba1f3b..e82631a 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,15 +1,19 @@ -# To get started with Dependabot version updates, you'll need to specify which -# package ecosystems to update and where the package manifests are located. -# Please see the documentation for all configuration options: -# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates - version: 2 + updates: - - package-ecosystem: "github-actions" - directory: "/" + - package-ecosystem: github-actions + directory: '/' schedule: - interval: "weekly" - - package-ecosystem: "gomod" - directory: "/" + interval: weekly + + - package-ecosystem: gomod + directory: '/' schedule: - interval: "weekly" + interval: weekly + groups: + gomod-security: + applies-to: security-updates + patterns: ['*'] + gomod-update: + applies-to: version-updates + patterns: ['*'] diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml new file mode 100644 index 0000000..7cff415 --- /dev/null +++ b/.github/workflows/pr.yml @@ -0,0 +1,38 @@ +name: PR check + +on: + push: + branches: [ main ] + pull_request: + merge_group: + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-go@v5 + with: + go-version-file: 'go.mod' + + - uses: gotesttools/gotestfmt-action@v2 + with: + token: ${{ secrets.GITHUB_TOKEN }} + + - uses: golangci/golangci-lint-action@v6 + with: + version: latest + + - name: Run tests + run: make test + + - uses: coverallsapp/github-action@v2 + with: + file: coverage.out + diff --git a/.github/workflows/pull-requests.yml b/.github/workflows/pull-requests.yml deleted file mode 100644 index af48aa2..0000000 --- a/.github/workflows/pull-requests.yml +++ /dev/null @@ -1,44 +0,0 @@ -name: Pull Requests - -on: - # Triggers the workflow on push or pull request events but only for the main branch - push: - branches: [ main ] - pull_request: - branches: [ main ] - # Allows you to run this workflow manually from the Actions tab - workflow_dispatch: - -concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} - cancel-in-progress: true - -env: - GOFLAGS: -mod=readonly - GOPROXY: https://proxy.golang.org - -jobs: - lint: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-go@v3 - with: - cache: true - check-latest: true - go-version-file: 'go.mod' - - uses: golangci/golangci-lint-action@v3 - - uses: golangci/golangci-lint-action@v3 - with: - working-directory: example - test: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-go@v3 - with: - cache: true - check-latest: true - go-version-file: 'go.mod' - - run: go test -v ./... - diff --git a/.github/workflows/releases.yml b/.github/workflows/releases.yml deleted file mode 100644 index 9f72302..0000000 --- a/.github/workflows/releases.yml +++ /dev/null @@ -1,31 +0,0 @@ -name: Releases - -on: - push: - tags: - - v*.*.* - workflow_dispatch: - -env: - GOFLAGS: -mod=readonly - GOPROXY: https://proxy.golang.org - -jobs: - release: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - run: git fetch --force --tags - - uses: actions/setup-go@v3 - with: - cache: true - check-latest: true - go-version-file: 'go.mod' - - uses: goreleaser/goreleaser-action@v4 - with: - version: latest - args: release --clean - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/tag.yml b/.github/workflows/tag.yml new file mode 100644 index 0000000..8457a33 --- /dev/null +++ b/.github/workflows/tag.yml @@ -0,0 +1,30 @@ +name: Release Tag + +on: + push: + tags: + - v*.*.* + workflow_dispatch: + +permissions: + contents: write + +jobs: + release: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Unshallow + run: git fetch --prune --unshallow + + - uses: actions/setup-go@v5 + with: + go-version-file: go.mod + + - uses: goreleaser/goreleaser-action@v6 + with: + version: latest + args: release --clean + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitignore b/.gitignore index b1e259c..5c03997 100644 --- a/.gitignore +++ b/.gitignore @@ -1,64 +1,11 @@ -# Created by https://www.toptal.com/developers/gitignore/api/jetbrains,go,visualstudiocode,macos -# Edit at https://www.toptal.com/developers/gitignore?templates=jetbrains,go,visualstudiocode,macos - -### macOS ### -# General -.DS_Store -.AppleDouble -.LSOverride - -# Icon must end with two \r -Icon - -# Thumbnails -._* - -# Files that might appear in the root of a volume -.DocumentRevisions-V100 -.fseventsd -.Spotlight-V100 -.TemporaryItems -.Trashes -.VolumeIcon.icns -.com.apple.timemachine.donotpresent - -# Directories potentially created on remote AFP share -.AppleDB -.AppleDesktop -Network Trash Folder -Temporary Items -.apdisk - -### Go ### -# Binaries for programs and plugins -*.exe -*.exe~ -*.dll -*.so -*.dylib - -# Test binary, built with `go test -c` -*.test - -# Output of the go coverage tool, specifically when used with LiteIDE +.* +*.log *.out - -# Dependency directories (remove the comment below to include it) -# vendor/ - -### Go Patch ### -/vendor/ -/Godeps/ - -### JetBrains ### -# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider -# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 -.idea/ - -### VisualStudioCode ### -.vscode/ - -# End of https://www.toptal.com/developers/gitignore/api/jetbrains,go,visualstudiocode,macos - +!.github/ +!.husky/ +!.editorconfig +!.gitignore +!.golangci.yml +!.goreleaser.yml +!.husky.yaml /tmp/ -*.log diff --git a/.golangci.yml b/.golangci.yml index 2aecc72..661ecec 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,132 +1,228 @@ run: - go: "1.19" - timeout: 3m - skip-dirs: - - tmp + timeout: 5m + +issues: + exclude-dirs: + - 'bin' + - 'tmp' + - 'vendor' + exclude-rules: + - path: _test\.go + linters: + - forcetypeassert + - gocheckcompilerdirectives linters-settings: - gci: - sections: - - prefix(github.com/foomo/keel) - revive: - rules: - - name: indent-error-flow - disabled: true + # https://golangci-lint.run/usage/linters/#misspell + misspell: + mode: restricted + # https://golangci-lint.run/usage/linters/#asasalint + asasalint: + ignore-test: true + # https://golangci-lint.run/usage/linters/#exhaustive + exhaustive: + default-signifies-exhaustive: true + # https://golangci-lint.run/usage/linters/#gocritic gocritic: - enabled-tags: - - diagnostic - - performance - - style - disabled-tags: - - experimental - - opinionated disabled-checks: + - assignOp - ifElseChain - settings: - hugeParam: - sizeThreshold: 512 + # https://golangci-lint.run/usage/linters/#testifylint + testifylint: + disable: + - float-compare # https://golangci-lint.run/usage/linters/#gosec gosec: - config: - G306: "0700" - excludes: - - G101 # Potential hardcoded credentials - - G102 # Bind to all interfaces - - G112 # Potential slowloris attack - - G401 # Detect the usage of DES, RC4, MD5 or SHA1 - - G402 # Look for bad TLS connection settings - - G404 # Insecure random number source (rand) - - G501 # Import blocklist: crypto/md5 - - G505 # Import blocklist: crypto/sha1 + confidence: medium + # https://golangci-lint.run/usage/linters/#revive + revive: + enable-all-rules: true + ignore-generated-header: true + rules: + - name: line-length-limit + disabled: true + #- name: if-return + # disabled: true + #- name: bare-return + # disabled: true + - name: cognitive-complexity + disabled: true + - name: unused-parameter + disabled: true + - name: add-constant + disabled: true + - name: indent-error-flow + disabled: true + - name: cyclomatic + disabled: true + - name: function-length + disabled: true + - name: early-return + disabled: true + #- name: nested-structs + # disabled: true + #- name: var-naming + # disabled: true + - name: use-any + disabled: true + - name: max-public-structs + disabled: true + #- name: function-result-limit + # disabled: true + - name: flag-parameter + disabled: true + - name: unused-receiver + disabled: true + #- name: argument-limit + # disabled: true + #- name: empty-lines + # disabled: true + - name: confusing-naming + disabled: true + #- name: import-alias-naming + # disabled: true + - name: empty-block + disabled: true + #- name: import-shadowing + # disabled: true + - name: unhandled-error + arguments: + - "fmt.Printf" + - "fmt.Println" + #- name: max-control-nesting + # disabled: true + - name: exported + disabled: true + #- name: unchecked-type-assertion + # disabled: true + #- name: unnecessary-stmt + # disabled: true + #- name: get-return + # disabled: true + #- name: context-keys-type + # disabled: true + #- name: comment-spacings + # disabled: true + #- name: struct-tag + # disabled: true + #- name: confusing-results + # disabled: true + - name: superfluous-else + disabled: true + - name: unexported-return + disabled: true + #- name: error-return + # disabled: true + #- name: redefines-builtin-id + # disabled: true linters: + disable-all: true enable: # Enabled by default linters: - - errcheck # Errcheck is a program for checking for unchecked errors in go programs. These unchecked errors can be critical bugs in some cases [fast: false, auto-fix: false] - - gosimple # (megacheck): Linter for Go source code that specializes in simplifying code [fast: false, auto-fix: false] - - govet # (vet, vetshadow): Vet examines Go source code and reports suspicious constructs, such as Printf calls whose arguments do not align with the format string [fast: false, auto-fix: false] + - errcheck # errcheck is a program for checking for unchecked errors in Go code. These unchecked errors can be critical bugs in some cases [fast: false, auto-fix: false] + - gosimple # (megacheck) Linter for Go source code that specializes in simplifying code [fast: false, auto-fix: false] + - govet # (vet, vetshadow) Vet examines Go source code and reports suspicious constructs. It is roughly the same as 'go vet' and uses its passes. [fast: false, auto-fix: false] - ineffassign # Detects when assignments to existing variables are not used [fast: true, auto-fix: false] - - staticcheck # (megacheck): It's a set of rules from staticcheck. It's not the same thing as the staticcheck binary. The author of staticcheck doesn't support or approve the use of staticcheck as a library inside golangci-lint. [fast: false, auto-fix: false] - - typecheck # Like the front-end of a Go compiler, parses and type-checks Go code [fast: false, auto-fix: false] - - unused # (megacheck): Checks Go code for unused constants, variables, functions and types [fast: false, auto-fix: false] + - staticcheck # (megacheck) It's a set of rules from staticcheck. It's not the same thing as the staticcheck binary. The author of staticcheck doesn't support or approve the use of staticcheck as a library inside golangci-lint. [fast: false, auto-fix: false] + - unused # (megacheck) Checks Go code for unused constants, variables, functions and types [fast: false, auto-fix: false] - # Disabled by default linters: + # Disabled by your configuration linters: - asasalint # check for pass []any as any in variadic func(...any) [fast: false, auto-fix: false] - - asciicheck # Simple linter to check that your code does not contain non-ASCII identifiers [fast: true, auto-fix: false] + - asciicheck # checks that all code identifiers does not have non-ASCII symbols in the name [fast: true, auto-fix: false] - bidichk # Checks for dangerous unicode character sequences [fast: true, auto-fix: false] - bodyclose # checks whether HTTP response body is closed successfully [fast: false, auto-fix: false] - #- containedctx # containedctx is a linter that detects struct contained context.Context field [fast: true, auto-fix: false] - #- contextcheck # check the function whether to use a non-inherited context [fast: false, auto-fix: false] + #- containedctx # containedctx is a linter that detects struct contained context.Context field [fast: false, auto-fix: false] + - contextcheck # check whether the function uses a non-inherited context [fast: false, auto-fix: false] + #- copyloopvar # (go >= 1.22) copyloopvar is a linter detects places where loop variables are copied [fast: true, auto-fix: false] #- cyclop # checks function and package cyclomatic complexity [fast: false, auto-fix: false] - decorder # check declaration order and count of types, constants, variables and functions [fast: true, auto-fix: false] - - depguard # Go linter that checks if package imports are in a list of acceptable packages [fast: true, auto-fix: false] - - dogsled # Checks assignments with too many blank identifiers (e.g. x, _, _, _, := f()) [fast: true, auto-fix: false] + #- depguard # Go linter that checks if package imports are in a list of acceptable packages [fast: true, auto-fix: false] + #- dogsled # Checks assignments with too many blank identifiers (e.g. x, _, _, _, := f()) [fast: true, auto-fix: false] #- dupl # Tool for code clone detection [fast: true, auto-fix: false] + #- dupword # checks for duplicate words in the source code [fast: true, auto-fix: false] - durationcheck # check for two durations multiplied together [fast: false, auto-fix: false] - - errchkjson # Checks types passed to the json encoding functions. Reports unsupported types and optionally reports occasions, where the check for the returned error can be omitted. [fast: false, auto-fix: false] + - errchkjson # Checks types passed to the json encoding functions. Reports unsupported types and reports occations, where the check for the returned error can be omitted. [fast: false, auto-fix: false] - errname # Checks that sentinel errors are prefixed with the `Err` and error types are suffixed with the `Error`. [fast: false, auto-fix: false] - errorlint # errorlint is a linter for that can be used to find code that will cause problems with the error wrapping scheme introduced in Go 1.13. [fast: false, auto-fix: false] - - execinquery # execinquery is a linter about query string checker in Query function which reads your Go src files and warning it finds [fast: false, auto-fix: false] - exhaustive # check exhaustiveness of enum switch statements [fast: false, auto-fix: false] #- exhaustruct # Checks if all structure fields are initialized [fast: false, auto-fix: false] - exportloopref # checks for pointers to enclosing loop variables [fast: false, auto-fix: false] - - forbidigo # Forbids identifiers [fast: true, auto-fix: false] + #- forbidigo # Forbids identifiers [fast: false, auto-fix: false] - forcetypeassert # finds forced type assertions [fast: true, auto-fix: false] #- funlen # Tool for detection of long functions [fast: true, auto-fix: false] - #- gci # Gci controls golang package import order and makes it always deterministic. [fast: true, auto-fix: false] - #- gochecknoglobals # check that no global variables exist [fast: true, auto-fix: false] + #- gci # Gci controls Go package import order and makes it always deterministic. [fast: true, auto-fix: true] + #- ginkgolinter # enforces standards of using ginkgo and gomega [fast: false, auto-fix: false] + - gocheckcompilerdirectives # Checks that go compiler directive comments (//go:) are valid. [fast: true, auto-fix: false] + #- gochecknoglobals # Check that no global variables exist. [fast: false, auto-fix: false] #- gochecknoinits # Checks that no init functions are present in Go code [fast: true, auto-fix: false] + - gochecksumtype # Run exhaustiveness checks on Go "sum types" [fast: false, auto-fix: false] #- gocognit # Computes and checks the cognitive complexity of functions [fast: true, auto-fix: false] - - goconst # Finds repeated strings that could be replaced by a constant [fast: true, auto-fix: false] - - gocritic # Provides diagnostics that check for bugs, performance and style issues. [fast: false, auto-fix: false] + #- goconst # Finds repeated strings that could be replaced by a constant [fast: true, auto-fix: false] + - gocritic # Provides diagnostics that check for bugs, performance and style issues. [fast: false, auto-fix: true] #- gocyclo # Computes and checks the cyclomatic complexity of functions [fast: true, auto-fix: false] #- godot # Check if comments end in a period [fast: true, auto-fix: true] #- godox # Tool for detection of FIXME, TODO and other comment keywords [fast: true, auto-fix: false] - # - goerr113 # Golang linter to check the errors handling expressions [fast: false, auto-fix: false] + #- goerr113 # Go linter to check the errors handling expressions [fast: false, auto-fix: false] - gofmt # Gofmt checks whether code was gofmt-ed. By default this tool runs with -s option to check for code simplification [fast: true, auto-fix: true] #- gofumpt # Gofumpt checks whether code was gofumpt-ed. [fast: true, auto-fix: true] - - goheader # Checks is file header matches to pattern [fast: true, auto-fix: false] - - goimports # In addition to fixing imports, goimports also formats your code in the same style as gofmt. [fast: true, auto-fix: true] + - goheader # Checks is file header matches to pattern [fast: true, auto-fix: true] + - goimports # Check import statements are formatted according to the 'goimport' command. Reformat imports in autofix mode. [fast: true, auto-fix: true] #- gomnd # An analyzer to detect magic numbers. [fast: true, auto-fix: false] - #- gomoddirectives # Manage the use of 'replace', 'retract', and 'excludes' directives in go.mod. [fast: true, auto-fix: false] + - gomoddirectives # Manage the use of 'replace', 'retract', and 'excludes' directives in go.mod. [fast: true, auto-fix: false] - gomodguard # Allow and block list linter for direct Go module dependencies. This is different from depguard where there are different block types for example version constraints and module recommendations. [fast: true, auto-fix: false] - - goprintffuncname # Checks that printf-like functions are named with `f` at the end [fast: true, auto-fix: false] - - gosec # (gas): Inspects source code for security problems [fast: false, auto-fix: false] - - grouper # An analyzer to analyze expression groups. [fast: true, auto-fix: false] + - goprintffuncname # Checks that printf-like functions are named with `f` at the end. [fast: true, auto-fix: false] + - gosec # (gas) Inspects source code for security problems [fast: false, auto-fix: false] + #- gosmopolitan # Report certain i18n/l10n anti-patterns in your Go codebase [fast: false, auto-fix: false] + - grouper # Analyze expression groups. [fast: true, auto-fix: false] - importas # Enforces consistent import aliases [fast: false, auto-fix: false] + #- inamedparam # reports interfaces with unnamed method parameters [fast: true, auto-fix: false] + #- interfacebloat # A linter that checks the number of methods inside an interface. [fast: true, auto-fix: false] + #- intrange # (go >= 1.22) intrange is a linter to find places where for loops could make use of an integer range. [fast: true, auto-fix: false] #- ireturn # Accept Interfaces, Return Concrete Types [fast: false, auto-fix: false] #- lll # Reports long lines [fast: true, auto-fix: false] - - maintidx # maintidx measures the maintainability index of each function. [fast: true, auto-fix: false] + #- loggercheck # (logrlint) Checks key value pairs for common logger libraries (kitlog,klog,logr,zap). [fast: false, auto-fix: false] + #- maintidx # maintidx measures the maintainability index of each function. [fast: true, auto-fix: false] - makezero # Finds slice declarations with non-zero initial length [fast: false, auto-fix: false] - - misspell # Finds commonly misspelled English words in comments [fast: true, auto-fix: true] - - nakedret # Finds naked returns in functions greater than a specified function length [fast: true, auto-fix: false] + - misspell # Finds commonly misspelled English words [fast: true, auto-fix: true] + - mirror # reports wrong mirror patterns of bytes/strings usage [fast: false, auto-fix: true] + - musttag # enforce field tags in (un)marshaled structs [fast: false, auto-fix: false] + #- nakedret # Checks that functions with naked returns are not longer than a maximum size (can be zero). [fast: true, auto-fix: false] #- nestif # Reports deeply nested if statements [fast: true, auto-fix: false] - nilerr # Finds the code that returns nil even if it checks that the error is not nil. [fast: false, auto-fix: false] - nilnil # Checks that there is no simultaneous return of `nil` error and an invalid value. [fast: false, auto-fix: false] #- nlreturn # nlreturn checks for a new line before return and branch statements to increase code clarity [fast: true, auto-fix: false] - - noctx # noctx finds sending http request without context.Context [fast: false, auto-fix: false] - - nolintlint # Reports ill-formed or insufficient nolint directives [fast: true, auto-fix: false] + - noctx # Finds sending http request without context.Context [fast: false, auto-fix: false] + - nolintlint # Reports ill-formed or insufficient nolint directives [fast: true, auto-fix: true] - nonamedreturns # Reports all named returns [fast: false, auto-fix: false] - nosprintfhostport # Checks for misuse of Sprintf to construct a host with port in a URL. [fast: true, auto-fix: false] - #- paralleltest # paralleltest detects missing usage of t.Parallel() method in your Go test [fast: false, auto-fix: false] + #- paralleltest # Detects missing usage of t.Parallel() method in your Go test [fast: false, auto-fix: false] + #- perfsprint # Checks that fmt.Sprintf can be replaced with a faster alternative. [fast: false, auto-fix: false] - prealloc # Finds slice declarations that could potentially be pre-allocated [fast: true, auto-fix: false] - predeclared # find code that shadows one of Go's predeclared identifiers [fast: true, auto-fix: false] - promlinter # Check Prometheus metrics naming via promlint [fast: true, auto-fix: false] + #- protogetter # Reports direct reads from proto message fields when getters should be used [fast: false, auto-fix: true] + - reassign # Checks that package variables are not reassigned [fast: false, auto-fix: false] - revive # Fast, configurable, extensible, flexible, and beautiful linter for Go. Drop-in replacement of golint. [fast: false, auto-fix: false] - - rowserrcheck # checks whether Err of rows is checked successfully [fast: false, auto-fix: false] - - sqlclosecheck # Checks that sql.Rows and sql.Stmt are closed. [fast: false, auto-fix: false] + #- rowserrcheck # checks whether Rows.Err of rows is checked successfully [fast: false, auto-fix: false] + #- sloglint # ensure consistent code style when using log/slog [fast: false, auto-fix: false] + #- spancheck # Checks for mistakes with OpenTelemetry/Census spans. [fast: false, auto-fix: false] + #- sqlclosecheck # Checks that sql.Rows, sql.Stmt, sqlx.NamedStmt, pgx.Query are closed. [fast: false, auto-fix: false] - stylecheck # Stylecheck is a replacement for golint [fast: false, auto-fix: false] + #- tagalign # check that struct tags are well aligned [fast: true, auto-fix: true] - tagliatelle # Checks the struct tags. [fast: true, auto-fix: false] - tenv # tenv is analyzer that detects using os.Setenv instead of t.Setenv since Go1.17 [fast: false, auto-fix: false] + - testableexamples # linter checks if examples are testable (have an expected output) [fast: true, auto-fix: false] + - testifylint # Checks usage of github.com/stretchr/testify. [fast: false, auto-fix: false] - testpackage # linter that makes you use a separate _test package [fast: true, auto-fix: false] - - thelper # thelper detects golang test helpers without t.Helper() call and checks the consistency of test helpers [fast: false, auto-fix: false] - - tparallel # tparallel detects inappropriate usage of t.Parallel() method in your Go test codes [fast: false, auto-fix: false] + - thelper # thelper detects tests helpers which is not start with t.Helper() method. [fast: false, auto-fix: false] + #- tparallel # tparallel detects inappropriate usage of t.Parallel() method in your Go test codes. [fast: false, auto-fix: false] - unconvert # Remove unnecessary type conversions [fast: false, auto-fix: false] - - unparam # Reports unused function parameters [fast: false, auto-fix: false] + #- unparam # Reports unused function parameters [fast: false, auto-fix: false] - usestdlibvars # A linter that detect the possibility to use variables/constants from the Go standard library. [fast: true, auto-fix: false] #- varnamelen # checks that the length of a variable's name matches its scope [fast: false, auto-fix: false] - - wastedassign # wastedassign finds wasted assignment statements. [fast: false, auto-fix: false] - - whitespace # Tool for detection of leading and trailing whitespace [fast: true, auto-fix: true] + - wastedassign # Finds wasted assignment statements [fast: false, auto-fix: false] + - whitespace # Whitespace is a linter that checks for unnecessary newlines at the start and end of functions, if, for, etc. [fast: true, auto-fix: true] #- wrapcheck # Checks that errors returned from external packages are wrapped [fast: false, auto-fix: false] - #- wsl # Whitespace Linter - Forces you to use empty lines! [fast: true, auto-fix: false] - + #- wsl # add or remove empty lines [fast: true, auto-fix: false] + #- zerologlint # Detects the wrong usage of `zerolog` that a user forgets to dispatch with `Send` or `Msg` [fast: false, auto-fix: false] diff --git a/.goreleaser.yml b/.goreleaser.yml index 2bb7412..6282460 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -1,2 +1,22 @@ +project_name: keel + +release: + github: + owner: foomo + name: keel + prerelease: auto + builds: - skip: true + +archives: + - format: tar.gz + format_overrides: + - goos: windows + format: zip + files: + - LICENSE + - README.md + +changelog: + use: github-native diff --git a/.husky.yaml b/.husky.yaml index fb2448e..2bbd935 100644 --- a/.husky.yaml +++ b/.husky.yaml @@ -9,9 +9,7 @@ hooks: lint-staged: '*.go': - goimports -l -w - - gofmt -l -w lint-commit: - email: '^(.+@bestbytes.com)$' types: '^(feat|fix|build|chore|docs|perf|refactor|revert|style|test|wip)$' header: '^(?P\w+)(\((?P[\w/.-]+)\))?(?P!)?:( +)?(?P
.+)' diff --git a/.husky/applypatch-msg b/.husky/applypatch-msg new file mode 100755 index 0000000..32d0649 --- /dev/null +++ b/.husky/applypatch-msg @@ -0,0 +1,3 @@ +#!/bin/sh + +husky hook $(basename "$0") $* diff --git a/.husky/commit-msg b/.husky/commit-msg new file mode 100755 index 0000000..32d0649 --- /dev/null +++ b/.husky/commit-msg @@ -0,0 +1,3 @@ +#!/bin/sh + +husky hook $(basename "$0") $* diff --git a/.husky/fsmonitor-watchman b/.husky/fsmonitor-watchman new file mode 100755 index 0000000..32d0649 --- /dev/null +++ b/.husky/fsmonitor-watchman @@ -0,0 +1,3 @@ +#!/bin/sh + +husky hook $(basename "$0") $* diff --git a/.husky/post-update b/.husky/post-update new file mode 100755 index 0000000..32d0649 --- /dev/null +++ b/.husky/post-update @@ -0,0 +1,3 @@ +#!/bin/sh + +husky hook $(basename "$0") $* diff --git a/.husky/pre-applypatch b/.husky/pre-applypatch new file mode 100755 index 0000000..32d0649 --- /dev/null +++ b/.husky/pre-applypatch @@ -0,0 +1,3 @@ +#!/bin/sh + +husky hook $(basename "$0") $* diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100755 index 0000000..32d0649 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1,3 @@ +#!/bin/sh + +husky hook $(basename "$0") $* diff --git a/.husky/pre-merge-commit b/.husky/pre-merge-commit new file mode 100755 index 0000000..32d0649 --- /dev/null +++ b/.husky/pre-merge-commit @@ -0,0 +1,3 @@ +#!/bin/sh + +husky hook $(basename "$0") $* diff --git a/.husky/pre-push b/.husky/pre-push new file mode 100755 index 0000000..32d0649 --- /dev/null +++ b/.husky/pre-push @@ -0,0 +1,3 @@ +#!/bin/sh + +husky hook $(basename "$0") $* diff --git a/.husky/pre-rebase b/.husky/pre-rebase new file mode 100755 index 0000000..32d0649 --- /dev/null +++ b/.husky/pre-rebase @@ -0,0 +1,3 @@ +#!/bin/sh + +husky hook $(basename "$0") $* diff --git a/.husky/pre-receive b/.husky/pre-receive new file mode 100755 index 0000000..32d0649 --- /dev/null +++ b/.husky/pre-receive @@ -0,0 +1,3 @@ +#!/bin/sh + +husky hook $(basename "$0") $* diff --git a/.husky/prepare-commit-msg b/.husky/prepare-commit-msg new file mode 100755 index 0000000..32d0649 --- /dev/null +++ b/.husky/prepare-commit-msg @@ -0,0 +1,3 @@ +#!/bin/sh + +husky hook $(basename "$0") $* diff --git a/.husky/push-to-checkout b/.husky/push-to-checkout new file mode 100755 index 0000000..32d0649 --- /dev/null +++ b/.husky/push-to-checkout @@ -0,0 +1,3 @@ +#!/bin/sh + +husky hook $(basename "$0") $* diff --git a/.husky/sendemail-validate b/.husky/sendemail-validate new file mode 100755 index 0000000..32d0649 --- /dev/null +++ b/.husky/sendemail-validate @@ -0,0 +1,3 @@ +#!/bin/sh + +husky hook $(basename "$0") $* diff --git a/.husky/update b/.husky/update new file mode 100755 index 0000000..32d0649 --- /dev/null +++ b/.husky/update @@ -0,0 +1,3 @@ +#!/bin/sh + +husky hook $(basename "$0") $* diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..34aabf4 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,128 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, religion, or sexual identity +and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our +community include: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +* Focusing on what is best not just for us as individuals, but for the + overall community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or + advances of any kind +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email + address, without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official e-mail address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement at +info@bestbytes.de. +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series +of actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or +permanent ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within +the community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.0, available at +https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. + +Community Impact Guidelines were inspired by [Mozilla's code of conduct +enforcement ladder](https://github.com/mozilla/diversity). + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see the FAQ at +https://www.contributor-covenant.org/faq. Translations are available at +https://www.contributor-covenant.org/translations. diff --git a/Makefile b/Makefile index 14ac590..da2a3f0 100644 --- a/Makefile +++ b/Makefile @@ -1,38 +1,55 @@ .DEFAULT_GOAL:=help +-include .makerc + +# --- Targets ----------------------------------------------------------------- + +# This allows us to accept extra arguments +%: .husky + @: + +.PHONY: .husky +# Configure git hooks for husky +.husky: + @if ! command -v husky &> /dev/null; then \ + echo "ERROR: missing executeable 'husky', please run:"; \ + echo "\n$ go install github.com/go-courier/husky/cmd/husky@latest\n"; \ + fi + @git config core.hooksPath .husky ## === Tasks === +.PHONY: doc +## Run tests +doc: + @open "http://localhost:6060/pkg/github.com/foomo/keel/" + @godoc -http=localhost:6060 -play + .PHONY: test ## Run tests test: - go test -v ./... + @go test -p 1 -coverprofile=coverage.out -race -json ./... | gotestfmt .PHONY: lint ## Run linter -lint: files=$(shell find . -type f -name go.mod) -lint: dirs=$(foreach file,$(files),$(dir $(file)) ) lint: - @for dir in $(dirs); do cd $$dir && pwd && golangci-lint run; done + @golangci-lint run .PHONY: lint.fix ## Fix lint violations -lint.fix: files=$(shell find . -type f -name go.mod) -lint.fix: dirs=$(foreach file,$(files),$(dir $(file)) ) lint.fix: - @for dir in $(dirs); do cd $$dir && golangci-lint run --fix; done + @golangci-lint run --fix -## === Utils === - -.PHONY: gomod +.PHONY: tidy ## Run go mod tidy -gomod: - go mod tidy - cd example && go mod tidy +tidy: + @go mod tidy -.PHONY: gomod.outdated +.PHONY: outdated ## Show outdated direct dependencies -gomod.outdated: - go list -u -m -json all | go-mod-outdated -update -direct +outdated: + @go list -u -m -json all | go-mod-outdated -update -direct + +## === Utils === ## Show help text help: diff --git a/README.md b/README.md index 02690fe..a5341aa 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,9 @@ # keel +[![Build Status](https://github.com/foomo/keel/actions/workflows/test.yml/badge.svg?branch=main&event=push)](https://github.com/foomo/keel/actions/workflows/test.yml) [![Go Report Card](https://goreportcard.com/badge/github.com/foomo/keel)](https://goreportcard.com/report/github.com/foomo/keel) -[![godoc](https://godoc.org/github.com/foomo/keel?status.svg)](https://godoc.org/github.com/foomo/keel) -[![GitHub Super-Linter](https://github.com/foomo/keel/workflows/CI/badge.svg)](https://github.com/marketplace/actions/super-linter) +[![Coverage Status](https://coveralls.io/repos/github/foomo/keel/badge.svg?branch=main&)](https://coveralls.io/github/foomo/keel?branch=main) +[![GoDoc](https://godoc.org/github.com/foomo/keel?status.svg)](https://godoc.org/github.com/foomo/keel) > Opinionated way to run services. @@ -25,6 +26,7 @@ import ( "net/http" "github.com/foomo/keel" + "github.com/foomo/keel/service" ) func main() { @@ -39,7 +41,7 @@ func main() { svs := newService() svr.AddService( - keel.NewServiceHTTP(l, "demo", ":8080", svs), + service.NewHTTP(l, "demo", "localhost:8080", svs), ) svr.Run() diff --git a/closer.go b/closer.go index 9de714d..fe583bd 100644 --- a/closer.go +++ b/closer.go @@ -1,37 +1,29 @@ package keel -import "context" - -type closer struct { - handle func(context.Context) error -} - -func NewCloserFn(handle func(context.Context) error) closer { - return closer{ - handle: handle, +import ( + "github.com/foomo/keel/interfaces" +) + +func IsCloser(v any) bool { + switch v.(type) { + case interfaces.Closer, + interfaces.ErrorCloser, + interfaces.CloserWithContext, + interfaces.ErrorCloserWithContext, + interfaces.Shutdowner, + interfaces.ErrorShutdowner, + interfaces.ShutdownerWithContext, + interfaces.ErrorShutdownerWithContext, + interfaces.Stopper, + interfaces.ErrorStopper, + interfaces.StopperWithContext, + interfaces.ErrorStopperWithContext, + interfaces.Unsubscriber, + interfaces.ErrorUnsubscriber, + interfaces.UnsubscriberWithContext, + interfaces.ErrorUnsubscriberWithContext: + return true + default: + return false } } - -func (h healther) Close(ctx context.Context) error { - return h.handle(ctx) -} - -// Closer interface -type Closer interface { - Close() -} - -// ErrorCloser interface -type ErrorCloser interface { - Close() error -} - -// CloserWithContext interface -type CloserWithContext interface { - Close(ctx context.Context) -} - -// ErrorCloserWithContext interface -type ErrorCloserWithContext interface { - Close(ctx context.Context) error -} diff --git a/config/config.go b/config/config.go index 7c4b26a..195d670 100644 --- a/config/config.go +++ b/config/config.go @@ -11,7 +11,10 @@ import ( // config holds the global configuration var ( - config *viper.Viper + config *viper.Viper + requiredKeys []string + defaults = map[string]interface{}{} + types = map[string]string{} ) // Init sets up the configuration @@ -28,254 +31,224 @@ func Config() *viper.Viper { } func GetBool(c *viper.Viper, key string, fallback bool) func() bool { - c = ensure(c) - c.SetDefault(key, fallback) + setDefault(c, key, "bool", fallback) return func() bool { return c.GetBool(key) } } -func MustGetBool(c *viper.Viper, key string, fallback bool) func() bool { - c = ensure(c) - must(c, key) +func MustGetBool(c *viper.Viper, key string) func() bool { + must(c, key, "bool") return func() bool { return c.GetBool(key) } } func GetInt(c *viper.Viper, key string, fallback int) func() int { - c.SetDefault(key, fallback) + setDefault(c, key, "int", fallback) return func() int { return c.GetInt(key) } } func MustGetInt(c *viper.Viper, key string) func() int { - must(c, key) + must(c, key, "int") return func() int { return c.GetInt(key) } } func GetInt32(c *viper.Viper, key string, fallback int32) func() int32 { - c = ensure(c) - c.SetDefault(key, fallback) + setDefault(c, key, "int32", fallback) return func() int32 { return c.GetInt32(key) } } func MustGetInt32(c *viper.Viper, key string) func() int32 { - c = ensure(c) - must(c, key) + must(c, key, "int32") return func() int32 { return c.GetInt32(key) } } func GetInt64(c *viper.Viper, key string, fallback int64) func() int64 { - c = ensure(c) - c.SetDefault(key, fallback) + setDefault(c, key, "int64", fallback) return func() int64 { return c.GetInt64(key) } } func MustGetInt64(c *viper.Viper, key string) func() int64 { - c = ensure(c) - must(c, key) + must(c, key, "int64") return func() int64 { return c.GetInt64(key) } } func GetUint(c *viper.Viper, key string, fallback uint) func() uint { - c = ensure(c) - c.SetDefault(key, fallback) + setDefault(c, key, "uint", fallback) return func() uint { return c.GetUint(key) } } func MustGetUint(c *viper.Viper, key string) func() uint { - c = ensure(c) - must(c, key) + must(c, key, "uint") return func() uint { return c.GetUint(key) } } func GetUint32(c *viper.Viper, key string, fallback uint32) func() uint32 { - c = ensure(c) - c.SetDefault(key, fallback) + setDefault(c, key, "uint32", fallback) return func() uint32 { return c.GetUint32(key) } } func MustGetUint32(c *viper.Viper, key string) func() uint32 { - c = ensure(c) - must(c, key) + must(c, key, "uint32") return func() uint32 { return c.GetUint32(key) } } func GetUint64(c *viper.Viper, key string, fallback uint64) func() uint64 { - c = ensure(c) - c.SetDefault(key, fallback) + setDefault(c, key, "uint64", fallback) return func() uint64 { return c.GetUint64(key) } } func MustGetUint64(c *viper.Viper, key string) func() uint64 { - c = ensure(c) - must(c, key) + must(c, key, "uint64") return func() uint64 { return c.GetUint64(key) } } func GetFloat64(c *viper.Viper, key string, fallback float64) func() float64 { - c = ensure(c) - c.SetDefault(key, fallback) + setDefault(c, key, "float64", fallback) return func() float64 { return c.GetFloat64(key) } } func MustGetFloat64(c *viper.Viper, key string) func() float64 { - c = ensure(c) - must(c, key) + must(c, key, "float64") return func() float64 { return c.GetFloat64(key) } } func GetString(c *viper.Viper, key, fallback string) func() string { - c = ensure(c) - c.SetDefault(key, fallback) + setDefault(c, key, "string", fallback) return func() string { return c.GetString(key) } } func MustGetString(c *viper.Viper, key string) func() string { - c = ensure(c) - must(c, key) + must(c, key, "string") return func() string { return c.GetString(key) } } func GetTime(c *viper.Viper, key string, fallback time.Time) func() time.Time { - c = ensure(c) - c.SetDefault(key, fallback) + setDefault(c, key, "time.Time", fallback) return func() time.Time { return c.GetTime(key) } } func MustGetTime(c *viper.Viper, key string) func() time.Time { - c = ensure(c) - must(c, key) + must(c, key, "time.Time") return func() time.Time { return c.GetTime(key) } } func GetDuration(c *viper.Viper, key string, fallback time.Duration) func() time.Duration { - c = ensure(c) - c.SetDefault(key, fallback) + setDefault(c, key, "time.Duration", fallback) return func() time.Duration { return c.GetDuration(key) } } func MustGetDuration(c *viper.Viper, key string) func() time.Duration { - c = ensure(c) - must(c, key) + must(c, key, "time.Duration") return func() time.Duration { return c.GetDuration(key) } } func GetIntSlice(c *viper.Viper, key string, fallback []int) func() []int { - c = ensure(c) - c.SetDefault(key, fallback) + setDefault(c, key, "[]int", fallback) return func() []int { return c.GetIntSlice(key) } } func MustGetIntSlice(c *viper.Viper, key string) func() []int { - c = ensure(c) - must(c, key) + must(c, key, "[]int") return func() []int { return c.GetIntSlice(key) } } func GetStringSlice(c *viper.Viper, key string, fallback []string) func() []string { - c = ensure(c) - c.SetDefault(key, fallback) + setDefault(c, key, "[]string", fallback) return func() []string { return c.GetStringSlice(key) } } func MustGetStringSlice(c *viper.Viper, key string) func() []string { - c = ensure(c) - must(c, key) + must(c, key, "[]string") return func() []string { return c.GetStringSlice(key) } } func GetStringMap(c *viper.Viper, key string, fallback map[string]interface{}) func() map[string]interface{} { - c = ensure(c) - c.SetDefault(key, fallback) + setDefault(c, key, "map[string]interface{}", fallback) return func() map[string]interface{} { return c.GetStringMap(key) } } func MustGetStringMap(c *viper.Viper, key string) func() map[string]interface{} { - c = ensure(c) - must(c, key) + must(c, key, "map[string]interface{}") return func() map[string]interface{} { return c.GetStringMap(key) } } func GetStringMapString(c *viper.Viper, key string, fallback map[string]string) func() map[string]string { - c = ensure(c) - c.SetDefault(key, fallback) + setDefault(c, key, "map[string]string", fallback) return func() map[string]string { return c.GetStringMapString(key) } } func MustGetStringMapString(c *viper.Viper, key string) func() map[string]string { - c = ensure(c) - must(c, key) + must(c, key, "map[string]string") return func() map[string]string { return c.GetStringMapString(key) } } func GetStringMapStringSlice(c *viper.Viper, key string, fallback map[string][]string) func() map[string][]string { - c = ensure(c) - c.SetDefault(key, fallback) + setDefault(c, key, "map[string][]string", fallback) return func() map[string][]string { return c.GetStringMapStringSlice(key) } } func MustGetStringMapStringSlice(c *viper.Viper, key string) func() map[string][]string { - c = ensure(c) - must(c, key) + must(c, key, "map[string][]string") return func() map[string][]string { return c.GetStringMapStringSlice(key) } @@ -316,6 +289,25 @@ func GetStruct(c *viper.Viper, key string, fallback interface{}) (func(v interfa }, nil } +func RequiredKeys() []string { + return requiredKeys +} + +func Defaults() map[string]interface{} { + return defaults +} + +func Types() map[string]string { + return types +} + +func TypeOf(key string) string { + if v, ok := types[key]; ok { + return v + } + return "" +} + func ensure(c *viper.Viper) *viper.Viper { if c == nil { c = config @@ -323,7 +315,10 @@ func ensure(c *viper.Viper) *viper.Viper { return c } -func must(c *viper.Viper, key string) { +func must(c *viper.Viper, key, typeof string) { + c = ensure(c) + types[key] = typeof + requiredKeys = append(requiredKeys, key) if !c.IsSet(key) { panic(fmt.Sprintf("missing required config key: %s", key)) } @@ -339,3 +334,10 @@ func decode(input, output interface{}) error { } return decoder.Decode(input) } + +func setDefault(c *viper.Viper, key, typeof string, fallback any) { + c = ensure(c) + c.SetDefault(key, fallback) + defaults[key] = fallback + types[key] = typeof +} diff --git a/config/readme.go b/config/readme.go new file mode 100644 index 0000000..bbcad9f --- /dev/null +++ b/config/readme.go @@ -0,0 +1,71 @@ +package config + +import ( + "fmt" + + "github.com/foomo/keel/markdown" +) + +func Readme() string { + var configRows [][]string + var remoteRows [][]string + c := Config() + md := &markdown.Markdown{} + + { + keys := c.AllKeys() + for _, key := range keys { + var fallback interface{} + if v, ok := defaults[key]; ok { + fallback = v + } + configRows = append(configRows, []string{ + markdown.Code(key), + markdown.Code(TypeOf(key)), + "", + markdown.Code(fmt.Sprintf("%v", fallback)), + }) + } + + for _, key := range requiredKeys { + configRows = append(configRows, []string{ + markdown.Code(key), + markdown.Code(TypeOf(key)), + markdown.Code("true"), + "", + }) + } + } + + { + for _, remote := range remotes { + remoteRows = append(remoteRows, []string{ + markdown.Code(remote.provider), + markdown.Code(remote.path), + }) + } + } + + if len(configRows) > 0 || len(remoteRows) > 0 { + md.Println("### Config") + md.Println("") + } + + if len(configRows) > 0 { + md.Println("List of all registered config variables with their defaults.") + md.Println("") + md.Table([]string{"Key", "Type", "Required", "Default"}, configRows) + md.Println("") + } + + if len(remoteRows) > 0 { + md.Println("#### Remotes") + md.Println("") + md.Println("List of remote config providers that are being watched.") + md.Println("") + md.Table([]string{"Provider", "Path"}, remoteRows) + md.Println("") + } + + return md.String() +} diff --git a/config/remote.go b/config/remote.go index 462c13c..ae54652 100644 --- a/config/remote.go +++ b/config/remote.go @@ -3,9 +3,15 @@ package config import ( "github.com/pkg/errors" "github.com/spf13/viper" - _ "github.com/spf13/viper/remote" + _ "github.com/spf13/viper/remote" // required import ) +var remotes []struct { + provider string + endpoint string + path string +} + func WithRemoteConfig(c *viper.Viper, provider, endpoint string, path string) error { if err := c.AddRemoteProvider(provider, endpoint, path); err != nil { return err @@ -19,5 +25,11 @@ func WithRemoteConfig(c *viper.Viper, provider, endpoint string, path string) er return errors.Wrap(err, "failed to watch remote config") } + remotes = append(remotes, struct { + provider string + endpoint string + path string + }{provider: provider, endpoint: endpoint, path: path}) + return nil } diff --git a/config/watch.go b/config/watch.go index 9713e2e..870b771 100644 --- a/config/watch.go +++ b/config/watch.go @@ -20,7 +20,7 @@ func WatchBool(ctx context.Context, fn func() bool, callback func(bool)) { func WatchTime(ctx context.Context, fn func() time.Time, callback func(time.Time)) { current := fn() watch(ctx, func() { - if value := fn(); value != current { + if value := fn(); !value.Equal(current) { current = value callback(current) } @@ -102,7 +102,7 @@ func WatchBoolChan(ctx context.Context, fn func() bool, ch chan bool) { func WatchTimeChan(ctx context.Context, fn func() time.Time, ch chan time.Time) { current := fn() watch(ctx, func() { - if value := fn(); value != current { + if value := fn(); !value.Equal(current) { current = value ch <- current } diff --git a/env/env.go b/env/env.go index 1fabba3..31b5c93 100644 --- a/env/env.go +++ b/env/env.go @@ -3,10 +3,17 @@ package env import ( "fmt" "os" + "slices" "strconv" "strings" ) +var ( + defaults = map[string]interface{}{} + requiredKeys []string + types = map[string]string{} +) + // Exists return true if env var is defined func Exists(key string) bool { _, ok := os.LookupEnv(key) @@ -15,13 +22,20 @@ func Exists(key string) bool { // MustExists panics if not exists func MustExists(key string) { - if _, ok := os.LookupEnv(key); !ok { - panic(fmt.Sprintf("required environment variable %s does not exist", key)) + if !Exists(key) { + panic(fmt.Sprintf("required environment variable `%s` does not exist", key)) + } + if !slices.Contains(requiredKeys, key) { + requiredKeys = append(requiredKeys, key) } } // Get env var or fallback func Get(key, fallback string) string { + defaults[key] = fallback + if _, ok := types[key]; !ok { + types[key] = "string" + } if v, ok := os.LookupEnv(key); ok { return v } @@ -36,6 +50,9 @@ func MustGet(key string) string { // GetInt env var or fallback as int func GetInt(key string, fallback int) int { + if _, ok := types[key]; !ok { + types[key] = "int" + } if value, err := strconv.Atoi(Get(key, "")); err == nil { return value } @@ -50,6 +67,9 @@ func MustGetInt(key string) int { // GetInt64 env var or fallback as int64 func GetInt64(key string, fallback int64) int64 { + if _, ok := types[key]; !ok { + types[key] = "int64" + } if value, err := strconv.ParseInt(Get(key, ""), 10, 64); err == nil { return value } @@ -64,6 +84,9 @@ func MustGetInt64(key string) int64 { // GetFloat64 env var or fallback as float64 func GetFloat64(key string, fallback float64) float64 { + if _, ok := types[key]; !ok { + types[key] = "float64" + } if value, err := strconv.ParseFloat(Get(key, ""), 64); err == nil { return value } @@ -78,6 +101,9 @@ func MustGetFloat64(key string) float64 { // GetBool env var or fallback as bool func GetBool(key string, fallback bool) bool { + if _, ok := types[key]; !ok { + types[key] = "bool" + } if val, err := strconv.ParseBool(Get(key, "")); err == nil { return val } @@ -92,6 +118,9 @@ func MustGetBool(key string) bool { // GetStringSlice env var or fallback as []string func GetStringSlice(key string, fallback []string) []string { + if _, ok := types[key]; !ok { + types[key] = "[]string" + } if v := Get(key, ""); v != "" { return strings.Split(v, ",") } @@ -106,6 +135,9 @@ func MustGetStringSlice(key string) []string { // GetIntSlice env var or fallback as []string func GetIntSlice(key string, fallback []int) []int { + if _, ok := types[key]; !ok { + types[key] = "[]int" + } if v := Get(key, ""); v != "" { elements := strings.Split(v, ",") ret := make([]int, len(elements)) @@ -125,3 +157,22 @@ func MustGetGetIntSlice(key string) []int { MustExists(key) return GetIntSlice(key, nil) } + +func RequiredKeys() []string { + return requiredKeys +} + +func Defaults() map[string]interface{} { + return defaults +} + +func Types() map[string]string { + return types +} + +func TypeOf(key string) string { + if v, ok := types[key]; ok { + return v + } + return "" +} diff --git a/env/readme.go b/env/readme.go new file mode 100644 index 0000000..909d1bf --- /dev/null +++ b/env/readme.go @@ -0,0 +1,43 @@ +package env + +import ( + "fmt" + + "github.com/foomo/keel/markdown" +) + +func Readme() string { + var rows [][]string + md := &markdown.Markdown{} + + { + for key, fallback := range defaults { + rows = append(rows, []string{ + markdown.Code(key), + markdown.Code(TypeOf(key)), + "", + markdown.Code(fmt.Sprintf("%v", fallback)), + }) + } + + for _, key := range requiredKeys { + rows = append(rows, []string{ + markdown.Code(key), + markdown.Code(TypeOf(key)), + markdown.Code("true"), + "", + }) + } + } + + if len(rows) > 0 { + md.Println("### Env") + md.Println("") + md.Println("List of all accessed environment variables.") + md.Println("") + md.Table([]string{"Key", "Type", "Required", "Default"}, rows) + md.Println("") + } + + return md.String() +} diff --git a/errors.go b/errors.go index f9d28eb..60f162a 100644 --- a/errors.go +++ b/errors.go @@ -5,6 +5,6 @@ import ( ) var ( - ErrServerNotRunning = errors.New("server not running") - ErrServiceNotRunning = errors.New("service not running") + ErrServerNotRunning = errors.New("server not running") + ErrServerShutdown = errors.New("server is shutting down") ) diff --git a/errors/wrappederror.go b/errors/wrappederror.go index 12ec753..9b1aa8d 100644 --- a/errors/wrappederror.go +++ b/errors/wrappederror.go @@ -1,12 +1,11 @@ package keelerrors -import "errors" - type wrappedError struct { err error cause error } +// NewWrappedError returns a new wrapped error func NewWrappedError(err, cause error) error { return &wrappedError{ err: err, @@ -14,22 +13,10 @@ func NewWrappedError(err, cause error) error { } } -func (e *wrappedError) As(target interface{}) bool { - return errors.As(e.err, target) || errors.As(e.cause, target) -} - -func (e *wrappedError) Is(target error) bool { - return errors.Is(e.err, target) || errors.Is(e.cause, target) -} - -func (e *wrappedError) Cause() error { - return e.cause -} - -func (e *wrappedError) Unwrap() error { - return e.err -} - func (e *wrappedError) Error() string { return e.err.Error() + ": " + e.cause.Error() } + +func (e *wrappedError) Unwrap() []error { + return []error{e.err, e.cause} +} diff --git a/errors/wrappederror_test.go b/errors/wrappederror_test.go new file mode 100644 index 0000000..da12b14 --- /dev/null +++ b/errors/wrappederror_test.go @@ -0,0 +1,76 @@ +package keelerrors_test + +import ( + "fmt" + "testing" + + keelerrors "github.com/foomo/keel/errors" + "github.com/pkg/errors" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func ExampleNewWrappedError() { + parentErr := errors.New("parent") + childErr := errors.New("child") + wrappedErr := keelerrors.NewWrappedError(parentErr, childErr) + fmt.Println(parentErr) + fmt.Println(childErr) + fmt.Println(wrappedErr) + // Output: + // parent + // child + // parent: child +} + +func TestNewWrappedError(t *testing.T) { + parentErr := errors.New("parent") + childErr := errors.New("child") + assert.Error(t, keelerrors.NewWrappedError(parentErr, childErr)) +} + +func TestWrapped(t *testing.T) { + parentErr := errors.New("parent") + childErr := errors.New("child") + assert.Error(t, keelerrors.NewWrappedError(parentErr, childErr)) +} + +func Test_wrappedError_As(t *testing.T) { + type ( + Parent struct { + error + } + Child struct { + error + } + ) + parentErr := &Parent{error: errors.New("parent")} + childErr := &Child{error: errors.New("parent")} + wrappedErr := keelerrors.NewWrappedError(parentErr, childErr) + + var ( + p *Parent + c *Child + ) + if assert.ErrorAs(t, wrappedErr, &p) { + assert.EqualError(t, p, parentErr.Error()) + } + if assert.ErrorAs(t, wrappedErr, &c) { + assert.EqualError(t, c, childErr.Error()) + } +} + +func Test_wrappedError_Error(t *testing.T) { + parentErr := errors.New("parent") + childErr := errors.New("child") + wrappedErr := keelerrors.NewWrappedError(parentErr, childErr) + assert.Equal(t, "parent: child", wrappedErr.Error()) +} + +func Test_wrappedError_Is(t *testing.T) { + parentErr := errors.New("parent") + childErr := errors.New("child") + wrappedErr := keelerrors.NewWrappedError(parentErr, childErr) + require.ErrorIs(t, wrappedErr, parentErr) + require.ErrorIs(t, wrappedErr, childErr) +} diff --git a/example/go.mod b/example/go.mod deleted file mode 100644 index aa10afc..0000000 --- a/example/go.mod +++ /dev/null @@ -1,137 +0,0 @@ -module github.com/foomo/keel/example - -go 1.19 - -require ( - github.com/davecgh/go-spew v1.1.1 - github.com/foomo/keel v0.0.0 - github.com/golang-jwt/jwt v3.2.2+incompatible - github.com/google/uuid v1.3.0 - github.com/nats-io/nats.go v1.24.0 - github.com/pkg/errors v0.9.1 - go.mongodb.org/mongo-driver v1.11.3 - go.opentelemetry.io/otel v1.7.0 - go.opentelemetry.io/otel/metric v0.30.0 - go.uber.org/zap v1.24.0 -) - -require ( - cloud.google.com/go v0.107.0 // indirect - cloud.google.com/go/compute v1.15.1 // indirect - cloud.google.com/go/compute/metadata v0.2.3 // indirect - cloud.google.com/go/firestore v1.9.0 // indirect - cloud.google.com/go/longrunning v0.3.0 // indirect - github.com/armon/go-metrics v0.4.0 // indirect - github.com/avast/retry-go v3.0.0+incompatible // indirect - github.com/beorn7/perks v1.0.1 // indirect - github.com/cenkalti/backoff/v4 v4.1.3 // indirect - github.com/cespare/xxhash/v2 v2.2.0 // indirect - github.com/coreos/go-semver v0.3.0 // indirect - github.com/coreos/go-systemd/v22 v22.3.2 // indirect - github.com/fatih/color v1.13.0 // indirect - github.com/felixge/httpsnoop v1.0.2 // indirect - github.com/fsnotify/fsnotify v1.6.0 // indirect - github.com/go-logr/logr v1.2.3 // indirect - github.com/go-logr/stdr v1.2.2 // indirect - github.com/go-ole/go-ole v1.2.6 // indirect - github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect - github.com/golang/protobuf v1.5.2 // indirect - github.com/golang/snappy v0.0.3 // indirect - github.com/google/go-cmp v0.5.9 // indirect - github.com/googleapis/enterprise-certificate-proxy v0.2.1 // indirect - github.com/googleapis/gax-go/v2 v2.7.0 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0 // indirect - github.com/hashicorp/consul/api v1.18.0 // indirect - github.com/hashicorp/go-cleanhttp v0.5.2 // indirect - github.com/hashicorp/go-hclog v1.2.0 // indirect - github.com/hashicorp/go-immutable-radix v1.3.1 // indirect - github.com/hashicorp/go-rootcerts v1.0.2 // indirect - github.com/hashicorp/golang-lru v0.5.4 // indirect - github.com/hashicorp/hcl v1.0.0 // indirect - github.com/hashicorp/serf v0.10.1 // indirect - github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/compress v1.14.4 // indirect - github.com/lib/pq v1.10.7 // indirect - github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect - github.com/magiconair/properties v1.8.7 // indirect - github.com/mattn/go-colorable v0.1.12 // indirect - github.com/mattn/go-isatty v0.0.14 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect - github.com/minio/highwayhash v1.0.2 // indirect - github.com/mitchellh/go-homedir v1.1.0 // indirect - github.com/mitchellh/mapstructure v1.5.0 // indirect - github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect - github.com/modern-go/reflect2 v1.0.2 // indirect - github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect - github.com/nats-io/jwt/v2 v2.3.0 // indirect - github.com/nats-io/nkeys v0.3.0 // indirect - github.com/nats-io/nuid v1.0.1 // indirect - github.com/pelletier/go-toml/v2 v2.0.6 // indirect - github.com/philhofer/fwd v1.1.2 // indirect - github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect - github.com/prometheus/client_golang v1.14.0 // indirect - github.com/prometheus/client_model v0.3.0 // indirect - github.com/prometheus/common v0.37.0 // indirect - github.com/prometheus/procfs v0.8.0 // indirect - github.com/sagikazarmark/crypt v0.9.0 // indirect - github.com/shirou/gopsutil/v3 v3.22.3 // indirect - github.com/sony/gobreaker v0.5.0 // indirect - github.com/spf13/afero v1.9.3 // indirect - github.com/spf13/cast v1.5.0 // indirect - github.com/spf13/jwalterweatherman v1.1.0 // indirect - github.com/spf13/pflag v1.0.5 // indirect - github.com/spf13/viper v1.15.0 // indirect - github.com/subosito/gotenv v1.4.2 // indirect - github.com/tinylib/msgp v1.1.8 // indirect - github.com/tklauser/go-sysconf v0.3.10 // indirect - github.com/tklauser/numcpus v0.4.0 // indirect - github.com/xdg-go/pbkdf2 v1.0.0 // indirect - github.com/xdg-go/scram v1.1.1 // indirect - github.com/xdg-go/stringprep v1.0.3 // indirect - github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect - github.com/yusufpapurcu/wmi v1.2.2 // indirect - go.etcd.io/etcd/api/v3 v3.5.6 // indirect - go.etcd.io/etcd/client/pkg/v3 v3.5.6 // indirect - go.etcd.io/etcd/client/v2 v2.305.6 // indirect - go.etcd.io/etcd/client/v3 v3.5.6 // indirect - go.opencensus.io v0.24.0 // indirect - go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo v0.32.0 // indirect - go.opentelemetry.io/contrib/instrumentation/host v0.32.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.32.0 // indirect - go.opentelemetry.io/contrib/instrumentation/runtime v0.32.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.7.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.7.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.7.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.7.0 // indirect - go.opentelemetry.io/otel/exporters/prometheus v0.30.0 // indirect - go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v0.30.0 // indirect - go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.7.0 // indirect - go.opentelemetry.io/otel/sdk v1.7.0 // indirect - go.opentelemetry.io/otel/sdk/metric v0.30.0 // indirect - go.opentelemetry.io/otel/trace v1.7.0 // indirect - go.opentelemetry.io/proto/otlp v0.16.0 // indirect - go.uber.org/atomic v1.9.0 // indirect - go.uber.org/multierr v1.8.0 // indirect - golang.org/x/crypto v0.7.0 // indirect - golang.org/x/net v0.8.0 // indirect - golang.org/x/oauth2 v0.4.0 // indirect - golang.org/x/sync v0.1.0 // indirect - golang.org/x/sys v0.6.0 // indirect - golang.org/x/text v0.8.0 // indirect - golang.org/x/time v0.1.0 // indirect - golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect - google.golang.org/api v0.107.0 // indirect - google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f // indirect - google.golang.org/grpc v1.53.0 // indirect - google.golang.org/protobuf v1.28.1 // indirect - gopkg.in/ini.v1 v1.67.0 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect -) - -replace ( - github.com/foomo/keel => ../ - // TODO remove once https://github.com/spf13/viper/pull/1371 is merged - github.com/spf13/viper v1.12.0 => github.com/franklinkim/viper v1.12.1-0.20220611111410-2d69ce7c2fe8 -) diff --git a/example/go.sum b/example/go.sum deleted file mode 100644 index 0b6b508..0000000 --- a/example/go.sum +++ /dev/null @@ -1,969 +0,0 @@ -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= -cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= -cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= -cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= -cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= -cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= -cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= -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.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= -cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= -cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= -cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= -cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= -cloud.google.com/go v0.107.0 h1:qkj22L7bgkl6vIeZDlOY2po43Mx/TIa2Wsa7VR+PEww= -cloud.google.com/go v0.107.0/go.mod h1:wpc2eNrD7hXUTy8EKS10jkxpZBjASrORK7goS+3YX2I= -cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= -cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= -cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= -cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= -cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= -cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/compute v1.15.1 h1:7UGq3QknM33pw5xATlpzeoomNxsacIVvTqTTvbfajmE= -cloud.google.com/go/compute v1.15.1/go.mod h1:bjjoF/NtFUrkD/urWfdHaKuOPDR5nWIs63rR+SXhcpA= -cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= -cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= -cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= -cloud.google.com/go/firestore v1.9.0 h1:IBlRyxgGySXu5VuW0RgGFlTtLukSnNkpDiEOMkQkmpA= -cloud.google.com/go/firestore v1.9.0/go.mod h1:HMkjKHNTtRyZNiMzu7YAsLr9K3X2udY2AMwDaMEQiiE= -cloud.google.com/go/longrunning v0.3.0 h1:NjljC+FYPV3uh5/OwWT6pVU+doBqMg2x/rZlE+CamDs= -cloud.google.com/go/longrunning v0.3.0/go.mod h1:qth9Y41RRSUE69rDcOn6DdK3HfQfsUI0YSmW3iIlLJc= -cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= -cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= -cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= -cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= -cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= -cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= -cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= -cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= -cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= -cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= -github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= -github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= -github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= -github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= -github.com/armon/go-metrics v0.4.0 h1:yCQqn7dwca4ITXb+CbubHmedzaQYHhNhrEXLYUeEe8Q= -github.com/armon/go-metrics v0.4.0/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= -github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/avast/retry-go v3.0.0+incompatible h1:4SOWQ7Qs+oroOTQOYnAHqelpCO0biHSxpiH9JdtuBj0= -github.com/avast/retry-go v3.0.0+incompatible/go.mod h1:XtSnn+n/sHqQIpZ10K1qAevBhOOCWBLXXy3hyiqqBrY= -github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= -github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= -github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= -github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= -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/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/cenkalti/backoff/v4 v4.1.3 h1:cFAlzYUlVYDysBEH2T5hyJZMh3+5+WCBvSnK6Q8UtC4= -github.com/cenkalti/backoff/v4 v4.1.3/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= -github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.1.2/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/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= -github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= -github.com/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/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= -github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= -github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI= -github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= -github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= -github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= -github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= -github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= -github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -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 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= -github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= -github.com/felixge/httpsnoop v1.0.2 h1:+nS9g82KMXccJ/wp0zyRW9ZBHFETmMGtkk+2CTTrW4o= -github.com/felixge/httpsnoop v1.0.2/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= -github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= -github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= -github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= -github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= -github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= -github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= -github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= -github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= -github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= -github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= -github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= -github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -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 v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= -github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ= -github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= -github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= -github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= -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= -github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -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 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.3 h1:fHPg5GQYlCeLIPB9BZqMVR5nR9A+IM5zcgeTdjMYmLA= -github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= -github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -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-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/enterprise-certificate-proxy v0.2.1 h1:RY7tHKZcRlk788d5WSo/e83gOyyy742E8GSs771ySpg= -github.com/googleapis/enterprise-certificate-proxy v0.2.1/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= -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.7.0 h1:IcsPKeInNvYi7eqSaDjiZqDDKu5rsmunY0Y1YupQSSQ= -github.com/googleapis/gax-go/v2 v2.7.0/go.mod h1:TEop28CZZQ2y+c0VxMUmu1lV+fQx57QpBWsYpwqHJx8= -github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= -github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0 h1:BZHcxBETFHIdVyhyEfOvn/RdU/QGdLI4y34qQGjGWO0= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks= -github.com/hashicorp/consul/api v1.18.0 h1:R7PPNzTCeN6VuQNDwwhZWJvzCtGSrNpJqfb22h3yH9g= -github.com/hashicorp/consul/api v1.18.0/go.mod h1:owRRGJ9M5xReDC5nfT8FTJrNAPbT4NM6p/k+d03q2v4= -github.com/hashicorp/consul/sdk v0.13.0 h1:lce3nFlpv8humJL8rNrrGHYSKc3q+Kxfeg3Ii1m6ZWU= -github.com/hashicorp/consul/sdk v0.13.0/go.mod h1:0hs/l5fOVhJy/VdcoaNqUSi2AUs95eF5WKtv+EYIQqE= -github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= -github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= -github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= -github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= -github.com/hashicorp/go-hclog v1.2.0 h1:La19f8d7WIlm4ogzNHB0JGqs5AUDAZ2UfCY4sJXcJdM= -github.com/hashicorp/go-hclog v1.2.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= -github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= -github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= -github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= -github.com/hashicorp/go-msgpack v0.5.3 h1:zKjpN5BK/P5lMYrLmBHdBULWbJ0XpYR+7NGzqkZzoD4= -github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= -github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= -github.com/hashicorp/go-multierror v1.1.0 h1:B9UzwGQJehnUY1yNrnwREHc3fGbC2xefo8g4TbElacI= -github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= -github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= -github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= -github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= -github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= -github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= -github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= -github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= -github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE= -github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-version v1.2.1 h1:zEfKbn2+PDgroKdiOzqiE8rsmLqU2uwi5PB5pBJ3TkI= -github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= -github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= -github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= -github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= -github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= -github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc= -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/serf v0.10.1 h1:Z1H2J60yRKvfDYAOZLd2MU0ND4AH/WDz7xYHDWQsIPY= -github.com/hashicorp/serf v0.10.1/go.mod h1:yL2t6BqATOLGc5HF7qbFkTfXoPIY0WZdWHfEvMqbG+4= -github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= -github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= -github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= -github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -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.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= -github.com/klauspost/compress v1.14.4 h1:eijASRJcobkVtSt81Olfh7JX43osYLwy5krOJo6YEu4= -github.com/klauspost/compress v1.14.4/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= -github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw= -github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= -github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= -github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= -github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= -github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= -github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40= -github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= -github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= -github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= -github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= -github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= -github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= -github.com/miekg/dns v1.1.41 h1:WMszZWJG0XmzbK9FEmzH2TVcqYzFesusSIB41b8KHxY= -github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= -github.com/minio/highwayhash v1.0.2 h1:Aak5U0nElisjDCfPSG79Tgzkn2gl66NxOMspRrKnA/g= -github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY= -github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= -github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= -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/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= -github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -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/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= -github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= -github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe h1:iruDEfMl2E6fbMZ9s0scYfZQ84/6SPL6zC8ACM2oIL0= -github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= -github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/nats-io/jwt/v2 v2.3.0 h1:z2mA1a7tIf5ShggOFlR1oBPgd6hGqcDYsISxZByUzdI= -github.com/nats-io/jwt/v2 v2.3.0/go.mod h1:0tqz9Hlu6bCBFLWAASKhE5vUA4c24L9KPUUgvwumE/k= -github.com/nats-io/nats-server/v2 v2.7.3 h1:P0NgsnbTxrPMMPZ1/rLXWjS5bbPpRMCcPwlMd4nBDK4= -github.com/nats-io/nats.go v1.24.0 h1:CRiD8L5GOQu/DcfkmgBcTTIQORMwizF+rPk6T0RaHVQ= -github.com/nats-io/nats.go v1.24.0/go.mod h1:dVQF+BK3SzUZpwyzHedXsvH3EO38aVKuOPkkHlv5hXA= -github.com/nats-io/nkeys v0.3.0 h1:cgM5tL53EvYRU+2YLXIK0G2mJtK12Ft9oeooSZMA2G8= -github.com/nats-io/nkeys v0.3.0/go.mod h1:gvUNGjVcM2IPr5rCsRsC6Wb3Hr2CQAm08dsxtV6A5y4= -github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= -github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= -github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= -github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= -github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= -github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvIwycIU= -github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek= -github.com/philhofer/fwd v1.1.2 h1:bnDivRJ1EWPjUIRXV5KfORO897HTbpFAQddBdE8t7Gw= -github.com/philhofer/fwd v1.1.2/go.mod h1:qkPdfjR2SIEbspLqpe1tO4n5yICnr2DY7mqEx2tUTP0= -github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= -github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= -github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= -github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= -github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= -github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= -github.com/prometheus/client_golang v1.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.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= -github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw= -github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= -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.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= -github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= -github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= -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.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= -github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE= -github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= -github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= -github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo= -github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= -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.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= -github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/sagikazarmark/crypt v0.9.0 h1:fipzMFW34hFUEc4D7fsLQFtE7yElkpgyS2zruedRdZk= -github.com/sagikazarmark/crypt v0.9.0/go.mod h1:RnH7sEhxfdnPm1z+XMgSLjWTEIjyK4z2dw6+4vHTMuo= -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/shirou/gopsutil/v3 v3.22.3 h1:UebRzEomgMpv61e3hgD1tGooqX5trFbdU/ehphbHd00= -github.com/shirou/gopsutil/v3 v3.22.3/go.mod h1:D01hZJ4pVHPpCTZ3m3T2+wDF2YAGfd+H4ifUguaQzHM= -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= -github.com/sony/gobreaker v0.5.0 h1:dRCvqm0P490vZPmy7ppEk2qCnCieBooFJ+YoXGYB+yg= -github.com/sony/gobreaker v0.5.0/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= -github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spf13/afero v1.9.3 h1:41FoI0fD7OR7mGcKE/aOiLkGreyf8ifIOQmJANWogMk= -github.com/spf13/afero v1.9.3/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= -github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= -github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= -github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= -github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= -github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= -github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.15.0 h1:js3yy885G8xwJa6iOISGFwd+qlUo5AvyXb7CiihdtiU= -github.com/spf13/viper v1.15.0/go.mod h1:fFcTBJxvhhzSJiZy8n+PeW6t8l+KeT/uTARa0jHOQLA= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= -github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= -github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= -github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= -github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= -github.com/tinylib/msgp v1.1.8 h1:FCXC1xanKO4I8plpHGH2P7koL/RzZs12l/+r7vakfm0= -github.com/tinylib/msgp v1.1.8/go.mod h1:qkpG+2ldGg4xRFmx+jfTvZPxfGFhi64BcnL9vkCm/Tw= -github.com/tklauser/go-sysconf v0.3.10 h1:IJ1AZGZRWbY8T5Vfk04D9WOA5WSejdflXxP03OUqALw= -github.com/tklauser/go-sysconf v0.3.10/go.mod h1:C8XykCvCb+Gn0oNCWPIlcb0RuglQTYaQ2hGm7jmxEFk= -github.com/tklauser/numcpus v0.4.0 h1:E53Dm1HjH1/R2/aoCtXtPgzmElmn51aOkhCFSuZq//o= -github.com/tklauser/numcpus v0.4.0/go.mod h1:1+UI3pD8NW14VMwdgJNJ1ESk2UnwhAnz5hMwiKKqXCQ= -github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= -github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= -github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= -github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs= -github.com/xdg-go/scram v1.1.1 h1:VOMT+81stJgXW3CpHyqHN3AXDYIMsx56mEFrB37Mb/E= -github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g= -github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM= -github.com/xdg-go/stringprep v1.0.3 h1:kdwGpVNwPFtjs98xCGkHjQtGKh86rDcRZN17QEMCOIs= -github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8= -github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA= -github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= -github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg= -github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= -go.etcd.io/etcd/api/v3 v3.5.6 h1:Cy2qx3npLcYqTKqGJzMypnMv2tiRyifZJ17BlWIWA7A= -go.etcd.io/etcd/api/v3 v3.5.6/go.mod h1:KFtNaxGDw4Yx/BA4iPPwevUTAuqcsPxzyX8PHydchN8= -go.etcd.io/etcd/client/pkg/v3 v3.5.6 h1:TXQWYceBKqLp4sa87rcPs11SXxUA/mHwH975v+BDvLU= -go.etcd.io/etcd/client/pkg/v3 v3.5.6/go.mod h1:ggrwbk069qxpKPq8/FKkQ3Xq9y39kbFR4LnKszpRXeQ= -go.etcd.io/etcd/client/v2 v2.305.6 h1:fIDR0p4KMjw01MJMfUIDWdQbjo06PD6CeYM5z4EHLi0= -go.etcd.io/etcd/client/v2 v2.305.6/go.mod h1:BHha8XJGe8vCIBfWBpbBLVZ4QjOIlfoouvOwydu63E0= -go.etcd.io/etcd/client/v3 v3.5.6 h1:coLs69PWCXE9G4FKquzNaSHrRyMCAXwF+IX1tAPVO8E= -go.etcd.io/etcd/client/v3 v3.5.6/go.mod h1:f6GRinRMCsFVv9Ht42EyY7nfsVGwrNO0WEoS2pRKzQk= -go.mongodb.org/mongo-driver v1.9.0/go.mod h1:0sQWfOeY63QTntERDJJ/0SuKK0T1uVSgKCuAROlKEPY= -go.mongodb.org/mongo-driver v1.11.3 h1:Ql6K6qYHEzB6xvu4+AU0BoRoqf9vFPcc4o7MUIdPW8Y= -go.mongodb.org/mongo-driver v1.11.3/go.mod h1:PTSz5yu21bkT/wXpkS7WR5f0ddqw5quethTUn9WM+2g= -go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= -go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= -go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -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.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= -go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= -go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo v0.32.0 h1:gNKQHn+q326vsi+kOskx9FCz9Jkz2fvxlf1y46dTN14= -go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo v0.32.0/go.mod h1:9WqBmOJ4AOChNHtnRBSCGlKN4PQf1coLTCK57fyXE/s= -go.opentelemetry.io/contrib/instrumentation/host v0.32.0 h1:rgDeaor0XDeUaUCGj0VJIRdQYwsYANlnIh4yMgnaZvo= -go.opentelemetry.io/contrib/instrumentation/host v0.32.0/go.mod h1:GavGOmrtAjm+/J0WkNWzDC9rCAKQaD2d9JUzG225sgc= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.32.0 h1:mac9BKRqwaX6zxHPDe3pvmWpwuuIM0vuXv2juCnQevE= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.32.0/go.mod h1:5eCOqeGphOyz6TsY3ZDNjE33SM/TFAK3RGuCL2naTgY= -go.opentelemetry.io/contrib/instrumentation/runtime v0.32.0 h1:eMQf85EgNd2YWEikRJwEy4ADOiwlIum4rcHcssB4Qzk= -go.opentelemetry.io/contrib/instrumentation/runtime v0.32.0/go.mod h1:qtaLlIO4HC4DfedkYTOrvS2u7nA3N/v8w9mehrBD4O8= -go.opentelemetry.io/otel v1.7.0 h1:Z2lA3Tdch0iDcrhJXDIlC94XE+bxok1F9B+4Lz/lGsM= -go.opentelemetry.io/otel v1.7.0/go.mod h1:5BdUoMIz5WEs0vt0CUEMtSSaTSHBBVwrhnz7+nrD5xk= -go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.7.0 h1:7Yxsak1q4XrJ5y7XBnNwqWx9amMZvoidCctv62XOQ6Y= -go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.7.0/go.mod h1:M1hVZHNxcbkAlcvrOMlpQ4YOO3Awf+4N2dxkZL3xm04= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.7.0 h1:cMDtmgJ5FpRvqx9x2Aq+Mm0O6K/zcUkH73SFz20TuBw= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.7.0/go.mod h1:ceUgdyfNv4h4gLxHR0WNfDiiVmZFodZhZSbOLhpxqXE= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.7.0 h1:MFAyzUPrTwLOwCi+cltN0ZVyy4phU41lwH+lyMyQTS4= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.7.0/go.mod h1:E+/KKhwOSw8yoPxSSuUHG6vKppkvhN+S1Jc7Nib3k3o= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.7.0 h1:pLP0MH4MAqeTEV0g/4flxw9O8Is48uAIauAnjznbW50= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.7.0/go.mod h1:aFXT9Ng2seM9eizF+LfKiyPBGy8xIZKwhusC1gIu3hA= -go.opentelemetry.io/otel/exporters/prometheus v0.30.0 h1:YXo5ZY5nofaEYMCMTTMaRH2cLDZB8+0UGuk5RwMfIo0= -go.opentelemetry.io/otel/exporters/prometheus v0.30.0/go.mod h1:qN5feW+0/d661KDtJuATEmHtw5bKBK7NSvNEP927zSs= -go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v0.30.0 h1:2glg1ZFVVZf47zFuX0iwBPPid4tqzBYYWTVVu0pc+us= -go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v0.30.0/go.mod h1:LGFXSl/Js7uN7mDcrzCcHVj48JOtoYDjm4oUI4dLif0= -go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.7.0 h1:8hPcgCg0rUJiKE6VWahRvjgLUrNl7rW2hffUEPKXVEM= -go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.7.0/go.mod h1:K4GDXPY6TjUiwbOh+DkKaEdCF8y+lvMoM6SeAPyfCCM= -go.opentelemetry.io/otel/metric v0.30.0 h1:Hs8eQZ8aQgs0U49diZoaS6Uaxw3+bBE3lcMUKBFIk3c= -go.opentelemetry.io/otel/metric v0.30.0/go.mod h1:/ShZ7+TS4dHzDFmfi1kSXMhMVubNoP0oIaBp70J6UXU= -go.opentelemetry.io/otel/sdk v1.7.0 h1:4OmStpcKVOfvDOgCt7UriAPtKolwIhxpnSNI/yK+1B0= -go.opentelemetry.io/otel/sdk v1.7.0/go.mod h1:uTEOTwaqIVuTGiJN7ii13Ibp75wJmYUDe374q6cZwUU= -go.opentelemetry.io/otel/sdk/metric v0.30.0 h1:XTqQ4y3erR2Oj8xSAOL5ovO5011ch2ELg51z4fVkpME= -go.opentelemetry.io/otel/sdk/metric v0.30.0/go.mod h1:8AKFRi5HyvTR0RRty3paN1aMC9HMT+NzcEhw/BLkLX8= -go.opentelemetry.io/otel/trace v1.7.0 h1:O37Iogk1lEkMRXewVtZ1BBTVn5JEp8GrJvP92bJqC6o= -go.opentelemetry.io/otel/trace v1.7.0/go.mod h1:fzLSB9nqR2eXzxPXb2JW9IKE+ScyXA48yyE4TNvoHqU= -go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -go.opentelemetry.io/proto/otlp v0.16.0 h1:WHzDWdXUvbc5bG2ObdrGfaNpQz7ft7QN9HHmJlbiB1E= -go.opentelemetry.io/proto/otlp v0.16.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= -go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= -go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA= -go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= -go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= -go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8= -go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= -go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= -go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= -go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= -golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= -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-20201216223049-8b5274cf687f/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= -golang.org/x/crypto v0.0.0-20210314154223-e6e6c4f2bb5b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A= -golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= -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= -golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= -golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= -golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= -golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -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.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.2/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.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -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-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -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-20201031054903-ff519b6c9102/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-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= -golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= -golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= -golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= -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-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.4.0 h1:NF0gk8LVPg1Ml7SSbGyySuoxdsXitj7TvgvuRxIMc/M= -golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec= -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= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/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-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/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-20210220032951-036812b2e83c/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.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= -golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -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-20190130150945-aca44879d564/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -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-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/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.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= -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.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= -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= -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.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.5/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.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= -golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -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= -golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.1.0 h1:xYY+Bajn2a7VBmTM5GikTmnK8ZuX8YgnQCqZpbBNtmA= -golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= -golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= -golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= -golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ= -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= -golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= -golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= -google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -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.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= -google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= -google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= -google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= -google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= -google.golang.org/api v0.107.0 h1:I2SlFjD8ZWabaIFOfeEDg3pf0BHJDh6iYQ1ic3Yu/UU= -google.golang.org/api v0.107.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= -google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= -google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= -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-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f h1:BWUVssLB0HVOSY78gIdvk1dTVYtT1y8SBWtPYuTJ/6w= -google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= -google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= -google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.1/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.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= -google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k= -google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= -google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= -google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= -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= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -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.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= -google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -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= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= -gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/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= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= -rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= -rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= -sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff --git a/example/graceful/main.go b/example/graceful/main.go deleted file mode 100644 index 7d030d6..0000000 --- a/example/graceful/main.go +++ /dev/null @@ -1,59 +0,0 @@ -package main - -import ( - "context" - "net/http" - "sync" - "time" - - "go.uber.org/zap" - - "github.com/foomo/keel" - "github.com/foomo/keel/log" -) - -func main() { - svr := keel.NewServer( - keel.WithHTTPZapService(true), - keel.WithHTTPViperService(true), - keel.WithHTTPPrometheusService(true), - keel.WithHTTPHealthzService(true), - ) - - l := svr.Logger() - - go waitGroup(svr.CancelContext(), l.With(log.FServiceName("waitGroup"))) - - // create demo service - svs := http.NewServeMux() - svs.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(http.StatusOK) - _, _ = w.Write([]byte("OK")) - }) - - svr.AddService( - keel.NewServiceHTTP(l, "demo", "localhost:8080", svs), - ) - - svr.Run() -} - -func waitGroup(ctx context.Context, l *zap.Logger) { - var wg sync.WaitGroup - - wg.Add(1) - go func() { - defer wg.Done() - for { - select { - case <-ctx.Done(): - l.Info("Break the loop") - return - case <-time.After(3 * time.Second): - l.Info("Hello in a loop") - } - } - }() - - wg.Wait() -} diff --git a/example/config/main.go b/examples/config/main.go similarity index 96% rename from example/config/main.go rename to examples/config/main.go index bf89a65..19e1f86 100644 --- a/example/config/main.go +++ b/examples/config/main.go @@ -7,6 +7,7 @@ import ( "time" "github.com/davecgh/go-spew/spew" + "github.com/foomo/keel/service" "github.com/foomo/keel" "github.com/foomo/keel/config" @@ -85,7 +86,7 @@ func main() { }) svr.AddService( - keel.NewServiceHTTP(l, "demo", "localhost:8081", svs), + service.NewHTTP(l, "demo", "localhost:8081", svs), ) svr.Run() diff --git a/example/errors/main.go b/examples/errors/main.go similarity index 100% rename from example/errors/main.go rename to examples/errors/main.go diff --git a/examples/graceful/main.go b/examples/graceful/main.go new file mode 100644 index 0000000..5fd3323 --- /dev/null +++ b/examples/graceful/main.go @@ -0,0 +1,130 @@ +package main + +import ( + "context" + "net/http" + "syscall" + "time" + + "github.com/foomo/keel/interfaces" + "github.com/foomo/keel/service" + "go.uber.org/zap" + + "github.com/foomo/keel" +) + +func main() { + service.DefaultHTTPHealthzAddr = "localhost:9400" + + l := zap.NewExample().Named("root") + + go func() { + c := make(chan bool, 1) + time.Sleep(2 * time.Second) + + l.Info("1. starting checks") + go func() { + c <- true + for { + call(l.Named("http"), "http://localhost:8080") + call(l.Named("readiness"), "http://localhost:9400/healthz/readiness") + time.Sleep(time.Second) + } + }() + <-c + close(c) + + l.Info("2. sleeping for 5 seconds") + time.Sleep(5 * time.Second) + + l.Info("3. sending shutdown signal") + if err := syscall.Kill(syscall.Getpid(), syscall.SIGTERM); err != nil { + l.Fatal(err.Error()) + } + }() + + svr := keel.NewServer( + keel.WithLogger(l.Named("server")), + keel.WithHTTPHealthzService(true), + ) + + // create demo service + svs := http.NewServeMux() + svs.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + _, _ = w.Write([]byte("OK")) + }) + + svr.AddService( + service.NewHTTP(l, "http", "localhost:8080", svs), + ) + + svr.AddCloser(interfaces.CloserFunc(func(ctx context.Context) error { + l := l.Named("closer") + l.Info("closing stuff") + time.Sleep(3 * time.Second) + l.Info("done closing stuff") + return nil + })) + + svr.Run() + l.Info("done") + + // Output: + // {"level":"info","logger":"root.server","msg":"starting keel server"} + // {"level":"info","logger":"root.server","msg":"starting keel service","keel_service_type":"http","keel_service_name":"healthz","net_host_ip":"localhost","net_host_port":"9400"} + // {"level":"info","logger":"root","msg":"starting keel service","keel_service_type":"http","keel_service_name":"http","net_host_ip":"localhost","net_host_port":"8080"} + // {"level":"info","logger":"root","msg":"1. starting checks"} + // {"level":"info","logger":"root","msg":"2. sleeping for 5 seconds"} + // {"level":"info","logger":"root.http","msg":"ok","url":"http://localhost:8080","status":200} + // {"level":"info","logger":"root.readiness","msg":"ok","url":"http://localhost:9400/healthz/readiness","status":200} + // {"level":"info","logger":"root.http","msg":"ok","url":"http://localhost:8080","status":200} + // {"level":"info","logger":"root.readiness","msg":"ok","url":"http://localhost:9400/healthz/readiness","status":200} + // {"level":"info","logger":"root.http","msg":"ok","url":"http://localhost:8080","status":200} + // {"level":"info","logger":"root.readiness","msg":"ok","url":"http://localhost:9400/healthz/readiness","status":200} + // {"level":"info","logger":"root.http","msg":"ok","url":"http://localhost:8080","status":200} + // {"level":"info","logger":"root.readiness","msg":"ok","url":"http://localhost:9400/healthz/readiness","status":200} + // {"level":"info","logger":"root.http","msg":"ok","url":"http://localhost:8080","status":200} + // {"level":"info","logger":"root.readiness","msg":"ok","url":"http://localhost:9400/healthz/readiness","status":200} + // {"level":"info","logger":"root","msg":"3. sending shutdown signal"} + // {"level":"info","logger":"root.server","msg":"keel graceful shutdown","graceful_period":"30s"} + // {"level":"info","logger":"root.server","msg":"keel graceful shutdown: closers"} + // {"level":"info","logger":"root","msg":"stopping keel service","keel_service_type":"http","keel_service_name":"http"} + // {"level":"debug","logger":"root.server","msg":"keel graceful shutdown: closer closed","name":"*service.HTTP"} + // {"level":"info","logger":"root.closer","msg":"closing stuff"} + // {"level":"error","logger":"root.http","msg":"failed to send request","url":"http://localhost:8080","error":"Get \"http://localhost:8080\": dial tcp [::1]:8080: connect: connection refused"} + // {"level":"debug","logger":"root.server","msg":"healthz probe failed","error_type":"*errors.errorString","error_message":"service not running","http_target":"/healthz/readiness"} + // {"level":"info","logger":"root.readiness","msg":"ok","url":"http://localhost:9400/healthz/readiness","status":503} + // {"level":"error","logger":"root.http","msg":"failed to send request","url":"http://localhost:8080","error":"Get \"http://localhost:8080\": dial tcp [::1]:8080: connect: connection refused"} + // {"level":"debug","logger":"root.server","msg":"healthz probe failed","error_type":"*errors.errorString","error_message":"service not running","http_target":"/healthz/readiness"} + // {"level":"info","logger":"root.readiness","msg":"ok","url":"http://localhost:9400/healthz/readiness","status":503} + // {"level":"error","logger":"root.http","msg":"failed to send request","url":"http://localhost:8080","error":"Get \"http://localhost:8080\": dial tcp [::1]:8080: connect: connection refused"} + // {"level":"debug","logger":"root.server","msg":"healthz probe failed","error_type":"*errors.errorString","error_message":"service not running","http_target":"/healthz/readiness"} + // {"level":"info","logger":"root.readiness","msg":"ok","url":"http://localhost:9400/healthz/readiness","status":503} + // {"level":"info","logger":"root.closer","msg":"done closing stuff"} + // {"level":"debug","logger":"root.server","msg":"keel graceful shutdown: closer closed","name":"interfaces.CloserFunc"} + // {"level":"info","logger":"root.server","msg":"stopping keel service","keel_service_type":"http","keel_service_name":"healthz"} + // {"level":"debug","logger":"root.server","msg":"keel graceful shutdown: closer closed","name":"*service.HTTP"} + // {"level":"debug","logger":"root.server","msg":"keel graceful shutdown: closer closed","name":"noop.TracerProvider"} + // {"level":"debug","logger":"root.server","msg":"keel graceful shutdown: closer closed","name":"noop.MeterProvider"} + // {"level":"info","logger":"root.server","msg":"keel graceful shutdown: complete"} + // {"level":"info","logger":"root.server","msg":"keel server stopped"} + // {"level":"info","logger":"root","msg":"done"} +} + +func call(l *zap.Logger, url string) { + l = l.With(zap.String("url", url)) + + ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond) + defer cancel() + req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) + if err != nil { + l.With(zap.Error(err)).Error("failed to create request") + return + } + resp, err := http.DefaultClient.Do(req) + if err != nil { + l.With(zap.Error(err)).Error("failed to send request") + return + } + l.Info("ok", zap.Int("status", resp.StatusCode)) +} diff --git a/example/healthz/handler/handler.go b/examples/healthz/handler/handler.go similarity index 100% rename from example/healthz/handler/handler.go rename to examples/healthz/handler/handler.go diff --git a/example/healthz/main.go b/examples/healthz/main.go similarity index 81% rename from example/healthz/main.go rename to examples/healthz/main.go index dacbbe3..6f61701 100644 --- a/example/healthz/main.go +++ b/examples/healthz/main.go @@ -7,18 +7,20 @@ import ( "time" "github.com/foomo/keel" - "github.com/foomo/keel/example/healthz/handler" + "github.com/foomo/keel/examples/healthz/handler" + "github.com/foomo/keel/healthz" + "github.com/foomo/keel/service" ) // See k8s for probe documentation // https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#types-of-probe func main() { + service.DefaultHTTPHealthzAddr = "localhost:9400" + // you can override the below config by settings env vars _ = os.Setenv("SERVICE_HEALTHZ_ENABLED", "true") svr := keel.NewServer( - keel.WithHTTPZapService(true), - keel.WithHTTPViperService(true), // allows you to use probes for health checks in cluster: // GET :9400/healthz // GET :9400/healthz/readiness @@ -46,7 +48,7 @@ func main() { svr.AddReadinessHealthzers(rh) // add inline probe e.g. in case you start go routines - svr.AddAlwaysHealthzers(keel.NewHealthzerFn(func(ctx context.Context) error { + svr.AddAlwaysHealthzers(healthz.NewHealthzerFn(func(ctx context.Context) error { l.Info("healther fn") return nil })) @@ -63,13 +65,13 @@ func main() { select { case <-time.After(10 * time.Second): l.Info("initialization done") - case <-svr.CancelContext().Done(): + case <-svr.ShutdownContext().Done(): l.Info("initialization canceled") } // add services svr.AddService( - keel.NewServiceHTTP(l, "demo", "localhost:8080", svs), + service.NewHTTP(l, "demo", "localhost:8080", svs), ) // start serer diff --git a/example/logging/main.go b/examples/logging/main.go similarity index 92% rename from example/logging/main.go rename to examples/logging/main.go index 8ef5df5..00027fa 100644 --- a/example/logging/main.go +++ b/examples/logging/main.go @@ -7,6 +7,7 @@ import ( "github.com/foomo/keel" "github.com/foomo/keel/log" + "github.com/foomo/keel/service" ) type CustomError struct { @@ -46,7 +47,7 @@ func main() { }) svr.AddService( - keel.NewServiceHTTP(l, "demo", "localhost:8080", svs), + service.NewHTTP(l, "demo", "localhost:8080", svs), ) svr.Run() diff --git a/example/middlewares/basicauth/main.go b/examples/middlewares/basicauth/main.go similarity index 89% rename from example/middlewares/basicauth/main.go rename to examples/middlewares/basicauth/main.go index 4497761..f231b07 100644 --- a/example/middlewares/basicauth/main.go +++ b/examples/middlewares/basicauth/main.go @@ -6,6 +6,7 @@ import ( "github.com/foomo/keel" "github.com/foomo/keel/log" "github.com/foomo/keel/net/http/middleware" + "github.com/foomo/keel/service" httputils "github.com/foomo/keel/utils/net/http" ) @@ -29,7 +30,7 @@ func main() { log.Must(l, err, "failed to hash password") svr.AddService( - keel.NewServiceHTTP(l, "demo", "localhost:8080", svs, + service.NewHTTP(l, "demo", "localhost:8080", svs, middleware.BasicAuth( username, passwordHash, diff --git a/example/middlewares/cors/main.go b/examples/middlewares/cors/main.go similarity index 88% rename from example/middlewares/cors/main.go rename to examples/middlewares/cors/main.go index 1ab29b7..f54aad5 100644 --- a/example/middlewares/cors/main.go +++ b/examples/middlewares/cors/main.go @@ -6,6 +6,7 @@ import ( "github.com/foomo/keel" keelhttp "github.com/foomo/keel/net/http" "github.com/foomo/keel/net/http/middleware" + "github.com/foomo/keel/service" ) func main() { @@ -22,7 +23,7 @@ func main() { }) svr.AddService( - keel.NewServiceHTTP(l, "demo", "localhost:8080", svs, + service.NewHTTP(l, "demo", "localhost:8080", svs, middleware.CORS( middleware.CORSWithAllowOrigins("example.com"), middleware.CORSWithAllowMethods(http.MethodGet, http.MethodPost), diff --git a/example/middlewares/jwtfromcookie/main.go b/examples/middlewares/jwtfromcookie/main.go similarity index 98% rename from example/middlewares/jwtfromcookie/main.go rename to examples/middlewares/jwtfromcookie/main.go index a224541..2443648 100644 --- a/example/middlewares/jwtfromcookie/main.go +++ b/examples/middlewares/jwtfromcookie/main.go @@ -6,6 +6,7 @@ import ( "net/http" "strings" + "github.com/foomo/keel/service" jwt2 "github.com/golang-jwt/jwt" "go.uber.org/zap" @@ -75,7 +76,7 @@ func main() { }) svr.AddService( - keel.NewServiceHTTP(l, "demo", "localhost:8080", svs, + service.NewHTTP(l, "demo", "localhost:8080", svs, middleware.Skip( middleware.JWT( jwtInst, diff --git a/example/middlewares/jwtfromtoken/main.go b/examples/middlewares/jwtfromtoken/main.go similarity index 96% rename from example/middlewares/jwtfromtoken/main.go rename to examples/middlewares/jwtfromtoken/main.go index 0876339..915e530 100644 --- a/example/middlewares/jwtfromtoken/main.go +++ b/examples/middlewares/jwtfromtoken/main.go @@ -5,6 +5,7 @@ import ( "crypto/rsa" "net/http" + "github.com/foomo/keel/service" jwt2 "github.com/golang-jwt/jwt" "github.com/foomo/keel" @@ -66,7 +67,7 @@ func main() { }) svr.AddService( - keel.NewServiceHTTP(l, "demo", "localhost:8080", svs, + service.NewHTTP(l, "demo", "localhost:8080", svs, middleware.Skip( middleware.JWT( jwtInst, diff --git a/example/middlewares/logger/main.go b/examples/middlewares/logger/main.go similarity index 85% rename from example/middlewares/logger/main.go rename to examples/middlewares/logger/main.go index 99d3c39..3d702f1 100644 --- a/example/middlewares/logger/main.go +++ b/examples/middlewares/logger/main.go @@ -6,6 +6,7 @@ import ( "github.com/foomo/keel" keelhttp "github.com/foomo/keel/net/http" "github.com/foomo/keel/net/http/middleware" + "github.com/foomo/keel/service" ) func main() { @@ -22,7 +23,7 @@ func main() { }) svr.AddService( - keel.NewServiceHTTP(l, "demo", "localhost:8080", svs, + service.NewHTTP(l, "demo", "localhost:8080", svs, middleware.Logger(), ), ) diff --git a/example/middlewares/recover/main.go b/examples/middlewares/recover/main.go similarity index 86% rename from example/middlewares/recover/main.go rename to examples/middlewares/recover/main.go index 8e9a5db..1931772 100644 --- a/example/middlewares/recover/main.go +++ b/examples/middlewares/recover/main.go @@ -5,6 +5,7 @@ import ( "github.com/foomo/keel" "github.com/foomo/keel/net/http/middleware" + "github.com/foomo/keel/service" ) func main() { @@ -23,7 +24,7 @@ func main() { }) svr.AddService( - keel.NewServiceHTTP(l, "demo", "localhost:8080", svs, + service.NewHTTP(l, "demo", "localhost:8080", svs, middleware.Recover( middleware.RecoverWithDisablePrintStack(true), ), diff --git a/example/middlewares/requestid/main.go b/examples/middlewares/requestid/main.go similarity index 89% rename from example/middlewares/requestid/main.go rename to examples/middlewares/requestid/main.go index ae058e3..c2cf576 100644 --- a/example/middlewares/requestid/main.go +++ b/examples/middlewares/requestid/main.go @@ -6,6 +6,7 @@ import ( "github.com/foomo/keel" keelhttp "github.com/foomo/keel/net/http" "github.com/foomo/keel/net/http/middleware" + "github.com/foomo/keel/service" ) func main() { @@ -27,7 +28,7 @@ func main() { }) svr.AddService( - keel.NewServiceHTTP(l, "demo", "localhost:8080", svs, + service.NewHTTP(l, "demo", "localhost:8080", svs, middleware.RequestID( middleware.RequestIDWithSetResponseHeader(true), middleware.RequestIDWithGenerator(requestIDGenerator), diff --git a/example/middlewares/responsetime/main.go b/examples/middlewares/responsetime/main.go similarity index 89% rename from example/middlewares/responsetime/main.go rename to examples/middlewares/responsetime/main.go index 70c72de..44a60f3 100644 --- a/example/middlewares/responsetime/main.go +++ b/examples/middlewares/responsetime/main.go @@ -6,6 +6,7 @@ import ( "github.com/foomo/keel" "github.com/foomo/keel/net/http/middleware" + "github.com/foomo/keel/service" ) func main() { @@ -27,7 +28,7 @@ func main() { }) svr.AddService( - keel.NewServiceHTTP(l, "demo", "localhost:8080", svs, + service.NewHTTP(l, "demo", "localhost:8080", svs, middleware.ResponseTime( // automatically set cookie if not exists middleware.ResponseTimeWithMaxDuration(time.Millisecond*500), diff --git a/example/middlewares/sessionid/main.go b/examples/middlewares/sessionid/main.go similarity index 94% rename from example/middlewares/sessionid/main.go rename to examples/middlewares/sessionid/main.go index 49cb4a2..984f53e 100644 --- a/example/middlewares/sessionid/main.go +++ b/examples/middlewares/sessionid/main.go @@ -8,6 +8,7 @@ import ( keelhttp "github.com/foomo/keel/net/http" "github.com/foomo/keel/net/http/cookie" "github.com/foomo/keel/net/http/middleware" + "github.com/foomo/keel/service" ) func main() { @@ -44,7 +45,7 @@ func main() { }) svr.AddService( - keel.NewServiceHTTP(l, "demo", "localhost:8080", svs, + service.NewHTTP(l, "demo", "localhost:8080", svs, middleware.SessionID( // automatically set cookie if not exists middleware.SessionIDWithSetCookie(true), diff --git a/example/middlewares/skip/main.go b/examples/middlewares/skip/main.go similarity index 87% rename from example/middlewares/skip/main.go rename to examples/middlewares/skip/main.go index 9402df8..4d03e13 100644 --- a/example/middlewares/skip/main.go +++ b/examples/middlewares/skip/main.go @@ -3,6 +3,7 @@ package main import ( "net/http" + "github.com/foomo/keel/service" "go.uber.org/zap" "github.com/foomo/keel" @@ -28,7 +29,7 @@ func main() { svr.AddServices( // with URI blacklist - keel.NewServiceHTTP(l, "demo", "localhost:8080", svs, + service.NewHTTP(l, "demo", "localhost:8080", svs, middleware.Skip( func(l *zap.Logger, name string, next http.Handler) http.Handler { return http.NotFoundHandler() @@ -38,7 +39,7 @@ func main() { ), // with URI whitelist - keel.NewServiceHTTP(l, "demo", ":8081", svs, + service.NewHTTP(l, "demo", "localhost:8081", svs, middleware.Skip( func(l *zap.Logger, name string, next http.Handler) http.Handler { return http.NotFoundHandler() diff --git a/example/middlewares/telemetry/main.go b/examples/middlewares/telemetry/main.go similarity index 86% rename from example/middlewares/telemetry/main.go rename to examples/middlewares/telemetry/main.go index 14f90b4..d43e2ec 100644 --- a/example/middlewares/telemetry/main.go +++ b/examples/middlewares/telemetry/main.go @@ -5,6 +5,7 @@ import ( "github.com/foomo/keel" "github.com/foomo/keel/net/http/middleware" + "github.com/foomo/keel/service" ) func main() { @@ -23,7 +24,7 @@ func main() { }) svr.AddService( - keel.NewServiceHTTP(l, "demo", "localhost:8080", svs, + service.NewHTTP(l, "demo", "localhost:8080", svs, middleware.Telemetry( middleware.TelemetryWithInjectPropagationHeader(true), ), diff --git a/example/middlewares/tokenauthfromcookie/main.go b/examples/middlewares/tokenauthfromcookie/main.go similarity index 88% rename from example/middlewares/tokenauthfromcookie/main.go rename to examples/middlewares/tokenauthfromcookie/main.go index 1020c56..eb1bdc0 100644 --- a/example/middlewares/tokenauthfromcookie/main.go +++ b/examples/middlewares/tokenauthfromcookie/main.go @@ -5,6 +5,7 @@ import ( "github.com/foomo/keel" "github.com/foomo/keel/net/http/middleware" + "github.com/foomo/keel/service" ) func main() { @@ -26,7 +27,7 @@ func main() { tokenProvider := middleware.CookieTokenProvider("keel-token") svr.AddService( - keel.NewServiceHTTP(l, "demo", "localhost:8080", svs, + service.NewHTTP(l, "demo", "localhost:8080", svs, middleware.TokenAuth( token, middleware.TokenAuthWithTokenProvider(tokenProvider), diff --git a/example/middlewares/tokenauthfromheader/main.go b/examples/middlewares/tokenauthfromheader/main.go similarity index 89% rename from example/middlewares/tokenauthfromheader/main.go rename to examples/middlewares/tokenauthfromheader/main.go index 1e14572..b3e8717 100644 --- a/example/middlewares/tokenauthfromheader/main.go +++ b/examples/middlewares/tokenauthfromheader/main.go @@ -5,6 +5,7 @@ import ( "github.com/foomo/keel" "github.com/foomo/keel/net/http/middleware" + "github.com/foomo/keel/service" ) func main() { @@ -29,7 +30,7 @@ func main() { ) svr.AddService( - keel.NewServiceHTTP(l, "demo", "localhost:8080", svs, + service.NewHTTP(l, "demo", "localhost:8080", svs, middleware.TokenAuth( token, middleware.TokenAuthWithTokenProvider(tokenProvider), diff --git a/example/persistence/mongo/main.go b/examples/persistence/mongo/main.go similarity index 92% rename from example/persistence/mongo/main.go rename to examples/persistence/mongo/main.go index 8ecdf80..b8efc8e 100644 --- a/example/persistence/mongo/main.go +++ b/examples/persistence/mongo/main.go @@ -12,8 +12,8 @@ import ( "go.mongodb.org/mongo-driver/mongo/options" "github.com/foomo/keel" - "github.com/foomo/keel/example/persistence/mongo/repository" - "github.com/foomo/keel/example/persistence/mongo/store" + "github.com/foomo/keel/examples/persistence/mongo/repository" + "github.com/foomo/keel/examples/persistence/mongo/store" "github.com/foomo/keel/log" keelmongo "github.com/foomo/keel/persistence/mongo" ) @@ -26,8 +26,9 @@ func main() { l := svr.Logger() cDateTime := &store.DateTimeCodec{} - rb := bson.NewRegistryBuilder() - rb.RegisterCodec(store.TDateTime, cDateTime) + rb := bson.NewRegistry() + rb.RegisterTypeEncoder(store.TDateTime, cDateTime) + rb.RegisterTypeDecoder(store.TDateTime, cDateTime) // create persistor persistor, err := keelmongo.New( @@ -36,7 +37,9 @@ func main() { // enable telemetry (enabled by default) keelmongo.WithOtelEnabled(true), keelmongo.WithClientOptions( - options.Client().SetRegistry(rb.Build()), + func(clientOptions *options.ClientOptions) { + clientOptions.SetRegistry(rb) + }, ), ) // use log must helper to exit on error diff --git a/example/persistence/mongo/repository/dummy.go b/examples/persistence/mongo/repository/dummy.go similarity index 95% rename from example/persistence/mongo/repository/dummy.go rename to examples/persistence/mongo/repository/dummy.go index ca10ac0..3b60e7e 100644 --- a/example/persistence/mongo/repository/dummy.go +++ b/examples/persistence/mongo/repository/dummy.go @@ -5,7 +5,7 @@ import ( "go.mongodb.org/mongo-driver/mongo/options" - "github.com/foomo/keel/example/persistence/mongo/store" + "github.com/foomo/keel/examples/persistence/mongo/store" keelmongo "github.com/foomo/keel/persistence/mongo" ) diff --git a/example/persistence/mongo/store/codec.go b/examples/persistence/mongo/store/codec.go similarity index 100% rename from example/persistence/mongo/store/codec.go rename to examples/persistence/mongo/store/codec.go diff --git a/example/persistence/mongo/store/datetime.go b/examples/persistence/mongo/store/datetime.go similarity index 100% rename from example/persistence/mongo/store/datetime.go rename to examples/persistence/mongo/store/datetime.go diff --git a/example/persistence/mongo/store/dummy.go b/examples/persistence/mongo/store/dummy.go similarity index 100% rename from example/persistence/mongo/store/dummy.go rename to examples/persistence/mongo/store/dummy.go diff --git a/example/persistence/mongo/store/entity.go b/examples/persistence/mongo/store/entity.go similarity index 100% rename from example/persistence/mongo/store/entity.go rename to examples/persistence/mongo/store/entity.go diff --git a/example/persistence/mongo/store/entitywithtimestamps.go b/examples/persistence/mongo/store/entitywithtimestamps.go similarity index 100% rename from example/persistence/mongo/store/entitywithtimestamps.go rename to examples/persistence/mongo/store/entitywithtimestamps.go diff --git a/example/persistence/mongo/store/entitywithversions.go b/examples/persistence/mongo/store/entitywithversions.go similarity index 100% rename from example/persistence/mongo/store/entitywithversions.go rename to examples/persistence/mongo/store/entitywithversions.go diff --git a/example/persistence/postgres/main.go b/examples/persistence/postgres/main.go similarity index 94% rename from example/persistence/postgres/main.go rename to examples/persistence/postgres/main.go index eab72c8..ba18908 100644 --- a/example/persistence/postgres/main.go +++ b/examples/persistence/postgres/main.go @@ -4,7 +4,7 @@ import ( "github.com/davecgh/go-spew/spew" "github.com/foomo/keel" - "github.com/foomo/keel/example/persistence/postgres/repository" + "github.com/foomo/keel/examples/persistence/postgres/repository" "github.com/foomo/keel/log" keelpostgres "github.com/foomo/keel/persistence/postgres" ) diff --git a/example/persistence/postgres/repository/dummy.go b/examples/persistence/postgres/repository/dummy.go similarity index 100% rename from example/persistence/postgres/repository/dummy.go rename to examples/persistence/postgres/repository/dummy.go diff --git a/example/remoteconfig/main.go b/examples/remoteconfig/main.go similarity index 81% rename from example/remoteconfig/main.go rename to examples/remoteconfig/main.go index 6cdddc9..7607b7e 100644 --- a/example/remoteconfig/main.go +++ b/examples/remoteconfig/main.go @@ -6,6 +6,7 @@ import ( "github.com/foomo/keel" "github.com/foomo/keel/config" + "github.com/foomo/keel/service" ) func main() { @@ -26,13 +27,13 @@ func main() { fmt.Println("initial foo:", fooFn()) //nolint:forbidigo // watch changes - config.WatchString(svr.CancelContext(), fooFn, func(s string) { + config.WatchString(svr.Context(), fooFn, func(s string) { fmt.Println("change foo:", fooFn()) //nolint:forbidigo }) ch := make(chan string) // watch changes - config.WatchStringChan(svr.CancelContext(), fooFn, ch) + config.WatchStringChan(svr.Context(), fooFn, ch) go func(ch chan string) { for { value := <-ch @@ -42,7 +43,7 @@ func main() { // curl localhost:8080 svr.AddService( - keel.NewServiceHTTP(l, "demo", "localhost:8080", http.HandlerFunc( + service.NewHTTP(l, "demo", "localhost:8080", http.HandlerFunc( func(w http.ResponseWriter, r *http.Request) { fmt.Println("current foo:", fooFn()) //nolint:forbidigo }), diff --git a/example/roundtripwares/logger/client.go b/examples/roundtripwares/logger/client.go similarity index 100% rename from example/roundtripwares/logger/client.go rename to examples/roundtripwares/logger/client.go diff --git a/example/roundtripwares/logger/main.go b/examples/roundtripwares/logger/main.go similarity index 100% rename from example/roundtripwares/logger/main.go rename to examples/roundtripwares/logger/main.go diff --git a/example/roundtripwares/logger/server.go b/examples/roundtripwares/logger/server.go similarity index 85% rename from example/roundtripwares/logger/server.go rename to examples/roundtripwares/logger/server.go index 676f4b2..5262ee0 100644 --- a/example/roundtripwares/logger/server.go +++ b/examples/roundtripwares/logger/server.go @@ -4,6 +4,7 @@ import ( "net/http" "github.com/foomo/keel" + "github.com/foomo/keel/service" ) func server() { @@ -26,7 +27,7 @@ func server() { }) svr.AddService( - keel.NewServiceHTTP(l, "demo", "localhost:8080", svs), + service.NewHTTP(l, "demo", "localhost:8080", svs), ) svr.Run() diff --git a/example/roundtripwares/requestid/main.go b/examples/roundtripwares/requestid/main.go similarity index 95% rename from example/roundtripwares/requestid/main.go rename to examples/roundtripwares/requestid/main.go index a928892..7fea6d8 100644 --- a/example/roundtripwares/requestid/main.go +++ b/examples/roundtripwares/requestid/main.go @@ -8,6 +8,7 @@ import ( keelhttp "github.com/foomo/keel/net/http" "github.com/foomo/keel/net/http/middleware" "github.com/foomo/keel/net/http/roundtripware" + "github.com/foomo/keel/service" httputils "github.com/foomo/keel/utils/net/http" ) @@ -52,7 +53,7 @@ func main() { }) svr.AddService( - keel.NewServiceHTTP(l, "demo", "localhost:8080", svs, + service.NewHTTP(l, "demo", "localhost:8080", svs, // add middleware middleware.RequestID(), // add middleware diff --git a/example/roundtripwares/retry/client.go b/examples/roundtripwares/retry/client.go similarity index 100% rename from example/roundtripwares/retry/client.go rename to examples/roundtripwares/retry/client.go diff --git a/example/roundtripwares/retry/main.go b/examples/roundtripwares/retry/main.go similarity index 100% rename from example/roundtripwares/retry/main.go rename to examples/roundtripwares/retry/main.go diff --git a/example/roundtripwares/retry/server.go b/examples/roundtripwares/retry/server.go similarity index 85% rename from example/roundtripwares/retry/server.go rename to examples/roundtripwares/retry/server.go index 70a270d..8133f94 100644 --- a/example/roundtripwares/retry/server.go +++ b/examples/roundtripwares/retry/server.go @@ -4,6 +4,7 @@ import ( "net/http" "github.com/foomo/keel" + "github.com/foomo/keel/service" ) func server() { @@ -27,7 +28,7 @@ func server() { }) svr.AddService( - keel.NewServiceHTTP(l, "demo", "localhost:8080", svs), + service.NewHTTP(l, "demo", "localhost:8080", svs), ) svr.Run() diff --git a/example/serviceenabler/main.go b/examples/serviceenabler/main.go similarity index 83% rename from example/serviceenabler/main.go rename to examples/serviceenabler/main.go index 289941e..592685d 100644 --- a/example/serviceenabler/main.go +++ b/examples/serviceenabler/main.go @@ -5,6 +5,7 @@ import ( "github.com/foomo/keel" "github.com/foomo/keel/config" + "github.com/foomo/keel/service" ) func main() { @@ -23,7 +24,7 @@ func main() { }) svr.AddServices( - keel.NewServiceHTTP(l, "demo", "localhost:8080", + service.NewHTTP(l, "demo", "localhost:8080", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { c.Set("service.enabled", !enabled()) w.WriteHeader(http.StatusOK) @@ -32,7 +33,7 @@ func main() { ), keel.NewServiceEnabler(l, "service-enabler", func() keel.Service { - return keel.NewServiceHTTP(l, "service", "localhost:8081", svs) + return service.NewHTTP(l, "service", "localhost:8081", svs) }, enabled, ), diff --git a/example/services/main.go b/examples/services/main.go similarity index 74% rename from example/services/main.go rename to examples/services/main.go index 2860b7a..27c7a75 100644 --- a/example/services/main.go +++ b/examples/services/main.go @@ -1,16 +1,19 @@ package main import ( - "net/http" "os" "github.com/foomo/keel" + "github.com/foomo/keel/service" ) func main() { + service.DefaultHTTPPrometheusAddr = "localhost:9200" + // you can override the below config by settings env vars _ = os.Setenv("SERVICE_ZAP_ENABLED", "true") _ = os.Setenv("SERVICE_VIPER_ENABLED", "true") + _ = os.Setenv("SERVICE_PPROF_ENABLED", "true") _ = os.Setenv("SERVICE_PROMETHEUS_ENABLED", "true") svr := keel.NewServer( @@ -23,25 +26,16 @@ func main() { // add prometheus service listening on 0.0.0.0:9200 // allows you to collect prometheus metrics: GET 0.0.0.0:9200/metrics keel.WithHTTPPrometheusService(false), + // add go pprof service listening on 0.0.0.0:6060 + // allows you to use go tool pprof: GET 0.0.0.0:6060/debug/pprof + keel.WithHTTPPProfService(false), ) - l := svr.Logger() - // alternatively you can add them manually // svr.AddServices(keel.NewDefaultServiceHTTPZap()) // svr.AddServices(keel.NewDefaultServiceHTTPViper()) + // svr.AddServices(keel.NewDefaultServiceHTTPPProf()) // svr.AddServices(keel.NewDefaultServiceHTTPPrometheus()) - // create demo service - svs := http.NewServeMux() - svs.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(http.StatusOK) - _, _ = w.Write([]byte("OK")) - }) - - svr.AddService( - keel.NewServiceHTTP(l, "demo", "localhost:8080", svs), - ) - svr.Run() } diff --git a/example/stream/jetstream/main.go b/examples/stream/jetstream/main.go similarity index 96% rename from example/stream/jetstream/main.go rename to examples/stream/jetstream/main.go index 40e6e1f..b7f88a8 100644 --- a/example/stream/jetstream/main.go +++ b/examples/stream/jetstream/main.go @@ -5,6 +5,7 @@ import ( "net/http" "time" + "github.com/foomo/keel/service" "github.com/nats-io/nats.go" "github.com/pkg/errors" "go.uber.org/zap" @@ -89,7 +90,7 @@ func main() { svr.AddClosers(subscription, stream) svr.AddService( - keel.NewServiceHTTP(l, "demo", "localhost:8080", svs), + service.NewHTTP(l, "demo", "localhost:8080", svs), ) svr.Run() diff --git a/example/stream/jetstreamraw/main.go b/examples/stream/jetstreamraw/main.go similarity index 95% rename from example/stream/jetstreamraw/main.go rename to examples/stream/jetstreamraw/main.go index 710a89c..b46a635 100644 --- a/example/stream/jetstreamraw/main.go +++ b/examples/stream/jetstreamraw/main.go @@ -4,6 +4,7 @@ import ( "net/http" "time" + "github.com/foomo/keel/service" "github.com/nats-io/nats.go" "github.com/foomo/keel" @@ -73,7 +74,7 @@ func main() { svr.AddClosers(subscription, stream.Conn()) svr.AddService( - keel.NewServiceHTTP(l, "demo", "localhost:8080", svs), + service.NewHTTP(l, "demo", "localhost:8080", svs), ) svr.Run() diff --git a/example/telemetry/main.go b/examples/telemetry/main.go similarity index 52% rename from example/telemetry/main.go rename to examples/telemetry/main.go index fa4f37d..a2c6f62 100644 --- a/example/telemetry/main.go +++ b/examples/telemetry/main.go @@ -3,15 +3,27 @@ package main import ( "math/rand" "net/http" + "time" + "github.com/foomo/keel/service" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promauto" "go.opentelemetry.io/otel/attribute" - "go.opentelemetry.io/otel/metric/instrument" "github.com/foomo/keel" "github.com/foomo/keel/log" "github.com/foomo/keel/net/http/middleware" + "go.opentelemetry.io/otel/metric" + "go.opentelemetry.io/otel/trace" ) +var metricRequestLatency = promauto.NewHistogram(prometheus.HistogramOpts{ + Namespace: "demo", + Name: "request_latency_seconds", + Help: "Request Latency", + Buckets: prometheus.ExponentialBuckets(.0001, 2, 50), +}) + func main() { // Run this example with the following env vars: // @@ -45,54 +57,76 @@ func main() { svs := http.NewServeMux() { // counter - counter, err := meter.SyncInt64().Counter( + counter, err := meter.Int64Counter( "a.counter", - instrument.WithDescription("Count things"), + metric.WithDescription("Count things"), ) log.Must(l, err, "failed to create counter meter") svs.HandleFunc("/count", func(w http.ResponseWriter, r *http.Request) { - counter.Add(r.Context(), 1, attribute.String("key", "value")) + counter.Add(r.Context(), 1, metric.WithAttributes(attribute.String("key", "value"))) w.WriteHeader(http.StatusOK) _, _ = w.Write([]byte("OK!")) }) } + promauto.NewCounter(prometheus.CounterOpts{ + Namespace: "foo", + Subsystem: "", + Name: "bar", + Help: "blubb", + ConstLabels: nil, + }) + { // up down - upDown, err := meter.SyncInt64().UpDownCounter( + upDown, err := meter.Int64UpDownCounter( "a.updown", - instrument.WithDescription("Up down values"), + metric.WithDescription("Up down values"), ) log.Must(l, err, "failed to create up down meter") svs.HandleFunc("/up", func(w http.ResponseWriter, r *http.Request) { - upDown.Add(r.Context(), 1, attribute.String("key", "value")) + upDown.Add(r.Context(), 1, metric.WithAttributes(attribute.String("key", "value"))) w.WriteHeader(http.StatusOK) _, _ = w.Write([]byte("OK!")) }) svs.HandleFunc("/down", func(w http.ResponseWriter, r *http.Request) { - upDown.Add(r.Context(), -1, attribute.String("key", "value")) + upDown.Add(r.Context(), -1, metric.WithAttributes(attribute.String("key", "value"))) w.WriteHeader(http.StatusOK) _, _ = w.Write([]byte("OK!")) }) } { // histogram - histogram, err := meter.SyncInt64().Histogram( + histogram, err := meter.Int64Histogram( "a.histogram", - instrument.WithDescription("Up down values"), + metric.WithDescription("Up down values"), + metric.WithUnit("ms"), ) log.Must(l, err, "failed to create up down meter") svs.HandleFunc("/histogram", func(w http.ResponseWriter, r *http.Request) { - histogram.Record(r.Context(), int64(rand.Int()), attribute.String("key", "value")) + start := time.Now() + time.Sleep(time.Second) + traceID := trace.SpanContextFromContext(r.Context()) + histogram.Record(r.Context(), int64(rand.Int()), + metric.WithAttributes( + attribute.String("key", "value"), + attribute.String("traceID", traceID.TraceID().String()), + ), + ) + + metricRequestLatency.(prometheus.ExemplarObserver).ObserveWithExemplar( + time.Since(start).Seconds(), prometheus.Labels{"traceID": traceID.TraceID().String()}, + ) + w.WriteHeader(http.StatusOK) _, _ = w.Write([]byte("OK!")) }) } svr.AddService( - keel.NewServiceHTTP(l, "demo", "localhost:8080", svs, + service.NewHTTP(l, "demo", "localhost:8080", svs, middleware.Telemetry(), middleware.Recover(), ), diff --git a/go.mod b/go.mod index 7a3c691..dfd0b9e 100644 --- a/go.mod +++ b/go.mod @@ -1,64 +1,64 @@ module github.com/foomo/keel -go 1.19 +go 1.21 require ( github.com/avast/retry-go v3.0.0+incompatible - github.com/foomo/gotsrpc/v2 v2.6.2 - github.com/go-logr/logr v1.2.3 + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc + github.com/fbiville/markdown-table-formatter v0.3.0 + github.com/foomo/gotsrpc/v2 v2.8.1 + github.com/go-logr/logr v1.4.1 github.com/golang-jwt/jwt v3.2.2+incompatible - github.com/google/uuid v1.3.0 - github.com/lib/pq v1.10.7 + github.com/google/uuid v1.6.0 + github.com/lib/pq v1.10.9 github.com/mitchellh/mapstructure v1.5.0 - github.com/nats-io/nats.go v1.24.0 + github.com/nats-io/nats.go v1.34.1 github.com/pkg/errors v0.9.1 - github.com/prometheus/client_golang v1.14.0 + github.com/prometheus/client_golang v1.19.0 github.com/sony/gobreaker v0.5.0 - github.com/spf13/viper v1.15.0 - github.com/stretchr/testify v1.8.2 + github.com/spf13/viper v1.18.2 + github.com/stretchr/testify v1.9.0 github.com/tidwall/pretty v1.2.1 - github.com/tinylib/msgp v1.1.8 - go.mongodb.org/mongo-driver v1.11.3 - go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo v0.32.0 - go.opentelemetry.io/contrib/instrumentation/host v0.32.0 - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.32.0 - go.opentelemetry.io/contrib/instrumentation/runtime v0.32.0 - go.opentelemetry.io/otel v1.7.0 - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.7.0 - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.7.0 - go.opentelemetry.io/otel/exporters/prometheus v0.30.0 - go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v0.30.0 - go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.7.0 - go.opentelemetry.io/otel/metric v0.30.0 - go.opentelemetry.io/otel/sdk v1.7.0 - go.opentelemetry.io/otel/sdk/metric v0.30.0 - go.opentelemetry.io/otel/trace v1.7.0 + github.com/tinylib/msgp v1.1.9 + go.mongodb.org/mongo-driver v1.15.0 + go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo v0.51.0 + go.opentelemetry.io/contrib/instrumentation/host v0.51.0 + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.51.0 + go.opentelemetry.io/contrib/instrumentation/runtime v0.51.0 + go.opentelemetry.io/otel v1.26.0 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.26.0 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.26.0 + go.opentelemetry.io/otel/exporters/prometheus v0.48.0 + go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.26.0 + go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.26.0 + go.opentelemetry.io/otel/metric v1.26.0 + go.opentelemetry.io/otel/sdk v1.26.0 + go.opentelemetry.io/otel/sdk/metric v1.26.0 + go.opentelemetry.io/otel/trace v1.26.0 go.temporal.io/api v1.8.0 go.temporal.io/sdk v1.15.0 go.temporal.io/sdk/contrib/opentelemetry v0.1.0 - go.uber.org/zap v1.24.0 - golang.org/x/crypto v0.7.0 - golang.org/x/sync v0.1.0 + go.uber.org/zap v1.27.0 + golang.org/x/crypto v0.22.0 + golang.org/x/sync v0.7.0 ) require ( - cloud.google.com/go v0.107.0 // indirect - cloud.google.com/go/compute v1.15.1 // indirect + cloud.google.com/go v0.112.0 // indirect + cloud.google.com/go/compute v1.24.0 // indirect cloud.google.com/go/compute/metadata v0.2.3 // indirect - cloud.google.com/go/firestore v1.9.0 // indirect - cloud.google.com/go/longrunning v0.3.0 // indirect - github.com/armon/go-metrics v0.4.0 // indirect - github.com/benbjohnson/clock v1.3.0 // indirect + cloud.google.com/go/firestore v1.14.0 // indirect + cloud.google.com/go/longrunning v0.5.5 // indirect + github.com/armon/go-metrics v0.4.1 // indirect github.com/beorn7/perks v1.0.1 // indirect - github.com/cenkalti/backoff/v4 v4.1.3 // indirect + github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/coreos/go-semver v0.3.0 // indirect github.com/coreos/go-systemd/v22 v22.3.2 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect github.com/facebookgo/clock v0.0.0-20150410010913-600d898af40a // indirect - github.com/fatih/color v1.13.0 // indirect - github.com/felixge/httpsnoop v1.0.2 // indirect - github.com/fsnotify/fsnotify v1.6.0 // indirect + github.com/fatih/color v1.14.1 // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect + github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.2.6 // indirect github.com/gogo/googleapis v1.4.1 // indirect @@ -66,16 +66,16 @@ require ( github.com/gogo/status v1.1.0 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/mock v1.6.0 // indirect - github.com/golang/protobuf v1.5.2 // indirect - github.com/golang/snappy v0.0.3 // indirect - github.com/google/go-cmp v0.5.9 // indirect - github.com/googleapis/enterprise-certificate-proxy v0.2.1 // indirect - github.com/googleapis/gax-go/v2 v2.7.0 // indirect + github.com/golang/protobuf v1.5.4 // indirect + github.com/golang/snappy v0.0.4 // 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.0 // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0 // indirect - github.com/hashicorp/consul/api v1.18.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1 // indirect + github.com/hashicorp/consul/api v1.25.1 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect - github.com/hashicorp/go-hclog v1.2.0 // indirect + github.com/hashicorp/go-hclog v1.5.0 // indirect github.com/hashicorp/go-immutable-radix v1.3.1 // indirect github.com/hashicorp/go-rootcerts v1.0.2 // indirect github.com/hashicorp/golang-lru v0.5.4 // indirect @@ -83,12 +83,11 @@ require ( github.com/hashicorp/serf v0.10.1 // indirect github.com/iancoleman/strcase v0.2.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/compress v1.14.4 // indirect + github.com/klauspost/compress v1.17.2 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/magiconair/properties v1.8.7 // indirect - github.com/mattn/go-colorable v0.1.12 // indirect - github.com/mattn/go-isatty v0.0.14 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect @@ -97,56 +96,59 @@ require ( github.com/nats-io/nkeys v0.3.0 // indirect github.com/nats-io/nuid v1.0.1 // indirect github.com/pborman/uuid v1.2.1 // indirect - github.com/pelletier/go-toml/v2 v2.0.6 // indirect + github.com/pelletier/go-toml/v2 v2.1.0 // indirect github.com/philhofer/fwd v1.1.2 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect - github.com/prometheus/client_model v0.3.0 // indirect - github.com/prometheus/common v0.37.0 // indirect - github.com/prometheus/procfs v0.8.0 // indirect + github.com/prometheus/client_model v0.6.1 // indirect + github.com/prometheus/common v0.48.0 // indirect + github.com/prometheus/procfs v0.12.0 // indirect github.com/robfig/cron v1.2.0 // indirect - github.com/sagikazarmark/crypt v0.9.0 // indirect - github.com/shirou/gopsutil/v3 v3.22.3 // indirect - github.com/spf13/afero v1.9.3 // indirect - github.com/spf13/cast v1.5.0 // indirect - github.com/spf13/jwalterweatherman v1.1.0 // indirect + github.com/sagikazarmark/crypt v0.17.0 // indirect + github.com/sagikazarmark/locafero v0.4.0 // indirect + github.com/sagikazarmark/slog-shim v0.1.0 // indirect + github.com/shirou/gopsutil/v3 v3.24.3 // indirect + github.com/shoenig/go-m1cpu v0.1.6 // indirect + github.com/sourcegraph/conc v0.3.0 // indirect + github.com/spf13/afero v1.11.0 // indirect + github.com/spf13/cast v1.6.0 // indirect github.com/spf13/pflag v1.0.5 // indirect - github.com/stretchr/objx v0.5.0 // indirect - github.com/subosito/gotenv v1.4.2 // indirect - github.com/tklauser/go-sysconf v0.3.10 // indirect - github.com/tklauser/numcpus v0.4.0 // indirect - github.com/ugorji/go/codec v1.2.7 // indirect + github.com/stretchr/objx v0.5.2 // indirect + github.com/subosito/gotenv v1.6.0 // indirect + github.com/tklauser/go-sysconf v0.3.12 // indirect + github.com/tklauser/numcpus v0.6.1 // indirect + github.com/ugorji/go/codec v1.2.12 // indirect github.com/xdg-go/pbkdf2 v1.0.0 // indirect - github.com/xdg-go/scram v1.1.1 // indirect - github.com/xdg-go/stringprep v1.0.3 // indirect + github.com/xdg-go/scram v1.1.2 // indirect + github.com/xdg-go/stringprep v1.0.4 // indirect github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect - github.com/yusufpapurcu/wmi v1.2.2 // indirect - go.etcd.io/etcd/api/v3 v3.5.6 // indirect - go.etcd.io/etcd/client/pkg/v3 v3.5.6 // indirect - go.etcd.io/etcd/client/v2 v2.305.6 // indirect - go.etcd.io/etcd/client/v3 v3.5.6 // indirect + github.com/yusufpapurcu/wmi v1.2.4 // indirect + go.etcd.io/etcd/api/v3 v3.5.10 // indirect + go.etcd.io/etcd/client/pkg/v3 v3.5.10 // indirect + go.etcd.io/etcd/client/v2 v2.305.10 // indirect + go.etcd.io/etcd/client/v3 v3.5.10 // indirect go.opencensus.io v0.24.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.7.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.7.0 // indirect - go.opentelemetry.io/proto/otlp v0.16.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.47.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.26.0 // indirect + go.opentelemetry.io/proto/otlp v1.2.0 // indirect go.uber.org/atomic v1.9.0 // indirect - go.uber.org/multierr v1.8.0 // indirect - golang.org/x/mod v0.8.0 // indirect - golang.org/x/net v0.8.0 // indirect - golang.org/x/oauth2 v0.4.0 // indirect - golang.org/x/sys v0.6.0 // indirect - golang.org/x/text v0.8.0 // indirect - golang.org/x/time v0.1.0 // indirect - golang.org/x/tools v0.6.0 // indirect - golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect - google.golang.org/api v0.107.0 // indirect - google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f // indirect - google.golang.org/grpc v1.53.0 // indirect - google.golang.org/protobuf v1.28.1 // indirect + go.uber.org/multierr v1.10.0 // indirect + golang.org/x/exp v0.0.0-20231127185646-65229373498e // indirect + golang.org/x/mod v0.16.0 // indirect + golang.org/x/net v0.23.0 // indirect + golang.org/x/oauth2 v0.17.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 + golang.org/x/tools v0.19.0 // indirect + google.golang.org/api v0.162.0 // indirect + google.golang.org/appengine v1.6.8 // indirect + google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240304212257-790db918fca8 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda // indirect + google.golang.org/grpc v1.63.2 // indirect + google.golang.org/protobuf v1.33.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) - -replace go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.32.0 => github.com/foomo/opentelemetry-go-contrib/instrumentation/net/http/otelhttp v0.32.1-0.20220517120905-10e2553b9bac diff --git a/go.sum b/go.sum index 7958d1e..3c24ad7 100644 --- a/go.sum +++ b/go.sum @@ -1,148 +1,98 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= -cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= -cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= -cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= -cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= -cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= -cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= -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.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= -cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= -cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= -cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= -cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= -cloud.google.com/go v0.107.0 h1:qkj22L7bgkl6vIeZDlOY2po43Mx/TIa2Wsa7VR+PEww= -cloud.google.com/go v0.107.0/go.mod h1:wpc2eNrD7hXUTy8EKS10jkxpZBjASrORK7goS+3YX2I= -cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= -cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= -cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= -cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= -cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= -cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/compute v1.15.1 h1:7UGq3QknM33pw5xATlpzeoomNxsacIVvTqTTvbfajmE= -cloud.google.com/go/compute v1.15.1/go.mod h1:bjjoF/NtFUrkD/urWfdHaKuOPDR5nWIs63rR+SXhcpA= +cloud.google.com/go v0.112.0 h1:tpFCD7hpHFlQ8yPwT3x+QeXqc2T6+n6T+hmABHfDUSM= +cloud.google.com/go v0.112.0/go.mod h1:3jEEVwZ/MHU4djK5t5RHuKOA/GbLddgTdVubX1qnPD4= +cloud.google.com/go/compute v1.24.0 h1:phWcR2eWzRJaL/kOiJwfFsPs4BaKq1j6vnpZrc1YlVg= +cloud.google.com/go/compute v1.24.0/go.mod h1:kw1/T+h/+tK2LJK0wiPPx1intgdAM3j/g3hFDlscY40= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= -cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= -cloud.google.com/go/firestore v1.9.0 h1:IBlRyxgGySXu5VuW0RgGFlTtLukSnNkpDiEOMkQkmpA= -cloud.google.com/go/firestore v1.9.0/go.mod h1:HMkjKHNTtRyZNiMzu7YAsLr9K3X2udY2AMwDaMEQiiE= -cloud.google.com/go/longrunning v0.3.0 h1:NjljC+FYPV3uh5/OwWT6pVU+doBqMg2x/rZlE+CamDs= -cloud.google.com/go/longrunning v0.3.0/go.mod h1:qth9Y41RRSUE69rDcOn6DdK3HfQfsUI0YSmW3iIlLJc= -cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= -cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= -cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= -cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= -cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= -cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= -cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= -cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= -cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= -cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +cloud.google.com/go/firestore v1.14.0 h1:8aLcKnMPoldYU3YHgu4t2exrKhLQkqaXAGqT0ljrFVw= +cloud.google.com/go/firestore v1.14.0/go.mod h1:96MVaHLsEhbvkBEdZgfN+AS/GIkco1LRpH9Xp9YZfzQ= +cloud.google.com/go/longrunning v0.5.5 h1:GOE6pZFdSrTb4KAiKnXsJBtlE6mEyaW44oKyMILWnOg= +cloud.google.com/go/longrunning v0.5.5/go.mod h1:WV2LAxD8/rg5Z1cNW6FJ/ZpX4E4VnDnoTk0yawPBB7s= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= -github.com/armon/go-metrics v0.4.0 h1:yCQqn7dwca4ITXb+CbubHmedzaQYHhNhrEXLYUeEe8Q= -github.com/armon/go-metrics v0.4.0/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +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/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/avast/retry-go v3.0.0+incompatible h1:4SOWQ7Qs+oroOTQOYnAHqelpCO0biHSxpiH9JdtuBj0= github.com/avast/retry-go v3.0.0+incompatible/go.mod h1:XtSnn+n/sHqQIpZ10K1qAevBhOOCWBLXXy3hyiqqBrY= -github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= -github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= 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/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/cenkalti/backoff/v4 v4.1.3 h1:cFAlzYUlVYDysBEH2T5hyJZMh3+5+WCBvSnK6Q8UtC4= -github.com/cenkalti/backoff/v4 v4.1.3/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= +github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= +github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.1.2/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/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/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/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +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/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= -github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= -github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/envoyproxy/protoc-gen-validate v1.0.4 h1:gVPz/FMfvh57HdSJQyvBtF00j8JU4zdyUgIUNhlgg0A= +github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod h1:qys6tmnRsYrQqIhm2bvKZH4Blx/1gTIZ2UKVY1M+Yew= github.com/facebookgo/clock v0.0.0-20150410010913-600d898af40a h1:yDWHCSQ40h88yih2JAcL6Ls/kVkSE8GFACTGVnMPruw= github.com/facebookgo/clock v0.0.0-20150410010913-600d898af40a/go.mod h1:7Ga40egUymuWXxAe151lTNnCv97MddSOVsjpPPkityA= 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 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= -github.com/felixge/httpsnoop v1.0.2 h1:+nS9g82KMXccJ/wp0zyRW9ZBHFETmMGtkk+2CTTrW4o= -github.com/felixge/httpsnoop v1.0.2/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/foomo/gotsrpc/v2 v2.6.2 h1:T4oJJCfnXW862ORBxKHTcg3d6oxFDfjFm2pIylkRFSA= -github.com/foomo/gotsrpc/v2 v2.6.2/go.mod h1:O9YjG1jCyseJLroaQQ24NLsuteCHL6wikIItXiv2I8w= -github.com/foomo/opentelemetry-go-contrib/instrumentation/net/http/otelhttp v0.32.1-0.20220517120905-10e2553b9bac h1:z8UXpHe2Hb9IzRawoeT49eUcxgGUY6g8Emj8TpUWl+4= -github.com/foomo/opentelemetry-go-contrib/instrumentation/net/http/otelhttp v0.32.1-0.20220517120905-10e2553b9bac/go.mod h1:5eCOqeGphOyz6TsY3ZDNjE33SM/TFAK3RGuCL2naTgY= -github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= -github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= -github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= +github.com/fatih/color v1.14.1 h1:qfhVLaG5s+nCROl1zJsZRxFeYrHLqWroPOQ8BWiNb4w= +github.com/fatih/color v1.14.1/go.mod h1:2oHN61fhTpgcxD3TSWCgKDiH1+x4OiDVVGH8WlgGZGg= +github.com/fbiville/markdown-table-formatter v0.3.0 h1:PIm1UNgJrFs8q1htGTw+wnnNYvwXQMMMIKNZop2SSho= +github.com/fbiville/markdown-table-formatter v0.3.0/go.mod h1:q89TDtSEVDdTaufgSbfHpNVdPU/bmfvqNkrC5HagmLY= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/foomo/gotsrpc/v2 v2.8.1 h1:UW2OMZ4WLZn2+nTbJuyhxsJuSGUm1AAHU8mTg5K51YI= +github.com/foomo/gotsrpc/v2 v2.8.1/go.mod h1:JEouU6o526p+RPTqM0DOS/AVr1CbE9DyCIJAAy/VuMI= +github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= +github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= -github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= -github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= -github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= +github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= @@ -161,28 +111,16 @@ github.com/gogo/status v1.1.0/go.mod h1:BFv9nrluPLmrS0EmGVvLaPNmRosr9KapBYd5/hpY github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ= -github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= -github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= -github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= 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= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= @@ -192,82 +130,64 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD 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 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.3 h1:fHPg5GQYlCeLIPB9BZqMVR5nR9A+IM5zcgeTdjMYmLA= -github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +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/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= -github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= +github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -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-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -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= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/enterprise-certificate-proxy v0.2.1 h1:RY7tHKZcRlk788d5WSo/e83gOyyy742E8GSs771ySpg= -github.com/googleapis/enterprise-certificate-proxy v0.2.1/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= -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.7.0 h1:IcsPKeInNvYi7eqSaDjiZqDDKu5rsmunY0Y1YupQSSQ= -github.com/googleapis/gax-go/v2 v2.7.0/go.mod h1:TEop28CZZQ2y+c0VxMUmu1lV+fQx57QpBWsYpwqHJx8= -github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs= +github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= +github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas= +github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU= github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw= github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= -github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0 h1:BZHcxBETFHIdVyhyEfOvn/RdU/QGdLI4y34qQGjGWO0= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks= -github.com/hashicorp/consul/api v1.18.0 h1:R7PPNzTCeN6VuQNDwwhZWJvzCtGSrNpJqfb22h3yH9g= -github.com/hashicorp/consul/api v1.18.0/go.mod h1:owRRGJ9M5xReDC5nfT8FTJrNAPbT4NM6p/k+d03q2v4= -github.com/hashicorp/consul/sdk v0.13.0 h1:lce3nFlpv8humJL8rNrrGHYSKc3q+Kxfeg3Ii1m6ZWU= -github.com/hashicorp/consul/sdk v0.13.0/go.mod h1:0hs/l5fOVhJy/VdcoaNqUSi2AUs95eF5WKtv+EYIQqE= -github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1 h1:/c3QmbOGMGTOumP2iT/rCwB7b0QDGLKzqOmktBjT+Is= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1/go.mod h1:5SN9VR2LTsRFsrEC6FHgRbTWrTHu6tqPeKxEQv15giM= +github.com/hashicorp/consul/api v1.25.1 h1:CqrdhYzc8XZuPnhIYZWH45toM0LB9ZeYr/gvpLVI3PE= +github.com/hashicorp/consul/api v1.25.1/go.mod h1:iiLVwR/htV7mas/sy0O+XSuEnrdBUUydemjxcUrAt4g= +github.com/hashicorp/consul/sdk v0.14.1 h1:ZiwE2bKb+zro68sWzZ1SgHF3kRMBZ94TwOCFRF4ylPs= +github.com/hashicorp/consul/sdk v0.14.1/go.mod h1:vFt03juSzocLRFo59NkeQHHmQa6+g7oU0pfzdI1mUhg= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= -github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= -github.com/hashicorp/go-hclog v1.2.0 h1:La19f8d7WIlm4ogzNHB0JGqs5AUDAZ2UfCY4sJXcJdM= -github.com/hashicorp/go-hclog v1.2.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= -github.com/hashicorp/go-msgpack v0.5.3 h1:zKjpN5BK/P5lMYrLmBHdBULWbJ0XpYR+7NGzqkZzoD4= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-msgpack v0.5.5 h1:i9R9JSrqIz0QVLz3sz+i3YJdT7TTSLcfLLzJi9aZTuI= +github.com/hashicorp/go-msgpack v0.5.5/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= -github.com/hashicorp/go-multierror v1.1.0 h1:B9UzwGQJehnUY1yNrnwREHc3fGbC2xefo8g4TbElacI= github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= @@ -277,12 +197,11 @@ github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjG github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE= -github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-version v1.2.1 h1:zEfKbn2+PDgroKdiOzqiE8rsmLqU2uwi5PB5pBJ3TkI= github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= @@ -295,38 +214,26 @@ github.com/hashicorp/serf v0.10.1 h1:Z1H2J60yRKvfDYAOZLd2MU0ND4AH/WDz7xYHDWQsIPY github.com/hashicorp/serf v0.10.1/go.mod h1:yL2t6BqATOLGc5HF7qbFkTfXoPIY0WZdWHfEvMqbG+4= github.com/iancoleman/strcase v0.2.0 h1:05I4QRnGpI0m37iZQRuskXh+w77mr6Z41lwQzuHLwW0= github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= -github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -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.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= -github.com/klauspost/compress v1.14.4 h1:eijASRJcobkVtSt81Olfh7JX43osYLwy5krOJo6YEu4= -github.com/klauspost/compress v1.14.4/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/klauspost/compress v1.17.2 h1:RlWWUY/Dr4fL8qk9YG7DTZ7PDgME2V4csBXA8L/ixi4= +github.com/klauspost/compress v1.17.2/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw= -github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= +github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= @@ -335,28 +242,25 @@ github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaO github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40= github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= github.com/miekg/dns v1.1.41 h1:WMszZWJG0XmzbK9FEmzH2TVcqYzFesusSIB41b8KHxY= github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= -github.com/minio/highwayhash v1.0.2 h1:Aak5U0nElisjDCfPSG79Tgzkn2gl66NxOMspRrKnA/g= -github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= 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/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= 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/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -369,17 +273,12 @@ github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjY github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe h1:iruDEfMl2E6fbMZ9s0scYfZQ84/6SPL6zC8ACM2oIL0= github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/nats-io/jwt/v2 v2.2.1-0.20220113022732-58e87895b296 h1:vU9tpM3apjYlLLeY23zRWJ9Zktr5jp+mloR942LEOpY= -github.com/nats-io/nats-server/v2 v2.7.4 h1:c+BZJ3rGzUKCBIM4IXO8uNT2u1vajGbD1kPA6wqCEaM= -github.com/nats-io/nats-server/v2 v2.7.4/go.mod h1:1vZ2Nijh8tcyNe8BDVyTviCd9NYzRbubQYiEHsvOQWc= -github.com/nats-io/nats.go v1.24.0 h1:CRiD8L5GOQu/DcfkmgBcTTIQORMwizF+rPk6T0RaHVQ= -github.com/nats-io/nats.go v1.24.0/go.mod h1:dVQF+BK3SzUZpwyzHedXsvH3EO38aVKuOPkkHlv5hXA= -github.com/nats-io/nkeys v0.3.0 h1:cgM5tL53EvYRU+2YLXIK0G2mJtK12Ft9oeooSZMA2G8= -github.com/nats-io/nkeys v0.3.0/go.mod h1:gvUNGjVcM2IPr5rCsRsC6Wb3Hr2CQAm08dsxtV6A5y4= +github.com/nats-io/nats.go v1.34.1 h1:syWey5xaNHZgicYBemv0nohUPPmaLteiBEUT6Q5+F/4= +github.com/nats-io/nats.go v1.34.1/go.mod h1:Ubdu4Nh9exXdSz0RVWRFBbRfrbSxOYd26oF0wkWclB8= +github.com/nats-io/nkeys v0.4.7 h1:RwNJbbIdYCoClSDNY7QVKZlyb/wfT6ugvFCiKy6vDvI= +github.com/nats-io/nkeys v0.4.7/go.mod h1:kqXRgRDPlGy7nGaEDMuYzmiJCIAAWDK0IMBtDmGD0nc= github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= @@ -387,17 +286,17 @@ github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0Mw github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pborman/uuid v1.2.1 h1:+ZZIw58t/ozdjRaXh/3awHfmWRbzYxJoAdNJxe/3pvw= github.com/pborman/uuid v1.2.1/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= -github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvIwycIU= -github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek= +github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4= +github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= github.com/philhofer/fwd v1.1.2 h1:bnDivRJ1EWPjUIRXV5KfORO897HTbpFAQddBdE8t7Gw= github.com/philhofer/fwd v1.1.2/go.mod h1:qkPdfjR2SIEbspLqpe1tO4n5yICnr2DY7mqEx2tUTP0= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= @@ -405,168 +304,155 @@ github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:Om github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= -github.com/prometheus/client_golang v1.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.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= -github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw= -github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= +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_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.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= -github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= +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.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= -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.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= -github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE= -github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= +github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE= +github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= -github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo= -github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= +github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= +github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= github.com/robfig/cron v1.2.0 h1:ZjScXvvxeQ63Dbyxy76Fj3AT3Ut0aKsyd2/tl3DTMuQ= github.com/robfig/cron v1.2.0/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k= 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.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= +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/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/sagikazarmark/crypt v0.9.0 h1:fipzMFW34hFUEc4D7fsLQFtE7yElkpgyS2zruedRdZk= -github.com/sagikazarmark/crypt v0.9.0/go.mod h1:RnH7sEhxfdnPm1z+XMgSLjWTEIjyK4z2dw6+4vHTMuo= +github.com/sagikazarmark/crypt v0.17.0 h1:ZA/7pXyjkHoK4bW4mIdnCLvL8hd+Nrbiw7Dqk7D4qUk= +github.com/sagikazarmark/crypt v0.17.0/go.mod h1:SMtHTvdmsZMuY/bpZoqokSoChIrcJ/epOxZN58PbZDg= +github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ= +github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= +github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= +github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= 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/shirou/gopsutil/v3 v3.22.3 h1:UebRzEomgMpv61e3hgD1tGooqX5trFbdU/ehphbHd00= -github.com/shirou/gopsutil/v3 v3.22.3/go.mod h1:D01hZJ4pVHPpCTZ3m3T2+wDF2YAGfd+H4ifUguaQzHM= +github.com/shirou/gopsutil/v3 v3.24.3 h1:eoUGJSmdfLzJ3mxIhmOAhgKEKgQkeOwKpz1NbhVnuPE= +github.com/shirou/gopsutil/v3 v3.24.3/go.mod h1:JpND7O217xa72ewWz9zN2eIIkPWsDN/3pl0H8Qt0uwg= +github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= +github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= +github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU= +github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k= 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= github.com/sony/gobreaker v0.5.0 h1:dRCvqm0P490vZPmy7ppEk2qCnCieBooFJ+YoXGYB+yg= github.com/sony/gobreaker v0.5.0/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= +github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= +github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spf13/afero v1.9.3 h1:41FoI0fD7OR7mGcKE/aOiLkGreyf8ifIOQmJANWogMk= -github.com/spf13/afero v1.9.3/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= -github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= -github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= -github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= -github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= +github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= +github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= +github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= +github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.15.0 h1:js3yy885G8xwJa6iOISGFwd+qlUo5AvyXb7CiihdtiU= -github.com/spf13/viper v1.15.0/go.mod h1:fFcTBJxvhhzSJiZy8n+PeW6t8l+KeT/uTARa0jHOQLA= +github.com/spf13/viper v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ= +github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.3.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= -github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= -github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= -github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= +github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= -github.com/tinylib/msgp v1.1.8 h1:FCXC1xanKO4I8plpHGH2P7koL/RzZs12l/+r7vakfm0= -github.com/tinylib/msgp v1.1.8/go.mod h1:qkpG+2ldGg4xRFmx+jfTvZPxfGFhi64BcnL9vkCm/Tw= -github.com/tklauser/go-sysconf v0.3.10 h1:IJ1AZGZRWbY8T5Vfk04D9WOA5WSejdflXxP03OUqALw= -github.com/tklauser/go-sysconf v0.3.10/go.mod h1:C8XykCvCb+Gn0oNCWPIlcb0RuglQTYaQ2hGm7jmxEFk= -github.com/tklauser/numcpus v0.4.0 h1:E53Dm1HjH1/R2/aoCtXtPgzmElmn51aOkhCFSuZq//o= -github.com/tklauser/numcpus v0.4.0/go.mod h1:1+UI3pD8NW14VMwdgJNJ1ESk2UnwhAnz5hMwiKKqXCQ= +github.com/tinylib/msgp v1.1.9 h1:SHf3yoO2sGA0veCJeCBYLHuttAVFHGm2RHgNodW7wQU= +github.com/tinylib/msgp v1.1.9/go.mod h1:BCXGB54lDD8qUEPmiG0cQQUANC4IUQyB2ItS2UDlO/k= +github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= +github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= +github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= +github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= -github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M= -github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0= -github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= +github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= +github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= -github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs= -github.com/xdg-go/scram v1.1.1 h1:VOMT+81stJgXW3CpHyqHN3AXDYIMsx56mEFrB37Mb/E= -github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g= -github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM= -github.com/xdg-go/stringprep v1.0.3 h1:kdwGpVNwPFtjs98xCGkHjQtGKh86rDcRZN17QEMCOIs= -github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8= +github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY= +github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4= +github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8= +github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM= github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA= github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= -github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg= -github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= -go.etcd.io/etcd/api/v3 v3.5.6 h1:Cy2qx3npLcYqTKqGJzMypnMv2tiRyifZJ17BlWIWA7A= -go.etcd.io/etcd/api/v3 v3.5.6/go.mod h1:KFtNaxGDw4Yx/BA4iPPwevUTAuqcsPxzyX8PHydchN8= -go.etcd.io/etcd/client/pkg/v3 v3.5.6 h1:TXQWYceBKqLp4sa87rcPs11SXxUA/mHwH975v+BDvLU= -go.etcd.io/etcd/client/pkg/v3 v3.5.6/go.mod h1:ggrwbk069qxpKPq8/FKkQ3Xq9y39kbFR4LnKszpRXeQ= -go.etcd.io/etcd/client/v2 v2.305.6 h1:fIDR0p4KMjw01MJMfUIDWdQbjo06PD6CeYM5z4EHLi0= -go.etcd.io/etcd/client/v2 v2.305.6/go.mod h1:BHha8XJGe8vCIBfWBpbBLVZ4QjOIlfoouvOwydu63E0= -go.etcd.io/etcd/client/v3 v3.5.6 h1:coLs69PWCXE9G4FKquzNaSHrRyMCAXwF+IX1tAPVO8E= -go.etcd.io/etcd/client/v3 v3.5.6/go.mod h1:f6GRinRMCsFVv9Ht42EyY7nfsVGwrNO0WEoS2pRKzQk= -go.mongodb.org/mongo-driver v1.9.0/go.mod h1:0sQWfOeY63QTntERDJJ/0SuKK0T1uVSgKCuAROlKEPY= -go.mongodb.org/mongo-driver v1.11.3 h1:Ql6K6qYHEzB6xvu4+AU0BoRoqf9vFPcc4o7MUIdPW8Y= -go.mongodb.org/mongo-driver v1.11.3/go.mod h1:PTSz5yu21bkT/wXpkS7WR5f0ddqw5quethTUn9WM+2g= -go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= -go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= -go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -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.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= +github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= +go.etcd.io/etcd/api/v3 v3.5.10 h1:szRajuUUbLyppkhs9K6BRtjY37l66XQQmw7oZRANE4k= +go.etcd.io/etcd/api/v3 v3.5.10/go.mod h1:TidfmT4Uycad3NM/o25fG3J07odo4GBB9hoxaodFCtI= +go.etcd.io/etcd/client/pkg/v3 v3.5.10 h1:kfYIdQftBnbAq8pUWFXfpuuxFSKzlmM5cSn76JByiT0= +go.etcd.io/etcd/client/pkg/v3 v3.5.10/go.mod h1:DYivfIviIuQ8+/lCq4vcxuseg2P2XbHygkKwFo9fc8U= +go.etcd.io/etcd/client/v2 v2.305.10 h1:MrmRktzv/XF8CvtQt+P6wLUlURaNpSDJHFZhe//2QE4= +go.etcd.io/etcd/client/v2 v2.305.10/go.mod h1:m3CKZi69HzilhVqtPDcjhSGp+kA1OmbNn0qamH80xjA= +go.etcd.io/etcd/client/v3 v3.5.10 h1:W9TXNZ+oB3MCd/8UjxHTWK5J9Nquw9fQBLJd5ne5/Ao= +go.etcd.io/etcd/client/v3 v3.5.10/go.mod h1:RVeBnDz2PUEZqTpgqwAtUd8nAPf5kjyFyND7P1VkOKc= +go.mongodb.org/mongo-driver v1.15.0 h1:rJCKC8eEliewXjZGf0ddURtl7tTVy1TK3bfl0gkUSLc= +go.mongodb.org/mongo-driver v1.15.0/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo v0.32.0 h1:gNKQHn+q326vsi+kOskx9FCz9Jkz2fvxlf1y46dTN14= -go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo v0.32.0/go.mod h1:9WqBmOJ4AOChNHtnRBSCGlKN4PQf1coLTCK57fyXE/s= -go.opentelemetry.io/contrib/instrumentation/host v0.32.0 h1:rgDeaor0XDeUaUCGj0VJIRdQYwsYANlnIh4yMgnaZvo= -go.opentelemetry.io/contrib/instrumentation/host v0.32.0/go.mod h1:GavGOmrtAjm+/J0WkNWzDC9rCAKQaD2d9JUzG225sgc= -go.opentelemetry.io/contrib/instrumentation/runtime v0.32.0 h1:eMQf85EgNd2YWEikRJwEy4ADOiwlIum4rcHcssB4Qzk= -go.opentelemetry.io/contrib/instrumentation/runtime v0.32.0/go.mod h1:qtaLlIO4HC4DfedkYTOrvS2u7nA3N/v8w9mehrBD4O8= +go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo v0.51.0 h1:FUwEjB8vjAYc3UFehdZZWevjgO018fpjuFPdYLIXk8U= +go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo v0.51.0/go.mod h1:am6Je3ZASbWJUPXWZrKB0gwnP0Y2sfAnURRwIxM3IQ0= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.47.0 h1:UNQQKPfTDe1J81ViolILjTKPr9WetKW6uei2hFgJmFs= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.47.0/go.mod h1:r9vWsPS/3AQItv3OSlEJ/E4mbrhUbbw18meOjArPtKQ= +go.opentelemetry.io/contrib/instrumentation/host v0.51.0 h1:QljwOKW6+mdod9+lK5SzhPzGtB8XQcLNGddK/wYlMI4= +go.opentelemetry.io/contrib/instrumentation/host v0.51.0/go.mod h1:wYX18WtmQZ45RNcpd0d9uLvjGOd7I2dOoQ4h4LvoVD8= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.51.0 h1:Xs2Ncz0gNihqu9iosIZ5SkBbWo5T8JhhLJFMQL1qmLI= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.51.0/go.mod h1:vy+2G/6NvVMpwGX/NyLqcC41fxepnuKHk16E6IZUcJc= +go.opentelemetry.io/contrib/instrumentation/runtime v0.51.0 h1:1tBjncp/Rr5iuV0WfdKGGynrzIJ8bMm5z7Zl6jMjfIE= +go.opentelemetry.io/contrib/instrumentation/runtime v0.51.0/go.mod h1:6MqTuVXkhmzrIc7SFHYVTo7N6OFvVpDH5eq5xXKpAZQ= go.opentelemetry.io/otel v1.2.0/go.mod h1:aT17Fk0Z1Nor9e0uisf98LrntPGMnk4frBO9+dkf69I= -go.opentelemetry.io/otel v1.7.0 h1:Z2lA3Tdch0iDcrhJXDIlC94XE+bxok1F9B+4Lz/lGsM= -go.opentelemetry.io/otel v1.7.0/go.mod h1:5BdUoMIz5WEs0vt0CUEMtSSaTSHBBVwrhnz7+nrD5xk= -go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.7.0 h1:7Yxsak1q4XrJ5y7XBnNwqWx9amMZvoidCctv62XOQ6Y= -go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.7.0/go.mod h1:M1hVZHNxcbkAlcvrOMlpQ4YOO3Awf+4N2dxkZL3xm04= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.7.0 h1:cMDtmgJ5FpRvqx9x2Aq+Mm0O6K/zcUkH73SFz20TuBw= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.7.0/go.mod h1:ceUgdyfNv4h4gLxHR0WNfDiiVmZFodZhZSbOLhpxqXE= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.7.0 h1:MFAyzUPrTwLOwCi+cltN0ZVyy4phU41lwH+lyMyQTS4= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.7.0/go.mod h1:E+/KKhwOSw8yoPxSSuUHG6vKppkvhN+S1Jc7Nib3k3o= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.7.0 h1:pLP0MH4MAqeTEV0g/4flxw9O8Is48uAIauAnjznbW50= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.7.0/go.mod h1:aFXT9Ng2seM9eizF+LfKiyPBGy8xIZKwhusC1gIu3hA= -go.opentelemetry.io/otel/exporters/prometheus v0.30.0 h1:YXo5ZY5nofaEYMCMTTMaRH2cLDZB8+0UGuk5RwMfIo0= -go.opentelemetry.io/otel/exporters/prometheus v0.30.0/go.mod h1:qN5feW+0/d661KDtJuATEmHtw5bKBK7NSvNEP927zSs= -go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v0.30.0 h1:2glg1ZFVVZf47zFuX0iwBPPid4tqzBYYWTVVu0pc+us= -go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v0.30.0/go.mod h1:LGFXSl/Js7uN7mDcrzCcHVj48JOtoYDjm4oUI4dLif0= -go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.7.0 h1:8hPcgCg0rUJiKE6VWahRvjgLUrNl7rW2hffUEPKXVEM= -go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.7.0/go.mod h1:K4GDXPY6TjUiwbOh+DkKaEdCF8y+lvMoM6SeAPyfCCM= -go.opentelemetry.io/otel/metric v0.30.0 h1:Hs8eQZ8aQgs0U49diZoaS6Uaxw3+bBE3lcMUKBFIk3c= -go.opentelemetry.io/otel/metric v0.30.0/go.mod h1:/ShZ7+TS4dHzDFmfi1kSXMhMVubNoP0oIaBp70J6UXU= +go.opentelemetry.io/otel v1.26.0 h1:LQwgL5s/1W7YiiRwxf03QGnWLb2HW4pLiAhaA5cZXBs= +go.opentelemetry.io/otel v1.26.0/go.mod h1:UmLkJHUAidDval2EICqBMbnAd0/m2vmpf/dAM+fvFs4= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.26.0 h1:1u/AyyOqAWzy+SkPxDpahCNZParHV8Vid1RnI2clyDE= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.26.0/go.mod h1:z46paqbJ9l7c9fIPCXTqTGwhQZ5XoTIsfeFYWboizjs= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.26.0 h1:Waw9Wfpo/IXzOI8bCB7DIk+0JZcqqsyn1JFnAc+iam8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.26.0/go.mod h1:wnJIG4fOqyynOnnQF/eQb4/16VlX2EJAHhHgqIqWfAo= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.26.0 h1:1wp/gyxsuYtuE/JFxsQRtcCDtMrO2qMvlfXALU5wkzI= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.26.0/go.mod h1:gbTHmghkGgqxMomVQQMur1Nba4M0MQ8AYThXDUjsJ38= +go.opentelemetry.io/otel/exporters/prometheus v0.48.0 h1:sBQe3VNGUjY9IKWQC6z2lNqa5iGbDSxhs60ABwK4y0s= +go.opentelemetry.io/otel/exporters/prometheus v0.48.0/go.mod h1:DtrbMzoZWwQHyrQmCfLam5DZbnmorsGbOtTbYHycU5o= +go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.26.0 h1:5fnmgteaar1VcAA69huatudPduNFz7guRtCmfZCooZI= +go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.26.0/go.mod h1:lsPccfZiz1cb1AhBPmicWM2E4F1VynFXEvD8SEBS4TM= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.26.0 h1:0W5o9SzoR15ocYHEQfvfipzcNog1lBxOLfnex91Hk6s= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.26.0/go.mod h1:zVZ8nz+VSggWmnh6tTsJqXQ7rU4xLwRtna1M4x5jq58= +go.opentelemetry.io/otel/metric v1.26.0 h1:7S39CLuY5Jgg9CrnA9HHiEjGMF/X2VHvoXGgSllRz30= +go.opentelemetry.io/otel/metric v1.26.0/go.mod h1:SY+rHOI4cEawI9a7N1A4nIg/nTQXe1ccCNWYOJUrpX4= go.opentelemetry.io/otel/sdk v1.2.0/go.mod h1:jNN8QtpvbsKhgaC6V5lHiejMoKD+V8uadoSafgHPx1U= -go.opentelemetry.io/otel/sdk v1.7.0 h1:4OmStpcKVOfvDOgCt7UriAPtKolwIhxpnSNI/yK+1B0= -go.opentelemetry.io/otel/sdk v1.7.0/go.mod h1:uTEOTwaqIVuTGiJN7ii13Ibp75wJmYUDe374q6cZwUU= -go.opentelemetry.io/otel/sdk/metric v0.30.0 h1:XTqQ4y3erR2Oj8xSAOL5ovO5011ch2ELg51z4fVkpME= -go.opentelemetry.io/otel/sdk/metric v0.30.0/go.mod h1:8AKFRi5HyvTR0RRty3paN1aMC9HMT+NzcEhw/BLkLX8= +go.opentelemetry.io/otel/sdk v1.26.0 h1:Y7bumHf5tAiDlRYFmGqetNcLaVUZmh4iYfmGxtmz7F8= +go.opentelemetry.io/otel/sdk v1.26.0/go.mod h1:0p8MXpqLeJ0pzcszQQN4F0S5FVjBLgypeGSngLsmirs= +go.opentelemetry.io/otel/sdk/metric v1.26.0 h1:cWSks5tfriHPdWFnl+qpX3P681aAYqlZHcAyHw5aU9Y= +go.opentelemetry.io/otel/sdk/metric v1.26.0/go.mod h1:ClMFFknnThJCksebJwz7KIyEDHO+nTB6gK8obLy8RyE= go.opentelemetry.io/otel/trace v1.2.0/go.mod h1:N5FLswTubnxKxOJHM7XZC074qpeEdLy3CgAVsdMucK0= -go.opentelemetry.io/otel/trace v1.7.0 h1:O37Iogk1lEkMRXewVtZ1BBTVn5JEp8GrJvP92bJqC6o= -go.opentelemetry.io/otel/trace v1.7.0/go.mod h1:fzLSB9nqR2eXzxPXb2JW9IKE+ScyXA48yyE4TNvoHqU= +go.opentelemetry.io/otel/trace v1.26.0 h1:1ieeAUb4y0TE26jUFrCIXKpTuVK7uJGN9/Z/2LP5sQA= +go.opentelemetry.io/otel/trace v1.26.0/go.mod h1:4iDxvGDQuUkHve82hJJ8UqrwswHYsZuWCBllGV2U2y0= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -go.opentelemetry.io/proto/otlp v0.16.0 h1:WHzDWdXUvbc5bG2ObdrGfaNpQz7ft7QN9HHmJlbiB1E= -go.opentelemetry.io/proto/otlp v0.16.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= +go.opentelemetry.io/proto/otlp v1.2.0 h1:pVeZGk7nXDC9O2hncA6nHldxEjm6LByfA2aN8IOkz94= +go.opentelemetry.io/proto/otlp v1.2.0/go.mod h1:gGpR8txAl5M03pDhMC79G6SdqNV26naRm/KDsgaHD8A= go.temporal.io/api v1.5.0/go.mod h1:BqKxEJJYdxb5dqf0ODfzfMxh8UEQ5L3zKS51FiIYYkA= go.temporal.io/api v1.8.0 h1:FzAMmBeLs6BEMFyHeJ9M9GAv6McFuH/GjnliBCdQ/Zw= go.temporal.io/api v1.8.0/go.mod h1:7m1ZOVUFi/54a5IMzMeELnvDy5sJwRfz11zi3Jrww8w= @@ -576,74 +462,39 @@ go.temporal.io/sdk v1.15.0/go.mod h1:peqnjALtNpJMKRplWEubefPhDXdAtRTnebsLSFypSts go.temporal.io/sdk/contrib/opentelemetry v0.1.0 h1:AdQUf0qWIAZLU2+hIR7AGO5YzO1im/xAVRgrCuXnHv4= go.temporal.io/sdk/contrib/opentelemetry v0.1.0/go.mod h1:TrPfwtdvlwR3vqJFyPyl+WcNUrAUcAkJHVi3PK/iPYk= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA= -go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= -go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8= -go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= +go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ= +go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= -go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= -go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= 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-20201216223049-8b5274cf687f/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= -golang.org/x/crypto v0.0.0-20210314154223-e6e6c4f2bb5b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A= -golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= +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-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= -golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= -golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= -golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/exp v0.0.0-20231127185646-65229373498e h1:Gvh4YaCaXNs6dKTlfgismwWZKyjVZXwOPfIyUaqU3No= +golang.org/x/exp v0.0.0-20231127185646-65229373498e/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= -golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 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.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8= -golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +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/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-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -651,337 +502,145 @@ golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 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-20201031054903-ff519b6c9102/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-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= -golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210913180222-943fd674d43e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220531201128-c960675eff93/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= -golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= -golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= +golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= 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-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.4.0 h1:NF0gk8LVPg1Ml7SSbGyySuoxdsXitj7TvgvuRxIMc/M= -golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec= +golang.org/x/oauth2 v0.17.0 h1:6m3ZPmLEFdVxKKWnKq4VqZ60gutO35zm+zrAHVmHyDQ= +golang.org/x/oauth2 v0.17.0/go.mod h1:OzPDGQiuQMguemayvdylqddI7qcD9lnSDb+1FiwQ5HA= 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= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/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-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/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-20210220032951-036812b2e83c/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.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= -golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +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-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 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= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -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-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210910150752-751e447fb3d0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/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.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +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.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= -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= 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.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/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.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= -golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -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= -golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +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.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.1.0 h1:xYY+Bajn2a7VBmTM5GikTmnK8ZuX8YgnQCqZpbBNtmA= -golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= +golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= -golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= -golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ= -golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= -golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +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/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= -golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= -golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= -google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -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.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= -google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= -google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= -google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= -google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= -google.golang.org/api v0.107.0 h1:I2SlFjD8ZWabaIFOfeEDg3pf0BHJDh6iYQ1ic3Yu/UU= -google.golang.org/api v0.107.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY= +google.golang.org/api v0.162.0 h1:Vhs54HkaEpkMBdgGdOT2P6F0csGG/vxDS0hWHJzmmps= +google.golang.org/api v0.162.0/go.mod h1:6SulDkfoBIg4NFmCuZ39XeeAgSHCPecfSUuDyYlAHs0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= -google.golang.org/appengine v1.6.7/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-20180518175338-11a468237815/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= -google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= 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-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20220602131408-e326c6e8e9c8/go.mod h1:yKyY4AMRwFiC8yMMNaMi+RkCnjZJt9LoWuvhXjMs+To= -google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f h1:BWUVssLB0HVOSY78gIdvk1dTVYtT1y8SBWtPYuTJ/6w= -google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de h1:F6qOa9AZTYJXOUEr4jDysRDLrm4PHePlge4v4TGAlxY= +google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:VUhTRKeHn9wwcdrk73nvdC9gF178Tzhmt/qyaFcPLSo= +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-20240401170217-c3f982113cda h1:LI5DOvAxUPMv/50agcLLoo+AdWc1irS9Rzz4vPuD1V4= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= -google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.1/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.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= -google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k= -google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= -google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= -google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +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= @@ -990,21 +649,19 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -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.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= -google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.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-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -1012,8 +669,6 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= @@ -1021,13 +676,4 @@ gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= -rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= -rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= -sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff --git a/healthz.go b/healthz.go new file mode 100644 index 0000000..7b43776 --- /dev/null +++ b/healthz.go @@ -0,0 +1,20 @@ +package keel + +import ( + "github.com/foomo/keel/healthz" + "github.com/foomo/keel/interfaces" +) + +func IsHealthz(v any) bool { + switch v.(type) { + case healthz.BoolHealthzer, + healthz.BoolHealthzerWithContext, + healthz.ErrorHealthzer, + healthz.ErrorHealthzWithContext, + interfaces.ErrorPinger, + interfaces.ErrorPingerWithContext: + return true + default: + return false + } +} diff --git a/healthz/docs.go b/healthz/docs.go new file mode 100644 index 0000000..59c42b6 --- /dev/null +++ b/healthz/docs.go @@ -0,0 +1 @@ +package healthz diff --git a/healthzer.go b/healthz/healthzer.go similarity index 87% rename from healthzer.go rename to healthz/healthzer.go index 3156353..5ed08cf 100644 --- a/healthzer.go +++ b/healthz/healthzer.go @@ -1,4 +1,4 @@ -package keel +package healthz import "context" @@ -16,6 +16,10 @@ func (h healther) Healthz(ctx context.Context) error { return h.handle(ctx) } +func (h healther) Close(ctx context.Context) error { + return h.handle(ctx) +} + // BoolHealthzer interface type BoolHealthzer interface { Healthz() bool diff --git a/healthztype.go b/healthz/type.go similarity index 70% rename from healthztype.go rename to healthz/type.go index 848edc0..e5c45ba 100644 --- a/healthztype.go +++ b/healthz/type.go @@ -1,31 +1,31 @@ -package keel +package healthz -// HealthzType type +// Type type // https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/ -type HealthzType string +type Type string const ( - // HealthzTypeAlways will run on any checks - HealthzTypeAlways HealthzType = "always" - // HealthzTypeStartup will run on /healthz/startup checks + // TypeAlways will run on any checks + TypeAlways Type = "always" + // TypeStartup will run on /healthz/startup checks // > The kubelet uses startup probes to know when a container application has started. If such a probe is configured, // > it disables liveness and readiness checks until it succeeds, making sure those probes don't interfere with the // > application startup. This can be used to adopt liveness checks on slow starting containers, avoiding them getting // > killed by the kubelet before they are up and running. - HealthzTypeStartup HealthzType = "startup" - // HealthzTypeReadiness will run on /healthz/readiness checks + TypeStartup Type = "startup" + // TypeReadiness will run on /healthz/readiness checks // > The kubelet uses readiness probes to know when a container is ready to start accepting traffic. // > A Pod is considered ready when all of its containers are ready. One use of this signal is to control // > which Pods are used as backends for Services. When a Pod is not ready, it is removed from Service load balancers. - HealthzTypeReadiness HealthzType = "readiness" - // HealthzTypeLiveness will run on /healthz/liveness checks + TypeReadiness Type = "readiness" + // TypeLiveness will run on /healthz/liveness checks // > The kubelet uses liveness probes to know when to restart a container. For example, liveness probes could catch // > a deadlock, where an application is running, but unable to make progress. Restarting a container in such a state // > can help to make the application more available despite bugs. - HealthzTypeLiveness HealthzType = "liveness" + TypeLiveness Type = "liveness" ) // String interface -func (t HealthzType) String() string { +func (t Type) String() string { return string(t) } diff --git a/integration/gotsrpc/net/middleware/telemetry.go b/integration/gotsrpc/net/middleware/telemetry.go index 79a004a..754b53b 100644 --- a/integration/gotsrpc/net/middleware/telemetry.go +++ b/integration/gotsrpc/net/middleware/telemetry.go @@ -1,14 +1,23 @@ package keelgotsrpcmiddleware import ( + "bytes" + "encoding/json" + "fmt" + "io" "net/http" + "strconv" "time" "github.com/foomo/gotsrpc/v2" + "github.com/foomo/keel/env" + httplog "github.com/foomo/keel/net/http/log" + "github.com/foomo/keel/telemetry" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" - "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/codes" + "go.opentelemetry.io/otel/trace" "go.uber.org/zap" "github.com/foomo/keel/net/http/middleware" @@ -20,42 +29,220 @@ const ( defaultGOTSRPCServiceLabel = "gotsrpc_service" defaultGOTSRPCPackageLabel = "gotsrpc_package" defaultGOTSRPCPackageOperation = "gotsrpc_operation" + defaultGOTSRPCError = "gotsrpc_error" + defaultGOTSRPCErrorCode = "gotsrpc_error_code" + defaultGOTSRPCErrorType = "gotsrpc_error_type" + defaultGOTSRPCErrorMessage = "gotsrpc_error_message" +) + +type ( + TelemetryOptions struct { + ExemplarsDisabled bool + ObserveExecution bool + ObserveMarshalling bool + ObserveUnmarshalling bool + PayloadAttributeDisabled bool + } + TelemetryOption func(*TelemetryOptions) ) var ( + gotsrpcRequestDurationHistogram = promauto.NewHistogramVec(prometheus.HistogramOpts{ + Namespace: "gotsrpc", + Name: "process_duration_seconds", + Help: "Specifies the duration of the gotsrpc process in seconds", + ConstLabels: nil, + Buckets: []float64{0.05, 0.1, 0.5, 1, 3, 5, 10}, + }, []string{ + defaultGOTSRPCFunctionLabel, + defaultGOTSRPCServiceLabel, + defaultGOTSRPCPackageLabel, + defaultGOTSRPCPackageOperation, + defaultGOTSRPCError, + }) + // Deprecated: use gotsrpc_process_duration_seconds gotsrpcRequestDurationSummary = promauto.NewSummaryVec(prometheus.SummaryOpts{ - Name: "gotsrpc_request_duration_seconds", + Namespace: "gotsrpc", + Name: "request_duration_seconds", Objectives: map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001}, - Help: "Specifies the duration of gotsrpc request in seconds", - }, []string{defaultGOTSRPCFunctionLabel, defaultGOTSRPCServiceLabel, defaultGOTSRPCPackageLabel, defaultGOTSRPCPackageOperation}) + Help: "Specifies the duration of gotsrpc request in seconds summary", + }, []string{ + defaultGOTSRPCFunctionLabel, + defaultGOTSRPCServiceLabel, + defaultGOTSRPCPackageLabel, + defaultGOTSRPCPackageOperation, + defaultGOTSRPCError, + }) ) +// DefaultTelemetryOptions returns the default options +func DefaultTelemetryOptions() TelemetryOptions { + return TelemetryOptions{ + ObserveExecution: true, + ObserveMarshalling: false, + ObserveUnmarshalling: false, + PayloadAttributeDisabled: env.GetBool("OTEL_GOTSRPC_PAYLOAD_ATTRIBUTE_DISABLED", true), + ExemplarsDisabled: env.GetBool("OTEL_GOTSRPC_EXEMPLARS_DISABLED", false), + } +} + +// TelemetryWithExemplarsDisabled middleware option +func TelemetryWithExemplarsDisabled(v bool) TelemetryOption { + return func(o *TelemetryOptions) { + o.ExemplarsDisabled = v + } +} + +// TelemetryWithObserveExecution middleware option +func TelemetryWithObserveExecution(v bool) TelemetryOption { + return func(o *TelemetryOptions) { + o.ObserveExecution = v + } +} + +// TelemetryWithObserveMarshalling middleware option +func TelemetryWithObserveMarshalling(v bool) TelemetryOption { + return func(o *TelemetryOptions) { + o.ObserveMarshalling = v + } +} + +// TelemetryWithObserveUnmarshalling middleware option +func TelemetryWithObserveUnmarshalling(v bool) TelemetryOption { + return func(o *TelemetryOptions) { + o.ObserveUnmarshalling = v + } +} + +// TelemetryWithPayloadAttributeDisabled middleware option +func TelemetryWithPayloadAttributeDisabled(v bool) TelemetryOption { + return func(o *TelemetryOptions) { + o.PayloadAttributeDisabled = v + } +} + // Telemetry middleware -func Telemetry() middleware.Middleware { +func Telemetry(opts ...TelemetryOption) middleware.Middleware { + options := DefaultTelemetryOptions() + for _, opt := range opts { + if opt != nil { + opt(&options) + } + } + return TelemetryWithOptions(options) +} + +// TelemetryWithOptions middleware +func TelemetryWithOptions(opts TelemetryOptions) middleware.Middleware { + observe := func(spanCtx trace.SpanContext, metric prometheus.ObserverVec, stats *gotsrpc.CallStats, operation string) { + observer := metric.WithLabelValues( + stats.Func, + stats.Service, + stats.Package, + operation, + strconv.FormatBool(stats.ErrorCode != 0), + ) + var duration time.Duration + switch operation { + case "marshalling": + duration = stats.Marshalling + case "unmarshalling": + duration = stats.Unmarshalling + case "execution": + duration = stats.Execution + } + if exemplarObserver, ok := observer.(prometheus.ExemplarObserver); ok && opts.ExemplarsDisabled && spanCtx.HasTraceID() && spanCtx.IsSampled() { + exemplarObserver.ObserveWithExemplar(duration.Seconds(), prometheus.Labels{ + "traceID": spanCtx.TraceID().String(), + }) + return + } + observer.Observe(duration.Seconds()) + } + + sanitizePayload := func(r *http.Request) string { + if r.Method != http.MethodPost { + return "" + } + body, err := io.ReadAll(r.Body) + if err != nil { + return "" + } + if err := r.Body.Close(); err != nil { + return "" + } + r.Body = io.NopCloser(bytes.NewBuffer(body)) + var out bytes.Buffer + if err = json.Indent(&out, body, "", " "); err != nil { + return "" + } + return out.String() + } + return func(l *zap.Logger, name string, next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - *r = *gotsrpc.RequestWithStatsContext(r) + ctx, span := telemetry.Start(r.Context(), "GOTSRPC") + *r = *gotsrpc.RequestWithStatsContext(r.WithContext(ctx)) + + if !opts.PayloadAttributeDisabled { + span.SetAttributes(attribute.String("gotsprc.payload", sanitizePayload(r))) + } + next.ServeHTTP(w, r) - if labeler, ok := otelhttp.LabelerFromContext(r.Context()); ok { - if stats, ok := gotsrpc.GetStatsForRequest(r); ok { - labeler.Add(attribute.String(defaultGOTSRPCFunctionLabel, stats.Func)) - labeler.Add(attribute.String(defaultGOTSRPCServiceLabel, stats.Service)) - labeler.Add(attribute.String(defaultGOTSRPCPackageLabel, stats.Package)) - - observe := func(operation string, duration time.Duration) { - gotsrpcRequestDurationSummary.WithLabelValues( - stats.Func, - stats.Service, - stats.Package, - operation, - ).Observe(duration.Seconds()) - } - observe("marshalling", stats.Marshalling) - observe("unmarshalling", stats.Unmarshalling) - observe("execution", stats.Execution) + if stats, ok := gotsrpc.GetStatsForRequest(r); ok { + span.SetName(fmt.Sprintf("GOTSRPC %s.%s", stats.Service, stats.Func)) + span.SetAttributes( + attribute.String("gotsrpc.func", stats.Func), + attribute.String("gotsrpc.service", stats.Service), + attribute.String("gotsrpc.package", stats.Package), + attribute.Int64("gotsrpc.marshalling", stats.Marshalling.Milliseconds()), + attribute.Int64("gotsrpc.unmarshalling", stats.Unmarshalling.Milliseconds()), + ) + if stats.ErrorCode != 0 { + span.SetStatus(codes.Error, fmt.Sprintf("%s: %s", stats.ErrorType, stats.ErrorMessage)) + span.SetAttributes(attribute.Int("gotsrpc.error.code", stats.ErrorCode)) + } + if stats.ErrorType != "" { + span.SetAttributes(attribute.String("gotsrpc.error.type", stats.ErrorType)) + } + if stats.ErrorMessage != "" { + span.SetAttributes(attribute.String("gotsrpc.error.message", stats.ErrorMessage)) + } + + // create custom metics + if opts.ObserveMarshalling { + observe(span.SpanContext(), gotsrpcRequestDurationSummary, stats, "marshalling") + observe(span.SpanContext(), gotsrpcRequestDurationHistogram, stats, "marshalling") + } + if opts.ObserveUnmarshalling { + observe(span.SpanContext(), gotsrpcRequestDurationSummary, stats, "unmarshalling") + observe(span.SpanContext(), gotsrpcRequestDurationHistogram, stats, "unmarshalling") + } + if opts.ObserveExecution { + observe(span.SpanContext(), gotsrpcRequestDurationSummary, stats, "execution") + observe(span.SpanContext(), gotsrpcRequestDurationHistogram, stats, "execution") + } + + // enrich logger + if labeler, ok := httplog.LabelerFromRequest(r); ok { + labeler.Add( + zap.String(defaultGOTSRPCFunctionLabel, stats.Func), + zap.String(defaultGOTSRPCServiceLabel, stats.Service), + zap.String(defaultGOTSRPCPackageLabel, stats.Package), + ) + if stats.ErrorCode != 0 { + labeler.Add(zap.Int(defaultGOTSRPCErrorCode, stats.ErrorCode)) + } + if stats.ErrorType != "" { + labeler.Add(zap.String(defaultGOTSRPCErrorType, stats.ErrorType)) + } + if stats.ErrorMessage != "" { + labeler.Add(zap.String(defaultGOTSRPCErrorMessage, stats.ErrorMessage)) + } } } + telemetry.End(span, nil) }) } } diff --git a/integration/temporal/metrics.go b/integration/temporal/metrics.go index cf28f4e..846ca44 100644 --- a/integration/temporal/metrics.go +++ b/integration/temporal/metrics.go @@ -7,8 +7,6 @@ import ( "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/metric" - "go.opentelemetry.io/otel/metric/instrument/asyncfloat64" - "go.opentelemetry.io/otel/metric/instrument/syncint64" "go.temporal.io/sdk/client" ) @@ -30,16 +28,16 @@ func (m metricsHandler) WithTags(tags map[string]string) client.MetricsHandler { } type counter struct { - inst syncint64.Counter + inst metric.Int64Counter attr []attribute.KeyValue } func (c *counter) Inc(v int64) { - c.inst.Add(context.Background(), v, c.attr...) + c.inst.Add(context.Background(), v, metric.WithAttributes(c.attr...)) } func (m metricsHandler) Counter(name string) client.MetricsCounter { - c, err := m.meter.SyncInt64().Counter(name) + c, err := m.meter.Int64Counter(name) if err != nil { otel.Handle(err) } @@ -50,36 +48,43 @@ func (m metricsHandler) Counter(name string) client.MetricsCounter { } type gauge struct { - inst asyncfloat64.Gauge - attr []attribute.KeyValue + inst metric.Float64ObservableGauge + value float64 } func (c *gauge) Update(v float64) { - c.inst.Observe(context.TODO(), v, c.attr...) + c.value = v } func (m metricsHandler) Gauge(name string) client.MetricsGauge { - c, err := m.meter.AsyncFloat64().Gauge(name) + c, err := m.meter.Float64ObservableGauge(name) if err != nil { otel.Handle(err) } - return &gauge{ + inst := &gauge{ inst: c, - attr: m.attr, } + _, err = m.meter.RegisterCallback(func(ctx context.Context, o metric.Observer) error { + o.ObserveFloat64(c, inst.value, metric.WithAttributes(m.attr...)) + return nil + }) + if err != nil { + otel.Handle(err) + } + return inst } type timer struct { - inst syncint64.Histogram + inst metric.Int64Histogram attr []attribute.KeyValue } func (c *timer) Record(v time.Duration) { - c.inst.Record(context.TODO(), v.Milliseconds(), c.attr...) + c.inst.Record(context.TODO(), v.Milliseconds(), metric.WithAttributes(c.attr...)) } func (m metricsHandler) Timer(name string) client.MetricsTimer { - c, err := m.meter.SyncInt64().Histogram(name) + c, err := m.meter.Int64Histogram(name) if err != nil { otel.Handle(err) } diff --git a/interfaces/closer.go b/interfaces/closer.go new file mode 100644 index 0000000..abbc719 --- /dev/null +++ b/interfaces/closer.go @@ -0,0 +1,25 @@ +package interfaces + +import ( + "context" +) + +// Closer interface +type Closer interface { + Close() +} + +// ErrorCloser interface +type ErrorCloser interface { + Close() error +} + +// CloserWithContext interface +type CloserWithContext interface { + Close(ctx context.Context) +} + +// ErrorCloserWithContext interface +type ErrorCloserWithContext interface { + Close(ctx context.Context) error +} diff --git a/interfaces/closerfunc.go b/interfaces/closerfunc.go new file mode 100644 index 0000000..cb7120f --- /dev/null +++ b/interfaces/closerfunc.go @@ -0,0 +1,11 @@ +package interfaces + +import ( + "context" +) + +type CloserFunc func(ctx context.Context) error + +func (f CloserFunc) Close(ctx context.Context) error { + return f(ctx) +} diff --git a/interfaces/doc.go b/interfaces/doc.go new file mode 100644 index 0000000..08badf2 --- /dev/null +++ b/interfaces/doc.go @@ -0,0 +1 @@ +package interfaces diff --git a/interfaces/namer.go b/interfaces/namer.go new file mode 100644 index 0000000..65250a1 --- /dev/null +++ b/interfaces/namer.go @@ -0,0 +1,6 @@ +package interfaces + +// Namer interface +type Namer interface { + Name() string +} diff --git a/pinger.go b/interfaces/pinger.go similarity index 91% rename from pinger.go rename to interfaces/pinger.go index 5d97f09..7cd2b7c 100644 --- a/pinger.go +++ b/interfaces/pinger.go @@ -1,4 +1,4 @@ -package keel +package interfaces import "context" diff --git a/interfaces/readmer.go b/interfaces/readmer.go new file mode 100644 index 0000000..a16ba1f --- /dev/null +++ b/interfaces/readmer.go @@ -0,0 +1,20 @@ +package interfaces + +// Readmer interface +type Readmer interface { + Readme() string +} + +type ReadmeHandler struct { + Value func() string +} + +func (r ReadmeHandler) Readme() string { + return r.Value() +} + +func ReadmeFunc(v func() string) ReadmeHandler { + return ReadmeHandler{ + Value: v, + } +} diff --git a/shutdowner.go b/interfaces/shutdowner.go similarity index 95% rename from shutdowner.go rename to interfaces/shutdowner.go index 08538d7..b587b86 100644 --- a/shutdowner.go +++ b/interfaces/shutdowner.go @@ -1,4 +1,4 @@ -package keel +package interfaces import "context" diff --git a/stopper.go b/interfaces/stopper.go similarity index 94% rename from stopper.go rename to interfaces/stopper.go index 93b49f3..6ada3d7 100644 --- a/stopper.go +++ b/interfaces/stopper.go @@ -1,4 +1,4 @@ -package keel +package interfaces import "context" diff --git a/unsubscriber.go b/interfaces/unsubscriber.go similarity index 95% rename from unsubscriber.go rename to interfaces/unsubscriber.go index 2d235f8..6395664 100644 --- a/unsubscriber.go +++ b/interfaces/unsubscriber.go @@ -1,4 +1,4 @@ -package keel +package interfaces import "context" diff --git a/jwt/jwtkey.go b/jwt/jwtkey.go index b55d872..b7fc16a 100644 --- a/jwt/jwtkey.go +++ b/jwt/jwtkey.go @@ -38,9 +38,9 @@ func NewKeyFromFilenames(publicKeyPemFilename, privateKeyPemFilename string) (Ke // load private key if privateKeyPemFilename != "" { - if bytes, err := os.ReadFile(privateKeyPemFilename); err != nil { + if value, err := os.ReadFile(privateKeyPemFilename); err != nil { return Key{}, errors.Wrap(err, "failed to read private key: "+privateKeyPemFilename) - } else if key, err := jwt.ParseRSAPrivateKeyFromPEM([]byte(strings.ReplaceAll(string(bytes), `\n`, "\n"))); err != nil { + } else if key, err := jwt.ParseRSAPrivateKeyFromPEM([]byte(strings.ReplaceAll(string(value), `\n`, "\n"))); err != nil { return Key{}, errors.Wrap(err, "failed to parse private key: "+privateKeyPemFilename) } else { private = key @@ -54,7 +54,7 @@ func NewKeyFromFilenames(publicKeyPemFilename, privateKeyPemFilename string) (Ke return Key{}, errors.Wrap(err, "failed to parse public key: "+publicKeyPemFilename) } else { hasher := sha256.New() - hasher.Write(bytes.TrimSpace(v)) + _, _ = hasher.Write(bytes.TrimSpace(v)) id = hex.EncodeToString(hasher.Sum(nil)) public = key } diff --git a/test/assert/assert.go b/keeltest/assert/assert.go similarity index 81% rename from test/assert/assert.go rename to keeltest/assert/assert.go index e024345..08333b5 100644 --- a/test/assert/assert.go +++ b/keeltest/assert/assert.go @@ -5,8 +5,8 @@ import ( "fmt" "testing" + "github.com/foomo/keel/keeltest" "github.com/foomo/keel/log" - keeltestutil "github.com/foomo/keel/test/util" "github.com/stretchr/testify/assert" "github.com/tidwall/pretty" ) @@ -14,7 +14,7 @@ import ( func InlineEqual(t *testing.T, actual interface{}, msgAndArgs ...interface{}) bool { t.Helper() - expected, ok := keeltestutil.Inline(t, 2, "%v", actual) + expected, ok := keeltest.Inline(t, 2, "%v", actual) if ok { return assert.Equal(t, expected, fmt.Sprintf("%v", actual), msgAndArgs...) } else { @@ -30,7 +30,7 @@ func InlineJSONEq(t *testing.T, actual interface{}, msgAndArgs ...interface{}) b t.Fatal("failed to marshal json", log.FError(err)) } - expected, ok := keeltestutil.Inline(t, 2, string(actualBytes)) + expected, ok := keeltest.Inline(t, 2, string(actualBytes)) if ok { return assert.Equal(t, string(pretty.Pretty([]byte(expected))), string(pretty.Pretty(actualBytes)), msgAndArgs...) } else { diff --git a/test/assert/assert_test.go b/keeltest/assert/assert_test.go similarity index 95% rename from test/assert/assert_test.go rename to keeltest/assert/assert_test.go index 6d86152..4121070 100644 --- a/test/assert/assert_test.go +++ b/keeltest/assert/assert_test.go @@ -3,7 +3,7 @@ package keelassert_test import ( "testing" - keelassert "github.com/foomo/keel/test/assert" + keelassert "github.com/foomo/keel/keeltest/assert" "github.com/stretchr/testify/assert" ) diff --git a/test/assert/assertions.go b/keeltest/assert/assertions.go similarity index 85% rename from test/assert/assertions.go rename to keeltest/assert/assertions.go index 6abcb76..cb37301 100644 --- a/test/assert/assertions.go +++ b/keeltest/assert/assertions.go @@ -5,8 +5,8 @@ import ( "fmt" "testing" + "github.com/foomo/keel/keeltest" "github.com/foomo/keel/log" - keeltestutil "github.com/foomo/keel/test/util" "github.com/stretchr/testify/assert" "github.com/tidwall/pretty" ) @@ -26,7 +26,7 @@ func New(t *testing.T) *Assertions { //nolint:thelper func (a *Assertions) InlineEqual(actual interface{}, msgAndArgs ...interface{}) bool { a.t.Helper() - expected, ok := keeltestutil.Inline(a.t, 2, "%v", actual) + expected, ok := keeltest.Inline(a.t, 2, "%v", actual) if ok { return assert.Equal(a.t, expected, fmt.Sprintf("%v", actual), msgAndArgs...) } else { @@ -42,7 +42,7 @@ func (a *Assertions) InlineJSONEq(actual interface{}, msgAndArgs ...interface{}) a.t.Fatal("failed to marshal json", log.FError(err)) } - expected, ok := keeltestutil.Inline(a.t, 2, string(actualBytes)) + expected, ok := keeltest.Inline(a.t, 2, string(actualBytes)) if ok { return assert.Equal(a.t, string(pretty.Pretty([]byte(expected))), string(pretty.Pretty(actualBytes)), msgAndArgs...) } else { diff --git a/test/client.go b/keeltest/client.go similarity index 100% rename from test/client.go rename to keeltest/client.go diff --git a/test/util/inline.go b/keeltest/inline.go similarity index 99% rename from test/util/inline.go rename to keeltest/inline.go index b5b8532..53357c6 100644 --- a/test/util/inline.go +++ b/keeltest/inline.go @@ -1,4 +1,4 @@ -package keeltestutil +package keeltest import ( "encoding/json" diff --git a/test/util/inline_test.go b/keeltest/inline_test.go similarity index 61% rename from test/util/inline_test.go rename to keeltest/inline_test.go index 28944a8..2907c02 100644 --- a/test/util/inline_test.go +++ b/keeltest/inline_test.go @@ -1,27 +1,27 @@ -package keeltestutil_test +package keeltest_test import ( "testing" - keeltestutil "github.com/foomo/keel/test/util" + "github.com/foomo/keel/keeltest" "github.com/stretchr/testify/assert" ) func TestInline(t *testing.T) { t.Run("read inline", func(t *testing.T) { - value, ok := keeltestutil.Inline(t, 1) // INLINE: hello world + value, ok := keeltest.Inline(t, 1) // INLINE: hello world assert.True(t, ok) assert.Equal(t, "hello world", value) }) t.Run("read inline int", func(t *testing.T) { - value, ok := keeltestutil.InlineInt(t, 1) // INLINE: 1 + value, ok := keeltest.InlineInt(t, 1) // INLINE: 1 assert.True(t, ok) assert.Equal(t, 1, value) }) t.Run("read inline float", func(t *testing.T) { - value, ok := keeltestutil.InlineFloat64(t, 1) // INLINE: 1.5 + value, ok := keeltest.InlineFloat64(t, 1) // INLINE: 1.5 assert.True(t, ok) assert.Equal(t, 1.5, value) }) @@ -30,12 +30,12 @@ func TestInline(t *testing.T) { var x struct { Foo string `json:"foo"` } - keeltestutil.InlineJSON(t, 1, &x) // INLINE: {"foo":"bar"} + keeltest.InlineJSON(t, 1, &x) // INLINE: {"foo":"bar"} assert.Equal(t, "bar", x.Foo) }) t.Run("write inline", func(t *testing.T) { - value, ok := keeltestutil.Inline(t, 1, "hello %s", "world") // INLINE: hello world + value, ok := keeltest.Inline(t, 1, "hello %s", "world") // INLINE: hello world assert.True(t, ok) assert.Equal(t, "hello world", value) }) diff --git a/test/option.go b/keeltest/option.go similarity index 100% rename from test/option.go rename to keeltest/option.go diff --git a/test/require/assertions.go b/keeltest/require/assertions.go similarity index 83% rename from test/require/assertions.go rename to keeltest/require/assertions.go index a9956e5..0e43989 100644 --- a/test/require/assertions.go +++ b/keeltest/require/assertions.go @@ -5,8 +5,8 @@ import ( "fmt" "testing" + "github.com/foomo/keel/keeltest" "github.com/foomo/keel/log" - keeltestutil "github.com/foomo/keel/test/util" "github.com/stretchr/testify/require" "github.com/tidwall/pretty" ) @@ -26,7 +26,7 @@ func New(t *testing.T) *Assertions { //nolint:thelper func (a *Assertions) InlineEqual(actual interface{}, msgAndArgs ...interface{}) { a.t.Helper() - if expected, ok := keeltestutil.Inline(a.t, 2, "%v", actual); ok { + if expected, ok := keeltest.Inline(a.t, 2, "%v", actual); ok { require.Equal(a.t, expected, fmt.Sprintf("%v", actual), msgAndArgs...) } } @@ -38,7 +38,7 @@ func (a *Assertions) InlineJSONEq(actual interface{}, msgAndArgs ...interface{}) if err != nil { a.t.Fatal("failed to marshal json", log.FError(err)) } - if expected, ok := keeltestutil.Inline(a.t, 2, string(actualBytes)); ok { + if expected, ok := keeltest.Inline(a.t, 2, string(actualBytes)); ok { require.Equal(a.t, string(pretty.Pretty([]byte(expected))), string(pretty.Pretty(actualBytes)), msgAndArgs...) } } diff --git a/test/require/require.go b/keeltest/require/require.go similarity index 78% rename from test/require/require.go rename to keeltest/require/require.go index c26a819..5d38172 100644 --- a/test/require/require.go +++ b/keeltest/require/require.go @@ -5,15 +5,15 @@ import ( "fmt" "testing" + "github.com/foomo/keel/keeltest" "github.com/foomo/keel/log" - keeltestutil "github.com/foomo/keel/test/util" "github.com/stretchr/testify/require" "github.com/tidwall/pretty" ) func InlineEqual(t *testing.T, actual interface{}, msgAndArgs ...interface{}) { t.Helper() - if expected, ok := keeltestutil.Inline(t, 2, "%v", actual); ok { + if expected, ok := keeltest.Inline(t, 2, "%v", actual); ok { require.Equal(t, expected, fmt.Sprintf("%v", actual), msgAndArgs...) } } @@ -25,7 +25,7 @@ func InlineJSONEq(t *testing.T, actual interface{}, msgAndArgs ...interface{}) { if err != nil { t.Fatal("failed to marshal json", log.FError(err)) } - if expected, ok := keeltestutil.Inline(t, 2, string(actualBytes)); ok { + if expected, ok := keeltest.Inline(t, 2, string(actualBytes)); ok { require.Equal(t, string(pretty.Pretty([]byte(expected))), string(pretty.Pretty(actualBytes)), msgAndArgs...) } } diff --git a/test/server.go b/keeltest/server.go similarity index 95% rename from test/server.go rename to keeltest/server.go index 6a83b12..c0200d4 100644 --- a/test/server.go +++ b/keeltest/server.go @@ -5,7 +5,7 @@ import ( "github.com/spf13/viper" "go.opentelemetry.io/otel/metric" - "go.opentelemetry.io/otel/metric/nonrecording" + "go.opentelemetry.io/otel/metric/noop" "go.opentelemetry.io/otel/trace" "go.uber.org/zap" @@ -34,7 +34,7 @@ func NewServer(opts ...Option) *Server { } { - inst.meterProvider = nonrecording.NewNoopMeterProvider() + inst.meterProvider = noop.NewMeterProvider() inst.meter = inst.meterProvider.Meter("github.com/foomo/keel") traceProfiver, err := telemetry.NewNoopTraceProvider() log.Must(inst.l, err, "failed to create noop trace provider") diff --git a/test/service.go b/keeltest/service.go similarity index 100% rename from test/service.go rename to keeltest/service.go diff --git a/test/servicehttp.go b/keeltest/servicehttp.go similarity index 100% rename from test/servicehttp.go rename to keeltest/servicehttp.go diff --git a/log/fields_http.go b/log/fields_http.go index 04e7923..d49704b 100644 --- a/log/fields_http.go +++ b/log/fields_http.go @@ -48,6 +48,9 @@ const ( // HTTPTrackingIDKey represents the HTTP tracking id if known (e.g. from X-Tracking-ID). HTTPTrackingIDKey = "http_tracking_id" + + // HTTPRefererKey identifies the address of the web page (i.e., the URI or IRI), from which the resource has been requested. + HTTPRefererKey = "http_referer" ) func FHTTPServerName(id string) zap.Field { @@ -98,6 +101,10 @@ func FHTTPUserAgent(userAgent string) zap.Field { return zap.String(HTTPUserAgentKey, userAgent) } +func FHTTPReferer(host string) zap.Field { + return zap.String(HTTPRefererKey, host) +} + func FHTTPHost(host string) zap.Field { return zap.String(HTTPHostKey, host) } diff --git a/log/fields_keel.go b/log/fields_keel.go new file mode 100644 index 0000000..81352ee --- /dev/null +++ b/log/fields_keel.go @@ -0,0 +1,11 @@ +package log + +import ( + "go.opentelemetry.io/otel/attribute" +) + +const ( + KeelServiceTypeKey = attribute.Key("keel.service.type") + KeelServiceNameKey = attribute.Key("keel.service.name") + KeelServiceInstKey = attribute.Key("keel.service.inst") +) diff --git a/log/fields_service.go b/log/fields_service.go index 3c20e7b..0496e91 100644 --- a/log/fields_service.go +++ b/log/fields_service.go @@ -15,6 +15,8 @@ func FPeerService(name string) zap.Field { } const ( + ServiceTypeKey = "service_type" + // ServiceNameKey represents the NameKey of the service. ServiceNameKey = "service_name" @@ -35,6 +37,10 @@ const ( ServiceVersionKey = "service_version" ) +func FServiceType(name string) zap.Field { + return zap.String(ServiceTypeKey, name) +} + func FServiceName(name string) zap.Field { return zap.String(ServiceNameKey, name) } diff --git a/log/fields_trace.go b/log/fields_trace.go index 0691d04..3c527af 100644 --- a/log/fields_trace.go +++ b/log/fields_trace.go @@ -5,9 +5,14 @@ import ( ) const ( + SpanID = "span_id" TraceID = "trace_id" ) +func FSpanID(traceID string) zap.Field { + return zap.String(SpanID, traceID) +} + func FTraceID(traceID string) zap.Field { return zap.String(TraceID, traceID) } diff --git a/log/labeler.go b/log/labeler.go index 0f98b6c..3532bb8 100644 --- a/log/labeler.go +++ b/log/labeler.go @@ -35,9 +35,9 @@ func InjectLabeler(ctx context.Context, key LabelerContextKey) (context.Context, return context.WithValue(ctx, key, l), l } -func LabelerFromContext(ctx context.Context, key LabelerContextKey) (context.Context, *Labeler) { +func LabelerFromContext(ctx context.Context, key LabelerContextKey) (*Labeler, bool) { if l, ok := ctx.Value(key).(*Labeler); ok { - return ctx, l + return l, true } - return InjectLabeler(ctx, key) + return nil, false } diff --git a/log/log.go b/log/logger.go similarity index 62% rename from log/log.go rename to log/logger.go index 1a27662..b0b5e1d 100644 --- a/log/log.go +++ b/log/logger.go @@ -2,7 +2,6 @@ package log import ( "fmt" - "time" "go.uber.org/zap" "go.uber.org/zap/zapcore" @@ -10,60 +9,40 @@ import ( "github.com/foomo/keel/env" ) -const ( - ModeDev = "dev" - ModeProd = "prod" -) - var ( config zap.Config atomicLevel = zap.NewAtomicLevelAt(zap.InfoLevel) ) func init() { - var level string - switch env.Get("LOG_MODE", ModeProd) { - case ModeDev: - config = NewDevelopmentConfig() - level = env.Get("LOG_LEVEL", "debug") - default: - config = NewProductionConfig() - level = env.Get("LOG_LEVEL", "info") + zap.ReplaceGlobals(NewLogger( + env.Get("LOG_LEVEL", "info"), + env.Get("LOG_FORMAT", "json"), + )) +} + +// NewLogger return a new logger instance +func NewLogger(level, encoding string) *zap.Logger { + config = zap.NewProductionConfig() + if value, err := zapcore.ParseLevel(level); err == nil { + atomicLevel.SetLevel(value) } + config.Encoding = encoding config.Level = atomicLevel config.EncoderConfig.TimeKey = "time" - config.DisableCaller = env.GetBool("LOG_DISABLE_STACKTRACE", true) - config.DisableStacktrace = env.GetBool("LOG_DISABLE_CALLER", true) - - if value, err := config.Build(); err != nil { - panic(err) - } else { - zap.ReplaceGlobals(value) + config.EncoderConfig.EncodeTime = zapcore.RFC3339NanoTimeEncoder + if encoding == "console" { + config.EncoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder } - - if value, err := zapcore.ParseLevel(env.Get("LOG_LEVEL", level)); err != nil { + config.DisableCaller = env.GetBool("LOG_DISABLE_STACKTRACE", !config.Level.Enabled(zap.DebugLevel)) + config.DisableStacktrace = env.GetBool("LOG_DISABLE_CALLER", !config.Level.Enabled(zap.DebugLevel)) + if value, err := config.Build(); err != nil { panic(err) } else { - atomicLevel.SetLevel(value) + return value } } -func NewProductionConfig() zap.Config { - config = zap.NewProductionConfig() - config.Encoding = env.Get("LOG_ENCODING", "json") - config.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder - return config -} - -func NewDevelopmentConfig() zap.Config { - config = zap.NewDevelopmentConfig() - config.Encoding = env.Get("LOG_ENCODING", "console") - config.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder - config.EncoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder - config.EncoderConfig.EncodeTime = func(t time.Time, enc zapcore.PrimitiveArrayEncoder) {} - return config -} - // Logger return the logger instance func Logger() *zap.Logger { return zap.L() diff --git a/log/with.go b/log/with.go index 1322792..e8d7640 100644 --- a/log/with.go +++ b/log/with.go @@ -7,6 +7,7 @@ import ( "net/http" "strings" + "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/trace" "go.uber.org/zap" @@ -20,6 +21,17 @@ func With(l *zap.Logger, fields ...zap.Field) *zap.Logger { return l.With(fields...) } +func WithAttributes(l *zap.Logger, attrs ...attribute.KeyValue) *zap.Logger { + if l == nil { + l = Logger() + } + fields := make([]zap.Field, len(attrs)) + for i, attr := range attrs { + fields[i] = zap.Any(strings.ReplaceAll(string(attr.Key), ".", "_"), attr.Value.AsInterface()) + } + return l.With(fields...) +} + func WithError(l *zap.Logger, err error) *zap.Logger { return With(l, FErrorType(err), FError(err)) } @@ -28,9 +40,9 @@ func WithServiceName(l *zap.Logger, name string) *zap.Logger { return With(l, FServiceName(name)) } -func WithTraceID(l *zap.Logger, ctx context.Context) *zap.Logger { - if spanCtx := trace.SpanContextFromContext(ctx); spanCtx.IsValid() { - l = With(l, FTraceID(spanCtx.TraceID().String())) +func WithTraceID(l *zap.Logger, ctx context.Context) *zap.Logger { //nolint:revive + if spanCtx := trace.SpanContextFromContext(ctx); spanCtx.IsValid() && spanCtx.IsSampled() { + l = With(l, FTraceID(spanCtx.TraceID().String()), FSpanID(spanCtx.SpanID().String())) } return l } @@ -77,6 +89,16 @@ func WithHTTPRequestID(l *zap.Logger, r *http.Request) *zap.Logger { } } +func WithHTTPReferer(l *zap.Logger, r *http.Request) *zap.Logger { + if value := r.Header.Get("X-Referer"); value != "" { + return With(l, FHTTPReferer(value)) + } else if value := r.Referer(); value != "" { + return With(l, FHTTPReferer(value)) + } else { + return l + } +} + func WithHTTPHost(l *zap.Logger, r *http.Request) *zap.Logger { if value := r.Header.Get("X-Forwarded-Host"); value != "" { return With(l, FHTTPHost(value)) @@ -120,6 +142,7 @@ func WithHTTPClientIP(l *zap.Logger, r *http.Request) *zap.Logger { func WithHTTPRequest(l *zap.Logger, r *http.Request) *zap.Logger { l = WithHTTPHost(l, r) + l = WithHTTPReferer(l, r) l = WithHTTPRequestID(l, r) l = WithHTTPSessionID(l, r) l = WithHTTPTrackingID(l, r) diff --git a/markdown/markdown.go b/markdown/markdown.go new file mode 100644 index 0000000..f195964 --- /dev/null +++ b/markdown/markdown.go @@ -0,0 +1,40 @@ +package markdown + +import ( + "fmt" + + markdowntable "github.com/fbiville/markdown-table-formatter/pkg/markdown" +) + +// Markdown output helper +type Markdown struct { + value string +} + +func (s *Markdown) Println(a ...any) { + s.value += fmt.Sprintln(a...) +} + +func (s *Markdown) Printf(format string, a ...any) { + s.Println(fmt.Sprintf(format, a...)) +} + +func (s *Markdown) Print(a ...any) { + s.value += fmt.Sprint(a...) +} + +func (s *Markdown) String() string { + return s.value +} + +func (s *Markdown) Table(headers []string, rows [][]string) { + table, err := markdowntable.NewTableFormatterBuilder(). + WithAlphabeticalSortIn(markdowntable.ASCENDING_ORDER). + WithPrettyPrint(). + Build(headers...). + Format(rows) + if err != nil { + panic(err) + } + s.Print(table) +} diff --git a/markdown/utils.go b/markdown/utils.go new file mode 100644 index 0000000..bea89ff --- /dev/null +++ b/markdown/utils.go @@ -0,0 +1,28 @@ +package markdown + +import ( + "fmt" +) + +func Code(v string) string { + if v == "" { + return "" + } + return "`" + v + "`" +} + +func Name(v any) string { + if i, ok := v.(interface { + Name() string + }); ok { + return i.Name() + } + return "" +} + +func String(v any) string { + if i, ok := v.(fmt.Stringer); ok { + return i.String() + } + return "" +} diff --git a/metrics/readme.go b/metrics/readme.go new file mode 100644 index 0000000..9273505 --- /dev/null +++ b/metrics/readme.go @@ -0,0 +1,32 @@ +package metrics + +import ( + "github.com/foomo/keel/markdown" + "github.com/prometheus/client_golang/prometheus" +) + +func Readme() string { + md := markdown.Markdown{} + var rows [][]string + + if gatherer, err := prometheus.DefaultGatherer.Gather(); err == nil { + for _, value := range gatherer { + rows = append(rows, []string{ + markdown.Code(value.GetName()), + value.GetType().String(), + value.GetHelp(), + }) + } + } + + if len(rows) > 0 { + md.Println("### Metrics") + md.Println("") + md.Println("List of all registered metrics than are being exposed.") + md.Println("") + md.Table([]string{"Name", "Type", "Description"}, rows) + md.Println("") + } + + return md.String() +} diff --git a/net/gotsrpc/errors.go b/net/gotsrpc/errors.go index 6105d64..46219ce 100644 --- a/net/gotsrpc/errors.go +++ b/net/gotsrpc/errors.go @@ -19,7 +19,7 @@ func NewError(e Error) *Error { func (e *Error) Is(err error) bool { if e == nil || err == nil { return false - } else if v, ok := err.(*Error); ok && v != nil { //nolint:errorlint + } else if v, ok := err.(*Error); ok && v != nil { return e.Error() == v.Error() } return false diff --git a/net/http/context/referrer.go b/net/http/context/referrer.go new file mode 100644 index 0000000..2c04a55 --- /dev/null +++ b/net/http/context/referrer.go @@ -0,0 +1,19 @@ +package context + +import ( + "context" +) + +const ContextKeyReferer contextKey = "referer" + +func GetReferer(ctx context.Context) (string, bool) { + if value, ok := ctx.Value(ContextKeyReferer).(string); ok { + return value, true + } else { + return "", false + } +} + +func SetReferer(ctx context.Context, referer string) context.Context { + return context.WithValue(ctx, ContextKeyReferer, referer) +} diff --git a/net/http/header.go b/net/http/header.go index 1524c12..2f8235f 100644 --- a/net/http/header.go +++ b/net/http/header.go @@ -36,6 +36,7 @@ const ( HeaderServer = "Server" HeaderTrueClientIP = "True-Client-Ip" HeaderOrigin = "Origin" + HeaderXReferer = "X-Referer" HeaderUserAgent = "User-Agent" // Cloudflare diff --git a/net/http/log/labeler.go b/net/http/log/labeler.go new file mode 100644 index 0000000..fe545f9 --- /dev/null +++ b/net/http/log/labeler.go @@ -0,0 +1,27 @@ +package log + +import ( + "context" + "net/http" + + "github.com/foomo/keel/log" +) + +const loggerLabelerContextKey log.LabelerContextKey = "github.com/foomo/keel/net/log.Labeler" + +func LabelerFromContext(ctx context.Context) (*log.Labeler, bool) { + return log.LabelerFromContext(ctx, loggerLabelerContextKey) +} + +func LabelerFromRequest(r *http.Request) (*log.Labeler, bool) { + return log.LabelerFromContext(r.Context(), loggerLabelerContextKey) +} + +func InjectLabelerIntoContext(ctx context.Context) (context.Context, *log.Labeler) { + return log.InjectLabeler(ctx, loggerLabelerContextKey) +} + +func InjectLabelerIntoRequest(r *http.Request) (*http.Request, *log.Labeler) { + ctx, labeler := InjectLabelerIntoContext(r.Context()) + return r.WithContext(ctx), labeler +} diff --git a/net/http/middleware/cors_test.go b/net/http/middleware/cors_test.go index 67b671e..f1b15d1 100644 --- a/net/http/middleware/cors_test.go +++ b/net/http/middleware/cors_test.go @@ -5,9 +5,9 @@ import ( "net/http/httptest" "testing" + keelassert "github.com/foomo/keel/keeltest/assert" keelhttp "github.com/foomo/keel/net/http" "github.com/foomo/keel/net/http/middleware" - keelassert "github.com/foomo/keel/test/assert" "go.uber.org/zap/zaptest" ) diff --git a/net/http/middleware/jwt.go b/net/http/middleware/jwt.go index d165ecf..2971f70 100644 --- a/net/http/middleware/jwt.go +++ b/net/http/middleware/jwt.go @@ -125,18 +125,18 @@ func JWTWithSetContext(v bool) JWTOption { } // JWT middleware -func JWT(jwt *jwt.JWT, contextKey interface{}, opts ...JWTOption) Middleware { +func JWT(v *jwt.JWT, contextKey interface{}, opts ...JWTOption) Middleware { options := GetDefaultJWTOptions() for _, opt := range opts { if opt != nil { opt(&options) } } - return JWTWithOptions(jwt, contextKey, options) + return JWTWithOptions(v, contextKey, options) } // JWTWithOptions middleware -func JWTWithOptions(jwt *jwt.JWT, contextKey interface{}, opts JWTOptions) Middleware { +func JWTWithOptions(v *jwt.JWT, contextKey interface{}, opts JWTOptions) Middleware { return func(l *zap.Logger, name string, next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { claims := opts.ClaimsProvider() @@ -174,7 +174,7 @@ func JWTWithOptions(jwt *jwt.JWT, contextKey interface{}, opts JWTOptions) Middl } // handle existing token - jwtToken, err := jwt.ParseWithClaims(token, claims) + jwtToken, err := v.ParseWithClaims(token, claims) if err != nil { if resume := opts.ErrorHandler(l, w, r, err); resume { next.ServeHTTP(w, r) diff --git a/net/http/middleware/logger.go b/net/http/middleware/logger.go index aaea0ab..7908f7a 100644 --- a/net/http/middleware/logger.go +++ b/net/http/middleware/logger.go @@ -1,18 +1,16 @@ package middleware import ( - "context" "net/http" "time" + httplog "github.com/foomo/keel/net/http/log" "go.uber.org/zap" "github.com/foomo/keel/log" keeltime "github.com/foomo/keel/time" ) -const loggerLabelerContextKey log.LabelerContextKey = "github.com/foomo/keel/net/middleware.Logger" - type ( LoggerOptions struct { Message string @@ -29,7 +27,7 @@ func GetDefaultLoggerOptions() LoggerOptions { Message: "handled http request", MinWarnCode: 400, MinErrorCode: 500, - InjectLabeler: false, + InjectLabeler: true, } } @@ -85,8 +83,8 @@ func LoggerWithOptions(opts LoggerOptions) Middleware { var labeler *log.Labeler - if opts.InjectLabeler { - r, labeler = LoggerLabelerFromRequest(r) + if labeler == nil && opts.InjectLabeler { + r, labeler = httplog.InjectLabelerIntoRequest(r) } next.ServeHTTP(wr, r) @@ -112,12 +110,3 @@ func LoggerWithOptions(opts LoggerOptions) Middleware { }) } } - -func LoggerLabelerFromContext(ctx context.Context) (context.Context, *log.Labeler) { - return log.LabelerFromContext(ctx, loggerLabelerContextKey) -} - -func LoggerLabelerFromRequest(r *http.Request) (*http.Request, *log.Labeler) { - ctx, l := log.LabelerFromContext(r.Context(), loggerLabelerContextKey) - return r.WithContext(ctx), l -} diff --git a/net/http/middleware/logger_test.go b/net/http/middleware/logger_test.go index faf7d3b..386c5f3 100644 --- a/net/http/middleware/logger_test.go +++ b/net/http/middleware/logger_test.go @@ -4,9 +4,10 @@ import ( "fmt" "net/http" + "github.com/foomo/keel/keeltest" "github.com/foomo/keel/log" + httplog "github.com/foomo/keel/net/http/log" "github.com/foomo/keel/net/http/middleware" - keeltest "github.com/foomo/keel/test" "go.uber.org/zap" ) @@ -57,8 +58,9 @@ func ExampleLoggerWithInjectLabeler() { keeltest.NewServiceHTTP(l, "demo", svs, func(l *zap.Logger, s string, next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - r, labeler := middleware.LoggerLabelerFromRequest(r) - labeler.Add(zap.String("injected", "message")) + if labeler, ok := httplog.LabelerFromRequest(r); ok { + labeler.Add(zap.String("injected", "message")) + } next.ServeHTTP(w, r) }) }, diff --git a/net/http/middleware/referrer.go b/net/http/middleware/referrer.go new file mode 100644 index 0000000..c9b1448 --- /dev/null +++ b/net/http/middleware/referrer.go @@ -0,0 +1,67 @@ +package middleware + +import ( + "net/http" + + "github.com/foomo/keel/net/http/context" + "go.uber.org/zap" +) + +type ( + RefererOptions struct { + RequestHeader []string + SetContext bool + } + RefererOption func(*RefererOptions) +) + +// GetDefaultRefererOptions returns the default options +func GetDefaultRefererOptions() RefererOptions { + return RefererOptions{ + RequestHeader: []string{"X-Referer", "Referer"}, + SetContext: true, + } +} + +// RefererWithRequestHeader middleware option +func RefererWithRequestHeader(v ...string) RefererOption { + return func(o *RefererOptions) { + o.RequestHeader = append(o.RequestHeader, v...) + } +} + +// RefererWithSetContext middleware option +func RefererWithSetContext(v bool) RefererOption { + return func(o *RefererOptions) { + o.SetContext = v + } +} + +// Referer middleware +func Referer(opts ...RefererOption) Middleware { + options := GetDefaultRefererOptions() + for _, opt := range opts { + if opt != nil { + opt(&options) + } + } + return RefererWithOptions(options) +} + +// RefererWithOptions middleware +func RefererWithOptions(opts RefererOptions) Middleware { + return func(l *zap.Logger, name string, next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + var referer string + for _, value := range opts.RequestHeader { + if referer = r.Header.Get(value); referer != "" { + break + } + } + if referer != "" && opts.SetContext { + r = r.WithContext(context.SetReferer(r.Context(), referer)) + } + next.ServeHTTP(w, r) + }) + } +} diff --git a/net/http/middleware/telemetry.go b/net/http/middleware/telemetry.go index d29238f..a48ffdb 100644 --- a/net/http/middleware/telemetry.go +++ b/net/http/middleware/telemetry.go @@ -1,15 +1,16 @@ package middleware import ( + "fmt" "net/http" + "github.com/foomo/keel/log" + httplog "github.com/foomo/keel/net/http/log" "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" "go.opentelemetry.io/otel" - "go.opentelemetry.io/otel/metric" - "go.opentelemetry.io/otel/metric/global" - "go.opentelemetry.io/otel/metric/instrument" "go.opentelemetry.io/otel/propagation" - semconv "go.opentelemetry.io/otel/semconv/v1.10.0" + semconv "go.opentelemetry.io/otel/semconv/v1.12.0" + "go.opentelemetry.io/otel/trace" "go.uber.org/zap" ) @@ -25,7 +26,11 @@ type ( // GetDefaultTelemetryOptions returns the default options func GetDefaultTelemetryOptions() TelemetryOptions { return TelemetryOptions{ - OtelOpts: []otelhttp.Option{}, + OtelOpts: []otelhttp.Option{ + otelhttp.WithSpanNameFormatter(func(operation string, r *http.Request) string { + return fmt.Sprintf("HTTP %s", operation) + }), + }, InjectPropagationHeader: true, } } @@ -56,7 +61,7 @@ func TelemetryWithInjectPropagationHeader(v bool) TelemetryOption { // TelemetryWithOtelOpts middleware options func TelemetryWithOtelOpts(v ...otelhttp.Option) TelemetryOption { return func(o *TelemetryOptions) { - o.OtelOpts = v + o.OtelOpts = append(o.OtelOpts, v...) } } @@ -66,31 +71,27 @@ func TelemetryWithOptions(opts TelemetryOptions) Middleware { if opts.Name != "" { name = opts.Name } - // TODO remove once https://github.com/open-telemetry/opentelemetry-go-contrib/pull/771 is merged - m := global.MeterProvider().Meter( - "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp", - metric.WithInstrumentationVersion(otelhttp.SemVersion()), - ) - c, err := m.SyncInt64().Counter( - otelhttp.RequestCount, - instrument.WithDescription("counts number of requests withs specific status code"), - ) - if err != nil { - otel.Handle(err) - } return otelhttp.NewHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if opts.InjectPropagationHeader { otel.GetTextMapPropagator().Inject(r.Context(), propagation.HeaderCarrier(w.Header())) } + if labeler, ok := otelhttp.LabelerFromContext(r.Context()); ok { + labeler.Add(semconv.HTTPServerNameKey.String(name)) + } + + if labeler, ok := httplog.LabelerFromRequest(r); ok { + if spanCtx := trace.SpanContextFromContext(r.Context()); spanCtx.IsValid() && spanCtx.IsSampled() { + labeler.Add(log.FTraceID(spanCtx.TraceID().String())) + labeler.Add(log.FSpanID(spanCtx.SpanID().String())) + } + } + // wrap response write to get access to status & size wr := WrapResponseWriter(w) next.ServeHTTP(wr, r) - - labeler, _ := otelhttp.LabelerFromContext(r.Context()) - c.Add(r.Context(), 1, append(labeler.Get(), semconv.HTTPStatusCodeKey.Int(wr.StatusCode()))...) }), name, opts.OtelOpts...) } } diff --git a/net/http/roundtripware/circuitbreaker.go b/net/http/roundtripware/circuitbreaker.go index 3c31c5d..407bcfa 100644 --- a/net/http/roundtripware/circuitbreaker.go +++ b/net/http/roundtripware/circuitbreaker.go @@ -10,8 +10,6 @@ import ( "github.com/sony/gobreaker" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/metric" - "go.opentelemetry.io/otel/metric/instrument" - "go.opentelemetry.io/otel/metric/instrument/syncint64" "go.uber.org/zap" ) @@ -20,6 +18,14 @@ var ( // RoundTripware. It wraps the two gobreaker errors (ErrTooManyRequests & ErrOpenState) so only one comparison is // needed ErrCircuitBreaker = errors.New("circuit breaker triggered") + + // ErrIgnoreSuccessfulness can be returned by the IsSuccessful callback in order for the RoundTripware to ignore the + // result of the function + ErrIgnoreSuccessfulness = errors.New("ignored successfulness") + + // ErrReadFromActualBody when it is attempted to read from a body in the IsSuccessful callback that has not + // previously been copied. + ErrReadFromActualBody = errors.New("read from actual body") ) // CircuitBreakerSettings is a copy of the gobreaker.Settings, except that the IsSuccessful function is omitted since we @@ -49,7 +55,7 @@ type CircuitBreakerSettings struct { } type CircuitBreakerOptions struct { - Counter syncint64.Counter + Counter metric.Int64Counter IsSuccessful func(err error, req *http.Request, resp *http.Response) error CopyReqBody bool @@ -77,9 +83,9 @@ func CircuitBreakerWithMetric( meterDescription string, ) CircuitBreakerOption { // intitialize the success counter - counter, err := meter.SyncInt64().Counter( + counter, err := meter.Int64Counter( meterName, - instrument.WithDescription(meterDescription), + metric.WithDescription(meterDescription), ) if err != nil { panic(err) @@ -122,10 +128,10 @@ func CircuitBreaker(set *CircuitBreakerSettings, opts ...CircuitBreakerOption) R ReadyToTrip: set.ReadyToTrip, OnStateChange: set.OnStateChange, } - circuitBreaker := gobreaker.NewCircuitBreaker(cbrSettings) + circuitBreaker := gobreaker.NewTwoStepCircuitBreaker(cbrSettings) return func(l *zap.Logger, next Handler) Handler { - return func(r *http.Request) (*http.Response, error) { + return func(r *http.Request) (resp *http.Response, err error) { //nolint:nonamedreturns if r == nil { return nil, errors.New("request is nil") } @@ -133,6 +139,32 @@ func CircuitBreaker(set *CircuitBreakerSettings, opts ...CircuitBreakerOption) R // we need to detect the state change by ourselves, because the context does not allow us to hand in a context fromState := circuitBreaker.State() + defer func() { + // detect and log a state change + toState := circuitBreaker.State() + if fromState != toState { + l.Warn("state change occurred", + zap.String("state_from", fromState.String()), + zap.String("state_to", toState.String()), + ) + } + + attributes := []attribute.KeyValue{ + attribute.String("current_state", toState.String()), + attribute.String("previous_state", fromState.String()), + attribute.Bool("state_change", fromState != toState), + } + if err != nil { + if o.Counter != nil { + attributes := append(attributes, attribute.Bool("error", true)) + o.Counter.Add(r.Context(), 1, metric.WithAttributes(attributes...)) + } + } else if o.Counter != nil { + attributes := append(attributes, attribute.Bool("error", false)) + o.Counter.Add(r.Context(), 1, metric.WithAttributes(attributes...)) + } + }() + // clone the request and the body if wanted var errCopy error reqCopy, errCopy := copyRequest(r, o.CopyReqBody) @@ -144,15 +176,27 @@ func CircuitBreaker(set *CircuitBreakerSettings, opts ...CircuitBreakerOption) R defer reqCopy.Body.Close() } - // call the next handler enclosed in the circuit breaker. - resp, err := circuitBreaker.Execute(func() (interface{}, error) { - resp, err := next(r) //nolint:bodyclose - if resp == nil { - return nil, o.IsSuccessful(err, reqCopy, nil) - } + // check whether the circuit breaker is closed (an error is returned if not) + done, err := circuitBreaker.Allow() + + // wrap the error in case it was produced because of the circuit breaker being (half-)open + if errors.Is(err, gobreaker.ErrTooManyRequests) || errors.Is(err, gobreaker.ErrOpenState) { + return nil, keelerrors.NewWrappedError(ErrCircuitBreaker, err) + } else if err != nil { + l.Error("unexpected error in circuit breaker", + log.FError(err), + zap.String("state", fromState.String()), + ) + return nil, err + } + + // continue with the middleware chain + resp, err = next(r) + var respCopy *http.Response + if resp != nil { // clone the response and the body if wanted - respCopy, errCopy := copyResponse(resp, o.CopyRespBody) + respCopy, errCopy = copyResponse(resp, o.CopyRespBody) if errCopy != nil { l.Error("unable to copy response", log.FError(errCopy)) return nil, errCopy @@ -160,47 +204,22 @@ func CircuitBreaker(set *CircuitBreakerSettings, opts ...CircuitBreakerOption) R // make sure the body is closed again - since it is a NopCloser it does not make a difference though defer respCopy.Body.Close() } - - return resp, o.IsSuccessful(err, reqCopy, respCopy) - }) - - // detect and log a state change - toState := circuitBreaker.State() - if fromState != toState { - l.Warn("state change occurred", - zap.String("from", fromState.String()), - zap.String("to", toState.String()), - ) } - // wrap the error in case it was produced because of the circuit breaker being (half-)open - if errors.Is(gobreaker.ErrTooManyRequests, err) || errors.Is(gobreaker.ErrOpenState, err) { - err = keelerrors.NewWrappedError(ErrCircuitBreaker, err) - } - - attributes := []attribute.KeyValue{ - attribute.String("current_state", toState.String()), - attribute.String("previous_state", fromState.String()), - attribute.Bool("state_change", fromState != toState), - } - if err != nil { - if o.Counter != nil { - attributes := append(attributes, attribute.Bool("error", true)) - o.Counter.Add(r.Context(), 1, attributes...) - } - return nil, err - } - - if o.Counter != nil { - attributes := append(attributes, attribute.Bool("error", false)) - o.Counter.Add(r.Context(), 1, attributes...) + if errSuccess := o.IsSuccessful(err, reqCopy, respCopy); errors.Is(errSuccess, errNoBody) { + l.Error("encountered read from not previously copied request/response body", + zap.Bool("copy_request", o.CopyReqBody), + zap.Bool("copy_response", o.CopyRespBody), + ) + // we actually want to return an error instead of the original request and error since the user + // should be made aware that there is a misconfiguration + return nil, ErrReadFromActualBody + } else if !errors.Is(errSuccess, ErrIgnoreSuccessfulness) { + done(errSuccess == nil) } - if res, ok := resp.(*http.Response); ok { - return res, nil - } else { - return nil, errors.New("result is no *http.Response") - } + // return the response and error received from the next call + return resp, err } } } diff --git a/net/http/roundtripware/circuitbreaker_test.go b/net/http/roundtripware/circuitbreaker_test.go index 784a881..36804b4 100644 --- a/net/http/roundtripware/circuitbreaker_test.go +++ b/net/http/roundtripware/circuitbreaker_test.go @@ -3,6 +3,7 @@ package roundtripware_test import ( "context" "errors" + "fmt" "io" "net/http" "net/http/httptest" @@ -13,6 +14,7 @@ import ( keelhttp "github.com/foomo/keel/net/http" "github.com/foomo/keel/net/http/roundtripware" "github.com/sony/gobreaker" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/zap/zaptest" ) @@ -23,7 +25,7 @@ var cbSettings = &roundtripware.CircuitBreakerSettings{ // MaxRequests is the maximum number of requests allowed to pass through // when the CircuitBreaker is half-open. // If MaxRequests is 0, the CircuitBreaker allows only 1 request. - MaxRequests: 1, + MaxRequests: 2, // Interval is the cyclic period of the closed state // for the CircuitBreaker to clear the internal Counts. // If Interval is less than or equal to 0, the CircuitBreaker doesn't clear internal Counts during the closed state. @@ -39,6 +41,9 @@ var cbSettings = &roundtripware.CircuitBreakerSettings{ ReadyToTrip: func(counts gobreaker.Counts) bool { return counts.ConsecutiveFailures > 3 }, + OnStateChange: func(name string, from gobreaker.State, to gobreaker.State) { + _, _ = fmt.Printf("\n\nstate changed from %s to %s\n\n", from, to) + }, } func TestCircuitBreaker(t *testing.T) { @@ -52,7 +57,6 @@ func TestCircuitBreaker(t *testing.T) { if i < 5 { w.WriteHeader(http.StatusInternalServerError) } - w.WriteHeader(http.StatusOK) })) defer svr.Close() @@ -66,19 +70,39 @@ func TestCircuitBreaker(t *testing.T) { return errors.New("invalid status code") } return nil - }, true, true, + }, false, false, ), ), ), ) + { + client := keelhttp.NewHTTPClient( + keelhttp.HTTPClientWithRoundTripware(l, + roundtripware.CircuitBreaker( + &roundtripware.CircuitBreakerSettings{ + Name: "my little circuit breakerâ„¢", + MaxRequests: 1, + Interval: time.Minute, + Timeout: 30 * time.Second, + ReadyToTrip: func(counts gobreaker.Counts) bool { + return counts.ConsecutiveFailures > 3 + }, + }, + ), + ), + ) + + _ = client + } + // do requests to trigger the circuit breaker for i := 0; i <= 3; i++ { req, err := http.NewRequestWithContext(context.Background(), http.MethodGet, svr.URL, nil) require.NoError(t, err) resp, err := client.Do(req) - if err == nil { - defer resp.Body.Close() + if resp != nil { + _ = resp.Body.Close() } require.NotErrorIs(t, err, roundtripware.ErrCircuitBreaker) } @@ -89,7 +113,7 @@ func TestCircuitBreaker(t *testing.T) { require.NoError(t, err) resp, err := client.Do(req) if err == nil { - defer resp.Body.Close() + _ = resp.Body.Close() } require.ErrorIs(t, err, roundtripware.ErrCircuitBreaker) @@ -99,8 +123,8 @@ func TestCircuitBreaker(t *testing.T) { req, err = http.NewRequestWithContext(context.Background(), http.MethodGet, svr.URL, nil) require.NoError(t, err) resp, err = client.Do(req) - if err == nil { - defer resp.Body.Close() + if resp != nil { + _ = resp.Body.Close() } require.NoError(t, err) } @@ -115,13 +139,10 @@ func TestCircuitBreakerCopyBodies(t *testing.T) { // create http server with handler svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { data, err := io.ReadAll(r.Body) - require.NoError(t, err) - require.Equal(t, string(data), requestData) - _, err = w.Write([]byte(responseData)) - if err != nil { - panic(err) + if assert.NoError(t, err) && assert.Equal(t, string(data), requestData) { + _, err = w.Write([]byte(responseData)) + assert.NoError(t, err) } - w.WriteHeader(http.StatusOK) })) defer svr.Close() @@ -139,7 +160,7 @@ func TestCircuitBreakerCopyBodies(t *testing.T) { require.NoError(t, errRead) // also try to close one of the bodies (should also be handled by the RoundTripware) - req.Body.Close() + _ = req.Body.Close() return err }, true, true, @@ -152,8 +173,8 @@ func TestCircuitBreakerCopyBodies(t *testing.T) { req, err := http.NewRequestWithContext(context.Background(), http.MethodGet, svr.URL, strings.NewReader(requestData)) require.NoError(t, err) resp, err := client.Do(req) - if err == nil { - defer resp.Body.Close() + if resp != nil { + _ = resp.Body.Close() } require.NoError(t, err) // make sure the correct data is returned @@ -172,13 +193,10 @@ func TestCircuitBreakerReadFromNotCopiedBodies(t *testing.T) { // create http server with handler svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { data, err := io.ReadAll(r.Body) - require.NoError(t, err) - require.Equal(t, string(data), requestData) - _, err = w.Write([]byte(responseData)) - if err != nil { - panic(err) + if assert.NoError(t, err) && assert.Equal(t, string(data), requestData) { + _, err = w.Write([]byte(responseData)) + assert.NoError(t, err) } - w.WriteHeader(http.StatusOK) })) defer svr.Close() @@ -205,10 +223,11 @@ func TestCircuitBreakerReadFromNotCopiedBodies(t *testing.T) { req, err := http.NewRequestWithContext(context.Background(), http.MethodGet, svr.URL, strings.NewReader(requestData)) require.NoError(t, err) resp, err := client.Do(req) - if err == nil { - defer resp.Body.Close() + if resp != nil { + _ = resp.Body.Close() } require.Error(t, err) + require.ErrorIs(t, err, roundtripware.ErrReadFromActualBody) // same thing for the response client = keelhttp.NewHTTPClient( @@ -233,10 +252,11 @@ func TestCircuitBreakerReadFromNotCopiedBodies(t *testing.T) { req, err = http.NewRequestWithContext(context.Background(), http.MethodGet, svr.URL, strings.NewReader(requestData)) require.NoError(t, err) resp, err = client.Do(req) - if err == nil { - defer resp.Body.Close() + if resp != nil { + _ = resp.Body.Close() } require.Error(t, err) + require.ErrorIs(t, err, roundtripware.ErrReadFromActualBody) } func TestCircuitBreakerInterval(t *testing.T) { @@ -268,7 +288,7 @@ func TestCircuitBreakerInterval(t *testing.T) { return errors.New("invalid status code") } return nil - }, true, true, + }, false, false, ), ), ), @@ -279,8 +299,8 @@ func TestCircuitBreakerInterval(t *testing.T) { req, err := http.NewRequestWithContext(context.Background(), http.MethodGet, svr.URL, nil) require.NoError(t, err) resp, err := client.Do(req) - if err == nil { - defer resp.Body.Close() + if resp != nil { + _ = resp.Body.Close() } require.NotErrorIs(t, err, roundtripware.ErrCircuitBreaker) } @@ -294,8 +314,8 @@ func TestCircuitBreakerInterval(t *testing.T) { req, err := http.NewRequestWithContext(context.Background(), http.MethodGet, svr.URL, nil) require.NoError(t, err) resp, err := client.Do(req) - if err == nil { - defer resp.Body.Close() + if resp != nil { + _ = resp.Body.Close() } require.NotErrorIs(t, err, roundtripware.ErrCircuitBreaker) } @@ -304,8 +324,99 @@ func TestCircuitBreakerInterval(t *testing.T) { req, err := http.NewRequestWithContext(context.Background(), http.MethodGet, svr.URL, nil) require.NoError(t, err) resp, err := client.Do(req) - if err == nil { - defer resp.Body.Close() + if resp != nil { + _ = resp.Body.Close() + } + require.ErrorIs(t, err, roundtripware.ErrCircuitBreaker) +} + +func TestCircuitBreakerIgnore(t *testing.T) { + // create logger + l := zaptest.NewLogger(t) + + // create http server with handler + svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // always return an invalid status code + w.WriteHeader(http.StatusInternalServerError) + })) + defer svr.Close() + + // create http client + client := keelhttp.NewHTTPClient( + keelhttp.HTTPClientWithRoundTripware(l, + roundtripware.CircuitBreaker(cbSettings, + roundtripware.CircuitBreakerWithIsSuccessful( + func(err error, req *http.Request, resp *http.Response) error { + if req.Method == http.MethodGet { + return roundtripware.ErrIgnoreSuccessfulness + } + if resp.StatusCode >= http.StatusInternalServerError { + return errors.New("invalid status code") + } + return nil + }, false, false, + ), + ), + ), + ) + + // send 4 requests (higher than the maximum amount of allowed consecutive failures), but they are ignored + // -> circuit breaker should remain open + for i := 0; i < 4; i++ { + req, err := http.NewRequestWithContext(context.Background(), http.MethodGet, svr.URL, nil) + require.NoError(t, err) + resp, err := client.Do(req) + if resp != nil { + _ = resp.Body.Close() + } + require.NotErrorIs(t, err, roundtripware.ErrCircuitBreaker) + require.NoError(t, err) + require.NotNil(t, resp) + } +} + +func TestCircuitBreakerTimeout(t *testing.T) { + // create logger + l := zaptest.NewLogger(t) + + // create http server with handler + svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + time.Sleep(250 * time.Millisecond) + })) + defer svr.Close() + + // create http client + client := keelhttp.NewHTTPClient( + keelhttp.HTTPClientWithRoundTripware(l, + roundtripware.CircuitBreaker(cbSettings), + ), + ) + + // send 4 requests (more than the maximum amount of allowed consecutive failures) + // -> circuit breaker should change to open state + for i := 0; i < 4; i++ { + ctx, cancel := context.WithTimeout(context.Background(), 200*time.Millisecond) + + req, err := http.NewRequestWithContext(ctx, http.MethodGet, svr.URL, nil) + require.NoError(t, err) + resp, err := client.Do(req) + if resp != nil { + _ = resp.Body.Close() + } + require.NotErrorIs(t, err, roundtripware.ErrCircuitBreaker) + require.ErrorIs(t, err, context.DeadlineExceeded) + cancel() + } + + // send another request with a bigger timeout + // this should be blocked by the circuit breaker though + ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond) + defer cancel() + req, err := http.NewRequestWithContext(ctx, http.MethodGet, svr.URL, nil) + require.NoError(t, err) + resp, err := client.Do(req) + if resp != nil { + _ = resp.Body.Close() } require.ErrorIs(t, err, roundtripware.ErrCircuitBreaker) } diff --git a/net/http/roundtripware/metric.go b/net/http/roundtripware/metric.go index d446432..f25b08e 100644 --- a/net/http/roundtripware/metric.go +++ b/net/http/roundtripware/metric.go @@ -6,15 +6,14 @@ import ( "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/metric" - "go.opentelemetry.io/otel/metric/instrument" "go.uber.org/zap" ) // Metric returns a RoundTripper which prints out the request & response object func Metric(meter metric.Meter, name, description string) RoundTripware { - histogram, err := meter.SyncFloat64().Histogram( + histogram, err := meter.Float64Histogram( name, - instrument.WithDescription(description), + metric.WithDescription(description), ) if err != nil { panic(err) @@ -37,7 +36,7 @@ func Metric(meter metric.Meter, name, description string) RoundTripware { attributes = append(labeler.Get(), attribute.Int("status_code", resp.StatusCode)) } - histogram.Record(ctx, duration.Seconds(), attributes...) + histogram.Record(ctx, duration.Seconds(), metric.WithAttributes(attributes...)) return resp, err } diff --git a/net/http/roundtripware/referer.go b/net/http/roundtripware/referer.go new file mode 100644 index 0000000..42d43fe --- /dev/null +++ b/net/http/roundtripware/referer.go @@ -0,0 +1,50 @@ +package roundtripware + +import ( + "net/http" + + "go.uber.org/zap" + + keelhttpcontext "github.com/foomo/keel/net/http/context" +) + +type ( + RefererOptions struct { + Header string + } + RefererOption func(*RefererOptions) +) + +// GetDefaultRefererOptions returns the default options +func GetDefaultRefererOptions() RefererOptions { + return RefererOptions{ + Header: "X-Referer", + } +} + +// RefererWithHeader middleware option +func RefererWithHeader(v string) RefererOption { + return func(o *RefererOptions) { + o.Header = v + } +} + +// Referer returns a RoundTripper which prints out the request & response object +func Referer(opts ...RefererOption) RoundTripware { + o := GetDefaultRefererOptions() + for _, opt := range opts { + if opt != nil { + opt(&o) + } + } + return func(l *zap.Logger, next Handler) Handler { + return func(r *http.Request) (*http.Response, error) { + if value := r.Header.Get(o.Header); value == "" { + if value, ok := keelhttpcontext.GetReferer(r.Context()); ok && value != "" { + r.Header.Set(o.Header, value) + } + } + return next(r) + } + } +} diff --git a/net/http/roundtripware/referer_test.go b/net/http/roundtripware/referer_test.go new file mode 100644 index 0000000..0c91cdd --- /dev/null +++ b/net/http/roundtripware/referer_test.go @@ -0,0 +1,125 @@ +package roundtripware_test + +import ( + "context" + "net/http" + "net/http/httptest" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.uber.org/zap/zaptest" + + keelhttp "github.com/foomo/keel/net/http" + keelhttpcontext "github.com/foomo/keel/net/http/context" + "github.com/foomo/keel/net/http/roundtripware" +) + +func TestReferer(t *testing.T) { + var testReferer string + + // create logger + l := zaptest.NewLogger(t) + + // create http server with handler + svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + testReferer = r.Header.Get(keelhttp.HeaderXReferer) + assert.Empty(t, testReferer) + w.WriteHeader(http.StatusOK) + })) + defer svr.Close() + + // create http client + client := keelhttp.NewHTTPClient( + keelhttp.HTTPClientWithRoundTripware(l, + roundtripware.Referer(), + ), + ) + + // create request + req, err := http.NewRequestWithContext(context.Background(), http.MethodGet, svr.URL, nil) + require.NoError(t, err) + + // do request + resp, err := client.Do(req) + require.NoError(t, err) + defer resp.Body.Close() + + // validate + assert.Equal(t, testReferer, req.Header.Get(keelhttp.HeaderXReferer)) +} + +func TestReferer_Context(t *testing.T) { + testReferer := "https://foomo.org/" + + // create logger + l := zaptest.NewLogger(t) + + // create http server with handler + svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, testReferer, r.Header.Get(keelhttp.HeaderXReferer)) + w.WriteHeader(http.StatusOK) + })) + defer svr.Close() + + // create http client + client := keelhttp.NewHTTPClient( + keelhttp.HTTPClientWithRoundTripware(l, + roundtripware.Referer(), + ), + ) + + // set request id on context + ctx := keelhttpcontext.SetReferer(context.Background(), testReferer) + + // create request + req, err := http.NewRequestWithContext(ctx, http.MethodGet, svr.URL, nil) + require.NoError(t, err) + + // do request + resp, err := client.Do(req) + require.NoError(t, err) + defer resp.Body.Close() + + // validate + assert.Equal(t, testReferer, req.Header.Get(keelhttp.HeaderXReferer)) +} + +func TestReferer_WithHeader(t *testing.T) { + testReferer := "https://foomo.org/" + testHeader := "X-Custom-Header" + + // create logger + l := zaptest.NewLogger(t) + + // create http server with handler + svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, testReferer, r.Header.Get(testHeader)) + w.WriteHeader(http.StatusOK) + })) + defer svr.Close() + + // create http client + client := keelhttp.NewHTTPClient( + keelhttp.HTTPClientWithRoundTripware(l, + roundtripware.Referer( + roundtripware.RefererWithHeader(testHeader), + ), + ), + ) + + // set request id on context + ctx := keelhttpcontext.SetReferer(context.Background(), testReferer) + + // create request + req, err := http.NewRequestWithContext(ctx, http.MethodGet, svr.URL, nil) + require.NoError(t, err) + + // do request + resp, err := client.Do(req) + require.NoError(t, err) + defer resp.Body.Close() + + // validate + assert.Equal(t, testReferer, req.Header.Get(testHeader)) +} diff --git a/net/stream/jetstream/readme.go b/net/stream/jetstream/readme.go new file mode 100644 index 0000000..75140d9 --- /dev/null +++ b/net/stream/jetstream/readme.go @@ -0,0 +1,62 @@ +package jetstream + +import ( + "github.com/foomo/keel/markdown" +) + +type ( + publisher struct { + Namespace string + Stream string + Subject string + } + subscriber struct { + Namespace string + Stream string + Subject string + } +) + +var ( + publishers []publisher + subscribers []subscriber +) + +func Readme() string { + if len(publishers) == 0 && len(subscribers) == 0 { + return "" + } + + var rows [][]string + md := &markdown.Markdown{} + md.Println("### NATS") + md.Println("") + md.Println("List of all registered nats publishers & subscribers.") + md.Println("") + + if len(publishers) > 0 { + for _, value := range publishers { + rows = append(rows, []string{ + markdown.Code(value.Namespace), + markdown.Code(value.Stream), + markdown.Code(value.Subject), + markdown.Code("publish"), + }) + } + } + + if len(subscribers) > 0 { + for _, value := range subscribers { + rows = append(rows, []string{ + markdown.Code(value.Namespace), + markdown.Code(value.Stream), + markdown.Code(value.Subject), + markdown.Code("subscribe"), + }) + } + } + + md.Table([]string{"Namespace", "Stream", "Subject", "Type"}, rows) + + return md.String() +} diff --git a/net/stream/jetstream/stream.go b/net/stream/jetstream/stream.go index 4608029..129d330 100644 --- a/net/stream/jetstream/stream.go +++ b/net/stream/jetstream/stream.go @@ -2,6 +2,7 @@ package jetstream import ( "encoding/json" + "slices" "time" "github.com/nats-io/nats.go" @@ -20,7 +21,9 @@ type ( name string info *nats.StreamInfo config *nats.StreamConfig + configJSOptions []nats.JSOpt namespace string + jsOptions []nats.JSOpt natsOptions []nats.Option reconnectMaxRetries int reconnectTimeout time.Duration @@ -59,22 +62,30 @@ func WithReconnectMaxRetries(v int) Option { } } -func WithConfig(v *nats.StreamConfig) Option { +func WithConfig(v *nats.StreamConfig, opts ...nats.JSOpt) Option { return func(o *Stream) { o.config = v + o.configJSOptions = append(o.configJSOptions, opts...) + } +} + +// WithJSOptions option +func WithJSOptions(v ...nats.JSOpt) Option { + return func(o *Stream) { + o.jsOptions = append(o.jsOptions, v...) } } // WithNatsOptions option func WithNatsOptions(v ...nats.Option) Option { return func(o *Stream) { - o.natsOptions = v + o.natsOptions = append(o.natsOptions, v...) } } func PublisherWithPubOpts(v ...nats.PubOpt) PublisherOption { return func(o *Publisher) { - o.pubOpts = v + o.pubOpts = append(o.pubOpts, v...) } } @@ -98,7 +109,7 @@ func SubscriberWithNamespace(v string) SubscriberOption { func SubscriberWithSubOpts(v ...nats.SubOpt) SubscriberOption { return func(o *Subscriber) { - o.opts = v + o.opts = append(o.opts, v...) } } @@ -118,9 +129,14 @@ func (s *Stream) connect() error { // create jet stream js, err := conn.JetStream( - nats.PublishAsyncErrHandler(func(js nats.JetStream, msg *nats.Msg, err error) { - s.l.Error("nats async publish error", log.FError(err)) - }), + append( + []nats.JSOpt{ + nats.PublishAsyncErrHandler(func(js nats.JetStream, msg *nats.Msg, err error) { + s.l.Error("nats async publish error", log.FError(err)) + }), + }, + s.jsOptions..., + )..., ) if err != nil { return err @@ -130,8 +146,8 @@ func (s *Stream) connect() error { // create / update stream if config exists if s.config != nil { s.config.Name = s.Name() - if _, err = js.StreamInfo(s.Name()); errors.Is(err, nats.ErrStreamNotFound) { - if info, err := js.AddStream(s.config); err != nil { + if _, err = js.StreamInfo(s.Name(), s.configJSOptions...); errors.Is(err, nats.ErrStreamNotFound) { + if info, err := js.AddStream(s.config, s.configJSOptions...); err != nil { return errors.Wrap(err, "failed to add stream") } else if err != nil { return errors.Wrap(err, "failed to retrieve stream info") @@ -140,7 +156,7 @@ func (s *Stream) connect() error { } } else if err != nil { return errors.Wrap(err, "failed get stream info") - } else if info, err := js.UpdateStream(s.config); err != nil { + } else if info, err := js.UpdateStream(s.config, s.configJSOptions...); err != nil { return errors.Wrap(err, "failed to update stream") } else { s.info = info @@ -265,6 +281,20 @@ func (s *Stream) Publisher(subject string, opts ...PublisherOption) *Publisher { opt(pub) } } + + { // append to recoreded publishers + value := publisher{ + Stream: s.name, + Namespace: s.namespace, + Subject: subject, + } + if !slices.ContainsFunc(publishers, func(p publisher) bool { + return p.Stream == value.Stream && p.Namespace == value.Namespace && p.Subject == value.Subject + }) { + publishers = append(publishers, value) + } + } + return pub } @@ -280,6 +310,20 @@ func (s *Stream) Subscriber(subject string, opts ...SubscriberOption) *Subscribe opt(sub) } } + + { // append to recoreded publishers + value := subscriber{ + Stream: s.name, + Namespace: s.namespace, + Subject: subject, + } + if !slices.ContainsFunc(subscribers, func(p subscriber) bool { + return p.Stream == value.Stream && p.Namespace == value.Namespace && p.Subject == value.Subject + }) { + subscribers = append(subscribers, value) + } + } + return sub } diff --git a/option.go b/option.go index a078a50..cf7d675 100644 --- a/option.go +++ b/option.go @@ -5,6 +5,7 @@ import ( "os" "time" + "github.com/foomo/keel/service" "github.com/spf13/viper" "go.uber.org/zap" @@ -61,10 +62,10 @@ func WithShutdownSignals(shutdownSignals ...os.Signal) Option { } } -// WithShutdownTimeout option -func WithShutdownTimeout(shutdownTimeout time.Duration) Option { +// WithGracefulPeriod option +func WithGracefulPeriod(gracefulPeriod time.Duration) Option { return func(inst *Server) { - inst.shutdownTimeout = shutdownTimeout + inst.gracefulPeriod = gracefulPeriod } } @@ -72,9 +73,9 @@ func WithShutdownTimeout(shutdownTimeout time.Duration) Option { func WithHTTPZapService(enabled bool) Option { return func(inst *Server) { if config.GetBool(inst.Config(), "service.zap.enabled", enabled)() { - service := NewDefaultServiceHTTPZap() - inst.initServices = append(inst.initServices, service) - inst.AddAlwaysHealthzers(service) + svs := service.NewDefaultHTTPZap(inst.Logger()) + inst.initServices = append(inst.initServices, svs) + inst.AddAlwaysHealthzers(svs) } } } @@ -83,9 +84,9 @@ func WithHTTPZapService(enabled bool) Option { func WithHTTPViperService(enabled bool) Option { return func(inst *Server) { if config.GetBool(inst.Config(), "service.viper.enabled", enabled)() { - service := NewDefaultServiceHTTPViper() - inst.initServices = append(inst.initServices, service) - inst.AddAlwaysHealthzers(service) + svs := service.NewDefaultHTTPViper(inst.Logger()) + inst.initServices = append(inst.initServices, svs) + inst.AddAlwaysHealthzers(svs) } } } @@ -149,19 +150,42 @@ func WithPrometheusMeter(enabled bool) Option { func WithHTTPPrometheusService(enabled bool) Option { return func(inst *Server) { if config.GetBool(inst.Config(), "service.prometheus.enabled", enabled)() { - service := NewDefaultServiceHTTPPrometheus() - inst.initServices = append(inst.initServices, service) - inst.AddAlwaysHealthzers(service) + svs := service.NewDefaultHTTPPrometheus(inst.Logger()) + inst.initServices = append(inst.initServices, svs) + inst.AddAlwaysHealthzers(svs) } } } +// WithHTTPPProfService option with default value +func WithHTTPPProfService(enabled bool) Option { + return func(inst *Server) { + if config.GetBool(inst.Config(), "service.pprof.enabled", enabled)() { + svs := service.NewDefaultHTTPPProf(inst.Logger()) + inst.initServices = append(inst.initServices, svs) + inst.AddAlwaysHealthzers(svs) + } + } +} + +// WithHTTPHealthzService option with default value func WithHTTPHealthzService(enabled bool) Option { return func(inst *Server) { if config.GetBool(inst.Config(), "service.healthz.enabled", enabled)() { - service := NewDefaultServiceHTTPProbes(inst.probes) - inst.initServices = append(inst.initServices, service) - inst.AddAlwaysHealthzers(service) + svs := service.NewDefaultHTTPProbes(inst.Logger(), inst.probes()) + inst.initServices = append(inst.initServices, svs) + inst.AddAlwaysHealthzers(svs) + } + } +} + +// WithHTTPReadmeService option with default value +func WithHTTPReadmeService(enabled bool) Option { + return func(inst *Server) { + if config.GetBool(inst.Config(), "service.readme.enabled", enabled)() { + svs := service.NewDefaultHTTPReadme(inst.Logger(), inst.readmers) + inst.initServices = append(inst.initServices, svs) + inst.AddAlwaysHealthzers(svs) } } } diff --git a/persistence/mongo/collection.go b/persistence/mongo/collection.go index 29b582b..29425b7 100644 --- a/persistence/mongo/collection.go +++ b/persistence/mongo/collection.go @@ -2,6 +2,7 @@ package keelmongo import ( "context" + "slices" "time" keelerrors "github.com/foomo/keel/errors" @@ -120,11 +121,22 @@ func NewCollection(db *mongo.Database, name string, opts ...CollectionOption) (* } col := db.Collection(name, o.CollectionOptions) + if !slices.Contains(dbs[db.Name()], name) { + dbs[db.Name()] = append(dbs[db.Name()], name) + } if len(o.Indexes) > 0 { if _, err := col.Indexes().CreateMany(o.IndexesContext, o.Indexes, o.CreateIndexesOptions); err != nil { return nil, err } + if _, ok := indices[db.Name()]; !ok { + indices[db.Name()] = map[string][]string{} + } + for _, index := range o.Indexes { + if index.Options != nil && index.Options.Name != nil { + indices[db.Name()][name] = append(indices[db.Name()][name], *index.Options.Name) + } + } } return &Collection{ @@ -189,8 +201,8 @@ func (c *Collection) Upsert(ctx context.Context, id string, entity Entity) error return c.Insert(ctx, entity) } else if err := c.collection.FindOneAndUpdate( ctx, - bson.D{{Key: "id", Value: id}, {Key: "version", Value: currentVersion}}, - bson.D{{Key: "$set", Value: entity}}, + bson.D{bson.E{Key: "id", Value: id}, bson.E{Key: "version", Value: currentVersion}}, + bson.D{bson.E{Key: "$set", Value: entity}}, options.FindOneAndUpdate().SetUpsert(false), ).Err(); errors.Is(err, mongo.ErrNoDocuments) { return keelerrors.NewWrappedError(keelpersistence.ErrDirtyWrite, err) @@ -199,8 +211,8 @@ func (c *Collection) Upsert(ctx context.Context, id string, entity Entity) error } } else if _, err := c.collection.UpdateOne( ctx, - bson.D{{Key: "id", Value: id}}, - bson.D{{Key: "$set", Value: entity}}, + bson.D{bson.E{Key: "id", Value: id}}, + bson.D{bson.E{Key: "$set", Value: entity}}, options.Update().SetUpsert(true), ); err != nil { return err @@ -242,16 +254,16 @@ func (c *Collection) UpsertMany(ctx context.Context, entities []Entity) error { versionUpserts++ operations = append(operations, mongo.NewUpdateOneModel(). - SetFilter(bson.D{{Key: "id", Value: entity.GetID()}, {Key: "version", Value: currentVersion}}). - SetUpdate(bson.D{{Key: "$set", Value: entity}}). + SetFilter(bson.D{bson.E{Key: "id", Value: entity.GetID()}, bson.E{Key: "version", Value: currentVersion}}). + SetUpdate(bson.D{bson.E{Key: "$set", Value: entity}}). SetUpsert(false), ) } } else { operations = append(operations, mongo.NewUpdateOneModel(). - SetFilter(bson.D{{Key: "id", Value: entity.GetID()}}). - SetUpdate(bson.D{{Key: "$set", Value: entity}}). + SetFilter(bson.D{bson.E{Key: "id", Value: entity.GetID()}}). + SetUpdate(bson.D{bson.E{Key: "$set", Value: entity}}). SetUpsert(true), ) } @@ -382,7 +394,7 @@ func (c *Collection) FindIterate(ctx context.Context, filter interface{}, handle return err } - defer CloseCursor(cursor) + defer CloseCursor(context.WithoutCancel(ctx), cursor) for cursor.Next(ctx) { if err := handler(cursor.Decode); err != nil { @@ -412,7 +424,7 @@ func (c *Collection) AggregateIterate(ctx context.Context, pipeline mongo.Pipeli return err } - defer CloseCursor(cursor) + defer CloseCursor(context.WithoutCancel(ctx), cursor) for cursor.Next(ctx) { if err := handler(cursor.Decode); err != nil { diff --git a/persistence/mongo/persistor.go b/persistence/mongo/persistor.go index 076d599..fc32c3f 100644 --- a/persistence/mongo/persistor.go +++ b/persistence/mongo/persistor.go @@ -24,12 +24,18 @@ type ( Options struct { OtelEnabled bool OtelOptions []otelmongo.Option - ClientOptions *options.ClientOptions - DatabaseOptions *options.DatabaseOptions + ClientOptions []ClientOption + DatabaseOptions []DatabaseOption } - Option func(o *Options) + Option func(o *Options) + ClientOption func(*options.ClientOptions) + DatabaseOption func(*options.DatabaseOptions) ) +// ------------------------------------------------------------------------------------------------ +// ~ Options +// ------------------------------------------------------------------------------------------------ + func WithOtelEnabled(v bool) Option { return func(o *Options) { o.OtelEnabled = v @@ -42,15 +48,15 @@ func WithOtelOptions(v ...otelmongo.Option) Option { } } -func WithClientOptions(v *options.ClientOptions) Option { +func WithClientOptions(v ...ClientOption) Option { return func(o *Options) { - o.ClientOptions = options.MergeClientOptions(o.ClientOptions, v) + o.ClientOptions = append(o.ClientOptions, v...) } } -func WithDatabaseOptions(v *options.DatabaseOptions) Option { +func WithDatabaseOptions(v ...DatabaseOption) Option { return func(o *Options) { - o.DatabaseOptions = options.MergeDatabaseOptions(o.DatabaseOptions, v) + o.DatabaseOptions = append(o.DatabaseOptions, v...) } } @@ -60,14 +66,20 @@ func DefaultOptions() Options { OtelOptions: []otelmongo.Option{ otelmongo.WithCommandAttributeDisabled(env.GetBool("OTEL_MONGO_COMMAND_ATTRIBUTE_DISABLED", false)), }, - ClientOptions: options.Client(). - SetReadConcern(readconcern.Majority()). - SetWriteConcern(writeconcern.New(writeconcern.WMajority())), + ClientOptions: []ClientOption{ + func(clientOptions *options.ClientOptions) { + clientOptions.SetReadConcern(readconcern.Majority()) + clientOptions.SetWriteConcern(writeconcern.Majority()) + }, + }, DatabaseOptions: nil, } } -// New ... +// ------------------------------------------------------------------------------------------------ +// ~ Constructor +// ------------------------------------------------------------------------------------------------ + func New(ctx context.Context, uri string, opts ...Option) (*Persistor, error) { o := DefaultOptions() @@ -79,23 +91,32 @@ func New(ctx context.Context, uri string, opts ...Option) (*Persistor, error) { return nil, errors.Errorf("missing database name in uri: %s", uri) } - // apply uri - o.ClientOptions.ApplyURI(uri) - // apply options for _, opt := range opts { opt(&o) } + // apply client options + clientOptions := options.Client().ApplyURI(uri) + for _, opt := range o.ClientOptions { + opt(clientOptions) + } + + // apply database options + databaseOptions := options.Database() + for _, opt := range o.DatabaseOptions { + opt(databaseOptions) + } + // setup otel if o.OtelEnabled { - o.ClientOptions.SetMonitor( + clientOptions.SetMonitor( otelmongo.NewMonitor(o.OtelOptions...), ) } // create connection - client, err := mongo.Connect(ctx, o.ClientOptions) + client, err := mongo.Connect(ctx, clientOptions) if err != nil { return nil, errors.Wrap(err, "failed to connect") } @@ -107,7 +128,7 @@ func New(ctx context.Context, uri string, opts ...Option) (*Persistor, error) { return &Persistor{ client: client, - db: client.Database(cs.Database), + db: client.Database(cs.Database, databaseOptions), }, nil } diff --git a/persistence/mongo/readme.go b/persistence/mongo/readme.go new file mode 100644 index 0000000..21a51f9 --- /dev/null +++ b/persistence/mongo/readme.go @@ -0,0 +1,42 @@ +package keelmongo + +import ( + "strings" + + "github.com/foomo/keel/markdown" +) + +var ( + dbs = map[string][]string{} + indices = map[string]map[string][]string{} +) + +func Readme() string { + var rows [][]string + md := &markdown.Markdown{} + + for db, collections := range dbs { + for _, collection := range collections { + var i string + if v, ok := indices[db][collection]; ok { + i += strings.Join(v, "`, `") + } + rows = append(rows, []string{ + markdown.Code(db), + markdown.Code(collection), + markdown.Code(i), + }) + } + } + + if len(rows) > 0 { + md.Println("### Mongo") + md.Println("") + md.Println("List of all used mongo collections including the configured indices options.") + md.Println("") + md.Table([]string{"Database", "Collection", "Indices"}, rows) + md.Println("") + } + + return md.String() +} diff --git a/persistence/mongo/utils.go b/persistence/mongo/utils.go index 9843ab5..7427447 100644 --- a/persistence/mongo/utils.go +++ b/persistence/mongo/utils.go @@ -8,8 +8,8 @@ import ( ) // CloseCursor with defer -func CloseCursor(cursor *mongo.Cursor) { - if err := cursor.Close(context.Background()); err != nil { +func CloseCursor(ctx context.Context, cursor *mongo.Cursor) { + if err := cursor.Close(ctx); err != nil { log.WithError(nil, err).Error("failed to close cursor") } } diff --git a/server.go b/server.go index 08b834a..551ee0c 100644 --- a/server.go +++ b/server.go @@ -2,15 +2,28 @@ package keel import ( "context" + "errors" "fmt" "net/http" "os" "os/signal" + "reflect" + "slices" + "sync" + "sync/atomic" "syscall" "time" + "github.com/foomo/keel/config" + "github.com/foomo/keel/env" + "github.com/foomo/keel/healthz" + "github.com/foomo/keel/interfaces" + "github.com/foomo/keel/log" + "github.com/foomo/keel/markdown" + "github.com/foomo/keel/metrics" + "github.com/foomo/keel/service" + "github.com/foomo/keel/telemetry" "github.com/go-logr/logr" - "github.com/pkg/errors" "github.com/spf13/viper" otelhost "go.opentelemetry.io/contrib/instrumentation/host" otelruntime "go.opentelemetry.io/contrib/instrumentation/runtime" @@ -20,11 +33,6 @@ import ( "go.opentelemetry.io/otel/trace" "go.uber.org/zap" "golang.org/x/sync/errgroup" - - "github.com/foomo/keel/config" - "github.com/foomo/keel/env" - "github.com/foomo/keel/log" - "github.com/foomo/keel/telemetry" ) // Server struct @@ -35,25 +43,33 @@ type Server struct { meterProvider metric.MeterProvider tracer trace.Tracer traceProvider trace.TracerProvider + shutdown atomic.Bool shutdownSignals []os.Signal - shutdownTimeout time.Duration - running bool - closers []interface{} - probes map[HealthzType][]interface{} - ctx context.Context - ctxCancel context.Context - ctxCancelFn context.CancelFunc - g *errgroup.Group - gCtx context.Context - l *zap.Logger - c *viper.Viper + // gracefulPeriod should equal the terminationGracePeriodSeconds + gracefulPeriod time.Duration + running atomic.Bool + syncClosers []interface{} + syncClosersLock sync.RWMutex + syncReadmers []interfaces.Readmer + syncReadmersLock sync.RWMutex + syncProbes map[healthz.Type][]interface{} + syncProbesLock sync.RWMutex + ctx context.Context + cancel context.CancelFunc + gracefulCtx context.Context + gracefulCancel context.CancelFunc + g *errgroup.Group + gCtx context.Context + l *zap.Logger + c *viper.Viper } func NewServer(opts ...Option) *Server { inst := &Server{ - shutdownTimeout: 30 * time.Second, - shutdownSignals: []os.Signal{os.Interrupt, syscall.SIGTERM}, - probes: map[HealthzType][]interface{}{}, + gracefulPeriod: time.Duration(env.GetInt("KEEL_GRACEFUL_PERIOD", 30)) * time.Second, + shutdownSignals: []os.Signal{syscall.SIGINT, syscall.SIGTERM}, + syncReadmers: []interfaces.Readmer{}, + syncProbes: map[healthz.Type][]interface{}{}, ctx: context.Background(), c: config.Config(), l: log.Logger(), @@ -64,75 +80,79 @@ func NewServer(opts ...Option) *Server { } { // setup error group - inst.ctxCancel, inst.ctxCancelFn = signal.NotifyContext(inst.ctx, inst.shutdownSignals...) - inst.g, inst.gCtx = errgroup.WithContext(inst.ctxCancel) + inst.AddReadinessHealthzers(healthz.NewHealthzerFn(func(ctx context.Context) error { + if inst.shutdown.Load() { + return ErrServerShutdown + } + return nil + })) + + inst.ctx, inst.cancel = context.WithCancel(inst.ctx) + inst.g, inst.gCtx = errgroup.WithContext(inst.ctx) + inst.gracefulCtx, inst.gracefulCancel = signal.NotifyContext(inst.ctx, inst.shutdownSignals...) // gracefully shutdown inst.g.Go(func() error { - <-inst.gCtx.Done() - inst.l.Debug("keel graceful shutdown") - defer inst.ctxCancelFn() - - timeoutCtx, timeoutCancel := context.WithTimeout(inst.ctx, inst.shutdownTimeout) + <-inst.gracefulCtx.Done() + inst.shutdown.Store(true) + timeoutCtx, timeoutCancel := context.WithTimeout(inst.ctx, inst.gracefulPeriod) defer timeoutCancel() + inst.l.Info("keel graceful shutdown", + zap.Duration("graceful_period", inst.gracefulPeriod), + ) + // append internal closers - closers := append(inst.closers, inst.traceProvider, inst.meterProvider) //nolint:gocritic + closers := append(inst.closers(), inst.traceProvider, inst.meterProvider) + inst.l.Info("keel graceful shutdown: closers") for _, closer := range closers { + var err error l := inst.l.With(log.FName(fmt.Sprintf("%T", closer))) switch c := closer.(type) { - case Closer: + case interfaces.Closer: c.Close() - case ErrorCloser: - if err := c.Close(); err != nil { - log.WithError(l, err).Error("failed to gracefully stop ErrorCloser") - } - case CloserWithContext: + case interfaces.ErrorCloser: + err = c.Close() + case interfaces.CloserWithContext: c.Close(timeoutCtx) - case ErrorCloserWithContext: - if err := c.Close(timeoutCtx); err != nil { - log.WithError(l, err).Error("failed to gracefully stop ErrorCloserWithContext") - } - case Shutdowner: + case interfaces.ErrorCloserWithContext: + err = c.Close(timeoutCtx) + case interfaces.Shutdowner: c.Shutdown() - case ErrorShutdowner: - if err := c.Shutdown(); err != nil { - log.WithError(l, err).Error("failed to gracefully stop ErrorShutdowner") - } - case ShutdownerWithContext: + case interfaces.ErrorShutdowner: + err = c.Shutdown() + case interfaces.ShutdownerWithContext: c.Shutdown(timeoutCtx) - case ErrorShutdownerWithContext: - if err := c.Shutdown(timeoutCtx); err != nil { - log.WithError(l, err).Error("failed to gracefully stop ErrorShutdownerWithContext") - } - case Stopper: + case interfaces.ErrorShutdownerWithContext: + err = c.Shutdown(timeoutCtx) + case interfaces.Stopper: c.Stop() - case ErrorStopper: - if err := c.Stop(); err != nil { - log.WithError(l, err).Error("failed to gracefully stop ErrorStopper") - } - case StopperWithContext: + case interfaces.ErrorStopper: + err = c.Stop() + case interfaces.StopperWithContext: c.Stop(timeoutCtx) - case ErrorStopperWithContext: - if err := c.Stop(timeoutCtx); err != nil { - log.WithError(l, err).Error("failed to gracefully stop ErrorStopperWithContext") - } - case Unsubscriber: + case interfaces.ErrorStopperWithContext: + err = c.Stop(timeoutCtx) + case interfaces.Unsubscriber: c.Unsubscribe() - case ErrorUnsubscriber: - if err := c.Unsubscribe(); err != nil { - log.WithError(l, err).Error("failed to gracefully stop ErrorUnsubscriber") - } - case UnsubscriberWithContext: + case interfaces.ErrorUnsubscriber: + err = c.Unsubscribe() + case interfaces.UnsubscriberWithContext: c.Unsubscribe(timeoutCtx) - case ErrorUnsubscriberWithContext: - if err := c.Unsubscribe(timeoutCtx); err != nil { - log.WithError(l, err).Error("failed to gracefully stop ErrorUnsubscriberWithContext") - } + case interfaces.ErrorUnsubscriberWithContext: + err = c.Unsubscribe(timeoutCtx) + } + if err != nil { + l.Warn("keel graceful shutdown: closer failed", zap.Error(err)) + } else { + l.Debug("keel graceful shutdown: closer closed") } } - return inst.gCtx.Err() + + inst.l.Info("keel graceful shutdown: complete") + + return ErrServerShutdown }) } @@ -164,6 +184,12 @@ func NewServer(opts ...Option) *Server { // add probe inst.AddAlwaysHealthzers(inst) + inst.AddReadmers( + interfaces.ReadmeFunc(env.Readme), + interfaces.ReadmeFunc(config.Readme), + inst, + interfaces.ReadmeFunc(metrics.Readme), + ) // start init services inst.startService(inst.initServices...) @@ -196,56 +222,42 @@ func (s *Server) Context() context.Context { return s.ctx } -// CancelContext returns server's cancel context -func (s *Server) CancelContext() context.Context { - return s.ctxCancel +// ShutdownContext returns server's shutdown cancel context +func (s *Server) ShutdownContext() context.Context { + return s.gracefulCtx +} + +// ShutdownCancel returns server's shutdown cancel function +func (s *Server) ShutdownCancel() context.CancelFunc { + return s.gracefulCancel } // AddService add a single service -func (s *Server) AddService(service Service) { - for _, value := range s.services { - if value == service { - return - } +func (s *Server) AddService(v Service) { + if !slices.Contains(s.services, v) { + s.services = append(s.services, v) + s.AddAlwaysHealthzers(v) + s.AddCloser(v) } - s.services = append(s.services, service) - s.AddAlwaysHealthzers(service) - s.AddCloser(service) } // AddServices adds multiple service func (s *Server) AddServices(services ...Service) { - for _, service := range services { - s.AddService(service) + for _, value := range services { + s.AddService(value) } } // AddCloser adds a closer to be called on shutdown func (s *Server) AddCloser(closer interface{}) { - for _, value := range s.closers { + for _, value := range s.closers() { if value == closer { return } } - switch closer.(type) { - case Closer, - ErrorCloser, - CloserWithContext, - ErrorCloserWithContext, - Shutdowner, - ErrorShutdowner, - ShutdownerWithContext, - ErrorShutdownerWithContext, - Stopper, - ErrorStopper, - StopperWithContext, - ErrorStopperWithContext, - Unsubscriber, - ErrorUnsubscriber, - UnsubscriberWithContext, - ErrorUnsubscriberWithContext: - s.closers = append(s.closers, closer) - default: + if IsCloser(closer) { + s.addClosers(closer) + } else { s.l.Warn("unable to add closer", log.FValue(fmt.Sprintf("%T", closer))) } } @@ -257,23 +269,29 @@ func (s *Server) AddClosers(closers ...interface{}) { } } +// AddReadmer adds a readmer to be added to the exposed readme +func (s *Server) AddReadmer(readmer interfaces.Readmer) { + s.addReadmers(readmer) +} + +// AddReadmers adds readmers to be added to the exposed readme +func (s *Server) AddReadmers(readmers ...interfaces.Readmer) { + for _, readmer := range readmers { + s.AddReadmer(readmer) + } +} + // AddHealthzer adds a probe to be called on healthz checks -func (s *Server) AddHealthzer(typ HealthzType, probe interface{}) { - switch probe.(type) { - case BoolHealthzer, - BoolHealthzerWithContext, - ErrorHealthzer, - ErrorHealthzWithContext, - ErrorPinger, - ErrorPingerWithContext: - s.probes[typ] = append(s.probes[typ], probe) - default: +func (s *Server) AddHealthzer(typ healthz.Type, probe interface{}) { + if IsHealthz(probe) { + s.addProbes(typ, probe) + } else { s.l.Debug("not a healthz probe", log.FValue(fmt.Sprintf("%T", probe))) } } // AddHealthzers adds the given probes to be called on healthz checks -func (s *Server) AddHealthzers(typ HealthzType, probes ...interface{}) { +func (s *Server) AddHealthzers(typ healthz.Type, probes ...interface{}) { for _, probe := range probes { s.AddHealthzer(typ, probe) } @@ -281,32 +299,27 @@ func (s *Server) AddHealthzers(typ HealthzType, probes ...interface{}) { // AddAlwaysHealthzers adds the probes to be called on any healthz checks func (s *Server) AddAlwaysHealthzers(probes ...interface{}) { - s.AddHealthzers(HealthzTypeAlways, probes...) + s.AddHealthzers(healthz.TypeAlways, probes...) } // AddStartupHealthzers adds the startup probes to be called on healthz checks func (s *Server) AddStartupHealthzers(probes ...interface{}) { - s.AddHealthzers(HealthzTypeStartup, probes...) + s.AddHealthzers(healthz.TypeStartup, probes...) } // AddLivenessHealthzers adds the liveness probes to be called on healthz checks func (s *Server) AddLivenessHealthzers(probes ...interface{}) { - s.AddHealthzers(HealthzTypeLiveness, probes...) + s.AddHealthzers(healthz.TypeLiveness, probes...) } // AddReadinessHealthzers adds the readiness probes to be called on healthz checks func (s *Server) AddReadinessHealthzers(probes ...interface{}) { - s.AddHealthzers(HealthzTypeReadiness, probes...) -} - -// IsCanceled returns true if the internal errgroup has been canceled -func (s *Server) IsCanceled() bool { - return errors.Is(s.gCtx.Err(), context.Canceled) + s.AddHealthzers(healthz.TypeReadiness, probes...) } // Healthz returns true if the server is running func (s *Server) Healthz() error { - if !s.running { + if !s.running.Load() { return ErrServerNotRunning } return nil @@ -314,13 +327,8 @@ func (s *Server) Healthz() error { // Run runs the server func (s *Server) Run() { - if s.IsCanceled() { - s.l.Info("keel server canceled") - return - } - - defer s.ctxCancelFn() s.l.Info("starting keel server") + defer s.cancel() // start services s.startService(s.services...) @@ -331,25 +339,76 @@ func (s *Server) Run() { } // set running - defer func() { - s.running = false - }() - s.running = true + defer s.running.Store(false) + s.running.Store(true) // wait for shutdown - if err := s.g.Wait(); err != nil && !errors.Is(err, context.Canceled) { - log.WithError(s.l, err).Error("service error") + if err := s.g.Wait(); errors.Is(err, ErrServerShutdown) { + s.l.Info("keel server stopped") + } else if err != nil { + log.WithError(s.l, err).Error("keel server failed") } +} + +func (s *Server) closers() []interface{} { + s.syncClosersLock.RLock() + defer s.syncClosersLock.RUnlock() + return s.syncClosers +} + +func (s *Server) addClosers(v ...interface{}) { + s.syncClosersLock.Lock() + defer s.syncClosersLock.Unlock() + s.syncClosers = append(s.syncClosers, v...) +} - s.l.Info("keel server stopped") +func (s *Server) readmers() []interfaces.Readmer { + s.syncReadmersLock.RLock() + defer s.syncReadmersLock.RUnlock() + return s.syncReadmers } +func (s *Server) addReadmers(v ...interfaces.Readmer) { + s.syncReadmersLock.Lock() + defer s.syncReadmersLock.Unlock() + s.syncReadmers = append(s.syncReadmers, v...) +} + +func (s *Server) probes() map[healthz.Type][]interface{} { + s.syncProbesLock.RLock() + defer s.syncProbesLock.RUnlock() + return s.syncProbes +} + +func (s *Server) addProbes(typ healthz.Type, v ...interface{}) { + s.syncProbesLock.Lock() + defer s.syncProbesLock.Unlock() + s.syncProbes[typ] = append(s.syncProbes[typ], v...) +} + +// Readme returns the self-documenting string +func (s *Server) Readme() string { + md := &markdown.Markdown{} + + md.Println(s.readmeServices()) + md.Println(s.readmeHealthz()) + md.Print(s.readmeCloser()) + + return md.String() +} + +// ------------------------------------------------------------------------------------------------ +// ~ Private methods +// ------------------------------------------------------------------------------------------------ + // startService starts the given services func (s *Server) startService(services ...Service) { - for _, service := range services { - service := service + c := make(chan struct{}, 1) + for _, value := range services { + value := value s.g.Go(func() error { - if err := service.Start(s.ctx); errors.Is(err, http.ErrServerClosed) { + c <- struct{}{} + if err := value.Start(s.ctx); errors.Is(err, http.ErrServerClosed) { log.WithError(s.l, err).Debug("server has closed") } else if err != nil { log.WithError(s.l, err).Error("failed to start service") @@ -357,5 +416,141 @@ func (s *Server) startService(services ...Service) { } return nil }) + <-c } + close(c) +} + +func (s *Server) readmeCloser() string { + md := &markdown.Markdown{} + closers := s.closers() + rows := make([][]string, 0, len(closers)) + for _, value := range closers { + t := reflect.TypeOf(value) + var closer string + switch value.(type) { + case interfaces.Closer: + closer = "Closer" + case interfaces.ErrorCloser: + closer = "ErrorCloser" + case interfaces.CloserWithContext: + closer = "CloserWithContext" + case interfaces.ErrorCloserWithContext: + closer = "ErrorCloserWithContext" + case interfaces.Shutdowner: + closer = "Shutdowner" + case interfaces.ErrorShutdowner: + closer = "ErrorShutdowner" + case interfaces.ShutdownerWithContext: + closer = "ShutdownerWithContext" + case interfaces.ErrorShutdownerWithContext: + closer = "ErrorShutdownerWithContext" + case interfaces.Stopper: + closer = "Stopper" + case interfaces.ErrorStopper: + closer = "ErrorStopper" + case interfaces.StopperWithContext: + closer = "StopperWithContext" + case interfaces.ErrorStopperWithContext: + closer = "ErrorStopperWithContext" + case interfaces.Unsubscriber: + closer = "Unsubscriber" + case interfaces.ErrorUnsubscriber: + closer = "ErrorUnsubscriber" + case interfaces.UnsubscriberWithContext: + closer = "UnsubscriberWithContext" + case interfaces.ErrorUnsubscriberWithContext: + closer = "ErrorUnsubscriberWithContext" + } + rows = append(rows, []string{ + markdown.Code(markdown.Name(value)), + markdown.Code(t.String()), + markdown.Code(closer), + markdown.String(value), + }) + } + if len(rows) > 0 { + md.Println("### Closers") + md.Println("") + md.Println("List of all registered closers that are being called during graceful shutdown.") + md.Println("") + md.Table([]string{"Name", "Type", "Closer", "Description"}, rows) + md.Println("") + } + + return md.String() +} + +func (s *Server) readmeHealthz() string { + var rows [][]string + md := &markdown.Markdown{} + + for k, probes := range s.probes() { + for _, probe := range probes { + t := reflect.TypeOf(probe) + rows = append(rows, []string{ + markdown.Code(markdown.Name(probe)), + markdown.Code(k.String()), + markdown.Code(t.String()), + markdown.String(probe), + }) + } + } + if len(rows) > 0 { + md.Println("### Health probes") + md.Println("") + md.Println("List of all registered healthz probes that are being called during startup and runtime.") + md.Println("") + md.Table([]string{"Name", "Probe", "Type", "Description"}, rows) + } + + return md.String() +} + +func (s *Server) readmeServices() string { + md := &markdown.Markdown{} + + { + var rows [][]string + for _, value := range s.initServices { + if v, ok := value.(*service.HTTP); ok { + t := reflect.TypeOf(v) + rows = append(rows, []string{ + markdown.Code(v.Name()), + markdown.Code(t.String()), + markdown.String(v), + }) + } + } + if len(rows) > 0 { + md.Println("### Init Services") + md.Println("") + md.Println("List of all registered init services that are being immediately started.") + md.Println("") + md.Table([]string{"Name", "Type", "Address"}, rows) + } + } + + md.Println("") + + { + var rows [][]string + for _, value := range s.services { + t := reflect.TypeOf(value) + rows = append(rows, []string{ + markdown.Code(value.Name()), + markdown.Code(t.String()), + markdown.String(value), + }) + } + if len(rows) > 0 { + md.Println("### Runtime Services") + md.Println("") + md.Println("List of all registered services that are being started.") + md.Println("") + md.Table([]string{"Name", "Type", "Description"}, rows) + } + } + + return md.String() } diff --git a/server_test.go b/server_test.go index c998dbe..0499cac 100644 --- a/server_test.go +++ b/server_test.go @@ -10,12 +10,12 @@ import ( "testing" "time" - "github.com/stretchr/testify/assert" + "github.com/foomo/keel/service" "github.com/stretchr/testify/suite" "go.uber.org/zap" + "go.uber.org/zap/zaptest" "github.com/foomo/keel" - keeltest "github.com/foomo/keel/test" ) type KeelTestSuite struct { @@ -28,12 +28,12 @@ type KeelTestSuite struct { // SetupSuite hook func (s *KeelTestSuite) SetupSuite() { - s.l = keeltest.NewLogger(s.T()).Zap() + s.l = zaptest.NewLogger(s.T()) } // BeforeTest hook func (s *KeelTestSuite) BeforeTest(suiteName, testName string) { - s.l = keeltest.NewLogger(s.T()).Zap() + s.l = zaptest.NewLogger(s.T()) s.mux = http.NewServeMux() s.mux.HandleFunc("/ok", func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) @@ -59,7 +59,10 @@ func (s *KeelTestSuite) BeforeTest(suiteName, testName string) { }) ctx, cancel := context.WithCancel(context.Background()) - s.svr = keel.NewServer(keel.WithContext(ctx), keel.WithLogger(s.l)) + s.svr = keel.NewServer( + keel.WithContext(ctx), + keel.WithLogger(s.l), + ) s.cancel = cancel } @@ -74,7 +77,7 @@ func (s *KeelTestSuite) TearDownSuite() {} func (s *KeelTestSuite) TestServiceHTTP() { s.svr.AddServices( - keel.NewServiceHTTP(s.l, "test", ":55000", s.mux), + service.NewHTTP(s.l, "test", "localhost:55000", s.mux), ) s.runServer() @@ -86,8 +89,8 @@ func (s *KeelTestSuite) TestServiceHTTP() { func (s *KeelTestSuite) TestServiceHTTPZap() { s.svr.AddServices( - keel.NewServiceHTTPZap(s.l, "zap", ":9100", "/log"), - keel.NewServiceHTTP(s.l, "test", ":55000", s.mux), + service.NewHTTPZap(s.l, "zap", "localhost:9100", "/log"), + service.NewHTTP(s.l, "test", "localhost:55000", s.mux), ) s.runServer() @@ -95,7 +98,7 @@ func (s *KeelTestSuite) TestServiceHTTPZap() { s.Run("default", func() { if statusCode, body, err := s.httpGet("http://localhost:9100/log"); s.NoError(err) { s.Equal(http.StatusOK, statusCode) - s.Equal(body, `{"level":"info","disableCaller":true,"disableStacktrace":true}`) + s.Equal(`{"level":"info","disableCaller":true,"disableStacktrace":true}`, body) } if statusCode, _, err := s.httpGet("http://localhost:55000/log/info"); s.NoError(err) { s.Equal(http.StatusOK, statusCode) @@ -108,7 +111,7 @@ func (s *KeelTestSuite) TestServiceHTTPZap() { s.Run("set debug level", func() { if statusCode, body, err := s.httpPut("http://localhost:9100/log", `{"level":"debug"}`); s.NoError(err) { s.Equal(http.StatusOK, statusCode) - s.Equal(body, `{"level":"debug","disableCaller":true,"disableStacktrace":true}`) + s.Equal(`{"level":"debug","disableCaller":true,"disableStacktrace":true}`, body) } if statusCode, _, err := s.httpGet("http://localhost:55000/log/info"); s.NoError(err) { s.Equal(http.StatusOK, statusCode) @@ -121,7 +124,7 @@ func (s *KeelTestSuite) TestServiceHTTPZap() { s.Run("enable caller", func() { if statusCode, body, err := s.httpPut("http://localhost:9100/log", `{"disableCaller":false}`); s.NoError(err) { s.Equal(http.StatusOK, statusCode) - s.Equal(body, `{"level":"debug","disableCaller":false,"disableStacktrace":true}`) + s.Equal(`{"level":"debug","disableCaller":false,"disableStacktrace":true}`, body) } if statusCode, _, err := s.httpGet("http://localhost:55000/log/error"); s.NoError(err) { s.Equal(http.StatusOK, statusCode) @@ -131,7 +134,7 @@ func (s *KeelTestSuite) TestServiceHTTPZap() { s.Run("enable stacktrace", func() { if statusCode, body, err := s.httpPut("http://localhost:9100/log", `{"disableStacktrace":false}`); s.NoError(err) { s.Equal(http.StatusOK, statusCode) - s.Equal(body, `{"level":"debug","disableCaller":false,"disableStacktrace":false}`) + s.Equal(`{"level":"debug","disableCaller":false,"disableStacktrace":false}`, body) } if statusCode, _, err := s.httpGet("http://localhost:55000/log/error"); s.NoError(err) { s.Equal(http.StatusOK, statusCode) @@ -141,7 +144,7 @@ func (s *KeelTestSuite) TestServiceHTTPZap() { func (s *KeelTestSuite) TestGraceful() { s.svr.AddServices( - keel.NewServiceHTTP(s.l, "test", ":55000", s.mux), + service.NewHTTP(s.l, "test", "localhost:55000", s.mux), ) s.runServer() @@ -172,7 +175,7 @@ func (s *KeelTestSuite) TestGraceful() { go func(waitChan chan string) { waitChan <- "ok" time.Sleep(time.Second) - if assert.NoError(s.T(), syscall.Kill(syscall.Getpid(), syscall.SIGINT)) { + if s.NoError(syscall.Kill(syscall.Getpid(), syscall.SIGINT)) { s.l.Info("killed myself") } }(waitChan) @@ -183,7 +186,7 @@ func (s *KeelTestSuite) TestGraceful() { { // check that server is down _, _, err := s.httpGet("http://localhost:55000/ok") - s.Error(err) + s.Require().Error(err) } s.l.Info("done") diff --git a/service/errors.go b/service/errors.go new file mode 100644 index 0000000..97c6c1b --- /dev/null +++ b/service/errors.go @@ -0,0 +1,10 @@ +package service + +import ( + "errors" +) + +var ( + ErrServiceNotRunning = errors.New("service not running") + ErrServiceShutdown = errors.New("service shutdown") +) diff --git a/service/goroutine.go b/service/goroutine.go new file mode 100644 index 0000000..ef895b7 --- /dev/null +++ b/service/goroutine.go @@ -0,0 +1,110 @@ +package service + +import ( + "context" + "fmt" + "sync" + "sync/atomic" + + "go.uber.org/zap" + "golang.org/x/sync/errgroup" + + "github.com/foomo/keel/log" +) + +// GoRoutine struct +type ( + GoRoutine struct { + running atomic.Bool + handler GoRoutineFn + cancel context.CancelCauseFunc + cancelLock sync.Mutex + parallel int + name string + wg errgroup.Group + l *zap.Logger + } + GoRoutineOption func(*GoRoutine) + GoRoutineFn func(ctx context.Context, l *zap.Logger) error +) + +func NewGoRoutine(l *zap.Logger, name string, handler GoRoutineFn, opts ...GoRoutineOption) *GoRoutine { + if l == nil { + l = log.Logger() + } + // enrich the log + l = log.WithAttributes(l, + log.KeelServiceTypeKey.String("goroutine"), + log.KeelServiceNameKey.String(name), + ) + + inst := &GoRoutine{ + handler: handler, + name: name, + parallel: 1, + l: l, + } + + for _, opt := range opts { + opt(inst) + } + + return inst +} + +// ------------------------------------------------------------------------------------------------ +// ~ Options +// ------------------------------------------------------------------------------------------------ + +func GoRoutineWithPralllel(v int) GoRoutineOption { + return func(o *GoRoutine) { + o.parallel = v + } +} + +// ------------------------------------------------------------------------------------------------ +// ~ Public methods +// ------------------------------------------------------------------------------------------------ + +func (s *GoRoutine) Name() string { + return s.name +} + +func (s *GoRoutine) Healthz() error { + if !s.running.Load() { + return ErrServiceNotRunning + } + return nil +} + +func (s *GoRoutine) String() string { + return fmt.Sprintf("parallel: `%d`", s.parallel) +} + +func (s *GoRoutine) Start(ctx context.Context) error { + s.l.Info("starting keel service") + ctx, cancel := context.WithCancelCause(ctx) + s.cancelLock.Lock() + s.cancel = cancel + s.cancelLock.Unlock() + for i := 0; i < s.parallel; i++ { + i := i + l := log.WithAttributes(s.l, log.KeelServiceInstKey.Int(i)) + s.wg.Go(func() error { + return s.handler(ctx, l) + }) + } + s.running.Store(true) + defer func() { + s.running.Store(false) + }() + return s.wg.Wait() +} + +func (s *GoRoutine) Close(ctx context.Context) error { + s.l.Info("stopping keel service") + s.cancelLock.Lock() + s.cancel(ErrServiceShutdown) + s.cancelLock.Unlock() + return s.wg.Wait() +} diff --git a/service/goroutine_test.go b/service/goroutine_test.go new file mode 100644 index 0000000..ad67482 --- /dev/null +++ b/service/goroutine_test.go @@ -0,0 +1,56 @@ +package service_test + +import ( + "context" + "sync" + "time" + + "github.com/foomo/keel" + "github.com/foomo/keel/service" + "github.com/pkg/errors" + "go.uber.org/zap" +) + +func ExampleNewGoRoutine() { + var once sync.Once + + svr := keel.NewServer( + keel.WithLogger(zap.NewExample()), + keel.WithGracefulPeriod(3*time.Second), + ) + + svr.AddService( + service.NewGoRoutine(svr.Logger(), "demo", func(ctx context.Context, l *zap.Logger) error { + for { + // handle graceful shutdowns + if err := ctx.Err(); errors.Is(context.Cause(ctx), service.ErrServiceShutdown) { + l.Info("context has been canceled du to graceful shutdow") + return nil + } else if err != nil { + return errors.Wrap(err, "unexpected context error") + } + + l.Info("ping") + time.Sleep(700 * time.Millisecond) + once.Do(shutdown) + } + }), + ) + + svr.Run() + + // Output: + // {"level":"info","msg":"starting keel server"} + // {"level":"info","msg":"starting keel service","keel_service_type":"goroutine","keel_service_name":"demo"} + // {"level":"info","msg":"ping","keel_service_type":"goroutine","keel_service_name":"demo","keel_service_inst":0} + // {"level":"info","msg":"ping","keel_service_type":"goroutine","keel_service_name":"demo","keel_service_inst":0} + // {"level":"info","msg":"keel graceful shutdown","graceful_period":"3s"} + // {"level":"info","msg":"keel graceful shutdown: closers"} + // {"level":"info","msg":"stopping keel service","keel_service_type":"goroutine","keel_service_name":"demo"} + // {"level":"info","msg":"context has been canceled du to graceful shutdow","keel_service_type":"goroutine","keel_service_name":"demo","keel_service_inst":0} + // {"level":"debug","msg":"keel graceful shutdown: closer closed","name":"*service.GoRoutine"} + // {"level":"debug","msg":"keel graceful shutdown: closer closed","name":"noop.TracerProvider"} + // {"level":"debug","msg":"keel graceful shutdown: closer closed","name":"noop.MeterProvider"} + // {"level":"info","msg":"keel graceful shutdown: complete"} + // {"level":"info","msg":"keel server stopped"} +} diff --git a/service/helper_test.go b/service/helper_test.go new file mode 100644 index 0000000..67a5568 --- /dev/null +++ b/service/helper_test.go @@ -0,0 +1,34 @@ +package service_test + +import ( + "io" + "net" + "net/http" + "syscall" + "time" +) + +func shutdown() { + if err := syscall.Kill(syscall.Getpid(), syscall.SIGINT); err != nil { + panic(err) + } +} + +func waitFor(addr string) { + if _, err := net.DialTimeout("tcp", addr, 10*time.Second); err != nil { + panic(err.Error()) + } +} + +func httpGet(url string) string { + resp, err := http.Get(url) //nolint:all + if err != nil { + panic(err.Error()) + } + defer resp.Body.Close() + b, err := io.ReadAll(resp.Body) + if err != nil { + panic(err.Error()) + } + return string(b) +} diff --git a/service/http.go b/service/http.go new file mode 100644 index 0000000..5655467 --- /dev/null +++ b/service/http.go @@ -0,0 +1,109 @@ +package service + +import ( + "context" + "fmt" + "net" + "net/http" + "strings" + "sync/atomic" + "time" + + "github.com/pkg/errors" + "go.uber.org/zap" + + "github.com/foomo/keel/log" + "github.com/foomo/keel/net/http/middleware" +) + +// HTTP struct +type HTTP struct { + l *zap.Logger + name string + server *http.Server + running atomic.Bool +} + +// ------------------------------------------------------------------------------------------------ +// ~ Constructor +// ------------------------------------------------------------------------------------------------ + +func NewHTTP(l *zap.Logger, name, addr string, handler http.Handler, middlewares ...middleware.Middleware) *HTTP { + if l == nil { + l = log.Logger() + } + // enrich the log + l = log.WithAttributes(l, + log.KeelServiceTypeKey.String("http"), + log.KeelServiceNameKey.String(name), + ) + + return &HTTP{ + l: l, + name: name, + server: &http.Server{ + Addr: addr, + Handler: middleware.Compose(l, name, handler, middlewares...), + ErrorLog: zap.NewStdLog(l), + IdleTimeout: 30 * time.Second, + }, + } +} + +// ------------------------------------------------------------------------------------------------ +// ~ Getter +// ------------------------------------------------------------------------------------------------ + +func (s *HTTP) Name() string { + return s.name +} + +func (s *HTTP) Server() *http.Server { + return s.server +} + +// ------------------------------------------------------------------------------------------------ +// ~ Public methods +// ------------------------------------------------------------------------------------------------ + +func (s *HTTP) Healthz() error { + if !s.running.Load() { + return ErrServiceNotRunning + } + return nil +} + +func (s *HTTP) String() string { + return fmt.Sprintf("`%T` on `%s`", s.server.Handler, s.server.Addr) +} + +func (s *HTTP) Start(ctx context.Context) error { + var fields []zap.Field + if value := strings.Split(s.server.Addr, ":"); len(value) == 2 { + ip, port := value[0], value[1] + if ip == "" { + ip = "0.0.0.0" + } + fields = append(fields, log.FNetHostIP(ip), log.FNetHostPort(port)) + } + s.l.Info("starting keel service", fields...) + s.server.BaseContext = func(_ net.Listener) context.Context { return ctx } + s.server.RegisterOnShutdown(func() { + s.running.Store(false) + }) + s.running.Store(true) + if err := s.server.ListenAndServe(); errors.Is(err, http.ErrServerClosed) { + return nil + } else if err != nil { + return errors.Wrap(err, "failed to start service") + } + return nil +} + +func (s *HTTP) Close(ctx context.Context) error { + s.l.Info("stopping keel service") + if err := s.server.Shutdown(ctx); err != nil { + return errors.Wrap(err, "failed to stop service") + } + return nil +} diff --git a/service/http_test.go b/service/http_test.go new file mode 100644 index 0000000..960a440 --- /dev/null +++ b/service/http_test.go @@ -0,0 +1,47 @@ +package service_test + +import ( + "net/http" + "time" + + "github.com/foomo/keel" + "github.com/foomo/keel/service" + "go.uber.org/zap" +) + +func ExampleNewHTTP() { + svr := keel.NewServer( + keel.WithLogger(zap.NewExample()), + keel.WithGracefulPeriod(10*time.Second), + ) + + l := svr.Logger() + + svr.AddService( + service.NewHTTP(l, "demo", "localhost:8080", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + _, _ = w.Write([]byte("OK")) + })), + ) + + go func() { + waitFor("localhost:8080") + l.Info(httpGet("http://localhost:8080")) + shutdown() + }() + + svr.Run() + + // Output: + // {"level":"info","msg":"starting keel server"} + // {"level":"info","msg":"starting keel service","keel_service_type":"http","keel_service_name":"demo","net_host_ip":"localhost","net_host_port":"8080"} + // {"level":"info","msg":"OK"} + // {"level":"info","msg":"keel graceful shutdown","graceful_period":"10s"} + // {"level":"info","msg":"keel graceful shutdown: closers"} + // {"level":"info","msg":"stopping keel service","keel_service_type":"http","keel_service_name":"demo"} + // {"level":"debug","msg":"keel graceful shutdown: closer closed","name":"*service.HTTP"} + // {"level":"debug","msg":"keel graceful shutdown: closer closed","name":"noop.TracerProvider"} + // {"level":"debug","msg":"keel graceful shutdown: closer closed","name":"noop.MeterProvider"} + // {"level":"info","msg":"keel graceful shutdown: complete"} + // {"level":"info","msg":"keel server stopped"} +} diff --git a/servicehttphealthz.go b/service/httphealthz.go similarity index 64% rename from servicehttphealthz.go rename to service/httphealthz.go index 1bdfe96..790b0f7 100644 --- a/servicehttphealthz.go +++ b/service/httphealthz.go @@ -1,19 +1,20 @@ -package keel +package service import ( "context" "errors" "net/http" - "go.uber.org/zap" - + "github.com/foomo/keel/healthz" + "github.com/foomo/keel/interfaces" "github.com/foomo/keel/log" + "go.uber.org/zap" ) -const ( - DefaultServiceHTTPHealthzName = "healthz" - DefaultServiceHTTPHealthzAddr = ":9400" - DefaultServiceHTTPHealthzPath = "/healthz" +var ( + DefaultHTTPHealthzName = "healthz" + DefaultHTTPHealthzAddr = ":9400" + DefaultHTTPHealthzPath = "/healthz" ) var ( @@ -24,29 +25,29 @@ var ( ErrStartupProbeFailed = errors.New("startup probe failed") ) -func NewServiceHTTPHealthz(l *zap.Logger, name, addr, path string, probes map[HealthzType][]interface{}) *ServiceHTTP { +func NewHealthz(l *zap.Logger, name, addr, path string, probes map[healthz.Type][]interface{}) *HTTP { handler := http.NewServeMux() unavailable := func(l *zap.Logger, w http.ResponseWriter, r *http.Request, err error) { if err != nil { - log.WithHTTPRequest(l, r).Info("http healthz server", log.FError(err), log.FHTTPStatusCode(http.StatusServiceUnavailable)) + log.WithError(l, err).With(log.FHTTPTarget(r.RequestURI)).Debug("healthz probe failed") http.Error(w, http.StatusText(http.StatusServiceUnavailable), http.StatusServiceUnavailable) } } call := func(ctx context.Context, probe interface{}) (bool, error) { switch h := probe.(type) { - case BoolHealthzer: + case healthz.BoolHealthzer: return h.Healthz(), nil - case BoolHealthzerWithContext: + case healthz.BoolHealthzerWithContext: return h.Healthz(ctx), nil - case ErrorHealthzer: + case healthz.ErrorHealthzer: return true, h.Healthz() - case ErrorHealthzWithContext: + case healthz.ErrorHealthzWithContext: return true, h.Healthz(ctx) - case ErrorPinger: + case interfaces.ErrorPinger: return true, h.Ping() - case ErrorPingerWithContext: + case interfaces.ErrorPingerWithContext: return true, h.Ping(ctx) default: return false, ErrUnhandledHealthzProbe @@ -55,7 +56,7 @@ func NewServiceHTTPHealthz(l *zap.Logger, name, addr, path string, probes map[He handler.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) { for typ, values := range probes { - if typ == HealthzTypeStartup { + if typ == healthz.TypeStartup { continue } for _, p := range values { @@ -72,12 +73,12 @@ func NewServiceHTTPHealthz(l *zap.Logger, name, addr, path string, probes map[He _, _ = w.Write([]byte("OK")) }) - handler.HandleFunc(path+"/"+HealthzTypeLiveness.String(), func(w http.ResponseWriter, r *http.Request) { + handler.HandleFunc(path+"/"+healthz.TypeLiveness.String(), func(w http.ResponseWriter, r *http.Request) { var ps []interface{} - if p, ok := probes[HealthzTypeAlways]; ok { + if p, ok := probes[healthz.TypeAlways]; ok { ps = append(ps, p...) } - if p, ok := probes[HealthzTypeLiveness]; ok { + if p, ok := probes[healthz.TypeLiveness]; ok { ps = append(ps, p...) } for _, p := range ps { @@ -93,12 +94,12 @@ func NewServiceHTTPHealthz(l *zap.Logger, name, addr, path string, probes map[He _, _ = w.Write([]byte("OK")) }) - handler.HandleFunc(path+"/"+HealthzTypeReadiness.String(), func(w http.ResponseWriter, r *http.Request) { + handler.HandleFunc(path+"/"+healthz.TypeReadiness.String(), func(w http.ResponseWriter, r *http.Request) { var ps []interface{} - if p, ok := probes[HealthzTypeAlways]; ok { + if p, ok := probes[healthz.TypeAlways]; ok { ps = append(ps, p...) } - if p, ok := probes[HealthzTypeReadiness]; ok { + if p, ok := probes[healthz.TypeReadiness]; ok { ps = append(ps, p...) } for _, p := range ps { @@ -114,12 +115,12 @@ func NewServiceHTTPHealthz(l *zap.Logger, name, addr, path string, probes map[He _, _ = w.Write([]byte("OK")) }) - handler.HandleFunc(path+"/"+HealthzTypeStartup.String(), func(w http.ResponseWriter, r *http.Request) { + handler.HandleFunc(path+"/"+healthz.TypeStartup.String(), func(w http.ResponseWriter, r *http.Request) { var ps []interface{} - if p, ok := probes[HealthzTypeAlways]; ok { + if p, ok := probes[healthz.TypeAlways]; ok { ps = append(ps, p...) } - if p, ok := probes[HealthzTypeStartup]; ok { + if p, ok := probes[healthz.TypeStartup]; ok { ps = append(ps, p...) } for _, p := range ps { @@ -134,15 +135,15 @@ func NewServiceHTTPHealthz(l *zap.Logger, name, addr, path string, probes map[He w.WriteHeader(http.StatusOK) _, _ = w.Write([]byte("OK")) }) - return NewServiceHTTP(l, name, addr, handler) + return NewHTTP(l, name, addr, handler) } -func NewDefaultServiceHTTPProbes(probes map[HealthzType][]interface{}) *ServiceHTTP { - return NewServiceHTTPHealthz( - log.Logger(), - DefaultServiceHTTPHealthzName, - DefaultServiceHTTPHealthzAddr, - DefaultServiceHTTPHealthzPath, +func NewDefaultHTTPProbes(l *zap.Logger, probes map[healthz.Type][]interface{}) *HTTP { + return NewHealthz( + l, + DefaultHTTPHealthzName, + DefaultHTTPHealthzAddr, + DefaultHTTPHealthzPath, probes, ) } diff --git a/service/httppprof.go b/service/httppprof.go new file mode 100644 index 0000000..e136cff --- /dev/null +++ b/service/httppprof.go @@ -0,0 +1,38 @@ +//go:build !pprof + +package service + +import ( + "net/http" + + "go.uber.org/zap" +) + +var ( + DefaultHTTPPProfName = "pprof" + DefaultHTTPPProfAddr = "localhost:6060" + DefaultHTTPPProfPath = "/debug/pprof" +) + +func NewHTTPPProf(l *zap.Logger, name, addr, path string) *HTTP { + route := func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusNotImplemented) + _, _ = w.Write([]byte("To enable pprof, you need to build your binary with the `-tags=pprof` flag")) + } + handler := http.NewServeMux() + handler.HandleFunc(path+"/", route) + handler.HandleFunc(path+"/cmdline", route) + handler.HandleFunc(path+"/profile", route) + handler.HandleFunc(path+"/symbol", route) + handler.HandleFunc(path+"/trace", route) + return NewHTTP(l, name, addr, handler) +} + +func NewDefaultHTTPPProf(l *zap.Logger) *HTTP { + return NewHTTPPProf( + l, + DefaultHTTPPProfName, + DefaultHTTPPProfAddr, + DefaultHTTPPProfPath, + ) +} diff --git a/service/httppprof_pprof.go b/service/httppprof_pprof.go new file mode 100644 index 0000000..4943a7c --- /dev/null +++ b/service/httppprof_pprof.go @@ -0,0 +1,36 @@ +//go:build pprof +// +build pprof + +package service + +import ( + "net/http" + "net/http/pprof" + + "go.uber.org/zap" +) + +var ( + DefaultHTTPPProfName = "pprof" + DefaultHTTPPProfAddr = "localhost:6060" + DefaultHTTPPProfPath = "/debug/pprof" +) + +func NewHTTPPProf(l *zap.Logger, name, addr, path string) *HTTP { + handler := http.NewServeMux() + handler.HandleFunc(path+"/", pprof.Index) + handler.HandleFunc(path+"/cmdline", pprof.Cmdline) + handler.HandleFunc(path+"/profile", pprof.Profile) + handler.HandleFunc(path+"/symbol", pprof.Symbol) + handler.HandleFunc(path+"/trace", pprof.Trace) + return NewHTTP(l, name, addr, handler) +} + +func NewDefaultHTTPPProf(l *zap.Logger) *HTTP { + return NewHTTPPProf( + l, + DefaultHTTPPProfName, + DefaultHTTPPProfAddr, + DefaultHTTPPProfPath, + ) +} diff --git a/service/httpprometheus.go b/service/httpprometheus.go new file mode 100644 index 0000000..08f5a31 --- /dev/null +++ b/service/httpprometheus.go @@ -0,0 +1,35 @@ +package service + +import ( + "net/http" + + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promhttp" + "go.uber.org/zap" +) + +var ( + DefaultHTTPPrometheusName = "prometheus" + DefaultHTTPPrometheusAddr = ":9200" + DefaultHTTPPrometheusPath = "/metrics" +) + +func NewHTTPPrometheus(l *zap.Logger, name, addr, path string) *HTTP { + handler := http.NewServeMux() + handler.Handle(path, promhttp.HandlerFor( + prometheus.DefaultGatherer, + promhttp.HandlerOpts{ + EnableOpenMetrics: true, + }, + )) + return NewHTTP(l, name, addr, handler) +} + +func NewDefaultHTTPPrometheus(l *zap.Logger) *HTTP { + return NewHTTPPrometheus( + l, + DefaultHTTPPrometheusName, + DefaultHTTPPrometheusAddr, + DefaultHTTPPrometheusPath, + ) +} diff --git a/service/httpreadme.go b/service/httpreadme.go new file mode 100644 index 0000000..3567d5a --- /dev/null +++ b/service/httpreadme.go @@ -0,0 +1,44 @@ +package service + +import ( + "net/http" + + "github.com/foomo/keel/interfaces" + "github.com/foomo/keel/markdown" + "go.uber.org/zap" +) + +var ( + DefaultHTTPReadmeName = "readme" + DefaultHTTPReadmeAddr = "localhost:9001" + DefaultHTTPReadmePath = "/readme" +) + +func NewHTTPReadme(l *zap.Logger, name, addr, path string, readmers func() []interfaces.Readmer) *HTTP { + handler := http.NewServeMux() + handler.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) { + switch r.Method { + case http.MethodGet: + w.Header().Add("Content-Type", "text/markdown") + w.WriteHeader(http.StatusOK) + md := &markdown.Markdown{} + for _, readmer := range readmers() { + md.Print(readmer.Readme()) + } + _, _ = w.Write([]byte(md.String())) + default: + http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed) + } + }) + return NewHTTP(l, name, addr, handler) +} + +func NewDefaultHTTPReadme(l *zap.Logger, readmers func() []interfaces.Readmer) *HTTP { + return NewHTTPReadme( + l, + DefaultHTTPReadmeName, + DefaultHTTPReadmeAddr, + DefaultHTTPReadmePath, + readmers, + ) +} diff --git a/service/httpreadme_test.go b/service/httpreadme_test.go new file mode 100644 index 0000000..a9cd65a --- /dev/null +++ b/service/httpreadme_test.go @@ -0,0 +1,200 @@ +package service_test + +import ( + "context" + "fmt" + "net/http" + "os" + "time" + + "github.com/foomo/keel" + "github.com/foomo/keel/config" + "github.com/foomo/keel/env" + "github.com/foomo/keel/net/http/middleware" + "github.com/foomo/keel/service" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promauto" + "go.opentelemetry.io/otel/metric" + "go.uber.org/zap" +) + +func _ExampleNewHTTPReadme() { //nolint:unused + // define vars so it does not panic + _ = os.Setenv("EXAMPLE_REQUIRED_BOOL", "true") + _ = os.Setenv("EXAMPLE_REQUIRED_STRING", "foo") + + svr := keel.NewServer( + keel.WithLogger(zap.NewNop()), + keel.WithPrometheusMeter(true), + keel.WithHTTPReadmeService(true), + keel.WithGracefulPeriod(3*time.Second), + ) + + // access some env vars + _ = env.Get("EXAMPLE_STRING", "demo") + _ = env.GetBool("EXAMPLE_BOOL", false) + _ = env.MustGet("EXAMPLE_REQUIRED_STRING") + _ = env.MustGetBool("EXAMPLE_REQUIRED_BOOL") + + l := svr.Logger() + + c := svr.Config() + // config with fallback + _ = config.GetBool(c, "example.bool", false) + _ = config.GetString(c, "example.string", "fallback") + // required configs + _ = config.MustGetBool(c, "example.required.bool") + _ = config.MustGetString(c, "example.required.string") + + m := svr.Meter() + + // add metrics + fooBarCounter := promauto.NewCounter(prometheus.CounterOpts{ + Name: "foo_bar_total", + Help: "Foo bar metrics", + }) + fooBazCounter, _ := m.Int64Counter("foo_baz_total", metric.WithDescription("Foo baz metrics")) + + fooBarCounter.Add(1) + fooBazCounter.Add(svr.Context(), 1) + + // add http service + svr.AddService( + service.NewHTTP(l, "demp-http", "localhost:8080", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + _, _ = w.Write([]byte("OK")) + }), + middleware.Telemetry(), + ), + ) + + // add go routine service + svr.AddService(service.NewGoRoutine(l, "demo-goroutine", func(ctx context.Context, l *zap.Logger) error { + return nil + })) + + go func() { + waitFor("localhost:9001") + httpGet("http://localhost:8080/") + fmt.Println(httpGet("http://localhost:9001/readme")) + shutdown() + }() + + svr.Run() + + // Output: + // ### Env + // + // List of all accessed environment variables. + // + // | Key | Type | Required | Default | + // | ------------------------- | -------- | -------- | --------- | + // | `EXAMPLE_BOOL` | `bool` | | | + // | `EXAMPLE_REQUIRED_BOOL` | `bool` | | | + // | `EXAMPLE_REQUIRED_BOOL` | `bool` | `true` | | + // | `EXAMPLE_REQUIRED_STRING` | `string` | | | + // | `EXAMPLE_REQUIRED_STRING` | `string` | `true` | | + // | `EXAMPLE_STRING` | `string` | | `demo` | + // | `KEEL_GRACEFUL_TIMEOUT` | `int` | | | + // | `KEEL_SHUTDOWN_TIMEOUT` | `int` | | | + // | `LOG_DISABLE_CALLER` | `bool` | | | + // | `LOG_DISABLE_STACKTRACE` | `bool` | | | + // | `LOG_ENCODING` | `string` | | `json` | + // | `LOG_LEVEL` | `string` | | `info` | + // | `LOG_MODE` | `string` | | `prod` | + // | `OTEL_ENABLED` | `bool` | | | + // | `OTEL_SERVICE_NAME` | `string` | | `service` | + // + // ### Config + // + // List of all registered config variables with their defaults. + // + // | Key | Type | Required | Default | + // | ------------------------- | -------- | -------- | ---------- | + // | `example.bool` | `bool` | | `false` | + // | `example.required.bool` | `bool` | `true` | | + // | `example.required.string` | `string` | `true` | | + // | `example.string` | `string` | | `fallback` | + // | `otel.enabled` | `bool` | | `true` | + // | `service.readme.enabled` | `bool` | | `true` | + // + // ### Init Services + // + // List of all registered init services that are being immediately started. + // + // | Name | Type | Address | + // | -------- | --------------- | ------------------------------------ | + // | `readme` | `*service.HTTP` | `*http.ServeMux` on `localhost:9001` | + // + // ### Runtime Services + // + // List of all registered services that are being started. + // + // | Name | Type | Description | + // | ---------------- | -------------------- | -------------------------------------- | + // | `demo-goroutine` | `*service.GoRoutine` | parallel: `1` | + // | `demp-http` | `*service.HTTP` | `http.HandlerFunc` on `localhost:8080` | + // + // ### Health probes + // + // List of all registered healthz probes that are being called during startup and runtime. + // + // | Name | Probe | Type | Description | + // | ---------------- | ----------- | -------------------- | -------------------------------------- | + // | | `always` | `*keel.Server` | | + // | | `readiness` | `healthz.healther` | | + // | `demo-goroutine` | `always` | `*service.GoRoutine` | parallel: `1` | + // | `demp-http` | `always` | `*service.HTTP` | `http.HandlerFunc` on `localhost:8080` | + // | `readme` | `always` | `*service.HTTP` | `*http.ServeMux` on `localhost:9001` | + // + // ### Closers + // + // List of all registered closers that are being called during graceful shutdown. + // + // | Name | Type | Closer | Description | + // | ---------------- | -------------------- | ------------------------ | -------------------------------------- | + // | `demo-goroutine` | `*service.GoRoutine` | `ErrorCloserWithContext` | parallel: `1` | + // | `demp-http` | `*service.HTTP` | `ErrorCloserWithContext` | `http.HandlerFunc` on `localhost:8080` | + // | `readme` | `*service.HTTP` | `ErrorCloserWithContext` | `*http.ServeMux` on `localhost:9001` | + // + // ### Metrics + // + // List of all registered metrics than are being exposed. + // + // | Name | Type | Description | + // | --------------------------------------- | --------- | ------------------------------------------------------------------ | + // | `foo_bar_total` | COUNTER | Foo bar metrics | + // | `foo_baz_total` | COUNTER | Foo baz metrics | + // | `go_gc_duration_seconds` | SUMMARY | A summary of the pause duration of garbage collection cycles. | + // | `go_goroutines` | GAUGE | Number of goroutines that currently exist. | + // | `go_info` | GAUGE | Information about the Go environment. | + // | `go_memstats_alloc_bytes_total` | COUNTER | Total number of bytes allocated, even if freed. | + // | `go_memstats_alloc_bytes` | GAUGE | Number of bytes allocated and still in use. | + // | `go_memstats_buck_hash_sys_bytes` | GAUGE | Number of bytes used by the profiling bucket hash table. | + // | `go_memstats_frees_total` | COUNTER | Total number of frees. | + // | `go_memstats_gc_sys_bytes` | GAUGE | Number of bytes used for garbage collection system metadata. | + // | `go_memstats_heap_alloc_bytes` | GAUGE | Number of heap bytes allocated and still in use. | + // | `go_memstats_heap_idle_bytes` | GAUGE | Number of heap bytes waiting to be used. | + // | `go_memstats_heap_inuse_bytes` | GAUGE | Number of heap bytes that are in use. | + // | `go_memstats_heap_objects` | GAUGE | Number of allocated objects. | + // | `go_memstats_heap_released_bytes` | GAUGE | Number of heap bytes released to OS. | + // | `go_memstats_heap_sys_bytes` | GAUGE | Number of heap bytes obtained from system. | + // | `go_memstats_last_gc_time_seconds` | GAUGE | Number of seconds since 1970 of last garbage collection. | + // | `go_memstats_lookups_total` | COUNTER | Total number of pointer lookups. | + // | `go_memstats_mallocs_total` | COUNTER | Total number of mallocs. | + // | `go_memstats_mcache_inuse_bytes` | GAUGE | Number of bytes in use by mcache structures. | + // | `go_memstats_mcache_sys_bytes` | GAUGE | Number of bytes used for mcache structures obtained from system. | + // | `go_memstats_mspan_inuse_bytes` | GAUGE | Number of bytes in use by mspan structures. | + // | `go_memstats_mspan_sys_bytes` | GAUGE | Number of bytes used for mspan structures obtained from system. | + // | `go_memstats_next_gc_bytes` | GAUGE | Number of heap bytes when next garbage collection will take place. | + // | `go_memstats_other_sys_bytes` | GAUGE | Number of bytes used for other system allocations. | + // | `go_memstats_stack_inuse_bytes` | GAUGE | Number of bytes in use by the stack allocator. | + // | `go_memstats_stack_sys_bytes` | GAUGE | Number of bytes obtained from system for stack allocator. | + // | `go_memstats_sys_bytes` | GAUGE | Number of bytes obtained from system. | + // | `go_threads` | GAUGE | Number of OS threads created. | + // | `http_server_duration_milliseconds` | HISTOGRAM | Measures the duration of inbound HTTP requests. | + // | `http_server_request_size_bytes_total` | COUNTER | Measures the size of HTTP request messages. | + // | `http_server_response_size_bytes_total` | COUNTER | Measures the size of HTTP response messages. | + // | `otel_scope_info` | GAUGE | Instrumentation Scope metadata | + // | `target_info` | GAUGE | Target metadata | +} diff --git a/servicehttpviper.go b/service/httpviper.go similarity index 64% rename from servicehttpviper.go rename to service/httpviper.go index 2e34025..22bb2c0 100644 --- a/servicehttpviper.go +++ b/service/httpviper.go @@ -1,4 +1,4 @@ -package keel +package service import ( "encoding/json" @@ -8,16 +8,15 @@ import ( "go.uber.org/zap" "github.com/foomo/keel/config" - "github.com/foomo/keel/log" ) -const ( - DefaultServiceHTTPViperName = "viper" - DefaultServiceHTTPViperAddr = "localhost:9300" - DefaultServiceHTTPViperPath = "/config" +var ( + DefaultHTTPViperName = "viper" + DefaultHTTPViperAddr = "localhost:9300" + DefaultHTTPViperPath = "/config" ) -func NewServiceHTTPViper(l *zap.Logger, c *viper.Viper, name, addr, path string) *ServiceHTTP { +func NewHTTPViper(l *zap.Logger, c *viper.Viper, name, addr, path string) *HTTP { handler := http.NewServeMux() handler.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) { type payload struct { @@ -44,15 +43,15 @@ func NewServiceHTTPViper(l *zap.Logger, c *viper.Viper, name, addr, path string) http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed) } }) - return NewServiceHTTP(l, name, addr, handler) + return NewHTTP(l, name, addr, handler) } -func NewDefaultServiceHTTPViper() *ServiceHTTP { - return NewServiceHTTPViper( - log.Logger(), +func NewDefaultHTTPViper(l *zap.Logger) *HTTP { + return NewHTTPViper( + l, config.Config(), - DefaultServiceHTTPViperName, - DefaultServiceHTTPViperAddr, - DefaultServiceHTTPViperPath, + DefaultHTTPViperName, + DefaultHTTPViperAddr, + DefaultHTTPViperPath, ) } diff --git a/servicehttpzap.go b/service/httpzap.go similarity index 84% rename from servicehttpzap.go rename to service/httpzap.go index 384189a..efea2f3 100644 --- a/servicehttpzap.go +++ b/service/httpzap.go @@ -1,4 +1,4 @@ -package keel +package service import ( "encoding/json" @@ -11,13 +11,13 @@ import ( "github.com/foomo/keel/log" ) -const ( - DefaultServiceHTTPZapName = "zap" - DefaultServiceHTTPZapAddr = "localhost:9100" - DefaultServiceHTTPZapPath = "/log" +var ( + DefaultHTTPZapName = "zap" + DefaultHTTPZapAddr = "localhost:9100" + DefaultHTTPZapPath = "/log" ) -func NewServiceHTTPZap(l *zap.Logger, name, addr, path string) *ServiceHTTP { +func NewHTTPZap(l *zap.Logger, name, addr, path string) *HTTP { handler := http.NewServeMux() handler.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) { type errorResponse struct { @@ -91,14 +91,14 @@ func NewServiceHTTPZap(l *zap.Logger, name, addr, path string) *ServiceHTTP { }) } }) - return NewServiceHTTP(l, name, addr, handler) + return NewHTTP(l, name, addr, handler) } -func NewDefaultServiceHTTPZap() *ServiceHTTP { - return NewServiceHTTPZap( - log.Logger(), - DefaultServiceHTTPZapName, - DefaultServiceHTTPZapAddr, - DefaultServiceHTTPZapPath, +func NewDefaultHTTPZap(l *zap.Logger) *HTTP { + return NewHTTPZap( + l, + DefaultHTTPZapName, + DefaultHTTPZapAddr, + DefaultHTTPZapPath, ) } diff --git a/serviceenabler.go b/serviceenabler.go index dd01a1a..19f38c3 100644 --- a/serviceenabler.go +++ b/serviceenabler.go @@ -2,6 +2,7 @@ package keel import ( "context" + "sync" "time" "go.uber.org/zap" @@ -12,23 +13,25 @@ import ( type ServiceFunc func() Service type ServiceEnabler struct { - l *zap.Logger - ctx context.Context - name string - service Service - serviceFn ServiceFunc - enabled bool - enabledFn func() bool - closed bool + l *zap.Logger + ctx context.Context + name string + service Service + serviceFn ServiceFunc + syncEnabled bool + syncEnabledLock sync.RWMutex + enabledFn func() bool + syncClosed bool + syncClosedLock sync.RWMutex } func NewServiceEnabler(l *zap.Logger, name string, serviceFn ServiceFunc, enabledFn func() bool) *ServiceEnabler { return &ServiceEnabler{ - l: log.WithServiceName(l, name), - name: name, - serviceFn: serviceFn, - enabled: enabledFn(), - enabledFn: enabledFn, + l: log.WithServiceName(l, name), + name: name, + serviceFn: serviceFn, + syncEnabled: enabledFn(), + enabledFn: enabledFn, } } @@ -36,35 +39,85 @@ func (w *ServiceEnabler) Name() string { return w.name } +func (w *ServiceEnabler) Start(ctx context.Context) error { + w.watch(w.ctx) //nolint:contextcheck + w.ctx = ctx + if w.enabled() { + if err := w.enable(w.ctx); err != nil { //nolint:contextcheck + return err + } + } else { + w.l.Info("skipping disabled dynamic service") + } + return nil +} + +func (w *ServiceEnabler) Close(ctx context.Context) error { + l := log.WithServiceName(w.l, w.Name()) + w.setClosed(true) + if w.enabled() { + if err := w.disable(w.ctx); err != nil { //nolint:contextcheck + return err + } + } else { + l.Info("skipping disabled dynamic service") + } + return nil +} + +func (w *ServiceEnabler) closed() bool { + w.syncClosedLock.RLock() + defer w.syncClosedLock.RUnlock() + return w.syncClosed +} + +func (w *ServiceEnabler) setClosed(v bool) { + w.syncClosedLock.Lock() + defer w.syncClosedLock.Unlock() + w.syncClosed = v +} + +func (w *ServiceEnabler) enabled() bool { + w.syncEnabledLock.RLock() + defer w.syncEnabledLock.RUnlock() + return w.syncEnabled +} + +func (w *ServiceEnabler) setEnabled(v bool) { + w.syncEnabledLock.Lock() + defer w.syncEnabledLock.Unlock() + w.syncEnabled = v +} + func (w *ServiceEnabler) enable(ctx context.Context) error { - w.enabled = true + w.setEnabled(true) w.service = w.serviceFn() w.l.Info("starting dynamic service") return w.service.Start(ctx) } func (w *ServiceEnabler) disable(ctx context.Context) error { - w.enabled = false + w.setEnabled(false) w.l.Info("stopping dynamic service") return w.service.Close(ctx) } -func (w *ServiceEnabler) watch() { +func (w *ServiceEnabler) watch(ctx context.Context) { go func() { for { - if w.closed { + if w.closed() { break } time.Sleep(time.Second) - if value := w.enabledFn(); value != w.enabled { + if value := w.enabledFn(); value != w.enabled() { if value { go func() { - if err := w.enable(w.ctx); err != nil { + if err := w.enable(ctx); err != nil { w.l.Fatal("failed to dynamically start service", log.FError(err)) } }() } else { - if err := w.disable(context.TODO()); err != nil { + if err := w.disable(context.TODO()); err != nil { //nolint:contextcheck w.l.Fatal("failed to dynamically close service", log.FError(err)) } } @@ -72,29 +125,3 @@ func (w *ServiceEnabler) watch() { } }() } - -func (w *ServiceEnabler) Start(ctx context.Context) error { - w.watch() - w.ctx = ctx - if w.enabled { - if err := w.enable(w.ctx); err != nil { - return err - } - } else { - w.l.Info("skipping disabled dynamic service") - } - return nil -} - -func (w *ServiceEnabler) Close(ctx context.Context) error { - l := log.WithServiceName(w.l, w.Name()) - w.closed = true - if w.enabled { - if err := w.disable(w.ctx); err != nil { - return err - } - } else { - l.Info("skipping disabled dynamic service") - } - return nil -} diff --git a/servicehttp.go b/servicehttp.go deleted file mode 100644 index e798576..0000000 --- a/servicehttp.go +++ /dev/null @@ -1,78 +0,0 @@ -package keel - -import ( - "context" - "net" - "net/http" - "strings" - - "github.com/pkg/errors" - "go.uber.org/zap" - - "github.com/foomo/keel/log" - "github.com/foomo/keel/net/http/middleware" -) - -// ServiceHTTP struct -type ServiceHTTP struct { - running bool - server *http.Server - name string - l *zap.Logger -} - -func NewServiceHTTP(l *zap.Logger, name, addr string, handler http.Handler, middlewares ...middleware.Middleware) *ServiceHTTP { - if l == nil { - l = log.Logger() - } - // enrich the log - l = log.WithHTTPServerName(l, name) - - return &ServiceHTTP{ - server: &http.Server{ - Addr: addr, - ErrorLog: zap.NewStdLog(l), - Handler: middleware.Compose(l, name, handler, middlewares...), - }, - name: name, - l: l, - } -} - -func (s *ServiceHTTP) Name() string { - return s.name -} - -func (s *ServiceHTTP) Healthz() error { - if !s.running { - return ErrServiceNotRunning - } - return nil -} - -func (s *ServiceHTTP) Start(ctx context.Context) error { - var fields []zap.Field - if value := strings.Split(s.server.Addr, ":"); len(value) == 2 { - ip, port := value[0], value[1] - if ip == "" { - ip = "0.0.0.0" - } - fields = append(fields, log.FNetHostIP(ip), log.FNetHostPort(port)) - } - s.l.Info("starting http service", fields...) - s.server.BaseContext = func(_ net.Listener) context.Context { return ctx } - s.server.RegisterOnShutdown(func() { - s.running = false - }) - s.running = true - if err := s.server.ListenAndServe(); !errors.Is(err, http.ErrServerClosed) { - log.WithError(s.l, err).Error("service error") - return err - } - return nil -} - -func (s *ServiceHTTP) Close(ctx context.Context) error { - s.l.Info("stopping http service") - return s.server.Shutdown(ctx) -} diff --git a/servicehttpprometheus.go b/servicehttpprometheus.go deleted file mode 100644 index 9636205..0000000 --- a/servicehttpprometheus.go +++ /dev/null @@ -1,37 +0,0 @@ -package keel - -import ( - "net/http" - - "github.com/prometheus/client_golang/prometheus" - "github.com/prometheus/client_golang/prometheus/promhttp" - "go.uber.org/zap" - - "github.com/foomo/keel/log" -) - -const ( - DefaultServiceHTTPPrometheusName = "prometheus" - DefaultServiceHTTPPrometheusAddr = ":9200" - DefaultServiceHTTPPrometheusPath = "/metrics" -) - -func NewServiceHTTPPrometheus(l *zap.Logger, name, addr, path string) *ServiceHTTP { - handler := http.NewServeMux() - handler.Handle(path, promhttp.HandlerFor( - prometheus.DefaultGatherer, - promhttp.HandlerOpts{ - EnableOpenMetrics: true, - }, - )) - return NewServiceHTTP(l, name, addr, handler) -} - -func NewDefaultServiceHTTPPrometheus() *ServiceHTTP { - return NewServiceHTTPPrometheus( - log.Logger(), - DefaultServiceHTTPPrometheusName, - DefaultServiceHTTPPrometheusAddr, - DefaultServiceHTTPPrometheusPath, - ) -} diff --git a/telemetry/meter.go b/telemetry/meter.go index d343a14..31eb9e8 100644 --- a/telemetry/meter.go +++ b/telemetry/meter.go @@ -2,23 +2,18 @@ package telemetry import ( "context" - "log" + "encoding/json" + "os" - "github.com/prometheus/client_golang/prometheus" - otelprometheus "go.opentelemetry.io/otel/exporters/prometheus" + "github.com/foomo/keel/env" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/exporters/prometheus" "go.opentelemetry.io/otel/exporters/stdout/stdoutmetric" "go.opentelemetry.io/otel/metric" - otelglobal "go.opentelemetry.io/otel/metric/global" - "go.opentelemetry.io/otel/metric/nonrecording" - "go.opentelemetry.io/otel/sdk/metric/aggregator/histogram" - otelcontroller "go.opentelemetry.io/otel/sdk/metric/controller/basic" - otelaggregation "go.opentelemetry.io/otel/sdk/metric/export/aggregation" - otelprocessor "go.opentelemetry.io/otel/sdk/metric/processor/basic" - otelselector "go.opentelemetry.io/otel/sdk/metric/selector/simple" + "go.opentelemetry.io/otel/metric/noop" + sdkmetric "go.opentelemetry.io/otel/sdk/metric" otelresource "go.opentelemetry.io/otel/sdk/resource" - semconv "go.opentelemetry.io/otel/semconv/v1.10.0" - - "github.com/foomo/keel/env" + semconv "go.opentelemetry.io/otel/semconv/v1.24.0" ) var ( @@ -27,71 +22,58 @@ var ( ) func Meter() metric.Meter { - return otelglobal.Meter("") + return otel.Meter("") } func NewNoopMeterProvider() (metric.MeterProvider, error) { - controller := nonrecording.NewNoopMeterProvider() - otelglobal.SetMeterProvider(controller) - return controller, nil + provider := noop.NewMeterProvider() + otel.SetMeterProvider(provider) + return provider, nil } func NewStdOutMeterProvider(ctx context.Context, opts ...stdoutmetric.Option) (metric.MeterProvider, error) { if env.GetBool("OTEL_EXPORTER_STDOUT_PRETTY_PRINT", true) { - opts = append(opts, stdoutmetric.WithPrettyPrint()) + enc := json.NewEncoder(os.Stdout) + enc.SetIndent("", " ") + opts = append(opts, stdoutmetric.WithEncoder(enc)) + } + if !env.GetBool("OTEL_EXPORTER_STDOUT_TIMESTAMP", true) { + opts = append(opts, stdoutmetric.WithoutTimestamps()) } exporter, err := stdoutmetric.New(opts...) if err != nil { - log.Fatalf("creating stdoutmetric exporter: %v", err) + return nil, err } resource := otelresource.NewSchemaless( semconv.ServiceNameKey.String(env.Get("OTEL_SERVICE_NAME", ServiceName)), ) - controller := otelcontroller.New( - otelprocessor.NewFactory( - otelselector.NewWithInexpensiveDistribution(), - exporter, - ), - otelcontroller.WithExporter(exporter), - otelcontroller.WithResource(resource), + provider := sdkmetric.NewMeterProvider( + sdkmetric.WithReader(sdkmetric.NewPeriodicReader(exporter)), + sdkmetric.WithResource(resource), ) - if err = controller.Start(ctx); err != nil { - return nil, err - } - - otelglobal.SetMeterProvider(controller) - return controller, nil + otel.SetMeterProvider(provider) + return provider, nil } func NewPrometheusMeterProvider() (metric.MeterProvider, error) { - config := otelprometheus.Config{ - Registerer: prometheus.DefaultRegisterer, - Gatherer: prometheus.DefaultGatherer, + exporter, err := prometheus.New() + if err != nil { + return nil, err } resource := otelresource.NewSchemaless( semconv.ServiceNameKey.String(env.Get("OTEL_SERVICE_NAME", ServiceName)), ) - controller := otelcontroller.New( - otelprocessor.NewFactory( - otelselector.NewWithHistogramDistribution( - histogram.WithExplicitBoundaries(DefaultHistogramBuckets)), - otelaggregation.CumulativeTemporalitySelector(), - otelprocessor.WithMemory(true), - ), - otelcontroller.WithResource(resource), + provider := sdkmetric.NewMeterProvider( + sdkmetric.WithReader(exporter), + sdkmetric.WithResource(resource), ) - _, err := otelprometheus.New(config, controller) - if err != nil { - return nil, err - } - - otelglobal.SetMeterProvider(controller) - return controller, nil + otel.SetMeterProvider(provider) + return provider, nil } diff --git a/telemetry/tracer.go b/telemetry/tracer.go index 1d75e4d..5ca41f6 100644 --- a/telemetry/tracer.go +++ b/telemetry/tracer.go @@ -11,6 +11,7 @@ import ( sdktrace "go.opentelemetry.io/otel/sdk/trace" semconv "go.opentelemetry.io/otel/semconv/v1.10.0" "go.opentelemetry.io/otel/trace" + "go.opentelemetry.io/otel/trace/noop" "github.com/foomo/keel/env" ) @@ -24,7 +25,7 @@ func TraceProvider() trace.TracerProvider { } func NewNoopTraceProvider() (trace.TracerProvider, error) { - tracerProvider := trace.NewNoopTracerProvider() + tracerProvider := noop.NewTracerProvider() otel.SetTracerProvider(tracerProvider) return tracerProvider, nil } @@ -34,6 +35,9 @@ func NewStdOutTraceProvider(ctx context.Context) (trace.TracerProvider, error) { if env.GetBool("OTEL_EXPORTER_STDOUT_PRETTY_PRINT", true) { exportOpts = append(exportOpts, stdouttrace.WithPrettyPrint()) } + if !env.GetBool("OTEL_EXPORTER_STDOUT_TIMESTAMPS", true) { + exportOpts = append(exportOpts, stdouttrace.WithoutTimestamps()) + } exporter, err := stdouttrace.New(exportOpts...) if err != nil { @@ -83,7 +87,11 @@ func newTracerProvider(e sdktrace.SpanExporter) (trace.TracerProvider, error) { tracerProvider := sdktrace.NewTracerProvider( sdktrace.WithBatcher(e), sdktrace.WithResource(resource), - sdktrace.WithSampler(sdktrace.TraceIDRatioBased(env.GetFloat64("OTEL_TRACE_RATIO", 1))), + sdktrace.WithSampler( + sdktrace.ParentBased( + sdktrace.TraceIDRatioBased(env.GetFloat64("OTEL_TRACE_RATIO", 1)), + ), + ), ) otel.SetTracerProvider(tracerProvider) diff --git a/test/log.go b/test/log.go deleted file mode 100644 index 82d2b5f..0000000 --- a/test/log.go +++ /dev/null @@ -1,105 +0,0 @@ -package keeltest - -import ( - "bytes" - "fmt" - - "go.uber.org/zap" - "go.uber.org/zap/zapcore" - "go.uber.org/zap/zaptest" -) - -type ( - Logger struct { - zap *zap.Logger - writer *testingWriter - } - LoggerOptions struct { - Level zapcore.LevelEnabler - zapOptions []zap.Option - } - LoggerOption func(*LoggerOptions) -) - -// LoggerWithLevel adds zap.Option's to a test Logger built by NewLogger. -func LoggerWithLevel(o zapcore.LevelEnabler) LoggerOption { - return func(v *LoggerOptions) { - v.Level = o - } -} - -// LoggerWithZapOptions adds zap.Option's to a test Logger built by NewLogger. -func LoggerWithZapOptions(o ...zap.Option) LoggerOption { - return func(v *LoggerOptions) { - v.zapOptions = o - } -} - -func NewLogger(t zaptest.TestingT, opts ...LoggerOption) *Logger { - cfg := LoggerOptions{ - Level: zapcore.DebugLevel, - } - for _, opt := range opts { - opt(&cfg) - } - - writer := newTestingWriter(t) - zapOptions := []zap.Option{ - zap.AddCaller(), - // zap.AddCallerSkip(1), - // Send zap errors to the same writer and mark the test as failed if that happens. - zap.ErrorOutput(writer), - } - zapOptions = append(zapOptions, cfg.zapOptions...) - - e := zap.NewDevelopmentEncoderConfig() - e.TimeKey = "" - e.EncodeLevel = zapcore.CapitalColorLevelEncoder - e.EncodeCaller = func(s zapcore.EntryCaller, enc zapcore.PrimitiveArrayEncoder) { - enc.AppendString(fmt.Sprintf("\x1b[%dm%s\x1b[0m", uint8(37), s.TrimmedPath())) - } - return &Logger{ - zap: zap.New( - zapcore.NewCore( - zapcore.NewConsoleEncoder(e), - writer, - cfg.Level, - ), - zapOptions..., - ), - writer: writer, - } -} - -func (l *Logger) T(t zaptest.TestingT) *Logger { - l.writer.t = t - return l -} - -func (l *Logger) Zap() *zap.Logger { - return l.zap -} - -// testingWriter is a WriteSyncer that writes to the given testing.TB. -type testingWriter struct { - t zaptest.TestingT -} - -func newTestingWriter(t zaptest.TestingT) *testingWriter { - return &testingWriter{t: t} -} - -func (w *testingWriter) Write(p []byte) (int, error) { - if w.t == nil { - return fmt.Printf("%s", p) //nolint:forbidigo - } else { - // Note: t.Log is safe for concurrent use. - // Strip trailing newline because t.Log always adds one. - w.t.Logf("%s", bytes.TrimRight(p, "\n")) - return len(p), nil - } -} - -func (w *testingWriter) Sync() error { - return nil -} diff --git a/utils/net/http/errors.go b/utils/net/http/errors.go index 4a001eb..0bcb462 100644 --- a/utils/net/http/errors.go +++ b/utils/net/http/errors.go @@ -3,8 +3,8 @@ package httputils import ( "net/http" - "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" - "go.opentelemetry.io/otel/attribute" + httplog "github.com/foomo/keel/net/http/log" + "github.com/pkg/errors" "go.uber.org/zap" "github.com/foomo/keel/log" @@ -43,11 +43,13 @@ func NotFoundServerError(l *zap.Logger, w http.ResponseWriter, r *http.Request, // ServerError http response func ServerError(l *zap.Logger, w http.ResponseWriter, r *http.Request, code int, err error) { if err != nil { - l = log.WithError(l, err) - if labeler, ok := otelhttp.LabelerFromContext(r.Context()); ok { - labeler.Add(attribute.Bool("error", true)) + if labeler, ok := httplog.LabelerFromRequest(r); ok { + labeler.Add(log.FErrorType(err), log.FError(errors.Wrap(err, "http server error"))) + } else { + l = log.WithError(l, err) + l = log.WithHTTPRequest(l, r) + l.Error("http server error", log.FHTTPStatusCode(code)) } - log.WithHTTPRequest(l, r).Error("http server error", log.FHTTPStatusCode(code)) // w.Header().Set(keelhttp.HeaderXError, err.Error()) TODO make configurable with better value http.Error(w, http.StatusText(code), code) }