Compare commits

..

1 Commits

Author SHA1 Message Date
spectatorMrZ
304fb182bb Fix pg model generation without tag (#1407)
1. fix pg model struct haven't tag
2. add pg command test from datasource
2022-01-08 21:48:09 +08:00
794 changed files with 10223 additions and 32714 deletions

3
.github/FUNDING.yml vendored
View File

@@ -9,5 +9,4 @@ community_bridge: # Replace with a single Community Bridge project-name e.g., cl
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
custom: # https://gitee.com/kevwan/static/raw/master/images/sponsor.jpg
ethereum: 0x5052b7f6B937B02563996D23feb69b38D06Ca150 | kevwan
custom: https://gitee.com/kevwan/static/raw/master/images/sponsor.jpg

View File

@@ -1,11 +0,0 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
- package-ecosystem: "gomod" # See documentation for possible values
directory: "/" # Location of package manifests
schedule:
interval: "daily"

View File

@@ -35,11 +35,11 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v3
uses: actions/checkout@v2
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
uses: github/codeql-action/init@v1
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
@@ -50,7 +50,7 @@ jobs:
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v2
uses: github/codeql-action/autobuild@v1
# Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
@@ -64,4 +64,4 @@ jobs:
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
uses: github/codeql-action/analyze@v1

View File

@@ -7,50 +7,32 @@ on:
branches: [ master ]
jobs:
test-linux:
name: Linux
build:
name: Build
runs-on: ubuntu-latest
steps:
- name: Set up Go 1.x
uses: actions/setup-go@v3
with:
go-version: ^1.16
id: go
- name: Check out code into the Go module directory
uses: actions/checkout@v3
- name: Set up Go 1.x
uses: actions/setup-go@v2
with:
go-version: ^1.14
id: go
- name: Get dependencies
run: |
go get -v -t -d ./...
- name: Check out code into the Go module directory
uses: actions/checkout@v2
- name: Lint
run: |
go vet -stdmethods=false $(go list ./...)
go install mvdan.cc/gofumpt@latest
test -z "$(gofumpt -l -extra .)" || echo "Please run 'gofumpt -l -w -extra .'"
- name: Get dependencies
run: |
go get -v -t -d ./...
- name: Test
run: go test -race -coverprofile=coverage.txt -covermode=atomic ./...
- name: Lint
run: |
go vet -stdmethods=false $(go list ./...)
go install mvdan.cc/gofumpt@latest
test -z "$(gofumpt -s -l -extra .)" || echo "Please run 'gofumpt -l -w -extra .'"
- name: Codecov
uses: codecov/codecov-action@v3
- name: Test
run: go test -race -coverprofile=coverage.txt -covermode=atomic ./...
test-win:
name: Windows
runs-on: windows-latest
steps:
- name: Set up Go 1.x
uses: actions/setup-go@v3
with:
go-version: ^1.16
- name: Checkout codebase
uses: actions/checkout@v3
- name: Test
run: |
go mod verify
go mod download
go test -v -race ./...
cd tools/goctl && go build -v goctl.go
- name: Codecov
uses: codecov/codecov-action@v2

View File

@@ -1,18 +0,0 @@
name: 'issue-translator'
on:
issue_comment:
types: [created]
issues:
types: [opened]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: usthe/issues-translate-action@v2.7
with:
IS_MODIFY_TITLE: true
# not require, default false, . Decide whether to modify the issue title
# if true, the robot account @Issues-translate-bot must have modification permissions, invite @Issues-translate-bot to your project or use your custom bot.
CUSTOM_BOT_NOTE: Bot detected the issue body's language is not English, translate it automatically. 👯👭🏻🧑‍🤝‍🧑👫🧑🏿‍🤝‍🧑🏻👩🏾‍🤝‍👨🏿👬🏿
# not require. Customize the translation robot prefix message.

View File

@@ -7,10 +7,10 @@ jobs:
close-issues:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v6
- uses: actions/stale@v3
with:
days-before-issue-stale: 365
days-before-issue-close: 90
days-before-issue-stale: 30
days-before-issue-close: 14
stale-issue-label: "stale"
stale-issue-message: "This issue is stale because it has been open for 30 days with no activity."
close-issue-message: "This issue was closed because it has been inactive for 14 days since being marked as stale."

View File

@@ -1,28 +0,0 @@
on:
push:
tags:
- "tools/goctl/*"
jobs:
releases-matrix:
name: Release goctl binary
runs-on: ubuntu-latest
strategy:
matrix:
# build and publish in parallel: linux/386, linux/amd64, linux/arm64,
# windows/386, windows/amd64, windows/arm64, darwin/amd64, darwin/arm64
goos: [ linux, windows, darwin ]
goarch: [ "386", amd64, arm64 ]
exclude:
- goarch: "386"
goos: darwin
steps:
- uses: actions/checkout@v3
- 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.17.5.linux-amd64.tar.gz"
project_path: "tools/goctl"
binary_name: "goctl"
extra_files: tools/goctl/readme.md tools/goctl/readme-cn.md

View File

@@ -5,7 +5,7 @@ jobs:
name: runner / staticcheck
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v2
- uses: reviewdog/action-staticcheck@v1
with:
github_token: ${{ secrets.github_token }}

5
.gitignore vendored
View File

@@ -16,13 +16,10 @@
**/logs
# for test purpose
**/adhoc
go.work
go.work.sum
adhoc
# gitlab ci
.cache
.golangci.yml
# vim auto backup file
*~

View File

@@ -40,7 +40,7 @@ We will help you to contribute in different areas like filing issues, developing
getting your work reviewed and merged.
If you have questions about the development process,
feel free to [file an issue](https://github.com/zeromicro/go-zero/issues/new/choose).
feel free to [file an issue](https://github.com/tal-tech/go-zero/issues/new/choose).
## Find something to work on
@@ -50,10 +50,10 @@ Here is how you get started.
### Find a good first topic
[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)
[go-zero](https://github.com/tal-tech/go-zero) has beginner-friendly issues that provide a good first issue.
For example, [go-zero](https://github.com/tal-tech/go-zero) has
[help wanted](https://github.com/tal-tech/go-zero/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22) and
[good first issue](https://github.com/tal-tech/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.
@@ -79,7 +79,7 @@ This is a rough outline of what a contributor's workflow looks like:
- 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).
- Submit a pull request to [go-zero](https://github.com/tal-tech/go-zero).
## Creating Pull Requests

View File

@@ -1,6 +1,6 @@
MIT License
Copyright (c) 2022 zeromicro
Copyright (c) 2020 xiaoheiban_server_go
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@@ -20,9 +20,9 @@ We hope that the items listed below will inspire further engagement from the com
- [x] Support `goctl bug` to report bugs conveniently
## 2022
- [x] Support `context` in redis related methods for timeout and tracing
- [x] Support `context` in sql related methods for timeout and tracing
- [x] Support `context` in mongodb related methods for timeout and tracing
- [x] Add `httpc.Do` with HTTP call governance, like circuit breaker etc.
- [ ] Support `goctl doctor` command to report potential issues for given service
- [ ] Support `goctl mock` command to start a mocking server with given `.api` file
- [ ] Add `httpx.Client` with governance, like circuit breaker etc.
- [ ] Support `goctl doctor` command to report potential issues for given service
- [ ] Support `context` in redis related methods for timeout and tracing
- [ ] Support `context` in sql related methods for timeout and tracing
- [ ] Support `context` in mongodb related methods for timeout and tracing

View File

@@ -4,8 +4,8 @@ import (
"errors"
"strconv"
"github.com/zeromicro/go-zero/core/hash"
"github.com/zeromicro/go-zero/core/stores/redis"
"github.com/tal-tech/go-zero/core/hash"
"github.com/tal-tech/go-zero/core/stores/redis"
)
const (
@@ -69,8 +69,11 @@ func (f *Filter) Exists(data []byte) (bool, error) {
if err != nil {
return false, err
}
if !isSet {
return false, nil
}
return isSet, nil
return true, nil
}
func (f *Filter) getLocations(data []byte) []uint {

View File

@@ -4,7 +4,7 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/zeromicro/go-zero/core/stores/redis/redistest"
"github.com/tal-tech/go-zero/core/stores/redis/redistest"
)
func TestRedisBitSet_New_Set_Test(t *testing.T) {

View File

@@ -5,12 +5,12 @@ import (
"fmt"
"strings"
"sync"
"time"
"github.com/zeromicro/go-zero/core/mathx"
"github.com/zeromicro/go-zero/core/proc"
"github.com/zeromicro/go-zero/core/stat"
"github.com/zeromicro/go-zero/core/stringx"
"github.com/tal-tech/go-zero/core/mathx"
"github.com/tal-tech/go-zero/core/proc"
"github.com/tal-tech/go-zero/core/stat"
"github.com/tal-tech/go-zero/core/stringx"
"github.com/tal-tech/go-zero/core/timex"
)
const (
@@ -171,7 +171,7 @@ func (lt loggedThrottle) allow() (Promise, error) {
func (lt loggedThrottle) doReq(req func() error, fallback func(err error) error, acceptable Acceptable) error {
return lt.logError(lt.internalThrottle.doReq(req, fallback, func(err error) bool {
accept := acceptable(err)
if !accept && err != nil {
if !accept {
lt.errWin.add(err.Error())
}
return accept
@@ -198,7 +198,7 @@ type errorWindow struct {
func (ew *errorWindow) add(reason string) {
ew.lock.Lock()
ew.reasons[ew.index] = fmt.Sprintf("%s %s", time.Now().Format(timeFormat), reason)
ew.reasons[ew.index] = fmt.Sprintf("%s %s", timex.Time().Format(timeFormat), reason)
ew.index = (ew.index + 1) % numHistoryReasons
ew.count = mathx.MinInt(ew.count+1, numHistoryReasons)
ew.lock.Unlock()

View File

@@ -8,7 +8,7 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/zeromicro/go-zero/core/stat"
"github.com/tal-tech/go-zero/core/stat"
)
func init() {

View File

@@ -6,7 +6,7 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/zeromicro/go-zero/core/stat"
"github.com/tal-tech/go-zero/core/stat"
)
func init() {

View File

@@ -4,8 +4,8 @@ import (
"math"
"time"
"github.com/zeromicro/go-zero/core/collection"
"github.com/zeromicro/go-zero/core/mathx"
"github.com/tal-tech/go-zero/core/collection"
"github.com/tal-tech/go-zero/core/mathx"
)
const (

View File

@@ -7,9 +7,9 @@ import (
"time"
"github.com/stretchr/testify/assert"
"github.com/zeromicro/go-zero/core/collection"
"github.com/zeromicro/go-zero/core/mathx"
"github.com/zeromicro/go-zero/core/stat"
"github.com/tal-tech/go-zero/core/collection"
"github.com/tal-tech/go-zero/core/mathx"
"github.com/tal-tech/go-zero/core/stat"
)
const (

View File

@@ -8,8 +8,8 @@ import (
"time"
"github.com/stretchr/testify/assert"
"github.com/zeromicro/go-zero/core/iox"
"github.com/zeromicro/go-zero/core/lang"
"github.com/tal-tech/go-zero/core/iox"
"github.com/tal-tech/go-zero/core/lang"
)
func TestEnterToContinue(t *testing.T) {

View File

@@ -7,7 +7,7 @@ import (
"encoding/base64"
"errors"
"github.com/zeromicro/go-zero/core/logx"
"github.com/tal-tech/go-zero/core/logx"
)
// ErrPaddingSize indicates bad padding size.

View File

@@ -7,7 +7,7 @@ import (
"encoding/base64"
"encoding/pem"
"errors"
"os"
"io/ioutil"
)
var (
@@ -48,7 +48,7 @@ type (
// NewRsaDecrypter returns a RsaDecrypter with the given file.
func NewRsaDecrypter(file string) (RsaDecrypter, error) {
content, err := os.ReadFile(file)
content, err := ioutil.ReadFile(file)
if err != nil {
return nil, err
}

View File

@@ -5,7 +5,7 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/zeromicro/go-zero/core/fs"
"github.com/tal-tech/go-zero/core/fs"
)
const (

View File

@@ -6,9 +6,9 @@ import (
"sync/atomic"
"time"
"github.com/zeromicro/go-zero/core/logx"
"github.com/zeromicro/go-zero/core/mathx"
"github.com/zeromicro/go-zero/core/syncx"
"github.com/tal-tech/go-zero/core/logx"
"github.com/tal-tech/go-zero/core/mathx"
"github.com/tal-tech/go-zero/core/syncx"
)
const (
@@ -26,7 +26,7 @@ type (
// CacheOption defines the method to customize a Cache.
CacheOption func(cache *Cache)
// A Cache object is an in-memory cache.
// A Cache object is a in-memory cache.
Cache struct {
name string
lock sync.Mutex
@@ -98,18 +98,13 @@ func (c *Cache) Get(key string) (interface{}, bool) {
// Set sets value into c with key.
func (c *Cache) Set(key string, value interface{}) {
c.SetWithExpire(key, value, c.expire)
}
// SetWithExpire sets value into c with key and expire with the given value.
func (c *Cache) SetWithExpire(key string, value interface{}, expire time.Duration) {
c.lock.Lock()
_, ok := c.data[key]
c.data[key] = value
c.lruCache.add(key)
c.lock.Unlock()
expiry := c.unstableExpiry.AroundDuration(expire)
expiry := c.unstableExpiry.AroundDuration(c.expire)
if ok {
c.timingWheel.MoveTimer(key, expiry)
} else {

View File

@@ -18,7 +18,7 @@ func TestCacheSet(t *testing.T) {
assert.Nil(t, err)
cache.Set("first", "first element")
cache.SetWithExpire("second", "second element", time.Second*3)
cache.Set("second", "second element")
value, ok := cache.Get("first")
assert.True(t, ok)

View File

@@ -61,41 +61,3 @@ func TestPutMore(t *testing.T) {
assert.Equal(t, string(element), string(body.([]byte)))
}
}
func TestPutMoreWithHeaderNotZero(t *testing.T) {
elements := [][]byte{
[]byte("hello"),
[]byte("world"),
[]byte("again"),
}
queue := NewQueue(4)
for i := range elements {
queue.Put(elements[i])
}
// take 1
body, ok := queue.Take()
assert.True(t, ok)
element, ok := body.([]byte)
assert.True(t, ok)
assert.Equal(t, element, []byte("hello"))
// put more
queue.Put([]byte("b4"))
queue.Put([]byte("b5")) // will store in elements[0]
queue.Put([]byte("b6")) // cause expansion
results := [][]byte{
[]byte("world"),
[]byte("again"),
[]byte("b4"),
[]byte("b5"),
[]byte("b6"),
}
for _, element := range results {
body, ok := queue.Take()
assert.True(t, ok)
assert.Equal(t, string(element), string(body.([]byte)))
}
}

View File

@@ -4,7 +4,7 @@ import (
"sync"
"time"
"github.com/zeromicro/go-zero/core/timex"
"github.com/tal-tech/go-zero/core/timex"
)
type (

View File

@@ -6,7 +6,7 @@ import (
"time"
"github.com/stretchr/testify/assert"
"github.com/zeromicro/go-zero/core/stringx"
"github.com/tal-tech/go-zero/core/stringx"
)
const duration = time.Millisecond * 50

View File

@@ -68,24 +68,6 @@ func (m *SafeMap) Get(key interface{}) (interface{}, bool) {
return val, ok
}
// Range calls f sequentially for each key and value present in the map.
// If f returns false, range stops the iteration.
func (m *SafeMap) Range(f func(key, val interface{}) bool) {
m.lock.RLock()
defer m.lock.RUnlock()
for k, v := range m.dirtyOld {
if !f(k, v) {
return
}
}
for k, v := range m.dirtyNew {
if !f(k, v) {
return
}
}
}
// Set sets the value into m with the given key.
func (m *SafeMap) Set(key, value interface{}) {
m.lock.Lock()

View File

@@ -1,11 +1,10 @@
package collection
import (
"sync/atomic"
"testing"
"github.com/stretchr/testify/assert"
"github.com/zeromicro/go-zero/core/stringx"
"github.com/tal-tech/go-zero/core/stringx"
)
func TestSafeMap(t *testing.T) {
@@ -108,42 +107,3 @@ func testSafeMapWithParameters(t *testing.T, size, exception int) {
}
}
}
func TestSafeMap_Range(t *testing.T) {
const (
size = 100000
exception1 = 5
exception2 = 500
)
m := NewSafeMap()
newMap := NewSafeMap()
for i := 0; i < size; i++ {
m.Set(i, i)
}
for i := 0; i < size; i++ {
if i%exception1 == 0 {
m.Del(i)
}
}
for i := size; i < size<<1; i++ {
m.Set(i, i)
}
for i := size; i < size<<1; i++ {
if i%exception2 != 0 {
m.Del(i)
}
}
var count int32
m.Range(func(k, v interface{}) bool {
atomic.AddInt32(&count, 1)
newMap.Set(k, v)
return true
})
assert.Equal(t, int(atomic.LoadInt32(&count)), m.Size())
assert.Equal(t, m.dirtyNew, newMap.dirtyNew)
assert.Equal(t, m.dirtyOld, newMap.dirtyOld)
}

View File

@@ -1,8 +1,8 @@
package collection
import (
"github.com/zeromicro/go-zero/core/lang"
"github.com/zeromicro/go-zero/core/logx"
"github.com/tal-tech/go-zero/core/lang"
"github.com/tal-tech/go-zero/core/logx"
)
const (

View File

@@ -5,7 +5,7 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/zeromicro/go-zero/core/logx"
"github.com/tal-tech/go-zero/core/logx"
)
func init() {

View File

@@ -2,22 +2,16 @@ package collection
import (
"container/list"
"errors"
"fmt"
"time"
"github.com/zeromicro/go-zero/core/lang"
"github.com/zeromicro/go-zero/core/threading"
"github.com/zeromicro/go-zero/core/timex"
"github.com/tal-tech/go-zero/core/lang"
"github.com/tal-tech/go-zero/core/threading"
"github.com/tal-tech/go-zero/core/timex"
)
const drainWorkers = 8
var (
ErrClosed = errors.New("TimingWheel is closed already")
ErrArgument = errors.New("incorrect task argument")
)
type (
// Execute defines the method to execute the task.
Execute func(key, value interface{})
@@ -65,15 +59,14 @@ type (
// NewTimingWheel returns a TimingWheel.
func NewTimingWheel(interval time.Duration, numSlots int, execute Execute) (*TimingWheel, error) {
if interval <= 0 || numSlots <= 0 || execute == nil {
return nil, fmt.Errorf("interval: %v, slots: %d, execute: %p",
interval, numSlots, execute)
return nil, fmt.Errorf("interval: %v, slots: %d, execute: %p", interval, numSlots, execute)
}
return newTimingWheelWithClock(interval, numSlots, execute, timex.NewTicker(interval))
}
func newTimingWheelWithClock(interval time.Duration, numSlots int, execute Execute,
ticker timex.Ticker) (*TimingWheel, error) {
func newTimingWheelWithClock(interval time.Duration, numSlots int, execute Execute, ticker timex.Ticker) (
*TimingWheel, error) {
tw := &TimingWheel{
interval: interval,
ticker: ticker,
@@ -96,67 +89,47 @@ func newTimingWheelWithClock(interval time.Duration, numSlots int, execute Execu
}
// Drain drains all items and executes them.
func (tw *TimingWheel) Drain(fn func(key, value interface{})) error {
select {
case tw.drainChannel <- fn:
return nil
case <-tw.stopChannel:
return ErrClosed
}
func (tw *TimingWheel) Drain(fn func(key, value interface{})) {
tw.drainChannel <- fn
}
// MoveTimer moves the task with the given key to the given delay.
func (tw *TimingWheel) MoveTimer(key interface{}, delay time.Duration) error {
func (tw *TimingWheel) MoveTimer(key interface{}, delay time.Duration) {
if delay <= 0 || key == nil {
return ErrArgument
return
}
select {
case tw.moveChannel <- baseEntry{
tw.moveChannel <- baseEntry{
delay: delay,
key: key,
}:
return nil
case <-tw.stopChannel:
return ErrClosed
}
}
// RemoveTimer removes the task with the given key.
func (tw *TimingWheel) RemoveTimer(key interface{}) error {
func (tw *TimingWheel) RemoveTimer(key interface{}) {
if key == nil {
return ErrArgument
return
}
select {
case tw.removeChannel <- key:
return nil
case <-tw.stopChannel:
return ErrClosed
}
tw.removeChannel <- key
}
// SetTimer sets the task value with the given key to the delay.
func (tw *TimingWheel) SetTimer(key, value interface{}, delay time.Duration) error {
func (tw *TimingWheel) SetTimer(key, value interface{}, delay time.Duration) {
if delay <= 0 || key == nil {
return ErrArgument
return
}
select {
case tw.setChannel <- timingEntry{
tw.setChannel <- timingEntry{
baseEntry: baseEntry{
delay: delay,
key: key,
},
value: value,
}:
return nil
case <-tw.stopChannel:
return ErrClosed
}
}
// Stop stops tw. No more actions after stopping a TimingWheel.
// Stop stops tw.
func (tw *TimingWheel) Stop() {
close(tw.stopChannel)
}

View File

@@ -8,10 +8,10 @@ import (
"time"
"github.com/stretchr/testify/assert"
"github.com/zeromicro/go-zero/core/lang"
"github.com/zeromicro/go-zero/core/stringx"
"github.com/zeromicro/go-zero/core/syncx"
"github.com/zeromicro/go-zero/core/timex"
"github.com/tal-tech/go-zero/core/lang"
"github.com/tal-tech/go-zero/core/stringx"
"github.com/tal-tech/go-zero/core/syncx"
"github.com/tal-tech/go-zero/core/timex"
)
const (
@@ -28,6 +28,7 @@ func TestTimingWheel_Drain(t *testing.T) {
ticker := timex.NewFakeTicker()
tw, _ := newTimingWheelWithClock(testStep, 10, func(k, v interface{}) {
}, ticker)
defer tw.Stop()
tw.SetTimer("first", 3, testStep*4)
tw.SetTimer("second", 5, testStep*7)
tw.SetTimer("third", 7, testStep*7)
@@ -55,8 +56,6 @@ func TestTimingWheel_Drain(t *testing.T) {
})
time.Sleep(time.Millisecond * 100)
assert.Equal(t, 0, count)
tw.Stop()
assert.Equal(t, ErrClosed, tw.Drain(func(key, value interface{}) {}))
}
func TestTimingWheel_SetTimerSoon(t *testing.T) {
@@ -103,13 +102,6 @@ func TestTimingWheel_SetTimerWrongDelay(t *testing.T) {
})
}
func TestTimingWheel_SetTimerAfterClose(t *testing.T) {
ticker := timex.NewFakeTicker()
tw, _ := newTimingWheelWithClock(testStep, 10, func(k, v interface{}) {}, ticker)
tw.Stop()
assert.Equal(t, ErrClosed, tw.SetTimer("any", 3, testStep))
}
func TestTimingWheel_MoveTimer(t *testing.T) {
run := syncx.NewAtomicBool()
ticker := timex.NewFakeTicker()
@@ -119,6 +111,7 @@ func TestTimingWheel_MoveTimer(t *testing.T) {
assert.Equal(t, 3, v.(int))
ticker.Done()
}, ticker)
defer tw.Stop()
tw.SetTimer("any", 3, testStep*4)
tw.MoveTimer("any", testStep*7)
tw.MoveTimer("any", -testStep)
@@ -132,8 +125,6 @@ func TestTimingWheel_MoveTimer(t *testing.T) {
}
assert.Nil(t, ticker.Wait(waitTime))
assert.True(t, run.True())
tw.Stop()
assert.Equal(t, ErrClosed, tw.MoveTimer("any", time.Millisecond))
}
func TestTimingWheel_MoveTimerSoon(t *testing.T) {
@@ -184,7 +175,6 @@ func TestTimingWheel_RemoveTimer(t *testing.T) {
ticker.Tick()
}
tw.Stop()
assert.Equal(t, ErrClosed, tw.RemoveTimer("any"))
}
func TestTimingWheel_SetTimer(t *testing.T) {

View File

@@ -1,73 +0,0 @@
package color
import "github.com/fatih/color"
const (
// NoColor is no color for both foreground and background.
NoColor Color = iota
// FgBlack is the foreground color black.
FgBlack
// FgRed is the foreground color red.
FgRed
// FgGreen is the foreground color green.
FgGreen
// FgYellow is the foreground color yellow.
FgYellow
// FgBlue is the foreground color blue.
FgBlue
// FgMagenta is the foreground color magenta.
FgMagenta
// FgCyan is the foreground color cyan.
FgCyan
// FgWhite is the foreground color white.
FgWhite
// BgBlack is the background color black.
BgBlack
// BgRed is the background color red.
BgRed
// BgGreen is the background color green.
BgGreen
// BgYellow is the background color yellow.
BgYellow
// BgBlue is the background color blue.
BgBlue
// BgMagenta is the background color magenta.
BgMagenta
// BgCyan is the background color cyan.
BgCyan
// BgWhite is the background color white.
BgWhite
)
var colors = map[Color][]color.Attribute{
FgBlack: {color.FgBlack, color.Bold},
FgRed: {color.FgRed, color.Bold},
FgGreen: {color.FgGreen, color.Bold},
FgYellow: {color.FgYellow, color.Bold},
FgBlue: {color.FgBlue, color.Bold},
FgMagenta: {color.FgMagenta, color.Bold},
FgCyan: {color.FgCyan, color.Bold},
FgWhite: {color.FgWhite, color.Bold},
BgBlack: {color.BgBlack, color.FgHiWhite, color.Bold},
BgRed: {color.BgRed, color.FgHiWhite, color.Bold},
BgGreen: {color.BgGreen, color.FgHiWhite, color.Bold},
BgYellow: {color.BgHiYellow, color.FgHiBlack, color.Bold},
BgBlue: {color.BgBlue, color.FgHiWhite, color.Bold},
BgMagenta: {color.BgMagenta, color.FgHiWhite, color.Bold},
BgCyan: {color.BgCyan, color.FgHiWhite, color.Bold},
BgWhite: {color.BgHiWhite, color.FgHiBlack, color.Bold},
}
type Color uint32
// WithColor returns a string with the given color applied.
func WithColor(text string, colour Color) string {
c := color.New(colors[colour]...)
return c.Sprint(text)
}
// WithColorPadding returns a string with the given color applied with leading and trailing spaces.
func WithColorPadding(text string, colour Color) string {
return WithColor(" "+text+" ", colour)
}

View File

@@ -1,17 +0,0 @@
package color
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestWithColor(t *testing.T) {
output := WithColor("Hello", BgRed)
assert.Equal(t, "Hello", output)
}
func TestWithColorPadding(t *testing.T) {
output := WithColorPadding("Hello", BgRed)
assert.Equal(t, " Hello ", output)
}

View File

@@ -2,29 +2,28 @@ package conf
import (
"fmt"
"io/ioutil"
"log"
"os"
"path"
"strings"
"github.com/zeromicro/go-zero/core/mapping"
"github.com/tal-tech/go-zero/core/mapping"
)
var loaders = map[string]func([]byte, interface{}) error{
".json": LoadFromJsonBytes,
".toml": LoadFromTomlBytes,
".yaml": LoadFromYamlBytes,
".yml": LoadFromYamlBytes,
".json": LoadConfigFromJsonBytes,
".yaml": LoadConfigFromYamlBytes,
".yml": LoadConfigFromYamlBytes,
}
// Load loads config into v from file, .json, .yaml and .yml are acceptable.
func Load(file string, v interface{}, opts ...Option) error {
content, err := os.ReadFile(file)
// LoadConfig loads config into v from file, .json, .yaml and .yml are acceptable.
func LoadConfig(file string, v interface{}, opts ...Option) error {
content, err := ioutil.ReadFile(file)
if err != nil {
return err
}
loader, ok := loaders[strings.ToLower(path.Ext(file))]
loader, ok := loaders[path.Ext(file)]
if !ok {
return fmt.Errorf("unrecognized file type: %s", file)
}
@@ -41,42 +40,19 @@ func Load(file string, v interface{}, opts ...Option) error {
return loader(content, v)
}
// LoadConfig loads config into v from file, .json, .yaml and .yml are acceptable.
// Deprecated: use Load instead.
func LoadConfig(file string, v interface{}, opts ...Option) error {
return Load(file, v, opts...)
}
// LoadFromJsonBytes loads config into v from content json bytes.
func LoadFromJsonBytes(content []byte, v interface{}) error {
// LoadConfigFromJsonBytes loads config into v from content json bytes.
func LoadConfigFromJsonBytes(content []byte, v interface{}) error {
return mapping.UnmarshalJsonBytes(content, v)
}
// LoadConfigFromJsonBytes loads config into v from content json bytes.
// Deprecated: use LoadFromJsonBytes instead.
func LoadConfigFromJsonBytes(content []byte, v interface{}) error {
return LoadFromJsonBytes(content, v)
}
// LoadFromTomlBytes loads config into v from content toml bytes.
func LoadFromTomlBytes(content []byte, v interface{}) error {
return mapping.UnmarshalTomlBytes(content, v)
}
// LoadFromYamlBytes loads config into v from content yaml bytes.
func LoadFromYamlBytes(content []byte, v interface{}) error {
return mapping.UnmarshalYamlBytes(content, v)
}
// LoadConfigFromYamlBytes loads config into v from content yaml bytes.
// Deprecated: use LoadFromYamlBytes instead.
func LoadConfigFromYamlBytes(content []byte, v interface{}) error {
return LoadFromYamlBytes(content, v)
return mapping.UnmarshalYamlBytes(content, v)
}
// MustLoad loads config into v from path, exits on error.
func MustLoad(path string, v interface{}, opts ...Option) {
if err := Load(path, v, opts...); err != nil {
if err := LoadConfig(path, v, opts...); err != nil {
log.Fatalf("error: config file %s, %s", path, err.Error())
}
}

View File

@@ -1,23 +1,24 @@
package conf
import (
"io/ioutil"
"os"
"testing"
"github.com/stretchr/testify/assert"
"github.com/zeromicro/go-zero/core/fs"
"github.com/zeromicro/go-zero/core/hash"
"github.com/tal-tech/go-zero/core/fs"
"github.com/tal-tech/go-zero/core/hash"
)
func TestLoadConfig_notExists(t *testing.T) {
assert.NotNil(t, Load("not_a_file", nil))
assert.NotNil(t, LoadConfig("not_a_file", nil))
}
func TestLoadConfig_notRecogFile(t *testing.T) {
filename, err := fs.TempFilenameWithText("hello")
assert.Nil(t, err)
defer os.Remove(filename)
assert.NotNil(t, Load(filename, nil))
assert.NotNil(t, LoadConfig(filename, nil))
}
func TestConfigJson(t *testing.T) {
@@ -56,57 +57,6 @@ func TestConfigJson(t *testing.T) {
}
}
func TestConfigToml(t *testing.T) {
text := `a = "foo"
b = 1
c = "${FOO}"
d = "abcd!@#$112"
`
os.Setenv("FOO", "2")
defer os.Unsetenv("FOO")
tmpfile, err := createTempFile(".toml", text)
assert.Nil(t, err)
defer os.Remove(tmpfile)
var val struct {
A string `json:"a"`
B int `json:"b"`
C string `json:"c"`
D string `json:"d"`
}
MustLoad(tmpfile, &val)
assert.Equal(t, "foo", val.A)
assert.Equal(t, 1, val.B)
assert.Equal(t, "${FOO}", val.C)
assert.Equal(t, "abcd!@#$112", val.D)
}
func TestConfigTomlEnv(t *testing.T) {
text := `a = "foo"
b = 1
c = "${FOO}"
d = "abcd!@#112"
`
os.Setenv("FOO", "2")
defer os.Unsetenv("FOO")
tmpfile, err := createTempFile(".toml", text)
assert.Nil(t, err)
defer os.Remove(tmpfile)
var val struct {
A string `json:"a"`
B int `json:"b"`
C string `json:"c"`
D string `json:"d"`
}
MustLoad(tmpfile, &val, UseEnv())
assert.Equal(t, "foo", val.A)
assert.Equal(t, 1, val.B)
assert.Equal(t, "2", val.C)
assert.Equal(t, "abcd!@#112", val.D)
}
func TestConfigJsonEnv(t *testing.T) {
tests := []string{
".json",
@@ -144,12 +94,12 @@ func TestConfigJsonEnv(t *testing.T) {
}
func createTempFile(ext, text string) (string, error) {
tmpfile, err := os.CreateTemp(os.TempDir(), hash.Md5Hex([]byte(text))+"*"+ext)
tmpfile, err := ioutil.TempFile(os.TempDir(), hash.Md5Hex([]byte(text))+"*"+ext)
if err != nil {
return "", err
}
if err := os.WriteFile(tmpfile.Name(), []byte(text), os.ModeTemporary); err != nil {
if err := ioutil.WriteFile(tmpfile.Name(), []byte(text), os.ModeTemporary); err != nil {
return "", err
}

View File

@@ -7,7 +7,7 @@ import (
"strings"
"sync"
"github.com/zeromicro/go-zero/core/iox"
"github.com/tal-tech/go-zero/core/iox"
)
// PropertyError represents a configuration error message.

View File

@@ -5,7 +5,7 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/zeromicro/go-zero/core/fs"
"github.com/tal-tech/go-zero/core/fs"
)
func TestProperties(t *testing.T) {

View File

@@ -1,57 +0,0 @@
## How to use
1. Define a config structure, like below:
```go
type RestfulConf struct {
Host string `json:",default=0.0.0.0"`
Port int
LogMode string `json:",options=[file,console]"`
Verbose bool `json:",optional"`
MaxConns int `json:",default=10000"`
MaxBytes int64 `json:",default=1048576"`
Timeout time.Duration `json:",default=3s"`
CpuThreshold int64 `json:",default=900,range=[0:1000]"`
}
```
2. Write the yaml, toml or json config file:
- yaml example
```yaml
# most fields are optional or have default values
Port: 8080
LogMode: console
# you can use env settings
MaxBytes: ${MAX_BYTES}
```
- toml example
```toml
# most fields are optional or have default values
Port = 8_080
LogMode = "console"
# you can use env settings
MaxBytes = "${MAX_BYTES}"
```
3. Load the config from a file:
```go
// exit on error
var config RestfulConf
conf.MustLoad(configFile, &config)
// or handle the error on your own
var config RestfulConf
if err := conf.Load(configFile, &config); err != nil {
log.Fatal(err)
}
// enable reading from environments
var config RestfulConf
conf.MustLoad(configFile, &config, conf.UseEnv())
```

View File

@@ -3,7 +3,7 @@ package contextx
import (
"context"
"github.com/zeromicro/go-zero/core/mapping"
"github.com/tal-tech/go-zero/core/mapping"
)
const contextTagKey = "ctx"

View File

@@ -1,6 +1,6 @@
package discov
import "github.com/zeromicro/go-zero/core/discov/internal"
import "github.com/tal-tech/go-zero/core/discov/internal"
// RegisterAccount registers the username/password to the given etcd cluster.
func RegisterAccount(endpoints []string, user, pass string) {

View File

@@ -4,8 +4,8 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/zeromicro/go-zero/core/discov/internal"
"github.com/zeromicro/go-zero/core/stringx"
"github.com/tal-tech/go-zero/core/discov/internal"
"github.com/tal-tech/go-zero/core/stringx"
)
func TestRegisterAccount(t *testing.T) {

View File

@@ -4,7 +4,7 @@ import (
"fmt"
"strings"
"github.com/zeromicro/go-zero/core/discov/internal"
"github.com/tal-tech/go-zero/core/discov/internal"
)
const (

View File

@@ -5,7 +5,7 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/zeromicro/go-zero/core/discov/internal"
"github.com/tal-tech/go-zero/core/discov/internal"
)
var mockLock sync.Mutex

View File

@@ -2,13 +2,6 @@ package discov
import "errors"
var (
// errEmptyEtcdHosts indicates that etcd hosts are empty.
errEmptyEtcdHosts = errors.New("empty etcd hosts")
// errEmptyEtcdKey indicates that etcd key is empty.
errEmptyEtcdKey = errors.New("empty etcd key")
)
// EtcdConf is the config item with the given key on etcd.
type EtcdConf struct {
Hosts []string
@@ -34,9 +27,9 @@ func (c EtcdConf) HasTLS() bool {
// Validate validates c.
func (c EtcdConf) Validate() error {
if len(c.Hosts) == 0 {
return errEmptyEtcdHosts
return errors.New("empty etcd hosts")
} else if len(c.Key) == 0 {
return errEmptyEtcdKey
return errors.New("empty etcd key")
} else {
return nil
}

View File

@@ -3,7 +3,7 @@ package internal
import (
"crypto/tls"
"crypto/x509"
"os"
"io/ioutil"
"sync"
)
@@ -37,7 +37,7 @@ func AddTLS(endpoints []string, certFile, certKeyFile, caFile string, insecureSk
return err
}
caData, err := os.ReadFile(caFile)
caData, err := ioutil.ReadFile(caFile)
if err != nil {
return err
}

View File

@@ -4,7 +4,7 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/zeromicro/go-zero/core/stringx"
"github.com/tal-tech/go-zero/core/stringx"
)
func TestAccount(t *testing.T) {

View File

@@ -9,11 +9,11 @@ import (
"sync"
"time"
"github.com/zeromicro/go-zero/core/contextx"
"github.com/zeromicro/go-zero/core/lang"
"github.com/zeromicro/go-zero/core/logx"
"github.com/zeromicro/go-zero/core/syncx"
"github.com/zeromicro/go-zero/core/threading"
"github.com/tal-tech/go-zero/core/contextx"
"github.com/tal-tech/go-zero/core/lang"
"github.com/tal-tech/go-zero/core/logx"
"github.com/tal-tech/go-zero/core/syncx"
"github.com/tal-tech/go-zero/core/threading"
clientv3 "go.etcd.io/etcd/client/v3"
)
@@ -191,11 +191,9 @@ func (c *cluster) handleWatchEvents(key string, events []*clientv3.Event) {
})
}
case clientv3.EventTypeDelete:
c.lock.Lock()
if vals, ok := c.values[key]; ok {
delete(vals, string(ev.Kv.Key))
}
c.lock.Unlock()
for _, l := range listeners {
l.OnDelete(KV{
Key: string(ev.Kv.Key),
@@ -208,7 +206,7 @@ func (c *cluster) handleWatchEvents(key string, events []*clientv3.Event) {
}
}
func (c *cluster) load(cli EtcdClient, key string) int64 {
func (c *cluster) load(cli EtcdClient, key string) {
var resp *clientv3.GetResponse
for {
var err error
@@ -232,8 +230,6 @@ func (c *cluster) load(cli EtcdClient, key string) int64 {
}
c.handleChanges(key, kvs)
return resp.Header.Revision
}
func (c *cluster) monitor(key string, l UpdateListener) error {
@@ -246,9 +242,9 @@ func (c *cluster) monitor(key string, l UpdateListener) error {
return err
}
rev := c.load(cli, key)
c.load(cli, key)
c.watchGroup.Run(func() {
c.watch(cli, key, rev)
c.watch(cli, key)
})
return nil
@@ -280,29 +276,22 @@ func (c *cluster) reload(cli EtcdClient) {
for _, key := range keys {
k := key
c.watchGroup.Run(func() {
rev := c.load(cli, k)
c.watch(cli, k, rev)
c.load(cli, k)
c.watch(cli, k)
})
}
}
func (c *cluster) watch(cli EtcdClient, key string, rev int64) {
func (c *cluster) watch(cli EtcdClient, key string) {
for {
if c.watchStream(cli, key, rev) {
if c.watchStream(cli, key) {
return
}
}
}
func (c *cluster) watchStream(cli EtcdClient, key string, rev int64) bool {
var rch clientv3.WatchChan
if rev != 0 {
rch = cli.Watch(clientv3.WithRequireLeader(c.context(cli)), makeKeyPrefix(key), clientv3.WithPrefix(),
clientv3.WithRev(rev+1))
} else {
rch = cli.Watch(clientv3.WithRequireLeader(c.context(cli)), makeKeyPrefix(key), clientv3.WithPrefix())
}
func (c *cluster) watchStream(cli EtcdClient, key string) bool {
rch := cli.Watch(clientv3.WithRequireLeader(c.context(cli)), makeKeyPrefix(key), clientv3.WithPrefix())
for {
select {
case wresp, ok := <-rch:
@@ -343,7 +332,6 @@ func DialClient(endpoints []string) (EtcdClient, error) {
DialKeepAliveTime: dialKeepAliveTime,
DialKeepAliveTimeout: DialTimeout,
RejectOldCluster: true,
PermitWithoutStream: true,
}
if account, ok := GetAccount(endpoints); ok {
cfg.Username = account.User

View File

@@ -7,11 +7,10 @@ import (
"github.com/golang/mock/gomock"
"github.com/stretchr/testify/assert"
"github.com/zeromicro/go-zero/core/contextx"
"github.com/zeromicro/go-zero/core/lang"
"github.com/zeromicro/go-zero/core/logx"
"github.com/zeromicro/go-zero/core/stringx"
"go.etcd.io/etcd/api/v3/etcdserverpb"
"github.com/tal-tech/go-zero/core/contextx"
"github.com/tal-tech/go-zero/core/lang"
"github.com/tal-tech/go-zero/core/logx"
"github.com/tal-tech/go-zero/core/stringx"
"go.etcd.io/etcd/api/v3/mvccpb"
clientv3 "go.etcd.io/etcd/client/v3"
)
@@ -113,7 +112,6 @@ func TestCluster_Load(t *testing.T) {
restore := setMockClient(cli)
defer restore()
cli.EXPECT().Get(gomock.Any(), "any/", gomock.Any()).Return(&clientv3.GetResponse{
Header: &etcdserverpb.ResponseHeader{},
Kvs: []*mvccpb.KeyValue{
{
Key: []byte("hello"),
@@ -170,7 +168,7 @@ func TestCluster_Watch(t *testing.T) {
listener.EXPECT().OnDelete(gomock.Any()).Do(func(_ interface{}) {
wg.Done()
}).MaxTimes(1)
go c.watch(cli, "any", 0)
go c.watch(cli, "any")
ch <- clientv3.WatchResponse{
Events: []*clientv3.Event{
{
@@ -214,7 +212,7 @@ func TestClusterWatch_RespFailures(t *testing.T) {
ch <- resp
close(c.done)
}()
c.watch(cli, "any", 0)
c.watch(cli, "any")
})
}
}
@@ -234,7 +232,7 @@ func TestClusterWatch_CloseChan(t *testing.T) {
close(ch)
close(c.done)
}()
c.watch(cli, "any", 0)
c.watch(cli, "any")
}
func TestValueOnlyContext(t *testing.T) {

View File

@@ -1,12 +1,12 @@
package discov
import (
"github.com/zeromicro/go-zero/core/discov/internal"
"github.com/zeromicro/go-zero/core/lang"
"github.com/zeromicro/go-zero/core/logx"
"github.com/zeromicro/go-zero/core/proc"
"github.com/zeromicro/go-zero/core/syncx"
"github.com/zeromicro/go-zero/core/threading"
"github.com/tal-tech/go-zero/core/discov/internal"
"github.com/tal-tech/go-zero/core/lang"
"github.com/tal-tech/go-zero/core/logx"
"github.com/tal-tech/go-zero/core/proc"
"github.com/tal-tech/go-zero/core/syncx"
"github.com/tal-tech/go-zero/core/threading"
clientv3 "go.etcd.io/etcd/client/v3"
)

View File

@@ -8,10 +8,10 @@ import (
"github.com/golang/mock/gomock"
"github.com/stretchr/testify/assert"
"github.com/zeromicro/go-zero/core/discov/internal"
"github.com/zeromicro/go-zero/core/lang"
"github.com/zeromicro/go-zero/core/logx"
"github.com/zeromicro/go-zero/core/stringx"
"github.com/tal-tech/go-zero/core/discov/internal"
"github.com/tal-tech/go-zero/core/lang"
"github.com/tal-tech/go-zero/core/logx"
"github.com/tal-tech/go-zero/core/stringx"
clientv3 "go.etcd.io/etcd/client/v3"
)

View File

@@ -4,9 +4,9 @@ import (
"sync"
"sync/atomic"
"github.com/zeromicro/go-zero/core/discov/internal"
"github.com/zeromicro/go-zero/core/logx"
"github.com/zeromicro/go-zero/core/syncx"
"github.com/tal-tech/go-zero/core/discov/internal"
"github.com/tal-tech/go-zero/core/logx"
"github.com/tal-tech/go-zero/core/syncx"
)
type (

View File

@@ -5,8 +5,8 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/zeromicro/go-zero/core/discov/internal"
"github.com/zeromicro/go-zero/core/stringx"
"github.com/tal-tech/go-zero/core/discov/internal"
"github.com/tal-tech/go-zero/core/stringx"
)
const (

View File

@@ -11,12 +11,10 @@ type (
errorArray []error
)
// Add adds errs to be, nil errors are ignored.
func (be *BatchError) Add(errs ...error) {
for _, err := range errs {
if err != nil {
be.errs = append(be.errs, err)
}
// Add adds err to be.
func (be *BatchError) Add(err error) {
if err != nil {
be.errs = append(be.errs, err)
}
}

View File

@@ -1,21 +0,0 @@
package errorx
import "fmt"
// Wrap returns an error that wraps err with given message.
func Wrap(err error, message string) error {
if err == nil {
return nil
}
return fmt.Errorf("%s: %w", message, err)
}
// Wrapf returns an error that wraps err with given format and args.
func Wrapf(err error, format string, args ...interface{}) error {
if err == nil {
return nil
}
return fmt.Errorf("%s: %w", fmt.Sprintf(format, args...), err)
}

View File

@@ -1,24 +0,0 @@
package errorx
import (
"errors"
"testing"
"github.com/stretchr/testify/assert"
)
func TestWrap(t *testing.T) {
assert.Nil(t, Wrap(nil, "test"))
assert.Equal(t, "foo: bar", Wrap(errors.New("bar"), "foo").Error())
err := errors.New("foo")
assert.True(t, errors.Is(Wrap(err, "bar"), err))
}
func TestWrapf(t *testing.T) {
assert.Nil(t, Wrapf(nil, "%s", "test"))
assert.Equal(t, "foo bar: quz", Wrapf(errors.New("quz"), "foo %s", "bar").Error())
err := errors.New("foo")
assert.True(t, errors.Is(Wrapf(err, "foo %s", "bar"), err))
}

View File

@@ -4,7 +4,7 @@ import (
"sync"
"time"
"github.com/zeromicro/go-zero/core/threading"
"github.com/tal-tech/go-zero/core/threading"
)
// A DelayExecutor delays a tasks on given delay interval.

View File

@@ -3,8 +3,8 @@ package executors
import (
"time"
"github.com/zeromicro/go-zero/core/syncx"
"github.com/zeromicro/go-zero/core/timex"
"github.com/tal-tech/go-zero/core/syncx"
"github.com/tal-tech/go-zero/core/timex"
)
// A LessExecutor is an executor to limit execution once within given time interval.

View File

@@ -5,7 +5,7 @@ import (
"time"
"github.com/stretchr/testify/assert"
"github.com/zeromicro/go-zero/core/timex"
"github.com/tal-tech/go-zero/core/timex"
)
func TestLessExecutor_DoOrDiscard(t *testing.T) {

View File

@@ -6,11 +6,11 @@ import (
"sync/atomic"
"time"
"github.com/zeromicro/go-zero/core/lang"
"github.com/zeromicro/go-zero/core/proc"
"github.com/zeromicro/go-zero/core/syncx"
"github.com/zeromicro/go-zero/core/threading"
"github.com/zeromicro/go-zero/core/timex"
"github.com/tal-tech/go-zero/core/lang"
"github.com/tal-tech/go-zero/core/proc"
"github.com/tal-tech/go-zero/core/syncx"
"github.com/tal-tech/go-zero/core/threading"
"github.com/tal-tech/go-zero/core/timex"
)
const idleRound = 10

View File

@@ -8,7 +8,7 @@ import (
"time"
"github.com/stretchr/testify/assert"
"github.com/zeromicro/go-zero/core/timex"
"github.com/tal-tech/go-zero/core/timex"
)
const threshold = 10

View File

@@ -5,7 +5,7 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/zeromicro/go-zero/core/fs"
"github.com/tal-tech/go-zero/core/fs"
)
const (

View File

@@ -5,7 +5,7 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/zeromicro/go-zero/core/fs"
"github.com/tal-tech/go-zero/core/fs"
)
func TestSplitLineChunks(t *testing.T) {

View File

@@ -5,9 +5,6 @@ import (
"os"
)
// errExceedFileSize indicates that the file size is exceeded.
var errExceedFileSize = errors.New("exceed file size")
// A RangeReader is used to read a range of content from a file.
type RangeReader struct {
file *os.File
@@ -32,7 +29,7 @@ func (rr *RangeReader) Read(p []byte) (n int, err error) {
}
if rr.stop < rr.start || rr.start >= stat.Size() {
return 0, errExceedFileSize
return 0, errors.New("exceed file size")
}
if rr.stop-rr.start < int64(len(p)) {

View File

@@ -5,7 +5,7 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/zeromicro/go-zero/core/fs"
"github.com/tal-tech/go-zero/core/fs"
)
func TestRangeReader(t *testing.T) {

View File

@@ -1,9 +1,10 @@
package fs
import (
"io/ioutil"
"os"
"github.com/zeromicro/go-zero/core/hash"
"github.com/tal-tech/go-zero/core/hash"
)
// TempFileWithText creates the temporary file with the given content,
@@ -11,12 +12,12 @@ import (
// The file is kept as open, the caller should close the file handle,
// and remove the file by name.
func TempFileWithText(text string) (*os.File, error) {
tmpfile, err := os.CreateTemp(os.TempDir(), hash.Md5Hex([]byte(text)))
tmpfile, err := ioutil.TempFile(os.TempDir(), hash.Md5Hex([]byte(text)))
if err != nil {
return nil, err
}
if err := os.WriteFile(tmpfile.Name(), []byte(text), os.ModeTemporary); err != nil {
if err := ioutil.WriteFile(tmpfile.Name(), []byte(text), os.ModeTemporary); err != nil {
return nil, err
}

View File

@@ -1,49 +0,0 @@
package fs
import (
"io"
"os"
"testing"
"github.com/stretchr/testify/assert"
)
func TestTempFileWithText(t *testing.T) {
f, err := TempFileWithText("test")
if err != nil {
t.Error(err)
}
if f == nil {
t.Error("TempFileWithText returned nil")
}
if f.Name() == "" {
t.Error("TempFileWithText returned empty file name")
}
defer os.Remove(f.Name())
bs, err := io.ReadAll(f)
assert.Nil(t, err)
if len(bs) != 4 {
t.Error("TempFileWithText returned wrong file size")
}
if f.Close() != nil {
t.Error("TempFileWithText returned error on close")
}
}
func TestTempFilenameWithText(t *testing.T) {
f, err := TempFilenameWithText("test")
if err != nil {
t.Error(err)
}
if f == "" {
t.Error("TempFilenameWithText returned empty file name")
}
defer os.Remove(f)
bs, err := os.ReadFile(f)
assert.Nil(t, err)
if len(bs) != 4 {
t.Error("TempFilenameWithText returned wrong file size")
}
}

View File

@@ -1,6 +1,6 @@
package fx
import "github.com/zeromicro/go-zero/core/threading"
import "github.com/tal-tech/go-zero/core/threading"
// Parallel runs fns parallelly and waits for done.
func Parallel(fns ...func()) {

View File

@@ -1,6 +1,6 @@
package fx
import "github.com/zeromicro/go-zero/core/errorx"
import "github.com/tal-tech/go-zero/core/errorx"
const defaultRetryTimes = 3

View File

@@ -4,9 +4,9 @@ import (
"sort"
"sync"
"github.com/zeromicro/go-zero/core/collection"
"github.com/zeromicro/go-zero/core/lang"
"github.com/zeromicro/go-zero/core/threading"
"github.com/tal-tech/go-zero/core/collection"
"github.com/tal-tech/go-zero/core/lang"
"github.com/tal-tech/go-zero/core/threading"
)
const (

View File

@@ -1,7 +1,7 @@
package fx
import (
"io"
"io/ioutil"
"log"
"math/rand"
"reflect"
@@ -13,8 +13,7 @@ import (
"time"
"github.com/stretchr/testify/assert"
"github.com/zeromicro/go-zero/core/stringx"
"go.uber.org/goleak"
"github.com/tal-tech/go-zero/core/stringx"
)
func TestBuffer(t *testing.T) {
@@ -238,7 +237,7 @@ func TestLast(t *testing.T) {
func TestMap(t *testing.T) {
runCheckedTest(t, func(t *testing.T) {
log.SetOutput(io.Discard)
log.SetOutput(ioutil.Discard)
tests := []struct {
mapper MapFunc
@@ -564,6 +563,9 @@ func equal(t *testing.T, stream Stream, data []interface{}) {
}
func runCheckedTest(t *testing.T, fn func(t *testing.T)) {
defer goleak.VerifyNone(t)
goroutines := runtime.NumGoroutine()
fn(t)
// let scheduler schedule first
time.Sleep(time.Millisecond)
assert.True(t, runtime.NumGoroutine() <= goroutines)
}

View File

@@ -6,8 +6,8 @@ import (
"strconv"
"sync"
"github.com/zeromicro/go-zero/core/lang"
"github.com/zeromicro/go-zero/core/mapping"
"github.com/tal-tech/go-zero/core/lang"
"github.com/tal-tech/go-zero/core/mapping"
)
const (

View File

@@ -6,7 +6,7 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/zeromicro/go-zero/core/mathx"
"github.com/tal-tech/go-zero/core/mathx"
)
const (

View File

@@ -4,6 +4,7 @@ import (
"bufio"
"bytes"
"io"
"io/ioutil"
"os"
"strings"
)
@@ -25,7 +26,7 @@ type (
func DupReadCloser(reader io.ReadCloser) (io.ReadCloser, io.ReadCloser) {
var buf bytes.Buffer
tee := io.TeeReader(reader, &buf)
return io.NopCloser(tee), io.NopCloser(&buf)
return ioutil.NopCloser(tee), ioutil.NopCloser(&buf)
}
// KeepSpace customizes the reading functions to keep leading and tailing spaces.
@@ -53,7 +54,7 @@ func ReadBytes(reader io.Reader, buf []byte) error {
// ReadText reads content from the given file with leading and tailing spaces trimmed.
func ReadText(filename string) (string, error) {
content, err := os.ReadFile(filename)
content, err := ioutil.ReadFile(filename)
if err != nil {
return "", err
}

View File

@@ -3,13 +3,14 @@ package iox
import (
"bytes"
"io"
"io/ioutil"
"os"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/zeromicro/go-zero/core/fs"
"github.com/zeromicro/go-zero/core/stringx"
"github.com/tal-tech/go-zero/core/fs"
"github.com/tal-tech/go-zero/core/stringx"
)
func TestReadText(t *testing.T) {
@@ -96,10 +97,10 @@ func TestReadTextLines(t *testing.T) {
func TestDupReadCloser(t *testing.T) {
input := "hello"
reader := io.NopCloser(bytes.NewBufferString(input))
reader := ioutil.NopCloser(bytes.NewBufferString(input))
r1, r2 := DupReadCloser(reader)
verify := func(r io.Reader) {
output, err := io.ReadAll(r)
output, err := ioutil.ReadAll(r)
assert.Nil(t, err)
assert.Equal(t, input, string(output))
}
@@ -109,7 +110,7 @@ func TestDupReadCloser(t *testing.T) {
}
func TestReadBytes(t *testing.T) {
reader := io.NopCloser(bytes.NewBufferString("helloworld"))
reader := ioutil.NopCloser(bytes.NewBufferString("helloworld"))
buf := make([]byte, 5)
err := ReadBytes(reader, buf)
assert.Nil(t, err)
@@ -117,7 +118,7 @@ func TestReadBytes(t *testing.T) {
}
func TestReadBytesNotEnough(t *testing.T) {
reader := io.NopCloser(bytes.NewBufferString("hell"))
reader := ioutil.NopCloser(bytes.NewBufferString("hell"))
buf := make([]byte, 5)
err := ReadBytes(reader, buf)
assert.Equal(t, io.EOF, err)

View File

@@ -1,6 +1,7 @@
package iox
import (
"io/ioutil"
"os"
"testing"
@@ -12,7 +13,7 @@ func TestCountLines(t *testing.T) {
2
3
4`
file, err := os.CreateTemp(os.TempDir(), "test-")
file, err := ioutil.TempFile(os.TempDir(), "test-")
if err != nil {
t.Fatal(err)
}

View File

@@ -13,16 +13,6 @@ func Marshal(v interface{}) ([]byte, error) {
return json.Marshal(v)
}
// MarshalToString marshals v into a string.
func MarshalToString(v interface{}) (string, error) {
data, err := Marshal(v)
if err != nil {
return "", err
}
return string(data), nil
}
// Unmarshal unmarshals data bytes into v.
func Unmarshal(data []byte, v interface{}) error {
decoder := json.NewDecoder(bytes.NewReader(data))
@@ -61,5 +51,5 @@ func unmarshalUseNumber(decoder *json.Decoder, v interface{}) error {
}
func formatError(v string, err error) error {
return fmt.Errorf("string: `%s`, error: `%w`", v, err)
return fmt.Errorf("string: `%s`, error: `%s`", v, err.Error())
}

View File

@@ -1,103 +0,0 @@
package jsonx
import (
"strings"
"testing"
"github.com/stretchr/testify/assert"
)
func TestMarshal(t *testing.T) {
var v = struct {
Name string `json:"name"`
Age int `json:"age"`
}{
Name: "John",
Age: 30,
}
bs, err := Marshal(v)
assert.Nil(t, err)
assert.Equal(t, `{"name":"John","age":30}`, string(bs))
}
func TestMarshalToString(t *testing.T) {
var v = struct {
Name string `json:"name"`
Age int `json:"age"`
}{
Name: "John",
Age: 30,
}
toString, err := MarshalToString(v)
assert.Nil(t, err)
assert.Equal(t, `{"name":"John","age":30}`, toString)
_, err = MarshalToString(make(chan int))
assert.NotNil(t, err)
}
func TestUnmarshal(t *testing.T) {
const s = `{"name":"John","age":30}`
var v struct {
Name string `json:"name"`
Age int `json:"age"`
}
err := Unmarshal([]byte(s), &v)
assert.Nil(t, err)
assert.Equal(t, "John", v.Name)
assert.Equal(t, 30, v.Age)
}
func TestUnmarshalError(t *testing.T) {
const s = `{"name":"John","age":30`
var v struct {
Name string `json:"name"`
Age int `json:"age"`
}
err := Unmarshal([]byte(s), &v)
assert.NotNil(t, err)
}
func TestUnmarshalFromString(t *testing.T) {
const s = `{"name":"John","age":30}`
var v struct {
Name string `json:"name"`
Age int `json:"age"`
}
err := UnmarshalFromString(s, &v)
assert.Nil(t, err)
assert.Equal(t, "John", v.Name)
assert.Equal(t, 30, v.Age)
}
func TestUnmarshalFromStringError(t *testing.T) {
const s = `{"name":"John","age":30`
var v struct {
Name string `json:"name"`
Age int `json:"age"`
}
err := UnmarshalFromString(s, &v)
assert.NotNil(t, err)
}
func TestUnmarshalFromRead(t *testing.T) {
const s = `{"name":"John","age":30}`
var v struct {
Name string `json:"name"`
Age int `json:"age"`
}
err := UnmarshalFromReader(strings.NewReader(s), &v)
assert.Nil(t, err)
assert.Equal(t, "John", v.Name)
assert.Equal(t, 30, v.Age)
}
func TestUnmarshalFromReaderError(t *testing.T) {
const s = `{"name":"John","age":30`
var v struct {
Name string `json:"name"`
Age int `json:"age"`
}
err := UnmarshalFromReader(strings.NewReader(s), &v)
assert.NotNil(t, err)
}

View File

@@ -1,28 +1,30 @@
package limit
import (
"context"
"errors"
"strconv"
"time"
"github.com/zeromicro/go-zero/core/stores/redis"
"github.com/tal-tech/go-zero/core/stores/redis"
)
// to be compatible with aliyun redis, we cannot use `local key = KEYS[1]` to reuse the key
const periodScript = `local limit = tonumber(ARGV[1])
const (
// to be compatible with aliyun redis, we cannot use `local key = KEYS[1]` to reuse the key
periodScript = `local limit = tonumber(ARGV[1])
local window = tonumber(ARGV[2])
local current = redis.call("INCRBY", KEYS[1], 1)
if current == 1 then
redis.call("expire", KEYS[1], window)
end
if current < limit then
return 1
elseif current < limit then
return 1
elseif current == limit then
return 2
else
return 0
end`
zoneDiff = 3600 * 8 // GMT+8 for our services
)
const (
// Unknown means not initialized state.
@@ -75,12 +77,7 @@ func NewPeriodLimit(period, quota int, limitStore *redis.Redis, keyPrefix string
// Take requests a permit, it returns the permit state.
func (h *PeriodLimit) Take(key string) (int, error) {
return h.TakeCtx(context.Background(), key)
}
// TakeCtx requests a permit with context, it returns the permit state.
func (h *PeriodLimit) TakeCtx(ctx context.Context, key string) (int, error) {
resp, err := h.limitStore.EvalCtx(ctx, periodScript, []string{h.keyPrefix + key}, []string{
resp, err := h.limitStore.Eval(periodScript, []string{h.keyPrefix + key}, []string{
strconv.Itoa(h.quota),
strconv.Itoa(h.calcExpireSeconds()),
})
@@ -107,9 +104,7 @@ func (h *PeriodLimit) TakeCtx(ctx context.Context, key string) (int, error) {
func (h *PeriodLimit) calcExpireSeconds() int {
if h.align {
now := time.Now()
_, offset := now.Zone()
unix := now.Unix() + int64(offset)
unix := time.Now().Unix() + zoneDiff
return h.period - int(unix%int64(h.period))
}
@@ -117,8 +112,6 @@ func (h *PeriodLimit) calcExpireSeconds() int {
}
// Align returns a func to customize a PeriodLimit with alignment.
// For example, if we want to limit end users with 5 sms verification messages every day,
// we need to align with the local timezone and the start of the day.
func Align() PeriodOption {
return func(l *PeriodLimit) {
l.align = true

View File

@@ -5,8 +5,8 @@ import (
"github.com/alicebob/miniredis/v2"
"github.com/stretchr/testify/assert"
"github.com/zeromicro/go-zero/core/stores/redis"
"github.com/zeromicro/go-zero/core/stores/redis/redistest"
"github.com/tal-tech/go-zero/core/stores/redis"
"github.com/tal-tech/go-zero/core/stores/redis/redistest"
)
func TestPeriodLimit_Take(t *testing.T) {
@@ -23,9 +23,10 @@ func TestPeriodLimit_RedisUnavailable(t *testing.T) {
const (
seconds = 1
total = 100
quota = 5
)
l := NewPeriodLimit(seconds, quota, redis.New(s.Addr()), "periodlimit")
l := NewPeriodLimit(seconds, quota, redis.NewRedis(s.Addr(), redis.NodeType), "periodlimit")
s.Close()
val, err := l.Take("first")
assert.NotNil(t, err)
@@ -65,13 +66,3 @@ func testPeriodLimit(t *testing.T, opts ...PeriodOption) {
assert.Equal(t, 1, hitQuota)
assert.Equal(t, total-quota, overQuota)
}
func TestQuotaFull(t *testing.T) {
s, err := miniredis.Run()
assert.Nil(t, err)
l := NewPeriodLimit(1, 1, redis.New(s.Addr()), "periodlimit")
val, err := l.Take("first")
assert.Nil(t, err)
assert.Equal(t, HitQuota, val)
}

View File

@@ -1,16 +1,14 @@
package limit
import (
"context"
"errors"
"fmt"
"strconv"
"sync"
"sync/atomic"
"time"
"github.com/zeromicro/go-zero/core/logx"
"github.com/zeromicro/go-zero/core/stores/redis"
"github.com/tal-tech/go-zero/core/logx"
"github.com/tal-tech/go-zero/core/stores/redis"
xrate "golang.org/x/time/rate"
)
@@ -60,8 +58,8 @@ type TokenLimiter struct {
timestampKey string
rescueLock sync.Mutex
redisAlive uint32
monitorStarted bool
rescueLimiter *xrate.Limiter
monitorStarted bool
}
// NewTokenLimiter returns a new TokenLimiter that allows events up to rate and permits
@@ -86,31 +84,19 @@ func (lim *TokenLimiter) Allow() bool {
return lim.AllowN(time.Now(), 1)
}
// AllowCtx is shorthand for AllowNCtx(ctx,time.Now(), 1) with incoming context.
func (lim *TokenLimiter) AllowCtx(ctx context.Context) bool {
return lim.AllowNCtx(ctx, time.Now(), 1)
}
// AllowN reports whether n events may happen at time now.
// Use this method if you intend to drop / skip events that exceed the rate.
// Otherwise, use Reserve or Wait.
// Use this method if you intend to drop / skip events that exceed the rate rate.
// Otherwise use Reserve or Wait.
func (lim *TokenLimiter) AllowN(now time.Time, n int) bool {
return lim.reserveN(context.Background(), now, n)
return lim.reserveN(now, n)
}
// AllowNCtx reports whether n events may happen at time now with incoming context.
// Use this method if you intend to drop / skip events that exceed the rate.
// Otherwise, use Reserve or Wait.
func (lim *TokenLimiter) AllowNCtx(ctx context.Context, now time.Time, n int) bool {
return lim.reserveN(ctx, now, n)
}
func (lim *TokenLimiter) reserveN(ctx context.Context, now time.Time, n int) bool {
func (lim *TokenLimiter) reserveN(now time.Time, n int) bool {
if atomic.LoadUint32(&lim.redisAlive) == 0 {
return lim.rescueLimiter.AllowN(now, n)
}
resp, err := lim.store.EvalCtx(ctx,
resp, err := lim.store.Eval(
script,
[]string{
lim.tokenKey,
@@ -126,12 +112,7 @@ func (lim *TokenLimiter) reserveN(ctx context.Context, now time.Time, n int) boo
// Lua boolean false -> r Nil bulk reply
if err == redis.Nil {
return false
}
if errors.Is(err, context.DeadlineExceeded) || errors.Is(err, context.Canceled) {
logx.Errorf("fail to use rate limiter: %s", err)
return false
}
if err != nil {
} else if err != nil {
logx.Errorf("fail to use rate limiter: %s, use in-process limiter for rescue", err)
lim.startMonitor()
return lim.rescueLimiter.AllowN(now, n)

View File

@@ -1,45 +1,20 @@
package limit
import (
"context"
"testing"
"time"
"github.com/alicebob/miniredis/v2"
"github.com/stretchr/testify/assert"
"github.com/zeromicro/go-zero/core/logx"
"github.com/zeromicro/go-zero/core/stores/redis"
"github.com/zeromicro/go-zero/core/stores/redis/redistest"
"github.com/tal-tech/go-zero/core/logx"
"github.com/tal-tech/go-zero/core/stores/redis"
"github.com/tal-tech/go-zero/core/stores/redis/redistest"
)
func init() {
logx.Disable()
}
func TestTokenLimit_WithCtx(t *testing.T) {
s, err := miniredis.Run()
assert.Nil(t, err)
const (
total = 100
rate = 5
burst = 10
)
l := NewTokenLimiter(rate, burst, redis.New(s.Addr()), "tokenlimit")
defer s.Close()
ctx, cancel := context.WithCancel(context.Background())
ok := l.AllowCtx(ctx)
assert.True(t, ok)
cancel()
for i := 0; i < total; i++ {
ok := l.AllowCtx(ctx)
assert.False(t, ok)
assert.False(t, l.monitorStarted)
}
}
func TestTokenLimit_Rescue(t *testing.T) {
s, err := miniredis.Run()
assert.Nil(t, err)

View File

@@ -7,17 +7,17 @@ import (
"sync/atomic"
"time"
"github.com/zeromicro/go-zero/core/collection"
"github.com/zeromicro/go-zero/core/logx"
"github.com/zeromicro/go-zero/core/stat"
"github.com/zeromicro/go-zero/core/syncx"
"github.com/zeromicro/go-zero/core/timex"
"github.com/tal-tech/go-zero/core/collection"
"github.com/tal-tech/go-zero/core/logx"
"github.com/tal-tech/go-zero/core/stat"
"github.com/tal-tech/go-zero/core/syncx"
"github.com/tal-tech/go-zero/core/timex"
)
const (
defaultBuckets = 50
defaultWindow = time.Second * 5
// using 1000m notation, 900m is like 90%, keep it as var for unit test
// using 1000m notation, 900m is like 80%, keep it as var for unit test
defaultCpuThreshold = 900
defaultMinRt = float64(time.Second / time.Millisecond)
// moving average hyperparameter beta for calculating requests on the fly
@@ -70,7 +70,7 @@ type (
flying int64
avgFlying float64
avgFlyingLock syncx.SpinLock
overloadTime *syncx.AtomicDuration
dropTime *syncx.AtomicDuration
droppedRecently *syncx.AtomicBool
passCounter *collection.RollingWindow
rtCounter *collection.RollingWindow
@@ -106,7 +106,7 @@ func NewAdaptiveShedder(opts ...ShedderOption) Shedder {
return &adaptiveShedder{
cpuThreshold: options.cpuThreshold,
windows: int64(time.Second / bucketDuration),
overloadTime: syncx.NewAtomicDuration(),
dropTime: syncx.NewAtomicDuration(),
droppedRecently: syncx.NewAtomicBool(),
passCounter: collection.NewRollingWindow(options.buckets, bucketDuration,
collection.IgnoreCurrentBucket()),
@@ -118,6 +118,7 @@ func NewAdaptiveShedder(opts ...ShedderOption) Shedder {
// Allow implements Shedder.Allow.
func (as *adaptiveShedder) Allow() (Promise, error) {
if as.shouldDrop() {
as.dropTime.Set(timex.Now())
as.droppedRecently.Set(true)
return nil, ErrServiceOverloaded
@@ -214,26 +215,21 @@ func (as *adaptiveShedder) stillHot() bool {
return false
}
overloadTime := as.overloadTime.Load()
if overloadTime == 0 {
dropTime := as.dropTime.Load()
if dropTime == 0 {
return false
}
if timex.Since(overloadTime) < coolOffDuration {
return true
hot := timex.Since(dropTime) < coolOffDuration
if !hot {
as.droppedRecently.Set(false)
}
as.droppedRecently.Set(false)
return false
return hot
}
func (as *adaptiveShedder) systemOverloaded() bool {
if !systemOverloadChecker(as.cpuThreshold) {
return false
}
as.overloadTime.Set(timex.Now())
return true
return systemOverloadChecker(as.cpuThreshold)
}
// WithBuckets customizes the Shedder with given number of buckets.

View File

@@ -8,12 +8,11 @@ import (
"time"
"github.com/stretchr/testify/assert"
"github.com/zeromicro/go-zero/core/collection"
"github.com/zeromicro/go-zero/core/logx"
"github.com/zeromicro/go-zero/core/mathx"
"github.com/zeromicro/go-zero/core/stat"
"github.com/zeromicro/go-zero/core/syncx"
"github.com/zeromicro/go-zero/core/timex"
"github.com/tal-tech/go-zero/core/collection"
"github.com/tal-tech/go-zero/core/logx"
"github.com/tal-tech/go-zero/core/mathx"
"github.com/tal-tech/go-zero/core/stat"
"github.com/tal-tech/go-zero/core/syncx"
)
const (
@@ -137,7 +136,7 @@ func TestAdaptiveShedderShouldDrop(t *testing.T) {
passCounter: passCounter,
rtCounter: rtCounter,
windows: buckets,
overloadTime: syncx.NewAtomicDuration(),
dropTime: syncx.NewAtomicDuration(),
droppedRecently: syncx.NewAtomicBool(),
}
// cpu >= 800, inflight < maxPass
@@ -191,15 +190,12 @@ func TestAdaptiveShedderStillHot(t *testing.T) {
passCounter: passCounter,
rtCounter: rtCounter,
windows: buckets,
overloadTime: syncx.NewAtomicDuration(),
dropTime: syncx.NewAtomicDuration(),
droppedRecently: syncx.ForAtomicBool(true),
}
assert.False(t, shedder.stillHot())
shedder.overloadTime.Set(-coolOffDuration * 2)
shedder.dropTime.Set(-coolOffDuration * 2)
assert.False(t, shedder.stillHot())
shedder.droppedRecently.Set(true)
shedder.overloadTime.Set(timex.Now())
assert.True(t, shedder.stillHot())
}
func BenchmarkAdaptiveShedder_Allow(b *testing.B) {

View File

@@ -3,7 +3,7 @@ package load
import (
"io"
"github.com/zeromicro/go-zero/core/syncx"
"github.com/tal-tech/go-zero/core/syncx"
)
// A ShedderGroup is a manager to manage key based shedders.

View File

@@ -4,8 +4,8 @@ import (
"sync/atomic"
"time"
"github.com/zeromicro/go-zero/core/logx"
"github.com/zeromicro/go-zero/core/stat"
"github.com/tal-tech/go-zero/core/logx"
"github.com/tal-tech/go-zero/core/stat"
)
type (

View File

@@ -1,122 +0,0 @@
package logc
import (
"context"
"fmt"
"github.com/zeromicro/go-zero/core/logx"
)
type (
LogConf = logx.LogConf
LogField = logx.LogField
)
// AddGlobalFields adds global fields.
func AddGlobalFields(fields ...LogField) {
logx.AddGlobalFields(fields...)
}
// Alert alerts v in alert level, and the message is written to error log.
func Alert(_ context.Context, v string) {
logx.Alert(v)
}
// Close closes the logging.
func Close() error {
return logx.Close()
}
// Error writes v into error log.
func Error(ctx context.Context, v ...interface{}) {
getLogger(ctx).Error(v...)
}
// Errorf writes v with format into error log.
func Errorf(ctx context.Context, format string, v ...interface{}) {
getLogger(ctx).Errorf(fmt.Errorf(format, v...).Error())
}
// Errorv writes v into error log with json content.
// No call stack attached, because not elegant to pack the messages.
func Errorv(ctx context.Context, v interface{}) {
getLogger(ctx).Errorv(v)
}
// Errorw writes msg along with fields into error log.
func Errorw(ctx context.Context, msg string, fields ...LogField) {
getLogger(ctx).Errorw(msg, fields...)
}
// Field returns a LogField for the given key and value.
func Field(key string, value interface{}) LogField {
return logx.Field(key, value)
}
// Info writes v into access log.
func Info(ctx context.Context, v ...interface{}) {
getLogger(ctx).Info(v...)
}
// Infof writes v with format into access log.
func Infof(ctx context.Context, format string, v ...interface{}) {
getLogger(ctx).Infof(format, v...)
}
// Infov writes v into access log with json content.
func Infov(ctx context.Context, v interface{}) {
getLogger(ctx).Infov(v)
}
// Infow writes msg along with fields into access log.
func Infow(ctx context.Context, msg string, fields ...LogField) {
getLogger(ctx).Infow(msg, fields...)
}
// Must checks if err is nil, otherwise logs the error and exits.
func Must(err error) {
logx.Must(err)
}
// MustSetup sets up logging with given config c. It exits on error.
func MustSetup(c logx.LogConf) {
logx.MustSetup(c)
}
// SetLevel sets the logging level. It can be used to suppress some logs.
func SetLevel(level uint32) {
logx.SetLevel(level)
}
// SetUp sets up the logx. If already set up, just return nil.
// we allow SetUp to be called multiple times, because for example
// we need to allow different service frameworks to initialize logx respectively.
// the same logic for SetUp
func SetUp(c LogConf) error {
return logx.SetUp(c)
}
// Slow writes v into slow log.
func Slow(ctx context.Context, v ...interface{}) {
getLogger(ctx).Slow(v...)
}
// Slowf writes v with format into slow log.
func Slowf(ctx context.Context, format string, v ...interface{}) {
getLogger(ctx).Slowf(format, v...)
}
// Slowv writes v into slow log with json content.
func Slowv(ctx context.Context, v interface{}) {
getLogger(ctx).Slowv(v)
}
// Sloww writes msg along with fields into slow log.
func Sloww(ctx context.Context, msg string, fields ...LogField) {
getLogger(ctx).Sloww(msg, fields...)
}
// getLogger returns the logx.Logger with the given ctx and correct caller.
func getLogger(ctx context.Context) logx.Logger {
return logx.WithContext(ctx).WithCallerSkip(1)
}

View File

@@ -1,218 +0,0 @@
package logc
import (
"bytes"
"context"
"encoding/json"
"fmt"
"runtime"
"strings"
"testing"
"github.com/stretchr/testify/assert"
"github.com/zeromicro/go-zero/core/logx"
)
func TestAddGlobalFields(t *testing.T) {
var buf bytes.Buffer
writer := logx.NewWriter(&buf)
old := logx.Reset()
logx.SetWriter(writer)
defer logx.SetWriter(old)
Info(context.Background(), "hello")
buf.Reset()
AddGlobalFields(Field("a", "1"), Field("b", "2"))
AddGlobalFields(Field("c", "3"))
Info(context.Background(), "world")
var m map[string]interface{}
assert.NoError(t, json.Unmarshal(buf.Bytes(), &m))
assert.Equal(t, "1", m["a"])
assert.Equal(t, "2", m["b"])
assert.Equal(t, "3", m["c"])
}
func TestAlert(t *testing.T) {
var buf strings.Builder
writer := logx.NewWriter(&buf)
old := logx.Reset()
logx.SetWriter(writer)
defer logx.SetWriter(old)
Alert(context.Background(), "foo")
assert.True(t, strings.Contains(buf.String(), "foo"), buf.String())
}
func TestError(t *testing.T) {
var buf strings.Builder
writer := logx.NewWriter(&buf)
old := logx.Reset()
logx.SetWriter(writer)
defer logx.SetWriter(old)
file, line := getFileLine()
Error(context.Background(), "foo")
assert.True(t, strings.Contains(buf.String(), fmt.Sprintf("%s:%d", file, line+1)))
}
func TestErrorf(t *testing.T) {
var buf strings.Builder
writer := logx.NewWriter(&buf)
old := logx.Reset()
logx.SetWriter(writer)
defer logx.SetWriter(old)
file, line := getFileLine()
Errorf(context.Background(), "foo %s", "bar")
assert.True(t, strings.Contains(buf.String(), fmt.Sprintf("%s:%d", file, line+1)))
}
func TestErrorv(t *testing.T) {
var buf strings.Builder
writer := logx.NewWriter(&buf)
old := logx.Reset()
logx.SetWriter(writer)
defer logx.SetWriter(old)
file, line := getFileLine()
Errorv(context.Background(), "foo")
assert.True(t, strings.Contains(buf.String(), fmt.Sprintf("%s:%d", file, line+1)))
}
func TestErrorw(t *testing.T) {
var buf strings.Builder
writer := logx.NewWriter(&buf)
old := logx.Reset()
logx.SetWriter(writer)
defer logx.SetWriter(old)
file, line := getFileLine()
Errorw(context.Background(), "foo", Field("a", "b"))
assert.True(t, strings.Contains(buf.String(), fmt.Sprintf("%s:%d", file, line+1)))
}
func TestInfo(t *testing.T) {
var buf strings.Builder
writer := logx.NewWriter(&buf)
old := logx.Reset()
logx.SetWriter(writer)
defer logx.SetWriter(old)
file, line := getFileLine()
Info(context.Background(), "foo")
assert.True(t, strings.Contains(buf.String(), fmt.Sprintf("%s:%d", file, line+1)))
}
func TestInfof(t *testing.T) {
var buf strings.Builder
writer := logx.NewWriter(&buf)
old := logx.Reset()
logx.SetWriter(writer)
defer logx.SetWriter(old)
file, line := getFileLine()
Infof(context.Background(), "foo %s", "bar")
assert.True(t, strings.Contains(buf.String(), fmt.Sprintf("%s:%d", file, line+1)))
}
func TestInfov(t *testing.T) {
var buf strings.Builder
writer := logx.NewWriter(&buf)
old := logx.Reset()
logx.SetWriter(writer)
defer logx.SetWriter(old)
file, line := getFileLine()
Infov(context.Background(), "foo")
assert.True(t, strings.Contains(buf.String(), fmt.Sprintf("%s:%d", file, line+1)))
}
func TestInfow(t *testing.T) {
var buf strings.Builder
writer := logx.NewWriter(&buf)
old := logx.Reset()
logx.SetWriter(writer)
defer logx.SetWriter(old)
file, line := getFileLine()
Infow(context.Background(), "foo", Field("a", "b"))
assert.True(t, strings.Contains(buf.String(), fmt.Sprintf("%s:%d", file, line+1)))
}
func TestMust(t *testing.T) {
assert.NotPanics(t, func() {
Must(nil)
})
assert.NotPanics(t, func() {
MustSetup(LogConf{})
})
}
func TestMisc(t *testing.T) {
SetLevel(logx.DebugLevel)
assert.NoError(t, SetUp(LogConf{}))
assert.NoError(t, Close())
}
func TestSlow(t *testing.T) {
var buf strings.Builder
writer := logx.NewWriter(&buf)
old := logx.Reset()
logx.SetWriter(writer)
defer logx.SetWriter(old)
file, line := getFileLine()
Slow(context.Background(), "foo")
assert.True(t, strings.Contains(buf.String(), fmt.Sprintf("%s:%d", file, line+1)), buf.String())
}
func TestSlowf(t *testing.T) {
var buf strings.Builder
writer := logx.NewWriter(&buf)
old := logx.Reset()
logx.SetWriter(writer)
defer logx.SetWriter(old)
file, line := getFileLine()
Slowf(context.Background(), "foo %s", "bar")
assert.True(t, strings.Contains(buf.String(), fmt.Sprintf("%s:%d", file, line+1)), buf.String())
}
func TestSlowv(t *testing.T) {
var buf strings.Builder
writer := logx.NewWriter(&buf)
old := logx.Reset()
logx.SetWriter(writer)
defer logx.SetWriter(old)
file, line := getFileLine()
Slowv(context.Background(), "foo")
assert.True(t, strings.Contains(buf.String(), fmt.Sprintf("%s:%d", file, line+1)), buf.String())
}
func TestSloww(t *testing.T) {
var buf strings.Builder
writer := logx.NewWriter(&buf)
old := logx.Reset()
logx.SetWriter(writer)
defer logx.SetWriter(old)
file, line := getFileLine()
Sloww(context.Background(), "foo", Field("a", "b"))
assert.True(t, strings.Contains(buf.String(), fmt.Sprintf("%s:%d", file, line+1)), buf.String())
}
func getFileLine() (string, int) {
_, file, line, _ := runtime.Caller(1)
short := file
for i := len(file) - 1; i > 0; i-- {
if file[i] == '/' {
short = file[i+1:]
break
}
}
return short, line
}

View File

@@ -1,26 +0,0 @@
package logx
import (
"sync/atomic"
"github.com/zeromicro/go-zero/core/color"
)
// WithColor is a helper function to add color to a string, only in plain encoding.
func WithColor(text string, colour color.Color) string {
if atomic.LoadUint32(&encoding) == plainEncodingType {
return color.WithColor(text, colour)
}
return text
}
// WithColorPadding is a helper function to add color to a string with leading and trailing spaces,
// only in plain encoding.
func WithColorPadding(text string, colour color.Color) string {
if atomic.LoadUint32(&encoding) == plainEncodingType {
return color.WithColorPadding(text, colour)
}
return text
}

View File

@@ -1,33 +0,0 @@
package logx
import (
"sync/atomic"
"testing"
"github.com/stretchr/testify/assert"
"github.com/zeromicro/go-zero/core/color"
)
func TestWithColor(t *testing.T) {
old := atomic.SwapUint32(&encoding, plainEncodingType)
defer atomic.StoreUint32(&encoding, old)
output := WithColor("hello", color.BgBlue)
assert.Equal(t, "hello", output)
atomic.StoreUint32(&encoding, jsonEncodingType)
output = WithColor("hello", color.BgBlue)
assert.Equal(t, "hello", output)
}
func TestWithColorPadding(t *testing.T) {
old := atomic.SwapUint32(&encoding, plainEncodingType)
defer atomic.StoreUint32(&encoding, old)
output := WithColorPadding("hello", color.BgBlue)
assert.Equal(t, " hello ", output)
atomic.StoreUint32(&encoding, jsonEncodingType)
output = WithColorPadding("hello", color.BgBlue)
assert.Equal(t, "hello", output)
}

View File

@@ -3,24 +3,11 @@ package logx
// A LogConf is a logging config.
type LogConf struct {
ServiceName string `json:",optional"`
Mode string `json:",default=console,options=[console,file,volume]"`
Encoding string `json:",default=json,options=[json,plain]"`
Mode string `json:",default=console,options=console|file|volume"`
TimeFormat string `json:",optional"`
Path string `json:",default=logs"`
Level string `json:",default=info,options=[debug,info,error,severe]"`
Level string `json:",default=info,options=info|error|severe"`
Compress bool `json:",optional"`
KeepDays int `json:",optional"`
StackCooldownMillis int `json:",default=100"`
// MaxBackups represents how many backup log files will be kept. 0 means all files will be kept forever.
// Only take effect when RotationRuleType is `size`.
// Even thougth `MaxBackups` sets 0, log files will still be removed
// if the `KeepDays` limitation is reached.
MaxBackups int `json:",default=0"`
// MaxSize represents how much space the writing log file takes up. 0 means no limit. The unit is `MB`.
// Only take effect when RotationRuleType is `size`
MaxSize int `json:",default=0"`
// RotationRuleType represents the type of log rotation rule. Default is `daily`.
// daily: daily rotation.
// size: size limited rotation.
Rotation string `json:",default=daily,options=[daily,size]"`
}

View File

@@ -0,0 +1,88 @@
package logx
import (
"fmt"
"io"
"time"
"github.com/tal-tech/go-zero/core/timex"
)
const durationCallerDepth = 3
type durationLogger logEntry
// WithDuration returns a Logger which logs the given duration.
func WithDuration(d time.Duration) Logger {
return &durationLogger{
Duration: timex.ReprOfDuration(d),
}
}
func (l *durationLogger) Error(v ...interface{}) {
if shallLog(ErrorLevel) {
l.write(errorLog, levelError, formatWithCaller(fmt.Sprint(v...), durationCallerDepth))
}
}
func (l *durationLogger) Errorf(format string, v ...interface{}) {
if shallLog(ErrorLevel) {
l.write(errorLog, levelError, formatWithCaller(fmt.Sprintf(format, v...), durationCallerDepth))
}
}
func (l *durationLogger) Errorv(v interface{}) {
if shallLog(ErrorLevel) {
l.write(errorLog, levelError, v)
}
}
func (l *durationLogger) Info(v ...interface{}) {
if shallLog(InfoLevel) {
l.write(infoLog, levelInfo, fmt.Sprint(v...))
}
}
func (l *durationLogger) Infof(format string, v ...interface{}) {
if shallLog(InfoLevel) {
l.write(infoLog, levelInfo, fmt.Sprintf(format, v...))
}
}
func (l *durationLogger) Infov(v interface{}) {
if shallLog(InfoLevel) {
l.write(infoLog, levelInfo, v)
}
}
func (l *durationLogger) Slow(v ...interface{}) {
if shallLog(ErrorLevel) {
l.write(slowLog, levelSlow, fmt.Sprint(v...))
}
}
func (l *durationLogger) Slowf(format string, v ...interface{}) {
if shallLog(ErrorLevel) {
l.write(slowLog, levelSlow, fmt.Sprintf(format, v...))
}
}
func (l *durationLogger) Slowv(v interface{}) {
if shallLog(ErrorLevel) {
l.write(slowLog, levelSlow, v)
}
}
func (l *durationLogger) WithDuration(duration time.Duration) Logger {
l.Duration = timex.ReprOfDuration(duration)
return l
}
func (l *durationLogger) write(writer io.Writer, level string, val interface{}) {
outputJson(writer, &durationLogger{
Timestamp: getTimestamp(),
Level: level,
Content: val,
Duration: l.Duration,
})
}

View File

@@ -0,0 +1,73 @@
package logx
import (
"log"
"strings"
"testing"
"time"
"github.com/stretchr/testify/assert"
)
func TestWithDurationError(t *testing.T) {
var builder strings.Builder
log.SetOutput(&builder)
WithDuration(time.Second).Error("foo")
assert.True(t, strings.Contains(builder.String(), "duration"), builder.String())
}
func TestWithDurationErrorf(t *testing.T) {
var builder strings.Builder
log.SetOutput(&builder)
WithDuration(time.Second).Errorf("foo")
assert.True(t, strings.Contains(builder.String(), "duration"), builder.String())
}
func TestWithDurationErrorv(t *testing.T) {
var builder strings.Builder
log.SetOutput(&builder)
WithDuration(time.Second).Errorv("foo")
assert.True(t, strings.Contains(builder.String(), "duration"), builder.String())
}
func TestWithDurationInfo(t *testing.T) {
var builder strings.Builder
log.SetOutput(&builder)
WithDuration(time.Second).Info("foo")
assert.True(t, strings.Contains(builder.String(), "duration"), builder.String())
}
func TestWithDurationInfof(t *testing.T) {
var builder strings.Builder
log.SetOutput(&builder)
WithDuration(time.Second).Infof("foo")
assert.True(t, strings.Contains(builder.String(), "duration"), builder.String())
}
func TestWithDurationInfov(t *testing.T) {
var builder strings.Builder
log.SetOutput(&builder)
WithDuration(time.Second).Infov("foo")
assert.True(t, strings.Contains(builder.String(), "duration"), builder.String())
}
func TestWithDurationSlow(t *testing.T) {
var builder strings.Builder
log.SetOutput(&builder)
WithDuration(time.Second).Slow("foo")
assert.True(t, strings.Contains(builder.String(), "duration"), builder.String())
}
func TestWithDurationSlowf(t *testing.T) {
var builder strings.Builder
log.SetOutput(&builder)
WithDuration(time.Second).WithDuration(time.Hour).Slowf("foo")
assert.True(t, strings.Contains(builder.String(), "duration"), builder.String())
}
func TestWithDurationSlowv(t *testing.T) {
var builder strings.Builder
log.SetOutput(&builder)
WithDuration(time.Second).WithDuration(time.Hour).Slowv("foo")
assert.True(t, strings.Contains(builder.String(), "duration"), builder.String())
}

View File

@@ -1,45 +0,0 @@
package logx
import (
"context"
"sync"
"sync/atomic"
)
var (
fieldsContextKey contextKey
globalFields atomic.Value
globalFieldsLock sync.Mutex
)
type contextKey struct{}
// AddGlobalFields adds global fields.
func AddGlobalFields(fields ...LogField) {
globalFieldsLock.Lock()
defer globalFieldsLock.Unlock()
old := globalFields.Load()
if old == nil {
globalFields.Store(append([]LogField(nil), fields...))
} else {
globalFields.Store(append(old.([]LogField), fields...))
}
}
// ContextWithFields returns a new context with the given fields.
func ContextWithFields(ctx context.Context, fields ...LogField) context.Context {
if val := ctx.Value(fieldsContextKey); val != nil {
if arr, ok := val.([]LogField); ok {
return context.WithValue(ctx, fieldsContextKey, append(arr, fields...))
}
}
return context.WithValue(ctx, fieldsContextKey, fields)
}
// WithFields returns a new logger with the given fields.
// deprecated: use ContextWithFields instead.
func WithFields(ctx context.Context, fields ...LogField) context.Context {
return ContextWithFields(ctx, fields...)
}

View File

@@ -1,104 +0,0 @@
package logx
import (
"bytes"
"context"
"encoding/json"
"sync"
"sync/atomic"
"testing"
"github.com/stretchr/testify/assert"
)
func TestAddGlobalFields(t *testing.T) {
var buf bytes.Buffer
writer := NewWriter(&buf)
old := Reset()
SetWriter(writer)
defer SetWriter(old)
Info("hello")
buf.Reset()
AddGlobalFields(Field("a", "1"), Field("b", "2"))
AddGlobalFields(Field("c", "3"))
Info("world")
var m map[string]interface{}
assert.NoError(t, json.Unmarshal(buf.Bytes(), &m))
assert.Equal(t, "1", m["a"])
assert.Equal(t, "2", m["b"])
assert.Equal(t, "3", m["c"])
}
func TestContextWithFields(t *testing.T) {
ctx := ContextWithFields(context.Background(), Field("a", 1), Field("b", 2))
vals := ctx.Value(fieldsContextKey)
assert.NotNil(t, vals)
fields, ok := vals.([]LogField)
assert.True(t, ok)
assert.EqualValues(t, []LogField{Field("a", 1), Field("b", 2)}, fields)
}
func TestWithFields(t *testing.T) {
ctx := WithFields(context.Background(), Field("a", 1), Field("b", 2))
vals := ctx.Value(fieldsContextKey)
assert.NotNil(t, vals)
fields, ok := vals.([]LogField)
assert.True(t, ok)
assert.EqualValues(t, []LogField{Field("a", 1), Field("b", 2)}, fields)
}
func TestWithFieldsAppend(t *testing.T) {
var dummyKey struct{}
ctx := context.WithValue(context.Background(), dummyKey, "dummy")
ctx = ContextWithFields(ctx, Field("a", 1), Field("b", 2))
ctx = ContextWithFields(ctx, Field("c", 3), Field("d", 4))
vals := ctx.Value(fieldsContextKey)
assert.NotNil(t, vals)
fields, ok := vals.([]LogField)
assert.True(t, ok)
assert.Equal(t, "dummy", ctx.Value(dummyKey))
assert.EqualValues(t, []LogField{
Field("a", 1),
Field("b", 2),
Field("c", 3),
Field("d", 4),
}, fields)
}
func BenchmarkAtomicValue(b *testing.B) {
b.ReportAllocs()
var container atomic.Value
vals := []LogField{
Field("a", "b"),
Field("c", "d"),
Field("e", "f"),
}
container.Store(&vals)
for i := 0; i < b.N; i++ {
val := container.Load()
if val != nil {
_ = *val.(*[]LogField)
}
}
}
func BenchmarkRWMutex(b *testing.B) {
b.ReportAllocs()
var lock sync.RWMutex
vals := []LogField{
Field("a", "b"),
Field("c", "d"),
Field("e", "f"),
}
for i := 0; i < b.N; i++ {
lock.RLock()
_ = vals
lock.RUnlock()
}
}

View File

@@ -1,6 +1,7 @@
package logx
import (
"log"
"strings"
"testing"
@@ -8,27 +9,23 @@ import (
)
func TestLessLogger_Error(t *testing.T) {
w := new(mockWriter)
old := writer.Swap(w)
defer writer.Store(old)
var builder strings.Builder
log.SetOutput(&builder)
l := NewLessLogger(500)
for i := 0; i < 100; i++ {
l.Error("hello")
}
assert.Equal(t, 1, strings.Count(w.String(), "\n"))
assert.Equal(t, 1, strings.Count(builder.String(), "\n"))
}
func TestLessLogger_Errorf(t *testing.T) {
w := new(mockWriter)
old := writer.Swap(w)
defer writer.Store(old)
var builder strings.Builder
log.SetOutput(&builder)
l := NewLessLogger(500)
for i := 0; i < 100; i++ {
l.Errorf("hello")
}
assert.Equal(t, 1, strings.Count(w.String(), "\n"))
assert.Equal(t, 1, strings.Count(builder.String(), "\n"))
}

View File

@@ -4,8 +4,8 @@ import (
"sync/atomic"
"time"
"github.com/zeromicro/go-zero/core/syncx"
"github.com/zeromicro/go-zero/core/timex"
"github.com/tal-tech/go-zero/core/syncx"
"github.com/tal-tech/go-zero/core/timex"
)
type limitedExecutor struct {

View File

@@ -6,7 +6,7 @@ import (
"time"
"github.com/stretchr/testify/assert"
"github.com/zeromicro/go-zero/core/timex"
"github.com/tal-tech/go-zero/core/timex"
)
func TestLimitedExecutor_logOrDiscard(t *testing.T) {

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