diff --git a/.codecov.yml b/.codecov.yml
index 4a78255b78f8..ea0a4218a33b 100644
--- a/.codecov.yml
+++ b/.codecov.yml
@@ -1,3 +1,7 @@
+coverage:
+ status:
+ patch: true
+ project: false # disabled because project coverage is not stable
comment:
layout: "flags, files"
behavior: once
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
index 4344747373ee..2b1ec376d924 100644
--- a/.github/workflows/codeql-analysis.yml
+++ b/.github/workflows/codeql-analysis.yml
@@ -35,7 +35,7 @@ jobs:
steps:
- name: Checkout repository
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml
index 7bf076e4c97f..f3a3d561b3e8 100644
--- a/.github/workflows/go.yml
+++ b/.github/workflows/go.yml
@@ -12,12 +12,12 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check out code into the Go module directory
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Set up Go 1.x
- uses: actions/setup-go@v3
+ uses: actions/setup-go@v4
with:
- go-version: 1.18
+ go-version: 1.19
check-latest: true
cache: true
id: go
@@ -47,13 +47,13 @@ jobs:
runs-on: windows-latest
steps:
- name: Checkout codebase
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Set up Go 1.x
- uses: actions/setup-go@v3
+ uses: actions/setup-go@v4
with:
- # use 1.18 to guarantee Go 1.18 compatibility
- go-version: 1.18
+ # use 1.19 to guarantee Go 1.19 compatibility
+ go-version: 1.19
check-latest: true
cache: true
diff --git a/.github/workflows/issues.yml b/.github/workflows/issues.yml
index 48c19053560e..b77275672d00 100644
--- a/.github/workflows/issues.yml
+++ b/.github/workflows/issues.yml
@@ -7,7 +7,7 @@ jobs:
close-issues:
runs-on: ubuntu-latest
steps:
- - uses: actions/stale@v6
+ - uses: actions/stale@v8
with:
days-before-issue-stale: 365
days-before-issue-close: 90
diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml
index 4a0378d7e67c..ff55c6eb6f09 100644
--- a/.github/workflows/release.yaml
+++ b/.github/workflows/release.yaml
@@ -16,13 +16,13 @@ jobs:
- goarch: "386"
goos: darwin
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- uses: zeromicro/go-zero-release-action@master
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
goos: ${{ matrix.goos }}
goarch: ${{ matrix.goarch }}
- goversion: "https://dl.google.com/go/go1.18.10.linux-amd64.tar.gz"
+ goversion: "https://dl.google.com/go/go1.19.13.linux-amd64.tar.gz"
project_path: "tools/goctl"
binary_name: "goctl"
extra_files: tools/goctl/readme.md tools/goctl/readme-cn.md
\ No newline at end of file
diff --git a/.github/workflows/reviewdog.yml b/.github/workflows/reviewdog.yml
index 415b567ef4eb..7620592dda99 100644
--- a/.github/workflows/reviewdog.yml
+++ b/.github/workflows/reviewdog.yml
@@ -5,7 +5,7 @@ jobs:
name: runner / staticcheck
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- uses: reviewdog/action-staticcheck@v1
with:
github_token: ${{ secrets.github_token }}
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index de56ce14ea12..da6b3e1cea85 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,102 +1,76 @@
-# Contributing
+# 🚀 Contributing to go-zero
-Welcome to go-zero!
+Welcome to the go-zero community! We're thrilled to have you here. Contributing to our project is a fantastic way to be a part of the go-zero journey. Let's make this guide exciting and fun!
-- [Before you get started](#before-you-get-started)
- - [Code of Conduct](#code-of-conduct)
- - [Community Expectations](#community-expectations)
-- [Getting started](#getting-started)
-- [Your First Contribution](#your-first-contribution)
- - [Find something to work on](#find-something-to-work-on)
- - [Find a good first topic](#find-a-good-first-topic)
- - [Work on an Issue](#work-on-an-issue)
- - [File an Issue](#file-an-issue)
-- [Contributor Workflow](#contributor-workflow)
- - [Creating Pull Requests](#creating-pull-requests)
- - [Code Review](#code-review)
- - [Testing](#testing)
+## 📜 Before You Dive In
-# Before you get started
+### 🤝 Code of Conduct
-## Code of Conduct
+Let's start on the right foot. Please take a moment to read and embrace our [Code of Conduct](/code-of-conduct.md). We're all about creating a welcoming and respectful environment.
-Please make sure to read and observe our [Code of Conduct](/code-of-conduct.md).
+### 🌟 Community Expectations
-## Community Expectations
+At go-zero, we're like a close-knit family, and we believe in creating a healthy, friendly, and productive atmosphere. It's all about sharing knowledge and building amazing things together.
-go-zero is a community project driven by its community which strives to promote a healthy, friendly and productive environment.
-go-zero is a web and rpc framework written in Go. It's born to ensure the stability of the busy sites with resilient design. Builtin goctl greatly improves the development productivity.
+## 🚀 Getting Started
-# Getting started
+Get your adventure rolling! Here's how to begin:
-- Fork the repository on GitHub.
-- Make your changes on your fork repository.
-- Submit a PR.
+1. 🍴 **Fork the Repository**: Head over to the GitHub repository and fork it to your own space.
+2. 🛠️ **Make Your Magic**: Work your magic in your forked repository. Create new features, squash bugs, or improve documentation - it's your world to conquer!
-# Your First Contribution
+3. 🚀 **Submit a PR (Pull Request)**: When you're ready to unveil your creation, submit a Pull Request. We can't wait to see your awesome work!
-We will help you to contribute in different areas like filing issues, developing features, fixing critical bugs and
-getting your work reviewed and merged.
+## 🌟 Your First Contribution
-If you have questions about the development process,
-feel free to [file an issue](https://github.com/zeromicro/go-zero/issues/new/choose).
+We're here to guide you on your quest to become a go-zero contributor. Whether you want to file issues, develop features, or tame some critical bugs, we've got you covered.
-## Find something to work on
+If you have questions or need guidance at any stage, don't hesitate to [open an issue](https://github.com/zeromicro/go-zero/issues/new/choose).
-We are always in need of help, be it fixing documentation, reporting bugs or writing some code.
-Look at places where you feel best coding practices aren't followed, code refactoring is needed or tests are missing.
-Here is how you get started.
+## 🔍 Find Something to Work On
-### Find a good first topic
+Ready to dive into the action? There are several ways to contribute:
-[go-zero](https://github.com/zeromicro/go-zero) has beginner-friendly issues that provide a good first issue.
-For example, [go-zero](https://github.com/zeromicro/go-zero) has
-[help wanted](https://github.com/zeromicro/go-zero/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22) and
-[good first issue](https://github.com/zeromicro/go-zero/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22)
-labels for issues that should not need deep knowledge of the system.
-We can help new contributors who wish to work on such issues.
+### 💼 Find a Good First Topic
-Another good way to contribute is to find a documentation improvement, such as a missing/broken link.
-Please see [Contributing](#contributing) below for the workflow.
+Discover easy-entry issues labeled as [help wanted](https://github.com/zeromicro/go-zero/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22) or [good first issue](https://github.com/zeromicro/go-zero/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22). These issues are perfect for newcomers and don't require deep knowledge of the system. We're here to assist you with these tasks.
-#### Work on an issue
+### 🪄 Work on an Issue
-When you are willing to take on an issue, just reply on the issue. The maintainer will assign it to you.
+Once you've picked an issue that excites you, let us know by commenting on it. Our maintainers will assign it to you, and you can embark on your mission!
-### File an Issue
+### 📢 File an Issue
-While we encourage everyone to contribute code, it is also appreciated when someone reports an issue.
+Reporting an issue is just as valuable as code contributions. If you discover a problem, don't hesitate to [open an issue](https://github.com/zeromicro/go-zero/issues/new/choose). Be sure to follow our guidelines when submitting an issue.
-Please follow the prompted submission guidelines while opening an issue.
+## 🎯 Contributor Workflow
-# Contributor Workflow
+Here's a rough guide to your contributor journey:
-Please do not ever hesitate to ask a question or send a pull request.
+1. 🌱 Create a New Branch: Start by creating a topic branch, usually based on the 'master' branch. This is where your contribution will grow.
-This is a rough outline of what a contributor's workflow looks like:
+2. 💡 Make Commits: Commit your work in logical units. Each commit should tell a story.
-- Create a topic branch from where to base the contribution. This is usually master.
-- Make commits of logical units.
-- Push changes in a topic branch to a personal fork of the repository.
-- Submit a pull request to [go-zero](https://github.com/zeromicro/go-zero).
+3. 🚀 Push Changes: Push the changes in your topic branch to your personal fork of the repository.
-## Creating Pull Requests
+4. 📦 Submit a Pull Request: When your creation is complete, submit a Pull Request to the [go-zero repository](https://github.com/zeromicro/go-zero).
-Pull requests are often called simply "PR".
-go-zero generally follows the standard [github pull request](https://help.github.com/articles/about-pull-requests/) process.
-To submit a proposed change, please develop the code/fix and add new test cases.
-After that, run these local verifications before submitting pull request to predict the pass or
-fail of continuous integration.
+## 🌠 Creating Pull Requests
-* Format the code with `gofmt`
-* Run the test with data race enabled `go test -race ./...`
+Pull Requests (PRs) are your way of making a grand entrance with your contribution. Here's how to do it:
-## Code Review
+- 💼 Format Your Code: Ensure your code is beautifully formatted with `gofmt`.
+- 🏃 Run Tests: Verify that your changes pass all the tests, including data race tests. Run `go test -race ./...` for the ultimate validation.
-To make it easier for your PR to receive reviews, consider the reviewers will need you to:
+## 👁️🗨️ Code Review
-* follow [good coding guidelines](https://github.com/golang/go/wiki/CodeReviewComments).
-* write [good commit messages](https://chris.beams.io/posts/git-commit/).
-* break large changes into a logical series of smaller patches which individually make easily understandable changes, and in aggregate solve a broader issue.
+Getting your PR reviewed is the final step before your contribution becomes part of go-zero's magical world. To make the process smooth, keep these things in mind:
+- 🧙♀️ Follow Good Coding Practices: Stick to [good coding guidelines](https://github.com/golang/go/wiki/CodeReviewComments).
+- 📝 Write Awesome Commit Messages: Craft [impressive commit messages](https://chris.beams.io/posts/git-commit/) - they're like spells in the wizard's book!
+- 🔍 Break It Down: For larger changes, consider breaking them into a series of smaller, logical patches. Each patch should make an understandable and meaningful improvement.
+
+Congratulations on your contribution journey! We're thrilled to have you as part of our go-zero community. Let's make amazing things together! 🌟
+
+Now, go out there and start your adventure! If you have any more magical ideas to enhance this guide, please share them. 🔥
\ No newline at end of file
diff --git a/code-of-conduct.md b/code-of-conduct.md
index 81b217c6c835..efe47da41ea3 100644
--- a/code-of-conduct.md
+++ b/code-of-conduct.md
@@ -1,76 +1,127 @@
+
# Contributor Covenant Code of Conduct
## Our Pledge
-In the interest of fostering an open and welcoming environment, we as
-contributors and maintainers pledge to make participation in our project and
-our community a harassment-free experience for everyone, regardless of age, body
-size, 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 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, caste, color, 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 creating a positive environment
-include:
+Examples of behavior that contributes to a positive environment for our
+community include:
-* Using welcoming and inclusive language
-* Being respectful of differing viewpoints and experiences
-* Gracefully accepting constructive criticism
-* Focusing on what is best for the community
-* Showing empathy towards other community members
+* 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 by participants include:
+Examples of unacceptable behavior include:
-* The use of sexualized language or imagery and unwelcome sexual attention or
- advances
-* Trolling, insulting/derogatory comments, and personal or political attacks
+* 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 electronic
- address, without explicit permission
+* 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
-## Our Responsibilities
+## Enforcement Responsibilities
-Project maintainers are responsible for clarifying the standards of acceptable
-behavior and are expected to take appropriate and fair corrective action in
-response to any instances of unacceptable behavior.
+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.
-Project maintainers 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, or to ban temporarily or
-permanently any contributor for other behaviors 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 project spaces, and it also applies when
-an individual is representing the project or its community in public spaces.
-Examples of representing a project or community include using an official
-project e-mail address, posting via an official social media account, or acting
-as an appointed representative at an online or offline event. Representation of
-a project may be further defined and clarified by project maintainers.
+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 by contacting the project team at [INSERT EMAIL ADDRESS]. All
-complaints will be reviewed and investigated and will result in a response that
-is deemed necessary and appropriate to the circumstances. The project team is
-obligated to maintain confidentiality with regard to the reporter of an incident.
-Further details of specific enforcement policies may be posted separately.
+reported to the community leaders responsible for enforcement at
+[INSERT CONTACT METHOD].
+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.
-Project maintainers who do not follow or enforce the Code of Conduct in good
-faith may face temporary or permanent repercussions as determined by other
-members of the project's leadership.
+**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 1.4,
-available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
+This Code of Conduct is adapted from the [Contributor Covenant][homepage],
+version 2.1, available at
+[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
-[homepage]: https://www.contributor-covenant.org
+Community Impact Guidelines were inspired by
+[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
-For answers to common questions about this code of conduct, see
-https://www.contributor-covenant.org/faq
+For answers to common questions about this code of conduct, see the FAQ at
+[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
+[https://www.contributor-covenant.org/translations][translations].
diff --git a/core/breaker/breaker.go b/core/breaker/breaker.go
index 3d5102ef89fd..9fc4a48321df 100644
--- a/core/breaker/breaker.go
+++ b/core/breaker/breaker.go
@@ -46,7 +46,7 @@ type (
// DoWithAcceptable returns an error instantly if the Breaker rejects the request.
// If a panic occurs in the request, the Breaker handles it as an error
// and causes the same panic again.
- // acceptable checks if it's a successful call, even if the err is not nil.
+ // acceptable checks if it's a successful call, even if the error is not nil.
DoWithAcceptable(req func() error, acceptable Acceptable) error
// DoWithFallback runs the given request if the Breaker accepts it.
@@ -59,7 +59,7 @@ type (
// DoWithFallbackAcceptable runs the fallback if the Breaker rejects the request.
// If a panic occurs in the request, the Breaker handles it as an error
// and causes the same panic again.
- // acceptable checks if it's a successful call, even if the err is not nil.
+ // acceptable checks if it's a successful call, even if the error is not nil.
DoWithFallbackAcceptable(req func() error, fallback func(err error) error, acceptable Acceptable) error
}
@@ -179,7 +179,7 @@ func (lt loggedThrottle) doReq(req func() error, fallback func(err error) error,
}
func (lt loggedThrottle) logError(err error) error {
- if err == ErrServiceUnavailable {
+ if errors.Is(err, ErrServiceUnavailable) {
// if circuit open, not possible to have empty error window
stat.Report(fmt.Sprintf(
"proc(%s/%d), callee: %s, breaker is open and requests dropped\nlast errors:\n%s",
diff --git a/core/breaker/breakers.go b/core/breaker/breakers.go
index 4adf189a6092..be55d55a2b2c 100644
--- a/core/breaker/breakers.go
+++ b/core/breaker/breakers.go
@@ -59,7 +59,7 @@ func GetBreaker(name string) Breaker {
// NoBreakerFor disables the circuit breaker for the given name.
func NoBreakerFor(name string) {
lock.Lock()
- breakers[name] = newNoOpBreaker()
+ breakers[name] = newNopBreaker()
lock.Unlock()
}
diff --git a/core/breaker/breakers_test.go b/core/breaker/breakers_test.go
index 74aa5b4c41c6..ad1e62fb2f0c 100644
--- a/core/breaker/breakers_test.go
+++ b/core/breaker/breakers_test.go
@@ -30,7 +30,7 @@ func TestBreakersDoWithAcceptable(t *testing.T) {
assert.Equal(t, errDummy, GetBreaker("anyone").DoWithAcceptable(func() error {
return errDummy
}, func(err error) bool {
- return err == nil || err == errDummy
+ return err == nil || errors.Is(err, errDummy)
}))
}
verify(t, func() bool {
@@ -45,12 +45,12 @@ func TestBreakersDoWithAcceptable(t *testing.T) {
}, func(err error) bool {
return err == nil
})
- assert.True(t, err == errDummy || err == ErrServiceUnavailable)
+ assert.True(t, errors.Is(err, errDummy) || errors.Is(err, ErrServiceUnavailable))
}
verify(t, func() bool {
- return ErrServiceUnavailable == Do("another", func() error {
+ return errors.Is(Do("another", func() error {
return nil
- })
+ }), ErrServiceUnavailable)
})
}
@@ -75,12 +75,12 @@ func TestBreakersFallback(t *testing.T) {
}, func(err error) error {
return nil
})
- assert.True(t, err == nil || err == errDummy)
+ assert.True(t, err == nil || errors.Is(err, errDummy))
}
verify(t, func() bool {
- return ErrServiceUnavailable == Do("fallback", func() error {
+ return errors.Is(Do("fallback", func() error {
return nil
- })
+ }), ErrServiceUnavailable)
})
}
@@ -94,12 +94,12 @@ func TestBreakersAcceptableFallback(t *testing.T) {
}, func(err error) bool {
return err == nil
})
- assert.True(t, err == nil || err == errDummy)
+ assert.True(t, err == nil || errors.Is(err, errDummy))
}
verify(t, func() bool {
- return ErrServiceUnavailable == Do("acceptablefallback", func() error {
+ return errors.Is(Do("acceptablefallback", func() error {
return nil
- })
+ }), ErrServiceUnavailable)
})
}
diff --git a/core/breaker/googlebreaker_test.go b/core/breaker/googlebreaker_test.go
index e525de5bb726..7a8c65b8ce61 100644
--- a/core/breaker/googlebreaker_test.go
+++ b/core/breaker/googlebreaker_test.go
@@ -95,7 +95,7 @@ func TestGoogleBreakerAcceptable(t *testing.T) {
assert.Equal(t, errAcceptable, b.doReq(func() error {
return errAcceptable
}, nil, func(err error) bool {
- return err == errAcceptable
+ return errors.Is(err, errAcceptable)
}))
}
@@ -105,7 +105,7 @@ func TestGoogleBreakerNotAcceptable(t *testing.T) {
assert.Equal(t, errAcceptable, b.doReq(func() error {
return errAcceptable
}, nil, func(err error) bool {
- return err != errAcceptable
+ return !errors.Is(err, errAcceptable)
}))
}
diff --git a/core/breaker/nopbreaker.go b/core/breaker/nopbreaker.go
index 2cf0f7169e7e..a1b2e7ccb95b 100644
--- a/core/breaker/nopbreaker.go
+++ b/core/breaker/nopbreaker.go
@@ -1,34 +1,34 @@
package breaker
-const noOpBreakerName = "nopBreaker"
+const nopBreakerName = "nopBreaker"
-type noOpBreaker struct{}
+type nopBreaker struct{}
-func newNoOpBreaker() Breaker {
- return noOpBreaker{}
+func newNopBreaker() Breaker {
+ return nopBreaker{}
}
-func (b noOpBreaker) Name() string {
- return noOpBreakerName
+func (b nopBreaker) Name() string {
+ return nopBreakerName
}
-func (b noOpBreaker) Allow() (Promise, error) {
+func (b nopBreaker) Allow() (Promise, error) {
return nopPromise{}, nil
}
-func (b noOpBreaker) Do(req func() error) error {
+func (b nopBreaker) Do(req func() error) error {
return req()
}
-func (b noOpBreaker) DoWithAcceptable(req func() error, _ Acceptable) error {
+func (b nopBreaker) DoWithAcceptable(req func() error, _ Acceptable) error {
return req()
}
-func (b noOpBreaker) DoWithFallback(req func() error, _ func(err error) error) error {
+func (b nopBreaker) DoWithFallback(req func() error, _ func(err error) error) error {
return req()
}
-func (b noOpBreaker) DoWithFallbackAcceptable(req func() error, _ func(err error) error,
+func (b nopBreaker) DoWithFallbackAcceptable(req func() error, _ func(err error) error,
_ Acceptable) error {
return req()
}
diff --git a/core/breaker/nopbreaker_test.go b/core/breaker/nopbreaker_test.go
index ecca1806bdcb..1756aa2a5dc7 100644
--- a/core/breaker/nopbreaker_test.go
+++ b/core/breaker/nopbreaker_test.go
@@ -8,8 +8,8 @@ import (
)
func TestNopBreaker(t *testing.T) {
- b := newNoOpBreaker()
- assert.Equal(t, noOpBreakerName, b.Name())
+ b := newNopBreaker()
+ assert.Equal(t, nopBreakerName, b.Name())
p, err := b.Allow()
assert.Nil(t, err)
p.Accept()
diff --git a/core/collection/ring.go b/core/collection/ring.go
index 8218d60dcb20..c7ad4fcba787 100644
--- a/core/collection/ring.go
+++ b/core/collection/ring.go
@@ -25,8 +25,14 @@ func (r *Ring) Add(v any) {
r.lock.Lock()
defer r.lock.Unlock()
- r.elements[r.index%len(r.elements)] = v
+ rlen := len(r.elements)
+ r.elements[r.index%rlen] = v
r.index++
+
+ // prevent ring index overflow
+ if r.index >= rlen<<1 {
+ r.index -= rlen
+ }
}
// Take takes all items from r.
@@ -36,16 +42,18 @@ func (r *Ring) Take() []any {
var size int
var start int
- if r.index > len(r.elements) {
- size = len(r.elements)
- start = r.index % len(r.elements)
+ rlen := len(r.elements)
+
+ if r.index > rlen {
+ size = rlen
+ start = r.index % rlen
} else {
size = r.index
}
elements := make([]any, size)
for i := 0; i < size; i++ {
- elements[i] = r.elements[(start+i)%len(r.elements)]
+ elements[i] = r.elements[(start+i)%rlen]
}
return elements
diff --git a/core/collection/safemap.go b/core/collection/safemap.go
index 6ab328a00ccc..13c994a0f98d 100644
--- a/core/collection/safemap.go
+++ b/core/collection/safemap.go
@@ -29,6 +29,8 @@ func NewSafeMap() *SafeMap {
// Del deletes the value with the given key from m.
func (m *SafeMap) Del(key any) {
m.lock.Lock()
+ defer m.lock.Unlock()
+
if _, ok := m.dirtyOld[key]; ok {
delete(m.dirtyOld, key)
m.deletionOld++
@@ -52,7 +54,6 @@ func (m *SafeMap) Del(key any) {
m.dirtyNew = make(map[any]any)
m.deletionNew = 0
}
- m.lock.Unlock()
}
// Get gets the value with the given key from m.
@@ -89,6 +90,8 @@ func (m *SafeMap) Range(f func(key, val any) bool) {
// Set sets the value into m with the given key.
func (m *SafeMap) Set(key, value any) {
m.lock.Lock()
+ defer m.lock.Unlock()
+
if m.deletionOld <= maxDeletion {
if _, ok := m.dirtyNew[key]; ok {
delete(m.dirtyNew, key)
@@ -102,7 +105,6 @@ func (m *SafeMap) Set(key, value any) {
}
m.dirtyNew[key] = value
}
- m.lock.Unlock()
}
// Size returns the size of m.
diff --git a/core/collection/safemap_test.go b/core/collection/safemap_test.go
index 26c734eeb893..dd54881dfc34 100644
--- a/core/collection/safemap_test.go
+++ b/core/collection/safemap_test.go
@@ -147,3 +147,65 @@ func TestSafeMap_Range(t *testing.T) {
assert.Equal(t, m.dirtyNew, newMap.dirtyNew)
assert.Equal(t, m.dirtyOld, newMap.dirtyOld)
}
+
+func TestSetManyTimes(t *testing.T) {
+ const iteration = maxDeletion * 2
+ m := NewSafeMap()
+ for i := 0; i < iteration; i++ {
+ m.Set(i, i)
+ if i%3 == 0 {
+ m.Del(i / 2)
+ }
+ }
+ var count int
+ m.Range(func(k, v any) bool {
+ count++
+ return count < maxDeletion/2
+ })
+ assert.Equal(t, maxDeletion/2, count)
+ for i := 0; i < iteration; i++ {
+ m.Set(i, i)
+ if i%3 == 0 {
+ m.Del(i / 2)
+ }
+ }
+ for i := 0; i < iteration; i++ {
+ m.Set(i, i)
+ if i%3 == 0 {
+ m.Del(i / 2)
+ }
+ }
+ for i := 0; i < iteration; i++ {
+ m.Set(i, i)
+ if i%3 == 0 {
+ m.Del(i / 2)
+ }
+ }
+
+ count = 0
+ m.Range(func(k, v any) bool {
+ count++
+ return count < maxDeletion
+ })
+ assert.Equal(t, maxDeletion, count)
+}
+
+func TestSetManyTimesNew(t *testing.T) {
+ m := NewSafeMap()
+ for i := 0; i < maxDeletion*3; i++ {
+ m.Set(i, i)
+ }
+ for i := 0; i < maxDeletion*2; i++ {
+ m.Del(i)
+ }
+ for i := 0; i < maxDeletion*3; i++ {
+ m.Set(i+maxDeletion*3, i+maxDeletion*3)
+ }
+ for i := 0; i < maxDeletion*2; i++ {
+ m.Del(i + maxDeletion*2)
+ }
+ for i := 0; i < maxDeletion-copyThreshold+1; i++ {
+ m.Del(i + maxDeletion*2)
+ }
+ assert.Equal(t, 0, len(m.dirtyNew))
+}
diff --git a/core/fx/retry.go b/core/fx/retry.go
index 4c0c03761f4d..e79c900224fc 100644
--- a/core/fx/retry.go
+++ b/core/fx/retry.go
@@ -2,7 +2,6 @@ package fx
import (
"context"
- "errors"
"time"
"github.com/zeromicro/go-zero/core/errorx"
@@ -10,8 +9,6 @@ import (
const defaultRetryTimes = 3
-var errTimeout = errors.New("retry timeout")
-
type (
// RetryOption defines the method to customize DoWithRetry.
RetryOption func(*retryOptions)
@@ -28,7 +25,7 @@ type (
// and performs modification operations, it is best to lock them,
// otherwise there may be data race issues
func DoWithRetry(fn func() error, opts ...RetryOption) error {
- return retry(func(errChan chan error, retryCount int) {
+ return retry(context.Background(), func(errChan chan error, retryCount int) {
errChan <- fn()
}, opts...)
}
@@ -40,12 +37,12 @@ func DoWithRetry(fn func() error, opts ...RetryOption) error {
// otherwise there may be data race issues
func DoWithRetryCtx(ctx context.Context, fn func(ctx context.Context, retryCount int) error,
opts ...RetryOption) error {
- return retry(func(errChan chan error, retryCount int) {
+ return retry(ctx, func(errChan chan error, retryCount int) {
errChan <- fn(ctx, retryCount)
}, opts...)
}
-func retry(fn func(errChan chan error, retryCount int), opts ...RetryOption) error {
+func retry(ctx context.Context, fn func(errChan chan error, retryCount int), opts ...RetryOption) error {
options := newRetryOptions()
for _, opt := range opts {
opt(options)
@@ -53,7 +50,6 @@ func retry(fn func(errChan chan error, retryCount int), opts ...RetryOption) err
var berr errorx.BatchError
var cancelFunc context.CancelFunc
- ctx := context.Background()
if options.timeout > 0 {
ctx, cancelFunc = context.WithTimeout(ctx, options.timeout)
defer cancelFunc()
@@ -71,14 +67,14 @@ func retry(fn func(errChan chan error, retryCount int), opts ...RetryOption) err
return nil
}
case <-ctx.Done():
- berr.Add(errTimeout)
+ berr.Add(ctx.Err())
return berr.Err()
}
if options.interval > 0 {
select {
case <-ctx.Done():
- berr.Add(errTimeout)
+ berr.Add(ctx.Err())
return berr.Err()
case <-time.After(options.interval):
}
diff --git a/core/fx/retry_test.go b/core/fx/retry_test.go
index d4569dc4ac19..045d782af594 100644
--- a/core/fx/retry_test.go
+++ b/core/fx/retry_test.go
@@ -98,19 +98,51 @@ func TestRetryWithInterval(t *testing.T) {
}
func TestRetryCtx(t *testing.T) {
- assert.NotNil(t, DoWithRetryCtx(context.Background(), func(ctx context.Context, retryCount int) error {
- if retryCount == 0 {
+ t.Run("with timeout", func(t *testing.T) {
+ assert.NotNil(t, DoWithRetryCtx(context.Background(), func(ctx context.Context, retryCount int) error {
+ if retryCount == 0 {
+ return errors.New("any")
+ }
+ time.Sleep(time.Millisecond * 150)
+ return nil
+ }, WithTimeout(time.Millisecond*250), WithInterval(time.Millisecond*150)))
+
+ assert.NotNil(t, DoWithRetryCtx(context.Background(), func(ctx context.Context, retryCount int) error {
+ if retryCount == 1 {
+ return nil
+ }
+ time.Sleep(time.Millisecond * 150)
+ return errors.New("any ")
+ }, WithTimeout(time.Millisecond*250), WithInterval(time.Millisecond*150)))
+ })
+
+ t.Run("with deadline exceeded", func(t *testing.T) {
+ ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(time.Millisecond*250))
+ defer cancel()
+
+ var times int
+ assert.Error(t, DoWithRetryCtx(ctx, func(ctx context.Context, retryCount int) error {
+ times++
+ time.Sleep(time.Millisecond * 150)
return errors.New("any")
- }
- time.Sleep(time.Millisecond * 150)
- return nil
- }, WithTimeout(time.Millisecond*250), WithInterval(time.Millisecond*150)))
+ }, WithInterval(time.Millisecond*150)))
+ assert.Equal(t, 1, times)
+ })
- assert.NotNil(t, DoWithRetryCtx(context.Background(), func(ctx context.Context, retryCount int) error {
- if retryCount == 1 {
- return nil
- }
- time.Sleep(time.Millisecond * 150)
- return errors.New("any ")
- }, WithTimeout(time.Millisecond*250), WithInterval(time.Millisecond*150)))
+ t.Run("with deadline not exceeded", func(t *testing.T) {
+ ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(time.Millisecond*250))
+ defer cancel()
+
+ var times int
+ assert.NoError(t, DoWithRetryCtx(ctx, func(ctx context.Context, retryCount int) error {
+ times++
+ if times == defaultRetryTimes {
+ return nil
+ }
+
+ time.Sleep(time.Millisecond * 50)
+ return errors.New("any")
+ }))
+ assert.Equal(t, defaultRetryTimes, times)
+ })
}
diff --git a/core/iox/nopcloser_test.go b/core/iox/nopcloser_test.go
new file mode 100644
index 000000000000..5dfd4d566e62
--- /dev/null
+++ b/core/iox/nopcloser_test.go
@@ -0,0 +1,12 @@
+package iox
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestNopCloser(t *testing.T) {
+ closer := NopCloser(nil)
+ assert.NoError(t, closer.Close())
+}
diff --git a/core/iox/read.go b/core/iox/read.go
index 530597fcdbd9..3ec024ec19f4 100644
--- a/core/iox/read.go
+++ b/core/iox/read.go
@@ -35,6 +35,16 @@ func KeepSpace() TextReadOption {
}
}
+// LimitDupReadCloser returns two io.ReadCloser that read from the first will be written to the second.
+// But the second io.ReadCloser is limited to up to n bytes.
+// The first returned reader needs to be read first, because the content
+// read from it will be written to the underlying buffer of the second reader.
+func LimitDupReadCloser(reader io.ReadCloser, n int64) (io.ReadCloser, io.ReadCloser) {
+ var buf bytes.Buffer
+ tee := LimitTeeReader(reader, &buf, n)
+ return io.NopCloser(tee), io.NopCloser(&buf)
+}
+
// ReadBytes reads exactly the bytes with the length of len(buf)
func ReadBytes(reader io.Reader, buf []byte) error {
var got int
diff --git a/core/iox/read_test.go b/core/iox/read_test.go
index 8ab2dd59275a..d2eb24353bf0 100644
--- a/core/iox/read_test.go
+++ b/core/iox/read_test.go
@@ -51,6 +51,11 @@ b`,
}
}
+func TestReadTextError(t *testing.T) {
+ _, err := ReadText("not-exist")
+ assert.NotNil(t, err)
+}
+
func TestReadTextLines(t *testing.T) {
text := `1
@@ -94,6 +99,11 @@ func TestReadTextLines(t *testing.T) {
}
}
+func TestReadTextLinesError(t *testing.T) {
+ _, err := ReadTextLines("not-exist")
+ assert.NotNil(t, err)
+}
+
func TestDupReadCloser(t *testing.T) {
input := "hello"
reader := io.NopCloser(bytes.NewBufferString(input))
@@ -108,6 +118,29 @@ func TestDupReadCloser(t *testing.T) {
verify(r2)
}
+func TestLimitDupReadCloser(t *testing.T) {
+ input := "hello world"
+ limitBytes := int64(4)
+ reader := io.NopCloser(bytes.NewBufferString(input))
+ r1, r2 := LimitDupReadCloser(reader, limitBytes)
+ verify := func(r io.Reader) {
+ output, err := io.ReadAll(r)
+ assert.Nil(t, err)
+ assert.Equal(t, input, string(output))
+ }
+ verifyLimit := func(r io.Reader, limit int64) {
+ output, err := io.ReadAll(r)
+ if limit < int64(len(input)) {
+ input = input[:limit]
+ }
+ assert.Nil(t, err)
+ assert.Equal(t, input, string(output))
+ }
+
+ verify(r1)
+ verifyLimit(r2, limitBytes)
+}
+
func TestReadBytes(t *testing.T) {
reader := io.NopCloser(bytes.NewBufferString("helloworld"))
buf := make([]byte, 5)
diff --git a/core/iox/tee.go b/core/iox/tee.go
new file mode 100644
index 000000000000..11c5221efaaa
--- /dev/null
+++ b/core/iox/tee.go
@@ -0,0 +1,35 @@
+package iox
+
+import "io"
+
+// LimitTeeReader returns a Reader that writes up to n bytes to w what it reads from r.
+// First n bytes reads from r performed through it are matched with
+// corresponding writes to w. There is no internal buffering -
+// the write must complete before the first n bytes read completes.
+// Any error encountered while writing is reported as a read error.
+func LimitTeeReader(r io.Reader, w io.Writer, n int64) io.Reader {
+ return &limitTeeReader{r, w, n}
+}
+
+type limitTeeReader struct {
+ r io.Reader
+ w io.Writer
+ n int64 // limit bytes remaining
+}
+
+func (t *limitTeeReader) Read(p []byte) (n int, err error) {
+ n, err = t.r.Read(p)
+ if n > 0 && t.n > 0 {
+ limit := int64(n)
+ if limit > t.n {
+ limit = t.n
+ }
+ if n, err := t.w.Write(p[:limit]); err != nil {
+ return n, err
+ }
+
+ t.n -= limit
+ }
+
+ return
+}
diff --git a/core/iox/tee_test.go b/core/iox/tee_test.go
new file mode 100644
index 000000000000..87f5267e1ad9
--- /dev/null
+++ b/core/iox/tee_test.go
@@ -0,0 +1,40 @@
+package iox
+
+import (
+ "bytes"
+ "io"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestLimitTeeReader(t *testing.T) {
+ limit := int64(4)
+ src := []byte("hello, world")
+ dst := make([]byte, len(src))
+ rb := bytes.NewBuffer(src)
+ wb := new(bytes.Buffer)
+ r := LimitTeeReader(rb, wb, limit)
+ if n, err := io.ReadFull(r, dst); err != nil || n != len(src) {
+ t.Fatalf("ReadFull(r, dst) = %d, %v; want %d, nil", n, err, len(src))
+ }
+ if !bytes.Equal(dst, src) {
+ t.Errorf("bytes read = %q want %q", dst, src)
+ }
+ if !bytes.Equal(wb.Bytes(), src[:limit]) {
+ t.Errorf("bytes written = %q want %q", wb.Bytes(), src)
+ }
+
+ n, err := r.Read(dst)
+ assert.Equal(t, 0, n)
+ assert.Equal(t, io.EOF, err)
+
+ rb = bytes.NewBuffer(src)
+ pr, pw := io.Pipe()
+ if assert.NoError(t, pr.Close()) {
+ r = LimitTeeReader(rb, pw, limit)
+ n, err := io.ReadFull(r, dst)
+ assert.Equal(t, 0, n)
+ assert.Equal(t, io.ErrClosedPipe, err)
+ }
+}
diff --git a/core/iox/textfile.go b/core/iox/textfile.go
index 8feced436102..89083cea684a 100644
--- a/core/iox/textfile.go
+++ b/core/iox/textfile.go
@@ -2,6 +2,7 @@ package iox
import (
"bytes"
+ "errors"
"io"
"os"
)
@@ -26,7 +27,7 @@ func CountLines(file string) (int, error) {
count += bytes.Count(buf[:c], lineSep)
switch {
- case err == io.EOF:
+ case errors.Is(err, io.EOF):
if noEol {
count++
}
diff --git a/core/iox/textfile_test.go b/core/iox/textfile_test.go
index 011d674b18a6..c58b3048140b 100644
--- a/core/iox/textfile_test.go
+++ b/core/iox/textfile_test.go
@@ -24,3 +24,8 @@ func TestCountLines(t *testing.T) {
assert.Nil(t, err)
assert.Equal(t, 4, lines)
}
+
+func TestCountLinesError(t *testing.T) {
+ _, err := CountLines("not-exist")
+ assert.NotNil(t, err)
+}
diff --git a/core/iox/textlinescanner_test.go b/core/iox/textlinescanner_test.go
index 621a36cca8ec..1559b8a2f4cb 100644
--- a/core/iox/textlinescanner_test.go
+++ b/core/iox/textlinescanner_test.go
@@ -3,6 +3,7 @@ package iox
import (
"strings"
"testing"
+ "testing/iotest"
"github.com/stretchr/testify/assert"
)
@@ -22,3 +23,10 @@ func TestScanner(t *testing.T) {
}
assert.EqualValues(t, []string{"1", "2", "3", "4"}, lines)
}
+
+func TestBadScanner(t *testing.T) {
+ scanner := NewTextLineScanner(iotest.ErrReader(iotest.ErrTimeout))
+ assert.False(t, scanner.Scan())
+ _, err := scanner.Line()
+ assert.ErrorIs(t, err, iotest.ErrTimeout)
+}
diff --git a/core/logx/readme.md b/core/logx/readme.md
index 1e3bdfb21fc4..1d303ea0bd5d 100644
--- a/core/logx/readme.md
+++ b/core/logx/readme.md
@@ -40,7 +40,7 @@ type LogConf struct {
- `Compress`: whether or not to compress log files, only works with `file` mode.
- `KeepDays`: how many days that the log files are kept, after the given days, the outdated files will be deleted automatically. It has no effect on `console` mode.
- `StackCooldownMillis`: how many milliseconds to rewrite stacktrace again. It’s used to avoid stacktrace flooding.
-- `MaxBackups`: represents how many backup log files will be kept. 0 means all files will be kept forever. Only take effect when `Rotation` is `size`. NOTE: the level of option `KeepDays` will be higher. Even thougth `MaxBackups` sets 0, log files will still be removed if the `KeepDays` limitation is reached.
+- `MaxBackups`: represents how many backup log files will be kept. 0 means all files will be kept forever. Only take effect when `Rotation` is `size`. NOTE: the level of option `KeepDays` will be higher. Even though `MaxBackups` sets 0, log files will still be removed if the `KeepDays` limitation is reached.
- `MaxSize`: represents how much space the writing log file takes up. 0 means no limit. The unit is `MB`. Only take effect when `Rotation` is `size`.
- `Rotation`: represents the type of log rotation rule. Default is `daily`.
- `daily` rotate the logs by day.
diff --git a/core/logx/richlogger.go b/core/logx/richlogger.go
index 0357e39747c5..185a96990ecc 100644
--- a/core/logx/richlogger.go
+++ b/core/logx/richlogger.go
@@ -41,67 +41,99 @@ type richLogger struct {
}
func (l *richLogger) Debug(v ...any) {
- l.debug(fmt.Sprint(v...))
+ if shallLog(DebugLevel) {
+ l.debug(fmt.Sprint(v...))
+ }
}
func (l *richLogger) Debugf(format string, v ...any) {
- l.debug(fmt.Sprintf(format, v...))
+ if shallLog(DebugLevel) {
+ l.debug(fmt.Sprintf(format, v...))
+ }
}
func (l *richLogger) Debugv(v any) {
- l.debug(v)
+ if shallLog(DebugLevel) {
+ l.debug(v)
+ }
}
func (l *richLogger) Debugw(msg string, fields ...LogField) {
- l.debug(msg, fields...)
+ if shallLog(DebugLevel) {
+ l.debug(msg, fields...)
+ }
}
func (l *richLogger) Error(v ...any) {
- l.err(fmt.Sprint(v...))
+ if shallLog(ErrorLevel) {
+ l.err(fmt.Sprint(v...))
+ }
}
func (l *richLogger) Errorf(format string, v ...any) {
- l.err(fmt.Sprintf(format, v...))
+ if shallLog(ErrorLevel) {
+ l.err(fmt.Sprintf(format, v...))
+ }
}
func (l *richLogger) Errorv(v any) {
- l.err(v)
+ if shallLog(ErrorLevel) {
+ l.err(v)
+ }
}
func (l *richLogger) Errorw(msg string, fields ...LogField) {
- l.err(msg, fields...)
+ if shallLog(ErrorLevel) {
+ l.err(msg, fields...)
+ }
}
func (l *richLogger) Info(v ...any) {
- l.info(fmt.Sprint(v...))
+ if shallLog(InfoLevel) {
+ l.info(fmt.Sprint(v...))
+ }
}
func (l *richLogger) Infof(format string, v ...any) {
- l.info(fmt.Sprintf(format, v...))
+ if shallLog(InfoLevel) {
+ l.info(fmt.Sprintf(format, v...))
+ }
}
func (l *richLogger) Infov(v any) {
- l.info(v)
+ if shallLog(InfoLevel) {
+ l.info(v)
+ }
}
func (l *richLogger) Infow(msg string, fields ...LogField) {
- l.info(msg, fields...)
+ if shallLog(InfoLevel) {
+ l.info(msg, fields...)
+ }
}
func (l *richLogger) Slow(v ...any) {
- l.slow(fmt.Sprint(v...))
+ if shallLog(ErrorLevel) {
+ l.slow(fmt.Sprint(v...))
+ }
}
func (l *richLogger) Slowf(format string, v ...any) {
- l.slow(fmt.Sprintf(format, v...))
+ if shallLog(ErrorLevel) {
+ l.slow(fmt.Sprintf(format, v...))
+ }
}
func (l *richLogger) Slowv(v any) {
- l.slow(v)
+ if shallLog(ErrorLevel) {
+ l.slow(v)
+ }
}
func (l *richLogger) Sloww(msg string, fields ...LogField) {
- l.slow(msg, fields...)
+ if shallLog(ErrorLevel) {
+ l.slow(msg, fields...)
+ }
}
func (l *richLogger) WithCallerSkip(skip int) Logger {
diff --git a/core/logx/rotatelogger.go b/core/logx/rotatelogger.go
index c8ef43a74dec..4b7f31e764fc 100644
--- a/core/logx/rotatelogger.go
+++ b/core/logx/rotatelogger.go
@@ -298,6 +298,7 @@ func (l *RotateLogger) initialize() error {
if l.fp, err = os.OpenFile(l.filename, os.O_APPEND|os.O_WRONLY, defaultFileMode); err != nil {
return err
}
+
l.currentSize = fileInfo.Size()
}
@@ -381,7 +382,15 @@ func (l *RotateLogger) startWorker() {
case event := <-l.channel:
l.write(event)
case <-l.done:
- return
+ // avoid losing logs before closing.
+ for {
+ select {
+ case event := <-l.channel:
+ l.write(event)
+ default:
+ return
+ }
+ }
}
}
}()
diff --git a/core/logx/rotatelogger_test.go b/core/logx/rotatelogger_test.go
index 68269f6e18a1..f370aa8cd384 100644
--- a/core/logx/rotatelogger_test.go
+++ b/core/logx/rotatelogger_test.go
@@ -206,6 +206,27 @@ func TestRotateLoggerClose(t *testing.T) {
_, err := logger.Write([]byte("foo"))
assert.ErrorIs(t, err, ErrLogFileClosed)
})
+
+ t.Run("close without losing logs", func(t *testing.T) {
+ text := "foo"
+ filename, err := fs.TempFilenameWithText(text)
+ assert.Nil(t, err)
+ if len(filename) > 0 {
+ defer os.Remove(filename)
+ }
+ logger, err := NewLogger(filename, new(DailyRotateRule), false)
+ assert.Nil(t, err)
+ msg := []byte("foo")
+ n := 100
+ for i := 0; i < n; i++ {
+ _, err = logger.Write(msg)
+ assert.Nil(t, err)
+ }
+ assert.Nil(t, logger.Close())
+ bs, err := os.ReadFile(filename)
+ assert.Nil(t, err)
+ assert.Equal(t, len(msg)*n+len(text), len(bs))
+ })
}
func TestRotateLoggerGetBackupFilename(t *testing.T) {
@@ -496,6 +517,21 @@ func TestGzipFile(t *testing.T) {
})
}
+func TestRotateLogger_WithExistingFile(t *testing.T) {
+ const body = "foo"
+ filename, err := fs.TempFilenameWithText(body)
+ assert.Nil(t, err)
+ if len(filename) > 0 {
+ defer os.Remove(filename)
+ }
+
+ rule := NewSizeLimitRotateRule(filename, "-", 1, 100, 3, false)
+ logger, err := NewLogger(filename, rule, false)
+ assert.Nil(t, err)
+ assert.Equal(t, int64(len(body)), logger.currentSize)
+ assert.Nil(t, logger.Close())
+}
+
func BenchmarkRotateLogger(b *testing.B) {
filename := "./test.log"
filename2 := "./test2.log"
diff --git a/core/logx/writer.go b/core/logx/writer.go
index 74d247e82249..ac19aa245e37 100644
--- a/core/logx/writer.go
+++ b/core/logx/writer.go
@@ -7,6 +7,7 @@ import (
"io"
"log"
"path"
+ "runtime/debug"
"sync"
"sync/atomic"
@@ -332,11 +333,13 @@ func wrapLevelWithColor(level string) string {
func writeJson(writer io.Writer, info any) {
if content, err := json.Marshal(info); err != nil {
- log.Println(err.Error())
+ log.Printf("err: %s\n\n%s", err.Error(), debug.Stack())
} else if writer == nil {
log.Println(string(content))
} else {
- writer.Write(append(content, '\n'))
+ if _, err := writer.Write(append(content, '\n')); err != nil {
+ log.Println(err.Error())
+ }
}
}
@@ -384,7 +387,7 @@ func writePlainValue(writer io.Writer, level string, val any, fields ...string)
buf.WriteString(level)
buf.WriteByte(plainEncodingSep)
if err := json.NewEncoder(&buf).Encode(val); err != nil {
- log.Println(err.Error())
+ log.Printf("err: %s\n\n%s", err.Error(), debug.Stack())
return
}
diff --git a/core/logx/writer_test.go b/core/logx/writer_test.go
index c88d0c7bda4d..0f810975f6bd 100644
--- a/core/logx/writer_test.go
+++ b/core/logx/writer_test.go
@@ -126,9 +126,23 @@ func TestWriteJson(t *testing.T) {
log.SetOutput(&buf)
writeJson(nil, "foo")
assert.Contains(t, buf.String(), "foo")
+
+ buf.Reset()
+ writeJson(hardToWriteWriter{}, "foo")
+ assert.Contains(t, buf.String(), "write error")
+
buf.Reset()
writeJson(nil, make(chan int))
assert.Contains(t, buf.String(), "unsupported type")
+
+ buf.Reset()
+ type C struct {
+ RC func()
+ }
+ writeJson(nil, C{
+ RC: func() {},
+ })
+ assert.Contains(t, buf.String(), "runtime/debug.Stack")
}
func TestWritePlainAny(t *testing.T) {
@@ -165,6 +179,14 @@ func TestWritePlainAny(t *testing.T) {
writePlainAny(hardToWriteWriter{}, levelFatal, "foo")
assert.Contains(t, buf.String(), "write error")
+ buf.Reset()
+ type C struct {
+ RC func()
+ }
+ writePlainAny(nil, levelError, C{
+ RC: func() {},
+ })
+ assert.Contains(t, buf.String(), "runtime/debug.Stack")
}
func TestLogWithLimitContentLength(t *testing.T) {
diff --git a/core/mapping/unmarshaler.go b/core/mapping/unmarshaler.go
index c0912e9d565b..15215693b62a 100644
--- a/core/mapping/unmarshaler.go
+++ b/core/mapping/unmarshaler.go
@@ -5,6 +5,7 @@ import (
"encoding/json"
"errors"
"fmt"
+ "math"
"reflect"
"strconv"
"strings"
@@ -18,9 +19,10 @@ import (
)
const (
- defaultKeyName = "key"
- delimiter = '.'
- ignoreKey = "-"
+ defaultKeyName = "key"
+ delimiter = '.'
+ ignoreKey = "-"
+ numberTypeString = "number"
)
var (
@@ -609,25 +611,23 @@ func (u *Unmarshaler) processFieldPrimitiveWithJSONNumber(fieldType reflect.Type
target := reflect.New(Deref(fieldType)).Elem()
switch typeKind {
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- iValue, err := v.Int64()
- if err != nil {
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
+ reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+ if err := setValueFromString(typeKind, target, v.String()); err != nil {
return err
}
-
- target.SetInt(iValue)
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
- iValue, err := v.Int64()
+ case reflect.Float32:
+ fValue, err := v.Float64()
if err != nil {
return err
}
- if iValue < 0 {
- return fmt.Errorf("unmarshal %q with bad value %q", fullName, v.String())
+ if fValue > math.MaxFloat32 {
+ return fmt.Errorf("parsing %q as float32: value out of range", v.String())
}
- target.SetUint(uint64(iValue))
- case reflect.Float32, reflect.Float64:
+ target.SetFloat(fValue)
+ case reflect.Float64:
fValue, err := v.Float64()
if err != nil {
return err
@@ -635,7 +635,7 @@ func (u *Unmarshaler) processFieldPrimitiveWithJSONNumber(fieldType reflect.Type
target.SetFloat(fValue)
default:
- return newTypeMismatchErrorWithHint(fullName, typeKind.String(), value.Type().String())
+ return newTypeMismatchErrorWithHint(fullName, typeKind.String(), numberTypeString)
}
SetValue(fieldType, value, target)
diff --git a/core/mapping/unmarshaler_test.go b/core/mapping/unmarshaler_test.go
index 2e0e423dfcc4..fd02fd6d2b0e 100644
--- a/core/mapping/unmarshaler_test.go
+++ b/core/mapping/unmarshaler_test.go
@@ -569,6 +569,468 @@ func TestUnmarshalIntWithString(t *testing.T) {
})
}
+func TestUnmarshalInt8WithOverflow(t *testing.T) {
+ t.Run("int8 from string", func(t *testing.T) {
+ type inner struct {
+ Value int8 `key:"int,string"`
+ }
+
+ m := map[string]any{
+ "int": "8589934592", // overflow
+ }
+
+ var in inner
+ assert.Error(t, UnmarshalKey(m, &in))
+ })
+
+ t.Run("int8 from json.Number", func(t *testing.T) {
+ type inner struct {
+ Value int8 `key:"int"`
+ }
+
+ m := map[string]any{
+ "int": json.Number("8589934592"), // overflow
+ }
+
+ var in inner
+ assert.Error(t, UnmarshalKey(m, &in))
+ })
+
+ t.Run("int8 from json.Number", func(t *testing.T) {
+ type inner struct {
+ Value int8 `key:"int"`
+ }
+
+ m := map[string]any{
+ "int": json.Number("-8589934592"), // overflow
+ }
+
+ var in inner
+ assert.Error(t, UnmarshalKey(m, &in))
+ })
+
+ t.Run("int8 from int64", func(t *testing.T) {
+ type inner struct {
+ Value int8 `key:"int"`
+ }
+
+ m := map[string]any{
+ "int": int64(1) << 36, // overflow
+ }
+
+ var in inner
+ assert.Error(t, UnmarshalKey(m, &in))
+ })
+}
+
+func TestUnmarshalInt16WithOverflow(t *testing.T) {
+ t.Run("int16 from string", func(t *testing.T) {
+ type inner struct {
+ Value int16 `key:"int,string"`
+ }
+
+ m := map[string]any{
+ "int": "8589934592", // overflow
+ }
+
+ var in inner
+ assert.Error(t, UnmarshalKey(m, &in))
+ })
+
+ t.Run("int16 from json.Number", func(t *testing.T) {
+ type inner struct {
+ Value int16 `key:"int"`
+ }
+
+ m := map[string]any{
+ "int": json.Number("8589934592"), // overflow
+ }
+
+ var in inner
+ assert.Error(t, UnmarshalKey(m, &in))
+ })
+
+ t.Run("int16 from json.Number", func(t *testing.T) {
+ type inner struct {
+ Value int16 `key:"int"`
+ }
+
+ m := map[string]any{
+ "int": json.Number("-8589934592"), // overflow
+ }
+
+ var in inner
+ assert.Error(t, UnmarshalKey(m, &in))
+ })
+
+ t.Run("int16 from int64", func(t *testing.T) {
+ type inner struct {
+ Value int16 `key:"int"`
+ }
+
+ m := map[string]any{
+ "int": int64(1) << 36, // overflow
+ }
+
+ var in inner
+ assert.Error(t, UnmarshalKey(m, &in))
+ })
+}
+
+func TestUnmarshalInt32WithOverflow(t *testing.T) {
+ t.Run("int32 from string", func(t *testing.T) {
+ type inner struct {
+ Value int32 `key:"int,string"`
+ }
+
+ m := map[string]any{
+ "int": "8589934592", // overflow
+ }
+
+ var in inner
+ assert.Error(t, UnmarshalKey(m, &in))
+ })
+
+ t.Run("int32 from json.Number", func(t *testing.T) {
+ type inner struct {
+ Value int32 `key:"int"`
+ }
+
+ m := map[string]any{
+ "int": json.Number("8589934592"), // overflow
+ }
+
+ var in inner
+ assert.Error(t, UnmarshalKey(m, &in))
+ })
+
+ t.Run("int32 from json.Number", func(t *testing.T) {
+ type inner struct {
+ Value int32 `key:"int"`
+ }
+
+ m := map[string]any{
+ "int": json.Number("-8589934592"), // overflow
+ }
+
+ var in inner
+ assert.Error(t, UnmarshalKey(m, &in))
+ })
+
+ t.Run("int32 from int64", func(t *testing.T) {
+ type inner struct {
+ Value int32 `key:"int"`
+ }
+
+ m := map[string]any{
+ "int": int64(1) << 36, // overflow
+ }
+
+ var in inner
+ assert.Error(t, UnmarshalKey(m, &in))
+ })
+}
+
+func TestUnmarshalInt64WithOverflow(t *testing.T) {
+ t.Run("int64 from string", func(t *testing.T) {
+ type inner struct {
+ Value int64 `key:"int,string"`
+ }
+
+ m := map[string]any{
+ "int": "18446744073709551616", // overflow, 1 << 64
+ }
+
+ var in inner
+ assert.Error(t, UnmarshalKey(m, &in))
+ })
+
+ t.Run("int64 from json.Number", func(t *testing.T) {
+ type inner struct {
+ Value int64 `key:"int,string"`
+ }
+
+ m := map[string]any{
+ "int": json.Number("18446744073709551616"), // overflow, 1 << 64
+ }
+
+ var in inner
+ assert.Error(t, UnmarshalKey(m, &in))
+ })
+}
+
+func TestUnmarshalUint8WithOverflow(t *testing.T) {
+ t.Run("uint8 from string", func(t *testing.T) {
+ type inner struct {
+ Value uint8 `key:"int,string"`
+ }
+
+ m := map[string]any{
+ "int": "8589934592", // overflow
+ }
+
+ var in inner
+ assert.Error(t, UnmarshalKey(m, &in))
+ })
+
+ t.Run("uint8 from json.Number", func(t *testing.T) {
+ type inner struct {
+ Value uint8 `key:"int"`
+ }
+
+ m := map[string]any{
+ "int": json.Number("8589934592"), // overflow
+ }
+
+ var in inner
+ assert.Error(t, UnmarshalKey(m, &in))
+ })
+
+ t.Run("uint8 from json.Number with negative", func(t *testing.T) {
+ type inner struct {
+ Value uint8 `key:"int"`
+ }
+
+ m := map[string]any{
+ "int": json.Number("-1"), // overflow
+ }
+
+ var in inner
+ assert.Error(t, UnmarshalKey(m, &in))
+ })
+
+ t.Run("uint8 from int64", func(t *testing.T) {
+ type inner struct {
+ Value uint8 `key:"int"`
+ }
+
+ m := map[string]any{
+ "int": int64(1) << 36, // overflow
+ }
+
+ var in inner
+ assert.Error(t, UnmarshalKey(m, &in))
+ })
+}
+
+func TestUnmarshalUint16WithOverflow(t *testing.T) {
+ t.Run("uint16 from string", func(t *testing.T) {
+ type inner struct {
+ Value uint16 `key:"int,string"`
+ }
+
+ m := map[string]any{
+ "int": "8589934592", // overflow
+ }
+
+ var in inner
+ assert.Error(t, UnmarshalKey(m, &in))
+ })
+
+ t.Run("uint16 from json.Number", func(t *testing.T) {
+ type inner struct {
+ Value uint16 `key:"int"`
+ }
+
+ m := map[string]any{
+ "int": json.Number("8589934592"), // overflow
+ }
+
+ var in inner
+ assert.Error(t, UnmarshalKey(m, &in))
+ })
+
+ t.Run("uint16 from json.Number with negative", func(t *testing.T) {
+ type inner struct {
+ Value uint16 `key:"int"`
+ }
+
+ m := map[string]any{
+ "int": json.Number("-1"), // overflow
+ }
+
+ var in inner
+ assert.Error(t, UnmarshalKey(m, &in))
+ })
+
+ t.Run("uint16 from int64", func(t *testing.T) {
+ type inner struct {
+ Value uint16 `key:"int"`
+ }
+
+ m := map[string]any{
+ "int": int64(1) << 36, // overflow
+ }
+
+ var in inner
+ assert.Error(t, UnmarshalKey(m, &in))
+ })
+}
+
+func TestUnmarshalUint32WithOverflow(t *testing.T) {
+ t.Run("uint32 from string", func(t *testing.T) {
+ type inner struct {
+ Value uint32 `key:"int,string"`
+ }
+
+ m := map[string]any{
+ "int": "8589934592", // overflow
+ }
+
+ var in inner
+ assert.Error(t, UnmarshalKey(m, &in))
+ })
+
+ t.Run("uint32 from json.Number", func(t *testing.T) {
+ type inner struct {
+ Value uint32 `key:"int"`
+ }
+
+ m := map[string]any{
+ "int": json.Number("8589934592"), // overflow
+ }
+
+ var in inner
+ assert.Error(t, UnmarshalKey(m, &in))
+ })
+
+ t.Run("uint32 from json.Number with negative", func(t *testing.T) {
+ type inner struct {
+ Value uint32 `key:"int"`
+ }
+
+ m := map[string]any{
+ "int": json.Number("-1"), // overflow
+ }
+
+ var in inner
+ assert.Error(t, UnmarshalKey(m, &in))
+ })
+
+ t.Run("uint32 from int64", func(t *testing.T) {
+ type inner struct {
+ Value uint32 `key:"int"`
+ }
+
+ m := map[string]any{
+ "int": int64(1) << 36, // overflow
+ }
+
+ var in inner
+ assert.Error(t, UnmarshalKey(m, &in))
+ })
+}
+
+func TestUnmarshalUint64WithOverflow(t *testing.T) {
+ t.Run("uint64 from string", func(t *testing.T) {
+ type inner struct {
+ Value uint64 `key:"int,string"`
+ }
+
+ m := map[string]any{
+ "int": "18446744073709551616", // overflow, 1 << 64
+ }
+
+ var in inner
+ assert.Error(t, UnmarshalKey(m, &in))
+ })
+
+ t.Run("uint64 from json.Number", func(t *testing.T) {
+ type inner struct {
+ Value uint64 `key:"int,string"`
+ }
+
+ m := map[string]any{
+ "int": json.Number("18446744073709551616"), // overflow, 1 << 64
+ }
+
+ var in inner
+ assert.Error(t, UnmarshalKey(m, &in))
+ })
+}
+
+func TestUnmarshalFloat32WithOverflow(t *testing.T) {
+ t.Run("float32 from string greater than float64", func(t *testing.T) {
+ type inner struct {
+ Value float32 `key:"float,string"`
+ }
+
+ m := map[string]any{
+ "float": "1.79769313486231570814527423731704356798070e+309", // overflow
+ }
+
+ var in inner
+ assert.Error(t, UnmarshalKey(m, &in))
+ })
+
+ t.Run("float32 from string greater than float32", func(t *testing.T) {
+ type inner struct {
+ Value float32 `key:"float,string"`
+ }
+
+ m := map[string]any{
+ "float": "1.79769313486231570814527423731704356798070e+300", // overflow
+ }
+
+ var in inner
+ assert.Error(t, UnmarshalKey(m, &in))
+ })
+
+ t.Run("float32 from json.Number greater than float64", func(t *testing.T) {
+ type inner struct {
+ Value float32 `key:"float"`
+ }
+
+ m := map[string]any{
+ "float": json.Number("1.79769313486231570814527423731704356798070e+309"), // overflow
+ }
+
+ var in inner
+ assert.Error(t, UnmarshalKey(m, &in))
+ })
+
+ t.Run("float32 from json.Number greater than float32", func(t *testing.T) {
+ type inner struct {
+ Value float32 `key:"float"`
+ }
+
+ m := map[string]any{
+ "float": json.Number("1.79769313486231570814527423731704356798070e+300"), // overflow
+ }
+
+ var in inner
+ assert.Error(t, UnmarshalKey(m, &in))
+ })
+}
+
+func TestUnmarshalFloat64WithOverflow(t *testing.T) {
+ t.Run("float64 from string greater than float64", func(t *testing.T) {
+ type inner struct {
+ Value float64 `key:"float,string"`
+ }
+
+ m := map[string]any{
+ "float": "1.79769313486231570814527423731704356798070e+309", // overflow
+ }
+
+ var in inner
+ assert.Error(t, UnmarshalKey(m, &in))
+ })
+
+ t.Run("float32 from json.Number greater than float64", func(t *testing.T) {
+ type inner struct {
+ Value float64 `key:"float"`
+ }
+
+ m := map[string]any{
+ "float": json.Number("1.79769313486231570814527423731704356798070e+309"), // overflow
+ }
+
+ var in inner
+ assert.Error(t, UnmarshalKey(m, &in))
+ })
+}
+
func TestUnmarshalBoolSliceRequired(t *testing.T) {
type inner struct {
Bools []bool `key:"bools"`
@@ -795,16 +1257,20 @@ func TestUnmarshalFloat(t *testing.T) {
type inner struct {
Float32 float32 `key:"float32"`
Float32Str float32 `key:"float32str,string"`
+ Float32Num float32 `key:"float32num"`
Float64 float64 `key:"float64"`
Float64Str float64 `key:"float64str,string"`
+ Float64Num float64 `key:"float64num"`
DefaultFloat float32 `key:"defaultfloat,default=5.5"`
Optional float32 `key:",optional"`
}
m := map[string]any{
"float32": float32(1.5),
"float32str": "2.5",
- "float64": float64(3.5),
+ "float32num": json.Number("2.6"),
+ "float64": 3.5,
"float64str": "4.5",
+ "float64num": json.Number("4.6"),
}
var in inner
@@ -812,8 +1278,10 @@ func TestUnmarshalFloat(t *testing.T) {
if ast.NoError(UnmarshalKey(m, &in)) {
ast.Equal(float32(1.5), in.Float32)
ast.Equal(float32(2.5), in.Float32Str)
+ ast.Equal(float32(2.6), in.Float32Num)
ast.Equal(3.5, in.Float64)
ast.Equal(4.5, in.Float64Str)
+ ast.Equal(4.6, in.Float64Num)
ast.Equal(float32(5.5), in.DefaultFloat)
}
}
@@ -5022,7 +5490,7 @@ func TestUnmarshalerProcessFieldPrimitiveWithJSONNumber(t *testing.T) {
err := m.processFieldPrimitiveWithJSONNumber(fieldType, value.Elem(), v,
&fieldOptionsWithContext{}, "field")
assert.Error(t, err)
- assert.Equal(t, `type mismatch for field "field", expect "string", actual "int"`, err.Error())
+ assert.Equal(t, `type mismatch for field "field", expect "string", actual "number"`, err.Error())
})
t.Run("right type", func(t *testing.T) {
@@ -5206,15 +5674,13 @@ func TestUnmarshalWithIgnoreFields(t *testing.T) {
assert.Equal(t, 0, bar1.IgnoreInt)
}
- var bar2 Bar1
+ var bar2 Bar2
if assert.NoError(t, unmarshaler.Unmarshal(map[string]any{
"Value": "foo",
"IgnoreString": "any",
"IgnoreInt": 2,
}, &bar2)) {
- assert.Empty(t, bar2.Value)
- assert.Empty(t, bar2.IgnoreString)
- assert.Equal(t, 0, bar2.IgnoreInt)
+ assert.Nil(t, bar2.Foo)
}
}
diff --git a/core/mapping/utils.go b/core/mapping/utils.go
index 3597c97ed182..67ea0ae3393e 100644
--- a/core/mapping/utils.go
+++ b/core/mapping/utils.go
@@ -30,6 +30,7 @@ const (
leftSquareBracket = '['
rightSquareBracket = ']'
segmentSeparator = ','
+ intSize = 32 << (^uint(0) >> 63) // 32 or 64
)
var (
@@ -100,27 +101,30 @@ func convertTypeFromString(kind reflect.Kind, str string) (any, error) {
default:
return false, errTypeMismatch
}
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- intValue, err := strconv.ParseInt(str, 10, 64)
- if err != nil {
- return 0, fmt.Errorf("the value %q cannot be parsed as int", str)
- }
-
- return intValue, nil
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
- uintValue, err := strconv.ParseUint(str, 10, 64)
- if err != nil {
- return 0, fmt.Errorf("the value %q cannot be parsed as uint", str)
- }
-
- return uintValue, nil
- case reflect.Float32, reflect.Float64:
- floatValue, err := strconv.ParseFloat(str, 64)
- if err != nil {
- return 0, fmt.Errorf("the value %q cannot be parsed as float", str)
- }
-
- return floatValue, nil
+ case reflect.Int:
+ return strconv.ParseInt(str, 10, intSize)
+ case reflect.Int8:
+ return strconv.ParseInt(str, 10, 8)
+ case reflect.Int16:
+ return strconv.ParseInt(str, 10, 16)
+ case reflect.Int32:
+ return strconv.ParseInt(str, 10, 32)
+ case reflect.Int64:
+ return strconv.ParseInt(str, 10, 64)
+ case reflect.Uint:
+ return strconv.ParseUint(str, 10, intSize)
+ case reflect.Uint8:
+ return strconv.ParseUint(str, 10, 8)
+ case reflect.Uint16:
+ return strconv.ParseUint(str, 10, 16)
+ case reflect.Uint32:
+ return strconv.ParseUint(str, 10, 32)
+ case reflect.Uint64:
+ return strconv.ParseUint(str, 10, 64)
+ case reflect.Float32:
+ return strconv.ParseFloat(str, 32)
+ case reflect.Float64:
+ return strconv.ParseFloat(str, 64)
case reflect.String:
return str, nil
default:
@@ -486,19 +490,22 @@ func setMatchedPrimitiveValue(kind reflect.Kind, value reflect.Value, v any) err
switch kind {
case reflect.Bool:
value.SetBool(v.(bool))
+ return nil
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
value.SetInt(v.(int64))
+ return nil
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
value.SetUint(v.(uint64))
+ return nil
case reflect.Float32, reflect.Float64:
value.SetFloat(v.(float64))
+ return nil
case reflect.String:
value.SetString(v.(string))
+ return nil
default:
return errUnsupportedType
}
-
- return nil
}
func setValueFromString(kind reflect.Kind, value reflect.Value, str string) error {
@@ -575,7 +582,8 @@ func usingDifferentKeys(key string, field reflect.StructField) bool {
return false
}
-func validateAndSetValue(kind reflect.Kind, value reflect.Value, str string, opts *fieldOptionsWithContext) error {
+func validateAndSetValue(kind reflect.Kind, value reflect.Value, str string,
+ opts *fieldOptionsWithContext) error {
if !value.CanSet() {
return errValueNotSettable
}
diff --git a/core/mapping/yamlunmarshaler_test.go b/core/mapping/yamlunmarshaler_test.go
index eef849ac8bd2..a9854b899dd9 100644
--- a/core/mapping/yamlunmarshaler_test.go
+++ b/core/mapping/yamlunmarshaler_test.go
@@ -1011,6 +1011,15 @@ func TestUnmarshalYamlMapRune(t *testing.T) {
assert.Equal(t, rune(3), v.Machine["node3"])
}
+func TestUnmarshalYamlStringOfInt(t *testing.T) {
+ text := `password: 123456`
+ var v struct {
+ Password string `json:"password"`
+ }
+ reader := strings.NewReader(text)
+ assert.Error(t, UnmarshalYamlReader(reader, &v))
+}
+
func TestUnmarshalYamlBadInput(t *testing.T) {
var v struct {
Any string
diff --git a/core/metric/counter.go b/core/metric/counter.go
index c95412f736e9..df6e6916eede 100644
--- a/core/metric/counter.go
+++ b/core/metric/counter.go
@@ -3,7 +3,6 @@ package metric
import (
prom "github.com/prometheus/client_golang/prometheus"
"github.com/zeromicro/go-zero/core/proc"
- "github.com/zeromicro/go-zero/core/prometheus"
)
type (
@@ -47,20 +46,16 @@ func NewCounterVec(cfg *CounterVecOpts) CounterVec {
return cv
}
-func (cv *promCounterVec) Inc(labels ...string) {
- if !prometheus.Enabled() {
- return
- }
-
- cv.counter.WithLabelValues(labels...).Inc()
-}
-
func (cv *promCounterVec) Add(v float64, labels ...string) {
- if !prometheus.Enabled() {
- return
- }
+ update(func() {
+ cv.counter.WithLabelValues(labels...).Add(v)
+ })
+}
- cv.counter.WithLabelValues(labels...).Add(v)
+func (cv *promCounterVec) Inc(labels ...string) {
+ update(func() {
+ cv.counter.WithLabelValues(labels...).Inc()
+ })
}
func (cv *promCounterVec) close() bool {
diff --git a/core/metric/gauge.go b/core/metric/gauge.go
index 52ff841de913..39555d000f6b 100644
--- a/core/metric/gauge.go
+++ b/core/metric/gauge.go
@@ -3,7 +3,6 @@ package metric
import (
prom "github.com/prometheus/client_golang/prometheus"
"github.com/zeromicro/go-zero/core/proc"
- "github.com/zeromicro/go-zero/core/prometheus"
)
type (
@@ -16,8 +15,12 @@ type (
Set(v float64, labels ...string)
// Inc increments labels.
Inc(labels ...string)
+ // Dec decrements labels.
+ Dec(labels ...string)
// Add adds v to labels.
Add(v float64, labels ...string)
+ // Sub subtracts v to labels.
+ Sub(v float64, labels ...string)
close() bool
}
@@ -32,13 +35,12 @@ func NewGaugeVec(cfg *GaugeVecOpts) GaugeVec {
return nil
}
- vec := prom.NewGaugeVec(
- prom.GaugeOpts{
- Namespace: cfg.Namespace,
- Subsystem: cfg.Subsystem,
- Name: cfg.Name,
- Help: cfg.Help,
- }, cfg.Labels)
+ vec := prom.NewGaugeVec(prom.GaugeOpts{
+ Namespace: cfg.Namespace,
+ Subsystem: cfg.Subsystem,
+ Name: cfg.Name,
+ Help: cfg.Help,
+ }, cfg.Labels)
prom.MustRegister(vec)
gv := &promGaugeVec{
gauge: vec,
@@ -50,28 +52,34 @@ func NewGaugeVec(cfg *GaugeVecOpts) GaugeVec {
return gv
}
-func (gv *promGaugeVec) Inc(labels ...string) {
- if !prometheus.Enabled() {
- return
- }
-
- gv.gauge.WithLabelValues(labels...).Inc()
+func (gv *promGaugeVec) Add(v float64, labels ...string) {
+ update(func() {
+ gv.gauge.WithLabelValues(labels...).Add(v)
+ })
}
-func (gv *promGaugeVec) Add(v float64, labels ...string) {
- if !prometheus.Enabled() {
- return
- }
+func (gv *promGaugeVec) Dec(labels ...string) {
+ update(func() {
+ gv.gauge.WithLabelValues(labels...).Dec()
+ })
+}
- gv.gauge.WithLabelValues(labels...).Add(v)
+func (gv *promGaugeVec) Inc(labels ...string) {
+ update(func() {
+ gv.gauge.WithLabelValues(labels...).Inc()
+ })
}
func (gv *promGaugeVec) Set(v float64, labels ...string) {
- if !prometheus.Enabled() {
- return
- }
+ update(func() {
+ gv.gauge.WithLabelValues(labels...).Set(v)
+ })
+}
- gv.gauge.WithLabelValues(labels...).Set(v)
+func (gv *promGaugeVec) Sub(v float64, labels ...string) {
+ update(func() {
+ gv.gauge.WithLabelValues(labels...).Sub(v)
+ })
}
func (gv *promGaugeVec) close() bool {
diff --git a/core/metric/gauge_test.go b/core/metric/gauge_test.go
index fb0702600ed5..1ebb2a3ff41e 100644
--- a/core/metric/gauge_test.go
+++ b/core/metric/gauge_test.go
@@ -40,6 +40,23 @@ func TestGaugeInc(t *testing.T) {
assert.Equal(t, float64(2), r)
}
+func TestGaugeDec(t *testing.T) {
+ startAgent()
+ gaugeVec := NewGaugeVec(&GaugeVecOpts{
+ Namespace: "rpc_client",
+ Subsystem: "requests",
+ Name: "duration_ms",
+ Help: "rpc server requests duration(ms).",
+ Labels: []string{"path"},
+ })
+ defer gaugeVec.close()
+ gv, _ := gaugeVec.(*promGaugeVec)
+ gv.Dec("/users")
+ gv.Dec("/users")
+ r := testutil.ToFloat64(gv.gauge)
+ assert.Equal(t, float64(-2), r)
+}
+
func TestGaugeAdd(t *testing.T) {
startAgent()
gaugeVec := NewGaugeVec(&GaugeVecOpts{
@@ -57,6 +74,23 @@ func TestGaugeAdd(t *testing.T) {
assert.Equal(t, float64(20), r)
}
+func TestGaugeSub(t *testing.T) {
+ startAgent()
+ gaugeVec := NewGaugeVec(&GaugeVecOpts{
+ Namespace: "rpc_client",
+ Subsystem: "request",
+ Name: "duration_ms",
+ Help: "rpc server requests duration(ms).",
+ Labels: []string{"path"},
+ })
+ defer gaugeVec.close()
+ gv, _ := gaugeVec.(*promGaugeVec)
+ gv.Sub(-100, "/classroom")
+ gv.Sub(30, "/classroom")
+ r := testutil.ToFloat64(gv.gauge)
+ assert.Equal(t, float64(70), r)
+}
+
func TestGaugeSet(t *testing.T) {
startAgent()
gaugeVec := NewGaugeVec(&GaugeVecOpts{
diff --git a/core/metric/histogram.go b/core/metric/histogram.go
index 4f0a1058bdb5..a40c536576a5 100644
--- a/core/metric/histogram.go
+++ b/core/metric/histogram.go
@@ -3,24 +3,26 @@ package metric
import (
prom "github.com/prometheus/client_golang/prometheus"
"github.com/zeromicro/go-zero/core/proc"
- "github.com/zeromicro/go-zero/core/prometheus"
)
type (
// A HistogramVecOpts is a histogram vector options.
HistogramVecOpts struct {
- Namespace string
- Subsystem string
- Name string
- Help string
- Labels []string
- Buckets []float64
+ Namespace string
+ Subsystem string
+ Name string
+ Help string
+ Labels []string
+ Buckets []float64
+ ConstLabels map[string]string
}
// A HistogramVec interface represents a histogram vector.
HistogramVec interface {
// Observe adds observation v to labels.
Observe(v int64, labels ...string)
+ // ObserveFloat allow to observe float64 values.
+ ObserveFloat(v float64, labels ...string)
close() bool
}
@@ -36,11 +38,12 @@ func NewHistogramVec(cfg *HistogramVecOpts) HistogramVec {
}
vec := prom.NewHistogramVec(prom.HistogramOpts{
- Namespace: cfg.Namespace,
- Subsystem: cfg.Subsystem,
- Name: cfg.Name,
- Help: cfg.Help,
- Buckets: cfg.Buckets,
+ Namespace: cfg.Namespace,
+ Subsystem: cfg.Subsystem,
+ Name: cfg.Name,
+ Help: cfg.Help,
+ Buckets: cfg.Buckets,
+ ConstLabels: cfg.ConstLabels,
}, cfg.Labels)
prom.MustRegister(vec)
hv := &promHistogramVec{
@@ -54,11 +57,15 @@ func NewHistogramVec(cfg *HistogramVecOpts) HistogramVec {
}
func (hv *promHistogramVec) Observe(v int64, labels ...string) {
- if !prometheus.Enabled() {
- return
- }
+ update(func() {
+ hv.histogram.WithLabelValues(labels...).Observe(float64(v))
+ })
+}
- hv.histogram.WithLabelValues(labels...).Observe(float64(v))
+func (hv *promHistogramVec) ObserveFloat(v float64, labels ...string) {
+ update(func() {
+ hv.histogram.WithLabelValues(labels...).Observe(v)
+ })
}
func (hv *promHistogramVec) close() bool {
diff --git a/core/metric/histogram_test.go b/core/metric/histogram_test.go
index 4874617b12af..b4ba72759636 100644
--- a/core/metric/histogram_test.go
+++ b/core/metric/histogram_test.go
@@ -14,7 +14,7 @@ func TestNewHistogramVec(t *testing.T) {
Help: "rpc server requests duration(ms).",
Buckets: []float64{1, 2, 3},
})
- defer histogramVec.close()
+ defer histogramVec.(*promHistogramVec).close()
histogramVecNil := NewHistogramVec(nil)
assert.NotNil(t, histogramVec)
assert.Nil(t, histogramVecNil)
@@ -28,9 +28,10 @@ func TestHistogramObserve(t *testing.T) {
Buckets: []float64{1, 2, 3},
Labels: []string{"method"},
})
- defer histogramVec.close()
+ defer histogramVec.(*promHistogramVec).close()
hv, _ := histogramVec.(*promHistogramVec)
hv.Observe(2, "/Users")
+ hv.ObserveFloat(1.1, "/Users")
metadata := `
# HELP counts rpc server requests duration(ms).
@@ -38,11 +39,11 @@ func TestHistogramObserve(t *testing.T) {
`
val := `
counts_bucket{method="/Users",le="1"} 0
- counts_bucket{method="/Users",le="2"} 1
- counts_bucket{method="/Users",le="3"} 1
- counts_bucket{method="/Users",le="+Inf"} 1
- counts_sum{method="/Users"} 2
- counts_count{method="/Users"} 1
+ counts_bucket{method="/Users",le="2"} 2
+ counts_bucket{method="/Users",le="3"} 2
+ counts_bucket{method="/Users",le="+Inf"} 2
+ counts_sum{method="/Users"} 3.1
+ counts_count{method="/Users"} 2
`
err := testutil.CollectAndCompare(hv.histogram, strings.NewReader(metadata+val))
diff --git a/core/metric/metric.go b/core/metric/metric.go
index f36e0f6727cf..27ea7ddd9b73 100644
--- a/core/metric/metric.go
+++ b/core/metric/metric.go
@@ -1,5 +1,7 @@
package metric
+import "github.com/zeromicro/go-zero/core/prometheus"
+
// A VectorOpts is a general configuration.
type VectorOpts struct {
Namespace string
@@ -8,3 +10,11 @@ type VectorOpts struct {
Help string
Labels []string
}
+
+func update(fn func()) {
+ if !prometheus.Enabled() {
+ return
+ }
+
+ fn()
+}
diff --git a/core/metric/summary.go b/core/metric/summary.go
index ecab0cbece81..e39cbb958d21 100644
--- a/core/metric/summary.go
+++ b/core/metric/summary.go
@@ -3,7 +3,6 @@ package metric
import (
prom "github.com/prometheus/client_golang/prometheus"
"github.com/zeromicro/go-zero/core/proc"
- "github.com/zeromicro/go-zero/core/prometheus"
)
type (
@@ -53,11 +52,9 @@ func NewSummaryVec(cfg *SummaryVecOpts) SummaryVec {
}
func (sv *promSummaryVec) Observe(v float64, labels ...string) {
- if !prometheus.Enabled() {
- return
- }
-
- sv.summary.WithLabelValues(labels...).Observe(v)
+ update(func() {
+ sv.summary.WithLabelValues(labels...).Observe(v)
+ })
}
func (sv *promSummaryVec) close() bool {
diff --git a/core/proc/shutdown.go b/core/proc/shutdown.go
index ece547d57b6f..763742a298df 100644
--- a/core/proc/shutdown.go
+++ b/core/proc/shutdown.go
@@ -52,10 +52,10 @@ func WrapUp() {
wrapUpListeners.notifyListeners()
}
-func gracefulStop(signals chan os.Signal) {
+func gracefulStop(signals chan os.Signal, sig syscall.Signal) {
signal.Stop(signals)
- logx.Info("Got signal SIGTERM, shutting down...")
+ logx.Infof("Got signal %d, shutting down...", sig)
go wrapUpListeners.notifyListeners()
time.Sleep(wrapUpTime)
@@ -63,7 +63,7 @@ func gracefulStop(signals chan os.Signal) {
time.Sleep(delayTimeBeforeForceQuit - wrapUpTime)
logx.Infof("Still alive after %v, going to force kill the process...", delayTimeBeforeForceQuit)
- syscall.Kill(syscall.Getpid(), syscall.SIGTERM)
+ _ = syscall.Kill(syscall.Getpid(), sig)
}
type listenerManager struct {
diff --git a/core/proc/signals.go b/core/proc/signals.go
index 2f9af2d13412..bbc41ce5fa79 100644
--- a/core/proc/signals.go
+++ b/core/proc/signals.go
@@ -6,21 +6,23 @@ import (
"os"
"os/signal"
"syscall"
+ "time"
"github.com/zeromicro/go-zero/core/logx"
)
-const timeFormat = "0102150405"
+const (
+ profileDuration = time.Minute
+ timeFormat = "0102150405"
+)
var done = make(chan struct{})
func init() {
go func() {
- var profiler Stopper
-
// https://golang.org/pkg/os/signal/#Notify
signals := make(chan os.Signal, 1)
- signal.Notify(signals, syscall.SIGUSR1, syscall.SIGUSR2, syscall.SIGTERM)
+ signal.Notify(signals, syscall.SIGUSR1, syscall.SIGUSR2, syscall.SIGTERM, syscall.SIGINT)
for {
v := <-signals
@@ -28,21 +30,17 @@ func init() {
case syscall.SIGUSR1:
dumpGoroutines(fileCreator{})
case syscall.SIGUSR2:
- if profiler == nil {
- profiler = StartProfile()
- } else {
+ profiler := StartProfile()
+ go func() {
+ <-time.After(profileDuration)
profiler.Stop()
- profiler = nil
- }
+ }()
case syscall.SIGTERM:
- select {
- case <-done:
- // already closed
- default:
- close(done)
- }
-
- gracefulStop(signals)
+ stopOnSignal()
+ gracefulStop(signals, syscall.SIGTERM)
+ case syscall.SIGINT:
+ stopOnSignal()
+ gracefulStop(signals, syscall.SIGINT)
default:
logx.Error("Got unregistered signal:", v)
}
@@ -54,3 +52,12 @@ func init() {
func Done() <-chan struct{} {
return done
}
+
+func stopOnSignal() {
+ select {
+ case <-done:
+ // already closed
+ default:
+ close(done)
+ }
+}
diff --git a/core/search/tree.go b/core/search/tree.go
index 960f3f3ffdbf..c386660ce6b8 100644
--- a/core/search/tree.go
+++ b/core/search/tree.go
@@ -69,10 +69,10 @@ func (t *Tree) Add(route string, item any) error {
}
err := add(t.root, route[1:], item)
- switch err {
- case errDupItem:
+ switch {
+ case errors.Is(err, errDupItem):
return duplicatedItem(route)
- case errDupSlash:
+ case errors.Is(err, errDupSlash):
return duplicatedSlash(route)
default:
return err
diff --git a/core/service/serviceconf.go b/core/service/serviceconf.go
index 04d9283efff0..a4999ab8b075 100644
--- a/core/service/serviceconf.go
+++ b/core/service/serviceconf.go
@@ -23,17 +23,22 @@ const (
ProMode = "pro"
)
-// A ServiceConf is a service config.
-type ServiceConf struct {
- Name string
- Log logx.LogConf
- Mode string `json:",default=pro,options=dev|test|rt|pre|pro"`
- MetricsUrl string `json:",optional"`
- // Deprecated: please use DevServer
- Prometheus prometheus.Config `json:",optional"`
- Telemetry trace.Config `json:",optional"`
- DevServer devserver.Config `json:",optional"`
-}
+type (
+ // DevServerConfig is type alias for devserver.Config
+ DevServerConfig = devserver.Config
+
+ // A ServiceConf is a service config.
+ ServiceConf struct {
+ Name string
+ Log logx.LogConf
+ Mode string `json:",default=pro,options=dev|test|rt|pre|pro"`
+ MetricsUrl string `json:",optional"`
+ // Deprecated: please use DevServer
+ Prometheus prometheus.Config `json:",optional"`
+ Telemetry trace.Config `json:",optional"`
+ DevServer DevServerConfig `json:",optional"`
+ }
+)
// MustSetUp sets up the service, exits on error.
func (sc ServiceConf) MustSetUp() {
diff --git a/core/service/serviceconf_test.go b/core/service/serviceconf_test.go
index badf249ffb17..5e37421de8de 100644
--- a/core/service/serviceconf_test.go
+++ b/core/service/serviceconf_test.go
@@ -5,6 +5,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/zeromicro/go-zero/core/logx"
+ "github.com/zeromicro/go-zero/internal/devserver"
)
func TestServiceConf(t *testing.T) {
@@ -14,6 +15,10 @@ func TestServiceConf(t *testing.T) {
Mode: "console",
},
Mode: "dev",
+ DevServer: devserver.Config{
+ Port: 6470,
+ HealthPath: "/healthz",
+ },
}
c.MustSetUp()
}
diff --git a/core/stores/builder/builder.go b/core/stores/builder/builder.go
index feee68742136..a797de2381d9 100644
--- a/core/stores/builder/builder.go
+++ b/core/stores/builder/builder.go
@@ -9,7 +9,7 @@ import (
const dbTag = "db"
// RawFieldNames converts golang struct field into slice string.
-func RawFieldNames(in any, postgresSql ...bool) []string {
+func RawFieldNames(in any, postgreSql ...bool) []string {
out := make([]string, 0)
v := reflect.ValueOf(in)
if v.Kind() == reflect.Ptr {
@@ -17,8 +17,8 @@ func RawFieldNames(in any, postgresSql ...bool) []string {
}
var pg bool
- if len(postgresSql) > 0 {
- pg = postgresSql[0]
+ if len(postgreSql) > 0 {
+ pg = postgreSql[0]
}
// we only accept structs
diff --git a/core/stores/cache/cachenode.go b/core/stores/cache/cachenode.go
index 3c0ccc428064..312e0196f661 100644
--- a/core/stores/cache/cachenode.go
+++ b/core/stores/cache/cachenode.go
@@ -96,7 +96,7 @@ func (c cacheNode) Get(key string, val any) error {
// GetCtx gets the cache with key and fills into v.
func (c cacheNode) GetCtx(ctx context.Context, key string, val any) error {
err := c.doGetCache(ctx, key, val)
- if err == errPlaceholder {
+ if errors.Is(err, errPlaceholder) {
return c.errNotFound
}
@@ -210,16 +210,16 @@ func (c cacheNode) doTake(ctx context.Context, v any, key string,
logger := logx.WithContext(ctx)
val, fresh, err := c.barrier.DoEx(key, func() (any, error) {
if err := c.doGetCache(ctx, key, v); err != nil {
- if err == errPlaceholder {
+ if errors.Is(err, errPlaceholder) {
return nil, c.errNotFound
- } else if err != c.errNotFound {
+ } else if !errors.Is(err, c.errNotFound) {
// why we just return the error instead of query from db,
// because we don't allow the disaster pass to the dbs.
// fail fast, in case we bring down the dbs.
return nil, err
}
- if err = query(v); err == c.errNotFound {
+ if err = query(v); errors.Is(err, c.errNotFound) {
if err = c.setCacheWithNotFound(ctx, key); err != nil {
logger.Error(err)
}
diff --git a/core/stores/mon/bulkinserter_test.go b/core/stores/mon/bulkinserter_test.go
index ebd0ec4a7467..40f14da7a16b 100644
--- a/core/stores/mon/bulkinserter_test.go
+++ b/core/stores/mon/bulkinserter_test.go
@@ -11,8 +11,6 @@ import (
func TestBulkInserter(t *testing.T) {
mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock))
- defer mt.Close()
-
mt.Run("test", func(mt *mtest.T) {
mt.AddMockResponses(mtest.CreateSuccessResponse(bson.D{{Key: "ok", Value: 1}}...))
bulk, err := NewBulkInserter(createModel(mt).Collection)
diff --git a/core/stores/mon/clientmanager_test.go b/core/stores/mon/clientmanager_test.go
index bc6b70f8c637..9c3eae5c37bc 100644
--- a/core/stores/mon/clientmanager_test.go
+++ b/core/stores/mon/clientmanager_test.go
@@ -9,8 +9,6 @@ import (
func TestClientManger_getClient(t *testing.T) {
mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock))
- defer mt.Close()
-
mt.Run("test", func(mt *mtest.T) {
Inject(mtest.ClusterURI(), mt.Client)
cli, err := getClient(mtest.ClusterURI())
diff --git a/core/stores/mon/collection.go b/core/stores/mon/collection.go
index 1c445939410c..a909bb0297f6 100644
--- a/core/stores/mon/collection.go
+++ b/core/stores/mon/collection.go
@@ -2,11 +2,10 @@ package mon
import (
"context"
- "encoding/json"
+ "errors"
"time"
"github.com/zeromicro/go-zero/core/breaker"
- "github.com/zeromicro/go-zero/core/logx"
"github.com/zeromicro/go-zero/core/timex"
"go.mongodb.org/mongo-driver/mongo"
mopt "go.mongodb.org/mongo-driver/mongo/options"
@@ -502,45 +501,11 @@ func (c *decoratedCollection) UpdateOne(ctx context.Context, filter, update any,
func (c *decoratedCollection) logDuration(ctx context.Context, method string,
startTime time.Duration, err error, docs ...any) {
- duration := timex.Since(startTime)
- logger := logx.WithContext(ctx).WithDuration(duration)
-
- content, jerr := json.Marshal(docs)
- // jerr should not be non-nil, but we don't care much on this,
- // if non-nil, we just log without docs.
- if jerr != nil {
- if err != nil {
- if duration > slowThreshold.Load() {
- logger.Slowf("[MONGO] mongo(%s) - slowcall - %s - fail(%s)", c.name, method, err.Error())
- } else {
- logger.Infof("mongo(%s) - %s - fail(%s)", c.name, method, err.Error())
- }
- } else {
- if duration > slowThreshold.Load() {
- logger.Slowf("[MONGO] mongo(%s) - slowcall - %s - ok", c.name, method)
- } else {
- logger.Infof("mongo(%s) - %s - ok", c.name, method)
- }
- }
- } else if err != nil {
- if duration > slowThreshold.Load() {
- logger.Slowf("[MONGO] mongo(%s) - slowcall - %s - fail(%s) - %s",
- c.name, method, err.Error(), string(content))
- } else {
- logger.Infof("mongo(%s) - %s - fail(%s) - %s",
- c.name, method, err.Error(), string(content))
- }
- } else {
- if duration > slowThreshold.Load() {
- logger.Slowf("[MONGO] mongo(%s) - slowcall - %s - ok - %s",
- c.name, method, string(content))
- } else {
- logger.Infof("mongo(%s) - %s - ok - %s", c.name, method, string(content))
- }
- }
+ logDurationWithDocs(ctx, c.name, method, startTime, err, docs...)
}
-func (c *decoratedCollection) logDurationSimple(ctx context.Context, method string, startTime time.Duration, err error) {
+func (c *decoratedCollection) logDurationSimple(ctx context.Context, method string,
+ startTime time.Duration, err error) {
logDuration(ctx, c.name, method, startTime, err)
}
@@ -562,11 +527,19 @@ func (p keepablePromise) keep(err error) error {
}
func acceptable(err error) bool {
- return err == nil || err == mongo.ErrNoDocuments || err == mongo.ErrNilValue ||
- err == mongo.ErrNilDocument || err == mongo.ErrNilCursor || err == mongo.ErrEmptySlice ||
+ return err == nil ||
+ errors.Is(err, mongo.ErrNoDocuments) ||
+ errors.Is(err, mongo.ErrNilValue) ||
+ errors.Is(err, mongo.ErrNilDocument) ||
+ errors.Is(err, mongo.ErrNilCursor) ||
+ errors.Is(err, mongo.ErrEmptySlice) ||
// session errors
- err == session.ErrSessionEnded || err == session.ErrNoTransactStarted ||
- err == session.ErrTransactInProgress || err == session.ErrAbortAfterCommit ||
- err == session.ErrAbortTwice || err == session.ErrCommitAfterAbort ||
- err == session.ErrUnackWCUnsupported || err == session.ErrSnapshotTransaction
+ errors.Is(err, session.ErrSessionEnded) ||
+ errors.Is(err, session.ErrNoTransactStarted) ||
+ errors.Is(err, session.ErrTransactInProgress) ||
+ errors.Is(err, session.ErrAbortAfterCommit) ||
+ errors.Is(err, session.ErrAbortTwice) ||
+ errors.Is(err, session.ErrCommitAfterAbort) ||
+ errors.Is(err, session.ErrUnackWCUnsupported) ||
+ errors.Is(err, session.ErrSnapshotTransaction)
}
diff --git a/core/stores/mon/collection_test.go b/core/stores/mon/collection_test.go
index 964ebb2331c6..ac65bbd9e7eb 100644
--- a/core/stores/mon/collection_test.go
+++ b/core/stores/mon/collection_test.go
@@ -68,7 +68,6 @@ func TestKeepPromise_keep(t *testing.T) {
func TestNewCollection(t *testing.T) {
mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock))
- defer mt.Close()
mt.Run("test", func(mt *mtest.T) {
coll := mt.Coll
assert.NotNil(t, coll)
@@ -79,7 +78,6 @@ func TestNewCollection(t *testing.T) {
func TestCollection_Aggregate(t *testing.T) {
mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock))
- defer mt.Close()
mt.Run("test", func(mt *mtest.T) {
coll := mt.Coll
assert.NotNil(t, coll)
@@ -96,8 +94,6 @@ func TestCollection_Aggregate(t *testing.T) {
func TestCollection_BulkWrite(t *testing.T) {
mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock))
- defer mt.Close()
-
mt.Run("test", func(mt *mtest.T) {
c := decoratedCollection{
Collection: mt.Coll,
@@ -119,8 +115,6 @@ func TestCollection_BulkWrite(t *testing.T) {
func TestCollection_CountDocuments(t *testing.T) {
mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock))
- defer mt.Close()
-
mt.Run("test", func(mt *mtest.T) {
c := decoratedCollection{
Collection: mt.Coll,
@@ -145,8 +139,6 @@ func TestCollection_CountDocuments(t *testing.T) {
func TestDecoratedCollection_DeleteMany(t *testing.T) {
mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock))
- defer mt.Close()
-
mt.Run("test", func(mt *mtest.T) {
c := decoratedCollection{
Collection: mt.Coll,
@@ -165,8 +157,6 @@ func TestDecoratedCollection_DeleteMany(t *testing.T) {
func TestCollection_Distinct(t *testing.T) {
mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock))
- defer mt.Close()
-
mt.Run("test", func(mt *mtest.T) {
c := decoratedCollection{
Collection: mt.Coll,
@@ -185,8 +175,6 @@ func TestCollection_Distinct(t *testing.T) {
func TestCollection_EstimatedDocumentCount(t *testing.T) {
mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock))
- defer mt.Close()
-
mt.Run("test", func(mt *mtest.T) {
c := decoratedCollection{
Collection: mt.Coll,
@@ -205,8 +193,6 @@ func TestCollection_EstimatedDocumentCount(t *testing.T) {
func TestCollection_Find(t *testing.T) {
mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock))
- defer mt.Close()
-
mt.Run("test", func(mt *mtest.T) {
c := decoratedCollection{
Collection: mt.Coll,
@@ -253,8 +239,6 @@ func TestCollection_Find(t *testing.T) {
func TestCollection_FindOne(t *testing.T) {
mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock))
- defer mt.Close()
-
mt.Run("test", func(mt *mtest.T) {
c := decoratedCollection{
Collection: mt.Coll,
@@ -297,8 +281,6 @@ func TestCollection_FindOne(t *testing.T) {
func TestCollection_FindOneAndDelete(t *testing.T) {
mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock))
- defer mt.Close()
-
mt.Run("test", func(mt *mtest.T) {
c := decoratedCollection{
Collection: mt.Coll,
@@ -328,8 +310,6 @@ func TestCollection_FindOneAndDelete(t *testing.T) {
func TestCollection_FindOneAndReplace(t *testing.T) {
mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock))
- defer mt.Close()
-
mt.Run("test", func(mt *mtest.T) {
c := decoratedCollection{
Collection: mt.Coll,
@@ -360,8 +340,6 @@ func TestCollection_FindOneAndReplace(t *testing.T) {
func TestCollection_FindOneAndUpdate(t *testing.T) {
mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock))
- defer mt.Close()
-
mt.Run("test", func(mt *mtest.T) {
c := decoratedCollection{
Collection: mt.Coll,
@@ -393,8 +371,6 @@ func TestCollection_FindOneAndUpdate(t *testing.T) {
func TestCollection_InsertOne(t *testing.T) {
mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock))
- defer mt.Close()
-
mt.Run("test", func(mt *mtest.T) {
c := decoratedCollection{
Collection: mt.Coll,
@@ -413,8 +389,6 @@ func TestCollection_InsertOne(t *testing.T) {
func TestCollection_InsertMany(t *testing.T) {
mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock))
- defer mt.Close()
-
mt.Run("test", func(mt *mtest.T) {
c := decoratedCollection{
Collection: mt.Coll,
@@ -437,8 +411,6 @@ func TestCollection_InsertMany(t *testing.T) {
func TestCollection_DeleteOne(t *testing.T) {
mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock))
- defer mt.Close()
-
mt.Run("test", func(mt *mtest.T) {
c := decoratedCollection{
Collection: mt.Coll,
@@ -457,8 +429,6 @@ func TestCollection_DeleteOne(t *testing.T) {
func TestCollection_DeleteMany(t *testing.T) {
mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock))
- defer mt.Close()
-
mt.Run("test", func(mt *mtest.T) {
c := decoratedCollection{
Collection: mt.Coll,
@@ -477,8 +447,6 @@ func TestCollection_DeleteMany(t *testing.T) {
func TestCollection_ReplaceOne(t *testing.T) {
mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock))
- defer mt.Close()
-
mt.Run("test", func(mt *mtest.T) {
c := decoratedCollection{
Collection: mt.Coll,
@@ -500,8 +468,6 @@ func TestCollection_ReplaceOne(t *testing.T) {
func TestCollection_UpdateOne(t *testing.T) {
mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock))
- defer mt.Close()
-
mt.Run("test", func(mt *mtest.T) {
c := decoratedCollection{
Collection: mt.Coll,
@@ -522,8 +488,6 @@ func TestCollection_UpdateOne(t *testing.T) {
func TestCollection_UpdateByID(t *testing.T) {
mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock))
- defer mt.Close()
-
mt.Run("test", func(mt *mtest.T) {
c := decoratedCollection{
Collection: mt.Coll,
@@ -544,8 +508,6 @@ func TestCollection_UpdateByID(t *testing.T) {
func TestCollection_UpdateMany(t *testing.T) {
mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock))
- defer mt.Close()
-
mt.Run("test", func(mt *mtest.T) {
c := decoratedCollection{
Collection: mt.Coll,
@@ -566,7 +528,6 @@ func TestCollection_UpdateMany(t *testing.T) {
func TestDecoratedCollection_LogDuration(t *testing.T) {
mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock))
- defer mt.Close()
c := decoratedCollection{
Collection: mt.Coll,
brk: breaker.NewBreaker(),
@@ -599,13 +560,11 @@ func TestDecoratedCollection_LogDuration(t *testing.T) {
errors.New("bar"), make(chan int))
assert.Contains(t, buf.String(), "foo")
assert.Contains(t, buf.String(), "bar")
- assert.Contains(t, buf.String(), "slowcall")
buf.Reset()
c.logDuration(context.Background(), "foo", timex.Now()-slowThreshold.Load()*2,
errors.New("bar"))
assert.Contains(t, buf.String(), "foo")
- assert.Contains(t, buf.String(), "slowcall")
buf.Reset()
c.logDuration(context.Background(), "foo", timex.Now()-slowThreshold.Load()*2, nil)
diff --git a/core/stores/mon/model_test.go b/core/stores/mon/model_test.go
index 4db60d837225..681be5a55c4c 100644
--- a/core/stores/mon/model_test.go
+++ b/core/stores/mon/model_test.go
@@ -12,8 +12,6 @@ import (
func TestModel_StartSession(t *testing.T) {
mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock))
- defer mt.Close()
-
mt.Run("test", func(mt *mtest.T) {
m := createModel(mt)
sess, err := m.StartSession()
@@ -34,8 +32,6 @@ func TestModel_StartSession(t *testing.T) {
func TestModel_Aggregate(t *testing.T) {
mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock))
- defer mt.Close()
-
mt.Run("test", func(mt *mtest.T) {
m := createModel(mt)
find := mtest.CreateCursorResponse(
@@ -71,8 +67,6 @@ func TestModel_Aggregate(t *testing.T) {
func TestModel_DeleteMany(t *testing.T) {
mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock))
- defer mt.Close()
-
mt.Run("test", func(mt *mtest.T) {
m := createModel(mt)
mt.AddMockResponses(mtest.CreateSuccessResponse(bson.D{{Key: "n", Value: 1}}...))
@@ -88,8 +82,6 @@ func TestModel_DeleteMany(t *testing.T) {
func TestModel_DeleteOne(t *testing.T) {
mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock))
- defer mt.Close()
-
mt.Run("test", func(mt *mtest.T) {
m := createModel(mt)
mt.AddMockResponses(mtest.CreateSuccessResponse(bson.D{{Key: "n", Value: 1}}...))
@@ -105,8 +97,6 @@ func TestModel_DeleteOne(t *testing.T) {
func TestModel_Find(t *testing.T) {
mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock))
- defer mt.Close()
-
mt.Run("test", func(mt *mtest.T) {
m := createModel(mt)
find := mtest.CreateCursorResponse(
@@ -142,8 +132,6 @@ func TestModel_Find(t *testing.T) {
func TestModel_FindOne(t *testing.T) {
mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock))
- defer mt.Close()
-
mt.Run("test", func(mt *mtest.T) {
m := createModel(mt)
find := mtest.CreateCursorResponse(
@@ -170,8 +158,6 @@ func TestModel_FindOne(t *testing.T) {
func TestModel_FindOneAndDelete(t *testing.T) {
mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock))
- defer mt.Close()
-
mt.Run("test", func(mt *mtest.T) {
m := createModel(mt)
mt.AddMockResponses(mtest.CreateSuccessResponse(bson.D{
@@ -189,8 +175,6 @@ func TestModel_FindOneAndDelete(t *testing.T) {
func TestModel_FindOneAndReplace(t *testing.T) {
mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock))
- defer mt.Close()
-
mt.Run("test", func(mt *mtest.T) {
m := createModel(mt)
mt.AddMockResponses(mtest.CreateSuccessResponse(bson.D{
@@ -212,8 +196,6 @@ func TestModel_FindOneAndReplace(t *testing.T) {
func TestModel_FindOneAndUpdate(t *testing.T) {
mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock))
- defer mt.Close()
-
mt.Run("test", func(mt *mtest.T) {
m := createModel(mt)
mt.AddMockResponses(mtest.CreateSuccessResponse(bson.D{
diff --git a/core/stores/mon/options.go b/core/stores/mon/options.go
index ca13bff84bf6..4097328faf02 100644
--- a/core/stores/mon/options.go
+++ b/core/stores/mon/options.go
@@ -9,7 +9,11 @@ import (
const defaultTimeout = time.Second * 3
-var slowThreshold = syncx.ForAtomicDuration(defaultSlowThreshold)
+var (
+ slowThreshold = syncx.ForAtomicDuration(defaultSlowThreshold)
+ logMon = syncx.ForAtomicBool(true)
+ logSlowMon = syncx.ForAtomicBool(true)
+)
type (
options = mopt.ClientOptions
@@ -18,6 +22,17 @@ type (
Option func(opts *options)
)
+// DisableLog disables logging of mongo commands, includes info and slow logs.
+func DisableLog() {
+ logMon.Set(false)
+ logSlowMon.Set(false)
+}
+
+// DisableInfoLog disables info logging of mongo commands, but keeps slow logs.
+func DisableInfoLog() {
+ logMon.Set(false)
+}
+
// SetSlowThreshold sets the slow threshold.
func SetSlowThreshold(threshold time.Duration) {
slowThreshold.Set(threshold)
diff --git a/core/stores/mon/options_test.go b/core/stores/mon/options_test.go
index 5582f4927466..ee944f94578c 100644
--- a/core/stores/mon/options_test.go
+++ b/core/stores/mon/options_test.go
@@ -25,3 +25,29 @@ func TestWithTimeout(t *testing.T) {
WithTimeout(time.Second)(opts)
assert.Equal(t, time.Second, *opts.Timeout)
}
+
+func TestDisableLog(t *testing.T) {
+ assert.True(t, logMon.True())
+ assert.True(t, logSlowMon.True())
+ defer func() {
+ logMon.Set(true)
+ logSlowMon.Set(true)
+ }()
+
+ DisableLog()
+ assert.False(t, logMon.True())
+ assert.False(t, logSlowMon.True())
+}
+
+func TestDisableInfoLog(t *testing.T) {
+ assert.True(t, logMon.True())
+ assert.True(t, logSlowMon.True())
+ defer func() {
+ logMon.Set(true)
+ logSlowMon.Set(true)
+ }()
+
+ DisableInfoLog()
+ assert.False(t, logMon.True())
+ assert.True(t, logSlowMon.True())
+}
diff --git a/core/stores/mon/trace.go b/core/stores/mon/trace.go
index 1c9d6061292a..99bf96b6240f 100644
--- a/core/stores/mon/trace.go
+++ b/core/stores/mon/trace.go
@@ -2,6 +2,7 @@ package mon
import (
"context"
+ "errors"
"github.com/zeromicro/go-zero/core/trace"
"go.mongodb.org/mongo-driver/mongo"
@@ -23,8 +24,8 @@ func startSpan(ctx context.Context, cmd string) (context.Context, oteltrace.Span
func endSpan(span oteltrace.Span, err error) {
defer span.End()
- if err == nil || err == mongo.ErrNoDocuments ||
- err == mongo.ErrNilValue || err == mongo.ErrNilDocument {
+ if err == nil || errors.Is(err, mongo.ErrNoDocuments) ||
+ errors.Is(err, mongo.ErrNilValue) || errors.Is(err, mongo.ErrNilDocument) {
span.SetStatus(codes.Ok, "")
return
}
diff --git a/core/stores/mon/util.go b/core/stores/mon/util.go
index e401df31ff38..03e9a70c6e82 100644
--- a/core/stores/mon/util.go
+++ b/core/stores/mon/util.go
@@ -2,6 +2,7 @@ package mon
import (
"context"
+ "encoding/json"
"strings"
"time"
@@ -20,8 +21,41 @@ func logDuration(ctx context.Context, name, method string, startTime time.Durati
duration := timex.Since(startTime)
logger := logx.WithContext(ctx).WithDuration(duration)
if err != nil {
- logger.Infof("mongo(%s) - %s - fail(%s)", name, method, err.Error())
- } else {
+ logger.Errorf("mongo(%s) - %s - fail(%s)", name, method, err.Error())
+ return
+ }
+
+ if logSlowMon.True() && duration > slowThreshold.Load() {
+ logger.Slowf("[MONGO] mongo(%s) - slowcall - %s - ok", name, method)
+ } else if logMon.True() {
logger.Infof("mongo(%s) - %s - ok", name, method)
}
}
+
+func logDurationWithDocs(ctx context.Context, name, method string, startTime time.Duration,
+ err error, docs ...any) {
+ duration := timex.Since(startTime)
+ logger := logx.WithContext(ctx).WithDuration(duration)
+
+ content, jerr := json.Marshal(docs)
+ // jerr should not be non-nil, but we don't care much on this,
+ // if non-nil, we just log without docs.
+ if jerr != nil {
+ if err != nil {
+ logger.Errorf("mongo(%s) - %s - fail(%s)", name, method, err.Error())
+ } else if logSlowMon.True() && duration > slowThreshold.Load() {
+ logger.Slowf("[MONGO] mongo(%s) - slowcall - %s - ok", name, method)
+ } else if logMon.True() {
+ logger.Infof("mongo(%s) - %s - ok", name, method)
+ }
+ return
+ }
+
+ if err != nil {
+ logger.Errorf("mongo(%s) - %s - fail(%s) - %s", name, method, err.Error(), string(content))
+ } else if logSlowMon.True() && duration > slowThreshold.Load() {
+ logger.Slowf("[MONGO] mongo(%s) - slowcall - %s - ok - %s", name, method, string(content))
+ } else if logMon.True() {
+ logger.Infof("mongo(%s) - %s - ok - %s", name, method, string(content))
+ }
+}
diff --git a/core/stores/mon/util_test.go b/core/stores/mon/util_test.go
index 3ab7cf2bd073..be0c859e81ba 100644
--- a/core/stores/mon/util_test.go
+++ b/core/stores/mon/util_test.go
@@ -4,10 +4,10 @@ import (
"context"
"errors"
"testing"
- "time"
"github.com/stretchr/testify/assert"
"github.com/zeromicro/go-zero/core/logx/logtest"
+ "github.com/zeromicro/go-zero/core/timex"
)
func TestFormatAddrs(t *testing.T) {
@@ -42,13 +42,148 @@ func Test_logDuration(t *testing.T) {
buf := logtest.NewCollector(t)
buf.Reset()
- logDuration(context.Background(), "foo", "bar", time.Millisecond, nil)
+ logDuration(context.Background(), "foo", "bar", timex.Now()-slowThreshold.Load()*2, nil)
assert.Contains(t, buf.String(), "foo")
assert.Contains(t, buf.String(), "bar")
+ assert.Contains(t, buf.String(), "slow")
buf.Reset()
- logDuration(context.Background(), "foo", "bar", time.Millisecond, errors.New("bar"))
+ logDuration(context.Background(), "foo", "bar", timex.Now(), nil)
+ assert.Contains(t, buf.String(), "foo")
+ assert.Contains(t, buf.String(), "bar")
+
+ buf.Reset()
+ logDuration(context.Background(), "foo", "bar", timex.Now(), errors.New("bar"))
+ assert.Contains(t, buf.String(), "foo")
+ assert.Contains(t, buf.String(), "bar")
+ assert.Contains(t, buf.String(), "fail")
+
+ defer func() {
+ logMon.Set(true)
+ logSlowMon.Set(true)
+ }()
+
+ buf.Reset()
+ DisableInfoLog()
+ logDuration(context.Background(), "foo", "bar", timex.Now(), nil)
+ assert.Empty(t, buf.String())
+
+ buf.Reset()
+ logDuration(context.Background(), "foo", "bar", timex.Now()-slowThreshold.Load()*2, nil)
+ assert.Contains(t, buf.String(), "foo")
+ assert.Contains(t, buf.String(), "bar")
+ assert.Contains(t, buf.String(), "slow")
+
+ buf.Reset()
+ DisableLog()
+ logDuration(context.Background(), "foo", "bar", timex.Now(), nil)
+ assert.Empty(t, buf.String())
+
+ buf.Reset()
+ logDuration(context.Background(), "foo", "bar", timex.Now()-slowThreshold.Load()*2, nil)
+ assert.Empty(t, buf.String())
+
+ buf.Reset()
+ logDuration(context.Background(), "foo", "bar", timex.Now(), errors.New("bar"))
+ assert.Contains(t, buf.String(), "foo")
+ assert.Contains(t, buf.String(), "bar")
+ assert.Contains(t, buf.String(), "fail")
+}
+
+func Test_logDurationWithDoc(t *testing.T) {
+ buf := logtest.NewCollector(t)
+ buf.Reset()
+
+ logDurationWithDocs(context.Background(), "foo", "bar", timex.Now()-slowThreshold.Load()*2, nil, make(chan int))
+ assert.Contains(t, buf.String(), "foo")
+ assert.Contains(t, buf.String(), "bar")
+ assert.Contains(t, buf.String(), "slow")
+
+ buf.Reset()
+ logDurationWithDocs(context.Background(), "foo", "bar", timex.Now()-slowThreshold.Load()*2, nil, "{'json': ''}")
+ assert.Contains(t, buf.String(), "foo")
+ assert.Contains(t, buf.String(), "bar")
+ assert.Contains(t, buf.String(), "slow")
+ assert.Contains(t, buf.String(), "json")
+
+ buf.Reset()
+ logDurationWithDocs(context.Background(), "foo", "bar", timex.Now(), nil, make(chan int))
+ assert.Contains(t, buf.String(), "foo")
+ assert.Contains(t, buf.String(), "bar")
+
+ buf.Reset()
+ logDurationWithDocs(context.Background(), "foo", "bar", timex.Now(), nil, "{'json': ''}")
+ assert.Contains(t, buf.String(), "foo")
+ assert.Contains(t, buf.String(), "bar")
+ assert.Contains(t, buf.String(), "json")
+
+ buf.Reset()
+ logDurationWithDocs(context.Background(), "foo", "bar", timex.Now(), errors.New("bar"), make(chan int))
+ assert.Contains(t, buf.String(), "foo")
+ assert.Contains(t, buf.String(), "bar")
+ assert.Contains(t, buf.String(), "fail")
+
+ buf.Reset()
+ logDurationWithDocs(context.Background(), "foo", "bar", timex.Now(), errors.New("bar"), "{'json': ''}")
+ assert.Contains(t, buf.String(), "foo")
+ assert.Contains(t, buf.String(), "bar")
+ assert.Contains(t, buf.String(), "fail")
+ assert.Contains(t, buf.String(), "json")
+
+ defer func() {
+ logMon.Set(true)
+ logSlowMon.Set(true)
+ }()
+
+ buf.Reset()
+ DisableInfoLog()
+ logDurationWithDocs(context.Background(), "foo", "bar", timex.Now(), nil, make(chan int))
+ assert.Empty(t, buf.String())
+
+ buf.Reset()
+ logDurationWithDocs(context.Background(), "foo", "bar", timex.Now(), nil, "{'json': ''}")
+ assert.Empty(t, buf.String())
+
+ buf.Reset()
+ logDurationWithDocs(context.Background(), "foo", "bar", timex.Now()-slowThreshold.Load()*2, nil, make(chan int))
+ assert.Contains(t, buf.String(), "foo")
+ assert.Contains(t, buf.String(), "bar")
+ assert.Contains(t, buf.String(), "slow")
+
+ buf.Reset()
+ logDurationWithDocs(context.Background(), "foo", "bar", timex.Now()-slowThreshold.Load()*2, nil, "{'json': ''}")
+ assert.Contains(t, buf.String(), "foo")
+ assert.Contains(t, buf.String(), "bar")
+ assert.Contains(t, buf.String(), "slow")
+ assert.Contains(t, buf.String(), "json")
+
+ buf.Reset()
+ DisableLog()
+ logDurationWithDocs(context.Background(), "foo", "bar", timex.Now(), nil, make(chan int))
+ assert.Empty(t, buf.String())
+
+ buf.Reset()
+ logDurationWithDocs(context.Background(), "foo", "bar", timex.Now(), nil, "{'json': ''}")
+ assert.Empty(t, buf.String())
+
+ buf.Reset()
+ logDurationWithDocs(context.Background(), "foo", "bar", timex.Now()-slowThreshold.Load()*2, nil, make(chan int))
+ assert.Empty(t, buf.String())
+
+ buf.Reset()
+ logDurationWithDocs(context.Background(), "foo", "bar", timex.Now()-slowThreshold.Load()*2, nil, "{'json': ''}")
+ assert.Empty(t, buf.String())
+
+ buf.Reset()
+ logDurationWithDocs(context.Background(), "foo", "bar", timex.Now(), errors.New("bar"), make(chan int))
+ assert.Contains(t, buf.String(), "foo")
+ assert.Contains(t, buf.String(), "bar")
+ assert.Contains(t, buf.String(), "fail")
+
+ buf.Reset()
+ logDurationWithDocs(context.Background(), "foo", "bar", timex.Now(), errors.New("bar"), "{'json': ''}")
assert.Contains(t, buf.String(), "foo")
assert.Contains(t, buf.String(), "bar")
assert.Contains(t, buf.String(), "fail")
+ assert.Contains(t, buf.String(), "json")
}
diff --git a/core/stores/monc/cachedmodel_test.go b/core/stores/monc/cachedmodel_test.go
index 0abc68e0d283..6a6e6128caca 100644
--- a/core/stores/monc/cachedmodel_test.go
+++ b/core/stores/monc/cachedmodel_test.go
@@ -17,8 +17,6 @@ import (
func TestNewModel(t *testing.T) {
mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock))
- defer mt.Close()
-
mt.Run("test", func(mt *mtest.T) {
_, err := newModel("foo", mt.DB.Name(), mt.Coll.Name(), nil)
assert.NotNil(mt, err)
@@ -27,8 +25,6 @@ func TestNewModel(t *testing.T) {
func TestModel_DelCache(t *testing.T) {
mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock))
- defer mt.Close()
-
mt.Run("test", func(mt *mtest.T) {
m := createModel(t, mt)
assert.Nil(t, m.cache.Set("foo", "bar"))
@@ -42,8 +38,6 @@ func TestModel_DelCache(t *testing.T) {
func TestModel_DeleteOne(t *testing.T) {
mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock))
- defer mt.Close()
-
mt.Run("test", func(mt *mtest.T) {
mt.AddMockResponses(mtest.CreateSuccessResponse(bson.D{{Key: "n", Value: 1}}...))
m := createModel(t, mt)
@@ -65,8 +59,6 @@ func TestModel_DeleteOne(t *testing.T) {
func TestModel_DeleteOneNoCache(t *testing.T) {
mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock))
- defer mt.Close()
-
mt.Run("test", func(mt *mtest.T) {
mt.AddMockResponses(mtest.CreateSuccessResponse(bson.D{{Key: "n", Value: 1}}...))
m := createModel(t, mt)
@@ -81,8 +73,6 @@ func TestModel_DeleteOneNoCache(t *testing.T) {
func TestModel_FindOne(t *testing.T) {
mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock))
- defer mt.Close()
-
mt.Run("test", func(mt *mtest.T) {
resp := mtest.CreateCursorResponse(
1,
@@ -104,8 +94,6 @@ func TestModel_FindOne(t *testing.T) {
func TestModel_FindOneNoCache(t *testing.T) {
mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock))
- defer mt.Close()
-
mt.Run("test", func(mt *mtest.T) {
resp := mtest.CreateCursorResponse(
1,
@@ -126,8 +114,6 @@ func TestModel_FindOneNoCache(t *testing.T) {
func TestModel_FindOneAndDelete(t *testing.T) {
mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock))
- defer mt.Close()
-
mt.Run("test", func(mt *mtest.T) {
mt.AddMockResponses(mtest.CreateSuccessResponse(bson.D{
{Key: "value", Value: bson.D{{Key: "foo", Value: "bar"}}},
@@ -152,8 +138,6 @@ func TestModel_FindOneAndDelete(t *testing.T) {
func TestModel_FindOneAndDeleteNoCache(t *testing.T) {
mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock))
- defer mt.Close()
-
mt.Run("test", func(mt *mtest.T) {
mt.AddMockResponses(mtest.CreateSuccessResponse(bson.D{
{Key: "value", Value: bson.D{{Key: "foo", Value: "bar"}}},
@@ -169,8 +153,6 @@ func TestModel_FindOneAndDeleteNoCache(t *testing.T) {
func TestModel_FindOneAndReplace(t *testing.T) {
mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock))
- defer mt.Close()
-
mt.Run("test", func(mt *mtest.T) {
mt.AddMockResponses(mtest.CreateSuccessResponse(bson.D{
{Key: "value", Value: bson.D{{Key: "foo", Value: "bar"}}},
@@ -201,8 +183,6 @@ func TestModel_FindOneAndReplace(t *testing.T) {
func TestModel_FindOneAndReplaceNoCache(t *testing.T) {
mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock))
- defer mt.Close()
-
mt.Run("test", func(mt *mtest.T) {
mt.AddMockResponses(mtest.CreateSuccessResponse(bson.D{
{Key: "value", Value: bson.D{{Key: "foo", Value: "bar"}}},
@@ -220,8 +200,6 @@ func TestModel_FindOneAndReplaceNoCache(t *testing.T) {
func TestModel_FindOneAndUpdate(t *testing.T) {
mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock))
- defer mt.Close()
-
mt.Run("test", func(mt *mtest.T) {
mt.AddMockResponses(mtest.CreateSuccessResponse(bson.D{
{Key: "value", Value: bson.D{{Key: "foo", Value: "bar"}}},
@@ -252,8 +230,6 @@ func TestModel_FindOneAndUpdate(t *testing.T) {
func TestModel_FindOneAndUpdateNoCache(t *testing.T) {
mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock))
- defer mt.Close()
-
mt.Run("test", func(mt *mtest.T) {
mt.AddMockResponses(mtest.CreateSuccessResponse(bson.D{
{Key: "value", Value: bson.D{{Key: "foo", Value: "bar"}}},
@@ -271,8 +247,6 @@ func TestModel_FindOneAndUpdateNoCache(t *testing.T) {
func TestModel_GetCache(t *testing.T) {
mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock))
- defer mt.Close()
-
mt.Run("test", func(mt *mtest.T) {
m := createModel(t, mt)
assert.NotNil(t, m.cache)
@@ -285,8 +259,6 @@ func TestModel_GetCache(t *testing.T) {
func TestModel_InsertOne(t *testing.T) {
mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock))
- defer mt.Close()
-
mt.Run("test", func(mt *mtest.T) {
mt.AddMockResponses(mtest.CreateSuccessResponse(bson.D{
{Key: "value", Value: bson.D{{Key: "foo", Value: "bar"}}},
@@ -318,8 +290,6 @@ func TestModel_InsertOne(t *testing.T) {
func TestModel_InsertOneNoCache(t *testing.T) {
mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock))
- defer mt.Close()
-
mt.Run("test", func(mt *mtest.T) {
mt.AddMockResponses(mtest.CreateSuccessResponse(bson.D{
{Key: "value", Value: bson.D{{Key: "foo", Value: "bar"}}},
@@ -335,8 +305,6 @@ func TestModel_InsertOneNoCache(t *testing.T) {
func TestModel_ReplaceOne(t *testing.T) {
mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock))
- defer mt.Close()
-
mt.Run("test", func(mt *mtest.T) {
mt.AddMockResponses(mtest.CreateSuccessResponse(bson.D{
{Key: "value", Value: bson.D{{Key: "foo", Value: "bar"}}},
@@ -368,8 +336,6 @@ func TestModel_ReplaceOne(t *testing.T) {
func TestModel_ReplaceOneNoCache(t *testing.T) {
mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock))
- defer mt.Close()
-
mt.Run("test", func(mt *mtest.T) {
mt.AddMockResponses(mtest.CreateSuccessResponse(bson.D{
{Key: "value", Value: bson.D{{Key: "foo", Value: "bar"}}},
@@ -385,8 +351,6 @@ func TestModel_ReplaceOneNoCache(t *testing.T) {
func TestModel_SetCache(t *testing.T) {
mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock))
- defer mt.Close()
-
mt.Run("test", func(mt *mtest.T) {
m := createModel(t, mt)
assert.Nil(t, m.SetCache("foo", "bar"))
@@ -398,8 +362,6 @@ func TestModel_SetCache(t *testing.T) {
func TestModel_UpdateByID(t *testing.T) {
mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock))
- defer mt.Close()
-
mt.Run("test", func(mt *mtest.T) {
mt.AddMockResponses(mtest.CreateSuccessResponse(bson.D{
{Key: "value", Value: bson.D{{Key: "foo", Value: "bar"}}},
@@ -431,8 +393,6 @@ func TestModel_UpdateByID(t *testing.T) {
func TestModel_UpdateByIDNoCache(t *testing.T) {
mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock))
- defer mt.Close()
-
mt.Run("test", func(mt *mtest.T) {
mt.AddMockResponses(mtest.CreateSuccessResponse(bson.D{
{Key: "value", Value: bson.D{{Key: "foo", Value: "bar"}}},
@@ -448,8 +408,6 @@ func TestModel_UpdateByIDNoCache(t *testing.T) {
func TestModel_UpdateMany(t *testing.T) {
mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock))
- defer mt.Close()
-
mt.Run("test", func(mt *mtest.T) {
mt.AddMockResponses(mtest.CreateSuccessResponse(bson.D{
{Key: "value", Value: bson.D{{Key: "foo", Value: "bar"}}},
@@ -483,8 +441,6 @@ func TestModel_UpdateMany(t *testing.T) {
func TestModel_UpdateManyNoCache(t *testing.T) {
mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock))
- defer mt.Close()
-
mt.Run("test", func(mt *mtest.T) {
mt.AddMockResponses(mtest.CreateSuccessResponse(bson.D{
{Key: "value", Value: bson.D{{Key: "foo", Value: "bar"}}},
@@ -500,8 +456,6 @@ func TestModel_UpdateManyNoCache(t *testing.T) {
func TestModel_UpdateOne(t *testing.T) {
mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock))
- defer mt.Close()
-
mt.Run("test", func(mt *mtest.T) {
mt.AddMockResponses(mtest.CreateSuccessResponse(bson.D{
{Key: "value", Value: bson.D{{Key: "foo", Value: "bar"}}},
@@ -533,8 +487,6 @@ func TestModel_UpdateOne(t *testing.T) {
func TestModel_UpdateOneNoCache(t *testing.T) {
mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock))
- defer mt.Close()
-
mt.Run("test", func(mt *mtest.T) {
mt.AddMockResponses(mtest.CreateSuccessResponse(bson.D{
{Key: "value", Value: bson.D{{Key: "foo", Value: "bar"}}},
diff --git a/core/stores/redis/hook.go b/core/stores/redis/hook.go
index b7a0a33289a5..46dfad1efa55 100644
--- a/core/stores/redis/hook.go
+++ b/core/stores/redis/hook.go
@@ -54,9 +54,10 @@ func (h hook) AfterProcess(ctx context.Context, cmd red.Cmder) error {
duration := timex.Since(start)
if duration > slowThreshold.Load() {
logDuration(ctx, []red.Cmder{cmd}, duration)
+ metricSlowCount.Inc(cmd.Name())
}
- metricReqDur.Observe(duration.Milliseconds(), cmd.Name())
+ metricReqDur.ObserveFloat(float64(duration)/float64(time.Millisecond), cmd.Name())
if msg := formatError(err); len(msg) > 0 {
metricReqErr.Inc(cmd.Name(), msg)
}
diff --git a/core/stores/redis/hook_test.go b/core/stores/redis/hook_test.go
index e9c6e2c1253b..78556ef9111f 100644
--- a/core/stores/redis/hook_test.go
+++ b/core/stores/redis/hook_test.go
@@ -52,19 +52,15 @@ func TestHookProcessCase2(t *testing.T) {
defer ztrace.StopAgent()
w := logtest.NewCollector(t)
-
ctx, err := durationHook.BeforeProcess(context.Background(), red.NewCmd(context.Background()))
if err != nil {
t.Fatal(err)
}
- assert.Equal(t, "redis", tracesdk.SpanFromContext(ctx).(interface{ Name() string }).Name())
time.Sleep(slowThreshold.Load() + time.Millisecond)
assert.Nil(t, durationHook.AfterProcess(ctx, red.NewCmd(context.Background(), "foo", "bar")))
assert.True(t, strings.Contains(w.String(), "slow"))
- assert.True(t, strings.Contains(w.String(), "trace"))
- assert.True(t, strings.Contains(w.String(), "span"))
}
func TestHookProcessCase3(t *testing.T) {
@@ -89,6 +85,14 @@ func TestHookProcessCase4(t *testing.T) {
}
func TestHookProcessPipelineCase1(t *testing.T) {
+ ztrace.StartAgent(ztrace.Config{
+ Name: "go-zero-test",
+ Endpoint: "http://localhost:14268/api/traces",
+ Batcher: "jaeger",
+ Sampler: 1.0,
+ })
+ defer ztrace.StopAgent()
+
writer := log.Writer()
var buf strings.Builder
log.SetOutput(&buf)
@@ -100,7 +104,6 @@ func TestHookProcessPipelineCase1(t *testing.T) {
red.NewCmd(context.Background()),
})
assert.NoError(t, err)
- assert.Equal(t, "redis", tracesdk.SpanFromContext(ctx).(interface{ Name() string }).Name())
assert.NoError(t, durationHook.AfterProcessPipeline(ctx, []red.Cmder{}))
assert.NoError(t, durationHook.AfterProcessPipeline(ctx, []red.Cmder{
@@ -119,12 +122,10 @@ func TestHookProcessPipelineCase2(t *testing.T) {
defer ztrace.StopAgent()
w := logtest.NewCollector(t)
-
ctx, err := durationHook.BeforeProcessPipeline(context.Background(), []red.Cmder{
red.NewCmd(context.Background()),
})
assert.NoError(t, err)
- assert.Equal(t, "redis", tracesdk.SpanFromContext(ctx).(interface{ Name() string }).Name())
time.Sleep(slowThreshold.Load() + time.Millisecond)
@@ -132,8 +133,6 @@ func TestHookProcessPipelineCase2(t *testing.T) {
red.NewCmd(context.Background(), "foo", "bar"),
}))
assert.True(t, strings.Contains(w.String(), "slow"))
- assert.True(t, strings.Contains(w.String(), "trace"))
- assert.True(t, strings.Contains(w.String(), "span"))
}
func TestHookProcessPipelineCase3(t *testing.T) {
diff --git a/core/stores/redis/metrics.go b/core/stores/redis/metrics.go
index 2cb381f44b8d..fe3ce9ccbe25 100644
--- a/core/stores/redis/metrics.go
+++ b/core/stores/redis/metrics.go
@@ -1,6 +1,12 @@
package redis
-import "github.com/zeromicro/go-zero/core/metric"
+import (
+ "sync"
+
+ red "github.com/go-redis/redis/v8"
+ "github.com/prometheus/client_golang/prometheus"
+ "github.com/zeromicro/go-zero/core/metric"
+)
const namespace = "redis_client"
@@ -11,7 +17,7 @@ var (
Name: "duration_ms",
Help: "redis client requests duration(ms).",
Labels: []string{"command"},
- Buckets: []float64{5, 10, 25, 50, 100, 250, 500, 1000, 2500},
+ Buckets: []float64{0.25, 0.5, 1, 1.5, 2, 3, 5, 10, 25, 50, 100, 250, 500, 1000, 2000, 5000, 10000, 15000},
})
metricReqErr = metric.NewCounterVec(&metric.CounterVecOpts{
Namespace: namespace,
@@ -20,4 +26,162 @@ var (
Help: "redis client requests error count.",
Labels: []string{"command", "error"},
})
+ metricSlowCount = metric.NewCounterVec(&metric.CounterVecOpts{
+ Namespace: namespace,
+ Subsystem: "requests",
+ Name: "slow_total",
+ Help: "redis client requests slow count.",
+ Labels: []string{"command"},
+ })
+
+ connLabels = []string{"key", "client_type"}
+ connCollector = newCollector()
+ _ prometheus.Collector = (*collector)(nil)
+)
+
+type (
+ statGetter struct {
+ clientType string
+ key string
+ poolSize int
+ poolStats func() *red.PoolStats
+ }
+
+ // collector collects statistics from a redis client.
+ // It implements the prometheus.Collector interface.
+ collector struct {
+ hitDesc *prometheus.Desc
+ missDesc *prometheus.Desc
+ timeoutDesc *prometheus.Desc
+ totalDesc *prometheus.Desc
+ idleDesc *prometheus.Desc
+ staleDesc *prometheus.Desc
+ maxDesc *prometheus.Desc
+
+ clients []*statGetter
+ lock sync.Mutex
+ }
)
+
+func newCollector() *collector {
+ c := &collector{
+ hitDesc: prometheus.NewDesc(
+ prometheus.BuildFQName(namespace, "", "pool_hit_total"),
+ "Number of times a connection was found in the pool",
+ connLabels, nil,
+ ),
+ missDesc: prometheus.NewDesc(
+ prometheus.BuildFQName(namespace, "", "pool_miss_total"),
+ "Number of times a connection was not found in the pool",
+ connLabels, nil,
+ ),
+ timeoutDesc: prometheus.NewDesc(
+ prometheus.BuildFQName(namespace, "", "pool_timeout_total"),
+ "Number of times a timeout occurred when looking for a connection in the pool",
+ connLabels, nil,
+ ),
+ totalDesc: prometheus.NewDesc(
+ prometheus.BuildFQName(namespace, "", "pool_conn_total_current"),
+ "Current number of connections in the pool",
+ connLabels, nil,
+ ),
+ idleDesc: prometheus.NewDesc(
+ prometheus.BuildFQName(namespace, "", "pool_conn_idle_current"),
+ "Current number of idle connections in the pool",
+ connLabels, nil,
+ ),
+ staleDesc: prometheus.NewDesc(
+ prometheus.BuildFQName(namespace, "", "pool_conn_stale_total"),
+ "Number of times a connection was removed from the pool because it was stale",
+ connLabels, nil,
+ ),
+ maxDesc: prometheus.NewDesc(
+ prometheus.BuildFQName(namespace, "", "pool_conn_max"),
+ "Max number of connections in the pool",
+ connLabels, nil,
+ ),
+ }
+
+ prometheus.MustRegister(c)
+
+ return c
+}
+
+// Describe implements the prometheus.Collector interface.
+func (s *collector) Describe(descs chan<- *prometheus.Desc) {
+ descs <- s.hitDesc
+ descs <- s.missDesc
+ descs <- s.timeoutDesc
+ descs <- s.totalDesc
+ descs <- s.idleDesc
+ descs <- s.staleDesc
+ descs <- s.maxDesc
+}
+
+// Collect implements the prometheus.Collector interface.
+func (s *collector) Collect(metrics chan<- prometheus.Metric) {
+ s.lock.Lock()
+ defer s.lock.Unlock()
+
+ for _, client := range s.clients {
+ key, clientType := client.key, client.clientType
+ stats := client.poolStats()
+
+ metrics <- prometheus.MustNewConstMetric(
+ s.hitDesc,
+ prometheus.CounterValue,
+ float64(stats.Hits),
+ key,
+ clientType,
+ )
+ metrics <- prometheus.MustNewConstMetric(
+ s.missDesc,
+ prometheus.CounterValue,
+ float64(stats.Misses),
+ key,
+ clientType,
+ )
+ metrics <- prometheus.MustNewConstMetric(
+ s.timeoutDesc,
+ prometheus.CounterValue,
+ float64(stats.Timeouts),
+ key,
+ clientType,
+ )
+ metrics <- prometheus.MustNewConstMetric(
+ s.totalDesc,
+ prometheus.GaugeValue,
+ float64(stats.TotalConns),
+ key,
+ clientType,
+ )
+ metrics <- prometheus.MustNewConstMetric(
+ s.idleDesc,
+ prometheus.GaugeValue,
+ float64(stats.IdleConns),
+ key,
+ clientType,
+ )
+ metrics <- prometheus.MustNewConstMetric(
+ s.staleDesc,
+ prometheus.CounterValue,
+ float64(stats.StaleConns),
+ key,
+ clientType,
+ )
+ metrics <- prometheus.MustNewConstMetric(
+ s.maxDesc,
+ prometheus.CounterValue,
+ float64(client.poolSize),
+ key,
+ clientType,
+ )
+ }
+}
+
+func (s *collector) registerClient(client *statGetter) {
+ s.lock.Lock()
+ defer s.lock.Unlock()
+
+ s.clients = append(s.clients, client)
+}
diff --git a/core/stores/redis/metrics_test.go b/core/stores/redis/metrics_test.go
new file mode 100644
index 000000000000..29c5f771ce4e
--- /dev/null
+++ b/core/stores/redis/metrics_test.go
@@ -0,0 +1,130 @@
+package redis
+
+import (
+ "io"
+ "net/http"
+ "strings"
+ "testing"
+ "time"
+
+ red "github.com/go-redis/redis/v8"
+ "github.com/prometheus/client_golang/prometheus"
+ "github.com/prometheus/client_golang/prometheus/testutil"
+ "github.com/stretchr/testify/assert"
+ "github.com/zeromicro/go-zero/core/conf"
+ "github.com/zeromicro/go-zero/internal/devserver"
+)
+
+func TestRedisMetric(t *testing.T) {
+ cfg := devserver.Config{}
+ _ = conf.FillDefault(&cfg)
+ server := devserver.NewServer(cfg)
+ server.StartAsync()
+ time.Sleep(time.Second)
+
+ metricReqDur.Observe(8, "test-cmd")
+ metricReqErr.Inc("test-cmd", "internal-error")
+ metricSlowCount.Inc("test-cmd")
+
+ url := "http://127.0.0.1:6060/metrics"
+ resp, err := http.Get(url)
+ assert.Nil(t, err)
+ defer resp.Body.Close()
+ s, err := io.ReadAll(resp.Body)
+ assert.Nil(t, err)
+ content := string(s)
+ assert.Contains(t, content, "redis_client_requests_duration_ms_sum{command=\"test-cmd\"} 8\n")
+ assert.Contains(t, content, "redis_client_requests_duration_ms_count{command=\"test-cmd\"} 1\n")
+ assert.Contains(t, content, "redis_client_requests_error_total{command=\"test-cmd\",error=\"internal-error\"} 1\n")
+ assert.Contains(t, content, "redis_client_requests_slow_total{command=\"test-cmd\"} 1\n")
+}
+
+func Test_newCollector(t *testing.T) {
+ prometheus.Unregister(connCollector)
+ c := newCollector()
+ c.registerClient(&statGetter{
+ clientType: "node",
+ key: "test1",
+ poolSize: 10,
+ poolStats: func() *red.PoolStats {
+ return &red.PoolStats{
+ Hits: 10000,
+ Misses: 10,
+ Timeouts: 5,
+ TotalConns: 100,
+ IdleConns: 20,
+ StaleConns: 1,
+ }
+ },
+ })
+ c.registerClient(&statGetter{
+ clientType: "node",
+ key: "test2",
+ poolSize: 11,
+ poolStats: func() *red.PoolStats {
+ return &red.PoolStats{
+ Hits: 10001,
+ Misses: 11,
+ Timeouts: 6,
+ TotalConns: 101,
+ IdleConns: 21,
+ StaleConns: 2,
+ }
+ },
+ })
+ c.registerClient(&statGetter{
+ clientType: "cluster",
+ key: "test3",
+ poolSize: 5,
+ poolStats: func() *red.PoolStats {
+ return &red.PoolStats{
+ Hits: 20000,
+ Misses: 20,
+ Timeouts: 10,
+ TotalConns: 200,
+ IdleConns: 40,
+ StaleConns: 2,
+ }
+ },
+ })
+ val := `
+ # HELP redis_client_pool_conn_idle_current Current number of idle connections in the pool
+ # TYPE redis_client_pool_conn_idle_current gauge
+ redis_client_pool_conn_idle_current{client_type="cluster",key="test3"} 40
+ redis_client_pool_conn_idle_current{client_type="node",key="test1"} 20
+ redis_client_pool_conn_idle_current{client_type="node",key="test2"} 21
+ # HELP redis_client_pool_conn_max Max number of connections in the pool
+ # TYPE redis_client_pool_conn_max counter
+ redis_client_pool_conn_max{client_type="cluster",key="test3"} 5
+ redis_client_pool_conn_max{client_type="node",key="test1"} 10
+ redis_client_pool_conn_max{client_type="node",key="test2"} 11
+ # HELP redis_client_pool_conn_stale_total Number of times a connection was removed from the pool because it was stale
+ # TYPE redis_client_pool_conn_stale_total counter
+ redis_client_pool_conn_stale_total{client_type="cluster",key="test3"} 2
+ redis_client_pool_conn_stale_total{client_type="node",key="test1"} 1
+ redis_client_pool_conn_stale_total{client_type="node",key="test2"} 2
+ # HELP redis_client_pool_conn_total_current Current number of connections in the pool
+ # TYPE redis_client_pool_conn_total_current gauge
+ redis_client_pool_conn_total_current{client_type="cluster",key="test3"} 200
+ redis_client_pool_conn_total_current{client_type="node",key="test1"} 100
+ redis_client_pool_conn_total_current{client_type="node",key="test2"} 101
+ # HELP redis_client_pool_hit_total Number of times a connection was found in the pool
+ # TYPE redis_client_pool_hit_total counter
+ redis_client_pool_hit_total{client_type="cluster",key="test3"} 20000
+ redis_client_pool_hit_total{client_type="node",key="test1"} 10000
+ redis_client_pool_hit_total{client_type="node",key="test2"} 10001
+ # HELP redis_client_pool_miss_total Number of times a connection was not found in the pool
+ # TYPE redis_client_pool_miss_total counter
+ redis_client_pool_miss_total{client_type="cluster",key="test3"} 20
+ redis_client_pool_miss_total{client_type="node",key="test1"} 10
+ redis_client_pool_miss_total{client_type="node",key="test2"} 11
+ # HELP redis_client_pool_timeout_total Number of times a timeout occurred when looking for a connection in the pool
+ # TYPE redis_client_pool_timeout_total counter
+ redis_client_pool_timeout_total{client_type="cluster",key="test3"} 10
+ redis_client_pool_timeout_total{client_type="node",key="test1"} 5
+ redis_client_pool_timeout_total{client_type="node",key="test2"} 6
+`
+
+ err := testutil.CollectAndCompare(c, strings.NewReader(val))
+ assert.NoError(t, err)
+}
diff --git a/core/stores/redis/redis.go b/core/stores/redis/redis.go
index 82a44ef37c19..c5549e3dab66 100644
--- a/core/stores/redis/redis.go
+++ b/core/stores/redis/redis.go
@@ -2849,7 +2849,7 @@ func withHook(hook red.Hook) Option {
}
func acceptable(err error) bool {
- return err == nil || err == red.Nil || err == context.Canceled
+ return err == nil || err == red.Nil || errors.Is(err, context.Canceled)
}
func getRedis(r *Redis) (RedisNode, error) {
diff --git a/core/stores/redis/redisclientmanager.go b/core/stores/redis/redisclientmanager.go
index 8311e8c09a2a..8b1b8ed5fc72 100644
--- a/core/stores/redis/redisclientmanager.go
+++ b/core/stores/redis/redisclientmanager.go
@@ -3,6 +3,7 @@ package redis
import (
"crypto/tls"
"io"
+ "runtime"
red "github.com/go-redis/redis/v8"
"github.com/zeromicro/go-zero/core/syncx"
@@ -14,7 +15,11 @@ const (
idleConns = 8
)
-var clientManager = syncx.NewResourceManager()
+var (
+ clientManager = syncx.NewResourceManager()
+ // nodePoolSize is default pool size for node type of redis.
+ nodePoolSize = 10 * runtime.GOMAXPROCS(0)
+)
func getClient(r *Redis) (*red.Client, error) {
val, err := clientManager.GetResource(r.Addr, func() (io.Closer, error) {
@@ -37,6 +42,15 @@ func getClient(r *Redis) (*red.Client, error) {
store.AddHook(hook)
}
+ connCollector.registerClient(&statGetter{
+ clientType: NodeType,
+ key: r.Addr,
+ poolSize: nodePoolSize,
+ poolStats: func() *red.PoolStats {
+ return store.PoolStats()
+ },
+ })
+
return store, nil
})
if err != nil {
diff --git a/core/stores/redis/redisclustermanager.go b/core/stores/redis/redisclustermanager.go
index d4a489e65c0b..105498e83995 100644
--- a/core/stores/redis/redisclustermanager.go
+++ b/core/stores/redis/redisclustermanager.go
@@ -3,6 +3,7 @@ package redis
import (
"crypto/tls"
"io"
+ "runtime"
"strings"
red "github.com/go-redis/redis/v8"
@@ -11,7 +12,11 @@ import (
const addrSep = ","
-var clusterManager = syncx.NewResourceManager()
+var (
+ clusterManager = syncx.NewResourceManager()
+ // clusterPoolSize is default pool size for cluster type of redis.
+ clusterPoolSize = 5 * runtime.GOMAXPROCS(0)
+)
func getCluster(r *Redis) (*red.ClusterClient, error) {
val, err := clusterManager.GetResource(r.Addr, func() (io.Closer, error) {
@@ -33,6 +38,15 @@ func getCluster(r *Redis) (*red.ClusterClient, error) {
store.AddHook(hook)
}
+ connCollector.registerClient(&statGetter{
+ clientType: ClusterType,
+ key: r.Addr,
+ poolSize: clusterPoolSize,
+ poolStats: func() *red.PoolStats {
+ return store.PoolStats()
+ },
+ })
+
return store, nil
})
if err != nil {
diff --git a/core/stores/redis/redisclustermanager_test.go b/core/stores/redis/redisclustermanager_test.go
index 5782ce22cd52..4d53a63236e9 100644
--- a/core/stores/redis/redisclustermanager_test.go
+++ b/core/stores/redis/redisclustermanager_test.go
@@ -3,6 +3,8 @@ package redis
import (
"testing"
+ "github.com/alicebob/miniredis/v2"
+ red "github.com/go-redis/redis/v8"
"github.com/stretchr/testify/assert"
)
@@ -41,3 +43,17 @@ func TestSplitClusterAddrs(t *testing.T) {
})
}
}
+
+func TestGetCluster(t *testing.T) {
+ r := miniredis.RunT(t)
+ defer r.Close()
+ c, err := getCluster(&Redis{
+ Addr: r.Addr(),
+ Type: ClusterType,
+ tls: true,
+ hooks: []red.Hook{durationHook},
+ })
+ if assert.NoError(t, err) {
+ assert.NotNil(t, c)
+ }
+}
diff --git a/core/stores/sqlx/bulkinserter.go b/core/stores/sqlx/bulkinserter.go
index 789d1e804a58..f251b76b9b96 100644
--- a/core/stores/sqlx/bulkinserter.go
+++ b/core/stores/sqlx/bulkinserter.go
@@ -4,6 +4,7 @@ import (
"database/sql"
"fmt"
"strings"
+ "sync"
"time"
"github.com/zeromicro/go-zero/core/executors"
@@ -30,6 +31,7 @@ type (
executor *executors.PeriodicalExecutor
inserter *dbInserter
stmt bulkStmt
+ lock sync.RWMutex // guards stmt
}
bulkStmt struct {
@@ -65,6 +67,9 @@ func (bi *BulkInserter) Flush() {
// Insert inserts given args.
func (bi *BulkInserter) Insert(args ...any) error {
+ bi.lock.RLock()
+ defer bi.lock.RUnlock()
+
value, err := format(bi.stmt.valueFormat, args...)
if err != nil {
return err
@@ -95,6 +100,11 @@ func (bi *BulkInserter) UpdateStmt(stmt string) error {
return err
}
+ bi.lock.Lock()
+ defer bi.lock.Unlock()
+
+ // with write lock, it doesn't matter what's the order of setting bi.stmt and calling flush.
+ bi.stmt = bkStmt
bi.executor.Flush()
bi.executor.Sync(func() {
bi.inserter.stmt = bkStmt
diff --git a/core/stores/sqlx/bulkinserter_test.go b/core/stores/sqlx/bulkinserter_test.go
index ae4bca1bcc44..6ffa349ea019 100644
--- a/core/stores/sqlx/bulkinserter_test.go
+++ b/core/stores/sqlx/bulkinserter_test.go
@@ -5,6 +5,9 @@ import (
"database/sql"
"errors"
"strconv"
+ "strings"
+ "sync"
+ "sync/atomic"
"testing"
"github.com/DATA-DOG/go-sqlmock"
@@ -13,14 +16,19 @@ import (
)
type mockedConn struct {
- query string
- args []any
- execErr error
+ query string
+ args []any
+ execErr error
+ updateCallback func(query string, args []any)
}
func (c *mockedConn) ExecCtx(_ context.Context, query string, args ...any) (sql.Result, error) {
c.query = query
c.args = args
+ if c.updateCallback != nil {
+ c.updateCallback(query, args)
+ }
+
return nil, c.execErr
}
@@ -144,3 +152,50 @@ func TestBulkInserter_Update(t *testing.T) {
assert.NotNil(t, inserter.UpdateStmt("foo"))
assert.NotNil(t, inserter.Insert("foo", "bar"))
}
+
+func TestBulkInserter_UpdateStmt(t *testing.T) {
+ var updated int32
+ conn := mockedConn{
+ execErr: errors.New("foo"),
+ updateCallback: func(query string, args []any) {
+ count := atomic.AddInt32(&updated, 1)
+ assert.Empty(t, args)
+ assert.Equal(t, 100, strings.Count(query, "foo"))
+ if count == 1 {
+ assert.Equal(t, 0, strings.Count(query, "bar"))
+ } else {
+ assert.Equal(t, 100, strings.Count(query, "bar"))
+ }
+ },
+ }
+
+ inserter, err := NewBulkInserter(&conn, `INSERT INTO classroom_dau(classroom) VALUES(?)`)
+ assert.NoError(t, err)
+
+ var wg1 sync.WaitGroup
+ wg1.Add(2)
+ for i := 0; i < 2; i++ {
+ go func() {
+ defer wg1.Done()
+ for i := 0; i < 50; i++ {
+ assert.NoError(t, inserter.Insert("foo"))
+ }
+ }()
+ }
+ wg1.Wait()
+
+ assert.NoError(t, inserter.UpdateStmt(`INSERT INTO classroom_dau(classroom, user) VALUES(?, ?)`))
+
+ var wg2 sync.WaitGroup
+ wg2.Add(1)
+ go func() {
+ defer wg2.Done()
+ for i := 0; i < 100; i++ {
+ assert.NoError(t, inserter.Insert("foo", "bar"))
+ }
+ inserter.Flush()
+ }()
+ wg2.Wait()
+
+ assert.Equal(t, int32(2), atomic.LoadInt32(&updated))
+}
diff --git a/core/stores/sqlx/metrics.go b/core/stores/sqlx/metrics.go
index 823da2b49033..1092c9a201d5 100644
--- a/core/stores/sqlx/metrics.go
+++ b/core/stores/sqlx/metrics.go
@@ -1,8 +1,14 @@
package sqlx
-import "github.com/zeromicro/go-zero/core/metric"
+import (
+ "database/sql"
+ "sync"
-const namespace = "sql_client"
+ "github.com/prometheus/client_golang/prometheus"
+ "github.com/zeromicro/go-zero/core/metric"
+)
+
+const namespace = "mysql_client"
var (
metricReqDur = metric.NewHistogramVec(&metric.HistogramVecOpts{
@@ -11,7 +17,7 @@ var (
Name: "duration_ms",
Help: "mysql client requests duration(ms).",
Labels: []string{"command"},
- Buckets: []float64{5, 10, 25, 50, 100, 250, 500, 1000, 2500},
+ Buckets: []float64{0.25, 0.5, 1, 1.5, 2, 3, 5, 10, 25, 50, 100, 250, 500, 1000, 2000, 5000, 10000, 15000},
})
metricReqErr = metric.NewCounterVec(&metric.CounterVecOpts{
Namespace: namespace,
@@ -20,4 +26,145 @@ var (
Help: "mysql client requests error count.",
Labels: []string{"command", "error"},
})
+ metricSlowCount = metric.NewCounterVec(&metric.CounterVecOpts{
+ Namespace: namespace,
+ Subsystem: "requests",
+ Name: "slow_total",
+ Help: "mysql client requests slow count.",
+ Labels: []string{"command"},
+ })
+
+ connLabels = []string{"db_name", "hash"}
+ connCollector = newCollector()
+ _ prometheus.Collector = (*collector)(nil)
)
+
+type (
+ statGetter struct {
+ dbName string
+ hash string
+ poolStats func() sql.DBStats
+ }
+
+ // collector collects statistics from a redis client.
+ // It implements the prometheus.Collector interface.
+ collector struct {
+ maxOpenConnections *prometheus.Desc
+
+ openConnections *prometheus.Desc
+ inUseConnections *prometheus.Desc
+ idleConnections *prometheus.Desc
+
+ waitCount *prometheus.Desc
+ waitDuration *prometheus.Desc
+ maxIdleClosed *prometheus.Desc
+ maxIdleTimeClosed *prometheus.Desc
+ maxLifetimeClosed *prometheus.Desc
+
+ clients []*statGetter
+ lock sync.Mutex
+ }
+)
+
+func newCollector() *collector {
+ c := &collector{
+ maxOpenConnections: prometheus.NewDesc(
+ prometheus.BuildFQName(namespace, "", "max_open_connections"),
+ "Maximum number of open connections to the database.",
+ connLabels, nil,
+ ),
+ openConnections: prometheus.NewDesc(
+ prometheus.BuildFQName(namespace, "", "open_connections"),
+ "The number of established connections both in use and idle.",
+ connLabels, nil,
+ ),
+ inUseConnections: prometheus.NewDesc(
+ prometheus.BuildFQName(namespace, "", "in_use_connections"),
+ "The number of connections currently in use.",
+ connLabels, nil,
+ ),
+ idleConnections: prometheus.NewDesc(
+ prometheus.BuildFQName(namespace, "", "idle_connections"),
+ "The number of idle connections.",
+ connLabels, nil,
+ ),
+ waitCount: prometheus.NewDesc(
+ prometheus.BuildFQName(namespace, "", "wait_count_total"),
+ "The total number of connections waited for.",
+ connLabels, nil,
+ ),
+ waitDuration: prometheus.NewDesc(
+ prometheus.BuildFQName(namespace, "", "wait_duration_seconds_total"),
+ "The total time blocked waiting for a new connection.",
+ connLabels, nil,
+ ),
+ maxIdleClosed: prometheus.NewDesc(
+ prometheus.BuildFQName(namespace, "", "max_idle_closed_total"),
+ "The total number of connections closed due to SetMaxIdleConns.",
+ connLabels, nil,
+ ),
+ maxIdleTimeClosed: prometheus.NewDesc(
+ prometheus.BuildFQName(namespace, "", "max_idle_time_closed_total"),
+ "The total number of connections closed due to SetConnMaxIdleTime.",
+ connLabels, nil,
+ ),
+ maxLifetimeClosed: prometheus.NewDesc(
+ prometheus.BuildFQName(namespace, "", "max_lifetime_closed_total"),
+ "The total number of connections closed due to SetConnMaxLifetime.",
+ connLabels, nil,
+ ),
+ }
+
+ prometheus.MustRegister(c)
+
+ return c
+}
+
+// Describe implements the prometheus.Collector interface.
+func (c *collector) Describe(ch chan<- *prometheus.Desc) {
+ ch <- c.maxOpenConnections
+ ch <- c.openConnections
+ ch <- c.inUseConnections
+ ch <- c.idleConnections
+ ch <- c.waitCount
+ ch <- c.waitDuration
+ ch <- c.maxIdleClosed
+ ch <- c.maxLifetimeClosed
+ ch <- c.maxIdleTimeClosed
+}
+
+// Collect implements the prometheus.Collector interface.
+func (c *collector) Collect(ch chan<- prometheus.Metric) {
+ c.lock.Lock()
+ defer c.lock.Unlock()
+
+ for _, client := range c.clients {
+ dbName, hash := client.dbName, client.hash
+ stats := client.poolStats()
+ ch <- prometheus.MustNewConstMetric(c.maxOpenConnections, prometheus.GaugeValue,
+ float64(stats.MaxOpenConnections), dbName, hash)
+ ch <- prometheus.MustNewConstMetric(c.openConnections, prometheus.GaugeValue,
+ float64(stats.OpenConnections), dbName, hash)
+ ch <- prometheus.MustNewConstMetric(c.inUseConnections, prometheus.GaugeValue,
+ float64(stats.InUse), dbName, hash)
+ ch <- prometheus.MustNewConstMetric(c.idleConnections, prometheus.GaugeValue,
+ float64(stats.Idle), dbName, hash)
+ ch <- prometheus.MustNewConstMetric(c.waitCount, prometheus.CounterValue,
+ float64(stats.WaitCount), dbName, hash)
+ ch <- prometheus.MustNewConstMetric(c.waitDuration, prometheus.CounterValue,
+ stats.WaitDuration.Seconds(), dbName, hash)
+ ch <- prometheus.MustNewConstMetric(c.maxIdleClosed, prometheus.CounterValue,
+ float64(stats.MaxIdleClosed), dbName, hash)
+ ch <- prometheus.MustNewConstMetric(c.maxLifetimeClosed, prometheus.CounterValue,
+ float64(stats.MaxLifetimeClosed), dbName, hash)
+ ch <- prometheus.MustNewConstMetric(c.maxIdleTimeClosed, prometheus.CounterValue,
+ float64(stats.MaxIdleTimeClosed), dbName, hash)
+ }
+}
+
+func (c *collector) registerClient(client *statGetter) {
+ c.lock.Lock()
+ defer c.lock.Unlock()
+
+ c.clients = append(c.clients, client)
+}
diff --git a/core/stores/sqlx/metrics_test.go b/core/stores/sqlx/metrics_test.go
new file mode 100644
index 000000000000..192d1f321b6c
--- /dev/null
+++ b/core/stores/sqlx/metrics_test.go
@@ -0,0 +1,147 @@
+package sqlx
+
+import (
+ "database/sql"
+ "io"
+ "net/http"
+ "strings"
+ "testing"
+ "time"
+
+ "github.com/prometheus/client_golang/prometheus"
+ "github.com/prometheus/client_golang/prometheus/testutil"
+ "github.com/stretchr/testify/assert"
+ "github.com/zeromicro/go-zero/core/conf"
+ "github.com/zeromicro/go-zero/internal/devserver"
+)
+
+func TestSqlxMetric(t *testing.T) {
+ cfg := devserver.Config{}
+ _ = conf.FillDefault(&cfg)
+ cfg.Port = 6480
+ server := devserver.NewServer(cfg)
+ server.StartAsync()
+ time.Sleep(time.Second)
+
+ metricReqDur.Observe(8, "test-cmd")
+ metricReqErr.Inc("test-cmd", "internal-error")
+ metricSlowCount.Inc("test-cmd")
+
+ url := "http://127.0.0.1:6480/metrics"
+ resp, err := http.Get(url)
+ assert.Nil(t, err)
+ defer resp.Body.Close()
+ s, err := io.ReadAll(resp.Body)
+ assert.Nil(t, err)
+ content := string(s)
+ assert.Contains(t, content, "mysql_client_requests_duration_ms_sum{command=\"test-cmd\"} 8\n")
+ assert.Contains(t, content, "mysql_client_requests_duration_ms_count{command=\"test-cmd\"} 1\n")
+ assert.Contains(t, content, "mysql_client_requests_error_total{command=\"test-cmd\",error=\"internal-error\"} 1\n")
+ assert.Contains(t, content, "mysql_client_requests_slow_total{command=\"test-cmd\"} 1\n")
+}
+
+func TestMetricCollector(t *testing.T) {
+ prometheus.Unregister(connCollector)
+ c := newCollector()
+ c.registerClient(&statGetter{
+ dbName: "db-1",
+ hash: "hash-1",
+ poolStats: func() sql.DBStats {
+ return sql.DBStats{
+ MaxOpenConnections: 1,
+ OpenConnections: 2,
+ InUse: 3,
+ Idle: 4,
+ WaitCount: 5,
+ WaitDuration: 6 * time.Second,
+ MaxIdleClosed: 7,
+ MaxIdleTimeClosed: 8,
+ MaxLifetimeClosed: 9,
+ }
+ },
+ })
+ c.registerClient(&statGetter{
+ dbName: "db-1",
+ hash: "hash-2",
+ poolStats: func() sql.DBStats {
+ return sql.DBStats{
+ MaxOpenConnections: 10,
+ OpenConnections: 20,
+ InUse: 30,
+ Idle: 40,
+ WaitCount: 50,
+ WaitDuration: 60 * time.Second,
+ MaxIdleClosed: 70,
+ MaxIdleTimeClosed: 80,
+ MaxLifetimeClosed: 90,
+ }
+ },
+ })
+ c.registerClient(&statGetter{
+ dbName: "db-2",
+ hash: "hash-2",
+ poolStats: func() sql.DBStats {
+ return sql.DBStats{
+ MaxOpenConnections: 100,
+ OpenConnections: 200,
+ InUse: 300,
+ Idle: 400,
+ WaitCount: 500,
+ WaitDuration: 600 * time.Second,
+ MaxIdleClosed: 700,
+ MaxIdleTimeClosed: 800,
+ MaxLifetimeClosed: 900,
+ }
+ },
+ })
+ val := `
+ # HELP mysql_client_idle_connections The number of idle connections.
+ # TYPE mysql_client_idle_connections gauge
+ mysql_client_idle_connections{db_name="db-1",hash="hash-1"} 4
+ mysql_client_idle_connections{db_name="db-1",hash="hash-2"} 40
+ mysql_client_idle_connections{db_name="db-2",hash="hash-2"} 400
+ # HELP mysql_client_in_use_connections The number of connections currently in use.
+ # TYPE mysql_client_in_use_connections gauge
+ mysql_client_in_use_connections{db_name="db-1",hash="hash-1"} 3
+ mysql_client_in_use_connections{db_name="db-1",hash="hash-2"} 30
+ mysql_client_in_use_connections{db_name="db-2",hash="hash-2"} 300
+ # HELP mysql_client_max_idle_closed_total The total number of connections closed due to SetMaxIdleConns.
+ # TYPE mysql_client_max_idle_closed_total counter
+ mysql_client_max_idle_closed_total{db_name="db-1",hash="hash-1"} 7
+ mysql_client_max_idle_closed_total{db_name="db-1",hash="hash-2"} 70
+ mysql_client_max_idle_closed_total{db_name="db-2",hash="hash-2"} 700
+ # HELP mysql_client_max_idle_time_closed_total The total number of connections closed due to SetConnMaxIdleTime.
+ # TYPE mysql_client_max_idle_time_closed_total counter
+ mysql_client_max_idle_time_closed_total{db_name="db-1",hash="hash-1"} 8
+ mysql_client_max_idle_time_closed_total{db_name="db-1",hash="hash-2"} 80
+ mysql_client_max_idle_time_closed_total{db_name="db-2",hash="hash-2"} 800
+ # HELP mysql_client_max_lifetime_closed_total The total number of connections closed due to SetConnMaxLifetime.
+ # TYPE mysql_client_max_lifetime_closed_total counter
+ mysql_client_max_lifetime_closed_total{db_name="db-1",hash="hash-1"} 9
+ mysql_client_max_lifetime_closed_total{db_name="db-1",hash="hash-2"} 90
+ mysql_client_max_lifetime_closed_total{db_name="db-2",hash="hash-2"} 900
+ # HELP mysql_client_max_open_connections Maximum number of open connections to the database.
+ # TYPE mysql_client_max_open_connections gauge
+ mysql_client_max_open_connections{db_name="db-1",hash="hash-1"} 1
+ mysql_client_max_open_connections{db_name="db-1",hash="hash-2"} 10
+ mysql_client_max_open_connections{db_name="db-2",hash="hash-2"} 100
+ # HELP mysql_client_open_connections The number of established connections both in use and idle.
+ # TYPE mysql_client_open_connections gauge
+ mysql_client_open_connections{db_name="db-1",hash="hash-1"} 2
+ mysql_client_open_connections{db_name="db-1",hash="hash-2"} 20
+ mysql_client_open_connections{db_name="db-2",hash="hash-2"} 200
+ # HELP mysql_client_wait_count_total The total number of connections waited for.
+ # TYPE mysql_client_wait_count_total counter
+ mysql_client_wait_count_total{db_name="db-1",hash="hash-1"} 5
+ mysql_client_wait_count_total{db_name="db-1",hash="hash-2"} 50
+ mysql_client_wait_count_total{db_name="db-2",hash="hash-2"} 500
+ # HELP mysql_client_wait_duration_seconds_total The total time blocked waiting for a new connection.
+ # TYPE mysql_client_wait_duration_seconds_total counter
+ mysql_client_wait_duration_seconds_total{db_name="db-1",hash="hash-1"} 6
+ mysql_client_wait_duration_seconds_total{db_name="db-1",hash="hash-2"} 60
+ mysql_client_wait_duration_seconds_total{db_name="db-2",hash="hash-2"} 600
+`
+
+ err := testutil.CollectAndCompare(c, strings.NewReader(val))
+ assert.NoError(t, err)
+}
diff --git a/core/stores/sqlx/mysql.go b/core/stores/sqlx/mysql.go
index 6f0f731d3004..3c026921e311 100644
--- a/core/stores/sqlx/mysql.go
+++ b/core/stores/sqlx/mysql.go
@@ -1,6 +1,10 @@
package sqlx
-import "github.com/go-sql-driver/mysql"
+import (
+ "errors"
+
+ "github.com/go-sql-driver/mysql"
+)
const (
mysqlDriverName = "mysql"
@@ -18,7 +22,8 @@ func mysqlAcceptable(err error) bool {
return true
}
- myerr, ok := err.(*mysql.MySQLError)
+ var myerr *mysql.MySQLError
+ ok := errors.As(err, &myerr)
if !ok {
return false
}
diff --git a/core/stores/sqlx/mysql_test.go b/core/stores/sqlx/mysql_test.go
index 9fd36b51078b..1a3ed277639e 100644
--- a/core/stores/sqlx/mysql_test.go
+++ b/core/stores/sqlx/mysql_test.go
@@ -23,7 +23,7 @@ func TestBreakerOnDuplicateEntry(t *testing.T) {
func TestBreakerOnNotHandlingDuplicateEntry(t *testing.T) {
var found bool
for i := 0; i < 100; i++ {
- if tryOnDuplicateEntryError(t, nil) == breaker.ErrServiceUnavailable {
+ if errors.Is(tryOnDuplicateEntryError(t, nil), breaker.ErrServiceUnavailable) {
found = true
}
}
diff --git a/core/stores/sqlx/sqlconn.go b/core/stores/sqlx/sqlconn.go
index 2aaa108bd2e3..10a57239f829 100644
--- a/core/stores/sqlx/sqlconn.go
+++ b/core/stores/sqlx/sqlconn.go
@@ -3,6 +3,7 @@ package sqlx
import (
"context"
"database/sql"
+ "errors"
"github.com/zeromicro/go-zero/core/breaker"
"github.com/zeromicro/go-zero/core/logx"
@@ -164,7 +165,7 @@ func (db *commonSqlConn) ExecCtx(ctx context.Context, q string, args ...any) (
result, err = exec(ctx, db.logOption, conn, q, args...)
return err
}, db.acceptable)
- if err == breaker.ErrServiceUnavailable {
+ if errors.Is(err, breaker.ErrServiceUnavailable) {
metricReqErr.Inc("Exec", "breaker")
}
@@ -205,7 +206,7 @@ func (db *commonSqlConn) PrepareCtx(ctx context.Context, query string) (stmt Stm
}
return nil
}, db.acceptable)
- if err == breaker.ErrServiceUnavailable {
+ if errors.Is(err, breaker.ErrServiceUnavailable) {
metricReqErr.Inc("Prepare", "breaker")
}
@@ -295,7 +296,7 @@ func (db *commonSqlConn) TransactCtx(ctx context.Context, fn func(context.Contex
err = db.brk.DoWithAcceptable(func() error {
return transact(ctx, db.logOption, db, db.beginTx, fn)
}, db.acceptable)
- if err == breaker.ErrServiceUnavailable {
+ if errors.Is(err, breaker.ErrServiceUnavailable) {
metricReqErr.Inc("Transact", "breaker")
}
@@ -303,11 +304,13 @@ func (db *commonSqlConn) TransactCtx(ctx context.Context, fn func(context.Contex
}
func (db *commonSqlConn) acceptable(err error) bool {
- if err == nil || err == sql.ErrNoRows || err == sql.ErrTxDone || err == context.Canceled {
+ if err == nil || errors.Is(err, sql.ErrNoRows) || errors.Is(err, sql.ErrTxDone) ||
+ errors.Is(err, context.Canceled) {
return true
}
- if _, ok := err.(acceptableError); ok {
+ var e acceptableError
+ if errors.As(err, &e) {
return true
}
@@ -333,9 +336,9 @@ func (db *commonSqlConn) queryRows(ctx context.Context, scanner func(*sql.Rows)
return qerr
}, q, args...)
}, func(err error) bool {
- return qerr == err || db.acceptable(err)
+ return errors.Is(err, qerr) || db.acceptable(err)
})
- if err == breaker.ErrServiceUnavailable {
+ if errors.Is(err, breaker.ErrServiceUnavailable) {
metricReqErr.Inc("queryRows", "breaker")
}
diff --git a/core/stores/sqlx/stmt.go b/core/stores/sqlx/stmt.go
index 4fe242885604..9942ab422705 100644
--- a/core/stores/sqlx/stmt.go
+++ b/core/stores/sqlx/stmt.go
@@ -158,9 +158,11 @@ func (e *realSqlGuard) start(q string, args ...any) error {
func (e *realSqlGuard) finish(ctx context.Context, err error) {
duration := timex.Since(e.startTime)
+
logger := logx.WithContext(ctx).WithDuration(duration)
if e.slowLog(duration) {
logger.Slowf("[SQL] %s: slowcall - %s", e.command, e.stmt)
+ metricSlowCount.Inc(e.command)
} else if e.statementLog() {
logger.Infof("sql %s: %s", e.command, e.stmt)
}
@@ -169,7 +171,7 @@ func (e *realSqlGuard) finish(ctx context.Context, err error) {
logSqlError(ctx, e.stmt, err)
}
- metricReqDur.Observe(duration.Milliseconds(), e.command)
+ metricReqDur.ObserveFloat(float64(duration)/float64(time.Millisecond), e.command)
}
func (e *realSqlGuard) slowLog(duration time.Duration) bool {
diff --git a/core/stores/sqlx/trace.go b/core/stores/sqlx/trace.go
index 6a3a0406454f..8a936d543b72 100644
--- a/core/stores/sqlx/trace.go
+++ b/core/stores/sqlx/trace.go
@@ -3,6 +3,7 @@ package sqlx
import (
"context"
"database/sql"
+ "errors"
"github.com/zeromicro/go-zero/core/trace"
"go.opentelemetry.io/otel/attribute"
@@ -23,7 +24,7 @@ func startSpan(ctx context.Context, method string) (context.Context, oteltrace.S
func endSpan(span oteltrace.Span, err error) {
defer span.End()
- if err == nil || err == sql.ErrNoRows {
+ if err == nil || errors.Is(err, sql.ErrNoRows) {
span.SetStatus(codes.Ok, "")
return
}
diff --git a/core/stores/sqlx/utils.go b/core/stores/sqlx/utils.go
index 5205aed21002..f58adc59c342 100644
--- a/core/stores/sqlx/utils.go
+++ b/core/stores/sqlx/utils.go
@@ -143,7 +143,7 @@ func logInstanceError(ctx context.Context, datasource string, err error) {
}
func logSqlError(ctx context.Context, stmt string, err error) {
- if err != nil && err != ErrNotFound {
+ if err != nil && !errors.Is(err, ErrNotFound) {
logx.WithContext(ctx).Errorf("stmt: %s, error: %s", stmt, err.Error())
}
}
diff --git a/core/stringx/replacer_fuzz_test.go b/core/stringx/replacer_fuzz_test.go
index da81ad9cbf02..6243039e6dc7 100644
--- a/core/stringx/replacer_fuzz_test.go
+++ b/core/stringx/replacer_fuzz_test.go
@@ -1,5 +1,3 @@
-//go:build go1.18
-
package stringx
import (
diff --git a/core/syncx/lockedcalls_test.go b/core/syncx/lockedcalls_test.go
index 3ae0debc0d55..93f6fe04314f 100644
--- a/core/syncx/lockedcalls_test.go
+++ b/core/syncx/lockedcalls_test.go
@@ -27,7 +27,7 @@ func TestLockedCallDoErr(t *testing.T) {
v, err := g.Do("key", func() (any, error) {
return nil, someErr
})
- if err != someErr {
+ if !errors.Is(err, someErr) {
t.Errorf("Do error = %v; want someErr", err)
}
if v != nil {
diff --git a/core/syncx/singleflight_test.go b/core/syncx/singleflight_test.go
index ba68f9d1f77a..591c2736a463 100644
--- a/core/syncx/singleflight_test.go
+++ b/core/syncx/singleflight_test.go
@@ -28,7 +28,7 @@ func TestExclusiveCallDoErr(t *testing.T) {
v, err := g.Do("key", func() (any, error) {
return nil, someErr
})
- if err != someErr {
+ if !errors.Is(err, someErr) {
t.Errorf("Do error = %v; want someErr", err)
}
if v != nil {
diff --git a/core/trace/agent.go b/core/trace/agent.go
index 19ae59cde08c..2a2e8c372616 100644
--- a/core/trace/agent.go
+++ b/core/trace/agent.go
@@ -113,11 +113,13 @@ func createExporter(c Config) (sdktrace.SpanExporter, error) {
}
func startAgent(c Config) error {
+ AddResources(semconv.ServiceNameKey.String(c.Name))
+
opts := []sdktrace.TracerProviderOption{
// Set the sampling rate based on the parent span to 100%
sdktrace.WithSampler(sdktrace.ParentBased(sdktrace.TraceIDRatioBased(c.Sampler))),
// Record information about this application in a Resource.
- sdktrace.WithResource(resource.NewSchemaless(semconv.ServiceNameKey.String(c.Name))),
+ sdktrace.WithResource(resource.NewSchemaless(attrResources...)),
}
if len(c.Endpoint) > 0 {
diff --git a/core/trace/resource.go b/core/trace/resource.go
new file mode 100644
index 000000000000..84d4d45350ca
--- /dev/null
+++ b/core/trace/resource.go
@@ -0,0 +1,10 @@
+package trace
+
+import "go.opentelemetry.io/otel/attribute"
+
+var attrResources = make([]attribute.KeyValue, 0)
+
+// AddResources add more resources in addition to configured trace name.
+func AddResources(attrs ...attribute.KeyValue) {
+ attrResources = append(attrResources, attrs...)
+}
diff --git a/go.mod b/go.mod
index fe1072a393af..fb31bff2c8a8 100644
--- a/go.mod
+++ b/go.mod
@@ -1,120 +1,121 @@
module github.com/zeromicro/go-zero
-go 1.18
+go 1.19
require (
github.com/DATA-DOG/go-sqlmock v1.5.0
- github.com/alicebob/miniredis/v2 v2.30.5
- github.com/fatih/color v1.15.0
- github.com/fullstorydev/grpcurl v1.8.7
+ github.com/alicebob/miniredis/v2 v2.31.0
+ github.com/fatih/color v1.16.0
+ github.com/fullstorydev/grpcurl v1.8.9
github.com/go-redis/redis/v8 v8.11.5
github.com/go-sql-driver/mysql v1.7.1
github.com/golang-jwt/jwt/v4 v4.5.0
github.com/golang/mock v1.6.0
github.com/golang/protobuf v1.5.3
- github.com/google/uuid v1.3.1
- github.com/jackc/pgx/v5 v5.4.3
- github.com/jhump/protoreflect v1.15.2
+ github.com/google/uuid v1.4.0
+ github.com/jackc/pgx/v5 v5.5.0
+ github.com/jhump/protoreflect v1.15.3
github.com/olekukonko/tablewriter v0.0.5
github.com/pelletier/go-toml/v2 v2.1.0
- github.com/prometheus/client_golang v1.16.0
+ github.com/prometheus/client_golang v1.17.0
github.com/spaolacci/murmur3 v1.1.0
github.com/stretchr/testify v1.8.4
- go.etcd.io/etcd/api/v3 v3.5.9
- go.etcd.io/etcd/client/v3 v3.5.9
- go.mongodb.org/mongo-driver v1.12.1
- go.opentelemetry.io/otel v1.14.0
- go.opentelemetry.io/otel/exporters/jaeger v1.14.0
- go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.14.0
- go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.14.0
- go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.14.0
- go.opentelemetry.io/otel/exporters/zipkin v1.14.0
- go.opentelemetry.io/otel/sdk v1.14.0
- go.opentelemetry.io/otel/trace v1.14.0
+ go.etcd.io/etcd/api/v3 v3.5.10
+ go.etcd.io/etcd/client/v3 v3.5.10
+ go.mongodb.org/mongo-driver v1.13.0
+ go.opentelemetry.io/otel v1.19.0
+ go.opentelemetry.io/otel/exporters/jaeger v1.17.0
+ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.19.0
+ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0
+ go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.19.0
+ go.opentelemetry.io/otel/exporters/zipkin v1.19.0
+ go.opentelemetry.io/otel/sdk v1.19.0
+ go.opentelemetry.io/otel/trace v1.19.0
go.uber.org/automaxprocs v1.5.3
go.uber.org/goleak v1.2.1
- golang.org/x/net v0.15.0
- golang.org/x/sys v0.12.0
- golang.org/x/time v0.3.0
- google.golang.org/genproto/googleapis/api v0.0.0-20230525234035-dd9d682886f9
- google.golang.org/grpc v1.57.0
+ golang.org/x/net v0.19.0
+ golang.org/x/sys v0.15.0
+ golang.org/x/time v0.5.0
+ google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b
+ google.golang.org/grpc v1.59.0
google.golang.org/protobuf v1.31.0
gopkg.in/cheggaaa/pb.v1 v1.0.28
gopkg.in/h2non/gock.v1 v1.1.2
gopkg.in/yaml.v2 v2.4.0
- k8s.io/api v0.26.3
- k8s.io/apimachinery v0.27.0-alpha.3
- k8s.io/client-go v0.26.3
- k8s.io/utils v0.0.0-20230209194617-a36077c30491
+ k8s.io/api v0.28.4
+ k8s.io/apimachinery v0.28.4
+ k8s.io/client-go v0.28.4
+ k8s.io/utils v0.0.0-20230726121419-3b25d923346b
)
require (
- github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a // indirect
+ github.com/alicebob/gopher-json v0.0.0-20230218143504-906a9b012302 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bufbuild/protocompile v0.6.0 // indirect
- github.com/cenkalti/backoff/v4 v4.2.0 // indirect
+ github.com/cenkalti/backoff/v4 v4.2.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/coreos/go-semver v0.3.1 // indirect
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/emicklei/go-restful/v3 v3.9.0 // indirect
- github.com/go-logr/logr v1.2.3 // indirect
+ github.com/go-logr/logr v1.2.4 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-openapi/jsonpointer v0.19.6 // indirect
- github.com/go-openapi/jsonreference v0.20.1 // indirect
- github.com/go-openapi/swag v0.22.3 // indirect
+ github.com/go-openapi/jsonreference v0.20.2 // indirect
+ github.com/go-openapi/swag v0.22.4 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/snappy v0.0.4 // indirect
- github.com/google/gnostic v0.5.7-v3refs // indirect
+ github.com/google/gnostic-models v0.6.8 // indirect
github.com/google/go-cmp v0.5.9 // indirect
github.com/google/gofuzz v1.2.0 // indirect
- github.com/grpc-ecosystem/grpc-gateway/v2 v2.15.0 // indirect
+ github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.0 // indirect
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
+ github.com/jackc/puddle/v2 v2.2.1 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
- github.com/klauspost/compress v1.15.15 // indirect
+ github.com/klauspost/compress v1.16.7 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
- github.com/mattn/go-isatty v0.0.17 // indirect
- github.com/mattn/go-runewidth v0.0.13 // indirect
+ github.com/mattn/go-isatty v0.0.20 // indirect
+ github.com/mattn/go-runewidth v0.0.15 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // 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/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
- github.com/openzipkin/zipkin-go v0.4.1 // indirect
+ github.com/openzipkin/zipkin-go v0.4.2 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
- github.com/prometheus/client_model v0.3.0 // indirect
- github.com/prometheus/common v0.42.0 // indirect
- github.com/prometheus/procfs v0.10.1 // indirect
+ github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 // indirect
+ github.com/prometheus/common v0.44.0 // indirect
+ github.com/prometheus/procfs v0.11.1 // indirect
github.com/rivo/uniseg v0.2.0 // indirect
github.com/xdg-go/pbkdf2 v1.0.0 // 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/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a // indirect
github.com/yuin/gopher-lua v1.1.0 // indirect
- go.etcd.io/etcd/client/pkg/v3 v3.5.9 // indirect
- go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.14.0 // indirect
- go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.14.0 // indirect
- go.opentelemetry.io/proto/otlp v0.19.0 // indirect
+ go.etcd.io/etcd/client/pkg/v3 v3.5.10 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 // indirect
+ go.opentelemetry.io/otel/metric v1.19.0 // indirect
+ go.opentelemetry.io/proto/otlp v1.0.0 // indirect
go.uber.org/atomic v1.10.0 // indirect
go.uber.org/multierr v1.9.0 // indirect
go.uber.org/zap v1.24.0 // indirect
- golang.org/x/crypto v0.13.0 // indirect
- golang.org/x/oauth2 v0.7.0 // indirect
+ golang.org/x/crypto v0.16.0 // indirect
+ golang.org/x/oauth2 v0.12.0 // indirect
golang.org/x/sync v0.3.0 // indirect
- golang.org/x/term v0.12.0 // indirect
- golang.org/x/text v0.13.0 // indirect
- google.golang.org/appengine v1.6.7 // indirect
- google.golang.org/genproto v0.0.0-20230526161137-0005af68ea54 // indirect
- google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 // indirect
+ golang.org/x/term v0.15.0 // indirect
+ golang.org/x/text v0.14.0 // indirect
+ google.golang.org/appengine v1.6.8 // indirect
+ google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b // indirect
+ google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
- k8s.io/klog/v2 v2.90.1 // indirect
- k8s.io/kube-openapi v0.0.0-20230307230338-69ee2d25a840 // indirect
+ k8s.io/klog/v2 v2.100.1 // indirect
+ k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 // indirect
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect
sigs.k8s.io/yaml v1.3.0 // indirect
diff --git a/go.sum b/go.sum
index cffa8117ce2c..7ecbd282674f 100644
--- a/go.sum
+++ b/go.sum
@@ -1,70 +1,23 @@
-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.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/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/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/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=
-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/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60=
github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
-github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
-github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a h1:HbKu58rmZpUGpz5+4FfNmIU+FmZg2P3Xaj2v2bfNWmk=
+github.com/DmitriyVTitov/size v1.5.0/go.mod h1:le6rNI4CoLQV1b9gzp1+3d7hMAD/uu2QcJ+aYbNgiU0=
github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc=
-github.com/alicebob/miniredis/v2 v2.30.5 h1:3r6kTHdKnuP4fkS8k2IrvSfxpxUTcW1SOL0wN7b7Dt0=
-github.com/alicebob/miniredis/v2 v2.30.5/go.mod h1:b25qWj4fCEsBeAAR2mlb0ufImGC6uH3VlUfb/HS5zKg=
-github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
+github.com/alicebob/gopher-json v0.0.0-20230218143504-906a9b012302 h1:uvdUDbHQHO85qeSydJtItA4T55Pw6BtAejd0APRJOCE=
+github.com/alicebob/gopher-json v0.0.0-20230218143504-906a9b012302/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc=
+github.com/alicebob/miniredis/v2 v2.31.0 h1:ObEFUNlJwoIiyjxdrYF0QIDE7qXcLc7D3WpSH4c22PU=
+github.com/alicebob/miniredis/v2 v2.31.0/go.mod h1:UB/T2Uztp7MlFSDakaX1sTXUv5CASoprx0wulRT6HBg=
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
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/bufbuild/protocompile v0.6.0 h1:Uu7WiSQ6Yj9DbkdnOe7U4mNKp58y9WDMKDn28/ZlunY=
github.com/bufbuild/protocompile v0.6.0/go.mod h1:YNP35qEYoYGme7QMtz5SBCoN4kL4g12jTtjuzRNdjpE=
-github.com/cenkalti/backoff/v4 v4.2.0 h1:HN5dHm3WBOgndBH6E8V0q2jIYIR3s9yglV8k/+MN3u4=
-github.com/cenkalti/backoff/v4 v4.2.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/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
+github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
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/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-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.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4=
github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec=
github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
@@ -75,77 +28,41 @@ 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/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
-github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
github.com/emicklei/go-restful/v3 v3.9.0 h1:XwGDlfxEnQZzuopoqxwSEllNcCOM9DhhFyhFIIGKwxE=
github.com/emicklei/go-restful/v3 v3.9.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
-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.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.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
-github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
+github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
+github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
-github.com/fullstorydev/grpcurl v1.8.7 h1:xJWosq3BQovQ4QrdPO72OrPiWuGgEsxY8ldYsJbPrqI=
-github.com/fullstorydev/grpcurl v1.8.7/go.mod h1:pVtM4qe3CMoLaIzYS8uvTuDj2jVYmXqMUkZeijnXp/E=
-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/fullstorydev/grpcurl v1.8.9 h1:JMvZXK8lHDGyLmTQ0ZdGDnVVGuwjbpaumf8p42z0d+c=
+github.com/fullstorydev/grpcurl v1.8.9/go.mod h1:PNNKevV5VNAV2loscyLISrEnWQI61eqR0F8l3bVadAA=
github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
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.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
+github.com/go-logr/logr v1.2.4/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-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE=
github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
-github.com/go-openapi/jsonreference v0.20.1 h1:FBLnyygC4/IZZr893oiomc9XaghoveYTrLC1F86HID8=
-github.com/go-openapi/jsonreference v0.20.1/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k=
-github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g=
+github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE=
+github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k=
github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
+github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU=
+github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI=
github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo=
github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI=
github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
+github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
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/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
-github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
-github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4=
-github.com/golang/glog v1.1.0 h1:/d3pCKDPWNnvIWe0vVUpNP32qc8U3PDVxySP/y360qE=
-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/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/glog v1.1.2 h1:DVjP2PbBOzHyzA+dn3WhHIq4NdVu3Q+pvivFICf/7fo=
+github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
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=
-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/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
@@ -153,75 +70,41 @@ github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiu
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
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/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
-github.com/google/gnostic v0.5.7-v3refs h1:FhTMOKj2VhjpouxvWJAV1TL304uMlb9zcDqkl6cEI54=
-github.com/google/gnostic v0.5.7-v3refs/go.mod h1:73MKFl6jIHelAJNaBGFzt3SPtZULs9dYrGFt8OiIsHQ=
-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/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I=
+github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U=
github.com/google/go-cmp v0.5.2/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.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/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
github.com/google/gofuzz v1.2.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/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/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.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4=
-github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-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/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
-github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks=
-github.com/grpc-ecosystem/grpc-gateway/v2 v2.15.0 h1:1JYBfzqrWPcCclBwxFCPAou9n+q86mfnu7NAeHfte7A=
-github.com/grpc-ecosystem/grpc-gateway/v2 v2.15.0/go.mod h1:YDZoGHuwE+ov0c8smSH49WLF3F2LaWnYYuDVd+EWrc0=
+github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec=
+github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4=
+github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.0 h1:RtRsiaGvWxcwd8y3BiRZxsylPT8hLWZ5SPcfI+3IDNk=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.0/go.mod h1:TzP6duP4Py2pHLVPPQp42aoYI92+PCrVotyR5e8Vqlk=
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw=
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI=
-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/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
-github.com/jackc/pgx/v5 v5.4.3 h1:cxFyXhxlvAifxnkKKdlxv8XqUf59tDlYjnV5YYfsJJY=
-github.com/jackc/pgx/v5 v5.4.3/go.mod h1:Ig06C2Vu0t5qXC60W8sqIthScaEnFvojjj9dSljmHRA=
-github.com/jhump/gopoet v0.0.0-20190322174617-17282ff210b3/go.mod h1:me9yfT6IJSlOL3FCfrg+L6yzUEZ+5jW6WHt4Sk+UPUI=
-github.com/jhump/gopoet v0.1.0/go.mod h1:me9yfT6IJSlOL3FCfrg+L6yzUEZ+5jW6WHt4Sk+UPUI=
-github.com/jhump/goprotoc v0.5.0/go.mod h1:VrbvcYrQOrTi3i0Vf+m+oqQWk9l72mjkJCYo7UvLHRQ=
-github.com/jhump/protoreflect v1.11.0/go.mod h1:U7aMIjN0NWq9swDP7xDdoMfRHb35uiuTd3Z9nFXJf5E=
-github.com/jhump/protoreflect v1.12.0/go.mod h1:JytZfP5d0r8pVNLZvai7U/MCuTWITgrI4tTg7puQFKI=
-github.com/jhump/protoreflect v1.15.2 h1:7YppbATX94jEt9KLAc5hICx4h6Yt3SaavhQRsIUEHP0=
-github.com/jhump/protoreflect v1.15.2/go.mod h1:4ORHmSBmlCW8fh3xHmJMGyul1zNqZK4Elxc8qKP+p1k=
+github.com/jackc/pgx/v5 v5.5.0 h1:NxstgwndsTRy7eq9/kqYc/BZh5w2hHJV86wjvO+1xPw=
+github.com/jackc/pgx/v5 v5.5.0/go.mod h1:Ig06C2Vu0t5qXC60W8sqIthScaEnFvojjj9dSljmHRA=
+github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk=
+github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
+github.com/jhump/protoreflect v1.15.3 h1:6SFRuqU45u9hIZPJAoZ8c28T3nK64BNdp9w6jFonzls=
+github.com/jhump/protoreflect v1.15.3/go.mod h1:4ORHmSBmlCW8fh3xHmJMGyul1zNqZK4Elxc8qKP+p1k=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
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/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.15.15 h1:EF27CXIuDsYJ6mmvtBRlEuB2UVOqHG1tAXgZ7yIO+lw=
-github.com/klauspost/compress v1.15.15/go.mod h1:ZcK2JAFqKOpnBlxcLsJzYfrS9X1akm9fHZNnD9+Vo/4=
-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/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I=
+github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
@@ -233,11 +116,11 @@ github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJ
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.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/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
+github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
-github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
-github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
+github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
+github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@@ -255,42 +138,35 @@ github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
-github.com/onsi/ginkgo/v2 v2.7.0 h1:/XxtEV3I3Eif/HobnVx9YmJgk8ENdRsuUmM+fLCFNow=
-github.com/onsi/gomega v1.26.0 h1:03cDLK28U6hWvCAns6NeydX3zIm4SF3ci69ulidS32Q=
-github.com/openzipkin/zipkin-go v0.4.1 h1:kNd/ST2yLLWhaWrkgchya40TJabe8Hioj9udfPcEO5A=
-github.com/openzipkin/zipkin-go v0.4.1/go.mod h1:qY0VqDSN1pOBN94dBc6w2GJlWLiovAyg7Qt6/I9HecM=
+github.com/onsi/ginkgo/v2 v2.11.0 h1:WgqUCUt/lT6yXoQ8Wef0fsNn5cAuMK7+KT9UFRz2tcU=
+github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI=
+github.com/openzipkin/zipkin-go v0.4.2 h1:zjqfqHjUpPmB3c1GlCvvgsM1G4LkvqQbBDueDOCg/jA=
+github.com/openzipkin/zipkin-go v0.4.2/go.mod h1:ZeVkFjuuBiSy13y8vpSDCjMi9GoI3hPpCJSBx/EYFhY=
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/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
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/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g=
-github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8=
-github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc=
-github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/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.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM=
-github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc=
-github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+PymziUAg=
-github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM=
+github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q=
+github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY=
+github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 h1:v7DLqVdK4VrYkVD5diGdl4sxJurKJEMnODWRJlxV9oM=
+github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU=
+github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY=
+github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY=
+github.com/prometheus/procfs v0.11.1 h1:xRC8Iq1yyca5ypa9n1EZnWZkt7dwcoRPQwX/5gwaUuI=
+github.com/prometheus/procfs v0.11.1/go.mod h1:eesXgaPo1q7lBpVMoMy0ZOFTth9hBn4W/y0/p/ScXhY=
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
-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.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
-github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
+github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
-github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
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.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=
@@ -303,52 +179,45 @@ 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/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a h1:fZHgsYlfvtyqToslyjUt3VOPF4J7aK/3MPcK7xp3PDk=
+github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a/go.mod h1:ul22v+Nro/R083muKhosV54bj5niojjWZvU8xrevuH4=
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/yuin/gopher-lua v1.1.0 h1:BojcDhfyDWgU2f2TOzYK/g5p2gxMrku8oupLDqlnSqE=
github.com/yuin/gopher-lua v1.1.0/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw=
-go.etcd.io/etcd/api/v3 v3.5.9 h1:4wSsluwyTbGGmyjJktOf3wFQoTBIURXHnq9n/G/JQHs=
-go.etcd.io/etcd/api/v3 v3.5.9/go.mod h1:uyAal843mC8uUVSLWz6eHa/d971iDGnCRpmKd2Z+X8k=
-go.etcd.io/etcd/client/pkg/v3 v3.5.9 h1:oidDC4+YEuSIQbsR94rY9gur91UPL6DnxDCIYd2IGsE=
-go.etcd.io/etcd/client/pkg/v3 v3.5.9/go.mod h1:y+CzeSmkMpWN2Jyu1npecjB9BBnABxGM4pN8cGuJeL4=
-go.etcd.io/etcd/client/v3 v3.5.9 h1:r5xghnU7CwbUxD/fbUtRyJGaYNfDun8sp/gTr1hew6E=
-go.etcd.io/etcd/client/v3 v3.5.9/go.mod h1:i/Eo5LrZ5IKqpbtpPDuaUnDOUv471oDg8cjQaUr2MbA=
-go.mongodb.org/mongo-driver v1.12.1 h1:nLkghSU8fQNaK7oUmDhQFsnrtcoNy7Z6LVFKsEecqgE=
-go.mongodb.org/mongo-driver v1.12.1/go.mod h1:/rGBTebI3XYboVmgz+Wv3Bcbl3aD0QF9zl6kDDw18rQ=
-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.opentelemetry.io/otel v1.14.0 h1:/79Huy8wbf5DnIPhemGB+zEPVwnN6fuQybr/SRXa6hM=
-go.opentelemetry.io/otel v1.14.0/go.mod h1:o4buv+dJzx8rohcUeRmWUZhqupFvzWis188WlggnNeU=
-go.opentelemetry.io/otel/exporters/jaeger v1.14.0 h1:CjbUNd4iN2hHmWekmOqZ+zSCU+dzZppG8XsV+A3oc8Q=
-go.opentelemetry.io/otel/exporters/jaeger v1.14.0/go.mod h1:4Ay9kk5vELRrbg5z4cpP9EtmQRFap2Wb0woPG4lujZA=
-go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.14.0 h1:/fXHZHGvro6MVqV34fJzDhi7sHGpX3Ej/Qjmfn003ho=
-go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.14.0/go.mod h1:UFG7EBMRdXyFstOwH028U0sVf+AvukSGhF0g8+dmNG8=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.14.0 h1:TKf2uAs2ueguzLaxOCBXNpHxfO/aC7PAdDsSH0IbeRQ=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.14.0/go.mod h1:HrbCVv40OOLTABmOn1ZWty6CHXkU8DK/Urc43tHug70=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.14.0 h1:ap+y8RXX3Mu9apKVtOkM6WSFESLM8K3wNQyOU8sWHcc=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.14.0/go.mod h1:5w41DY6S9gZrbjuq6Y+753e96WfPha5IcsOSZTtullM=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.14.0 h1:3jAYbRHQAqzLjd9I4tzxwJ8Pk/N6AqBcF6m1ZHrxG94=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.14.0/go.mod h1:+N7zNjIJv4K+DeX67XXET0P+eIciESgaFDBqh+ZJFS4=
-go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.14.0 h1:sEL90JjOO/4yhquXl5zTAkLLsZ5+MycAgX99SDsxGc8=
-go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.14.0/go.mod h1:oCslUcizYdpKYyS9e8srZEqM6BB8fq41VJBjLAE6z1w=
-go.opentelemetry.io/otel/exporters/zipkin v1.14.0 h1:reEVE1upBF9tcujgvSqLJS0SrI7JQPaTKP4s4rymnSs=
-go.opentelemetry.io/otel/exporters/zipkin v1.14.0/go.mod h1:RcjvOAcvhzcufQP8aHmzRw1gE9g/VEZufDdo2w+s4sk=
-go.opentelemetry.io/otel/sdk v1.14.0 h1:PDCppFRDq8A1jL9v6KMI6dYesaq+DFcDZvjsoGvxGzY=
-go.opentelemetry.io/otel/sdk v1.14.0/go.mod h1:bwIC5TjrNG6QDCHNWvW4HLHtUQ4I+VQDsnjhvyZCALM=
-go.opentelemetry.io/otel/trace v1.14.0 h1:wp2Mmvj41tDsyAJXiWDWpfNsOiIyd38fy85pyKcFq/M=
-go.opentelemetry.io/otel/trace v1.14.0/go.mod h1:8avnQLK+CG77yNLUae4ea2JDQ6iT+gozhnZjy/rw9G8=
-go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
-go.opentelemetry.io/proto/otlp v0.19.0 h1:IVN6GR+mhC4s5yfcTbmzHYODqvWAp3ZedA2SJPI1Nnw=
-go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U=
+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/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.13.0 h1:67DgFFjYOCMWdtTEmKFpV3ffWlFnh+CYZ8ZS/tXWUfY=
+go.mongodb.org/mongo-driver v1.13.0/go.mod h1:/rGBTebI3XYboVmgz+Wv3Bcbl3aD0QF9zl6kDDw18rQ=
+go.opentelemetry.io/otel v1.19.0 h1:MuS/TNf4/j4IXsZuJegVzI1cwut7Qc00344rgH7p8bs=
+go.opentelemetry.io/otel v1.19.0/go.mod h1:i0QyjOq3UPoTzff0PJB2N66fb4S0+rSbSB15/oyH9fY=
+go.opentelemetry.io/otel/exporters/jaeger v1.17.0 h1:D7UpUy2Xc2wsi1Ras6V40q806WM07rqoCWzXu7Sqy+4=
+go.opentelemetry.io/otel/exporters/jaeger v1.17.0/go.mod h1:nPCqOnEH9rNLKqH/+rrUjiMzHJdV1BlpKcTwRTyKkKI=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 h1:Mne5On7VWdx7omSrSSZvM4Kw7cS7NQkOOmLcgscI51U=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0/go.mod h1:IPtUMKL4O3tH5y+iXVyAXqpAwMuzC1IrxVS81rummfE=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.19.0 h1:3d+S281UTjM+AbF31XSOYn1qXn3BgIdWl8HNEpx08Jk=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.19.0/go.mod h1:0+KuTDyKL4gjKCF75pHOX4wuzYDUZYfAQdSu43o+Z2I=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0 h1:IeMeyr1aBvBiPVYihXIaeIZba6b8E1bYp7lbdxK8CQg=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0/go.mod h1:oVdCUtjq9MK9BlS7TtucsQwUcXcymNiEDjgDD2jMtZU=
+go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.19.0 h1:Nw7Dv4lwvGrI68+wULbcq7su9K2cebeCUrDjVrUJHxM=
+go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.19.0/go.mod h1:1MsF6Y7gTqosgoZvHlzcaaM8DIMNZgJh87ykokoNH7Y=
+go.opentelemetry.io/otel/exporters/zipkin v1.19.0 h1:EGY0h5mGliP9o/nIkVuLI0vRiQqmsYOcbwCuotksO1o=
+go.opentelemetry.io/otel/exporters/zipkin v1.19.0/go.mod h1:JQgTGJP11yi3o4GHzIWYodhPisxANdqxF1eHwDSnJrI=
+go.opentelemetry.io/otel/metric v1.19.0 h1:aTzpGtV0ar9wlV4Sna9sdJyII5jTVJEvKETPiOKwvpE=
+go.opentelemetry.io/otel/metric v1.19.0/go.mod h1:L5rUsV9kM1IxCj1MmSdS+JQAcVm319EUrDVLrt7jqt8=
+go.opentelemetry.io/otel/sdk v1.19.0 h1:6USY6zH+L8uMH8L3t1enZPR3WFEmSTADlqldyHtJi3o=
+go.opentelemetry.io/otel/sdk v1.19.0/go.mod h1:NedEbbS4w3C6zElbLdPJKOpJQOrGUJ+GfzpjUvI0v1A=
+go.opentelemetry.io/otel/trace v1.19.0 h1:DFVQmlVbfVeOuBRrwdtaehRrWiL1JoVs9CPIQ1Dzxpg=
+go.opentelemetry.io/otel/trace v1.19.0/go.mod h1:mfaSyvGyEJEI0nyV2I4qhNQnbBOUUmYZpYojqMnX2vo=
+go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I=
+go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM=
go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ=
go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
go.uber.org/automaxprocs v1.5.3 h1:kWazyxZUrS3Gs4qUpbwo5kEIMGe/DAvi5Z4tl2NW4j8=
@@ -360,129 +229,42 @@ go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTV
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-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-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
-golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck=
-golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
-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/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/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY=
+golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
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.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
-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-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-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-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-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-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
-golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8=
-golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
-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-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
-golang.org/x/oauth2 v0.7.0 h1:qe6s0zUXlPX80/dITx3440hWZ7GwMwgDDyrSGTPJG/g=
-golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4=
-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/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c=
+golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
+golang.org/x/oauth2 v0.12.0 h1:smVPGxink+n1ZI5pkQa8y6fZT0RW0MgCO5bFpepy4B4=
+golang.org/x/oauth2 v0.12.0/go.mod h1:A74bZ3aGXgCY0qaIC9Ahg6Lglin4AMAco8cIv9baba4=
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-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.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
-golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/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-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-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-20191001151750-bb3f8db39f24/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-20200113162924-86b910548bc1/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-20200803210538-64077c9b5642/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-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -490,219 +272,76 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
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-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
-golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
+golang.org/x/sys v0.15.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.12.0 h1:/ZfYdc3zq+q02Rv9vGqTeSItdzZTSNDmfTi0mBAuidU=
-golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
-golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4=
+golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
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.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.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
-golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
-golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
-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.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
-golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
+golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
+golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
+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-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-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-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
+golang.org/x/tools v0.9.3 h1:Gn1I8+64MsuTb/HpH+LmQtNas23LhUVr3rYZ0eKuaMM=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-google.golang.org/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/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-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
-google.golang.org/genproto v0.0.0-20230526161137-0005af68ea54 h1:9NWlQfY2ePejTmfwUH1OWwmznFa+0kKcHGPDvcPza9M=
-google.golang.org/genproto v0.0.0-20230526161137-0005af68ea54/go.mod h1:zqTuNwFlFRsw5zIts5VnzLQxSRqh+CGOTVMlYbY0Eyk=
-google.golang.org/genproto/googleapis/api v0.0.0-20230525234035-dd9d682886f9 h1:m8v1xLLLzMe1m5P+gCTF8nJB9epwZQUBERm20Oy1poQ=
-google.golang.org/genproto/googleapis/api v0.0.0-20230525234035-dd9d682886f9/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 h1:0nDDozoAU19Qb2HwhXadU8OcsiO/09cnTqhUtq2MEOM=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA=
-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.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
-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.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
-google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
-google.golang.org/grpc v1.57.0 h1:kfzNeI/klCGD2YPMUlaGNT3pxvYfga7smW3Vth8Zsiw=
-google.golang.org/grpc v1.57.0/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt16Mo=
-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/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-20231016165738-49dd2c1f3d0b h1:+YaDE2r2OG8t/z5qmsh7Y+XXwCbvadxxZ0YY6mTdrVA=
+google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:CgAqfJo+Xmu0GwA0411Ht3OU3OntXwsGmrmjI8ioGXI=
+google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b h1:CIC2YMXmIhYw6evmhPxBKJ4fmLbOFtXQN/GV3XOZR8k=
+google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:IBQ646DjkDkvUIsVq/cc03FUFQ9wbZu7yE396YcL870=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b h1:ZlWIi1wSK56/8hn4QcBp/j9M7Gt3U/3hZw3mC7vDICo=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:swOH3j0KzcDDgGUWr+SNpyTen5YrXjS3eyPzFYKc6lc=
+google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk=
+google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98=
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.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
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-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/cheggaaa/pb.v1 v1.0.28 h1:n1tBJnnK2r7g9OW2btFH91V92STTUevLXYFb8gy9EMk=
gopkg.in/cheggaaa/pb.v1 v1.0.28/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
-gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/h2non/gock.v1 v1.1.2 h1:jBbHXgGBK/AoPVfJh5x4r/WxIrElvbLel8TCZkkZJoY=
gopkg.in/h2non/gock.v1 v1.1.2/go.mod h1:n7UGz/ckNChHiK05rDoiC4MYSunEC/lyaUm2WWaDva0=
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
-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.8/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-20200615113413-eeeca48fe776/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=
-k8s.io/api v0.26.3 h1:emf74GIQMTik01Aum9dPP0gAypL8JTLl/lHa4V9RFSU=
-k8s.io/api v0.26.3/go.mod h1:PXsqwPMXBSBcL1lJ9CYDKy7kIReUydukS5JiRlxC3qE=
-k8s.io/apimachinery v0.27.0-alpha.3 h1:uujqsdFrbqF+cEbqFHrkLKp+s3XxRgphTpc6Yg84qLo=
-k8s.io/apimachinery v0.27.0-alpha.3/go.mod h1:TO4higCGNMwebVSdb1XPJdXMU4kk+nmMY/cTMVCGa6M=
-k8s.io/client-go v0.26.3 h1:k1UY+KXfkxV2ScEL3gilKcF7761xkYsSD6BC9szIu8s=
-k8s.io/client-go v0.26.3/go.mod h1:ZPNu9lm8/dbRIPAgteN30RSXea6vrCpFvq+MateTUuQ=
-k8s.io/klog/v2 v2.90.1 h1:m4bYOKall2MmOiRaR1J+We67Do7vm9KiQVlT96lnHUw=
-k8s.io/klog/v2 v2.90.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
-k8s.io/kube-openapi v0.0.0-20230307230338-69ee2d25a840 h1:1Q4XWtrQQh04ZweCpL7aMNYafFMoPEiST4dl5b4PmYw=
-k8s.io/kube-openapi v0.0.0-20230307230338-69ee2d25a840/go.mod h1:y5VtZWM9sHHc2ZodIH/6SHzXj+TPU5USoA8lcIeKEKY=
-k8s.io/utils v0.0.0-20230209194617-a36077c30491 h1:r0BAOLElQnnFhE/ApUsg3iHdVYYPBjNSSOMowRZxxsY=
-k8s.io/utils v0.0.0-20230209194617-a36077c30491/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
-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=
+k8s.io/api v0.28.4 h1:8ZBrLjwosLl/NYgv1P7EQLqoO8MGQApnbgH8tu3BMzY=
+k8s.io/api v0.28.4/go.mod h1:axWTGrY88s/5YE+JSt4uUi6NMM+gur1en2REMR7IRj0=
+k8s.io/apimachinery v0.28.4 h1:zOSJe1mc+GxuMnFzD4Z/U1wst50X28ZNsn5bhgIIao8=
+k8s.io/apimachinery v0.28.4/go.mod h1:wI37ncBvfAoswfq626yPTe6Bz1c22L7uaJ8dho83mgg=
+k8s.io/client-go v0.28.4 h1:Np5ocjlZcTrkyRJ3+T3PkXDpe4UpatQxj85+xjaD2wY=
+k8s.io/client-go v0.28.4/go.mod h1:0VDZFpgoZfelyP5Wqu0/r/TRYcLYuJ2U1KEeoaPa1N4=
+k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg=
+k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
+k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 h1:aVUu9fTY98ivBPKR9Y5w/AuzbMm96cd3YHRTU83I780=
+k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00/go.mod h1:AsvuZPBlUDVuCdzJ87iajxtXuR9oktsTctW/R9wwouA=
+k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI=
+k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE=
diff --git a/readme-cn.md b/readme-cn.md
index ef3689d328cb..d60e2cf32e3c 100644
--- a/readme-cn.md
+++ b/readme-cn.md
@@ -122,7 +122,7 @@ GO111MODULE=on GOPROXY=https://goproxy.cn/,direct go get -u github.com/zeromicro
# run goctl like
docker run --rm -it -v `pwd`:/app kevinwan/goctl goctl --help
- # docker for arm64 (M1) architecture
+ # docker for arm64(Mac) architecture
docker pull kevinwan/goctl:latest-arm64
# run goctl like
docker run --rm -it -v `pwd`:/app kevinwan/goctl:latest-arm64 goctl --help
@@ -296,6 +296,8 @@ go-zero 已被许多公司用于生产部署,接入场景如在线教育、电
>92. 深圳市万佳安物联科技股份有限公司
>93. 武侯区编程之美软件开发工作室
>94. 西安交通大学智慧能源与碳中和研究中心
+>95. 成都创软科技有限责任公司
+>96. Sonderbase Technologies
如果贵公司也已使用 go-zero,欢迎在 [登记地址](https://github.com/zeromicro/go-zero/issues/602) 登记,仅仅为了推广,不做其它用途。
diff --git a/readme.md b/readme.md
index 883dc3cadee5..63800fc7794c 100644
--- a/readme.md
+++ b/readme.md
@@ -31,41 +31,43 @@ go-zero contains simple API description syntax and code generation tool called `
#### Advantages of go-zero:
-* improve the stability of the services with tens of millions of daily active users
-* builtin chained timeout control, concurrency control, rate limit, adaptive circuit breaker, adaptive load shedding, even no configuration needed
-* builtin middlewares also can be integrated into your frameworks
-* simple API syntax, one command to generate a couple of different languages
-* auto validate the request parameters from clients
-* plenty of builtin microservice management and concurrent toolkits
+* Improves the stability of the services with tens of millions of daily active users
+* Builtin chained timeout control, concurrency control, rate limit, adaptive circuit breaker, adaptive load shedding, even no configuration needed
+* Builtin middlewares also can be integrated into your frameworks
+* Simple API syntax, one command to generate a couple of different languages
+* Auto validate the request parameters from clients
+* Plenty of builtin microservice management and concurrent toolkits
## Backgrounds of go-zero
At the beginning of 2018, we decided to re-design our system, from monolithic architecture with Java+MongoDB to microservice architecture. After research and comparison, we chose to:
+In early 2018, we embarked on a transformative journey to redesign our system, transitioning from a monolithic architecture built with Java and MongoDB to a microservices architecture. After careful research and comparison, we made a deliberate choice to:
-* Golang based
- * great performance
- * simple syntax
- * proven engineering efficiency
- * extreme deployment experience
- * less server resource consumption
-* Self-designed microservice architecture
- * I have rich experience in designing microservice architectures
- * easy to locate the problems
- * easy to extend the features
+* Go Beyond with Golang
+ * Great performance
+ * Simple syntax
+ * Proven engineering efficiency
+ * Extreme deployment experience
+ * Less server resource consumption
+
+* Self-Design Our Microservice Architecture
+ * Microservice architecture facilitates the creation of scalable, flexible, and maintainable software systems with independent, reusable components.
+ * Easy to locate the problems within microservices.
+ * Easy to extend the features by adding or modifying specific microservices without impacting the entire system.
## Design considerations on go-zero
By designing the microservice architecture, we expected to ensure stability, as well as productivity. And from just the beginning, we have the following design principles:
-* keep it simple
-* high availability
-* stable on high concurrency
-* easy to extend
-* resilience design, failure-oriented programming
-* try best to be friendly to the business logic development, encapsulate the complexity
-* one thing, one way
+* Keep it simple
+* High availability
+* Stable on high concurrency
+* Easy to extend
+* Resilience design, failure-oriented programming
+* Try best to be friendly to the business logic development, encapsulate the complexity
+* One thing, one way
After almost half a year, we finished the transfer from a monolithic system to microservice system and deployed on August 2018. The new system guaranteed business growth and system stability.
@@ -73,19 +75,19 @@ After almost half a year, we finished the transfer from a monolithic system to m
go-zero is a web and rpc framework that integrates lots of engineering practices. The features are mainly listed below:
-* powerful tool included, less code to write
-* simple interfaces
-* fully compatible with net/http
-* middlewares are supported, easy to extend
-* high performance
-* failure-oriented programming, resilience design
-* builtin service discovery, load balancing
-* builtin concurrency control, adaptive circuit breaker, adaptive load shedding, auto-trigger, auto recover
-* auto validation of API request parameters
-* chained timeout control
-* auto management of data caching
-* call tracing, metrics, and monitoring
-* high concurrency protected
+* Powerful tool included, less code to write
+* Simple interfaces
+* Fully compatible with net/http
+* Middlewares are supported, easy to extend
+* High performance
+* Failure-oriented programming, resilience design
+* Builtin service discovery, load balancing
+* Builtin concurrency control, adaptive circuit breaker, adaptive load shedding, auto-trigger, auto recover
+* Auto validation of API request parameters
+* Chained timeout control
+* Auto management of data caching
+* Call tracing, metrics, and monitoring
+* High concurrency protected
As below, go-zero protects the system with a couple of layers and mechanisms:
@@ -105,13 +107,13 @@ go get -u github.com/zeromicro/go-zero
## Quick Start
-1. full examples can be checked out from below:
+1. Full examples can be checked out from below:
[Rapid development of microservice systems](https://github.com/zeromicro/zero-doc/blob/main/doc/shorturl-en.md)
[Rapid development of microservice systems - multiple RPCs](https://github.com/zeromicro/zero-doc/blob/main/docs/zero/bookstore-en.md)
-2. install goctl
+2. Install goctl
`goctl`can be read as `go control`. `goctl` means not to be controlled by code, instead, we control it. The inside `go` is not `golang`. At the very beginning, I was expecting it to help us improve productivity, and make our lives easier.
@@ -127,7 +129,7 @@ go get -u github.com/zeromicro/go-zero
# run goctl like
docker run --rm -it -v `pwd`:/app kevinwan/goctl goctl --help
- # docker for arm64 (M1) architecture
+ # docker for arm64(Mac) architecture
docker pull kevinwan/goctl:latest-arm64
# run goctl like
docker run --rm -it -v `pwd`:/app kevinwan/goctl:latest-arm64 goctl --help
@@ -135,7 +137,7 @@ go get -u github.com/zeromicro/go-zero
make sure goctl is executable.
-3. create the API file, like greet.api, you can install the plugin of goctl in vs code, api syntax is supported.
+3. Create the API file, like greet.api, you can install the plugin of goctl in vs code, api syntax is supported.
```go
type (
@@ -160,7 +162,7 @@ go get -u github.com/zeromicro/go-zero
goctl api -o greet.api
```
-4. generate the go server-side code
+4. Generate the go server-side code
```shell
goctl api go -api greet.api -dir greet
@@ -215,7 +217,7 @@ go get -u github.com/zeromicro/go-zero
5. Write the business logic code
- * the dependencies can be passed into the logic within servicecontext.go, like mysql, reds, etc.
+ * the dependencies can be passed into the logic within servicecontext.go, like mysql, redis, etc.
* add the logic code in a logic package according to .api file
6. Generate code like Java, TypeScript, Dart, JavaScript, etc. just from the api file
diff --git a/rest/handler/cryptionhandler.go b/rest/handler/cryptionhandler.go
index 0ef92379033f..18ba85b326c8 100644
--- a/rest/handler/cryptionhandler.go
+++ b/rest/handler/cryptionhandler.go
@@ -132,7 +132,7 @@ func (w *cryptionResponseWriter) flush(key []byte) {
body := base64.StdEncoding.EncodeToString(content)
if n, err := io.WriteString(w.ResponseWriter, body); err != nil {
logx.Errorf("write response failed, error: %s", err)
- } else if n < len(content) {
- logx.Errorf("actual bytes: %d, written bytes: %d", len(content), n)
+ } else if n < len(body) {
+ logx.Errorf("actual bytes: %d, written bytes: %d", len(body), n)
}
}
diff --git a/rest/handler/cryptionhandler_test.go b/rest/handler/cryptionhandler_test.go
index b24a58509e57..b76384d6a03e 100644
--- a/rest/handler/cryptionhandler_test.go
+++ b/rest/handler/cryptionhandler_test.go
@@ -2,15 +2,18 @@ package handler
import (
"bytes"
+ "crypto/rand"
"encoding/base64"
"io"
- "math/rand"
"net/http"
"net/http/httptest"
+ "strings"
"testing"
+ "testing/iotest"
"github.com/stretchr/testify/assert"
"github.com/zeromicro/go-zero/core/codec"
+ "github.com/zeromicro/go-zero/core/logx/logtest"
)
const (
@@ -37,6 +40,19 @@ func TestCryptionHandlerGet(t *testing.T) {
assert.Equal(t, base64.StdEncoding.EncodeToString(expect), recorder.Body.String())
}
+func TestCryptionHandlerGet_badKey(t *testing.T) {
+ req := httptest.NewRequest(http.MethodGet, "/any", http.NoBody)
+ handler := CryptionHandler(append(aesKey, aesKey...))(http.HandlerFunc(
+ func(w http.ResponseWriter, r *http.Request) {
+ _, err := w.Write([]byte(respText))
+ w.Header().Set("X-Test", "test")
+ assert.Nil(t, err)
+ }))
+ recorder := httptest.NewRecorder()
+ handler.ServeHTTP(recorder, req)
+ assert.Equal(t, http.StatusInternalServerError, recorder.Code)
+}
+
func TestCryptionHandlerPost(t *testing.T) {
var buf bytes.Buffer
enc, err := codec.EcbEncrypt(aesKey, []byte(reqText))
@@ -120,10 +136,110 @@ func TestCryptionHandler_ContentTooLong(t *testing.T) {
defer svr.Close()
body := make([]byte, maxBytes+1)
- rand.Read(body)
+ _, err := rand.Read(body)
+ assert.NoError(t, err)
req, err := http.NewRequest(http.MethodPost, svr.URL, bytes.NewReader(body))
assert.Nil(t, err)
resp, err := http.DefaultClient.Do(req)
assert.Nil(t, err)
assert.Equal(t, http.StatusBadRequest, resp.StatusCode)
}
+
+func TestCryptionHandler_BadBody(t *testing.T) {
+ req, err := http.NewRequest(http.MethodPost, "/foo", iotest.ErrReader(io.ErrUnexpectedEOF))
+ assert.Nil(t, err)
+ err = decryptBody(maxBytes, aesKey, req)
+ assert.ErrorIs(t, err, io.ErrUnexpectedEOF)
+}
+
+func TestCryptionHandler_BadKey(t *testing.T) {
+ var buf bytes.Buffer
+ enc, err := codec.EcbEncrypt(aesKey, []byte(reqText))
+ assert.Nil(t, err)
+ buf.WriteString(base64.StdEncoding.EncodeToString(enc))
+
+ req := httptest.NewRequest(http.MethodPost, "/any", &buf)
+ err = decryptBody(maxBytes, append(aesKey, aesKey...), req)
+ assert.Error(t, err)
+}
+
+func TestCryptionResponseWriter_Flush(t *testing.T) {
+ body := []byte("hello, world!")
+
+ t.Run("half", func(t *testing.T) {
+ recorder := httptest.NewRecorder()
+ f := flushableResponseWriter{
+ writer: &halfWriter{recorder},
+ }
+ w := newCryptionResponseWriter(f)
+ _, err := w.Write(body)
+ assert.NoError(t, err)
+ w.flush(aesKey)
+ b, err := io.ReadAll(recorder.Body)
+ assert.NoError(t, err)
+ expected, err := codec.EcbEncrypt(aesKey, body)
+ assert.NoError(t, err)
+ assert.True(t, strings.HasPrefix(base64.StdEncoding.EncodeToString(expected), string(b)))
+ assert.True(t, len(string(b)) < len(base64.StdEncoding.EncodeToString(expected)))
+ })
+
+ t.Run("full", func(t *testing.T) {
+ recorder := httptest.NewRecorder()
+ f := flushableResponseWriter{
+ writer: recorder,
+ }
+ w := newCryptionResponseWriter(f)
+ _, err := w.Write(body)
+ assert.NoError(t, err)
+ w.flush(aesKey)
+ b, err := io.ReadAll(recorder.Body)
+ assert.NoError(t, err)
+ expected, err := codec.EcbEncrypt(aesKey, body)
+ assert.NoError(t, err)
+ assert.Equal(t, base64.StdEncoding.EncodeToString(expected), string(b))
+ })
+
+ t.Run("bad writer", func(t *testing.T) {
+ buf := logtest.NewCollector(t)
+ f := flushableResponseWriter{
+ writer: new(badWriter),
+ }
+ w := newCryptionResponseWriter(f)
+ _, err := w.Write(body)
+ assert.NoError(t, err)
+ w.flush(aesKey)
+ assert.True(t, strings.Contains(buf.Content(), io.ErrClosedPipe.Error()))
+ })
+}
+
+type flushableResponseWriter struct {
+ writer io.Writer
+}
+
+func (m flushableResponseWriter) Header() http.Header {
+ panic("implement me")
+}
+
+func (m flushableResponseWriter) Write(p []byte) (int, error) {
+ return m.writer.Write(p)
+}
+
+func (m flushableResponseWriter) WriteHeader(statusCode int) {
+ panic("implement me")
+}
+
+type halfWriter struct {
+ w io.Writer
+}
+
+func (t *halfWriter) Write(p []byte) (n int, err error) {
+ n = len(p) >> 1
+ return t.w.Write(p[0:n])
+}
+
+type badWriter struct {
+}
+
+func (b *badWriter) Write(p []byte) (n int, err error) {
+ return 0, io.ErrClosedPipe
+}
diff --git a/rest/handler/loghandler.go b/rest/handler/loghandler.go
index 07cbdf19c2b9..eaf59a16b826 100644
--- a/rest/handler/loghandler.go
+++ b/rest/handler/loghandler.go
@@ -10,7 +10,6 @@ import (
"net/http"
"net/http/httputil"
"strconv"
- "strings"
"time"
"github.com/zeromicro/go-zero/core/color"
@@ -39,7 +38,7 @@ func LogHandler(next http.Handler) http.Handler {
lrw := response.NewWithCodeResponseWriter(w)
var dup io.ReadCloser
- r.Body, dup = iox.DupReadCloser(r.Body)
+ r.Body, dup = iox.LimitDupReadCloser(r.Body, limitBodyBytes)
next.ServeHTTP(lrw, r.WithContext(internal.WithLogCollector(r.Context(), logs)))
r.Body = dup
logBrief(r, lrw.Code, timer, logs)
@@ -136,14 +135,7 @@ func logBrief(r *http.Request, code int, timer *utils.ElapsedTimer, logs *intern
ok := isOkResponse(code)
if !ok {
- fullReq := dumpRequest(r)
- limitReader := io.LimitReader(strings.NewReader(fullReq), limitBodyBytes)
- body, err := io.ReadAll(limitReader)
- if err != nil {
- buf.WriteString(fmt.Sprintf("\n%s", fullReq))
- } else {
- buf.WriteString(fmt.Sprintf("\n%s", string(body)))
- }
+ buf.WriteString(fmt.Sprintf("\n%s", dumpRequest(r)))
}
body := logs.Flush()
diff --git a/rest/httpc/internal/metricsinterceptor.go b/rest/httpc/internal/metricsinterceptor.go
new file mode 100644
index 000000000000..99835f92158e
--- /dev/null
+++ b/rest/httpc/internal/metricsinterceptor.go
@@ -0,0 +1,69 @@
+package internal
+
+import (
+ "net/http"
+ "net/url"
+ "strconv"
+ "time"
+
+ "github.com/zeromicro/go-zero/core/metric"
+ "github.com/zeromicro/go-zero/core/timex"
+)
+
+const clientNamespace = "httpc_client"
+
+var (
+ MetricClientReqDur = metric.NewHistogramVec(&metric.HistogramVecOpts{
+ Namespace: clientNamespace,
+ Subsystem: "requests",
+ Name: "duration_ms",
+ Help: "http client requests duration(ms).",
+ Labels: []string{"name", "method", "url"},
+ Buckets: []float64{0.25, 0.5, 1, 2, 5, 10, 25, 50, 100, 250, 500, 1000, 2000, 5000, 10000, 15000},
+ })
+
+ MetricClientReqCodeTotal = metric.NewCounterVec(&metric.CounterVecOpts{
+ Namespace: clientNamespace,
+ Subsystem: "requests",
+ Name: "code_total",
+ Help: "http client requests code count.",
+ Labels: []string{"name", "method", "url", "code"},
+ })
+)
+
+type MetricsURLRewriter func(u url.URL) string
+
+func MetricsInterceptor(name string, pr MetricsURLRewriter) Interceptor {
+ return func(r *http.Request) (*http.Request, ResponseHandler) {
+ startTime := timex.Now()
+ return r, func(resp *http.Response, err error) {
+ var code int
+ var path string
+
+ // error or resp is nil, set code=500
+ if err != nil || resp == nil {
+ code = http.StatusInternalServerError
+ } else {
+ code = resp.StatusCode
+ }
+
+ u := cleanURL(*r.URL)
+ method := r.Method
+ if pr != nil {
+ path = pr(u)
+ } else {
+ path = u.String()
+ }
+
+ MetricClientReqDur.ObserveFloat(float64(timex.Since(startTime))/float64(time.Millisecond), name, method, path)
+ MetricClientReqCodeTotal.Inc(name, method, path, strconv.Itoa(code))
+ }
+ }
+}
+
+func cleanURL(r url.URL) url.URL {
+ r.RawQuery = ""
+ r.RawFragment = ""
+ r.User = nil
+ return r
+}
diff --git a/rest/httpc/internal/metricsinterceptor_test.go b/rest/httpc/internal/metricsinterceptor_test.go
new file mode 100644
index 000000000000..413619f99a51
--- /dev/null
+++ b/rest/httpc/internal/metricsinterceptor_test.go
@@ -0,0 +1,35 @@
+package internal
+
+import (
+ "net/http"
+ "net/http/httptest"
+ "testing"
+ "time"
+
+ "github.com/golang/mock/gomock"
+ "github.com/stretchr/testify/assert"
+ "github.com/zeromicro/go-zero/core/logx"
+)
+
+func TestMetricsInterceptor(t *testing.T) {
+ c := gomock.NewController(t)
+ defer c.Finish()
+
+ logx.Disable()
+
+ svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ time.Sleep(100 * time.Millisecond)
+ w.WriteHeader(http.StatusInternalServerError)
+ }))
+ defer svr.Close()
+
+ req, err := http.NewRequest(http.MethodGet, svr.URL, nil)
+ assert.NotNil(t, req)
+ assert.Nil(t, err)
+ interceptor := MetricsInterceptor("test", nil)
+ req, handler := interceptor(req)
+ resp, err := http.DefaultClient.Do(req)
+ assert.NotNil(t, resp)
+ assert.Nil(t, err)
+ handler(resp, err)
+}
diff --git a/rest/httpx/responses.go b/rest/httpx/responses.go
index 0461c7889d4e..edd133a42561 100644
--- a/rest/httpx/responses.go
+++ b/rest/httpx/responses.go
@@ -3,6 +3,7 @@ package httpx
import (
"context"
"encoding/json"
+ "errors"
"fmt"
"net/http"
"sync"
@@ -141,10 +142,10 @@ func doHandleError(w http.ResponseWriter, err error, handler func(error) (int, a
return
}
- e, ok := body.(error)
- if ok {
- http.Error(w, e.Error(), code)
- } else {
+ switch v := body.(type) {
+ case error:
+ http.Error(w, v.Error(), code)
+ default:
writeJson(w, code, body)
}
}
@@ -162,7 +163,7 @@ func doWriteJson(w http.ResponseWriter, code int, v any) error {
if n, err := w.Write(bs); err != nil {
// http.ErrHandlerTimeout has been handled by http.TimeoutHandler,
// so it's ignored here.
- if err != http.ErrHandlerTimeout {
+ if !errors.Is(err, http.ErrHandlerTimeout) {
return fmt.Errorf("write response failed, error: %w", err)
}
} else if n < len(bs) {
diff --git a/rest/internal/starter.go b/rest/internal/starter.go
index 6ac180d4d566..174303342b7e 100644
--- a/rest/internal/starter.go
+++ b/rest/internal/starter.go
@@ -2,6 +2,7 @@ package internal
import (
"context"
+ "errors"
"fmt"
"net/http"
@@ -42,14 +43,14 @@ func start(host string, port int, handler http.Handler, run func(svr *http.Serve
}
healthManager := health.NewHealthManager(fmt.Sprintf("%s-%s:%d", probeNamePrefix, host, port))
- waitForCalled := proc.AddWrapUpListener(func() {
+ waitForCalled := proc.AddShutdownListener(func() {
healthManager.MarkNotReady()
if e := server.Shutdown(context.Background()); e != nil {
logx.Error(e)
}
})
defer func() {
- if err == http.ErrServerClosed {
+ if errors.Is(err, http.ErrServerClosed) {
waitForCalled()
}
}()
diff --git a/rest/server.go b/rest/server.go
index 9583ea528a0c..bbf6ff39d039 100644
--- a/rest/server.go
+++ b/rest/server.go
@@ -2,6 +2,7 @@ package rest
import (
"crypto/tls"
+ "errors"
"net/http"
"path"
"time"
@@ -307,7 +308,7 @@ func WithUnsignedCallback(callback handler.UnsignedCallback) RunOption {
func handleError(err error) {
// ErrServerClosed means the server is closed manually
- if err == nil || err == http.ErrServerClosed {
+ if err == nil || errors.Is(err, http.ErrServerClosed) {
return
}
diff --git a/tools/goctl/api/dartgen/genapi.go b/tools/goctl/api/dartgen/genapi.go
index c99e25bb4899..44f09bf19d76 100644
--- a/tools/goctl/api/dartgen/genapi.go
+++ b/tools/goctl/api/dartgen/genapi.go
@@ -15,8 +15,8 @@ import '../data/{{with .Info}}{{getBaseName .Title}}{{end}}.dart';
{{range .Routes}}
/// --{{.Path}}--
///
-/// 请求: {{with .RequestType}}{{.Name}}{{end}}
-/// 返回: {{with .ResponseType}}{{.Name}}{{end}}
+/// request: {{with .RequestType}}{{.Name}}{{end}}
+/// response: {{with .ResponseType}}{{.Name}}{{end}}
Future {{pathToFuncName .Path}}( {{if ne .Method "get"}}{{with .RequestType}}{{.Name}} request,{{end}}{{end}}
{Function({{with .ResponseType}}{{.Name}}{{end}}) ok,
Function(String) fail,
diff --git a/tools/goctl/api/dartgen/gendata.go b/tools/goctl/api/dartgen/gendata.go
index 7894cfb3cb55..7f21b42a6405 100644
--- a/tools/goctl/api/dartgen/gendata.go
+++ b/tools/goctl/api/dartgen/gendata.go
@@ -51,6 +51,8 @@ class {{.Name}} {
m['{{getPropertyFromMember .}}']?.cast<{{getCoreType .Type.Name}}>() {{appendDefaultEmptyValue .Type.Name}}
{{else if isClassListType .Type.Name}}
((m['{{getPropertyFromMember .}}'] {{appendDefaultEmptyValue .Type.Name}}) as List).map((i) => {{getCoreType .Type.Name}}.fromJson(i)).toList()
+ {{else if isMapType .Type.Name}}
+ {{if isNumberType .Type.Name}}num{{else}}{{.Type.Name}}{{end}}.from(m['{{getPropertyFromMember .}}'] ?? {})
{{else}}
{{.Type.Name}}.fromJson(m['{{getPropertyFromMember .}}']){{end}}
,{{end}}
@@ -61,6 +63,8 @@ class {{.Name}} {
'{{getPropertyFromMember .}}':
{{if isDirectType .Type.Name}}
{{lowCamelCase .Name}}
+ {{else if isMapType .Type.Name}}
+ {{lowCamelCase .Name}}
{{else if isClassListType .Type.Name}}
{{lowCamelCase .Name}}{{if isNullableType .Type.Name}}?{{end}}.map((i) => i{{if isListItemsNullable .Type.Name}}?{{end}}.toJson())
{{else}}
diff --git a/tools/goctl/api/dartgen/vars.go b/tools/goctl/api/dartgen/vars.go
index 3dcff8e72e4b..c34d364a4d3f 100644
--- a/tools/goctl/api/dartgen/vars.go
+++ b/tools/goctl/api/dartgen/vars.go
@@ -3,23 +3,24 @@ package dartgen
import "text/template"
var funcMap = template.FuncMap{
+ "appendNullCoalescing": appendNullCoalescing,
+ "appendDefaultEmptyValue": appendDefaultEmptyValue,
+ "extractPositionalParamsFromPath": extractPositionalParamsFromPath,
"getBaseName": getBaseName,
+ "getCoreType": getCoreType,
"getPropertyFromMember": getPropertyFromMember,
- "isDirectType": isDirectType,
+ "hasUrlPathParams": hasUrlPathParams,
+ "isAtomicListType": isAtomicListType,
"isAtomicType": isAtomicType,
- "isNumberType": isNumberType,
+ "isDirectType": isDirectType,
"isClassListType": isClassListType,
- "isAtomicListType": isAtomicListType,
"isListItemsNullable": isListItemsNullable,
+ "isMapType": isMapType,
"isNullableType": isNullableType,
- "appendNullCoalescing": appendNullCoalescing,
- "appendDefaultEmptyValue": appendDefaultEmptyValue,
- "getCoreType": getCoreType,
+ "isNumberType": isNumberType,
"lowCamelCase": lowCamelCase,
- "normalizeHandlerName": normalizeHandlerName,
- "hasUrlPathParams": hasUrlPathParams,
- "extractPositionalParamsFromPath": extractPositionalParamsFromPath,
"makeDartRequestUrlPath": makeDartRequestUrlPath,
+ "normalizeHandlerName": normalizeHandlerName,
}
const (
@@ -28,28 +29,32 @@ import 'dart:convert';
import '../vars/kv.dart';
import '../vars/vars.dart';
-/// 发送POST请求.
+/// Send GET request.
///
-/// data:为你要post的结构体,我们会帮你转换成json字符串;
-/// ok函数:请求成功的时候调用,fail函数:请求失败的时候会调用,eventually函数:无论成功失败都会调用
-Future apiPost(String path, dynamic data,
+/// ok: the function that will be called on success.
+/// fail:the fuction that will be called on failure.
+/// eventually:the function that will be called regardless of success or failure.
+Future apiGet(String path,
{Map header,
Function(Map) ok,
Function(String) fail,
Function eventually}) async {
- await _apiRequest('POST', path, data,
+ await _apiRequest('GET', path, null,
header: header, ok: ok, fail: fail, eventually: eventually);
}
-/// 发送GET请求.
+/// Send POST request.
///
-/// ok函数:请求成功的时候调用,fail函数:请求失败的时候会调用,eventually函数:无论成功失败都会调用
-Future apiGet(String path,
+/// data: the data to post, it will be marshaled to json automatically.
+/// ok: the function that will be called on success.
+/// fail:the fuction that will be called on failure.
+/// eventually:the function that will be called regardless of success or failure.
+Future apiPost(String path, dynamic data,
{Map header,
Function(Map) ok,
Function(String) fail,
Function eventually}) async {
- await _apiRequest('GET', path, null,
+ await _apiRequest('POST', path, data,
header: header, ok: ok, fail: fail, eventually: eventually);
}
@@ -212,11 +217,11 @@ Future _apiRequest(String method, String path, dynamic data,
}`
tokensFileContent = `class Tokens {
- /// 用于访问的token, 每次请求都必须带在Header里面
+ /// the token used to access, it must be carried in the header of each request
final String accessToken;
final int accessExpire;
- /// 用于刷新token
+ /// the token used to refresh
final String refreshToken;
final int refreshExpire;
final int refreshAfter;
@@ -247,11 +252,11 @@ Future _apiRequest(String method, String path, dynamic data,
`
tokensFileContentV2 = `class Tokens {
- /// 用于访问的token, 每次请求都必须带在Header里面
+ /// the token used to access, it must be carried in the header of each request
final String accessToken;
final int accessExpire;
- /// 用于刷新token
+ /// the token used to refresh
final String refreshToken;
final int refreshExpire;
final int refreshAfter;
diff --git a/tools/goctl/api/gogen/gen_test.go b/tools/goctl/api/gogen/gen_test.go
index 2aab5c686587..d2cb68426717 100644
--- a/tools/goctl/api/gogen/gen_test.go
+++ b/tools/goctl/api/gogen/gen_test.go
@@ -10,6 +10,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/zeromicro/go-zero/tools/goctl/api/parser"
+ "github.com/zeromicro/go-zero/tools/goctl/pkg/env"
"github.com/zeromicro/go-zero/tools/goctl/rpc/execx"
"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
)
@@ -53,7 +54,10 @@ func TestParser(t *testing.T) {
filename := "greet.api"
err := os.WriteFile(filename, []byte(testApiTemplate), os.ModePerm)
assert.Nil(t, err)
- defer os.Remove(filename)
+ env.Set(t, env.GoctlExperimental, "off")
+ t.Cleanup(func() {
+ os.Remove(filename)
+ })
api, err := parser.Parse(filename)
assert.Nil(t, err)
diff --git a/tools/goctl/api/parser/g4/ast/apiparser.go b/tools/goctl/api/parser/g4/ast/apiparser.go
index f5c66ae0382a..1cf5539643f6 100644
--- a/tools/goctl/api/parser/g4/ast/apiparser.go
+++ b/tools/goctl/api/parser/g4/ast/apiparser.go
@@ -156,6 +156,7 @@ func (p *Parser) invokeImportedApi(filename string, imports []*ImportExpr) ([]*A
}
// ignore already imported file
if p.alreadyImported(impPath) {
+ p.importStatck.pop()
continue
}
p.fileMap[impPath] = PlaceHolder{}
diff --git a/tools/goctl/api/parser/g4/gen/api/file_splitor_test.go b/tools/goctl/api/parser/g4/gen/api/file_splitor_test.go
index 77ac0b1d0529..8353c078f2c0 100644
--- a/tools/goctl/api/parser/g4/gen/api/file_splitor_test.go
+++ b/tools/goctl/api/parser/g4/gen/api/file_splitor_test.go
@@ -16,6 +16,7 @@ import (
)
func TestFileSplitor(t *testing.T) {
+ t.Skip("skip this test because it is used to split the apiparser_parser.go file by developer.")
dir := "."
data, err := os.ReadFile(filepath.Join(dir, "apiparser_parser.go"))
if err != nil {
diff --git a/tools/goctl/api/parser/parser.go b/tools/goctl/api/parser/parser.go
index 8aac8f9cfd58..0eff38fc9e62 100644
--- a/tools/goctl/api/parser/parser.go
+++ b/tools/goctl/api/parser/parser.go
@@ -17,7 +17,9 @@ type parser struct {
spec *spec.ApiSpec
}
-// Parse parses the api file
+// Depreacted: use tools/goctl/pkg/parser/api/parser/parser.go:18 instead,
+// it will be removed in the future.
+// Parse parses the api file.
func Parse(filename string) (*spec.ApiSpec, error) {
if env.UseExperimental() {
return apiParser.Parse(filename, "")
@@ -61,11 +63,15 @@ func parseContent(content string, skipCheckTypeDeclaration bool, filename ...str
return apiSpec, nil
}
+// Depreacted: use tools/goctl/pkg/parser/api/parser/parser.go:18 instead,
+// it will be removed in the future.
// ParseContent parses the api content
func ParseContent(content string, filename ...string) (*spec.ApiSpec, error) {
return parseContent(content, false, filename...)
}
+// Depreacted: use tools/goctl/pkg/parser/api/parser/parser.go:18 instead,
+// it will be removed in the future.
// ParseContentWithParserSkipCheckTypeDeclaration parses the api content with skip check type declaration
func ParseContentWithParserSkipCheckTypeDeclaration(content string, filename ...string) (*spec.ApiSpec, error) {
return parseContent(content, true, filename...)
@@ -174,17 +180,15 @@ func (p parser) findDefinedType(name string) (*spec.Type, error) {
}
func (p parser) fieldToMember(field *ast.TypeField) spec.Member {
- name := ""
- tag := ""
+ var name string
+ var tag string
if !field.IsAnonymous {
name = field.Name.Text()
- if field.Tag == nil {
- panic(fmt.Sprintf("error: line %d:%d field %s has no tag",
- field.Name.Line(), field.Name.Column(), field.Name.Text()))
+ if field.Tag != nil {
+ tag = field.Tag.Text()
}
-
- tag = field.Tag.Text()
}
+
return spec.Member{
Name: name,
Type: p.astTypeToSpec(field.DataType),
diff --git a/tools/goctl/go.mod b/tools/goctl/go.mod
index caf5ced6c5c6..7283e1015ba3 100644
--- a/tools/goctl/go.mod
+++ b/tools/goctl/go.mod
@@ -1,32 +1,32 @@
module github.com/zeromicro/go-zero/tools/goctl
-go 1.18
+go 1.19
require (
github.com/DATA-DOG/go-sqlmock v1.5.0
- github.com/emicklei/proto v1.12.1
+ github.com/emicklei/proto v1.12.2
github.com/fatih/structtag v1.2.0
github.com/go-sql-driver/mysql v1.7.1
github.com/gookit/color v1.5.4
github.com/iancoleman/strcase v0.3.0
- github.com/spf13/cobra v1.7.0
+ github.com/spf13/cobra v1.8.0
github.com/spf13/pflag v1.0.5
github.com/stretchr/testify v1.8.4
github.com/withfig/autocomplete-tools/integrations/cobra v1.2.1
github.com/zeromicro/antlr v0.0.1
github.com/zeromicro/ddl-parser v1.0.5
- github.com/zeromicro/go-zero v1.5.5
- golang.org/x/text v0.13.0
- google.golang.org/grpc v1.57.0
+ github.com/zeromicro/go-zero v1.6.0
+ golang.org/x/text v0.14.0
+ google.golang.org/grpc v1.59.0
google.golang.org/protobuf v1.31.0
)
require (
- github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a // indirect
- github.com/alicebob/miniredis/v2 v2.30.5 // indirect
+ github.com/alicebob/gopher-json v0.0.0-20230218143504-906a9b012302 // indirect
+ github.com/alicebob/miniredis/v2 v2.31.0 // indirect
github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20210521184019-c5ad59b459ec // indirect
github.com/beorn7/perks v1.0.1 // indirect
- github.com/cenkalti/backoff/v4 v4.2.0 // indirect
+ github.com/cenkalti/backoff/v4 v4.2.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/coreos/go-semver v0.3.1 // indirect
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
@@ -35,19 +35,20 @@ require (
github.com/emicklei/go-restful/v3 v3.9.0 // indirect
github.com/fatih/color v1.15.0 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect
- github.com/go-logr/logr v1.2.3 // indirect
+ github.com/go-logr/logr v1.2.4 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-openapi/jsonpointer v0.19.6 // indirect
- github.com/go-openapi/jsonreference v0.20.1 // indirect
- github.com/go-openapi/swag v0.22.3 // indirect
+ github.com/go-openapi/jsonreference v0.20.2 // indirect
+ github.com/go-openapi/swag v0.22.4 // indirect
github.com/go-redis/redis/v8 v8.11.5 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/mock v1.6.0 // indirect
github.com/golang/protobuf v1.5.3 // indirect
- github.com/google/gnostic v0.5.7-v3refs // indirect
+ github.com/google/gnostic-models v0.6.8 // indirect
github.com/google/go-cmp v0.5.9 // indirect
github.com/google/gofuzz v1.2.0 // indirect
- github.com/grpc-ecosystem/grpc-gateway/v2 v2.15.0 // indirect
+ github.com/google/uuid v1.4.0 // indirect
+ github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
@@ -57,58 +58,58 @@ require (
github.com/logrusorgru/aurora v2.0.3+incompatible // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
- github.com/mattn/go-isatty v0.0.17 // indirect
+ github.com/mattn/go-isatty v0.0.20 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
- github.com/openzipkin/zipkin-go v0.4.1 // indirect
- github.com/pelletier/go-toml/v2 v2.0.9 // indirect
+ github.com/openzipkin/zipkin-go v0.4.2 // indirect
+ github.com/pelletier/go-toml/v2 v2.1.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
- github.com/prometheus/client_golang v1.16.0 // indirect
- github.com/prometheus/client_model v0.3.0 // indirect
- github.com/prometheus/common v0.42.0 // indirect
- github.com/prometheus/procfs v0.10.1 // indirect
+ github.com/prometheus/client_golang v1.17.0 // indirect
+ github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 // indirect
+ github.com/prometheus/common v0.44.0 // indirect
+ github.com/prometheus/procfs v0.11.1 // indirect
github.com/spaolacci/murmur3 v1.1.0 // indirect
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect
github.com/yuin/gopher-lua v1.1.0 // indirect
- go.etcd.io/etcd/api/v3 v3.5.9 // indirect
- go.etcd.io/etcd/client/pkg/v3 v3.5.9 // indirect
- go.etcd.io/etcd/client/v3 v3.5.9 // indirect
- go.opentelemetry.io/otel v1.14.0 // indirect
- go.opentelemetry.io/otel/exporters/jaeger v1.14.0 // indirect
- go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.14.0 // indirect
- go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.14.0 // indirect
- go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.14.0 // indirect
- go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.14.0 // indirect
- go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.14.0 // indirect
- go.opentelemetry.io/otel/exporters/zipkin v1.14.0 // indirect
- go.opentelemetry.io/otel/sdk v1.14.0 // indirect
- go.opentelemetry.io/otel/trace v1.14.0 // indirect
- go.opentelemetry.io/proto/otlp v0.19.0 // 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/v3 v3.5.10 // indirect
+ go.opentelemetry.io/otel v1.19.0 // indirect
+ go.opentelemetry.io/otel/exporters/jaeger v1.17.0 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.19.0 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0 // indirect
+ go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.19.0 // indirect
+ go.opentelemetry.io/otel/exporters/zipkin v1.19.0 // indirect
+ go.opentelemetry.io/otel/metric v1.19.0 // indirect
+ go.opentelemetry.io/otel/sdk v1.19.0 // indirect
+ go.opentelemetry.io/otel/trace v1.19.0 // indirect
+ go.opentelemetry.io/proto/otlp v1.0.0 // indirect
go.uber.org/atomic v1.10.0 // indirect
go.uber.org/automaxprocs v1.5.3 // indirect
go.uber.org/multierr v1.9.0 // indirect
go.uber.org/zap v1.24.0 // indirect
- golang.org/x/crypto v0.12.0 // indirect
- golang.org/x/net v0.14.0 // indirect
- golang.org/x/oauth2 v0.7.0 // indirect
- golang.org/x/sys v0.11.0 // indirect
- golang.org/x/term v0.11.0 // indirect
+ golang.org/x/crypto v0.14.0 // indirect
+ golang.org/x/net v0.17.0 // indirect
+ golang.org/x/oauth2 v0.12.0 // indirect
+ golang.org/x/sys v0.13.0 // indirect
+ golang.org/x/term v0.13.0 // indirect
golang.org/x/time v0.3.0 // indirect
- google.golang.org/appengine v1.6.7 // indirect
- google.golang.org/genproto v0.0.0-20230526161137-0005af68ea54 // indirect
- google.golang.org/genproto/googleapis/api v0.0.0-20230525234035-dd9d682886f9 // indirect
- google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 // indirect
+ google.golang.org/appengine v1.6.8 // indirect
+ google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b // indirect
+ google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b // indirect
+ google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
- k8s.io/api v0.26.3 // indirect
- k8s.io/apimachinery v0.27.0-alpha.3 // indirect
- k8s.io/client-go v0.26.3 // indirect
- k8s.io/klog/v2 v2.90.1 // indirect
- k8s.io/kube-openapi v0.0.0-20230307230338-69ee2d25a840 // indirect
- k8s.io/utils v0.0.0-20230209194617-a36077c30491 // indirect
+ k8s.io/api v0.28.3 // indirect
+ k8s.io/apimachinery v0.28.3 // indirect
+ k8s.io/client-go v0.28.3 // indirect
+ k8s.io/klog/v2 v2.100.1 // indirect
+ k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 // indirect
+ k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect
sigs.k8s.io/yaml v1.3.0 // indirect
diff --git a/tools/goctl/go.sum b/tools/goctl/go.sum
index 7aefe22d34a4..3c8e441134bb 100644
--- a/tools/goctl/go.sum
+++ b/tools/goctl/go.sum
@@ -1,198 +1,92 @@
-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.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/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/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/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=
-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/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60=
github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
-github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
-github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a h1:HbKu58rmZpUGpz5+4FfNmIU+FmZg2P3Xaj2v2bfNWmk=
+github.com/DmitriyVTitov/size v1.5.0/go.mod h1:le6rNI4CoLQV1b9gzp1+3d7hMAD/uu2QcJ+aYbNgiU0=
github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc=
-github.com/alicebob/miniredis/v2 v2.30.5 h1:3r6kTHdKnuP4fkS8k2IrvSfxpxUTcW1SOL0wN7b7Dt0=
-github.com/alicebob/miniredis/v2 v2.30.5/go.mod h1:b25qWj4fCEsBeAAR2mlb0ufImGC6uH3VlUfb/HS5zKg=
-github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
+github.com/alicebob/gopher-json v0.0.0-20230218143504-906a9b012302 h1:uvdUDbHQHO85qeSydJtItA4T55Pw6BtAejd0APRJOCE=
+github.com/alicebob/gopher-json v0.0.0-20230218143504-906a9b012302/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc=
+github.com/alicebob/miniredis/v2 v2.31.0 h1:ObEFUNlJwoIiyjxdrYF0QIDE7qXcLc7D3WpSH4c22PU=
+github.com/alicebob/miniredis/v2 v2.31.0/go.mod h1:UB/T2Uztp7MlFSDakaX1sTXUv5CASoprx0wulRT6HBg=
github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20210521184019-c5ad59b459ec h1:EEyRvzmpEUZ+I8WmD5cw/vY8EqhambkOqy5iFr0908A=
github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20210521184019-c5ad59b459ec/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY=
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
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/cenkalti/backoff/v4 v4.2.0 h1:HN5dHm3WBOgndBH6E8V0q2jIYIR3s9yglV8k/+MN3u4=
-github.com/cenkalti/backoff/v4 v4.2.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/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
+github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
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/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-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-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4=
github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec=
github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
-github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
+github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
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/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
-github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
github.com/emicklei/go-restful/v3 v3.9.0 h1:XwGDlfxEnQZzuopoqxwSEllNcCOM9DhhFyhFIIGKwxE=
github.com/emicklei/go-restful/v3 v3.9.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
-github.com/emicklei/proto v1.12.1 h1:6n/Z2pZAnBwuhU66Gs8160B8rrrYKo7h2F2sCOnNceE=
-github.com/emicklei/proto v1.12.1/go.mod h1:rn1FgRS/FANiZdD2djyH7TMA9jdRDcYQ9IEN9yvjX0A=
-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.9-0.20201210154907-fd9021fe5dad/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/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
+github.com/emicklei/proto v1.12.2 h1:ZDyDzrfMt7ncmyor/j07uoOCGLKtU5F87vTPwIzLe/o=
+github.com/emicklei/proto v1.12.2/go.mod h1:rn1FgRS/FANiZdD2djyH7TMA9jdRDcYQ9IEN9yvjX0A=
github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4=
github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94=
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-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
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.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
+github.com/go-logr/logr v1.2.4/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-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE=
github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
-github.com/go-openapi/jsonreference v0.20.1 h1:FBLnyygC4/IZZr893oiomc9XaghoveYTrLC1F86HID8=
-github.com/go-openapi/jsonreference v0.20.1/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k=
-github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g=
+github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE=
+github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k=
github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
+github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU=
+github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI=
github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo=
github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI=
github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
+github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
-github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
-github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4=
-github.com/golang/glog v1.1.0 h1:/d3pCKDPWNnvIWe0vVUpNP32qc8U3PDVxySP/y360qE=
-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/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/glog v1.1.2 h1:DVjP2PbBOzHyzA+dn3WhHIq4NdVu3Q+pvivFICf/7fo=
+github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
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=
-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/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
-github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
-github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
-github.com/google/gnostic v0.5.7-v3refs h1:FhTMOKj2VhjpouxvWJAV1TL304uMlb9zcDqkl6cEI54=
-github.com/google/gnostic v0.5.7-v3refs/go.mod h1:73MKFl6jIHelAJNaBGFzt3SPtZULs9dYrGFt8OiIsHQ=
-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/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I=
+github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U=
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.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/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
github.com/google/gofuzz v1.2.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/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/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/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/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec=
+github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4=
+github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gookit/color v1.5.4 h1:FZmqs7XOyGgCAxmWyPslpiok1k05wmY3SJTytgvYFs0=
github.com/gookit/color v1.5.4/go.mod h1:pZJOeOS8DM43rXbp4AZo1n9zCU2qjpcRko0b6/QJi9w=
-github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
-github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks=
-github.com/grpc-ecosystem/grpc-gateway/v2 v2.15.0 h1:1JYBfzqrWPcCclBwxFCPAou9n+q86mfnu7NAeHfte7A=
-github.com/grpc-ecosystem/grpc-gateway/v2 v2.15.0/go.mod h1:YDZoGHuwE+ov0c8smSH49WLF3F2LaWnYYuDVd+EWrc0=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.0 h1:RtRsiaGvWxcwd8y3BiRZxsylPT8hLWZ5SPcfI+3IDNk=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.0/go.mod h1:TzP6duP4Py2pHLVPPQp42aoYI92+PCrVotyR5e8Vqlk=
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw=
-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/iancoleman/strcase v0.3.0 h1:nTXanmYxhfFAMjZL34Ov6gkzEsSJZ5DbhxWjvSASxEI=
github.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=
-github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
@@ -205,12 +99,8 @@ github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8Hm
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
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/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/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.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
@@ -224,8 +114,8 @@ github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJ
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.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/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
+github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@@ -237,44 +127,37 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
-github.com/onsi/ginkgo/v2 v2.7.0 h1:/XxtEV3I3Eif/HobnVx9YmJgk8ENdRsuUmM+fLCFNow=
-github.com/onsi/gomega v1.26.0 h1:03cDLK28U6hWvCAns6NeydX3zIm4SF3ci69ulidS32Q=
-github.com/openzipkin/zipkin-go v0.4.1 h1:kNd/ST2yLLWhaWrkgchya40TJabe8Hioj9udfPcEO5A=
-github.com/openzipkin/zipkin-go v0.4.1/go.mod h1:qY0VqDSN1pOBN94dBc6w2GJlWLiovAyg7Qt6/I9HecM=
-github.com/pelletier/go-toml/v2 v2.0.9 h1:uH2qQXheeefCCkuBBSLi7jCiSmj3VRh2+Goq2N7Xxu0=
-github.com/pelletier/go-toml/v2 v2.0.9/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
+github.com/onsi/ginkgo/v2 v2.11.0 h1:WgqUCUt/lT6yXoQ8Wef0fsNn5cAuMK7+KT9UFRz2tcU=
+github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI=
+github.com/openzipkin/zipkin-go v0.4.2 h1:zjqfqHjUpPmB3c1GlCvvgsM1G4LkvqQbBDueDOCg/jA=
+github.com/openzipkin/zipkin-go v0.4.2/go.mod h1:ZeVkFjuuBiSy13y8vpSDCjMi9GoI3hPpCJSBx/EYFhY=
+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/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
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/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g=
-github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8=
-github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc=
-github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/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.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM=
-github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc=
-github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+PymziUAg=
-github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM=
-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.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
+github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q=
+github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY=
+github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 h1:v7DLqVdK4VrYkVD5diGdl4sxJurKJEMnODWRJlxV9oM=
+github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU=
+github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY=
+github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY=
+github.com/prometheus/procfs v0.11.1 h1:xRC8Iq1yyca5ypa9n1EZnWZkt7dwcoRPQwX/5gwaUuI=
+github.com/prometheus/procfs v0.11.1/go.mod h1:eesXgaPo1q7lBpVMoMy0ZOFTth9hBn4W/y0/p/ScXhY=
+github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
-github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
-github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I=
-github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0=
+github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0=
+github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=
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/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
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.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=
@@ -285,53 +168,46 @@ github.com/withfig/autocomplete-tools/integrations/cobra v1.2.1 h1:+dBg5k7nuTE38
github.com/withfig/autocomplete-tools/integrations/cobra v1.2.1/go.mod h1:nmuySobZb4kFgFy6BptpXp/BBw+xFSyvVPP6auoJB4k=
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 h1:QldyIu/L63oPpyvQmHgvgickp1Yw510KJOqX7H24mg8=
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs=
-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/yuin/gopher-lua v1.1.0 h1:BojcDhfyDWgU2f2TOzYK/g5p2gxMrku8oupLDqlnSqE=
github.com/yuin/gopher-lua v1.1.0/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw=
github.com/zeromicro/antlr v0.0.1 h1:CQpIn/dc0pUjgGQ81y98s/NGOm2Hfru2NNio2I9mQgk=
github.com/zeromicro/antlr v0.0.1/go.mod h1:nfpjEwFR6Q4xGDJMcZnCL9tEfQRgszMwu3rDz2Z+p5M=
github.com/zeromicro/ddl-parser v1.0.5 h1:LaVqHdzMTjasua1yYpIYaksxKqRzFrEukj2Wi2EbWaQ=
github.com/zeromicro/ddl-parser v1.0.5/go.mod h1:ISU/8NuPyEpl9pa17Py9TBPetMjtsiHrb9f5XGiYbo8=
-github.com/zeromicro/go-zero v1.5.5 h1:qEHnDuCBu/gDBmfWEZXYow6ZmWmzsrJTjtjSMVm4SiY=
-github.com/zeromicro/go-zero v1.5.5/go.mod h1:AGCspTFitHzYjl5ddAmYWLfdt341+BrhefqlwO45UbU=
-go.etcd.io/etcd/api/v3 v3.5.9 h1:4wSsluwyTbGGmyjJktOf3wFQoTBIURXHnq9n/G/JQHs=
-go.etcd.io/etcd/api/v3 v3.5.9/go.mod h1:uyAal843mC8uUVSLWz6eHa/d971iDGnCRpmKd2Z+X8k=
-go.etcd.io/etcd/client/pkg/v3 v3.5.9 h1:oidDC4+YEuSIQbsR94rY9gur91UPL6DnxDCIYd2IGsE=
-go.etcd.io/etcd/client/pkg/v3 v3.5.9/go.mod h1:y+CzeSmkMpWN2Jyu1npecjB9BBnABxGM4pN8cGuJeL4=
-go.etcd.io/etcd/client/v3 v3.5.9 h1:r5xghnU7CwbUxD/fbUtRyJGaYNfDun8sp/gTr1hew6E=
-go.etcd.io/etcd/client/v3 v3.5.9/go.mod h1:i/Eo5LrZ5IKqpbtpPDuaUnDOUv471oDg8cjQaUr2MbA=
-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.opentelemetry.io/otel v1.14.0 h1:/79Huy8wbf5DnIPhemGB+zEPVwnN6fuQybr/SRXa6hM=
-go.opentelemetry.io/otel v1.14.0/go.mod h1:o4buv+dJzx8rohcUeRmWUZhqupFvzWis188WlggnNeU=
-go.opentelemetry.io/otel/exporters/jaeger v1.14.0 h1:CjbUNd4iN2hHmWekmOqZ+zSCU+dzZppG8XsV+A3oc8Q=
-go.opentelemetry.io/otel/exporters/jaeger v1.14.0/go.mod h1:4Ay9kk5vELRrbg5z4cpP9EtmQRFap2Wb0woPG4lujZA=
-go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.14.0 h1:/fXHZHGvro6MVqV34fJzDhi7sHGpX3Ej/Qjmfn003ho=
-go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.14.0/go.mod h1:UFG7EBMRdXyFstOwH028U0sVf+AvukSGhF0g8+dmNG8=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.14.0 h1:TKf2uAs2ueguzLaxOCBXNpHxfO/aC7PAdDsSH0IbeRQ=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.14.0/go.mod h1:HrbCVv40OOLTABmOn1ZWty6CHXkU8DK/Urc43tHug70=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.14.0 h1:ap+y8RXX3Mu9apKVtOkM6WSFESLM8K3wNQyOU8sWHcc=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.14.0/go.mod h1:5w41DY6S9gZrbjuq6Y+753e96WfPha5IcsOSZTtullM=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.14.0 h1:3jAYbRHQAqzLjd9I4tzxwJ8Pk/N6AqBcF6m1ZHrxG94=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.14.0/go.mod h1:+N7zNjIJv4K+DeX67XXET0P+eIciESgaFDBqh+ZJFS4=
-go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.14.0 h1:sEL90JjOO/4yhquXl5zTAkLLsZ5+MycAgX99SDsxGc8=
-go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.14.0/go.mod h1:oCslUcizYdpKYyS9e8srZEqM6BB8fq41VJBjLAE6z1w=
-go.opentelemetry.io/otel/exporters/zipkin v1.14.0 h1:reEVE1upBF9tcujgvSqLJS0SrI7JQPaTKP4s4rymnSs=
-go.opentelemetry.io/otel/exporters/zipkin v1.14.0/go.mod h1:RcjvOAcvhzcufQP8aHmzRw1gE9g/VEZufDdo2w+s4sk=
-go.opentelemetry.io/otel/sdk v1.14.0 h1:PDCppFRDq8A1jL9v6KMI6dYesaq+DFcDZvjsoGvxGzY=
-go.opentelemetry.io/otel/sdk v1.14.0/go.mod h1:bwIC5TjrNG6QDCHNWvW4HLHtUQ4I+VQDsnjhvyZCALM=
-go.opentelemetry.io/otel/trace v1.14.0 h1:wp2Mmvj41tDsyAJXiWDWpfNsOiIyd38fy85pyKcFq/M=
-go.opentelemetry.io/otel/trace v1.14.0/go.mod h1:8avnQLK+CG77yNLUae4ea2JDQ6iT+gozhnZjy/rw9G8=
-go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
-go.opentelemetry.io/proto/otlp v0.19.0 h1:IVN6GR+mhC4s5yfcTbmzHYODqvWAp3ZedA2SJPI1Nnw=
-go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U=
+github.com/zeromicro/go-zero v1.6.0 h1:UwSOR1lGZ2g7L0S07PM8RoneAcubtd5x//EfbuNucQ0=
+github.com/zeromicro/go-zero v1.6.0/go.mod h1:E9GCFPb0SwsTKFBcFr9UynGvXiDMmfc6fI5F15vqvAQ=
+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/v3 v3.5.10 h1:W9TXNZ+oB3MCd/8UjxHTWK5J9Nquw9fQBLJd5ne5/Ao=
+go.etcd.io/etcd/client/v3 v3.5.10/go.mod h1:RVeBnDz2PUEZqTpgqwAtUd8nAPf5kjyFyND7P1VkOKc=
+go.opentelemetry.io/otel v1.19.0 h1:MuS/TNf4/j4IXsZuJegVzI1cwut7Qc00344rgH7p8bs=
+go.opentelemetry.io/otel v1.19.0/go.mod h1:i0QyjOq3UPoTzff0PJB2N66fb4S0+rSbSB15/oyH9fY=
+go.opentelemetry.io/otel/exporters/jaeger v1.17.0 h1:D7UpUy2Xc2wsi1Ras6V40q806WM07rqoCWzXu7Sqy+4=
+go.opentelemetry.io/otel/exporters/jaeger v1.17.0/go.mod h1:nPCqOnEH9rNLKqH/+rrUjiMzHJdV1BlpKcTwRTyKkKI=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 h1:Mne5On7VWdx7omSrSSZvM4Kw7cS7NQkOOmLcgscI51U=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0/go.mod h1:IPtUMKL4O3tH5y+iXVyAXqpAwMuzC1IrxVS81rummfE=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.19.0 h1:3d+S281UTjM+AbF31XSOYn1qXn3BgIdWl8HNEpx08Jk=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.19.0/go.mod h1:0+KuTDyKL4gjKCF75pHOX4wuzYDUZYfAQdSu43o+Z2I=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0 h1:IeMeyr1aBvBiPVYihXIaeIZba6b8E1bYp7lbdxK8CQg=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0/go.mod h1:oVdCUtjq9MK9BlS7TtucsQwUcXcymNiEDjgDD2jMtZU=
+go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.19.0 h1:Nw7Dv4lwvGrI68+wULbcq7su9K2cebeCUrDjVrUJHxM=
+go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.19.0/go.mod h1:1MsF6Y7gTqosgoZvHlzcaaM8DIMNZgJh87ykokoNH7Y=
+go.opentelemetry.io/otel/exporters/zipkin v1.19.0 h1:EGY0h5mGliP9o/nIkVuLI0vRiQqmsYOcbwCuotksO1o=
+go.opentelemetry.io/otel/exporters/zipkin v1.19.0/go.mod h1:JQgTGJP11yi3o4GHzIWYodhPisxANdqxF1eHwDSnJrI=
+go.opentelemetry.io/otel/metric v1.19.0 h1:aTzpGtV0ar9wlV4Sna9sdJyII5jTVJEvKETPiOKwvpE=
+go.opentelemetry.io/otel/metric v1.19.0/go.mod h1:L5rUsV9kM1IxCj1MmSdS+JQAcVm319EUrDVLrt7jqt8=
+go.opentelemetry.io/otel/sdk v1.19.0 h1:6USY6zH+L8uMH8L3t1enZPR3WFEmSTADlqldyHtJi3o=
+go.opentelemetry.io/otel/sdk v1.19.0/go.mod h1:NedEbbS4w3C6zElbLdPJKOpJQOrGUJ+GfzpjUvI0v1A=
+go.opentelemetry.io/otel/trace v1.19.0 h1:DFVQmlVbfVeOuBRrwdtaehRrWiL1JoVs9CPIQ1Dzxpg=
+go.opentelemetry.io/otel/trace v1.19.0/go.mod h1:mfaSyvGyEJEI0nyV2I4qhNQnbBOUUmYZpYojqMnX2vo=
+go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I=
+go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM=
go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ=
go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
go.uber.org/automaxprocs v1.5.3 h1:kWazyxZUrS3Gs4qUpbwo5kEIMGe/DAvi5Z4tl2NW4j8=
@@ -342,324 +218,109 @@ go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTV
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-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-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk=
-golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
-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/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/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
+golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
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.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-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-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/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
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-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-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-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
-golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14=
-golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
-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-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
-golang.org/x/oauth2 v0.7.0 h1:qe6s0zUXlPX80/dITx3440hWZ7GwMwgDDyrSGTPJG/g=
-golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4=
-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/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
+golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
+golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
+golang.org/x/oauth2 v0.12.0 h1:smVPGxink+n1ZI5pkQa8y6fZT0RW0MgCO5bFpepy4B4=
+golang.org/x/oauth2 v0.12.0/go.mod h1:A74bZ3aGXgCY0qaIC9Ahg6Lglin4AMAco8cIv9baba4=
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-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/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-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-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-20191001151750-bb3f8db39f24/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-20200113162924-86b910548bc1/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-20200803210538-64077c9b5642/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-20210330210617-4fbd30eecc44/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-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM=
-golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
+golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
-golang.org/x/term v0.11.0 h1:F9tnn/DA/Im8nCwm+fX+1/eBwi4qFjRT++MhtVC4ZX0=
-golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU=
-golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
+golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek=
+golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
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.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
-golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
-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.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
+golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
+golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
+golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
golang.org/x/time v0.3.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-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-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-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
+golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
+golang.org/x/tools v0.9.3 h1:Gn1I8+64MsuTb/HpH+LmQtNas23LhUVr3rYZ0eKuaMM=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-google.golang.org/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/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-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
-google.golang.org/genproto v0.0.0-20230526161137-0005af68ea54 h1:9NWlQfY2ePejTmfwUH1OWwmznFa+0kKcHGPDvcPza9M=
-google.golang.org/genproto v0.0.0-20230526161137-0005af68ea54/go.mod h1:zqTuNwFlFRsw5zIts5VnzLQxSRqh+CGOTVMlYbY0Eyk=
-google.golang.org/genproto/googleapis/api v0.0.0-20230525234035-dd9d682886f9 h1:m8v1xLLLzMe1m5P+gCTF8nJB9epwZQUBERm20Oy1poQ=
-google.golang.org/genproto/googleapis/api v0.0.0-20230525234035-dd9d682886f9/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 h1:0nDDozoAU19Qb2HwhXadU8OcsiO/09cnTqhUtq2MEOM=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA=
-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.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
-google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
-google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
-google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
-google.golang.org/grpc v1.57.0 h1:kfzNeI/klCGD2YPMUlaGNT3pxvYfga7smW3Vth8Zsiw=
-google.golang.org/grpc v1.57.0/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt16Mo=
-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/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-20231016165738-49dd2c1f3d0b h1:+YaDE2r2OG8t/z5qmsh7Y+XXwCbvadxxZ0YY6mTdrVA=
+google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:CgAqfJo+Xmu0GwA0411Ht3OU3OntXwsGmrmjI8ioGXI=
+google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b h1:CIC2YMXmIhYw6evmhPxBKJ4fmLbOFtXQN/GV3XOZR8k=
+google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:IBQ646DjkDkvUIsVq/cc03FUFQ9wbZu7yE396YcL870=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b h1:ZlWIi1wSK56/8hn4QcBp/j9M7Gt3U/3hZw3mC7vDICo=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:swOH3j0KzcDDgGUWr+SNpyTen5YrXjS3eyPzFYKc6lc=
+google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk=
+google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98=
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.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
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-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
-gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/h2non/gock.v1 v1.1.2 h1:jBbHXgGBK/AoPVfJh5x4r/WxIrElvbLel8TCZkkZJoY=
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
-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.8/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-20200615113413-eeeca48fe776/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=
-k8s.io/api v0.26.3 h1:emf74GIQMTik01Aum9dPP0gAypL8JTLl/lHa4V9RFSU=
-k8s.io/api v0.26.3/go.mod h1:PXsqwPMXBSBcL1lJ9CYDKy7kIReUydukS5JiRlxC3qE=
-k8s.io/apimachinery v0.27.0-alpha.3 h1:uujqsdFrbqF+cEbqFHrkLKp+s3XxRgphTpc6Yg84qLo=
-k8s.io/apimachinery v0.27.0-alpha.3/go.mod h1:TO4higCGNMwebVSdb1XPJdXMU4kk+nmMY/cTMVCGa6M=
-k8s.io/client-go v0.26.3 h1:k1UY+KXfkxV2ScEL3gilKcF7761xkYsSD6BC9szIu8s=
-k8s.io/client-go v0.26.3/go.mod h1:ZPNu9lm8/dbRIPAgteN30RSXea6vrCpFvq+MateTUuQ=
-k8s.io/klog/v2 v2.90.1 h1:m4bYOKall2MmOiRaR1J+We67Do7vm9KiQVlT96lnHUw=
-k8s.io/klog/v2 v2.90.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
-k8s.io/kube-openapi v0.0.0-20230307230338-69ee2d25a840 h1:1Q4XWtrQQh04ZweCpL7aMNYafFMoPEiST4dl5b4PmYw=
-k8s.io/kube-openapi v0.0.0-20230307230338-69ee2d25a840/go.mod h1:y5VtZWM9sHHc2ZodIH/6SHzXj+TPU5USoA8lcIeKEKY=
-k8s.io/utils v0.0.0-20230209194617-a36077c30491 h1:r0BAOLElQnnFhE/ApUsg3iHdVYYPBjNSSOMowRZxxsY=
-k8s.io/utils v0.0.0-20230209194617-a36077c30491/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
-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=
+k8s.io/api v0.28.3 h1:Gj1HtbSdB4P08C8rs9AR94MfSGpRhJgsS+GF9V26xMM=
+k8s.io/api v0.28.3/go.mod h1:MRCV/jr1dW87/qJnZ57U5Pak65LGmQVkKTzf3AtKFHc=
+k8s.io/apimachinery v0.28.3 h1:B1wYx8txOaCQG0HmYF6nbpU8dg6HvA06x5tEffvOe7A=
+k8s.io/apimachinery v0.28.3/go.mod h1:uQTKmIqs+rAYaq+DFaoD2X7pcjLOqbQX2AOiO0nIpb8=
+k8s.io/client-go v0.28.3 h1:2OqNb72ZuTZPKCl+4gTKvqao0AMOl9f3o2ijbAj3LI4=
+k8s.io/client-go v0.28.3/go.mod h1:LTykbBp9gsA7SwqirlCXBWtK0guzfhpoW4qSm7i9dxo=
+k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg=
+k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
+k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 h1:aVUu9fTY98ivBPKR9Y5w/AuzbMm96cd3YHRTU83I780=
+k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00/go.mod h1:AsvuZPBlUDVuCdzJ87iajxtXuR9oktsTctW/R9wwouA=
+k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI=
+k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE=
diff --git a/tools/goctl/internal/version/version.go b/tools/goctl/internal/version/version.go
index 5fd996d0b536..c1f3947c29f8 100644
--- a/tools/goctl/internal/version/version.go
+++ b/tools/goctl/internal/version/version.go
@@ -6,7 +6,7 @@ import (
)
// BuildVersion is the version of goctl.
-const BuildVersion = "1.5.5"
+const BuildVersion = "1.6.0"
var tag = map[string]int{"pre-alpha": 0, "alpha": 1, "pre-bata": 2, "beta": 3, "released": 4, "": 5}
diff --git a/tools/goctl/model/cmd.go b/tools/goctl/model/cmd.go
index faaf63e6ecf9..e340f2c58729 100644
--- a/tools/goctl/model/cmd.go
+++ b/tools/goctl/model/cmd.go
@@ -46,7 +46,7 @@ func init() {
datasourceCmdFlags.StringVar(&command.VarStringBranch, "branch")
pgDatasourceCmdFlags.StringVar(&command.VarStringURL, "url")
- pgDatasourceCmdFlags.StringVarP(&command.VarStringTable, "table", "t")
+ pgDatasourceCmdFlags.StringSliceVarP(&command.VarStringSliceTable, "table", "t")
pgDatasourceCmdFlags.StringVarPWithDefaultValue(&command.VarStringSchema, "schema", "s", "public")
pgDatasourceCmdFlags.BoolVarP(&command.VarBoolCache, "cache", "c")
pgDatasourceCmdFlags.StringVarP(&command.VarStringDir, "dir", "d")
@@ -56,6 +56,8 @@ func init() {
pgDatasourceCmdFlags.StringVar(&command.VarStringHome, "home")
pgDatasourceCmdFlags.StringVar(&command.VarStringRemote, "remote")
pgDatasourceCmdFlags.StringVar(&command.VarStringBranch, "branch")
+ pgCmd.PersistentFlags().StringSliceVarPWithDefaultValue(&command.VarStringSliceIgnoreColumns,
+ "ignore-columns", "i", []string{"create_at", "created_at", "create_time", "update_at", "updated_at", "update_time"})
mongoCmdFlags.StringSliceVarP(&mongo.VarStringSliceType, "type", "t")
mongoCmdFlags.BoolVarP(&mongo.VarBoolCache, "cache", "c")
@@ -67,7 +69,8 @@ func init() {
mongoCmdFlags.StringVar(&mongo.VarStringBranch, "branch")
mysqlCmd.PersistentFlags().BoolVar(&command.VarBoolStrict, "strict")
- mysqlCmd.PersistentFlags().StringSliceVarPWithDefaultValue(&command.VarStringSliceIgnoreColumns, "ignore-columns", "i", []string{"create_at", "created_at", "create_time", "update_at", "updated_at", "update_time"})
+ mysqlCmd.PersistentFlags().StringSliceVarPWithDefaultValue(&command.VarStringSliceIgnoreColumns,
+ "ignore-columns", "i", []string{"create_at", "created_at", "create_time", "update_at", "updated_at", "update_time"})
mysqlCmd.AddCommand(datasourceCmd, ddlCmd)
pgCmd.AddCommand(pgDatasourceCmd)
diff --git a/tools/goctl/model/sql/README.MD b/tools/goctl/model/sql/README.MD
index ae58f9b4683f..db92d7151aee 100644
--- a/tools/goctl/model/sql/README.MD
+++ b/tools/goctl/model/sql/README.MD
@@ -344,7 +344,7 @@ OPTIONS:
理论上是没任何问题,但是我们认为,对于model层的数据操作均是以整个结构体为单位,包括查询,我不建议只查询某部分字段(不反对),否则我们的缓存就没有意义了。
-* 为什么不支持`findPageLimit`、`findAll`这么模式代码生层?
+* 为什么不支持`findPageLimit`、`findAll`这种模型代码生成?
目前,我认为除了基本的CURD外,其他的代码均属于业务型代码,这个我觉得开发人员根据业务需要进行编写更好。
@@ -378,4 +378,4 @@ OPTIONS:
| longtext | string | sql.NullString |
| enum | string | sql.NullString |
| set | string | sql.NullString |
-| json | string | sql.NullString |
\ No newline at end of file
+| json | string | sql.NullString |
diff --git a/tools/goctl/model/sql/command/command.go b/tools/goctl/model/sql/command/command.go
index f00b422901c1..e29a3092a82e 100644
--- a/tools/goctl/model/sql/command/command.go
+++ b/tools/goctl/model/sql/command/command.go
@@ -35,8 +35,6 @@ var (
VarStringURL string
// VarStringSliceTable describes tables.
VarStringSliceTable []string
- // VarStringTable describes a table of sql.
- VarStringTable string
// VarStringStyle describes the style.
VarStringStyle string
// VarStringDatabase describes the database.
@@ -211,13 +209,14 @@ func PostgreSqlDataSource(_ *cobra.Command, _ []string) error {
schema = "public"
}
- pattern := strings.TrimSpace(VarStringTable)
+ patterns := parseTableList(VarStringSliceTable)
cfg, err := config.NewConfig(style)
if err != nil {
return err
}
+ ignoreColumns := mergeColumns(VarStringSliceIgnoreColumns)
- return fromPostgreSqlDataSource(url, pattern, dir, schema, cfg, cache, idea, VarBoolStrict)
+ return fromPostgreSqlDataSource(url, patterns, dir, schema, cfg, cache, idea, VarBoolStrict, ignoreColumns)
}
type ddlArg struct {
@@ -329,7 +328,7 @@ func fromMysqlDataSource(arg dataSourceArg) error {
return generator.StartFromInformationSchema(matchTables, arg.cache, arg.strict)
}
-func fromPostgreSqlDataSource(url, pattern, dir, schema string, cfg *config.Config, cache, idea, strict bool) error {
+func fromPostgreSqlDataSource(url string, pattern pattern, dir, schema string, cfg *config.Config, cache, idea, strict bool, ignoreColumns []string) error {
log := console.NewConsole(idea)
if len(url) == 0 {
log.Error("%v", "expected data source of postgresql, but nothing found")
@@ -350,12 +349,7 @@ func fromPostgreSqlDataSource(url, pattern, dir, schema string, cfg *config.Conf
matchTables := make(map[string]*model.Table)
for _, item := range tables {
- match, err := filepath.Match(pattern, item)
- if err != nil {
- return err
- }
-
- if !match {
+ if !pattern.Match(item) {
continue
}
@@ -376,7 +370,7 @@ func fromPostgreSqlDataSource(url, pattern, dir, schema string, cfg *config.Conf
return errors.New("no tables matched")
}
- generator, err := gen.NewDefaultGenerator(dir, cfg, gen.WithConsoleOption(log), gen.WithPostgreSql())
+ generator, err := gen.NewDefaultGenerator(dir, cfg, gen.WithConsoleOption(log), gen.WithPostgreSql(), gen.WithIgnoreColumns(ignoreColumns))
if err != nil {
return err
}
diff --git a/tools/goctl/model/sql/gen/keys_test.go b/tools/goctl/model/sql/gen/keys_test.go
index 145f136ed802..c54cc4fed114 100644
--- a/tools/goctl/model/sql/gen/keys_test.go
+++ b/tools/goctl/model/sql/gen/keys_test.go
@@ -76,9 +76,9 @@ func TestGenCacheKeys(t *testing.T) {
VarExpression: `cacheGoZeroUserIdPrefix = "cache:goZero:user:id:"`,
KeyLeft: "goZeroUserIdKey",
KeyRight: `fmt.Sprintf("%s%v", cacheGoZeroUserIdPrefix, id)`,
- DataKeyRight: `fmt.Sprintf("%s%v", cacheGoZeroUserIdPrefix, data.ID)`,
+ DataKeyRight: `fmt.Sprintf("%s%v", cacheGoZeroUserIdPrefix, data.Id)`,
KeyExpression: `goZeroUserIdKey := fmt.Sprintf("%s%v", cacheGoZeroUserIdPrefix, id)`,
- DataKeyExpression: `goZeroUserIdKey := fmt.Sprintf("%s%v", cacheGoZeroUserIdPrefix, data.ID)`,
+ DataKeyExpression: `goZeroUserIdKey := fmt.Sprintf("%s%v", cacheGoZeroUserIdPrefix, data.Id)`,
FieldNameJoin: []string{"id"},
})
}())
@@ -170,9 +170,9 @@ func TestGenCacheKeys(t *testing.T) {
VarExpression: `cacheUserIdPrefix = "cache:user:id:"`,
KeyLeft: "userIdKey",
KeyRight: `fmt.Sprintf("%s%v", cacheUserIdPrefix, id)`,
- DataKeyRight: `fmt.Sprintf("%s%v", cacheUserIdPrefix, data.ID)`,
+ DataKeyRight: `fmt.Sprintf("%s%v", cacheUserIdPrefix, data.Id)`,
KeyExpression: `userIdKey := fmt.Sprintf("%s%v", cacheUserIdPrefix, id)`,
- DataKeyExpression: `userIdKey := fmt.Sprintf("%s%v", cacheUserIdPrefix, data.ID)`,
+ DataKeyExpression: `userIdKey := fmt.Sprintf("%s%v", cacheUserIdPrefix, data.Id)`,
FieldNameJoin: []string{"id"},
})
}())
diff --git a/tools/goctl/model/sql/template/tpl/find-one.tpl b/tools/goctl/model/sql/template/tpl/find-one.tpl
index a808558000b8..4f9319d1c341 100644
--- a/tools/goctl/model/sql/template/tpl/find-one.tpl
+++ b/tools/goctl/model/sql/template/tpl/find-one.tpl
@@ -18,7 +18,7 @@ func (m *default{{.upperStartCamelObject}}Model) FindOne(ctx context.Context, {{
switch err {
case nil:
return &resp, nil
- case sqlc.ErrNotFound:
+ case sqlx.ErrNotFound:
return nil, ErrNotFound
default:
return nil, err
diff --git a/tools/goctl/model/sql/template/tpl/model-new.tpl b/tools/goctl/model/sql/template/tpl/model-new.tpl
index 1743e57896ec..f6271ccac2a2 100644
--- a/tools/goctl/model/sql/template/tpl/model-new.tpl
+++ b/tools/goctl/model/sql/template/tpl/model-new.tpl
@@ -5,9 +5,3 @@ func new{{.upperStartCamelObject}}Model(conn sqlx.SqlConn{{if .withCache}}, c ca
}
}
-func (m *default{{.upperStartCamelObject}}Model) withSession(session sqlx.Session) *default{{.upperStartCamelObject}}Model {
- return &default{{.upperStartCamelObject}}Model{
- {{if .withCache}}CachedConn:m.CachedConn.WithSession(session){{else}}conn:sqlx.NewSqlConnFromSession(session){{end}},
- table: {{.table}},
- }
-}
diff --git a/tools/goctl/model/sql/template/tpl/model.tpl b/tools/goctl/model/sql/template/tpl/model.tpl
index 3b1b10135bc4..d861da7968e5 100644
--- a/tools/goctl/model/sql/template/tpl/model.tpl
+++ b/tools/goctl/model/sql/template/tpl/model.tpl
@@ -15,6 +15,7 @@ type (
// and implement the added methods in custom{{.upperStartCamelObject}}Model.
{{.upperStartCamelObject}}Model interface {
{{.lowerStartCamelObject}}Model
+ {{if not .withCache}}withSession(session sqlx.Session) {{.upperStartCamelObject}}Model{{end}}
}
custom{{.upperStartCamelObject}}Model struct {
@@ -28,3 +29,10 @@ func New{{.upperStartCamelObject}}Model(conn sqlx.SqlConn{{if .withCache}}, c ca
default{{.upperStartCamelObject}}Model: new{{.upperStartCamelObject}}Model(conn{{if .withCache}}, c, opts...{{end}}),
}
}
+
+{{if not .withCache}}
+func (m *custom{{.upperStartCamelObject}}Model) withSession(session sqlx.Session) {{.upperStartCamelObject}}Model {
+ return New{{.upperStartCamelObject}}Model(sqlx.NewSqlConnFromSession(session))
+}
+{{end}}
+
diff --git a/tools/goctl/model/sql/test/model/model_test.go b/tools/goctl/model/sql/test/model/model_test.go
index 08bf121c16c4..d42680edf17d 100644
--- a/tools/goctl/model/sql/test/model/model_test.go
+++ b/tools/goctl/model/sql/test/model/model_test.go
@@ -43,7 +43,7 @@ func TestStudentModel(t *testing.T) {
Valid: true,
}
- err := mockStudent(func(mock sqlmock.Sqlmock) {
+ err := mockStudent(t, func(mock sqlmock.Sqlmock) {
mock.ExpectExec(fmt.Sprintf("insert into %s", testTable)).
WithArgs(data.Class, data.Name, data.Age, data.Score).
WillReturnResult(sqlmock.NewResult(testInsertId, testRowsAffected))
@@ -61,7 +61,7 @@ func TestStudentModel(t *testing.T) {
})
assert.Nil(t, err)
- err = mockStudent(func(mock sqlmock.Sqlmock) {
+ err = mockStudent(t, func(mock sqlmock.Sqlmock) {
mock.ExpectQuery(fmt.Sprintf("select (.+) from %s", testTable)).
WithArgs(testInsertId).
WillReturnRows(sqlmock.NewRows([]string{"id", "class", "name", "age", "score", "create_time", "update_time"}).AddRow(testInsertId, data.Class, data.Name, data.Age, data.Score, testTimeValue, testTimeValue))
@@ -79,7 +79,7 @@ func TestStudentModel(t *testing.T) {
})
assert.Nil(t, err)
- err = mockStudent(func(mock sqlmock.Sqlmock) {
+ err = mockStudent(t, func(mock sqlmock.Sqlmock) {
mock.ExpectExec(fmt.Sprintf("update %s", testTable)).WithArgs(data.Class, testUpdateName, data.Age, data.Score, testInsertId).WillReturnResult(sqlmock.NewResult(testInsertId, testRowsAffected))
}, func(m StudentModel, redis *redis.Redis) {
data.Name = testUpdateName
@@ -93,7 +93,7 @@ func TestStudentModel(t *testing.T) {
assert.Nil(t, err)
data.Name = testUpdateName
- err = mockStudent(func(mock sqlmock.Sqlmock) {
+ err = mockStudent(t, func(mock sqlmock.Sqlmock) {
mock.ExpectQuery(fmt.Sprintf("select (.+) from %s ", testTable)).
WithArgs(testInsertId).
WillReturnRows(sqlmock.NewRows([]string{"id", "class", "name", "age", "score", "create_time", "update_time"}).AddRow(testInsertId, data.Class, data.Name, data.Age, data.Score, testTimeValue, testTimeValue))
@@ -111,7 +111,7 @@ func TestStudentModel(t *testing.T) {
})
assert.Nil(t, err)
- err = mockStudent(func(mock sqlmock.Sqlmock) {
+ err = mockStudent(t, func(mock sqlmock.Sqlmock) {
mock.ExpectQuery(fmt.Sprintf("select (.+) from %s ", testTable)).
WithArgs(class, testUpdateName).
WillReturnRows(sqlmock.NewRows([]string{"id", "class", "name", "age", "score", "create_time", "update_time"}).AddRow(testInsertId, data.Class, data.Name, data.Age, data.Score, testTimeValue, testTimeValue))
@@ -126,7 +126,7 @@ func TestStudentModel(t *testing.T) {
})
assert.Nil(t, err)
- err = mockStudent(func(mock sqlmock.Sqlmock) {
+ err = mockStudent(t, func(mock sqlmock.Sqlmock) {
mock.ExpectExec(fmt.Sprintf("delete from %s where `id` = ?", testTable)).WithArgs(testInsertId).WillReturnResult(sqlmock.NewResult(testInsertId, testRowsAffected))
}, func(m StudentModel, redis *redis.Redis) {
err = m.Delete(testInsertId, class, testUpdateName)
@@ -228,7 +228,7 @@ func TestUserModel(t *testing.T) {
}
// with cache
-func mockStudent(mockFn func(mock sqlmock.Sqlmock), fn func(m StudentModel, r *redis.Redis)) error {
+func mockStudent(t *testing.T, mockFn func(mock sqlmock.Sqlmock), fn func(m StudentModel, r *redis.Redis)) error {
db, mock, err := sqlmock.New()
if err != nil {
return err
@@ -241,13 +241,7 @@ func mockStudent(mockFn func(mock sqlmock.Sqlmock), fn func(m StudentModel, r *r
mock.ExpectCommit()
conn := mocksql.NewMockConn(db)
- r, clean, err := redistest.CreateRedis()
- if err != nil {
- return err
- }
-
- defer clean()
-
+ r := redistest.CreateRedis(t)
m := NewStudentModel(conn, cache.CacheConf{
{
RedisConf: redis.RedisConf{
diff --git a/tools/goctl/model/sql/test/orm.go b/tools/goctl/model/sql/test/orm.go
index 4f84f6f25ac0..00b061d5bc97 100644
--- a/tools/goctl/model/sql/test/orm.go
+++ b/tools/goctl/model/sql/test/orm.go
@@ -128,7 +128,7 @@ func unmarshalRow(v any, scanner rowsScanner, strict bool) error {
}
rv := reflect.ValueOf(v)
- if err := mapping.ValidatePtr(&rv); err != nil {
+ if err := mapping.ValidatePtr(rv); err != nil {
return err
}
@@ -163,7 +163,7 @@ func unmarshalRow(v any, scanner rowsScanner, strict bool) error {
func unmarshalRows(v any, scanner rowsScanner, strict bool) error {
rv := reflect.ValueOf(v)
- if err := mapping.ValidatePtr(&rv); err != nil {
+ if err := mapping.ValidatePtr(rv); err != nil {
return err
}
diff --git a/tools/goctl/pkg/env/env.go b/tools/goctl/pkg/env/env.go
index a617784037e4..2a7ce052154c 100644
--- a/tools/goctl/pkg/env/env.go
+++ b/tools/goctl/pkg/env/env.go
@@ -7,6 +7,7 @@ import (
"path/filepath"
"runtime"
"strings"
+ "testing"
"github.com/zeromicro/go-zero/tools/goctl/internal/version"
sortedmap "github.com/zeromicro/go-zero/tools/goctl/pkg/collection"
@@ -59,7 +60,7 @@ func init() {
if value := existsEnv.GetStringOr(GoctlCache, ""); value != "" {
goctlEnv.SetKV(GoctlCache, value)
}
- experimental := existsEnv.GetOr(GoctlExperimental, ExperimentalOff)
+ experimental := existsEnv.GetOr(GoctlExperimental, ExperimentalOn)
goctlEnv.SetKV(GoctlExperimental, experimental)
}
@@ -76,7 +77,7 @@ func init() {
}
if !goctlEnv.HasKey(GoctlExperimental) {
- goctlEnv.SetKV(GoctlExperimental, ExperimentalOff)
+ goctlEnv.SetKV(GoctlExperimental, ExperimentalOn)
}
goctlEnv.SetKV(GoctlVersion, version.BuildVersion)
@@ -111,6 +112,14 @@ func Get(key string) string {
return GetOr(key, "")
}
+// Set sets the environment variable for testing
+func Set(t *testing.T, key, value string) {
+ goctlEnv.SetKV(key, value)
+ t.Cleanup(func() {
+ goctlEnv.Remove(key)
+ })
+}
+
func GetOr(key, def string) string {
return goctlEnv.GetStringOr(key, def)
}
diff --git a/tools/goctl/pkg/parser/api/importstack/importstack.go b/tools/goctl/pkg/parser/api/importstack/importstack.go
new file mode 100644
index 000000000000..385466498565
--- /dev/null
+++ b/tools/goctl/pkg/parser/api/importstack/importstack.go
@@ -0,0 +1,31 @@
+package importstack
+
+import "errors"
+
+// ErrImportCycleNotAllowed defines an error for circular importing
+var ErrImportCycleNotAllowed = errors.New("import cycle not allowed")
+
+// ImportStack a stack of import paths
+type ImportStack []string
+
+func New() *ImportStack {
+ return &ImportStack{}
+}
+
+func (s *ImportStack) Push(p string) error {
+ for _, x := range *s {
+ if x == p {
+ return ErrImportCycleNotAllowed
+ }
+ }
+ *s = append(*s, p)
+ return nil
+}
+
+func (s *ImportStack) Pop() {
+ *s = (*s)[0 : len(*s)-1]
+}
+
+func (s *ImportStack) List() []string {
+ return *s
+}
diff --git a/tools/goctl/pkg/parser/api/parser/analyzer.go b/tools/goctl/pkg/parser/api/parser/analyzer.go
index eebc60731418..236630e42004 100644
--- a/tools/goctl/pkg/parser/api/parser/analyzer.go
+++ b/tools/goctl/pkg/parser/api/parser/analyzer.go
@@ -2,10 +2,13 @@ package parser
import (
"fmt"
+ "sort"
"strings"
+ "github.com/zeromicro/go-zero/core/lang"
"github.com/zeromicro/go-zero/tools/goctl/api/spec"
"github.com/zeromicro/go-zero/tools/goctl/pkg/parser/api/ast"
+ "github.com/zeromicro/go-zero/tools/goctl/pkg/parser/api/importstack"
"github.com/zeromicro/go-zero/tools/goctl/pkg/parser/api/placeholder"
"github.com/zeromicro/go-zero/tools/goctl/pkg/parser/api/token"
)
@@ -18,13 +21,14 @@ type Analyzer struct {
func (a *Analyzer) astTypeToSpec(in ast.DataType) (spec.Type, error) {
isLiteralType := func(dt ast.DataType) bool {
- _, ok := dt.(*ast.BaseDataType)
- if ok {
+ if _, ok := dt.(*ast.BaseDataType); ok {
return true
}
- _, ok = dt.(*ast.AnyDataType)
+
+ _, ok := dt.(*ast.AnyDataType)
return ok
}
+
switch v := (in).(type) {
case *ast.BaseDataType:
raw := v.RawText()
@@ -33,6 +37,7 @@ func (a *Analyzer) astTypeToSpec(in ast.DataType) (spec.Type, error) {
RawName: raw,
}, nil
}
+
return spec.DefineStruct{RawName: raw}, nil
case *ast.AnyDataType:
return nil, ast.SyntaxError(v.Pos(), "unsupported any type")
@@ -47,10 +52,12 @@ func (a *Analyzer) astTypeToSpec(in ast.DataType) (spec.Type, error) {
if !v.Key.CanEqual() {
return nil, ast.SyntaxError(v.Pos(), "map key <%T> must be equal data type", v)
}
+
value, err := a.astTypeToSpec(v.Value)
if err != nil {
return nil, err
}
+
return spec.MapType{
RawName: v.RawText(),
Key: v.RawText(),
@@ -66,6 +73,7 @@ func (a *Analyzer) astTypeToSpec(in ast.DataType) (spec.Type, error) {
if err != nil {
return nil, err
}
+
return spec.PointerType{
RawName: v.RawText(),
Type: value,
@@ -74,10 +82,12 @@ func (a *Analyzer) astTypeToSpec(in ast.DataType) (spec.Type, error) {
if v.Length.Token.Type == token.ELLIPSIS {
return nil, ast.SyntaxError(v.Pos(), "Array: unsupported dynamic length")
}
+
value, err := a.astTypeToSpec(v.DataType)
if err != nil {
return nil, err
}
+
return spec.ArrayType{
RawName: v.RawText(),
Value: value,
@@ -87,6 +97,7 @@ func (a *Analyzer) astTypeToSpec(in ast.DataType) (spec.Type, error) {
if err != nil {
return nil, err
}
+
return spec.ArrayType{
RawName: v.RawText(),
Value: value,
@@ -101,7 +112,27 @@ func (a *Analyzer) convert2Spec() error {
return err
}
- return a.fillService()
+ if err := a.fillService(); err != nil {
+ return err
+ }
+
+ sort.SliceStable(a.spec.Types, func(i, j int) bool {
+ return a.spec.Types[i].Name() < a.spec.Types[j].Name()
+ })
+
+ groups := make([]spec.Group, 0, len(a.spec.Service.Groups))
+ for _, v := range a.spec.Service.Groups {
+ sort.SliceStable(v.Routes, func(i, j int) bool {
+ return v.Routes[i].Path < v.Routes[j].Path
+ })
+ groups = append(groups, v)
+ }
+ sort.SliceStable(groups, func(i, j int) bool {
+ return groups[i].Annotation.Properties["group"] < groups[j].Annotation.Properties["group"]
+ })
+ a.spec.Service.Groups = groups
+
+ return nil
}
func (a *Analyzer) convertAtDoc(atDoc ast.AtDocStmt) spec.AtDoc {
@@ -146,6 +177,7 @@ func (a *Analyzer) fieldToMember(field *ast.ElemExpr) (spec.Member, error) {
if field.Tag != nil {
m.Tag = field.Tag.Token.Text
}
+
return m, nil
}
@@ -242,8 +274,7 @@ func (a *Analyzer) fillTypes() error {
for _, item := range a.api.TypeStmt {
switch v := (item).(type) {
case *ast.TypeLiteralStmt:
- err := a.fillTypeExpr(v.Expr)
- if err != nil {
+ if err := a.fillTypeExpr(v.Expr); err != nil {
return err
}
case *ast.TypeGroupStmt:
@@ -361,9 +392,14 @@ func Parse(filename string, src interface{}) (*spec.ApiSpec, error) {
return nil, err
}
- var importManager = make(map[string]placeholder.Type)
- importManager[ast.Filename] = placeholder.PlaceHolder
- api, err := convert2API(ast, importManager)
+ is := importstack.New()
+ err := is.Push(ast.Filename)
+ if err != nil {
+ return nil, err
+ }
+
+ importSet := map[string]lang.PlaceholderType{}
+ api, err := convert2API(ast, importSet, is)
if err != nil {
return nil, err
}
diff --git a/tools/goctl/pkg/parser/api/parser/api.go b/tools/goctl/pkg/parser/api/parser/api.go
index a1b961b65a80..10b5a1a454d8 100644
--- a/tools/goctl/pkg/parser/api/parser/api.go
+++ b/tools/goctl/pkg/parser/api/parser/api.go
@@ -5,7 +5,9 @@ import (
"path/filepath"
"strings"
+ "github.com/zeromicro/go-zero/core/lang"
"github.com/zeromicro/go-zero/tools/goctl/pkg/parser/api/ast"
+ "github.com/zeromicro/go-zero/tools/goctl/pkg/parser/api/importstack"
"github.com/zeromicro/go-zero/tools/goctl/pkg/parser/api/placeholder"
"github.com/zeromicro/go-zero/tools/goctl/pkg/parser/api/token"
)
@@ -18,31 +20,55 @@ type API struct {
importStmt []ast.ImportStmt // ImportStmt block does not participate in code generation.
TypeStmt []ast.TypeStmt
ServiceStmts []*ast.ServiceStmt
- importManager map[string]placeholder.Type
+ importManager *importstack.ImportStack
+ importSet map[string]lang.PlaceholderType
}
-func convert2API(a *ast.AST, importManager map[string]placeholder.Type) (*API, error) {
+func convert2API(a *ast.AST, importSet map[string]lang.PlaceholderType, is *importstack.ImportStack) (*API, error) {
var api = new(API)
- api.importManager = make(map[string]placeholder.Type)
+ api.importManager = is
+ api.importSet = make(map[string]lang.PlaceholderType)
api.Filename = a.Filename
- for k, v := range importManager {
- api.importManager[k] = v
+ for k, v := range importSet {
+ api.importSet[k] = v
}
one := a.Stmts[0]
syntax, ok := one.(*ast.SyntaxStmt)
if !ok {
- return nil, ast.SyntaxError(one.Pos(), "expected syntax statement, got <%T>", one)
+ syntax = &ast.SyntaxStmt{
+ Syntax: ast.NewTokenNode(token.Token{
+ Type: token.IDENT,
+ Text: token.Syntax,
+ }),
+ Assign: ast.NewTokenNode(token.Token{
+ Type: token.ASSIGN,
+ Text: "=",
+ }),
+ Value: ast.NewTokenNode(token.Token{
+ Type: token.STRING,
+ Text: `"v1"`,
+ }),
+ }
}
- api.Syntax = syntax
- for i := 1; i < len(a.Stmts); i++ {
+ api.Syntax = syntax
+ var hasSyntax, hasInfo bool
+ for i := 0; i < len(a.Stmts); i++ {
one := a.Stmts[i]
switch val := one.(type) {
case *ast.SyntaxStmt:
- return nil, ast.DuplicateStmtError(val.Pos(), "duplicate syntax statement")
+ if hasSyntax {
+ return nil, ast.DuplicateStmtError(val.Pos(), "duplicate syntax statement")
+ } else {
+ hasSyntax = true
+ }
case *ast.InfoStmt:
if api.info != nil {
- return nil, ast.DuplicateStmtError(val.Pos(), "duplicate info statement")
+ if hasInfo {
+ return nil, ast.DuplicateStmtError(val.Pos(), "duplicate info statement")
+ }
+ } else {
+ hasInfo = true
}
api.info = val
case ast.ImportStmt:
@@ -208,9 +234,6 @@ func (api *API) getAtServerValue(atServer *ast.AtServerStmt, key string) string
}
func (api *API) mergeAPI(in *API) error {
- for k, v := range in.importManager {
- api.importManager[k] = v
- }
if api.Syntax.Value.Format() != in.Syntax.Value.Format() {
return ast.SyntaxError(in.Syntax.Value.Pos(),
"multiple syntax value expression, expected <%s>, got <%s>",
@@ -247,11 +270,15 @@ func (api *API) parseImportedAPI(imports []ast.ImportStmt) ([]*API, error) {
impPath = filepath.Join(dir, impPath)
}
// import cycle check
- if _, ok := api.importManager[impPath]; ok {
- return nil, ast.SyntaxError(tok.Position, "import circle not allowed")
- } else {
- api.importManager[impPath] = placeholder.PlaceHolder
+ if err := api.importManager.Push(impPath); err != nil {
+ return nil, ast.SyntaxError(tok.Position, err.Error())
+ }
+
+ if _, ok := api.importSet[impPath]; ok {
+ api.importManager.Pop()
+ continue
}
+ api.importSet[impPath] = lang.Placeholder
p := New(impPath, "")
ast := p.Parse()
@@ -259,7 +286,7 @@ func (api *API) parseImportedAPI(imports []ast.ImportStmt) ([]*API, error) {
return nil, err
}
- nestedApi, err := convert2API(ast, api.importManager)
+ nestedApi, err := convert2API(ast, api.importSet, api.importManager)
if err != nil {
return nil, err
}
@@ -268,6 +295,7 @@ func (api *API) parseImportedAPI(imports []ast.ImportStmt) ([]*API, error) {
return nil, err
}
+ api.importManager.Pop()
list = append(list, nestedApi)
if err != nil {
diff --git a/tools/goctl/pkg/parser/api/parser/testdata/invalid.api b/tools/goctl/pkg/parser/api/parser/testdata/invalid.api
index 3f0106d457f8..cf58be84454d 100644
--- a/tools/goctl/pkg/parser/api/parser/testdata/invalid.api
+++ b/tools/goctl/pkg/parser/api/parser/testdata/invalid.api
@@ -1,7 +1,3 @@
-// test case: expected syntax statement
-info ()
-
------
// test case: duplicate syntax statement
syntax = "v1"
syntax = "v1"
diff --git a/tools/goctl/pkg/parser/api/scanner/scanner.go b/tools/goctl/pkg/parser/api/scanner/scanner.go
index 35a9332dd9d6..87767c17c3a2 100644
--- a/tools/goctl/pkg/parser/api/scanner/scanner.go
+++ b/tools/goctl/pkg/parser/api/scanner/scanner.go
@@ -26,7 +26,6 @@ const (
stringOpen
stringClose
// string mode end
-
)
var missingInput = errors.New("missing input")
@@ -268,6 +267,7 @@ func (s *Scanner) scanNanosecond(bgPos int) token.Token {
return s.illegalToken()
}
s.readRune()
+
return token.Token{
Type: token.DURATION,
Text: string(s.data[bgPos:s.position]),
@@ -485,6 +485,7 @@ func (s *Scanner) scanLineComment() token.Token {
for s.ch != '\n' && s.ch != 0 {
s.readRune()
}
+
return token.Token{
Type: token.COMMENT,
Text: string(s.data[position:s.position]),
@@ -546,6 +547,7 @@ func (s *Scanner) assertExpected(actual token.Type, expected ...token.Type) erro
strings.Join(expects, " | "),
actual.String(),
))
+
return errors.New(text)
}
@@ -560,6 +562,7 @@ func (s *Scanner) assertExpectedString(actual string, expected ...string) error
strings.Join(expects, " | "),
actual,
))
+
return errors.New(text)
}
@@ -647,21 +650,22 @@ func NewScanner(filename string, src interface{}) (*Scanner, error) {
}
func readData(filename string, src interface{}) ([]byte, error) {
- data, err := os.ReadFile(filename)
- if err == nil {
+ if strings.HasSuffix(filename, ".api") {
+ data, err := os.ReadFile(filename)
+ if err != nil {
+ return nil, err
+ }
return data, nil
}
switch v := src.(type) {
case []byte:
- data = append(data, v...)
+ return v, nil
case *bytes.Buffer:
- data = v.Bytes()
+ return v.Bytes(), nil
case string:
- data = []byte(v)
+ return []byte(v), nil
default:
return nil, fmt.Errorf("unsupported type: %T", src)
}
-
- return data, nil
}
diff --git a/tools/goctl/rpc/generator/genpb.go b/tools/goctl/rpc/generator/genpb.go
index 797a1fc8bdea..758bc2f631ff 100644
--- a/tools/goctl/rpc/generator/genpb.go
+++ b/tools/goctl/rpc/generator/genpb.go
@@ -31,14 +31,14 @@ func (g *Generator) genPbDirect(ctx DirContext, c *ZRpcContext) error {
}
func (g *Generator) setPbDir(ctx DirContext, c *ZRpcContext) error {
- pbDir, err := findPbFile(c.GoOutput, false)
+ pbDir, err := findPbFile(c.GoOutput, c.Src, false)
if err != nil {
return err
}
if len(pbDir) == 0 {
return fmt.Errorf("pg.go is not found under %q", c.GoOutput)
}
- grpcDir, err := findPbFile(c.GrpcOutput, true)
+ grpcDir, err := findPbFile(c.GrpcOutput, c.Src, true)
if err != nil {
return err
}
@@ -62,7 +62,11 @@ const (
grpcSuffix = "_grpc.pb.go"
)
-func findPbFile(current string, grpc bool) (string, error) {
+func findPbFile(current string, src string, grpc bool) (string, error) {
+ protoName := strings.TrimSuffix(filepath.Base(src), filepath.Ext(src))
+ pbFile := protoName + "." + pbSuffix
+ grpcFile := protoName + grpcSuffix
+
fileSystem := os.DirFS(current)
var ret string
err := fs.WalkDir(fileSystem, ".", func(path string, d fs.DirEntry, err error) error {
@@ -71,11 +75,11 @@ func findPbFile(current string, grpc bool) (string, error) {
}
if strings.HasSuffix(path, pbSuffix) {
if grpc {
- if strings.HasSuffix(path, grpcSuffix) {
+ if strings.HasSuffix(path, grpcFile) {
ret = path
return os.ErrExist
}
- } else if !strings.HasSuffix(path, grpcSuffix) {
+ } else if strings.HasSuffix(path, pbFile) {
ret = path
return os.ErrExist
}
diff --git a/tools/goctl/rpc/generator/genpb_test.go b/tools/goctl/rpc/generator/genpb_test.go
index 9ed939a4755b..dbc6d5d9ae5b 100644
--- a/tools/goctl/rpc/generator/genpb_test.go
+++ b/tools/goctl/rpc/generator/genpb_test.go
@@ -46,12 +46,12 @@ service Greeter {
t.Log(err)
return
}
- pbDir, err := findPbFile(output, false)
+ pbDir, err := findPbFile(output, protoFile, false)
assert.Nil(t, err)
pbGo := filepath.Join(pbDir, "greet.pb.go")
assert.True(t, pathx.FileExists(pbGo))
- grpcDir, err := findPbFile(output, true)
+ grpcDir, err := findPbFile(output, protoFile, true)
assert.Nil(t, err)
grpcGo := filepath.Join(grpcDir, "greet_grpc.pb.go")
assert.True(t, pathx.FileExists(grpcGo))
@@ -76,12 +76,12 @@ service Greeter {
t.Log(err)
return
}
- pbDir, err := findPbFile(output, false)
+ pbDir, err := findPbFile(output, protoFile, false)
assert.Nil(t, err)
pbGo := filepath.Join(pbDir, "greet.pb.go")
assert.True(t, pathx.FileExists(pbGo))
- grpcDir, err := findPbFile(output, true)
+ grpcDir, err := findPbFile(output, protoFile, true)
assert.Nil(t, err)
grpcGo := filepath.Join(grpcDir, "greet_grpc.pb.go")
assert.True(t, pathx.FileExists(grpcGo))
@@ -108,12 +108,12 @@ service Greeter {
t.Log(err)
return
}
- pbDir, err := findPbFile(output, false)
+ pbDir, err := findPbFile(output, protoFile, false)
assert.Nil(t, err)
pbGo := filepath.Join(pbDir, "greet.pb.go")
assert.True(t, pathx.FileExists(pbGo))
- grpcDir, err := findPbFile(output, true)
+ grpcDir, err := findPbFile(output, protoFile, true)
assert.Nil(t, err)
grpcGo := filepath.Join(grpcDir, "greet_grpc.pb.go")
assert.True(t, pathx.FileExists(grpcGo))
@@ -140,12 +140,12 @@ service Greeter {
t.Log(err)
return
}
- pbDir, err := findPbFile(output, false)
+ pbDir, err := findPbFile(output, protoFile, false)
assert.Nil(t, err)
pbGo := filepath.Join(pbDir, "greet.pb.go")
assert.True(t, pathx.FileExists(pbGo))
- grpcDir, err := findPbFile(output, true)
+ grpcDir, err := findPbFile(output, protoFile, true)
assert.Nil(t, err)
grpcGo := filepath.Join(grpcDir, "greet_grpc.pb.go")
assert.True(t, pathx.FileExists(grpcGo))
@@ -183,12 +183,12 @@ service Greeter {
t.Log(err)
return
}
- pbDir, err := findPbFile(output, false)
+ pbDir, err := findPbFile(output, protoFile, false)
assert.Nil(t, err)
pbGo := filepath.Join(pbDir, "greet.pb.go")
assert.True(t, pathx.FileExists(pbGo))
- grpcDir, err := findPbFile(output, true)
+ grpcDir, err := findPbFile(output, protoFile, true)
assert.Nil(t, err)
grpcGo := filepath.Join(grpcDir, "greet_grpc.pb.go")
assert.True(t, pathx.FileExists(grpcGo))
diff --git a/tools/goctl/test/integration/model/mongo/Dockerfile b/tools/goctl/test/integration/model/mongo/Dockerfile
index 4116de77ad3f..91bce4fcd87c 100644
--- a/tools/goctl/test/integration/model/mongo/Dockerfile
+++ b/tools/goctl/test/integration/model/mongo/Dockerfile
@@ -1,4 +1,4 @@
-FROM golang:1.18
+FROM golang:1.19
ENV TZ Asia/Shanghai
ENV GOPROXY https://goproxy.cn,direct
diff --git a/tools/goctl/util/ctx/gomod_test.go b/tools/goctl/util/ctx/gomod_test.go
index b8bc46127f16..393674221bc2 100644
--- a/tools/goctl/util/ctx/gomod_test.go
+++ b/tools/goctl/util/ctx/gomod_test.go
@@ -81,13 +81,13 @@ func Test_getRealModule(t *testing.T) {
"Path":"foo",
"Dir":"/home/foo",
"GoMod":"/home/foo/go.mod",
- "GoVersion":"go1.18"
+ "GoVersion":"go1.19"
}
{
"Path":"bar",
"Dir":"/home/bar",
"GoMod":"/home/bar/go.mod",
- "GoVersion":"go1.18"
+ "GoVersion":"go1.19"
}`, nil
},
},
@@ -95,7 +95,7 @@ func Test_getRealModule(t *testing.T) {
Path: "bar",
Dir: "/home/bar",
GoMod: "/home/bar/go.mod",
- GoVersion: "go1.18",
+ GoVersion: "go1.19",
},
},
}
@@ -143,26 +143,26 @@ func TestDecodePackages(t *testing.T) {
"Path":"foo",
"Dir":"/home/foo",
"GoMod":"/home/foo/go.mod",
- "GoVersion":"go1.18"
+ "GoVersion":"go1.19"
}
{
"Path":"bar",
"Dir":"/home/bar",
"GoMod":"/home/bar/go.mod",
- "GoVersion":"go1.18"
+ "GoVersion":"go1.19"
}`),
want: []Module{
{
Path: "foo",
Dir: "/home/foo",
GoMod: "/home/foo/go.mod",
- GoVersion: "go1.18",
+ GoVersion: "go1.19",
},
{
Path: "bar",
Dir: "/home/bar",
GoMod: "/home/bar/go.mod",
- GoVersion: "go1.18",
+ GoVersion: "go1.19",
},
},
},
@@ -173,14 +173,14 @@ func TestDecodePackages(t *testing.T) {
"Path":"foo",
"Dir":"/home/foo",
"GoMod":"/home/foo/go.mod",
- "GoVersion":"go1.18"
+ "GoVersion":"go1.19"
}`),
want: []Module{
{
Path: "foo",
Dir: "/home/foo",
GoMod: "/home/foo/go.mod",
- GoVersion: "go1.18",
+ GoVersion: "go1.19",
},
},
},
diff --git a/zrpc/client.go b/zrpc/client.go
index ab0f924a1a54..e44abc165f80 100644
--- a/zrpc/client.go
+++ b/zrpc/client.go
@@ -110,3 +110,8 @@ func DontLogClientContentForMethod(method string) {
func SetClientSlowThreshold(threshold time.Duration) {
clientinterceptors.SetSlowThreshold(threshold)
}
+
+// WithCallTimeout return a call option with given timeout to make a method call.
+func WithCallTimeout(timeout time.Duration) grpc.CallOption {
+ return clientinterceptors.WithCallTimeout(timeout)
+}
diff --git a/zrpc/client_test.go b/zrpc/client_test.go
index eb232a82826c..09a06cbb1947 100644
--- a/zrpc/client_test.go
+++ b/zrpc/client_test.go
@@ -43,30 +43,35 @@ func TestDepositServer_Deposit(t *testing.T) {
tests := []struct {
name string
amount float32
+ timeout time.Duration
res *mock.DepositResponse
errCode codes.Code
errMsg string
}{
{
- "invalid request with negative amount",
- -1.11,
- nil,
- codes.InvalidArgument,
- fmt.Sprintf("cannot deposit %v", -1.11),
+ name: "invalid request with negative amount",
+ amount: -1.11,
+ errCode: codes.InvalidArgument,
+ errMsg: fmt.Sprintf("cannot deposit %v", -1.11),
},
{
- "valid request with non negative amount",
- 0.00,
- &mock.DepositResponse{Ok: true},
- codes.OK,
- "",
+ name: "valid request with non negative amount",
+ res: &mock.DepositResponse{Ok: true},
+ errCode: codes.OK,
},
{
- "valid request with long handling time",
- 2000.00,
- nil,
- codes.DeadlineExceeded,
- "context deadline exceeded",
+ name: "valid request with long handling time",
+ amount: 2000.00,
+ errCode: codes.DeadlineExceeded,
+ errMsg: "context deadline exceeded",
+ },
+ {
+ name: "valid request with timeout call option",
+ amount: 2000.00,
+ timeout: time.Second * 3,
+ res: &mock.DepositResponse{Ok: true},
+ errCode: codes.OK,
+ errMsg: "",
},
}
@@ -156,9 +161,22 @@ func TestDepositServer_Deposit(t *testing.T) {
client := client
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
+
cli := mock.NewDepositServiceClient(client.Conn())
request := &mock.DepositRequest{Amount: tt.amount}
- response, err := cli.Deposit(context.Background(), request)
+
+ var (
+ ctx = context.Background()
+ response *mock.DepositResponse
+ err error
+ )
+
+ if tt.timeout > 0 {
+ response, err = cli.Deposit(ctx, request, WithCallTimeout(tt.timeout))
+ } else {
+ response, err = cli.Deposit(ctx, request)
+ }
+
if response != nil {
assert.True(t, len(response.String()) > 0)
if response.GetOk() != tt.res.GetOk() {
diff --git a/zrpc/config.go b/zrpc/config.go
index afbb48824ae1..84a32160dc67 100644
--- a/zrpc/config.go
+++ b/zrpc/config.go
@@ -17,6 +17,8 @@ type (
ServerMiddlewaresConf = internal.ServerMiddlewaresConf
// StatConf defines the stat config.
StatConf = internal.StatConf
+ // MethodTimeoutConf defines specified timeout for gRPC method.
+ MethodTimeoutConf = internal.MethodTimeoutConf
// A RpcClientConf is a rpc client config.
RpcClientConf struct {
@@ -45,6 +47,8 @@ type (
// grpc health check switch
Health bool `json:",default=true"`
Middlewares ServerMiddlewaresConf
+ // setting specified timeout for gRPC method
+ MethodTimeouts []MethodTimeoutConf `json:",optional"`
}
)
diff --git a/zrpc/internal/balancer/p2c/p2c_test.go b/zrpc/internal/balancer/p2c/p2c_test.go
index b92420b0fab5..8d42362269ce 100644
--- a/zrpc/internal/balancer/p2c/p2c_test.go
+++ b/zrpc/internal/balancer/p2c/p2c_test.go
@@ -147,3 +147,6 @@ func (m mockClientConn) UpdateAddresses(addresses []resolver.Address) {
func (m mockClientConn) Connect() {
}
+
+func (m mockClientConn) Shutdown() {
+}
diff --git a/zrpc/internal/clientinterceptors/prometheusinterceptor.go b/zrpc/internal/clientinterceptors/prometheusinterceptor.go
index 23ab3a75c0ff..fe677dba2410 100644
--- a/zrpc/internal/clientinterceptors/prometheusinterceptor.go
+++ b/zrpc/internal/clientinterceptors/prometheusinterceptor.go
@@ -19,7 +19,7 @@ var (
Name: "duration_ms",
Help: "rpc client requests duration(ms).",
Labels: []string{"method"},
- Buckets: []float64{5, 10, 25, 50, 100, 250, 500, 1000},
+ Buckets: []float64{1, 2, 5, 10, 25, 50, 100, 250, 500, 1000, 2000, 5000},
})
metricClientReqCodeTotal = metric.NewCounterVec(&metric.CounterVecOpts{
diff --git a/zrpc/internal/clientinterceptors/timeoutinterceptor.go b/zrpc/internal/clientinterceptors/timeoutinterceptor.go
index 20111fc1d3a8..770030fec5ba 100644
--- a/zrpc/internal/clientinterceptors/timeoutinterceptor.go
+++ b/zrpc/internal/clientinterceptors/timeoutinterceptor.go
@@ -7,17 +7,41 @@ import (
"google.golang.org/grpc"
)
+// TimeoutCallOption is a call option that controls timeout.
+type TimeoutCallOption struct {
+ grpc.EmptyCallOption
+ timeout time.Duration
+}
+
// TimeoutInterceptor is an interceptor that controls timeout.
func TimeoutInterceptor(timeout time.Duration) grpc.UnaryClientInterceptor {
return func(ctx context.Context, method string, req, reply any, cc *grpc.ClientConn,
invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
- if timeout <= 0 {
+ t := getTimeoutFromCallOptions(opts, timeout)
+ if t <= 0 {
return invoker(ctx, method, req, reply, cc, opts...)
}
- ctx, cancel := context.WithTimeout(ctx, timeout)
+ ctx, cancel := context.WithTimeout(ctx, t)
defer cancel()
return invoker(ctx, method, req, reply, cc, opts...)
}
}
+
+// WithCallTimeout returns a call option that controls method call timeout.
+func WithCallTimeout(timeout time.Duration) grpc.CallOption {
+ return TimeoutCallOption{
+ timeout: timeout,
+ }
+}
+
+func getTimeoutFromCallOptions(opts []grpc.CallOption, defaultTimeout time.Duration) time.Duration {
+ for _, opt := range opts {
+ if o, ok := opt.(TimeoutCallOption); ok {
+ return o.timeout
+ }
+ }
+
+ return defaultTimeout
+}
diff --git a/zrpc/internal/clientinterceptors/timeoutinterceptor_test.go b/zrpc/internal/clientinterceptors/timeoutinterceptor_test.go
index 67b5ab05e685..d93476656c13 100644
--- a/zrpc/internal/clientinterceptors/timeoutinterceptor_test.go
+++ b/zrpc/internal/clientinterceptors/timeoutinterceptor_test.go
@@ -66,3 +66,74 @@ func TestTimeoutInterceptor_panic(t *testing.T) {
})
}
}
+
+func TestTimeoutInterceptor_TimeoutCallOption(t *testing.T) {
+ type args struct {
+ interceptorTimeout time.Duration
+ callOptionTimeout time.Duration
+ runTime time.Duration
+ }
+ var tests = []struct {
+ name string
+ args args
+ wantErr error
+ }{
+ {
+ name: "do not timeout without call option timeout",
+ args: args{
+ interceptorTimeout: time.Second,
+ runTime: time.Millisecond * 50,
+ },
+ wantErr: nil,
+ },
+ {
+ name: "timeout without call option timeout",
+ args: args{
+ interceptorTimeout: time.Second,
+ runTime: time.Second * 2,
+ },
+ wantErr: context.DeadlineExceeded,
+ },
+ {
+ name: "do not timeout with call option timeout",
+ args: args{
+ interceptorTimeout: time.Second,
+ callOptionTimeout: time.Second * 3,
+ runTime: time.Second * 2,
+ },
+ wantErr: nil,
+ },
+ }
+ for _, tt := range tests {
+ tt := tt
+ t.Run(tt.name, func(t *testing.T) {
+ t.Parallel()
+
+ interceptor := TimeoutInterceptor(tt.args.interceptorTimeout)
+
+ cc := new(grpc.ClientConn)
+ var co []grpc.CallOption
+ if tt.args.callOptionTimeout > 0 {
+ co = append(co, WithCallTimeout(tt.args.callOptionTimeout))
+ }
+
+ err := interceptor(context.Background(), "/foo", nil, nil, cc,
+ func(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn,
+ opts ...grpc.CallOption) error {
+ timer := time.NewTimer(tt.args.runTime)
+ defer timer.Stop()
+
+ select {
+ case <-timer.C:
+ return nil
+ case <-ctx.Done():
+ return ctx.Err()
+ }
+ }, co...,
+ )
+ t.Logf("error: %+v", err)
+
+ assert.EqualValues(t, tt.wantErr, err)
+ })
+ }
+}
diff --git a/zrpc/internal/codes/accept.go b/zrpc/internal/codes/accept.go
index 8ecf292ac968..f11e29c2bd58 100644
--- a/zrpc/internal/codes/accept.go
+++ b/zrpc/internal/codes/accept.go
@@ -8,7 +8,8 @@ import (
// Acceptable checks if given error is acceptable.
func Acceptable(err error) bool {
switch status.Code(err) {
- case codes.DeadlineExceeded, codes.Internal, codes.Unavailable, codes.DataLoss, codes.Unimplemented:
+ case codes.DeadlineExceeded, codes.Internal, codes.Unavailable, codes.DataLoss,
+ codes.Unimplemented, codes.ResourceExhausted:
return false
default:
return true
diff --git a/zrpc/internal/config.go b/zrpc/internal/config.go
index b60e1f099b7d..df141c467740 100644
--- a/zrpc/internal/config.go
+++ b/zrpc/internal/config.go
@@ -24,4 +24,7 @@ type (
Prometheus bool `json:",default=true"`
Breaker bool `json:",default=true"`
}
+
+ // MethodTimeoutConf defines specified timeout for gRPC methods.
+ MethodTimeoutConf = serverinterceptors.MethodTimeoutConf
)
diff --git a/zrpc/internal/rpcserver.go b/zrpc/internal/rpcserver.go
index f1b90e424af9..ed4aa2356b6a 100644
--- a/zrpc/internal/rpcserver.go
+++ b/zrpc/internal/rpcserver.go
@@ -76,7 +76,7 @@ func (s *rpcServer) Start(register RegisterFn) error {
// we need to make sure all others are wrapped up,
// so we do graceful stop at shutdown phase instead of wrap up phase
- waitForCalled := proc.AddWrapUpListener(func() {
+ waitForCalled := proc.AddShutdownListener(func() {
if s.health != nil {
s.health.Shutdown()
}
diff --git a/zrpc/internal/rpcserver_test.go b/zrpc/internal/rpcserver_test.go
index 99b48eb4f094..7af40110a662 100644
--- a/zrpc/internal/rpcserver_test.go
+++ b/zrpc/internal/rpcserver_test.go
@@ -47,7 +47,7 @@ func TestRpcServer(t *testing.T) {
grpcServer.GracefulStop()
lock.Unlock()
- proc.WrapUp()
+ proc.Shutdown()
wgDone.Wait()
}
diff --git a/zrpc/internal/serverinterceptors/breakerinterceptor.go b/zrpc/internal/serverinterceptors/breakerinterceptor.go
index 0298658fb753..79d8c68c5982 100644
--- a/zrpc/internal/serverinterceptors/breakerinterceptor.go
+++ b/zrpc/internal/serverinterceptors/breakerinterceptor.go
@@ -2,10 +2,13 @@ package serverinterceptors
import (
"context"
+ "errors"
"github.com/zeromicro/go-zero/core/breaker"
"github.com/zeromicro/go-zero/zrpc/internal/codes"
"google.golang.org/grpc"
+ gcodes "google.golang.org/grpc/codes"
+ "google.golang.org/grpc/status"
)
// StreamBreakerInterceptor is an interceptor that acts as a circuit breaker.
@@ -26,6 +29,9 @@ func UnaryBreakerInterceptor(ctx context.Context, req any, info *grpc.UnaryServe
resp, err = handler(ctx, req)
return err
}, codes.Acceptable)
+ if errors.Is(err, breaker.ErrServiceUnavailable) {
+ err = status.Error(gcodes.Unavailable, err.Error())
+ }
return resp, err
}
diff --git a/zrpc/internal/serverinterceptors/prometheusinterceptor.go b/zrpc/internal/serverinterceptors/prometheusinterceptor.go
index 9fcaaef9f67a..aa22a3891ad1 100644
--- a/zrpc/internal/serverinterceptors/prometheusinterceptor.go
+++ b/zrpc/internal/serverinterceptors/prometheusinterceptor.go
@@ -19,7 +19,7 @@ var (
Name: "duration_ms",
Help: "rpc server requests duration(ms).",
Labels: []string{"method"},
- Buckets: []float64{5, 10, 25, 50, 100, 250, 500, 1000},
+ Buckets: []float64{1, 2, 5, 10, 25, 50, 100, 250, 500, 1000, 2000, 5000},
})
metricServerReqCodeTotal = metric.NewCounterVec(&metric.CounterVecOpts{
diff --git a/zrpc/internal/serverinterceptors/sheddinginterceptor.go b/zrpc/internal/serverinterceptors/sheddinginterceptor.go
index 2b8ac1f13e41..4885795d21f5 100644
--- a/zrpc/internal/serverinterceptors/sheddinginterceptor.go
+++ b/zrpc/internal/serverinterceptors/sheddinginterceptor.go
@@ -2,11 +2,14 @@ package serverinterceptors
import (
"context"
+ "errors"
"sync"
"github.com/zeromicro/go-zero/core/load"
"github.com/zeromicro/go-zero/core/stat"
"google.golang.org/grpc"
+ "google.golang.org/grpc/codes"
+ "google.golang.org/grpc/status"
)
const serviceType = "rpc"
@@ -28,11 +31,12 @@ func UnarySheddingInterceptor(shedder load.Shedder, metrics *stat.Metrics) grpc.
if err != nil {
metrics.AddDrop()
sheddingStat.IncrementDrop()
+ err = status.Error(codes.ResourceExhausted, err.Error())
return
}
defer func() {
- if err == context.DeadlineExceeded {
+ if errors.Is(err, context.DeadlineExceeded) {
promise.Fail()
} else {
sheddingStat.IncrementPass()
diff --git a/zrpc/internal/serverinterceptors/sheddinginterceptor_test.go b/zrpc/internal/serverinterceptors/sheddinginterceptor_test.go
index 7b8afde6a485..bf8fc0a1fb70 100644
--- a/zrpc/internal/serverinterceptors/sheddinginterceptor_test.go
+++ b/zrpc/internal/serverinterceptors/sheddinginterceptor_test.go
@@ -8,6 +8,8 @@ import (
"github.com/zeromicro/go-zero/core/load"
"github.com/zeromicro/go-zero/core/stat"
"google.golang.org/grpc"
+ "google.golang.org/grpc/codes"
+ "google.golang.org/grpc/status"
)
func TestUnarySheddingInterceptor(t *testing.T) {
@@ -33,7 +35,7 @@ func TestUnarySheddingInterceptor(t *testing.T) {
name: "reject",
allow: false,
handleErr: nil,
- expect: load.ErrServiceOverloaded,
+ expect: status.Error(codes.ResourceExhausted, load.ErrServiceOverloaded.Error()),
},
}
diff --git a/zrpc/internal/serverinterceptors/timeoutinterceptor.go b/zrpc/internal/serverinterceptors/timeoutinterceptor.go
index 27cded03fd55..a6eebbebb313 100644
--- a/zrpc/internal/serverinterceptors/timeoutinterceptor.go
+++ b/zrpc/internal/serverinterceptors/timeoutinterceptor.go
@@ -2,6 +2,7 @@ package serverinterceptors
import (
"context"
+ "errors"
"fmt"
"runtime/debug"
"strings"
@@ -13,11 +14,24 @@ import (
"google.golang.org/grpc/status"
)
+type (
+ // MethodTimeoutConf defines specified timeout for gRPC method.
+ MethodTimeoutConf struct {
+ FullMethod string
+ Timeout time.Duration
+ }
+
+ methodTimeouts map[string]time.Duration
+)
+
// UnaryTimeoutInterceptor returns a func that sets timeout to incoming unary requests.
-func UnaryTimeoutInterceptor(timeout time.Duration) grpc.UnaryServerInterceptor {
+func UnaryTimeoutInterceptor(timeout time.Duration,
+ methodTimeouts ...MethodTimeoutConf) grpc.UnaryServerInterceptor {
+ timeouts := buildMethodTimeouts(methodTimeouts)
return func(ctx context.Context, req any, info *grpc.UnaryServerInfo,
handler grpc.UnaryHandler) (any, error) {
- ctx, cancel := context.WithTimeout(ctx, timeout)
+ t := getTimeoutByUnaryServerInfo(info.FullMethod, timeouts, timeout)
+ ctx, cancel := context.WithTimeout(ctx, t)
defer cancel()
var resp any
@@ -49,12 +63,32 @@ func UnaryTimeoutInterceptor(timeout time.Duration) grpc.UnaryServerInterceptor
return resp, err
case <-ctx.Done():
err := ctx.Err()
- if err == context.Canceled {
+ if errors.Is(err, context.Canceled) {
err = status.Error(codes.Canceled, err.Error())
- } else if err == context.DeadlineExceeded {
+ } else if errors.Is(err, context.DeadlineExceeded) {
err = status.Error(codes.DeadlineExceeded, err.Error())
}
return nil, err
}
}
}
+
+func buildMethodTimeouts(timeouts []MethodTimeoutConf) methodTimeouts {
+ mt := make(methodTimeouts, len(timeouts))
+ for _, st := range timeouts {
+ if st.FullMethod != "" {
+ mt[st.FullMethod] = st.Timeout
+ }
+ }
+
+ return mt
+}
+
+func getTimeoutByUnaryServerInfo(method string, timeouts methodTimeouts,
+ defaultTimeout time.Duration) time.Duration {
+ if v, ok := timeouts[method]; ok {
+ return v
+ }
+
+ return defaultTimeout
+}
diff --git a/zrpc/internal/serverinterceptors/timeoutinterceptor_test.go b/zrpc/internal/serverinterceptors/timeoutinterceptor_test.go
index 0e89eac6144d..1469e4c3a72a 100644
--- a/zrpc/internal/serverinterceptors/timeoutinterceptor_test.go
+++ b/zrpc/internal/serverinterceptors/timeoutinterceptor_test.go
@@ -12,6 +12,11 @@ import (
"google.golang.org/grpc/status"
)
+var (
+ deadlineExceededErr = status.Error(codes.DeadlineExceeded, context.DeadlineExceeded.Error())
+ canceledErr = status.Error(codes.Canceled, context.Canceled.Error())
+)
+
func TestUnaryTimeoutInterceptor(t *testing.T) {
interceptor := UnaryTimeoutInterceptor(time.Millisecond * 10)
_, err := interceptor(context.Background(), nil, &grpc.UnaryServerInfo{
@@ -68,7 +73,7 @@ func TestUnaryTimeoutInterceptor_timeoutExpire(t *testing.T) {
return nil, nil
})
wg.Wait()
- assert.EqualValues(t, status.Error(codes.DeadlineExceeded, context.DeadlineExceeded.Error()), err)
+ assert.EqualValues(t, deadlineExceededErr, err)
}
func TestUnaryTimeoutInterceptor_cancel(t *testing.T) {
@@ -88,5 +93,153 @@ func TestUnaryTimeoutInterceptor_cancel(t *testing.T) {
})
wg.Wait()
- assert.EqualValues(t, status.Error(codes.Canceled, context.Canceled.Error()), err)
+ assert.EqualValues(t, canceledErr, err)
+}
+
+type tempServer struct {
+ timeout time.Duration
+}
+
+func (s *tempServer) run(duration time.Duration) {
+ time.Sleep(duration)
+}
+
+func TestUnaryTimeoutInterceptor_TimeoutStrategy(t *testing.T) {
+ type args struct {
+ interceptorTimeout time.Duration
+ contextTimeout time.Duration
+ serverTimeout time.Duration
+ runTime time.Duration
+
+ fullMethod string
+ }
+ var tests = []struct {
+ name string
+ args args
+ wantErr error
+ }{
+ {
+ name: "do not timeout with interceptor timeout",
+ args: args{
+ interceptorTimeout: time.Second,
+ contextTimeout: time.Second * 5,
+ serverTimeout: time.Second * 3,
+ runTime: time.Millisecond * 50,
+ fullMethod: "/",
+ },
+ wantErr: nil,
+ },
+ {
+ name: "timeout with interceptor timeout",
+ args: args{
+ interceptorTimeout: time.Second,
+ contextTimeout: time.Second * 5,
+ serverTimeout: time.Second * 3,
+ runTime: time.Second * 2,
+ fullMethod: "/",
+ },
+ wantErr: deadlineExceededErr,
+ },
+ }
+ for _, tt := range tests {
+ tt := tt
+ t.Run(tt.name, func(t *testing.T) {
+ t.Parallel()
+
+ interceptor := UnaryTimeoutInterceptor(tt.args.interceptorTimeout)
+ ctx, cancel := context.WithTimeout(context.Background(), tt.args.contextTimeout)
+ defer cancel()
+
+ svr := &tempServer{timeout: tt.args.serverTimeout}
+
+ _, err := interceptor(ctx, nil, &grpc.UnaryServerInfo{
+ Server: svr,
+ FullMethod: tt.args.fullMethod,
+ }, func(ctx context.Context, req interface{}) (interface{}, error) {
+ svr.run(tt.args.runTime)
+ return nil, nil
+ })
+ t.Logf("error: %+v", err)
+
+ assert.EqualValues(t, tt.wantErr, err)
+ })
+ }
+}
+
+func TestUnaryTimeoutInterceptor_SpecifiedTimeout(t *testing.T) {
+ type args struct {
+ interceptorTimeout time.Duration
+ contextTimeout time.Duration
+ method string
+ methodTimeout time.Duration
+ runTime time.Duration
+ }
+ var tests = []struct {
+ name string
+ args args
+ wantErr error
+ }{
+ {
+ name: "do not timeout without set timeout for full method",
+ args: args{
+ interceptorTimeout: time.Second,
+ contextTimeout: time.Second * 5,
+ method: "/run",
+ runTime: time.Millisecond * 50,
+ },
+ wantErr: nil,
+ },
+ {
+ name: "do not timeout with set timeout for full method",
+ args: args{
+ interceptorTimeout: time.Second,
+ contextTimeout: time.Second * 5,
+ method: "/run/do_not_timeout",
+ methodTimeout: time.Second * 3,
+ runTime: time.Second * 2,
+ },
+ wantErr: nil,
+ },
+ {
+ name: "timeout with set timeout for full method",
+ args: args{
+ interceptorTimeout: time.Second,
+ contextTimeout: time.Second * 5,
+ method: "/run/timeout",
+ methodTimeout: time.Millisecond * 100,
+ runTime: time.Millisecond * 500,
+ },
+ wantErr: deadlineExceededErr,
+ },
+ }
+ for _, tt := range tests {
+ tt := tt
+ t.Run(tt.name, func(t *testing.T) {
+ t.Parallel()
+
+ var specifiedTimeouts []MethodTimeoutConf
+ if tt.args.methodTimeout > 0 {
+ specifiedTimeouts = []MethodTimeoutConf{
+ {
+ FullMethod: tt.args.method,
+ Timeout: tt.args.methodTimeout,
+ },
+ }
+ }
+
+ interceptor := UnaryTimeoutInterceptor(tt.args.interceptorTimeout, specifiedTimeouts...)
+ ctx, cancel := context.WithTimeout(context.Background(), tt.args.contextTimeout)
+ defer cancel()
+
+ _, err := interceptor(ctx, nil, &grpc.UnaryServerInfo{
+ FullMethod: tt.args.method,
+ }, func(ctx context.Context, req interface{}) (interface{}, error) {
+ time.Sleep(tt.args.runTime)
+ return nil, nil
+ })
+ t.Logf("error: %+v", err)
+
+ assert.EqualValues(t, tt.wantErr, err)
+ })
+ }
}
diff --git a/zrpc/resolver/internal/kube/deploy/clusterrole.yaml b/zrpc/resolver/internal/kube/deploy/clusterrole.yaml
deleted file mode 100644
index d95e7378bb36..000000000000
--- a/zrpc/resolver/internal/kube/deploy/clusterrole.yaml
+++ /dev/null
@@ -1,9 +0,0 @@
-apiVersion: rbac.authorization.k8s.io/v1
-kind: ClusterRole
-metadata:
- name: endpoints-reader
-rules:
- - apiGroups: [""]
- resources: ["endpoints"]
- verbs: ["get", "watch", "list"]
-
diff --git a/zrpc/resolver/internal/kube/deploy/clusterrolebinding.yaml b/zrpc/resolver/internal/kube/deploy/clusterrolebinding.yaml
deleted file mode 100644
index 6d0b4c6a8d80..000000000000
--- a/zrpc/resolver/internal/kube/deploy/clusterrolebinding.yaml
+++ /dev/null
@@ -1,12 +0,0 @@
-apiVersion: rbac.authorization.k8s.io/v1
-kind: ClusterRoleBinding
-metadata:
- name: endpoints-reader
-subjects:
- - kind: ServiceAccount
- name: endpoints-reader
- namespace: kevin # the namespace that the ServiceAccount resides in
-roleRef:
- kind: ClusterRole
- name: endpoints-reader
- apiGroup: rbac.authorization.k8s.io
diff --git a/zrpc/resolver/internal/kube/deploy/serviceaccount.yaml b/zrpc/resolver/internal/kube/deploy/serviceaccount.yaml
deleted file mode 100644
index 8364d5aa92fd..000000000000
--- a/zrpc/resolver/internal/kube/deploy/serviceaccount.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-apiVersion: v1
-kind: ServiceAccount
-metadata:
- name: endpoints-reader
- namespace: kevin # the namespace to create the ServiceAccount
diff --git a/zrpc/resolver/internal/kube/eventhandler.go b/zrpc/resolver/internal/kube/eventhandler.go
index 44a8ff7a2aa5..3e0c6b14fd51 100644
--- a/zrpc/resolver/internal/kube/eventhandler.go
+++ b/zrpc/resolver/internal/kube/eventhandler.go
@@ -6,8 +6,11 @@ import (
"github.com/zeromicro/go-zero/core/lang"
"github.com/zeromicro/go-zero/core/logx"
v1 "k8s.io/api/core/v1"
+ "k8s.io/client-go/tools/cache"
)
+var _ cache.ResourceEventHandler = (*EventHandler)(nil)
+
// EventHandler is ResourceEventHandler implementation.
type EventHandler struct {
update func([]string)
@@ -24,7 +27,7 @@ func NewEventHandler(update func([]string)) *EventHandler {
}
// OnAdd handles the endpoints add events.
-func (h *EventHandler) OnAdd(obj any) {
+func (h *EventHandler) OnAdd(obj any, _ bool) {
endpoints, ok := obj.(*v1.Endpoints)
if !ok {
logx.Errorf("%v is not an object with type *v1.Endpoints", obj)
diff --git a/zrpc/resolver/internal/kube/eventhandler_test.go b/zrpc/resolver/internal/kube/eventhandler_test.go
index 7325f0080d1a..fed504ab31e6 100644
--- a/zrpc/resolver/internal/kube/eventhandler_test.go
+++ b/zrpc/resolver/internal/kube/eventhandler_test.go
@@ -13,7 +13,7 @@ func TestAdd(t *testing.T) {
h := NewEventHandler(func(change []string) {
endpoints = change
})
- h.OnAdd("bad")
+ h.OnAdd("bad", false)
h.OnAdd(&v1.Endpoints{Subsets: []v1.EndpointSubset{
{
Addresses: []v1.EndpointAddress{
@@ -28,7 +28,7 @@ func TestAdd(t *testing.T) {
},
},
},
- }})
+ }}, false)
assert.ElementsMatch(t, []string{"0.0.0.1", "0.0.0.2", "0.0.0.3"}, endpoints)
}
@@ -51,7 +51,7 @@ func TestDelete(t *testing.T) {
},
},
},
- }})
+ }}, false)
h.OnDelete("bad")
h.OnDelete(&v1.Endpoints{Subsets: []v1.EndpointSubset{
{
@@ -167,7 +167,7 @@ func TestUpdateChangeWithDifferentVersion(t *testing.T) {
},
},
},
- }})
+ }}, false)
h.OnUpdate(&v1.Endpoints{
Subsets: []v1.EndpointSubset{
{
@@ -220,7 +220,7 @@ func TestUpdateNoChangeWithDifferentVersion(t *testing.T) {
},
},
},
- }})
+ }}, false)
h.OnUpdate("bad", &v1.Endpoints{Subsets: []v1.EndpointSubset{
{
Addresses: []v1.EndpointAddress{
diff --git a/zrpc/resolver/internal/kubebuilder.go b/zrpc/resolver/internal/kubebuilder.go
index 38c1f7752fbe..2392cc67a244 100644
--- a/zrpc/resolver/internal/kubebuilder.go
+++ b/zrpc/resolver/internal/kubebuilder.go
@@ -68,7 +68,11 @@ func (b *kubeBuilder) Build(target resolver.Target, cc resolver.ClientConn,
options.FieldSelector = nameSelector + svc.Name
}))
in := inf.Core().V1().Endpoints()
- in.Informer().AddEventHandler(handler)
+ _, err = in.Informer().AddEventHandler(handler)
+ if err != nil {
+ return nil, err
+ }
+
threading.GoSafe(func() {
inf.Start(proc.Done())
})
@@ -76,6 +80,7 @@ func (b *kubeBuilder) Build(target resolver.Target, cc resolver.ClientConn,
if err != nil {
return nil, err
}
+
handler.Update(endpoints)
return &nopResolver{cc: cc}, nil
diff --git a/zrpc/server.go b/zrpc/server.go
index 9cf5a87355b6..d891c8e69924 100644
--- a/zrpc/server.go
+++ b/zrpc/server.go
@@ -132,7 +132,7 @@ func setupInterceptors(svr internal.Server, c RpcServerConf, metrics *stat.Metri
if c.Timeout > 0 {
svr.AddUnaryInterceptors(serverinterceptors.UnaryTimeoutInterceptor(
- time.Duration(c.Timeout) * time.Millisecond))
+ time.Duration(c.Timeout)*time.Millisecond, c.MethodTimeouts...))
}
if c.Auth {
diff --git a/zrpc/server_test.go b/zrpc/server_test.go
index d35f6c3ae1c6..e99f224fa419 100644
--- a/zrpc/server_test.go
+++ b/zrpc/server_test.go
@@ -40,6 +40,12 @@ func TestServer_setupInterceptors(t *testing.T) {
Prometheus: true,
Breaker: true,
},
+ MethodTimeouts: []MethodTimeoutConf{
+ {
+ FullMethod: "/foo",
+ Timeout: 5 * time.Second,
+ },
+ },
}
err = setupInterceptors(server, conf, new(stat.Metrics))
assert.Nil(t, err)
@@ -75,6 +81,12 @@ func TestServer(t *testing.T) {
Prometheus: true,
Breaker: true,
},
+ MethodTimeouts: []MethodTimeoutConf{
+ {
+ FullMethod: "/foo",
+ Timeout: time.Second,
+ },
+ },
}, func(server *grpc.Server) {
})
svr.AddOptions(grpc.ConnectionTimeout(time.Hour))
@@ -105,6 +117,7 @@ func TestServerError(t *testing.T) {
Prometheus: true,
Breaker: true,
},
+ MethodTimeouts: []MethodTimeoutConf{},
}, func(server *grpc.Server) {
})
assert.NotNil(t, err)
@@ -131,6 +144,7 @@ func TestServer_HasEtcd(t *testing.T) {
Prometheus: true,
Breaker: true,
},
+ MethodTimeouts: []MethodTimeoutConf{},
}, func(server *grpc.Server) {
})
svr.AddOptions(grpc.ConnectionTimeout(time.Hour))