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 Architecture ## 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))