Compare commits

..

100 Commits

Author SHA1 Message Date
Kevin Wan
2bd95aa007 update goctl version to 1.2.1 (#1042) 2021-09-14 08:32:56 +08:00
Kevin Wan
e8376936d5 remove goctl config command (#1035) 2021-09-13 14:04:06 +08:00
Kevin Wan
71c0288023 fix symlink issue on windows for goctl (#1034)
* fix symlink issue on windows for goctl

* move readlink into separate file
2021-09-13 11:49:07 +08:00
Kevin Wan
9e2f07a842 update k8s.io/client-go etc to use go 1.15 (#1031) 2021-09-13 10:45:34 +08:00
Kevin Wan
24fd34413f fix golint issues (#1027) 2021-09-12 16:15:42 +08:00
Kevin Wan
3f47251892 fix proc.Done not found in windows (#1026) 2021-09-12 15:41:33 +08:00
Kevin Wan
0b6bc69afa reorg imports, format code (#1024) 2021-09-11 21:28:47 +08:00
anqiansong
5b9bdc8d02 Merge pull request #1023 from anqiansong/1014-rollback
revert changes
2021-09-11 20:58:42 +08:00
anqiansong
ded22e296e revert changes 2021-09-11 20:57:58 +08:00
anqiansong
f0ed2370a3 fix #1014 (#1018)
* fix #1014

* remove unused code

* * optimize generate pb.go on Windows
* format code
* optimize console.go

* version rollback

Co-authored-by: anqiansong <anqiansong@bytedance.com>
2021-09-11 12:48:32 +08:00
Kevin Wan
6bf6cfdd01 add go-zero users (#1022) 2021-09-10 22:03:24 +08:00
Kevin Wan
5cc9eb0de4 rename sharedcalls to singleflight (#1017) 2021-09-09 18:06:27 +08:00
Kevin Wan
f070d447ef refactor for better error reporting on sql error (#1016)
* refactor for better error reporting on sql error

* fix errors

* add docs
2021-09-09 15:43:33 +08:00
Kevin Wan
f6d9e19ecb expose sql.DB to let orm operate on it (#1015)
* expose sql.DB to let orm operate on it

* add missing RawDB methods

* add NewSqlConnFromDB for cooperate with dtm
2021-09-09 11:40:28 +08:00
Kevin Wan
56807aabf6 fix golint issues, update codecov settings. (#1011)
* update codecov settings

* fix golint issues
2021-09-07 22:33:02 +08:00
Kevin Wan
861dcf2f36 update codecov settings (#1010) 2021-09-07 18:09:53 +08:00
Kevin Wan
c837dc21bb refactoring tracing interceptors. (#1009)
* refactor tracing interceptors

* add stream tracing interceptor
2021-09-07 17:58:22 +08:00
Kevin Wan
96a35ecf1a fix #1006 (#1008)
* use sdktrace instead of trace for opentelemetry to avoid conflicts

* disable opentelemetry for right now

* use os.ModeSymlink instead of fs.ModeSymlink for backward compatibility
2021-09-07 15:38:40 +08:00
Kevin Wan
bdec5f2349 use sdktrace instead of trace for opentelemetry to avoid conflicts (#1005)
* use sdktrace instead of trace for opentelemetry to avoid conflicts

* disable opentelemetry for right now
2021-09-07 12:02:41 +08:00
shenbaise9527
bc92b57bdb api文件中使用group时生成的handler和logic的包名应该为group的名字 (#545)
* api文件中使用group时生成的handler和logic的包名应该为group的名字

* Update genhandlers.go

fix errors.

Co-authored-by: Kevin Wan <wanjunfeng@gmail.com>
2021-09-07 11:03:04 +08:00
neosu
d8905b9e9e add api template file (#1003) 2021-09-07 10:16:10 +08:00
neosu
dec6309c55 add opentelemetry test (#1002) 2021-09-07 09:26:45 +08:00
Kevin Wan
10805577f5 reorg imports, format code (#1000) 2021-09-06 14:56:46 +08:00
SunJun
a4d8286e36 开启otel后,tracelog自动获取otle的traceId和spanId (#946)
* 开启otel后,tracelog自动获取otle的traceId和spanId

* 去除opentelemetry判断

* 通过 IsRecording 判断span是否活跃
2021-09-06 14:31:54 +08:00
anqiansong
84d2b64e7c optimize unit test (#999) 2021-09-06 14:20:21 +08:00
Kevin Wan
6476da4a18 rest log with context (#998) 2021-09-05 22:58:42 +08:00
Kevin Wan
79eab0ea2f refactor to shorter config name (#997) 2021-09-05 22:43:15 +08:00
Allen Liu
3b683fd498 feat: change logger to traceLogger for getting traceId when recovering (#374) 2021-09-05 22:40:10 +08:00
toven tang
d179b342b2 修复使用 postgres 数据库时,位置参数重复,导致参数与值不对应的问题。 (#960)
* 修复使用 postgres 数据库时,位置参数重复,导致参数与值不对应的问题。

* 修复使用 postgres 数据库时,位置参数重复,导致参数与值不对应的问题。

Co-authored-by: toven <toven@advan.onaliyun.com>
2021-09-05 22:27:59 +08:00
Kevin Wan
58874779e7 move opentelemetry into trace package, and refactoring (#996)
* move opentelemetry into trace package, and refactoring

* rename rewritten package names
2021-09-05 22:18:35 +08:00
anqiansong
8829c31c0d Feature goctl error wrap (#995)
* Add `Wrap` in file errorx.go

* Wrap error with `GoctlError`

* format code

* Refactor package `env` to `version`

* Refactor package `IsVersionGatherThan`

* fix typo

Co-authored-by: anqiansong <anqiansong@bytedance.com>
2021-09-05 21:57:44 +08:00
Kevin Wan
b42f3fa047 disable codecov github checks (#993) 2021-09-04 13:32:23 +08:00
Kevin Wan
9bdadf2381 fix golint issues (#992) 2021-09-04 12:16:30 +08:00
Kevin Wan
20f665ede8 implement k8s service discovery (#988)
* implement k8s service discovery

* simplify code

* use default namespace if not provided

* disable codecov bot comment

* ignore adhoc dir

* simplify building target in NewClient

* reformat code

* Fix filepath (#990)

* format code, and reorg imports (#991)

* add more unit test

Co-authored-by: anqiansong <anqiansong@gmail.com>
2021-09-04 10:27:08 +08:00
Kevin Wan
0325d8e92d format code, and reorg imports (#991) 2021-09-04 10:08:49 +08:00
anqiansong
2125977281 Fix filepath (#990) 2021-09-04 08:15:22 +08:00
Vee Zhang
c26c187e11 remote handler blank line when .HasRequest is false (#986) 2021-09-03 07:25:04 +08:00
Kevin Wan
4ef1859f0b use codecov action v1 (#985) 2021-09-02 19:07:30 +08:00
Kevin Wan
407a6cbf9c format coding style (#983) 2021-09-01 19:52:56 +08:00
Vee Zhang
76fc1ef460 httpx.Error response without body (#982)
* httpx.Error support response without body

* fix doc
2021-09-01 19:33:33 +08:00
miaogaolin
423955c55f format code (#979) 2021-08-31 17:15:36 +08:00
Kevin Wan
db95b3f0e3 configurable for load and stat statistics logs (#980) 2021-08-31 17:14:31 +08:00
Kevin Wan
4bee60eb7f add go-zero users (#978) 2021-08-31 16:08:33 +08:00
Kevin Wan
7618139dad refactor (#977) 2021-08-31 12:04:09 +08:00
Kevin Wan
6fd08027ff update go version to 1.14 for github workflow (#976) 2021-08-31 11:46:22 +08:00
chenquan
b9e268aae8 Update Codecov action (#974) 2021-08-31 11:25:58 +08:00
Kevin Wan
4c1bb1148b fix #971 (#972) 2021-08-29 11:38:34 +08:00
Kevin Wan
50a6bbe6b9 format coding style (#970) 2021-08-28 12:11:11 +08:00
chenquan
dfb3cb510a Fix context error in grpc (#962)
* Fix context error in rpc

* Add a test case

* Optimize judgment conditions

* Add customized breaker errors for the client and server

* Update method signature

* Delete customized breaker errors

* Delete the wrong test case
2021-08-28 12:07:14 +08:00
Kevin Wan
519db812b4 format coding style (#969) 2021-08-27 23:09:47 +08:00
anqiansong
3203f8e06b Fix issues (#965) 2021-08-27 15:05:54 +08:00
chenquan
b71ac2042a Add a test case for database code generation tool (#961) 2021-08-27 06:50:09 +08:00
Kevin Wan
d0f9e57022 fix #957 (#959) 2021-08-26 16:47:28 +08:00
SunJun
aa68210cde 修复stream拦截器tracer名问题 (#944) 2021-08-24 15:17:53 +08:00
zhoushuguang
280e837c9e rest otel support (#943) 2021-08-24 10:04:12 +08:00
Kevin Wan
f669e1226c fix #556 (#938) 2021-08-22 23:36:35 +08:00
Kevin Wan
cd15c19250 fix lint errors (#937) 2021-08-22 10:24:32 +08:00
neosu
5b35fa17de add the opentelemetry tracing (#908)
* add the opentelemetry tracing

* fix the error sampler config

* 添加stream的链路跟踪

* fix the error field name
2021-08-22 10:03:56 +08:00
Kevin Wan
9672298fa8 make sure setting code happen before callback in rest (#936) 2021-08-22 09:27:20 +08:00
Kevin Wan
bf3ce16823 fix #820 (#934) 2021-08-19 22:48:21 +08:00
anqiansong
189721da16 Fix issues (#931)
* fix #929

* fix #925

* add test case

* update model README

* fix #929

* fix #929

* fix #929

* refactor dir

* Adding todo comments

Co-authored-by: anqiansong <anqiansong@xiaoheiban.cn>
2021-08-19 22:47:45 +08:00
Kevin Wan
a523ab1f93 update slack invite url (#933) 2021-08-19 22:25:41 +08:00
Kevin Wan
7ea8b636d9 add go-zero users (#928) 2021-08-19 10:39:47 +08:00
anqiansong
b2fea65faa Optimize model naming (#910)
* add unit test

* fix #907

* format code

* format code

* format code

Co-authored-by: anqiansong <anqiansong@xiaoheiban.cn>
2021-08-18 17:09:34 +08:00
anqiansong
a1fe8bf6cd fix missing updateMethodTemplateFile (#924) 2021-08-18 12:23:43 +08:00
Kevin Wan
67ee9e4391 add unit test (#921) 2021-08-17 17:09:26 +08:00
Kevin Wan
9c1ee50497 refactor (#920) 2021-08-17 10:24:12 +08:00
chenquan
7c842f22d0 Add traceId to the response headers (#919)
* Add traceId to the request headers

* Add test cases

* Update refactor code
2021-08-17 10:12:08 +08:00
anqiansong
14ec29991c fix #915 (#917) 2021-08-16 15:07:11 +08:00
Kevin Wan
c7f5aad83a add stringx.FirstN with ellipsis (#916) 2021-08-16 12:08:33 +08:00
lucaq
e77747cff8 redis.go,type StringCmd = red.StringCmd (#790)
* Add Sinter,Sinterstore; Modify TestRedis_Set

* type StringCmd

* redis.go,type StringCmd = red.StringCmd

Co-authored-by: lucq <lucq@toopsoon.com>
2021-08-16 09:52:16 +08:00
Kevin Wan
f2612db4b1 add stringx.FirstN (#914) 2021-08-15 23:02:48 +08:00
Kevin Wan
a21ff71373 fix #889 (#912) 2021-08-15 15:33:45 +08:00
Kevin Wan
fc04ad7854 export pathvar for user-defined routers (#911)
* refactor

* export pathvar for user-defined routers
2021-08-14 22:57:28 +08:00
Kevin Wan
fbf2eebc42 add Errorv/Infov/Slowv (#909) 2021-08-13 18:28:39 +08:00
anqiansong
dc43430812 optimize grpc generation env check (#900)
* optimize grpc generation env check

* optimize grpc generation env check

* format code

* fix postgresql data type convert error

Co-authored-by: anqiansong <anqiansong@xiaoheiban.cn>
2021-08-13 11:47:42 +08:00
Kevin Wan
c6642bc2e6 add workflow for closing inactive issues (#906)
* add workflow for closing inactive issues

* add workflow for closing inactive issues, add newline
2021-08-12 15:28:29 +08:00
Phibe
bdca24dd3b Update readme for better description. (#904) 2021-08-12 14:59:17 +08:00
Kevin Wan
00c5734021 format coding style (#905) 2021-08-12 14:58:37 +08:00
lovelly
33f87cf1f0 带下划线的项目,配置文件名字错误。 (#733) 2021-08-12 14:55:39 +08:00
Kevin Wan
69935c1ba3 refactor goctl, fix golint issues (#903) 2021-08-11 18:08:01 +08:00
Kevin Wan
1fb356f328 refactor goctl (#902) 2021-08-11 18:04:42 +08:00
市民233
0b0406f41a fix: 解决golint 部分警告 (#897)
* feat:  解决goreportcard的警报
ps: warning: if block ends with a return statement, so drop this else and outdent its block (golint)

* feat: 优化golint警告,将processFieldPrimitiveWithJsonNumber 改成 processFieldPrimitiveWithJSONNumber
unmarshaler.go:248:23: method processFieldPrimitiveWithJsonNumber should be processFieldPrimitiveWithJSONNumber

* feat: 添加 WithCanonicalKeyFunc 注释

* feat: 添加DisableStat的注释

* feat: 添加 RegisterGoctlHome 注释

* feat: 添加 PostgreSqlJoin 注释

* feat: 解决goline警告should not use basic type string as key in context.WithValue问题

* feat: 解决golint警告信息: should not use basic type string as key in context.WithValue

* fix: 定义自定义字段类型,导致go test fail 问题

* update: 恢复原有测试用例

* fix golint warning
2021-08-11 17:57:20 +08:00
_ksco
cc264dcf55 refactor (#878)
* refactor(tools ): refactor cod

Improve code readability and performance

* fix(tools ): fix len bug

Co-authored-by: ksco <hyang@33.cn>
2021-08-11 17:33:18 +08:00
Kevin Wan
e024aebb66 fix golint issues (#899) 2021-08-11 11:38:55 +08:00
Phibe
f204729482 remove unnecessary chars. (#898) 2021-08-11 10:51:28 +08:00
Phibe
d20cf56a69 simplify type definition in readme (#896)
* better text rendering

* simplify type definition in readme
2021-08-10 18:02:11 +08:00
Kevin Wan
54d57c7d4b refactor rest code (#895) 2021-08-10 17:59:33 +08:00
voidint
28a7c9d38f fix http header binding failure bug #885 (#887) 2021-08-10 17:38:03 +08:00
Kevin Wan
872e75e10d add logx.DisableStat() to disable stat logs (#893)
* add logx.DisableStat() to disable stat logs

* refactor logx code
2021-08-10 16:55:38 +08:00
Phibe
af1730079e better text rendering (#892) 2021-08-10 15:13:09 +08:00
Kevin Wan
04521e2d24 format code (#888) 2021-08-09 23:03:08 +08:00
Kevin Wan
02adcccbf4 format code (#884) 2021-08-09 18:11:08 +08:00
anqiansong
a74aaf1823 optimize mongo generation without cache (fix #881) (#882)
* fix #881

* fix #881

Co-authored-by: anqiansong <anqiansong@xiaoheiban.cn>
2021-08-09 11:33:01 +08:00
Kevin Wan
1eb2089c69 add go-zero users (#883) 2021-08-09 08:37:43 +08:00
Kevin Wan
f7f3730e1a update goctl version to 1.1.10 (#874) 2021-08-04 19:29:40 +08:00
Kevin Wan
0ee7654407 fix #792 (#873) 2021-08-04 18:45:05 +08:00
neosu
16cc990fdd fix context missing (#872)
Co-authored-by: suzhenpeng <suzhenpeng@ecoplants.tech>
2021-08-04 17:46:51 +08:00
neosu
00061c2e5b add goctl rpc template home flag (#871)
Co-authored-by: suzhenpeng <suzhenpeng@ecoplants.tech>
2021-08-04 15:54:43 +08:00
Kevin Wan
6793f7a1de fix bug that proc.SetTimeToForceQuit not working in windows (#869) 2021-08-04 11:31:33 +08:00
177 changed files with 4834 additions and 1104 deletions

View File

@@ -1,4 +1,3 @@
comment: false
ignore: ignore:
- "doc" - "tools"
- "example"
- "tools"

View File

@@ -15,7 +15,7 @@ jobs:
- name: Set up Go 1.x - name: Set up Go 1.x
uses: actions/setup-go@v2 uses: actions/setup-go@v2
with: with:
go-version: ^1.13 go-version: ^1.14
id: go id: go
- name: Check out code into the Go module directory - name: Check out code into the Go module directory
@@ -29,6 +29,4 @@ jobs:
run: go test -race -coverprofile=coverage.txt -covermode=atomic ./... run: go test -race -coverprofile=coverage.txt -covermode=atomic ./...
- name: Codecov - name: Codecov
uses: codecov/codecov-action@v1.0.6 uses: codecov/codecov-action@v2
with:
token: ${{secrets.CODECOV_TOKEN}}

19
.github/workflows/issues.yml vendored Normal file
View File

@@ -0,0 +1,19 @@
name: Close inactive issues
on:
schedule:
- cron: "30 1 * * *"
jobs:
close-issues:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v3
with:
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."
days-before-pr-stale: -1
days-before-pr-close: -1
repo-token: ${{ secrets.GITHUB_TOKEN }}

4
.gitignore vendored
View File

@@ -10,10 +10,14 @@
!*/ !*/
!api !api
# ignore
.idea .idea
**/.DS_Store **/.DS_Store
**/logs **/logs
# ignore adhoc test code
**/adhoc
# gitlab ci # gitlab ci
.cache .cache

View File

@@ -90,7 +90,7 @@ After that, run these local verifications before submitting pull request to pred
fail of continuous integration. fail of continuous integration.
* Format the code with `gofmt` * Format the code with `gofmt`
* Run the test with data race enabled `go test -race ./` * Run the test with data race enabled `go test -race ./...`
## Code Review ## Code Review

View File

@@ -34,7 +34,7 @@ type (
expire time.Duration expire time.Duration
timingWheel *TimingWheel timingWheel *TimingWheel
lruCache lru lruCache lru
barrier syncx.SharedCalls barrier syncx.SingleFlight
unstableExpiry mathx.Unstable unstableExpiry mathx.Unstable
stats *cacheStat stats *cacheStat
} }
@@ -46,7 +46,7 @@ func NewCache(expire time.Duration, opts ...CacheOption) (*Cache, error) {
data: make(map[string]interface{}), data: make(map[string]interface{}),
expire: expire, expire: expire,
lruCache: emptyLruCache, lruCache: emptyLruCache,
barrier: syncx.NewSharedCalls(), barrier: syncx.NewSingleFlight(),
unstableExpiry: mathx.NewUnstable(expiryDeviation), unstableExpiry: mathx.NewUnstable(expiryDeviation),
} }

View File

@@ -47,9 +47,11 @@ func TestUnmarshalContextWithMissing(t *testing.T) {
Name string `ctx:"name"` Name string `ctx:"name"`
Age int `ctx:"age"` Age int `ctx:"age"`
} }
type name string
const PersonNameKey name = "name"
ctx := context.Background() ctx := context.Background()
ctx = context.WithValue(ctx, "name", "kevin") ctx = context.WithValue(ctx, PersonNameKey, "kevin")
var person Person var person Person
err := For(ctx, &person) err := For(ctx, &person)

View File

@@ -9,7 +9,9 @@ import (
) )
func TestContextCancel(t *testing.T) { func TestContextCancel(t *testing.T) {
c := context.WithValue(context.Background(), "key", "value") type key string
var nameKey key = "name"
c := context.WithValue(context.Background(), nameKey, "value")
c1, cancel := context.WithCancel(c) c1, cancel := context.WithCancel(c)
o := ValueOnlyFrom(c1) o := ValueOnlyFrom(c1)
c2, cancel2 := context.WithCancel(o) c2, cancel2 := context.WithCancel(o)

View File

@@ -1,3 +1,4 @@
//go:build windows
// +build windows // +build windows
package fs package fs

View File

@@ -2,6 +2,9 @@ package fx
import ( import (
"context" "context"
"fmt"
"runtime/debug"
"strings"
"time" "time"
) )
@@ -30,7 +33,8 @@ func DoWithTimeout(fn func() error, timeout time.Duration, opts ...DoOption) err
go func() { go func() {
defer func() { defer func() {
if p := recover(); p != nil { if p := recover(); p != nil {
panicChan <- p // attach call stack to avoid missing in different goroutine
panicChan <- fmt.Sprintf("%+v\n\n%s", p, strings.TrimSpace(string(debug.Stack())))
} }
}() }()
done <- fn() done <- fn()

View File

@@ -31,6 +31,8 @@ var (
// default to be enabled // default to be enabled
enabled = syncx.ForAtomicBool(true) enabled = syncx.ForAtomicBool(true)
// default to be enabled
logEnabled = syncx.ForAtomicBool(true)
// make it a variable for unit test // make it a variable for unit test
systemOverloadChecker = func(cpuThreshold int64) bool { systemOverloadChecker = func(cpuThreshold int64) bool {
return stat.CpuUsage() >= cpuThreshold return stat.CpuUsage() >= cpuThreshold
@@ -80,6 +82,11 @@ func Disable() {
enabled.Set(false) enabled.Set(false)
} }
// DisableLog disables the stat logs for load shedding.
func DisableLog() {
logEnabled.Set(false)
}
// NewAdaptiveShedder returns an adaptive shedder. // NewAdaptiveShedder returns an adaptive shedder.
// opts can be used to customize the Shedder. // opts can be used to customize the Shedder.
func NewAdaptiveShedder(opts ...ShedderOption) Shedder { func NewAdaptiveShedder(opts ...ShedderOption) Shedder {

View File

@@ -25,6 +25,7 @@ func init() {
} }
func TestAdaptiveShedder(t *testing.T) { func TestAdaptiveShedder(t *testing.T) {
DisableLog()
shedder := NewAdaptiveShedder(WithWindow(bucketDuration), WithBuckets(buckets), WithCpuThreshold(100)) shedder := NewAdaptiveShedder(WithWindow(bucketDuration), WithBuckets(buckets), WithCpuThreshold(100))
var wg sync.WaitGroup var wg sync.WaitGroup
var drop int64 var drop int64

View File

@@ -48,6 +48,25 @@ func (s *SheddingStat) IncrementDrop() {
atomic.AddInt64(&s.drop, 1) atomic.AddInt64(&s.drop, 1)
} }
func (s *SheddingStat) loop(c <-chan time.Time) {
for range c {
st := s.reset()
if !logEnabled.True() {
continue
}
c := stat.CpuUsage()
if st.Drop == 0 {
logx.Statf("(%s) shedding_stat [1m], cpu: %d, total: %d, pass: %d, drop: %d",
s.name, c, st.Total, st.Pass, st.Drop)
} else {
logx.Statf("(%s) shedding_stat_drop [1m], cpu: %d, total: %d, pass: %d, drop: %d",
s.name, c, st.Total, st.Pass, st.Drop)
}
}
}
func (s *SheddingStat) reset() snapshot { func (s *SheddingStat) reset() snapshot {
return snapshot{ return snapshot{
Total: atomic.SwapInt64(&s.total, 0), Total: atomic.SwapInt64(&s.total, 0),
@@ -59,15 +78,6 @@ func (s *SheddingStat) reset() snapshot {
func (s *SheddingStat) run() { func (s *SheddingStat) run() {
ticker := time.NewTicker(time.Minute) ticker := time.NewTicker(time.Minute)
defer ticker.Stop() defer ticker.Stop()
for range ticker.C {
c := stat.CpuUsage() s.loop(ticker.C)
st := s.reset()
if st.Drop == 0 {
logx.Statf("(%s) shedding_stat [1m], cpu: %d, total: %d, pass: %d, drop: %d",
s.name, c, st.Total, st.Pass, st.Drop)
} else {
logx.Statf("(%s) shedding_stat_drop [1m], cpu: %d, total: %d, pass: %d, drop: %d",
s.name, c, st.Total, st.Pass, st.Drop)
}
}
} }

View File

@@ -2,6 +2,7 @@ package load
import ( import (
"testing" "testing"
"time"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
@@ -22,3 +23,32 @@ func TestSheddingStat(t *testing.T) {
assert.Equal(t, int64(5), result.Pass) assert.Equal(t, int64(5), result.Pass)
assert.Equal(t, int64(7), result.Drop) assert.Equal(t, int64(7), result.Drop)
} }
func TestLoopTrue(t *testing.T) {
ch := make(chan time.Time, 1)
ch <- time.Now()
close(ch)
st := new(SheddingStat)
logEnabled.Set(true)
st.loop(ch)
}
func TestLoopTrueAndDrop(t *testing.T) {
ch := make(chan time.Time, 1)
ch <- time.Now()
close(ch)
st := new(SheddingStat)
st.IncrementDrop()
logEnabled.Set(true)
st.loop(ch)
}
func TestLoopFalseAndDrop(t *testing.T) {
ch := make(chan time.Time, 1)
ch <- time.Now()
close(ch)
st := new(SheddingStat)
st.IncrementDrop()
logEnabled.Set(false)
st.loop(ch)
}

View File

@@ -20,49 +20,67 @@ func WithDuration(d time.Duration) Logger {
} }
func (l *durationLogger) Error(v ...interface{}) { func (l *durationLogger) Error(v ...interface{}) {
if shouldLog(ErrorLevel) { if shallLog(ErrorLevel) {
l.write(errorLog, levelError, formatWithCaller(fmt.Sprint(v...), durationCallerDepth)) l.write(errorLog, levelError, formatWithCaller(fmt.Sprint(v...), durationCallerDepth))
} }
} }
func (l *durationLogger) Errorf(format string, v ...interface{}) { func (l *durationLogger) Errorf(format string, v ...interface{}) {
if shouldLog(ErrorLevel) { if shallLog(ErrorLevel) {
l.write(errorLog, levelError, formatWithCaller(fmt.Sprintf(format, v...), durationCallerDepth)) 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{}) { func (l *durationLogger) Info(v ...interface{}) {
if shouldLog(InfoLevel) { if shallLog(InfoLevel) {
l.write(infoLog, levelInfo, fmt.Sprint(v...)) l.write(infoLog, levelInfo, fmt.Sprint(v...))
} }
} }
func (l *durationLogger) Infof(format string, v ...interface{}) { func (l *durationLogger) Infof(format string, v ...interface{}) {
if shouldLog(InfoLevel) { if shallLog(InfoLevel) {
l.write(infoLog, levelInfo, fmt.Sprintf(format, v...)) 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{}) { func (l *durationLogger) Slow(v ...interface{}) {
if shouldLog(ErrorLevel) { if shallLog(ErrorLevel) {
l.write(slowLog, levelSlow, fmt.Sprint(v...)) l.write(slowLog, levelSlow, fmt.Sprint(v...))
} }
} }
func (l *durationLogger) Slowf(format string, v ...interface{}) { func (l *durationLogger) Slowf(format string, v ...interface{}) {
if shouldLog(ErrorLevel) { if shallLog(ErrorLevel) {
l.write(slowLog, levelSlow, fmt.Sprintf(format, v...)) 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 { func (l *durationLogger) WithDuration(duration time.Duration) Logger {
l.Duration = timex.ReprOfDuration(duration) l.Duration = timex.ReprOfDuration(duration)
return l return l
} }
func (l *durationLogger) write(writer io.Writer, level, content string) { func (l *durationLogger) write(writer io.Writer, level string, val interface{}) {
l.Timestamp = getTimestamp() l.Timestamp = getTimestamp()
l.Level = level l.Level = level
l.Content = content l.Content = val
outputJson(writer, logEntry(*l)) outputJson(writer, l)
} }

View File

@@ -65,12 +65,14 @@ var (
timeFormat = "2006-01-02T15:04:05.000Z07" timeFormat = "2006-01-02T15:04:05.000Z07"
writeConsole bool writeConsole bool
logLevel uint32 logLevel uint32
infoLog io.WriteCloser // use uint32 for atomic operations
errorLog io.WriteCloser disableStat uint32
severeLog io.WriteCloser infoLog io.WriteCloser
slowLog io.WriteCloser errorLog io.WriteCloser
statLog io.WriteCloser severeLog io.WriteCloser
stackLog io.Writer slowLog io.WriteCloser
statLog io.WriteCloser
stackLog io.Writer
once sync.Once once sync.Once
initialized uint32 initialized uint32
@@ -79,10 +81,10 @@ var (
type ( type (
logEntry struct { logEntry struct {
Timestamp string `json:"@timestamp"` Timestamp string `json:"@timestamp"`
Level string `json:"level"` Level string `json:"level"`
Duration string `json:"duration,omitempty"` Duration string `json:"duration,omitempty"`
Content string `json:"content"` Content interface{} `json:"content"`
} }
logOptions struct { logOptions struct {
@@ -98,10 +100,13 @@ type (
Logger interface { Logger interface {
Error(...interface{}) Error(...interface{})
Errorf(string, ...interface{}) Errorf(string, ...interface{})
Errorv(interface{})
Info(...interface{}) Info(...interface{})
Infof(string, ...interface{}) Infof(string, ...interface{})
Infov(interface{})
Slow(...interface{}) Slow(...interface{})
Slowf(string, ...interface{}) Slowf(string, ...interface{})
Slowv(interface{})
WithDuration(time.Duration) Logger WithDuration(time.Duration) Logger
} }
) )
@@ -133,7 +138,7 @@ func SetUp(c LogConf) error {
// Alert alerts v in alert level, and the message is written to error log. // Alert alerts v in alert level, and the message is written to error log.
func Alert(v string) { func Alert(v string) {
output(errorLog, levelAlert, v) outputText(errorLog, levelAlert, v)
} }
// Close closes the logging. // Close closes the logging.
@@ -195,24 +200,29 @@ func Disable() {
}) })
} }
// DisableStat disables the stat logs.
func DisableStat() {
atomic.StoreUint32(&disableStat, 1)
}
// Error writes v into error log. // Error writes v into error log.
func Error(v ...interface{}) { func Error(v ...interface{}) {
ErrorCaller(1, v...) ErrorCaller(1, v...)
} }
// Errorf writes v with format into error log.
func Errorf(format string, v ...interface{}) {
ErrorCallerf(1, format, v...)
}
// ErrorCaller writes v with context into error log. // ErrorCaller writes v with context into error log.
func ErrorCaller(callDepth int, v ...interface{}) { func ErrorCaller(callDepth int, v ...interface{}) {
errorSync(fmt.Sprint(v...), callDepth+callerInnerDepth) errorTextSync(fmt.Sprint(v...), callDepth+callerInnerDepth)
} }
// ErrorCallerf writes v with context in format into error log. // ErrorCallerf writes v with context in format into error log.
func ErrorCallerf(callDepth int, format string, v ...interface{}) { func ErrorCallerf(callDepth int, format string, v ...interface{}) {
errorSync(fmt.Sprintf(format, v...), callDepth+callerInnerDepth) errorTextSync(fmt.Sprintf(format, v...), callDepth+callerInnerDepth)
}
// Errorf writes v with format into error log.
func Errorf(format string, v ...interface{}) {
ErrorCallerf(1, format, v...)
} }
// ErrorStack writes v along with call stack into error log. // ErrorStack writes v along with call stack into error log.
@@ -227,14 +237,25 @@ func ErrorStackf(format string, v ...interface{}) {
stackSync(fmt.Sprintf(format, v...)) stackSync(fmt.Sprintf(format, v...))
} }
// Errorv writes v into error log with json content.
// No call stack attached, because not elegant to pack the messages.
func Errorv(v interface{}) {
errorAnySync(v)
}
// Info writes v into access log. // Info writes v into access log.
func Info(v ...interface{}) { func Info(v ...interface{}) {
infoSync(fmt.Sprint(v...)) infoTextSync(fmt.Sprint(v...))
} }
// Infof writes v with format into access log. // Infof writes v with format into access log.
func Infof(format string, v ...interface{}) { func Infof(format string, v ...interface{}) {
infoSync(fmt.Sprintf(format, v...)) infoTextSync(fmt.Sprintf(format, v...))
}
// Infov writes v into access log with json content.
func Infov(v interface{}) {
infoAnySync(v)
} }
// Must checks if err is nil, otherwise logs the err and exits. // Must checks if err is nil, otherwise logs the err and exits.
@@ -242,7 +263,7 @@ func Must(err error) {
if err != nil { if err != nil {
msg := formatWithCaller(err.Error(), 3) msg := formatWithCaller(err.Error(), 3)
log.Print(msg) log.Print(msg)
output(severeLog, levelFatal, msg) outputText(severeLog, levelFatal, msg)
os.Exit(1) os.Exit(1)
} }
} }
@@ -264,12 +285,17 @@ func Severef(format string, v ...interface{}) {
// Slow writes v into slow log. // Slow writes v into slow log.
func Slow(v ...interface{}) { func Slow(v ...interface{}) {
slowSync(fmt.Sprint(v...)) slowTextSync(fmt.Sprint(v...))
} }
// Slowf writes v with format into slow log. // Slowf writes v with format into slow log.
func Slowf(format string, v ...interface{}) { func Slowf(format string, v ...interface{}) {
slowSync(fmt.Sprintf(format, v...)) slowTextSync(fmt.Sprintf(format, v...))
}
// Slowv writes v into slow log with json content.
func Slowv(v interface{}) {
slowAnySync(v)
} }
// Stat writes v into stat log. // Stat writes v into stat log.
@@ -312,8 +338,14 @@ func createOutput(path string) (io.WriteCloser, error) {
options.gzipEnabled), options.gzipEnabled) options.gzipEnabled), options.gzipEnabled)
} }
func errorSync(msg string, callDepth int) { func errorAnySync(v interface{}) {
if shouldLog(ErrorLevel) { if shallLog(ErrorLevel) {
outputAny(errorLog, levelError, v)
}
}
func errorTextSync(msg string, callDepth int) {
if shallLog(ErrorLevel) {
outputError(errorLog, msg, callDepth) outputError(errorLog, msg, callDepth)
} }
} }
@@ -362,13 +394,28 @@ func handleOptions(opts []LogOption) {
} }
} }
func infoSync(msg string) { func infoAnySync(val interface{}) {
if shouldLog(InfoLevel) { if shallLog(InfoLevel) {
output(infoLog, levelInfo, msg) outputAny(infoLog, levelInfo, val)
} }
} }
func output(writer io.Writer, level, msg string) { func infoTextSync(msg string) {
if shallLog(InfoLevel) {
outputText(infoLog, levelInfo, msg)
}
}
func outputAny(writer io.Writer, level string, val interface{}) {
info := logEntry{
Timestamp: getTimestamp(),
Level: level,
Content: val,
}
outputJson(writer, info)
}
func outputText(writer io.Writer, level, msg string) {
info := logEntry{ info := logEntry{
Timestamp: getTimestamp(), Timestamp: getTimestamp(),
Level: level, Level: level,
@@ -379,7 +426,7 @@ func output(writer io.Writer, level, msg string) {
func outputError(writer io.Writer, msg string, callDepth int) { func outputError(writer io.Writer, msg string, callDepth int) {
content := formatWithCaller(msg, callDepth) content := formatWithCaller(msg, callDepth)
output(writer, levelError, content) outputText(writer, levelError, content)
} }
func outputJson(writer io.Writer, info interface{}) { func outputJson(writer io.Writer, info interface{}) {
@@ -481,30 +528,40 @@ func setupWithVolume(c LogConf) error {
} }
func severeSync(msg string) { func severeSync(msg string) {
if shouldLog(SevereLevel) { if shallLog(SevereLevel) {
output(severeLog, levelSevere, fmt.Sprintf("%s\n%s", msg, string(debug.Stack()))) outputText(severeLog, levelSevere, fmt.Sprintf("%s\n%s", msg, string(debug.Stack())))
} }
} }
func shouldLog(level uint32) bool { func shallLog(level uint32) bool {
return atomic.LoadUint32(&logLevel) <= level return atomic.LoadUint32(&logLevel) <= level
} }
func slowSync(msg string) { func shallLogStat() bool {
if shouldLog(ErrorLevel) { return atomic.LoadUint32(&disableStat) == 0
output(slowLog, levelSlow, msg) }
func slowAnySync(v interface{}) {
if shallLog(ErrorLevel) {
outputAny(slowLog, levelSlow, v)
}
}
func slowTextSync(msg string) {
if shallLog(ErrorLevel) {
outputText(slowLog, levelSlow, msg)
} }
} }
func stackSync(msg string) { func stackSync(msg string) {
if shouldLog(ErrorLevel) { if shallLog(ErrorLevel) {
output(stackLog, levelError, fmt.Sprintf("%s\n%s", msg, string(debug.Stack()))) outputText(stackLog, levelError, fmt.Sprintf("%s\n%s", msg, string(debug.Stack())))
} }
} }
func statSync(msg string) { func statSync(msg string) {
if shouldLog(InfoLevel) { if shallLogStat() && shallLog(InfoLevel) {
output(statLog, levelStat, msg) outputText(statLog, levelStat, msg)
} }
} }

View File

@@ -92,6 +92,30 @@ func TestStructedLogAlert(t *testing.T) {
}) })
} }
func TestStructedLogError(t *testing.T) {
doTestStructedLog(t, levelError, func(writer io.WriteCloser) {
errorLog = writer
}, func(v ...interface{}) {
Error(v...)
})
}
func TestStructedLogErrorf(t *testing.T) {
doTestStructedLog(t, levelError, func(writer io.WriteCloser) {
errorLog = writer
}, func(v ...interface{}) {
Errorf("%s", fmt.Sprint(v...))
})
}
func TestStructedLogErrorv(t *testing.T) {
doTestStructedLog(t, levelError, func(writer io.WriteCloser) {
errorLog = writer
}, func(v ...interface{}) {
Errorv(fmt.Sprint(v...))
})
}
func TestStructedLogInfo(t *testing.T) { func TestStructedLogInfo(t *testing.T) {
doTestStructedLog(t, levelInfo, func(writer io.WriteCloser) { doTestStructedLog(t, levelInfo, func(writer io.WriteCloser) {
infoLog = writer infoLog = writer
@@ -100,6 +124,22 @@ func TestStructedLogInfo(t *testing.T) {
}) })
} }
func TestStructedLogInfof(t *testing.T) {
doTestStructedLog(t, levelInfo, func(writer io.WriteCloser) {
infoLog = writer
}, func(v ...interface{}) {
Infof("%s", fmt.Sprint(v...))
})
}
func TestStructedLogInfov(t *testing.T) {
doTestStructedLog(t, levelInfo, func(writer io.WriteCloser) {
infoLog = writer
}, func(v ...interface{}) {
Infov(fmt.Sprint(v...))
})
}
func TestStructedLogSlow(t *testing.T) { func TestStructedLogSlow(t *testing.T) {
doTestStructedLog(t, levelSlow, func(writer io.WriteCloser) { doTestStructedLog(t, levelSlow, func(writer io.WriteCloser) {
slowLog = writer slowLog = writer
@@ -116,6 +156,14 @@ func TestStructedLogSlowf(t *testing.T) {
}) })
} }
func TestStructedLogSlowv(t *testing.T) {
doTestStructedLog(t, levelSlow, func(writer io.WriteCloser) {
slowLog = writer
}, func(v ...interface{}) {
Slowv(fmt.Sprint(v...))
})
}
func TestStructedLogStat(t *testing.T) { func TestStructedLogStat(t *testing.T) {
doTestStructedLog(t, levelStat, func(writer io.WriteCloser) { doTestStructedLog(t, levelStat, func(writer io.WriteCloser) {
statLog = writer statLog = writer
@@ -246,6 +294,17 @@ func TestDisable(t *testing.T) {
assert.Nil(t, Close()) assert.Nil(t, Close())
} }
func TestDisableStat(t *testing.T) {
DisableStat()
const message = "hello there"
writer := new(mockWriter)
statLog = writer
atomic.StoreUint32(&initialized, 1)
Stat(message)
assert.Equal(t, 0, writer.builder.Len())
}
func TestWithGzip(t *testing.T) { func TestWithGzip(t *testing.T) {
fn := WithGzip() fn := WithGzip()
var opt logOptions var opt logOptions
@@ -357,7 +416,9 @@ func doTestStructedLog(t *testing.T, level string, setup func(writer io.WriteClo
t.Error(err) t.Error(err)
} }
assert.Equal(t, level, entry.Level) assert.Equal(t, level, entry.Level)
assert.True(t, strings.Contains(entry.Content, message)) val, ok := entry.Content.(string)
assert.True(t, ok)
assert.True(t, strings.Contains(val, message))
} }
func testSetLevelTwiceWithMode(t *testing.T, mode string) { func testSetLevelTwiceWithMode(t *testing.T, mode string) {

View File

@@ -44,5 +44,5 @@ func captureOutput(f func()) string {
func getContent(jsonStr string) string { func getContent(jsonStr string) string {
var entry logEntry var entry logEntry
json.Unmarshal([]byte(jsonStr), &entry) json.Unmarshal([]byte(jsonStr), &entry)
return entry.Content return entry.Content.(string)
} }

View File

@@ -8,6 +8,7 @@ import (
"github.com/tal-tech/go-zero/core/timex" "github.com/tal-tech/go-zero/core/timex"
"github.com/tal-tech/go-zero/core/trace/tracespec" "github.com/tal-tech/go-zero/core/trace/tracespec"
"go.opentelemetry.io/otel/trace"
) )
type traceLogger struct { type traceLogger struct {
@@ -18,50 +19,68 @@ type traceLogger struct {
} }
func (l *traceLogger) Error(v ...interface{}) { func (l *traceLogger) Error(v ...interface{}) {
if shouldLog(ErrorLevel) { if shallLog(ErrorLevel) {
l.write(errorLog, levelError, formatWithCaller(fmt.Sprint(v...), durationCallerDepth)) l.write(errorLog, levelError, formatWithCaller(fmt.Sprint(v...), durationCallerDepth))
} }
} }
func (l *traceLogger) Errorf(format string, v ...interface{}) { func (l *traceLogger) Errorf(format string, v ...interface{}) {
if shouldLog(ErrorLevel) { if shallLog(ErrorLevel) {
l.write(errorLog, levelError, formatWithCaller(fmt.Sprintf(format, v...), durationCallerDepth)) l.write(errorLog, levelError, formatWithCaller(fmt.Sprintf(format, v...), durationCallerDepth))
} }
} }
func (l *traceLogger) Errorv(v interface{}) {
if shallLog(ErrorLevel) {
l.write(errorLog, levelError, v)
}
}
func (l *traceLogger) Info(v ...interface{}) { func (l *traceLogger) Info(v ...interface{}) {
if shouldLog(InfoLevel) { if shallLog(InfoLevel) {
l.write(infoLog, levelInfo, fmt.Sprint(v...)) l.write(infoLog, levelInfo, fmt.Sprint(v...))
} }
} }
func (l *traceLogger) Infof(format string, v ...interface{}) { func (l *traceLogger) Infof(format string, v ...interface{}) {
if shouldLog(InfoLevel) { if shallLog(InfoLevel) {
l.write(infoLog, levelInfo, fmt.Sprintf(format, v...)) l.write(infoLog, levelInfo, fmt.Sprintf(format, v...))
} }
} }
func (l *traceLogger) Infov(v interface{}) {
if shallLog(InfoLevel) {
l.write(infoLog, levelInfo, v)
}
}
func (l *traceLogger) Slow(v ...interface{}) { func (l *traceLogger) Slow(v ...interface{}) {
if shouldLog(ErrorLevel) { if shallLog(ErrorLevel) {
l.write(slowLog, levelSlow, fmt.Sprint(v...)) l.write(slowLog, levelSlow, fmt.Sprint(v...))
} }
} }
func (l *traceLogger) Slowf(format string, v ...interface{}) { func (l *traceLogger) Slowf(format string, v ...interface{}) {
if shouldLog(ErrorLevel) { if shallLog(ErrorLevel) {
l.write(slowLog, levelSlow, fmt.Sprintf(format, v...)) l.write(slowLog, levelSlow, fmt.Sprintf(format, v...))
} }
} }
func (l *traceLogger) Slowv(v interface{}) {
if shallLog(ErrorLevel) {
l.write(slowLog, levelSlow, v)
}
}
func (l *traceLogger) WithDuration(duration time.Duration) Logger { func (l *traceLogger) WithDuration(duration time.Duration) Logger {
l.Duration = timex.ReprOfDuration(duration) l.Duration = timex.ReprOfDuration(duration)
return l return l
} }
func (l *traceLogger) write(writer io.Writer, level, content string) { func (l *traceLogger) write(writer io.Writer, level string, val interface{}) {
l.Timestamp = getTimestamp() l.Timestamp = getTimestamp()
l.Level = level l.Level = level
l.Content = content l.Content = val
l.Trace = traceIdFromContext(l.ctx) l.Trace = traceIdFromContext(l.ctx)
l.Span = spanIdFromContext(l.ctx) l.Span = spanIdFromContext(l.ctx)
outputJson(writer, l) outputJson(writer, l)
@@ -75,6 +94,11 @@ func WithContext(ctx context.Context) Logger {
} }
func spanIdFromContext(ctx context.Context) string { func spanIdFromContext(ctx context.Context) string {
span := trace.SpanFromContext(ctx)
if span.IsRecording() {
return span.SpanContext().SpanID().String()
}
t, ok := ctx.Value(tracespec.TracingKey).(tracespec.Trace) t, ok := ctx.Value(tracespec.TracingKey).(tracespec.Trace)
if !ok { if !ok {
return "" return ""
@@ -84,6 +108,11 @@ func spanIdFromContext(ctx context.Context) string {
} }
func traceIdFromContext(ctx context.Context) string { func traceIdFromContext(ctx context.Context) string {
span := trace.SpanFromContext(ctx)
if span.IsRecording() {
return span.SpanContext().SpanID().String()
}
t, ok := ctx.Value(tracespec.TracingKey).(tracespec.Trace) t, ok := ctx.Value(tracespec.TracingKey).(tracespec.Trace)
if !ok { if !ok {
return "" return ""

View File

@@ -43,7 +43,8 @@ type (
UnmarshalOption func(*unmarshalOptions) UnmarshalOption func(*unmarshalOptions)
unmarshalOptions struct { unmarshalOptions struct {
fromString bool fromString bool
canonicalKey func(key string) string
} }
keyCache map[string][]string keyCache map[string][]string
@@ -229,7 +230,7 @@ func (u *Unmarshaler) processFieldPrimitive(field reflect.StructField, value ref
default: default:
switch v := mapValue.(type) { switch v := mapValue.(type) {
case json.Number: case json.Number:
return u.processFieldPrimitiveWithJsonNumber(field, value, v, opts, fullName) return u.processFieldPrimitiveWithJSONNumber(field, value, v, opts, fullName)
default: default:
if typeKind == valueKind { if typeKind == valueKind {
if err := validateValueInOptions(opts.options(), mapValue); err != nil { if err := validateValueInOptions(opts.options(), mapValue); err != nil {
@@ -244,7 +245,7 @@ func (u *Unmarshaler) processFieldPrimitive(field reflect.StructField, value ref
return newTypeMismatchError(fullName) return newTypeMismatchError(fullName)
} }
func (u *Unmarshaler) processFieldPrimitiveWithJsonNumber(field reflect.StructField, value reflect.Value, func (u *Unmarshaler) processFieldPrimitiveWithJSONNumber(field reflect.StructField, value reflect.Value,
v json.Number, opts *fieldOptionsWithContext, fullName string) error { v json.Number, opts *fieldOptionsWithContext, fullName string) error {
fieldType := field.Type fieldType := field.Type
fieldKind := fieldType.Kind() fieldKind := fieldType.Kind()
@@ -323,7 +324,11 @@ func (u *Unmarshaler) processNamedField(field reflect.StructField, value reflect
} }
fullName = join(fullName, key) fullName = join(fullName, key)
mapValue, hasValue := getValue(m, key) canonicalKey := key
if u.opts.canonicalKey != nil {
canonicalKey = u.opts.canonicalKey(key)
}
mapValue, hasValue := getValue(m, canonicalKey)
if hasValue { if hasValue {
return u.processNamedFieldWithValue(field, value, mapValue, key, opts, fullName) return u.processNamedFieldWithValue(field, value, mapValue, key, opts, fullName)
} }
@@ -513,14 +518,14 @@ func (u *Unmarshaler) fillSliceValue(slice reflect.Value, index int, baseKind re
target.Set(reflect.ValueOf(value)) target.Set(reflect.ValueOf(value))
ithVal.Set(target.Addr()) ithVal.Set(target.Addr())
return nil return nil
} else {
if ithVal.Kind() != reflect.TypeOf(value).Kind() {
return errTypeMismatch
}
ithVal.Set(reflect.ValueOf(value))
return nil
} }
if ithVal.Kind() != reflect.TypeOf(value).Kind() {
return errTypeMismatch
}
ithVal.Set(reflect.ValueOf(value))
return nil
} }
} }
@@ -621,6 +626,13 @@ func WithStringValues() UnmarshalOption {
} }
} }
// WithCanonicalKeyFunc customizes a Unmarshaler with Canonical Key func
func WithCanonicalKeyFunc(f func(string) string) UnmarshalOption {
return func(opt *unmarshalOptions) {
opt.canonicalKey = f
}
}
func fillDurationValue(fieldKind reflect.Kind, value reflect.Value, dur string) error { func fillDurationValue(fieldKind reflect.Kind, value reflect.Value, dur string) error {
d, err := time.ParseDuration(dur) d, err := time.ParseDuration(dur)
if err != nil { if err != nil {

View File

@@ -112,6 +112,12 @@ func MapReduceWithSource(source <-chan interface{}, mapper MapperFunc, reducer R
opts ...Option) (interface{}, error) { opts ...Option) (interface{}, error) {
options := buildOptions(opts...) options := buildOptions(opts...)
output := make(chan interface{}) output := make(chan interface{})
defer func() {
for range output {
panic("more than one element written in reducer")
}
}()
collector := make(chan interface{}, options.workers) collector := make(chan interface{}, options.workers)
done := syncx.NewDoneChan() done := syncx.NewDoneChan()
writer := newGuardedWriter(output, done.Done()) writer := newGuardedWriter(output, done.Done())

View File

@@ -202,6 +202,22 @@ func TestMapReduce(t *testing.T) {
} }
} }
func TestMapReduceWithReduerWriteMoreThanOnce(t *testing.T) {
assert.Panics(t, func() {
MapReduce(func(source chan<- interface{}) {
for i := 0; i < 10; i++ {
source <- i
}
}, func(item interface{}, writer Writer, cancel func(error)) {
writer.Write(item)
}, func(pipe <-chan interface{}, writer Writer, cancel func(error)) {
drain(pipe)
writer.Write("one")
writer.Write("two")
})
})
}
func TestMapReduceVoid(t *testing.T) { func TestMapReduceVoid(t *testing.T) {
var value uint32 var value uint32
tests := []struct { tests := []struct {

View File

@@ -1,3 +1,4 @@
//go:build windows
// +build windows // +build windows
package proc package proc

View File

@@ -1,3 +1,4 @@
//go:build linux || darwin
// +build linux darwin // +build linux darwin
package proc package proc

View File

@@ -1,3 +1,4 @@
//go:build windows
// +build windows // +build windows
package proc package proc

View File

@@ -1,3 +1,4 @@
//go:build linux || darwin
// +build linux darwin // +build linux darwin
package proc package proc

View File

@@ -1,3 +1,4 @@
//go:build windows
// +build windows // +build windows
package proc package proc
@@ -14,5 +15,5 @@ func AddWrapUpListener(fn func()) func() {
return fn return fn
} }
func SetTimeoutToForceQuit(duration time.Duration) { func SetTimeToForceQuit(duration time.Duration) {
} }

View File

@@ -0,0 +1,10 @@
//go:build windows
// +build windows
package proc
import "context"
func Done() <-chan struct{} {
return context.Background().Done()
}

View File

@@ -1,3 +1,4 @@
//go:build linux || darwin
// +build linux darwin // +build linux darwin
package proc package proc
@@ -12,6 +13,8 @@ import (
const timeFormat = "0102150405" const timeFormat = "0102150405"
var done = make(chan struct{})
func init() { func init() {
go func() { go func() {
var profiler Stopper var profiler Stopper
@@ -33,6 +36,13 @@ func init() {
profiler = nil profiler = nil
} }
case syscall.SIGTERM: case syscall.SIGTERM:
select {
case <-done:
// already closed
default:
close(done)
}
gracefulStop(signals) gracefulStop(signals)
default: default:
logx.Error("Got unregistered signal:", v) logx.Error("Got unregistered signal:", v)
@@ -40,3 +50,8 @@ func init() {
} }
}() }()
} }
// Done returns the channel that notifies the process quitting.
func Done() <-chan struct{} {
return done
}

16
core/proc/signals_test.go Normal file
View File

@@ -0,0 +1,16 @@
package proc
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestDone(t *testing.T) {
select {
case <-Done():
assert.Fail(t, "should run")
default:
}
assert.NotNil(t, Done())
}

View File

@@ -29,6 +29,8 @@ type ServiceConf struct {
Mode string `json:",default=pro,options=dev|test|rt|pre|pro"` Mode string `json:",default=pro,options=dev|test|rt|pre|pro"`
MetricsUrl string `json:",optional"` MetricsUrl string `json:",optional"`
Prometheus prometheus.Config `json:",optional"` Prometheus prometheus.Config `json:",optional"`
// TODO: enable it in v1.2.1
// Telemetry opentelemetry.Config `json:",optional"`
} }
// MustSetUp sets up the service, exits on error. // MustSetUp sets up the service, exits on error.
@@ -49,6 +51,13 @@ func (sc ServiceConf) SetUp() error {
sc.initMode() sc.initMode()
prometheus.StartAgent(sc.Prometheus) prometheus.StartAgent(sc.Prometheus)
// TODO: enable it in v1.2.1
// if len(sc.Telemetry.Name) == 0 {
// sc.Telemetry.Name = sc.Name
// }
// opentelemetry.StartAgent(sc.Telemetry)
if len(sc.MetricsUrl) > 0 { if len(sc.MetricsUrl) > 0 {
stat.SetReportWriter(stat.NewRemoteWriter(sc.MetricsUrl)) stat.SetReportWriter(stat.NewRemoteWriter(sc.MetricsUrl))
} }

View File

@@ -1,3 +1,4 @@
//go:build !linux
// +build !linux // +build !linux
package stat package stat

View File

@@ -38,7 +38,9 @@ func init() {
atomic.StoreInt64(&cpuUsage, usage) atomic.StoreInt64(&cpuUsage, usage)
}) })
case <-allTicker.C: case <-allTicker.C:
printUsage() if logEnabled.True() {
printUsage()
}
} }
} }
}() }()

View File

@@ -29,7 +29,7 @@ type (
) )
// New returns a Cache. // New returns a Cache.
func New(c ClusterConf, barrier syncx.SharedCalls, st *Stat, errNotFound error, func New(c ClusterConf, barrier syncx.SingleFlight, st *Stat, errNotFound error,
opts ...Option) Cache { opts ...Option) Cache {
if len(c) == 0 || TotalWeights(c) <= 0 { if len(c) == 0 || TotalWeights(c) <= 0 {
log.Fatal("no cache nodes") log.Fatal("no cache nodes")

View File

@@ -23,6 +23,7 @@ type mockedNode struct {
func (mc *mockedNode) Del(keys ...string) error { func (mc *mockedNode) Del(keys ...string) error {
var be errorx.BatchError var be errorx.BatchError
for _, key := range keys { for _, key := range keys {
if _, ok := mc.vals[key]; !ok { if _, ok := mc.vals[key]; !ok {
be.Add(mc.errNotFound) be.Add(mc.errNotFound)
@@ -30,6 +31,7 @@ func (mc *mockedNode) Del(keys ...string) error {
delete(mc.vals, key) delete(mc.vals, key)
} }
} }
return be.Err() return be.Err()
} }
@@ -102,7 +104,7 @@ func TestCache_SetDel(t *testing.T) {
Weight: 100, Weight: 100,
}, },
} }
c := New(conf, syncx.NewSharedCalls(), NewStat("mock"), errPlaceholder) c := New(conf, syncx.NewSingleFlight(), NewStat("mock"), errPlaceholder)
for i := 0; i < total; i++ { for i := 0; i < total; i++ {
if i%2 == 0 { if i%2 == 0 {
assert.Nil(t, c.Set(fmt.Sprintf("key/%d", i), i)) assert.Nil(t, c.Set(fmt.Sprintf("key/%d", i), i))
@@ -140,7 +142,7 @@ func TestCache_OneNode(t *testing.T) {
Weight: 100, Weight: 100,
}, },
} }
c := New(conf, syncx.NewSharedCalls(), NewStat("mock"), errPlaceholder) c := New(conf, syncx.NewSingleFlight(), NewStat("mock"), errPlaceholder)
for i := 0; i < total; i++ { for i := 0; i < total; i++ {
if i%2 == 0 { if i%2 == 0 {
assert.Nil(t, c.Set(fmt.Sprintf("key/%d", i), i)) assert.Nil(t, c.Set(fmt.Sprintf("key/%d", i), i))

View File

@@ -29,7 +29,7 @@ type cacheNode struct {
rds *redis.Redis rds *redis.Redis
expiry time.Duration expiry time.Duration
notFoundExpiry time.Duration notFoundExpiry time.Duration
barrier syncx.SharedCalls barrier syncx.SingleFlight
r *rand.Rand r *rand.Rand
lock *sync.Mutex lock *sync.Mutex
unstableExpiry mathx.Unstable unstableExpiry mathx.Unstable
@@ -43,7 +43,7 @@ type cacheNode struct {
// st is used to stat the cache. // st is used to stat the cache.
// errNotFound defines the error that returned on cache not found. // errNotFound defines the error that returned on cache not found.
// opts are the options that customize the cacheNode. // opts are the options that customize the cacheNode.
func NewNode(rds *redis.Redis, barrier syncx.SharedCalls, st *Stat, func NewNode(rds *redis.Redis, barrier syncx.SingleFlight, st *Stat,
errNotFound error, opts ...Option) Cache { errNotFound error, opts ...Option) Cache {
o := newOptions(opts...) o := newOptions(opts...)
return cacheNode{ return cacheNode{
@@ -65,9 +65,18 @@ func (c cacheNode) Del(keys ...string) error {
return nil return nil
} }
if _, err := c.rds.Del(keys...); err != nil { if len(keys) > 1 && c.rds.Type == redis.ClusterType {
logx.Errorf("failed to clear cache with keys: %q, error: %v", formatKeys(keys), err) for _, key := range keys {
c.asyncRetryDelCache(keys...) if _, err := c.rds.Del(key); err != nil {
logx.Errorf("failed to clear cache with key: %q, error: %v", key, err)
c.asyncRetryDelCache(key)
}
}
} else {
if _, err := c.rds.Del(keys...); err != nil {
logx.Errorf("failed to clear cache with keys: %q, error: %v", formatKeys(keys), err)
c.asyncRetryDelCache(keys...)
}
} }
return nil return nil

View File

@@ -29,6 +29,7 @@ func init() {
func TestCacheNode_DelCache(t *testing.T) { func TestCacheNode_DelCache(t *testing.T) {
store, clean, err := redistest.CreateRedis() store, clean, err := redistest.CreateRedis()
assert.Nil(t, err) assert.Nil(t, err)
store.Type = redis.ClusterType
defer clean() defer clean()
cn := cacheNode{ cn := cacheNode{
@@ -49,6 +50,23 @@ func TestCacheNode_DelCache(t *testing.T) {
assert.Nil(t, cn.Del("first", "second")) assert.Nil(t, cn.Del("first", "second"))
} }
func TestCacheNode_DelCacheWithErrors(t *testing.T) {
store, clean, err := redistest.CreateRedis()
assert.Nil(t, err)
store.Type = redis.ClusterType
clean()
cn := cacheNode{
rds: store,
r: rand.New(rand.NewSource(time.Now().UnixNano())),
lock: new(sync.Mutex),
unstableExpiry: mathx.NewUnstable(expiryDeviation),
stat: NewStat("any"),
errNotFound: errTestNotFound,
}
assert.Nil(t, cn.Del("third", "fourth"))
}
func TestCacheNode_InvalidCache(t *testing.T) { func TestCacheNode_InvalidCache(t *testing.T) {
s, err := miniredis.Run() s, err := miniredis.Run()
assert.Nil(t, err) assert.Nil(t, err)
@@ -78,7 +96,7 @@ func TestCacheNode_Take(t *testing.T) {
cn := cacheNode{ cn := cacheNode{
rds: store, rds: store,
r: rand.New(rand.NewSource(time.Now().UnixNano())), r: rand.New(rand.NewSource(time.Now().UnixNano())),
barrier: syncx.NewSharedCalls(), barrier: syncx.NewSingleFlight(),
lock: new(sync.Mutex), lock: new(sync.Mutex),
unstableExpiry: mathx.NewUnstable(expiryDeviation), unstableExpiry: mathx.NewUnstable(expiryDeviation),
stat: NewStat("any"), stat: NewStat("any"),
@@ -105,7 +123,7 @@ func TestCacheNode_TakeNotFound(t *testing.T) {
cn := cacheNode{ cn := cacheNode{
rds: store, rds: store,
r: rand.New(rand.NewSource(time.Now().UnixNano())), r: rand.New(rand.NewSource(time.Now().UnixNano())),
barrier: syncx.NewSharedCalls(), barrier: syncx.NewSingleFlight(),
lock: new(sync.Mutex), lock: new(sync.Mutex),
unstableExpiry: mathx.NewUnstable(expiryDeviation), unstableExpiry: mathx.NewUnstable(expiryDeviation),
stat: NewStat("any"), stat: NewStat("any"),
@@ -144,7 +162,7 @@ func TestCacheNode_TakeWithExpire(t *testing.T) {
cn := cacheNode{ cn := cacheNode{
rds: store, rds: store,
r: rand.New(rand.NewSource(time.Now().UnixNano())), r: rand.New(rand.NewSource(time.Now().UnixNano())),
barrier: syncx.NewSharedCalls(), barrier: syncx.NewSingleFlight(),
lock: new(sync.Mutex), lock: new(sync.Mutex),
unstableExpiry: mathx.NewUnstable(expiryDeviation), unstableExpiry: mathx.NewUnstable(expiryDeviation),
stat: NewStat("any"), stat: NewStat("any"),
@@ -171,7 +189,7 @@ func TestCacheNode_String(t *testing.T) {
cn := cacheNode{ cn := cacheNode{
rds: store, rds: store,
r: rand.New(rand.NewSource(time.Now().UnixNano())), r: rand.New(rand.NewSource(time.Now().UnixNano())),
barrier: syncx.NewSharedCalls(), barrier: syncx.NewSingleFlight(),
lock: new(sync.Mutex), lock: new(sync.Mutex),
unstableExpiry: mathx.NewUnstable(expiryDeviation), unstableExpiry: mathx.NewUnstable(expiryDeviation),
stat: NewStat("any"), stat: NewStat("any"),
@@ -188,7 +206,7 @@ func TestCacheValueWithBigInt(t *testing.T) {
cn := cacheNode{ cn := cacheNode{
rds: store, rds: store,
r: rand.New(rand.NewSource(time.Now().UnixNano())), r: rand.New(rand.NewSource(time.Now().UnixNano())),
barrier: syncx.NewSharedCalls(), barrier: syncx.NewSingleFlight(),
lock: new(sync.Mutex), lock: new(sync.Mutex),
unstableExpiry: mathx.NewUnstable(expiryDeviation), unstableExpiry: mathx.NewUnstable(expiryDeviation),
stat: NewStat("any"), stat: NewStat("any"),

View File

@@ -1,7 +1,7 @@
package clickhouse package clickhouse
import ( import (
// imports the driver. // imports the driver, don't remove this comment, golint requires.
_ "github.com/ClickHouse/clickhouse-go" _ "github.com/ClickHouse/clickhouse-go"
"github.com/tal-tech/go-zero/core/stores/sqlx" "github.com/tal-tech/go-zero/core/stores/sqlx"
) )

View File

@@ -11,8 +11,8 @@ var (
// ErrNotFound is an alias of mgo.ErrNotFound. // ErrNotFound is an alias of mgo.ErrNotFound.
ErrNotFound = mgo.ErrNotFound ErrNotFound = mgo.ErrNotFound
// can't use one SharedCalls per conn, because multiple conns may share the same cache key. // can't use one SingleFlight per conn, because multiple conns may share the same cache key.
sharedCalls = syncx.NewSharedCalls() sharedCalls = syncx.NewSingleFlight()
stats = cache.NewStat("mongoc") stats = cache.NewStat("mongoc")
) )

View File

@@ -1,7 +1,7 @@
package postgres package postgres
import ( import (
// imports the driver. // imports the driver, don't remove this comment, golint requires.
_ "github.com/lib/pq" _ "github.com/lib/pq"
"github.com/tal-tech/go-zero/core/stores/sqlx" "github.com/tal-tech/go-zero/core/stores/sqlx"
) )

View File

@@ -71,6 +71,8 @@ type (
IntCmd = red.IntCmd IntCmd = red.IntCmd
// FloatCmd is an alias of redis.FloatCmd. // FloatCmd is an alias of redis.FloatCmd.
FloatCmd = red.FloatCmd FloatCmd = red.FloatCmd
// StringCmd is an alias of redis.StringCmd.
StringCmd = red.StringCmd
) )
// New returns a Redis with given options. // New returns a Redis with given options.

View File

@@ -17,8 +17,8 @@ var (
// ErrNotFound is an alias of sqlx.ErrNotFound. // ErrNotFound is an alias of sqlx.ErrNotFound.
ErrNotFound = sqlx.ErrNotFound ErrNotFound = sqlx.ErrNotFound
// can't use one SharedCalls per conn, because multiple conns may share the same cache key. // can't use one SingleFlight per conn, because multiple conns may share the same cache key.
exclusiveCalls = syncx.NewSharedCalls() exclusiveCalls = syncx.NewSingleFlight()
stats = cache.NewStat("sqlc") stats = cache.NewStat("sqlc")
) )

View File

@@ -600,6 +600,10 @@ func (d dummySqlConn) QueryRowsPartial(v interface{}, query string, args ...inte
return nil return nil
} }
func (d dummySqlConn) RawDB() (*sql.DB, error) {
return nil, nil
}
func (d dummySqlConn) Transact(func(session sqlx.Session) error) error { func (d dummySqlConn) Transact(func(session sqlx.Session) error) error {
return nil return nil
} }
@@ -621,6 +625,10 @@ func (c *trackedConn) QueryRows(v interface{}, query string, args ...interface{}
return c.dummySqlConn.QueryRows(v, query, args...) return c.dummySqlConn.QueryRows(v, query, args...)
} }
func (c *trackedConn) RawDB() (*sql.DB, error) {
return nil, nil
}
func (c *trackedConn) Transact(fn func(session sqlx.Session) error) error { func (c *trackedConn) Transact(fn func(session sqlx.Session) error) error {
c.transactValue = true c.transactValue = true
return c.dummySqlConn.Transact(fn) return c.dummySqlConn.Transact(fn)

View File

@@ -43,6 +43,10 @@ func (c *mockedConn) QueryRowsPartial(v interface{}, query string, args ...inter
panic("should not called") panic("should not called")
} }
func (c *mockedConn) RawDB() (*sql.DB, error) {
panic("should not called")
}
func (c *mockedConn) Transact(func(session Session) error) error { func (c *mockedConn) Transact(func(session Session) error) error {
panic("should not called") panic("should not called")
} }

View File

@@ -4,6 +4,7 @@ import (
"database/sql" "database/sql"
"github.com/tal-tech/go-zero/core/breaker" "github.com/tal-tech/go-zero/core/breaker"
"github.com/tal-tech/go-zero/core/logx"
) )
// ErrNotFound is an alias of sql.ErrNoRows // ErrNotFound is an alias of sql.ErrNoRows
@@ -23,6 +24,8 @@ type (
// SqlConn only stands for raw connections, so Transact method can be called. // SqlConn only stands for raw connections, so Transact method can be called.
SqlConn interface { SqlConn interface {
Session Session
// RawDB is for other ORM to operate with, use it with caution.
RawDB() (*sql.DB, error)
Transact(func(session Session) error) error Transact(func(session Session) error) error
} }
@@ -43,13 +46,15 @@ type (
// Because CORBA doesn't support PREPARE, so we need to combine the // Because CORBA doesn't support PREPARE, so we need to combine the
// query arguments into one string and do underlying query without arguments // query arguments into one string and do underlying query without arguments
commonSqlConn struct { commonSqlConn struct {
driverName string connProv connProvider
datasource string onError func(error)
beginTx beginnable beginTx beginnable
brk breaker.Breaker brk breaker.Breaker
accept func(error) bool accept func(error) bool
} }
connProvider func() (*sql.DB, error)
sessionConn interface { sessionConn interface {
Exec(query string, args ...interface{}) (sql.Result, error) Exec(query string, args ...interface{}) (sql.Result, error)
Query(query string, args ...interface{}) (*sql.Rows, error) Query(query string, args ...interface{}) (*sql.Rows, error)
@@ -69,10 +74,34 @@ type (
// NewSqlConn returns a SqlConn with given driver name and datasource. // NewSqlConn returns a SqlConn with given driver name and datasource.
func NewSqlConn(driverName, datasource string, opts ...SqlOption) SqlConn { func NewSqlConn(driverName, datasource string, opts ...SqlOption) SqlConn {
conn := &commonSqlConn{ conn := &commonSqlConn{
driverName: driverName, connProv: func() (*sql.DB, error) {
datasource: datasource, return getSqlConn(driverName, datasource)
beginTx: begin, },
brk: breaker.NewBreaker(), onError: func(err error) {
logInstanceError(datasource, err)
},
beginTx: begin,
brk: breaker.NewBreaker(),
}
for _, opt := range opts {
opt(conn)
}
return conn
}
// NewSqlConnFromDB returns a SqlConn with the given sql.DB.
// Use it with caution, it's provided for other ORM to interact with.
func NewSqlConnFromDB(db *sql.DB, opts ...SqlOption) SqlConn {
conn := &commonSqlConn{
connProv: func() (*sql.DB, error) {
return db, nil
},
onError: func(err error) {
logx.Errorf("Error on getting sql instance: %v", err)
},
beginTx: begin,
brk: breaker.NewBreaker(),
} }
for _, opt := range opts { for _, opt := range opts {
opt(conn) opt(conn)
@@ -84,9 +113,9 @@ func NewSqlConn(driverName, datasource string, opts ...SqlOption) SqlConn {
func (db *commonSqlConn) Exec(q string, args ...interface{}) (result sql.Result, err error) { func (db *commonSqlConn) Exec(q string, args ...interface{}) (result sql.Result, err error) {
err = db.brk.DoWithAcceptable(func() error { err = db.brk.DoWithAcceptable(func() error {
var conn *sql.DB var conn *sql.DB
conn, err = getSqlConn(db.driverName, db.datasource) conn, err = db.connProv()
if err != nil { if err != nil {
logInstanceError(db.datasource, err) db.onError(err)
return err return err
} }
@@ -100,9 +129,9 @@ func (db *commonSqlConn) Exec(q string, args ...interface{}) (result sql.Result,
func (db *commonSqlConn) Prepare(query string) (stmt StmtSession, err error) { func (db *commonSqlConn) Prepare(query string) (stmt StmtSession, err error) {
err = db.brk.DoWithAcceptable(func() error { err = db.brk.DoWithAcceptable(func() error {
var conn *sql.DB var conn *sql.DB
conn, err = getSqlConn(db.driverName, db.datasource) conn, err = db.connProv()
if err != nil { if err != nil {
logInstanceError(db.datasource, err) db.onError(err)
return err return err
} }
@@ -145,6 +174,10 @@ func (db *commonSqlConn) QueryRowsPartial(v interface{}, q string, args ...inter
}, q, args...) }, q, args...)
} }
func (db *commonSqlConn) RawDB() (*sql.DB, error) {
return db.connProv()
}
func (db *commonSqlConn) Transact(fn func(Session) error) error { func (db *commonSqlConn) Transact(fn func(Session) error) error {
return db.brk.DoWithAcceptable(func() error { return db.brk.DoWithAcceptable(func() error {
return transact(db, db.beginTx, fn) return transact(db, db.beginTx, fn)
@@ -163,9 +196,9 @@ func (db *commonSqlConn) acceptable(err error) bool {
func (db *commonSqlConn) queryRows(scanner func(*sql.Rows) error, q string, args ...interface{}) error { func (db *commonSqlConn) queryRows(scanner func(*sql.Rows) error, q string, args ...interface{}) error {
var qerr error var qerr error
return db.brk.DoWithAcceptable(func() error { return db.brk.DoWithAcceptable(func() error {
conn, err := getSqlConn(db.driverName, db.datasource) conn, err := db.connProv()
if err != nil { if err != nil {
logInstanceError(db.datasource, err) db.onError(err)
return err return err
} }

View File

@@ -21,12 +21,15 @@ func TestSqlConn(t *testing.T) {
mock.ExpectExec("any") mock.ExpectExec("any")
mock.ExpectQuery("any").WillReturnRows(sqlmock.NewRows([]string{"foo"})) mock.ExpectQuery("any").WillReturnRows(sqlmock.NewRows([]string{"foo"}))
conn := NewMysql(mockedDatasource) conn := NewMysql(mockedDatasource)
db, err := conn.RawDB()
assert.Nil(t, err)
rawConn := NewSqlConnFromDB(db, withMysqlAcceptable())
badConn := NewMysql("badsql") badConn := NewMysql("badsql")
_, err := conn.Exec("any", "value") _, err = conn.Exec("any", "value")
assert.NotNil(t, err) assert.NotNil(t, err)
_, err = badConn.Exec("any", "value") _, err = badConn.Exec("any", "value")
assert.NotNil(t, err) assert.NotNil(t, err)
_, err = conn.Prepare("any") _, err = rawConn.Prepare("any")
assert.NotNil(t, err) assert.NotNil(t, err)
_, err = badConn.Prepare("any") _, err = badConn.Prepare("any")
assert.NotNil(t, err) assert.NotNil(t, err)

View File

@@ -71,9 +71,9 @@ func begin(db *sql.DB) (trans, error) {
} }
func transact(db *commonSqlConn, b beginnable, fn func(Session) error) (err error) { func transact(db *commonSqlConn, b beginnable, fn func(Session) error) (err error) {
conn, err := getSqlConn(db.driverName, db.datasource) conn, err := db.connProv()
if err != nil { if err != nil {
logInstanceError(db.datasource, err) db.onError(err)
return err return err
} }

View File

@@ -40,6 +40,24 @@ func Filter(s string, filter func(r rune) bool) string {
return string(chars[:n]) return string(chars[:n])
} }
// FirstN returns first n runes from s.
func FirstN(s string, n int, ellipsis ...string) string {
var i int
for j := range s {
if i == n {
ret := s[:j]
for _, each := range ellipsis {
ret += each
}
return ret
}
i++
}
return s
}
// HasEmpty checks if there are empty strings in args. // HasEmpty checks if there are empty strings in args.
func HasEmpty(args ...string) bool { func HasEmpty(args ...string) bool {
for _, arg := range args { for _, arg := range args {

View File

@@ -92,6 +92,61 @@ func TestFilter(t *testing.T) {
} }
} }
func TestFirstN(t *testing.T) {
tests := []struct {
name string
input string
n int
ellipsis string
expect string
}{
{
name: "english string",
input: "anything that we use",
n: 8,
expect: "anything",
},
{
name: "english string with ellipsis",
input: "anything that we use",
n: 8,
ellipsis: "...",
expect: "anything...",
},
{
name: "english string more",
input: "anything that we use",
n: 80,
expect: "anything that we use",
},
{
name: "chinese string",
input: "我是中国人",
n: 2,
expect: "我是",
},
{
name: "chinese string with ellipsis",
input: "我是中国人",
n: 2,
ellipsis: "...",
expect: "我是...",
},
{
name: "chinese string",
input: "我是中国人",
n: 10,
expect: "我是中国人",
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
assert.Equal(t, test.expect, FirstN(test.input, test.n, test.ellipsis))
})
}
}
func TestRemove(t *testing.T) { func TestRemove(t *testing.T) {
cases := []struct { cases := []struct {
input []string input []string

View File

@@ -9,16 +9,16 @@ import (
// A ResourceManager is a manager that used to manage resources. // A ResourceManager is a manager that used to manage resources.
type ResourceManager struct { type ResourceManager struct {
resources map[string]io.Closer resources map[string]io.Closer
sharedCalls SharedCalls singleFlight SingleFlight
lock sync.RWMutex lock sync.RWMutex
} }
// NewResourceManager returns a ResourceManager. // NewResourceManager returns a ResourceManager.
func NewResourceManager() *ResourceManager { func NewResourceManager() *ResourceManager {
return &ResourceManager{ return &ResourceManager{
resources: make(map[string]io.Closer), resources: make(map[string]io.Closer),
sharedCalls: NewSharedCalls(), singleFlight: NewSingleFlight(),
} }
} }
@@ -39,7 +39,7 @@ func (manager *ResourceManager) Close() error {
// GetResource returns the resource associated with given key. // GetResource returns the resource associated with given key.
func (manager *ResourceManager) GetResource(key string, create func() (io.Closer, error)) (io.Closer, error) { func (manager *ResourceManager) GetResource(key string, create func() (io.Closer, error)) (io.Closer, error) {
val, err := manager.sharedCalls.Do(key, func() (interface{}, error) { val, err := manager.singleFlight.Do(key, func() (interface{}, error) {
manager.lock.RLock() manager.lock.RLock()
resource, ok := manager.resources[key] resource, ok := manager.resources[key]
manager.lock.RUnlock() manager.lock.RUnlock()

View File

@@ -3,13 +3,17 @@ package syncx
import "sync" import "sync"
type ( type (
// SharedCalls lets the concurrent calls with the same key to share the call result. // SharedCalls is an alias of SingleFlight.
// Deprecated: use SingleFlight.
SharedCalls = SingleFlight
// SingleFlight lets the concurrent calls with the same key to share the call result.
// For example, A called F, before it's done, B called F. Then B would not execute F, // For example, A called F, before it's done, B called F. Then B would not execute F,
// and shared the result returned by F which called by A. // and shared the result returned by F which called by A.
// The calls with the same key are dependent, concurrent calls share the returned values. // The calls with the same key are dependent, concurrent calls share the returned values.
// A ------->calls F with key<------------------->returns val // A ------->calls F with key<------------------->returns val
// B --------------------->calls F with key------>returns val // B --------------------->calls F with key------>returns val
SharedCalls interface { SingleFlight interface {
Do(key string, fn func() (interface{}, error)) (interface{}, error) Do(key string, fn func() (interface{}, error)) (interface{}, error)
DoEx(key string, fn func() (interface{}, error)) (interface{}, bool, error) DoEx(key string, fn func() (interface{}, error)) (interface{}, bool, error)
} }
@@ -20,20 +24,26 @@ type (
err error err error
} }
sharedGroup struct { flightGroup struct {
calls map[string]*call calls map[string]*call
lock sync.Mutex lock sync.Mutex
} }
) )
// NewSharedCalls returns a SharedCalls. // NewSingleFlight returns a SingleFlight.
func NewSharedCalls() SharedCalls { func NewSingleFlight() SingleFlight {
return &sharedGroup{ return &flightGroup{
calls: make(map[string]*call), calls: make(map[string]*call),
} }
} }
func (g *sharedGroup) Do(key string, fn func() (interface{}, error)) (interface{}, error) { // NewSharedCalls returns a SingleFlight.
// Deprecated: use NewSingleFlight.
func NewSharedCalls() SingleFlight {
return NewSingleFlight()
}
func (g *flightGroup) Do(key string, fn func() (interface{}, error)) (interface{}, error) {
c, done := g.createCall(key) c, done := g.createCall(key)
if done { if done {
return c.val, c.err return c.val, c.err
@@ -43,7 +53,7 @@ func (g *sharedGroup) Do(key string, fn func() (interface{}, error)) (interface{
return c.val, c.err return c.val, c.err
} }
func (g *sharedGroup) DoEx(key string, fn func() (interface{}, error)) (val interface{}, fresh bool, err error) { func (g *flightGroup) DoEx(key string, fn func() (interface{}, error)) (val interface{}, fresh bool, err error) {
c, done := g.createCall(key) c, done := g.createCall(key)
if done { if done {
return c.val, false, c.err return c.val, false, c.err
@@ -53,7 +63,7 @@ func (g *sharedGroup) DoEx(key string, fn func() (interface{}, error)) (val inte
return c.val, true, c.err return c.val, true, c.err
} }
func (g *sharedGroup) createCall(key string) (c *call, done bool) { func (g *flightGroup) createCall(key string) (c *call, done bool) {
g.lock.Lock() g.lock.Lock()
if c, ok := g.calls[key]; ok { if c, ok := g.calls[key]; ok {
g.lock.Unlock() g.lock.Unlock()
@@ -69,7 +79,7 @@ func (g *sharedGroup) createCall(key string) (c *call, done bool) {
return c, false return c, false
} }
func (g *sharedGroup) makeCall(c *call, key string, fn func() (interface{}, error)) { func (g *flightGroup) makeCall(c *call, key string, fn func() (interface{}, error)) {
defer func() { defer func() {
g.lock.Lock() g.lock.Lock()
delete(g.calls, key) delete(g.calls, key)

View File

@@ -10,7 +10,7 @@ import (
) )
func TestExclusiveCallDo(t *testing.T) { func TestExclusiveCallDo(t *testing.T) {
g := NewSharedCalls() g := NewSingleFlight()
v, err := g.Do("key", func() (interface{}, error) { v, err := g.Do("key", func() (interface{}, error) {
return "bar", nil return "bar", nil
}) })
@@ -23,7 +23,7 @@ func TestExclusiveCallDo(t *testing.T) {
} }
func TestExclusiveCallDoErr(t *testing.T) { func TestExclusiveCallDoErr(t *testing.T) {
g := NewSharedCalls() g := NewSingleFlight()
someErr := errors.New("some error") someErr := errors.New("some error")
v, err := g.Do("key", func() (interface{}, error) { v, err := g.Do("key", func() (interface{}, error) {
return nil, someErr return nil, someErr
@@ -37,7 +37,7 @@ func TestExclusiveCallDoErr(t *testing.T) {
} }
func TestExclusiveCallDoDupSuppress(t *testing.T) { func TestExclusiveCallDoDupSuppress(t *testing.T) {
g := NewSharedCalls() g := NewSingleFlight()
c := make(chan string) c := make(chan string)
var calls int32 var calls int32
fn := func() (interface{}, error) { fn := func() (interface{}, error) {
@@ -69,7 +69,7 @@ func TestExclusiveCallDoDupSuppress(t *testing.T) {
} }
func TestExclusiveCallDoDiffDupSuppress(t *testing.T) { func TestExclusiveCallDoDiffDupSuppress(t *testing.T) {
g := NewSharedCalls() g := NewSingleFlight()
broadcast := make(chan struct{}) broadcast := make(chan struct{})
var calls int32 var calls int32
tests := []string{"e", "a", "e", "a", "b", "c", "b", "a", "c", "d", "b", "c", "d"} tests := []string{"e", "a", "e", "a", "b", "c", "b", "a", "c", "d", "b", "c", "d"}
@@ -102,7 +102,7 @@ func TestExclusiveCallDoDiffDupSuppress(t *testing.T) {
} }
func TestExclusiveCallDoExDupSuppress(t *testing.T) { func TestExclusiveCallDoExDupSuppress(t *testing.T) {
g := NewSharedCalls() g := NewSingleFlight()
c := make(chan string) c := make(chan string)
var calls int32 var calls int32
fn := func() (interface{}, error) { fn := func() (interface{}, error) {

View File

@@ -1,6 +1,8 @@
package trace package trace
const ( const (
traceIdKey = "X-Trace-ID" // TraceIdKey is the trace id header.
spanIdKey = "X-Span-ID" TraceIdKey = "X-Trace-ID"
spanIdKey = "X-Span-ID"
) )

View File

@@ -0,0 +1,68 @@
package opentelemetry
import (
"sync"
"github.com/tal-tech/go-zero/core/logx"
"github.com/tal-tech/go-zero/core/syncx"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/exporters/jaeger"
"go.opentelemetry.io/otel/propagation"
"go.opentelemetry.io/otel/sdk/resource"
sdktrace "go.opentelemetry.io/otel/sdk/trace"
semconv "go.opentelemetry.io/otel/semconv/v1.4.0"
)
var (
once sync.Once
enabled syncx.AtomicBool
)
// Enabled returns if opentelemetry is enabled.
func Enabled() bool {
return enabled.True()
}
// StartAgent starts a opentelemetry agent.
func StartAgent(c Config) {
once.Do(func() {
if len(c.Endpoint) == 0 {
return
}
// Just support jaeger now
if c.Batcher != "jaeger" {
return
}
exp, err := jaeger.New(jaeger.WithCollectorEndpoint(jaeger.WithEndpoint(c.Endpoint)))
if err != nil {
logx.Error(err)
return
}
tp := sdktrace.NewTracerProvider(
// Set the sampling rate based on the parent span to 100%
sdktrace.WithSampler(sdktrace.ParentBased(sdktrace.TraceIDRatioBased(c.Sampler))),
// Always be sure to batch in production.
sdktrace.WithBatcher(exp),
// Record information about this application in an Resource.
sdktrace.WithResource(resource.NewSchemaless(semconv.ServiceNameKey.String(c.Name))),
)
otel.SetTracerProvider(tp)
otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{}))
otel.SetErrorHandler(otelErrHandler{})
enabled.Set(true)
})
}
// errHandler handing otel errors.
type otelErrHandler struct{}
var _ otel.ErrorHandler = otelErrHandler{}
func (o otelErrHandler) Handle(err error) {
logx.Errorf("[otel] error: %v", err)
}

View File

@@ -0,0 +1,40 @@
package opentelemetry
import (
"go.opentelemetry.io/otel/attribute"
semconv "go.opentelemetry.io/otel/semconv/v1.4.0"
gcodes "google.golang.org/grpc/codes"
)
const (
// GRPCStatusCodeKey is convention for numeric status code of a gRPC request.
GRPCStatusCodeKey = attribute.Key("rpc.grpc.status_code")
// RPCNameKey is the name of message transmitted or received.
RPCNameKey = attribute.Key("name")
// RPCMessageTypeKey is the type of message transmitted or received.
RPCMessageTypeKey = attribute.Key("message.type")
// RPCMessageIDKey is the identifier of message transmitted or received.
RPCMessageIDKey = attribute.Key("message.id")
// RPCMessageCompressedSizeKey is the compressed size of the message transmitted or received in bytes.
RPCMessageCompressedSizeKey = attribute.Key("message.compressed_size")
// RPCMessageUncompressedSizeKey is the uncompressed size of the message
// transmitted or received in bytes.
RPCMessageUncompressedSizeKey = attribute.Key("message.uncompressed_size")
)
// Semantic conventions for common RPC attributes.
var (
// RPCSystemGRPC is the semantic convention for gRPC as the remoting system.
RPCSystemGRPC = semconv.RPCSystemKey.String("grpc")
// RPCNameMessage is the semantic convention for a message named message.
RPCNameMessage = RPCNameKey.String("message")
// RPCMessageTypeSent is the semantic conventions for sent RPC message types.
RPCMessageTypeSent = RPCMessageTypeKey.String("SENT")
// RPCMessageTypeReceived is the semantic conventions for the received RPC message types.
RPCMessageTypeReceived = RPCMessageTypeKey.String("RECEIVED")
)
// StatusCodeAttr returns a attribute.KeyValue that represents the give c.
func StatusCodeAttr(c gcodes.Code) attribute.KeyValue {
return GRPCStatusCodeKey.Int64(int64(c))
}

View File

@@ -0,0 +1,121 @@
package opentelemetry
import (
"context"
"io"
"google.golang.org/grpc"
"google.golang.org/grpc/metadata"
)
const (
receiveEndEvent streamEventType = iota
errorEvent
)
type (
streamEventType int
streamEvent struct {
Type streamEventType
Err error
}
clientStream struct {
grpc.ClientStream
Finished chan error
desc *grpc.StreamDesc
events chan streamEvent
eventsDone chan struct{}
receivedMessageID int
sentMessageID int
}
)
func (w *clientStream) RecvMsg(m interface{}) error {
err := w.ClientStream.RecvMsg(m)
if err == nil && !w.desc.ServerStreams {
w.sendStreamEvent(receiveEndEvent, nil)
} else if err == io.EOF {
w.sendStreamEvent(receiveEndEvent, nil)
} else if err != nil {
w.sendStreamEvent(errorEvent, err)
} else {
w.receivedMessageID++
MessageReceived.Event(w.Context(), w.receivedMessageID, m)
}
return err
}
func (w *clientStream) SendMsg(m interface{}) error {
err := w.ClientStream.SendMsg(m)
w.sentMessageID++
MessageSent.Event(w.Context(), w.sentMessageID, m)
if err != nil {
w.sendStreamEvent(errorEvent, err)
}
return err
}
func (w *clientStream) Header() (metadata.MD, error) {
md, err := w.ClientStream.Header()
if err != nil {
w.sendStreamEvent(errorEvent, err)
}
return md, err
}
func (w *clientStream) CloseSend() error {
err := w.ClientStream.CloseSend()
if err != nil {
w.sendStreamEvent(errorEvent, err)
}
return err
}
func (w *clientStream) sendStreamEvent(eventType streamEventType, err error) {
select {
case <-w.eventsDone:
case w.events <- streamEvent{Type: eventType, Err: err}:
}
}
// WrapClientStream wraps s with given ctx and desc.
func WrapClientStream(ctx context.Context, s grpc.ClientStream, desc *grpc.StreamDesc) *clientStream {
events := make(chan streamEvent)
eventsDone := make(chan struct{})
finished := make(chan error)
go func() {
defer close(eventsDone)
for {
select {
case event := <-events:
switch event.Type {
case receiveEndEvent:
finished <- nil
return
case errorEvent:
finished <- event.Err
return
}
case <-ctx.Done():
finished <- ctx.Err()
return
}
}
}()
return &clientStream{
ClientStream: s,
desc: desc,
events: events,
eventsDone: eventsDone,
Finished: finished,
}
}

View File

@@ -0,0 +1,12 @@
package opentelemetry
// TraceName represents the tracing name.
const TraceName = "go-zero"
// A Config is a opentelemetry config.
type Config struct {
Name string `json:",optional"`
Endpoint string `json:",optional"`
Sampler float64 `json:",default=1.0"`
Batcher string `json:",default=jaeger"`
}

View File

@@ -0,0 +1,38 @@
package opentelemetry
import (
"context"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/trace"
"google.golang.org/protobuf/proto"
)
const messageEvent = "message"
var (
// MessageSent is the type of sent messages.
MessageSent = messageType(RPCMessageTypeSent)
// MessageReceived is the type of received messages.
MessageReceived = messageType(RPCMessageTypeReceived)
)
type messageType attribute.KeyValue
// Event adds an event of the messageType to the span associated with the
// passed context with id and size (if message is a proto message).
func (m messageType) Event(ctx context.Context, id int, message interface{}) {
span := trace.SpanFromContext(ctx)
if p, ok := message.(proto.Message); ok {
span.AddEvent(messageEvent, trace.WithAttributes(
attribute.KeyValue(m),
RPCMessageIDKey.Int(id),
RPCMessageUncompressedSizeKey.Int(proto.Size(p)),
))
} else {
span.AddEvent(messageEvent, trace.WithAttributes(
attribute.KeyValue(m),
RPCMessageIDKey.Int(id),
))
}
}

View File

@@ -0,0 +1,47 @@
package opentelemetry
import (
"context"
"google.golang.org/grpc"
)
// serverStream wraps around the embedded grpc.ServerStream, and intercepts the RecvMsg and
// SendMsg method call.
type serverStream struct {
grpc.ServerStream
ctx context.Context
receivedMessageID int
sentMessageID int
}
func (w *serverStream) Context() context.Context {
return w.ctx
}
func (w *serverStream) RecvMsg(m interface{}) error {
err := w.ServerStream.RecvMsg(m)
if err == nil {
w.receivedMessageID++
MessageReceived.Event(w.Context(), w.receivedMessageID, m)
}
return err
}
func (w *serverStream) SendMsg(m interface{}) error {
err := w.ServerStream.SendMsg(m)
w.sentMessageID++
MessageSent.Event(w.Context(), w.sentMessageID, m)
return err
}
// WrapServerStream wraps the given grpc.ServerStream with the given context.
func WrapServerStream(ctx context.Context, ss grpc.ServerStream) *serverStream {
return &serverStream{
ServerStream: ss,
ctx: ctx,
}
}

View File

@@ -0,0 +1,56 @@
package opentelemetry
import (
"context"
"go.opentelemetry.io/otel/baggage"
"go.opentelemetry.io/otel/propagation"
sdktrace "go.opentelemetry.io/otel/trace"
"google.golang.org/grpc/metadata"
)
// assert that metadataSupplier implements the TextMapCarrier interface
var _ propagation.TextMapCarrier = new(metadataSupplier)
type metadataSupplier struct {
metadata *metadata.MD
}
func (s *metadataSupplier) Get(key string) string {
values := s.metadata.Get(key)
if len(values) == 0 {
return ""
}
return values[0]
}
func (s *metadataSupplier) Set(key, value string) {
s.metadata.Set(key, value)
}
func (s *metadataSupplier) Keys() []string {
out := make([]string, 0, len(*s.metadata))
for key := range *s.metadata {
out = append(out, key)
}
return out
}
// Inject injects the metadata into ctx.
func Inject(ctx context.Context, p propagation.TextMapPropagator, metadata *metadata.MD) {
p.Inject(ctx, &metadataSupplier{
metadata: metadata,
})
}
// Extract extracts the metadata from ctx.
func Extract(ctx context.Context, p propagation.TextMapPropagator, metadata *metadata.MD) (
baggage.Baggage, sdktrace.SpanContext) {
ctx = p.Extract(ctx, &metadataSupplier{
metadata: metadata,
})
return baggage.FromContext(ctx), sdktrace.SpanContextFromContext(ctx)
}

View File

@@ -0,0 +1,346 @@
package opentelemetry
import (
"context"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/propagation"
"go.opentelemetry.io/otel/trace"
"google.golang.org/grpc/metadata"
)
const (
traceIDStr = "4bf92f3577b34da6a3ce929d0e0e4736"
spanIDStr = "00f067aa0ba902b7"
)
var (
traceID = mustTraceIDFromHex(traceIDStr)
spanID = mustSpanIDFromHex(spanIDStr)
)
func mustTraceIDFromHex(s string) (t trace.TraceID) {
var err error
t, err = trace.TraceIDFromHex(s)
if err != nil {
panic(err)
}
return
}
func mustSpanIDFromHex(s string) (t trace.SpanID) {
var err error
t, err = trace.SpanIDFromHex(s)
if err != nil {
panic(err)
}
return
}
func TestExtractValidTraceContext(t *testing.T) {
stateStr := "key1=value1,key2=value2"
state, err := trace.ParseTraceState(stateStr)
require.NoError(t, err)
tests := []struct {
name string
traceparent string
tracestate string
sc trace.SpanContext
}{
{
name: "not sampled",
traceparent: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00",
sc: trace.NewSpanContext(trace.SpanContextConfig{
TraceID: traceID,
SpanID: spanID,
Remote: true,
}),
},
{
name: "sampled",
traceparent: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01",
sc: trace.NewSpanContext(trace.SpanContextConfig{
TraceID: traceID,
SpanID: spanID,
TraceFlags: trace.FlagsSampled,
Remote: true,
}),
},
{
name: "valid tracestate",
traceparent: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00",
tracestate: stateStr,
sc: trace.NewSpanContext(trace.SpanContextConfig{
TraceID: traceID,
SpanID: spanID,
TraceState: state,
Remote: true,
}),
},
{
name: "invalid tracestate perserves traceparent",
traceparent: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00",
tracestate: "invalid$@#=invalid",
sc: trace.NewSpanContext(trace.SpanContextConfig{
TraceID: traceID,
SpanID: spanID,
Remote: true,
}),
},
{
name: "future version not sampled",
traceparent: "02-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00",
sc: trace.NewSpanContext(trace.SpanContextConfig{
TraceID: traceID,
SpanID: spanID,
Remote: true,
}),
},
{
name: "future version sampled",
traceparent: "02-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01",
sc: trace.NewSpanContext(trace.SpanContextConfig{
TraceID: traceID,
SpanID: spanID,
TraceFlags: trace.FlagsSampled,
Remote: true,
}),
},
{
name: "future version sample bit set",
traceparent: "02-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-09",
sc: trace.NewSpanContext(trace.SpanContextConfig{
TraceID: traceID,
SpanID: spanID,
TraceFlags: trace.FlagsSampled,
Remote: true,
}),
},
{
name: "future version sample bit not set",
traceparent: "02-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-08",
sc: trace.NewSpanContext(trace.SpanContextConfig{
TraceID: traceID,
SpanID: spanID,
Remote: true,
}),
},
{
name: "future version additional data",
traceparent: "02-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00-XYZxsf09",
sc: trace.NewSpanContext(trace.SpanContextConfig{
TraceID: traceID,
SpanID: spanID,
Remote: true,
}),
},
{
name: "B3 format ending in dash",
traceparent: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00-",
sc: trace.NewSpanContext(trace.SpanContextConfig{
TraceID: traceID,
SpanID: spanID,
Remote: true,
}),
},
{
name: "future version B3 format ending in dash",
traceparent: "03-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00-",
sc: trace.NewSpanContext(trace.SpanContextConfig{
TraceID: traceID,
SpanID: spanID,
Remote: true,
}),
},
}
otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{}))
propagator := otel.GetTextMapPropagator()
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ctx := context.Background()
md := metadata.MD{}
md.Set("traceparent", tt.traceparent)
md.Set("tracestate", tt.tracestate)
_, spanCtx := Extract(ctx, propagator, &md)
assert.Equal(t, tt.sc, spanCtx)
})
}
}
func TestExtractInvalidTraceContext(t *testing.T) {
tests := []struct {
name string
header string
}{
{
name: "wrong version length",
header: "0000-00000000000000000000000000000000-0000000000000000-01",
},
{
name: "wrong trace ID length",
header: "00-ab00000000000000000000000000000000-cd00000000000000-01",
},
{
name: "wrong span ID length",
header: "00-ab000000000000000000000000000000-cd0000000000000000-01",
},
{
name: "wrong trace flag length",
header: "00-ab000000000000000000000000000000-cd00000000000000-0100",
},
{
name: "bogus version",
header: "qw-00000000000000000000000000000000-0000000000000000-01",
},
{
name: "bogus trace ID",
header: "00-qw000000000000000000000000000000-cd00000000000000-01",
},
{
name: "bogus span ID",
header: "00-ab000000000000000000000000000000-qw00000000000000-01",
},
{
name: "bogus trace flag",
header: "00-ab000000000000000000000000000000-cd00000000000000-qw",
},
{
name: "upper case version",
header: "A0-00000000000000000000000000000000-0000000000000000-01",
},
{
name: "upper case trace ID",
header: "00-AB000000000000000000000000000000-cd00000000000000-01",
},
{
name: "upper case span ID",
header: "00-ab000000000000000000000000000000-CD00000000000000-01",
},
{
name: "upper case trace flag",
header: "00-ab000000000000000000000000000000-cd00000000000000-A1",
},
{
name: "zero trace ID and span ID",
header: "00-00000000000000000000000000000000-0000000000000000-01",
},
{
name: "trace-flag unused bits set",
header: "00-ab000000000000000000000000000000-cd00000000000000-09",
},
{
name: "missing options",
header: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7",
},
{
name: "empty options",
header: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-",
},
}
otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{}))
propagator := otel.GetTextMapPropagator()
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ctx := context.Background()
md := metadata.MD{}
md.Set("traceparent", tt.header)
_, spanCtx := Extract(ctx, propagator, &md)
assert.Equal(t, trace.SpanContext{}, spanCtx)
})
}
}
func TestInjectValidTraceContext(t *testing.T) {
stateStr := "key1=value1,key2=value2"
state, err := trace.ParseTraceState(stateStr)
require.NoError(t, err)
tests := []struct {
name string
traceparent string
tracestate string
sc trace.SpanContext
}{
{
name: "not sampled",
traceparent: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00",
sc: trace.NewSpanContext(trace.SpanContextConfig{
TraceID: traceID,
SpanID: spanID,
Remote: true,
}),
},
{
name: "sampled",
traceparent: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01",
sc: trace.NewSpanContext(trace.SpanContextConfig{
TraceID: traceID,
SpanID: spanID,
TraceFlags: trace.FlagsSampled,
Remote: true,
}),
},
{
name: "unsupported trace flag bits dropped",
traceparent: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01",
sc: trace.NewSpanContext(trace.SpanContextConfig{
TraceID: traceID,
SpanID: spanID,
TraceFlags: 0xff,
Remote: true,
}),
},
{
name: "with tracestate",
traceparent: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00",
tracestate: stateStr,
sc: trace.NewSpanContext(trace.SpanContextConfig{
TraceID: traceID,
SpanID: spanID,
TraceState: state,
Remote: true,
}),
},
}
otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{}))
propagator := otel.GetTextMapPropagator()
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ctx := context.Background()
ctx = trace.ContextWithRemoteSpanContext(ctx, tt.sc)
want := metadata.MD{}
want.Set("traceparent", tt.traceparent)
if len(tt.tracestate) > 0 {
want.Set("tracestate", tt.tracestate)
}
md := metadata.MD{}
Inject(ctx, propagator, &md)
assert.Equal(t, want, md)
})
}
}
func TestInvalidSpanContextDropped(t *testing.T) {
invalidSC := trace.SpanContext{}
require.False(t, invalidSC.IsValid())
ctx := trace.ContextWithRemoteSpanContext(context.Background(), invalidSC)
otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{}))
propagator := otel.GetTextMapPropagator()
md := metadata.MD{}
Inject(ctx, propagator, &md)
mm := &metadataSupplier{
metadata: &md,
}
assert.Equal(t, "", mm.Get("traceparent"), "injected invalid SpanContext")
}

View File

@@ -0,0 +1,69 @@
package opentelemetry
import (
"context"
"net"
"strings"
"go.opentelemetry.io/otel/attribute"
semconv "go.opentelemetry.io/otel/semconv/v1.4.0"
"google.golang.org/grpc/peer"
)
const localhost = "127.0.0.1"
// PeerFromCtx returns the peer from ctx.
func PeerFromCtx(ctx context.Context) string {
p, ok := peer.FromContext(ctx)
if !ok {
return ""
}
return p.Addr.String()
}
// SpanInfo returns the span info.
func SpanInfo(fullMethod, peerAddress string) (string, []attribute.KeyValue) {
attrs := []attribute.KeyValue{RPCSystemGRPC}
name, mAttrs := ParseFullMethod(fullMethod)
attrs = append(attrs, mAttrs...)
attrs = append(attrs, PeerAttr(peerAddress)...)
return name, attrs
}
// ParseFullMethod returns the method name and attributes.
func ParseFullMethod(fullMethod string) (string, []attribute.KeyValue) {
name := strings.TrimLeft(fullMethod, "/")
parts := strings.SplitN(name, "/", 2)
if len(parts) != 2 {
// Invalid format, does not follow `/package.service/method`.
return name, []attribute.KeyValue(nil)
}
var attrs []attribute.KeyValue
if service := parts[0]; service != "" {
attrs = append(attrs, semconv.RPCServiceKey.String(service))
}
if method := parts[1]; method != "" {
attrs = append(attrs, semconv.RPCMethodKey.String(method))
}
return name, attrs
}
// PeerAttr returns the peer attributes.
func PeerAttr(addr string) []attribute.KeyValue {
host, port, err := net.SplitHostPort(addr)
if err != nil {
return []attribute.KeyValue(nil)
}
if len(host) == 0 {
host = localhost
}
return []attribute.KeyValue{
semconv.NetPeerIPKey.String(host),
semconv.NetPeerPortKey.String(port),
}
}

View File

@@ -0,0 +1,70 @@
package opentelemetry
import (
"testing"
"github.com/stretchr/testify/assert"
"go.opentelemetry.io/otel/attribute"
semconv "go.opentelemetry.io/otel/semconv/v1.4.0"
)
func TestParseFullMethod(t *testing.T) {
tests := []struct {
fullMethod string
name string
attr []attribute.KeyValue
}{
{
fullMethod: "/grpc.test.EchoService/Echo",
name: "grpc.test.EchoService/Echo",
attr: []attribute.KeyValue{
semconv.RPCServiceKey.String("grpc.test.EchoService"),
semconv.RPCMethodKey.String("Echo"),
},
}, {
fullMethod: "/com.example.ExampleRmiService/exampleMethod",
name: "com.example.ExampleRmiService/exampleMethod",
attr: []attribute.KeyValue{
semconv.RPCServiceKey.String("com.example.ExampleRmiService"),
semconv.RPCMethodKey.String("exampleMethod"),
},
}, {
fullMethod: "/MyCalcService.Calculator/Add",
name: "MyCalcService.Calculator/Add",
attr: []attribute.KeyValue{
semconv.RPCServiceKey.String("MyCalcService.Calculator"),
semconv.RPCMethodKey.String("Add"),
},
}, {
fullMethod: "/MyServiceReference.ICalculator/Add",
name: "MyServiceReference.ICalculator/Add",
attr: []attribute.KeyValue{
semconv.RPCServiceKey.String("MyServiceReference.ICalculator"),
semconv.RPCMethodKey.String("Add"),
},
}, {
fullMethod: "/MyServiceWithNoPackage/theMethod",
name: "MyServiceWithNoPackage/theMethod",
attr: []attribute.KeyValue{
semconv.RPCServiceKey.String("MyServiceWithNoPackage"),
semconv.RPCMethodKey.String("theMethod"),
},
}, {
fullMethod: "/pkg.srv",
name: "pkg.srv",
attr: []attribute.KeyValue(nil),
}, {
fullMethod: "/pkg.srv/",
name: "pkg.srv/",
attr: []attribute.KeyValue{
semconv.RPCServiceKey.String("pkg.srv"),
},
},
}
for _, test := range tests {
n, a := ParseFullMethod(test.fullMethod)
assert.Equal(t, test.name, n)
assert.Equal(t, test.attr, a)
}
}

View File

@@ -11,11 +11,11 @@ import (
func TestHttpPropagator_Extract(t *testing.T) { func TestHttpPropagator_Extract(t *testing.T) {
req := httptest.NewRequest(http.MethodGet, "http://localhost", nil) req := httptest.NewRequest(http.MethodGet, "http://localhost", nil)
req.Header.Set(traceIdKey, "trace") req.Header.Set(TraceIdKey, "trace")
req.Header.Set(spanIdKey, "span") req.Header.Set(spanIdKey, "span")
carrier, err := Extract(HttpFormat, req.Header) carrier, err := Extract(HttpFormat, req.Header)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, "trace", carrier.Get(traceIdKey)) assert.Equal(t, "trace", carrier.Get(TraceIdKey))
assert.Equal(t, "span", carrier.Get(spanIdKey)) assert.Equal(t, "span", carrier.Get(spanIdKey))
_, err = Extract(HttpFormat, req) _, err = Extract(HttpFormat, req)
@@ -24,11 +24,11 @@ func TestHttpPropagator_Extract(t *testing.T) {
func TestHttpPropagator_Inject(t *testing.T) { func TestHttpPropagator_Inject(t *testing.T) {
req := httptest.NewRequest(http.MethodGet, "http://localhost", nil) req := httptest.NewRequest(http.MethodGet, "http://localhost", nil)
req.Header.Set(traceIdKey, "trace") req.Header.Set(TraceIdKey, "trace")
req.Header.Set(spanIdKey, "span") req.Header.Set(spanIdKey, "span")
carrier, err := Inject(HttpFormat, req.Header) carrier, err := Inject(HttpFormat, req.Header)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, "trace", carrier.Get(traceIdKey)) assert.Equal(t, "trace", carrier.Get(TraceIdKey))
assert.Equal(t, "span", carrier.Get(spanIdKey)) assert.Equal(t, "span", carrier.Get(spanIdKey))
_, err = Inject(HttpFormat, req) _, err = Inject(HttpFormat, req)
@@ -37,12 +37,12 @@ func TestHttpPropagator_Inject(t *testing.T) {
func TestGrpcPropagator_Extract(t *testing.T) { func TestGrpcPropagator_Extract(t *testing.T) {
md := metadata.New(map[string]string{ md := metadata.New(map[string]string{
traceIdKey: "trace", TraceIdKey: "trace",
spanIdKey: "span", spanIdKey: "span",
}) })
carrier, err := Extract(GrpcFormat, md) carrier, err := Extract(GrpcFormat, md)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, "trace", carrier.Get(traceIdKey)) assert.Equal(t, "trace", carrier.Get(TraceIdKey))
assert.Equal(t, "span", carrier.Get(spanIdKey)) assert.Equal(t, "span", carrier.Get(spanIdKey))
_, err = Extract(GrpcFormat, 1) _, err = Extract(GrpcFormat, 1)
@@ -53,12 +53,12 @@ func TestGrpcPropagator_Extract(t *testing.T) {
func TestGrpcPropagator_Inject(t *testing.T) { func TestGrpcPropagator_Inject(t *testing.T) {
md := metadata.New(map[string]string{ md := metadata.New(map[string]string{
traceIdKey: "trace", TraceIdKey: "trace",
spanIdKey: "span", spanIdKey: "span",
}) })
carrier, err := Inject(GrpcFormat, md) carrier, err := Inject(GrpcFormat, md)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, "trace", carrier.Get(traceIdKey)) assert.Equal(t, "trace", carrier.Get(TraceIdKey))
assert.Equal(t, "span", carrier.Get(spanIdKey)) assert.Equal(t, "span", carrier.Get(spanIdKey))
_, err = Inject(GrpcFormat, 1) _, err = Inject(GrpcFormat, 1)

View File

@@ -34,7 +34,7 @@ type Span struct {
func newServerSpan(carrier Carrier, serviceName, operationName string) tracespec.Trace { func newServerSpan(carrier Carrier, serviceName, operationName string) tracespec.Trace {
traceId := stringx.TakeWithPriority(func() string { traceId := stringx.TakeWithPriority(func() string {
if carrier != nil { if carrier != nil {
return carrier.Get(traceIdKey) return carrier.Get(TraceIdKey)
} }
return "" return ""
}, stringx.RandId) }, stringx.RandId)

View File

@@ -57,7 +57,7 @@ func TestServerSpan(t *testing.T) {
func TestServerSpan_WithCarrier(t *testing.T) { func TestServerSpan_WithCarrier(t *testing.T) {
md := metadata.New(map[string]string{ md := metadata.New(map[string]string{
traceIdKey: "a", TraceIdKey: "a",
spanIdKey: "0.1", spanIdKey: "0.1",
}) })
ctx, span := StartServerSpan(context.Background(), grpcCarrier(md), "service", "operation") ctx, span := StartServerSpan(context.Background(), grpcCarrier(md), "service", "operation")
@@ -99,7 +99,7 @@ func TestSpan_Follow(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(stringx.RandId(), func(t *testing.T) { t.Run(stringx.RandId(), func(t *testing.T) {
md := metadata.New(map[string]string{ md := metadata.New(map[string]string{
traceIdKey: "a", TraceIdKey: "a",
spanIdKey: test.span, spanIdKey: test.span,
}) })
ctx, span := StartServerSpan(context.Background(), grpcCarrier(md), ctx, span := StartServerSpan(context.Background(), grpcCarrier(md),

View File

@@ -14,6 +14,6 @@ func (sc spanContext) SpanId() string {
} }
func (sc spanContext) Visit(fn func(key, val string) bool) { func (sc spanContext) Visit(fn func(key, val string) bool) {
fn(traceIdKey, sc.traceId) fn(TraceIdKey, sc.traceId)
fn(spanIdKey, sc.spanId) fn(spanIdKey, sc.spanId)
} }

18
go.mod
View File

@@ -21,14 +21,10 @@ require (
github.com/google/uuid v1.1.2 github.com/google/uuid v1.1.2
github.com/iancoleman/strcase v0.1.2 github.com/iancoleman/strcase v0.1.2
github.com/justinas/alice v1.2.0 github.com/justinas/alice v1.2.0
github.com/kr/pretty v0.2.0 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/lib/pq v1.3.0 github.com/lib/pq v1.3.0
github.com/logrusorgru/aurora v2.0.3+incompatible github.com/logrusorgru/aurora v2.0.3+incompatible
github.com/mattn/go-colorable v0.1.6 // indirect github.com/mattn/go-colorable v0.1.6 // indirect
github.com/olekukonko/tablewriter v0.0.5 github.com/olekukonko/tablewriter v0.0.5
github.com/onsi/ginkgo v1.7.0 // indirect
github.com/onsi/gomega v1.5.0 // indirect
github.com/pierrec/lz4 v2.5.1+incompatible // indirect github.com/pierrec/lz4 v2.5.1+incompatible // indirect
github.com/prometheus/client_golang v1.11.0 github.com/prometheus/client_golang v1.11.0
github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect
@@ -36,16 +32,24 @@ require (
github.com/stretchr/testify v1.7.0 github.com/stretchr/testify v1.7.0
github.com/urfave/cli v1.22.5 github.com/urfave/cli v1.22.5
github.com/zeromicro/antlr v0.0.1 github.com/zeromicro/antlr v0.0.1
github.com/zeromicro/ddl-parser v0.0.0-20210712021150-63520aca7348 // indirect github.com/zeromicro/ddl-parser v0.0.0-20210712021150-63520aca7348
go.etcd.io/etcd/api/v3 v3.5.0 go.etcd.io/etcd/api/v3 v3.5.0
go.etcd.io/etcd/client/v3 v3.5.0 go.etcd.io/etcd/client/v3 v3.5.0
go.opentelemetry.io/otel v1.0.0-RC2
go.opentelemetry.io/otel/exporters/jaeger v1.0.0-RC2
go.opentelemetry.io/otel/sdk v1.0.0-RC2
go.opentelemetry.io/otel/trace v1.0.0-RC2
go.uber.org/automaxprocs v1.3.0 go.uber.org/automaxprocs v1.3.0
golang.org/x/net v0.0.0-20210716203947-853a461950ff golang.org/x/net v0.0.0-20210716203947-853a461950ff
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c // indirect golang.org/x/sys v0.0.0-20210820121016-41cdb8703e55 // indirect
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac
google.golang.org/genproto v0.0.0-20210722135532-667f2b7c528f // indirect google.golang.org/genproto v0.0.0-20210722135532-667f2b7c528f // indirect
google.golang.org/grpc v1.39.0 google.golang.org/grpc v1.39.0
google.golang.org/protobuf v1.27.1
gopkg.in/cheggaaa/pb.v1 v1.0.28 gopkg.in/cheggaaa/pb.v1 v1.0.28
gopkg.in/h2non/gock.v1 v1.0.15 gopkg.in/h2non/gock.v1 v1.0.15
gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v2 v2.4.0
k8s.io/api v0.20.10
k8s.io/apimachinery v0.20.10
k8s.io/client-go v0.20.10
) )

300
go.sum
View File

@@ -1,10 +1,44 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 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.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/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/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/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=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
github.com/Azure/go-autorest/autorest v0.11.1/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw=
github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg=
github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A=
github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74=
github.com/Azure/go-autorest/autorest/mocks v0.4.0/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k=
github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k=
github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8=
github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 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/ClickHouse/clickhouse-go v1.4.3 h1:iAFMa2UrQdR5bHJ2/yaSLffZkxpcOYQMCUuKeNXGdqc= github.com/ClickHouse/clickhouse-go v1.4.3 h1:iAFMa2UrQdR5bHJ2/yaSLffZkxpcOYQMCUuKeNXGdqc=
github.com/ClickHouse/clickhouse-go v1.4.3/go.mod h1:EaI/sW7Azgz9UATzd5ZdZHRUhHgv5+JMS9NSr2smCJI= github.com/ClickHouse/clickhouse-go v1.4.3/go.mod h1:EaI/sW7Azgz9UATzd5ZdZHRUhHgv5+JMS9NSr2smCJI=
github.com/DATA-DOG/go-sqlmock v1.4.1 h1:ThlnYciV1iM/V0OSF/dtkqWb6xo5qITT1TJBG1MRDJM= github.com/DATA-DOG/go-sqlmock v1.4.1 h1:ThlnYciV1iM/V0OSF/dtkqWb6xo5qITT1TJBG1MRDJM=
github.com/DATA-DOG/go-sqlmock v1.4.1/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= github.com/DATA-DOG/go-sqlmock v1.4.1/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
@@ -17,6 +51,7 @@ github.com/alicebob/miniredis/v2 v2.14.1/go.mod h1:uS970Sw5Gs9/iK3yBg0l9Uj9s25wX
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
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 h1:EEyRvzmpEUZ+I8WmD5cw/vY8EqhambkOqy5iFr0908A=
github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20210521184019-c5ad59b459ec/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY= github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20210521184019-c5ad59b459ec/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY=
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
@@ -42,13 +77,16 @@ github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSV
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM= github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
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.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 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
github.com/emicklei/proto v1.9.0 h1:l0QiNT6Qs7Yj0Mb4X6dnWBQer4ebei2BFcgQLbGqUDc= github.com/emicklei/proto v1.9.0 h1:l0QiNT6Qs7Yj0Mb4X6dnWBQer4ebei2BFcgQLbGqUDc=
github.com/emicklei/proto v1.9.0/go.mod h1:rn1FgRS/FANiZdD2djyH7TMA9jdRDcYQ9IEN9yvjX0A= github.com/emicklei/proto v1.9.0/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.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
@@ -58,23 +96,40 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.m
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.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.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s= github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s=
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4= 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/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94=
github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
github.com/frankban/quicktest v1.7.2 h1:2QxQoC1TS09S7fhCPsrvqYdvP1H5M1P1ih5ABm3BTYk= github.com/frankban/quicktest v1.7.2 h1:2QxQoC1TS09S7fhCPsrvqYdvP1H5M1P1ih5ABm3BTYk=
github.com/frankban/quicktest v1.7.2/go.mod h1:jaStnuzAqU1AJdCO0l53JDCJrVDKcS03DbaAcR7Ks/o= github.com/frankban/quicktest v1.7.2/go.mod h1:jaStnuzAqU1AJdCO0l53JDCJrVDKcS03DbaAcR7Ks/o=
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8 h1:DujepqpGd1hyOd7aW59XpK7Qymp8iy83xq74fLr21is= github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8 h1:DujepqpGd1hyOd7aW59XpK7Qymp8iy83xq74fLr21is=
github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
github.com/go-logr/logr v0.2.0 h1:QvGt2nLcHH0WK9orKa+ppBPAxREcH364nPUedEpK0TY=
github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg=
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc=
github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8=
github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo=
github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-redis/redis v6.15.7+incompatible h1:3skhDh95XQMpnqeqNftPkQD9jL9e5e36z/1SUm6dy1U= github.com/go-redis/redis v6.15.7+incompatible h1:3skhDh95XQMpnqeqNftPkQD9jL9e5e36z/1SUm6dy1U=
github.com/go-redis/redis v6.15.7+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= github.com/go-redis/redis v6.15.7+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
@@ -90,13 +145,22 @@ github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7a
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= 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 v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
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 h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY=
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.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 h1:GV+pQPG/EUUbkh47niozDcADz6go/dUwhVzdUQHIVRw= github.com/golang/mock v1.4.3 h1:GV+pQPG/EUUbkh47niozDcADz6go/dUwhVzdUQHIVRw=
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 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.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.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.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.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= 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.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.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
@@ -108,31 +172,57 @@ github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.2/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/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 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.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.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.0/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.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.5/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 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g=
github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
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/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/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/googleapis/gnostic v0.4.1 h1:DLJCy1n/vrD4HPjOvYcT8aYQXpPIzoRZONaYwyycI+I=
github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg=
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw= 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/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 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/iancoleman/strcase v0.1.2 h1:gnomlvw9tnV3ITTAxzKSgTF+8kFWcU/f+TgttpXGz1U= github.com/iancoleman/strcase v0.1.2 h1:gnomlvw9tnV3ITTAxzKSgTF+8kFWcU/f+TgttpXGz1U=
github.com/iancoleman/strcase v0.1.2/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE= github.com/iancoleman/strcase v0.1.2/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks= github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks=
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMWAQ=
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
github.com/justinas/alice v1.2.0 h1:+MHSA/vccVCF4Uq37S42jwlkvI2Xzl7zTPCN5BnZNVo= github.com/justinas/alice v1.2.0 h1:+MHSA/vccVCF4Uq37S42jwlkvI2Xzl7zTPCN5BnZNVo=
@@ -146,14 +236,16 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN
github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs=
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.3.0 h1:/qkRGz8zljWiDcFvgpwUpwIAPu3r07TDvs3Rws+o/pU= github.com/lib/pq v1.3.0 h1:/qkRGz8zljWiDcFvgpwUpwIAPu3r07TDvs3Rws+o/pU=
github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8= github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8=
github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.6 h1:6Su7aK7lXmJ/U79bYtBjLNaha4Fs1Rg9plHpcH+vvnE= github.com/mattn/go-colorable v0.1.6 h1:6Su7aK7lXmJ/U79bYtBjLNaha4Fs1Rg9plHpcH+vvnE=
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
@@ -166,21 +258,29 @@ github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m
github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32 h1:W6apQkHrMkS0Muv8G/TipAy/FJl/rCYT0+EuS8+Z0z4= github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32 h1:W6apQkHrMkS0Muv8G/TipAy/FJl/rCYT0+EuS8+Z0z4=
github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms= github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms=
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= 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/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs= github.com/onsi/ginkgo v1.11.0 h1:JAKSXpt1YjtLA7YpPiqO9ss6sNXEsPfSGdwN0UHqzrw=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v1.5.0 h1:izbySO9zDPmjJ8rDjLvkA2zJHIo+HkYXHnf7eN7SSyo= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME=
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pierrec/lz4 v2.5.1+incompatible h1:Yq0up0149Hh5Ekhm/91lgkZuD1ZDnXNM26bycpTzYBM= github.com/pierrec/lz4 v2.5.1+incompatible h1:Yq0up0149Hh5Ekhm/91lgkZuD1ZDnXNM26bycpTzYBM=
github.com/pierrec/lz4 v2.5.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pierrec/lz4 v2.5.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
@@ -220,12 +320,19 @@ github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6Mwd
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
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/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 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.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/urfave/cli v1.22.5 h1:lNq9sAHXK2qfdI8W+GRItjCEkI+2oR4d+MEHy1CKXoU= github.com/urfave/cli v1.22.5 h1:lNq9sAHXK2qfdI8W+GRItjCEkI+2oR4d+MEHy1CKXoU=
@@ -237,8 +344,6 @@ github.com/yuin/gopher-lua v0.0.0-20191220021717-ab39c6098bdb h1:ZkM6LRnq40pR1Ox
github.com/yuin/gopher-lua v0.0.0-20191220021717-ab39c6098bdb/go.mod h1:gqRgreBUhTSL0GeU64rtZ3Uq3wtjOa/TB2YfrtkCbVQ= github.com/yuin/gopher-lua v0.0.0-20191220021717-ab39c6098bdb/go.mod h1:gqRgreBUhTSL0GeU64rtZ3Uq3wtjOa/TB2YfrtkCbVQ=
github.com/zeromicro/antlr v0.0.1 h1:CQpIn/dc0pUjgGQ81y98s/NGOm2Hfru2NNio2I9mQgk= 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/antlr v0.0.1/go.mod h1:nfpjEwFR6Q4xGDJMcZnCL9tEfQRgszMwu3rDz2Z+p5M=
github.com/zeromicro/ddl-parser v0.0.0-20210710132903-bc9dbb9789b1 h1:zItUIfobEHTYD9X0fAt9QWEWIFWDa8CypF+Z62zIR+M=
github.com/zeromicro/ddl-parser v0.0.0-20210710132903-bc9dbb9789b1/go.mod h1:ISU/8NuPyEpl9pa17Py9TBPetMjtsiHrb9f5XGiYbo8=
github.com/zeromicro/ddl-parser v0.0.0-20210712021150-63520aca7348 h1:OhxL9tn28gDeJVzreIUiE5oVxZCjL3tBJ0XBNw8p5R8= github.com/zeromicro/ddl-parser v0.0.0-20210712021150-63520aca7348 h1:OhxL9tn28gDeJVzreIUiE5oVxZCjL3tBJ0XBNw8p5R8=
github.com/zeromicro/ddl-parser v0.0.0-20210712021150-63520aca7348/go.mod h1:ISU/8NuPyEpl9pa17Py9TBPetMjtsiHrb9f5XGiYbo8= github.com/zeromicro/ddl-parser v0.0.0-20210712021150-63520aca7348/go.mod h1:ISU/8NuPyEpl9pa17Py9TBPetMjtsiHrb9f5XGiYbo8=
go.etcd.io/etcd/api/v3 v3.5.0 h1:GsV3S+OfZEOCNXdtNkBSR7kgLobAa/SO6tCxRa0GAYw= go.etcd.io/etcd/api/v3 v3.5.0 h1:GsV3S+OfZEOCNXdtNkBSR7kgLobAa/SO6tCxRa0GAYw=
@@ -247,6 +352,18 @@ go.etcd.io/etcd/client/pkg/v3 v3.5.0 h1:2aQv6F436YnN7I4VbI8PPYrBhu+SmrTaADcf8Mi/
go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
go.etcd.io/etcd/client/v3 v3.5.0 h1:62Eh0XOro+rDwkrypAGDfgmNh5Joq+z+W9HZdlXMzek= go.etcd.io/etcd/client/v3 v3.5.0 h1:62Eh0XOro+rDwkrypAGDfgmNh5Joq+z+W9HZdlXMzek=
go.etcd.io/etcd/client/v3 v3.5.0/go.mod h1:AIKXXVX/DQXtfTEqBryiLTUXwON+GuvO6Z7lLS/oTh0= go.etcd.io/etcd/client/v3 v3.5.0/go.mod h1:AIKXXVX/DQXtfTEqBryiLTUXwON+GuvO6Z7lLS/oTh0=
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.opentelemetry.io/otel v1.0.0-RC2 h1:SHhxSjB+omnGZPgGlKe+QMp3MyazcOHdQ8qwo89oKbg=
go.opentelemetry.io/otel v1.0.0-RC2/go.mod h1:w1thVQ7qbAy8MHb0IFj8a5Q2QU0l2ksf8u/CN8m3NOM=
go.opentelemetry.io/otel/exporters/jaeger v1.0.0-RC2 h1:RF0nWsIDpDBe+s06lkLxUw9CWQUAhO6hBSxxB7dz45s=
go.opentelemetry.io/otel/exporters/jaeger v1.0.0-RC2/go.mod h1:sZZqN3Vb0iT+NE6mZ1S7sNyH3t4PFk6ElK5TLGFBZ7E=
go.opentelemetry.io/otel/sdk v1.0.0-RC2 h1:ROuteeSCBaZNjiT9JcFzZepmInDvLktR28Y6qKo8bCs=
go.opentelemetry.io/otel/sdk v1.0.0-RC2/go.mod h1:fgwHyiDn4e5k40TD9VX243rOxXR+jzsWBZYA2P5jpEw=
go.opentelemetry.io/otel/trace v1.0.0-RC2 h1:dunAP0qDULMIT82atj34m5RgvsIK6LcsXf1c/MsYg1w=
go.opentelemetry.io/otel/trace v1.0.0-RC2/go.mod h1:JPQ+z6nNw9mqEGT8o3eoPTdnNI+Aj5JcxEsVGREIAy4=
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
@@ -259,16 +376,41 @@ go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-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-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-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/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.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0 h1:hb9wdF1z5waM+dSIICn1l0DkLVDT3hqhhQsDNUmHPRE=
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 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-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-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-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-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.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.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.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.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
@@ -280,23 +422,37 @@ golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73r
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-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-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-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/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-20190827160401-ba9fcec4b297/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-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-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200822124328-c89045814202/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-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210614182718-04defd469f4e h1:XpT3nA5TvE525Ne3hInMh6+GETgn27Zfm9dxsThnX2Q=
golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210716203947-853a461950ff h1:j2EK/QoxYNBsXI4R7fQkkRUk8y6wnOBI+6hgPdP/6Ds= golang.org/x/net v0.0.0-20210716203947-853a461950ff h1:j2EK/QoxYNBsXI4R7fQkkRUk8y6wnOBI+6hgPdP/6Ds=
golang.org/x/net v0.0.0-20210716203947-853a461950ff/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210716203947-853a461950ff/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 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-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 h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-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-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-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -309,75 +465,148 @@ golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/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-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/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-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-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-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22 h1:RqytpXGR1iVNX7psjB3ff8y7sNFinVFvkx1c8SjBkio= golang.org/x/sys v0.0.0-20210820121016-41cdb8703e55 h1:rw6UNGRMfarCepjI8qOepea/SXwIBVfTKjztZ5gBbq4=
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210820121016-41cdb8703e55/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.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.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.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba h1:O8mE0/t419eoIwhTFpKVkHiTs/Igowgfkj25AcZrtiE= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/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.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2MaV/MapERkDIy+mwPyjs=
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/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-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-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-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-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-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-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-20190614205625-5aca471b1d59/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-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-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-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-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-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/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-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 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-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-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/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.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 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.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 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM=
google.golang.org/appengine v1.6.5/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-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-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-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
google.golang.org/genproto v0.0.0-20210617175327-b9e0b3197ced h1:c5geK1iMU3cDKtFrCVQIcjR3W+JOZMuhIyICMCTbtus=
google.golang.org/genproto v0.0.0-20210617175327-b9e0b3197ced/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24=
google.golang.org/genproto v0.0.0-20210722135532-667f2b7c528f h1:YORWxaStkWBnWgELOHTmDrqNlFXuVGEbhwbB5iK94bQ= google.golang.org/genproto v0.0.0-20210722135532-667f2b7c528f h1:YORWxaStkWBnWgELOHTmDrqNlFXuVGEbhwbB5iK94bQ=
google.golang.org/genproto v0.0.0-20210722135532-667f2b7c528f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= google.golang.org/genproto v0.0.0-20210722135532-667f2b7c528f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= 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.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= 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.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= 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.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.38.0 h1:/9BgsAsa5nWe26HqOlvlgJnqBuktYOLCgjCPqsa56W0=
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
google.golang.org/grpc v1.39.0 h1:Klz8I9kdtkIN6EpHHUOMLCYhTn/2WAe5a0s1hcBkdTI= google.golang.org/grpc v1.39.0 h1:Klz8I9kdtkIN6EpHHUOMLCYhTn/2WAe5a0s1hcBkdTI=
google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
@@ -391,7 +620,6 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/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.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
@@ -407,6 +635,8 @@ gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/h2non/gock.v1 v1.0.15 h1:SzLqcIlb/fDfg7UvukMpNcWsu7sI5tWwL+KCATZqks0= gopkg.in/h2non/gock.v1 v1.0.15 h1:SzLqcIlb/fDfg7UvukMpNcWsu7sI5tWwL+KCATZqks0=
gopkg.in/h2non/gock.v1 v1.0.15/go.mod h1:sX4zAkdYX1TRGJ2JY156cFspQn4yRWn6p9EMdODlynE= gopkg.in/h2non/gock.v1 v1.0.15/go.mod h1:sX4zAkdYX1TRGJ2JY156cFspQn4yRWn6p9EMdODlynE=
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/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
@@ -422,8 +652,30 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/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-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.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-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
k8s.io/api v0.20.10 h1:kAdgi1zcyenV88/uVEzS9B/fn1m4KRbmdKB0Lxl6z/M=
k8s.io/api v0.20.10/go.mod h1:0kei3F6biGjtRQBo5dUeujq6Ji3UCh9aOSfp/THYd7I=
k8s.io/apimachinery v0.20.10 h1:GcFwz5hsGgKLohcNgv8GrInk60vUdFgBXW7uOY1i1YM=
k8s.io/apimachinery v0.20.10/go.mod h1:kQa//VOAwyVwJ2+L9kOREbsnryfsGSkSM1przND4+mw=
k8s.io/client-go v0.20.10 h1:TgAL2pqcNWMH4eZoS9Uw0BLh2lu5a2A4pmegjp5pmsk=
k8s.io/client-go v0.20.10/go.mod h1:fFg+aLoasv/R+xiVaWjxeqGFYltzgQcOQzkFaSRfnJ0=
k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
k8s.io/klog/v2 v2.4.0 h1:7+X0fUguPyrKEC4WjH8iGDg3laWgMo5tMnRTIGTTxGQ=
k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM=
k8s.io/utils v0.0.0-20201110183641-67b214c5f920 h1:CbnUZsM497iRC5QMVkHwyl8s2tB3g7yaSHkYPkpgelw=
k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
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/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
sigs.k8s.io/structured-merge-diff/v4 v4.1.2 h1:Hr/htKFmJEbtMgS/UD0N+gtgctAqz81t3nu+sPzynno=
sigs.k8s.io/structured-merge-diff/v4 v4.1.2/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4=
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q=
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=

View File

@@ -50,9 +50,7 @@ go-zero 包含极简的 API 定义和生成工具 goctl可以根据定义的
* 保持简单,第一原则 * 保持简单,第一原则
* 弹性设计,面向故障编程 * 弹性设计,面向故障编程
* 工具大于约定和文档 * 工具大于约定和文档
* 高可用 * 高可用、高并发、易扩展
* 高并发
* 易扩展
* 对业务开发友好,封装复杂度 * 对业务开发友好,封装复杂度
* 约束做一件事只有一种方式 * 约束做一件事只有一种方式
@@ -103,7 +101,11 @@ GO111MODULE=on GOPROXY=https://goproxy.cn/,direct go get -u github.com/tal-tech/
`goctl` 读作 `go control`,不要读成 `go C-T-L``goctl` 的意思是不要被代码控制,而是要去控制它。其中的 `go` 不是指 `golang`。在设计 `goctl` 之初,我就希望通过 ` 她 ` 来解放我们的双手👈 `goctl` 读作 `go control`,不要读成 `go C-T-L``goctl` 的意思是不要被代码控制,而是要去控制它。其中的 `go` 不是指 `golang`。在设计 `goctl` 之初,我就希望通过 ` 她 ` 来解放我们的双手👈
```shell ```shell
# Go 1.15 及之前版本
GO111MODULE=on GOPROXY=https://goproxy.cn/,direct go get -u github.com/tal-tech/go-zero/tools/goctl GO111MODULE=on GOPROXY=https://goproxy.cn/,direct go get -u github.com/tal-tech/go-zero/tools/goctl
# Go 1.16 及以后版本
go install github.com/tal-tech/go-zero/tools/goctl@latest
``` ```
确保 goctl 可执行 确保 goctl 可执行
@@ -118,7 +120,7 @@ GO111MODULE=on GOPROXY=https://goproxy.cn/,direct go get -u github.com/tal-tech/
go run greet.go -f etc/greet-api.yaml go run greet.go -f etc/greet-api.yaml
``` ```
默认侦听在 8888 端口(可以在配置文件里修改),可以通过 curl 请求: 默认侦听在 `8888` 端口(可以在配置文件里修改),可以通过 `curl` 请求:
```shell ```shell
curl -i http://localhost:8888/from/you curl -i http://localhost:8888/from/you
@@ -129,17 +131,17 @@ GO111MODULE=on GOPROXY=https://goproxy.cn/,direct go get -u github.com/tal-tech/
```http ```http
HTTP/1.1 200 OK HTTP/1.1 200 OK
Content-Type: application/json Content-Type: application/json
Date: Thu, 22 Oct 2020 14:03:18 GMT Date: Thu, 22 Oct 2020 14:03:18 GMT
Content-Length: 14 Content-Length: 14
{"message":""} {"message":""}
``` ```
编写业务代码: 编写业务代码:
* api 文件定义了服务对外暴露的路由,可参考 [api 规范](https://github.com/tal-tech/zero-doc/blob/main/doc/goctl.md) * api 文件定义了服务对外 HTTP 接口,可参考 [api 规范](https://github.com/tal-tech/zero-doc/blob/main/doc/goctl.md)
* 可以在 servicecontext.go 里面传递依赖给 logic比如 mysql, redis 等 * 可以在 `servicecontext.go` 里面传递依赖给 logic比如 mysql, redis 等
* 在 api 定义的 get/post/put/delete 等请求对应的 logic 里增加业务处理逻辑 * 在 api 定义的 `get/post/put/delete` 等请求对应的 logic 里增加业务处理逻辑
3. 可以根据 api 文件生成前端需要的 Java, TypeScript, Dart, JavaScript 代码 3. 可以根据 api 文件生成前端需要的 Java, TypeScript, Dart, JavaScript 代码
@@ -216,6 +218,10 @@ go-zero 已被许多公司用于生产部署,接入场景如在线教育、电
>34. 南宁宸升计算机科技有限公司 >34. 南宁宸升计算机科技有限公司
>35. 秦皇岛2084team >35. 秦皇岛2084team
>36. 天翼云股份有限公司 >36. 天翼云股份有限公司
>37. 南京速优云信息科技有限公司
>38. 北京小鸦科技有限公司
>39. 深圳无边界技术有限公司
>40. 马鞍山百助网络科技有限公司
如果贵公司也已使用 go-zero欢迎在 [登记地址](https://github.com/tal-tech/go-zero/issues/602) 登记,仅仅为了推广,不做其它用途。 如果贵公司也已使用 go-zero欢迎在 [登记地址](https://github.com/tal-tech/go-zero/issues/602) 登记,仅仅为了推广,不做其它用途。
@@ -233,6 +239,6 @@ go-zero 已被许多公司用于生产部署,接入场景如在线教育、电
如果您发现 ***bug*** 请及时提 ***issue***,我们会尽快确认并修改。 如果您发现 ***bug*** 请及时提 ***issue***,我们会尽快确认并修改。
加群之前有劳点一下 ***star***,一个小小的 ***star*** 是作者们回答海量问题的动力🤝 加群之前有劳点一下 ***star***,一个小小的 ***star*** 是作者们回答海量问题的动力🤝
<img src="https://raw.githubusercontent.com/tal-tech/zero-doc/main/doc/images/wechat.jpg" alt="wechat" width="300" /> <img src="https://raw.githubusercontent.com/tal-tech/zero-doc/main/doc/images/wechat.jpg" alt="wechat" width="300" />

View File

@@ -104,7 +104,11 @@ go get -u github.com/tal-tech/go-zero
`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 the productivity, and make our lives easier. `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 the productivity, and make our lives easier.
```shell ```shell
# for Go 1.15 and earlier
GO111MODULE=on go get -u github.com/tal-tech/go-zero/tools/goctl GO111MODULE=on go get -u github.com/tal-tech/go-zero/tools/goctl
# for Go 1.16 and later
go install github.com/tal-tech/go-zero/tools/goctl@latest
``` ```
make sure goctl is executable. make sure goctl is executable.
@@ -112,17 +116,19 @@ go get -u github.com/tal-tech/go-zero
2. create the API file, like greet.api, you can install the plugin of goctl in vs code, api syntax is supported. 2. create the API file, like greet.api, you can install the plugin of goctl in vs code, api syntax is supported.
```go ```go
type Request struct { type (
Name string `path:"name,options=you|me"` // parameters are auto validated Request {
} Name string `path:"name,options=you|me"` // parameters are auto validated
}
type Response struct { Response {
Message string `json:"message"` Message string `json:"message"`
} }
)
service greet-api { service greet-api {
@handler GreetHandler @handler GreetHandler
get /greet/from/:name(Request) returns (Response); get /greet/from/:name(Request) returns (Response)
} }
``` ```
@@ -213,8 +219,8 @@ go get -u github.com/tal-tech/go-zero
## 9. Chat group ## 9. Chat group
Join the chat via https://join.slack.com/t/go-zero/shared_invite/zt-thyennhc-_fNXFpeUJcGE_tQNZFpsdA Join the chat via https://join.slack.com/t/go-zero/shared_invite/zt-ulzixfgi-NAkZjq856TewLY2KQSxHCw
## Give a Star! ⭐ ## Give a Star! ⭐
If you like or are using this project to learn or start your solution, please give it a star. Thanks! If you like or are using this project to learn or start your solution, please give it a star. Thanks!

View File

@@ -108,6 +108,7 @@ func (s *engine) bindRoute(fr featuredRoutes, router httpx.Router, metrics *stat
route Route, verifier func(chain alice.Chain) alice.Chain) error { route Route, verifier func(chain alice.Chain) alice.Chain) error {
chain := alice.New( chain := alice.New(
handler.TracingHandler, handler.TracingHandler,
handler.OtelHandler(route.Path),
s.getLogHandler(), s.getLogHandler(),
handler.PrometheusHandler(route.Path), handler.PrometheusHandler(route.Path),
handler.MaxConns(s.conf.MaxConns), handler.MaxConns(s.conf.MaxConns),

View File

@@ -112,11 +112,12 @@ func unauthorized(w http.ResponseWriter, r *http.Request, err error, callback Un
} else { } else {
detailAuthLog(r, noDetailReason) detailAuthLog(r, noDetailReason)
} }
writer.WriteHeader(http.StatusUnauthorized)
if callback != nil { if callback != nil {
callback(writer, r, err) callback(writer, r, err)
} }
writer.WriteHeader(http.StatusUnauthorized)
} }
type guardedResponseWriter struct { type guardedResponseWriter struct {

View File

@@ -7,9 +7,11 @@ import (
"errors" "errors"
"fmt" "fmt"
"io" "io"
"io/ioutil"
"net" "net"
"net/http" "net/http"
"net/http/httputil" "net/http/httputil"
"strings"
"time" "time"
"github.com/tal-tech/go-zero/core/iox" "github.com/tal-tech/go-zero/core/iox"
@@ -20,7 +22,10 @@ import (
"github.com/tal-tech/go-zero/rest/internal" "github.com/tal-tech/go-zero/rest/internal"
) )
const slowThreshold = time.Millisecond * 500 const (
limitBodyBytes = 1024
slowThreshold = time.Millisecond * 500
)
type loggedResponseWriter struct { type loggedResponseWriter struct {
w http.ResponseWriter w http.ResponseWriter
@@ -156,7 +161,14 @@ func logBrief(r *http.Request, code int, timer *utils.ElapsedTimer, logs *intern
ok := isOkResponse(code) ok := isOkResponse(code)
if !ok { if !ok {
buf.WriteString(fmt.Sprintf("\n%s", dumpRequest(r))) fullReq := dumpRequest(r)
limitReader := io.LimitReader(strings.NewReader(fullReq), limitBodyBytes)
body, err := ioutil.ReadAll(limitReader)
if err != nil {
buf.WriteString(fmt.Sprintf("\n%s", fullReq))
} else {
buf.WriteString(fmt.Sprintf("\n%s", string(body)))
}
} }
body := logs.Flush() body := logs.Flush()

View File

@@ -0,0 +1,36 @@
package handler
import (
"net/http"
"github.com/tal-tech/go-zero/core/trace/opentelemetry"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/propagation"
semconv "go.opentelemetry.io/otel/semconv/v1.4.0"
oteltrace "go.opentelemetry.io/otel/trace"
)
// OtelHandler return a middleware that process the opentelemetry.
func OtelHandler(path string) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
if !opentelemetry.Enabled() {
return next
}
propagator := otel.GetTextMapPropagator()
tracer := otel.GetTracerProvider().Tracer(opentelemetry.TraceName)
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ctx := propagator.Extract(r.Context(), propagation.HeaderCarrier(r.Header))
spanCtx, span := tracer.Start(
ctx,
path,
oteltrace.WithSpanKind(oteltrace.SpanKindServer),
oteltrace.WithAttributes(semconv.HTTPServerAttributesFromHTTPRequest("", path, r)...),
)
defer span.End()
next.ServeHTTP(w, r.WithContext(spanCtx))
})
}
}

View File

@@ -0,0 +1,48 @@
package handler
import (
"context"
"net/http"
"net/http/httptest"
"testing"
"github.com/stretchr/testify/assert"
"github.com/tal-tech/go-zero/core/trace/opentelemetry"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/propagation"
"go.opentelemetry.io/otel/trace"
)
func TestOtelHandler(t *testing.T) {
opentelemetry.StartAgent(opentelemetry.Config{
Name: "go-zero-test",
Endpoint: "http://localhost:14268/api/traces",
Batcher: "jaeger",
Sampler: 1.0,
})
ts := httptest.NewServer(
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ctx := otel.GetTextMapPropagator().Extract(r.Context(), propagation.HeaderCarrier(r.Header))
spanCtx := trace.SpanContextFromContext(ctx)
assert.Equal(t, true, spanCtx.IsValid())
}),
)
defer ts.Close()
client := ts.Client()
err := func(ctx context.Context) error {
ctx, span := otel.Tracer("httptrace/client").Start(ctx, "test")
defer span.End()
req, _ := http.NewRequest("GET", ts.URL, nil)
otel.GetTextMapPropagator().Inject(ctx, propagation.HeaderCarrier(req.Header))
res, err := client.Do(req)
assert.Equal(t, err, nil)
_ = res.Body.Close()
return nil
}(context.Background())
assert.Equal(t, err, nil)
}

View File

@@ -21,6 +21,8 @@ func TracingHandler(next http.Handler) http.Handler {
defer span.Finish() defer span.Finish()
r = r.WithContext(ctx) r = r.WithContext(ctx)
// conveniently tracking error messages
w.Header().Set(trace.TraceIdKey, span.TraceId())
next.ServeHTTP(w, r) next.ServeHTTP(w, r)
}) })
} }

View File

@@ -6,19 +6,26 @@ import (
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/tal-tech/go-zero/core/stringx"
"github.com/tal-tech/go-zero/core/trace"
"github.com/tal-tech/go-zero/core/trace/tracespec" "github.com/tal-tech/go-zero/core/trace/tracespec"
) )
func TestTracingHandler(t *testing.T) { func TestTracingHandler(t *testing.T) {
req := httptest.NewRequest(http.MethodGet, "http://localhost", nil) req := httptest.NewRequest(http.MethodGet, "http://localhost", nil)
req.Header.Set("X-Trace-ID", "theid")
traceId := stringx.RandId()
req.Header.Set(trace.TraceIdKey, traceId)
handler := TracingHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { handler := TracingHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
span, ok := r.Context().Value(tracespec.TracingKey).(tracespec.Trace) span, ok := r.Context().Value(tracespec.TracingKey).(tracespec.Trace)
assert.True(t, ok) assert.True(t, ok)
assert.Equal(t, "theid", span.TraceId()) assert.Equal(t, traceId, span.TraceId())
})) }))
resp := httptest.NewRecorder() resp := httptest.NewRecorder()
handler.ServeHTTP(resp, req) handler.ServeHTTP(resp, req)
assert.Equal(t, http.StatusOK, resp.Code) assert.Equal(t, http.StatusOK, resp.Code)
assert.Equal(t, traceId, resp.Header().Get(trace.TraceIdKey))
} }

View File

@@ -3,10 +3,11 @@ package httpx
import ( import (
"io" "io"
"net/http" "net/http"
"net/textproto"
"strings" "strings"
"github.com/tal-tech/go-zero/core/mapping" "github.com/tal-tech/go-zero/core/mapping"
"github.com/tal-tech/go-zero/rest/internal/context" "github.com/tal-tech/go-zero/rest/pathvar"
) )
const ( const (
@@ -23,7 +24,8 @@ const (
var ( var (
formUnmarshaler = mapping.NewUnmarshaler(formKey, mapping.WithStringValues()) formUnmarshaler = mapping.NewUnmarshaler(formKey, mapping.WithStringValues())
pathUnmarshaler = mapping.NewUnmarshaler(pathKey, mapping.WithStringValues()) pathUnmarshaler = mapping.NewUnmarshaler(pathKey, mapping.WithStringValues())
headerUnmarshaler = mapping.NewUnmarshaler(headerKey, mapping.WithStringValues()) headerUnmarshaler = mapping.NewUnmarshaler(headerKey, mapping.WithStringValues(),
mapping.WithCanonicalKeyFunc(textproto.CanonicalMIMEHeaderKey))
) )
// Parse parses the request. // Parse parses the request.
@@ -47,7 +49,6 @@ func Parse(r *http.Request, v interface{}) error {
func ParseHeaders(r *http.Request, v interface{}) error { func ParseHeaders(r *http.Request, v interface{}) error {
m := map[string]interface{}{} m := map[string]interface{}{}
for k, v := range r.Header { for k, v := range r.Header {
k = strings.ToLower(k)
if len(v) == 1 { if len(v) == 1 {
m[k] = v[0] m[k] = v[0]
} else { } else {
@@ -118,7 +119,7 @@ func ParseJsonBody(r *http.Request, v interface{}) error {
// ParsePath parses the symbols reside in url path. // ParsePath parses the symbols reside in url path.
// Like http://localhost/bag/:name // Like http://localhost/bag/:name
func ParsePath(r *http.Request, v interface{}) error { func ParsePath(r *http.Request, v interface{}) error {
vars := context.Vars(r) vars := pathvar.Vars(r)
m := make(map[string]interface{}, len(vars)) m := make(map[string]interface{}, len(vars))
for k, v := range vars { for k, v := range vars {
m[k] = v m[k] = v

View File

@@ -203,10 +203,16 @@ func BenchmarkParseAuto(b *testing.B) {
} }
func TestParseHeaders(t *testing.T) { func TestParseHeaders(t *testing.T) {
type AnonymousStruct struct {
XRealIP string `header:"x-real-ip"`
Accept string `header:"Accept,optional"`
}
v := struct { v := struct {
Name string `header:"name"` Name string `header:"name,optional"`
Percent string `header:"percent"` Percent string `header:"percent"`
Addrs []string `header:"addrs"` Addrs []string `header:"addrs"`
XForwardedFor string `header:"X-Forwarded-For,optional"`
AnonymousStruct
}{} }{}
request, err := http.NewRequest("POST", "http://hello.com/", nil) request, err := http.NewRequest("POST", "http://hello.com/", nil)
if err != nil { if err != nil {
@@ -216,6 +222,9 @@ func TestParseHeaders(t *testing.T) {
request.Header.Set("percent", "1") request.Header.Set("percent", "1")
request.Header.Add("addrs", "addr1") request.Header.Add("addrs", "addr1")
request.Header.Add("addrs", "addr2") request.Header.Add("addrs", "addr2")
request.Header.Add("X-Forwarded-For", "10.0.10.11")
request.Header.Add("x-real-ip", "10.0.11.10")
request.Header.Add("Accept", "application/json")
err = ParseHeaders(request, &v) err = ParseHeaders(request, &v)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@@ -223,4 +232,7 @@ func TestParseHeaders(t *testing.T) {
assert.Equal(t, "chenquan", v.Name) assert.Equal(t, "chenquan", v.Name)
assert.Equal(t, "1", v.Percent) assert.Equal(t, "1", v.Percent)
assert.Equal(t, []string{"addr1", "addr2"}, v.Addrs) assert.Equal(t, []string{"addr1", "addr2"}, v.Addrs)
assert.Equal(t, "10.0.10.11", v.XForwardedFor)
assert.Equal(t, "10.0.11.10", v.XRealIP)
assert.Equal(t, "application/json", v.Accept)
} }

View File

@@ -25,6 +25,11 @@ func Error(w http.ResponseWriter, err error) {
} }
code, body := errorHandler(err) code, body := errorHandler(err)
if body == nil {
w.WriteHeader(code)
return
}
e, ok := body.(error) e, ok := body.(error)
if ok { if ok {
http.Error(w, e.Error(), code) http.Error(w, e.Error(), code)

View File

@@ -25,17 +25,19 @@ func TestError(t *testing.T) {
) )
tests := []struct { tests := []struct {
name string name string
input string input string
errorHandler func(error) (int, interface{}) errorHandler func(error) (int, interface{})
expectBody string expectHasBody bool
expectCode int expectBody string
expectCode int
}{ }{
{ {
name: "default error handler", name: "default error handler",
input: body, input: body,
expectBody: body, expectHasBody: true,
expectCode: http.StatusBadRequest, expectBody: body,
expectCode: http.StatusBadRequest,
}, },
{ {
name: "customized error handler return string", name: "customized error handler return string",
@@ -43,8 +45,9 @@ func TestError(t *testing.T) {
errorHandler: func(err error) (int, interface{}) { errorHandler: func(err error) (int, interface{}) {
return http.StatusForbidden, err.Error() return http.StatusForbidden, err.Error()
}, },
expectBody: wrappedBody, expectHasBody: true,
expectCode: http.StatusForbidden, expectBody: wrappedBody,
expectCode: http.StatusForbidden,
}, },
{ {
name: "customized error handler return error", name: "customized error handler return error",
@@ -52,8 +55,19 @@ func TestError(t *testing.T) {
errorHandler: func(err error) (int, interface{}) { errorHandler: func(err error) (int, interface{}) {
return http.StatusForbidden, err return http.StatusForbidden, err
}, },
expectBody: body, expectHasBody: true,
expectCode: http.StatusForbidden, expectBody: body,
expectCode: http.StatusForbidden,
},
{
name: "customized error handler return nil",
input: body,
errorHandler: func(err error) (int, interface{}) {
return http.StatusForbidden, nil
},
expectHasBody: false,
expectBody: "",
expectCode: http.StatusForbidden,
}, },
} }
@@ -75,6 +89,7 @@ func TestError(t *testing.T) {
} }
Error(&w, errors.New(test.input)) Error(&w, errors.New(test.input))
assert.Equal(t, test.expectCode, w.code) assert.Equal(t, test.expectCode, w.code)
assert.Equal(t, test.expectHasBody, w.hasBody)
assert.Equal(t, test.expectBody, strings.TrimSpace(w.builder.String())) assert.Equal(t, test.expectBody, strings.TrimSpace(w.builder.String()))
}) })
} }
@@ -122,6 +137,7 @@ func TestWriteJsonLessWritten(t *testing.T) {
type tracedResponseWriter struct { type tracedResponseWriter struct {
headers map[string][]string headers map[string][]string
builder strings.Builder builder strings.Builder
hasBody bool
code int code int
lessWritten bool lessWritten bool
timeout bool timeout bool
@@ -140,6 +156,8 @@ func (w *tracedResponseWriter) Write(bytes []byte) (n int, err error) {
if w.lessWritten { if w.lessWritten {
n -= 1 n -= 1
} }
w.hasBody = true
return return
} }

View File

@@ -54,12 +54,12 @@ func (lc *LogCollector) takeAll() []string {
// Error logs the given v along with r in error log. // Error logs the given v along with r in error log.
func Error(r *http.Request, v ...interface{}) { func Error(r *http.Request, v ...interface{}) {
logx.ErrorCaller(1, format(r, v...)) logx.WithContext(r.Context()).Error(format(r, v...))
} }
// Errorf logs the given v with format along with r in error log. // Errorf logs the given v with format along with r in error log.
func Errorf(r *http.Request, format string, v ...interface{}) { func Errorf(r *http.Request, format string, v ...interface{}) {
logx.ErrorCaller(1, formatf(r, format, v...)) logx.WithContext(r.Context()).Error(formatf(r, format, v...))
} }
// Info logs the given v along with r in access log. // Info logs the given v along with r in access log.

View File

@@ -1,4 +1,4 @@
package context package pathvar
import ( import (
"context" "context"
@@ -17,13 +17,13 @@ func Vars(r *http.Request) map[string]string {
return nil return nil
} }
// WithPathVars writes params into given r and returns a new http.Request. // WithVars writes params into given r and returns a new http.Request.
func WithPathVars(r *http.Request, params map[string]string) *http.Request { func WithVars(r *http.Request, params map[string]string) *http.Request {
return r.WithContext(context.WithValue(r.Context(), pathVars, params)) return r.WithContext(context.WithValue(r.Context(), pathVars, params))
} }
type contextKey string type contextKey string
func (c contextKey) String() string { func (c contextKey) String() string {
return "rest/internal/context key: " + string(c) return "rest/pathvar/context key: " + string(c)
} }

View File

@@ -1,4 +1,4 @@
package context package pathvar
import ( import (
"context" "context"

View File

@@ -8,7 +8,7 @@ import (
"github.com/tal-tech/go-zero/core/search" "github.com/tal-tech/go-zero/core/search"
"github.com/tal-tech/go-zero/rest/httpx" "github.com/tal-tech/go-zero/rest/httpx"
"github.com/tal-tech/go-zero/rest/internal/context" "github.com/tal-tech/go-zero/rest/pathvar"
) )
const ( const (
@@ -61,7 +61,7 @@ func (pr *patRouter) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if tree, ok := pr.trees[r.Method]; ok { if tree, ok := pr.trees[r.Method]; ok {
if result, ok := tree.Search(reqPath); ok { if result, ok := tree.Search(reqPath); ok {
if len(result.Params) > 0 { if len(result.Params) > 0 {
r = context.WithPathVars(r, result.Params) r = pathvar.WithVars(r, result.Params)
} }
result.Item.(http.Handler).ServeHTTP(w, r) result.Item.(http.Handler).ServeHTTP(w, r)
return return

View File

@@ -11,7 +11,7 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/tal-tech/go-zero/rest/httpx" "github.com/tal-tech/go-zero/rest/httpx"
"github.com/tal-tech/go-zero/rest/internal/context" "github.com/tal-tech/go-zero/rest/pathvar"
) )
const ( const (
@@ -107,12 +107,12 @@ func TestPatRouter(t *testing.T) {
router := NewRouter() router := NewRouter()
err := router.Handle(test.method, "/a/:b", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { err := router.Handle(test.method, "/a/:b", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
routed = true routed = true
assert.Equal(t, 1, len(context.Vars(r))) assert.Equal(t, 1, len(pathvar.Vars(r)))
})) }))
assert.Nil(t, err) assert.Nil(t, err)
err = router.Handle(test.method, "/a/b/c", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { err = router.Handle(test.method, "/a/b/c", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
routed = true routed = true
assert.Nil(t, context.Vars(r)) assert.Nil(t, pathvar.Vars(r))
})) }))
assert.Nil(t, err) assert.Nil(t, err)
err = router.Handle(test.method, "/b/c", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { err = router.Handle(test.method, "/b/c", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {

View File

@@ -29,12 +29,12 @@ type (
// Be aware that later RunOption might overwrite previous one that write the same option. // Be aware that later RunOption might overwrite previous one that write the same option.
// The process will exit if error occurs. // The process will exit if error occurs.
func MustNewServer(c RestConf, opts ...RunOption) *Server { func MustNewServer(c RestConf, opts ...RunOption) *Server {
engine, err := NewServer(c, opts...) server, err := NewServer(c, opts...)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
return engine return server
} }
// NewServer returns a server with given config of c and options defined in opts. // NewServer returns a server with given config of c and options defined in opts.
@@ -61,36 +61,36 @@ func NewServer(c RestConf, opts ...RunOption) (*Server, error) {
} }
// AddRoutes add given routes into the Server. // AddRoutes add given routes into the Server.
func (e *Server) AddRoutes(rs []Route, opts ...RouteOption) { func (s *Server) AddRoutes(rs []Route, opts ...RouteOption) {
r := featuredRoutes{ r := featuredRoutes{
routes: rs, routes: rs,
} }
for _, opt := range opts { for _, opt := range opts {
opt(&r) opt(&r)
} }
e.ngin.AddRoutes(r) s.ngin.AddRoutes(r)
} }
// AddRoute adds given route into the Server. // AddRoute adds given route into the Server.
func (e *Server) AddRoute(r Route, opts ...RouteOption) { func (s *Server) AddRoute(r Route, opts ...RouteOption) {
e.AddRoutes([]Route{r}, opts...) s.AddRoutes([]Route{r}, opts...)
} }
// Start starts the Server. // Start starts the Server.
// Graceful shutdown is enabled by default. // Graceful shutdown is enabled by default.
// Use proc.SetTimeToForceQuit to customize the graceful shutdown period. // Use proc.SetTimeToForceQuit to customize the graceful shutdown period.
func (e *Server) Start() { func (s *Server) Start() {
handleError(e.opts.start(e.ngin)) handleError(s.opts.start(s.ngin))
} }
// Stop stops the Server. // Stop stops the Server.
func (e *Server) Stop() { func (s *Server) Stop() {
logx.Close() logx.Close()
} }
// Use adds the given middleware in the Server. // Use adds the given middleware in the Server.
func (e *Server) Use(middleware Middleware) { func (s *Server) Use(middleware Middleware) {
e.ngin.use(middleware) s.ngin.use(middleware)
} }
// ToMiddleware converts the given handler to a Middleware. // ToMiddleware converts the given handler to a Middleware.

View File

@@ -52,13 +52,24 @@ func ApiCommand(c *cli.Context) error {
} }
defer fp.Close() defer fp.Close()
home := c.String("home")
if len(home) > 0 {
util.RegisterGoctlHome(home)
}
text, err := util.LoadTemplate(category, apiTemplateFile, apiTemplate)
if err != nil {
return err
}
baseName := util.FileNameWithoutExt(filepath.Base(apiFile)) baseName := util.FileNameWithoutExt(filepath.Base(apiFile))
if strings.HasSuffix(strings.ToLower(baseName), "-api") { if strings.HasSuffix(strings.ToLower(baseName), "-api") {
baseName = baseName[:len(baseName)-4] baseName = baseName[:len(baseName)-4]
} else if strings.HasSuffix(strings.ToLower(baseName), "api") { } else if strings.HasSuffix(strings.ToLower(baseName), "api") {
baseName = baseName[:len(baseName)-3] baseName = baseName[:len(baseName)-3]
} }
t := template.Must(template.New("etcTemplate").Parse(apiTemplate))
t := template.Must(template.New("etcTemplate").Parse(text))
if err := t.Execute(fp, map[string]string{ if err := t.Execute(fp, map[string]string{
"gitUser": getGitName(), "gitUser": getGitName(),
"gitEmail": getGitEmail(), "gitEmail": getGitEmail(),

View File

@@ -0,0 +1,51 @@
package apigen
import (
"fmt"
"github.com/tal-tech/go-zero/tools/goctl/util"
"github.com/urfave/cli"
)
const (
category = "api"
apiTemplateFile = "template.tpl"
)
var templates = map[string]string{
apiTemplateFile: apiTemplate,
}
// Category returns the category of the api files.
func Category() string {
return category
}
// Clean cleans the generated deployment files.
func Clean() error {
return util.Clean(category)
}
// GenTemplates generates api template files.
func GenTemplates(_ *cli.Context) error {
return util.InitTemplates(category, templates)
}
// RevertTemplate reverts the given template file to the default value.
func RevertTemplate(name string) error {
content, ok := templates[name]
if !ok {
return fmt.Errorf("%s: no such file name", name)
}
return util.CreateTemplate(category, name, content)
}
// Update updates the template files to the templates built in current goctl.
func Update() error {
err := Clean()
if err != nil {
return err
}
return util.InitTemplates(category, templates)
}

View File

@@ -7,16 +7,20 @@ import (
"github.com/tal-tech/go-zero/tools/goctl/api/spec" "github.com/tal-tech/go-zero/tools/goctl/api/spec"
"github.com/tal-tech/go-zero/tools/goctl/config" "github.com/tal-tech/go-zero/tools/goctl/config"
"github.com/tal-tech/go-zero/tools/goctl/internal/version"
"github.com/tal-tech/go-zero/tools/goctl/util" "github.com/tal-tech/go-zero/tools/goctl/util"
"github.com/tal-tech/go-zero/tools/goctl/util/format" "github.com/tal-tech/go-zero/tools/goctl/util/format"
"github.com/tal-tech/go-zero/tools/goctl/vars" "github.com/tal-tech/go-zero/tools/goctl/vars"
) )
const handlerTemplate = `package handler const (
defaultLogicPackage = "logic"
handlerTemplate = `package {{.PkgName}}
import ( import (
"net/http" "net/http"
{{if .After1_1_10}}"github.com/tal-tech/go-zero/rest/httpx"{{end}}
{{.ImportPackages}} {{.ImportPackages}}
) )
@@ -26,9 +30,9 @@ func {{.HandlerName}}(ctx *svc.ServiceContext) http.HandlerFunc {
if err := httpx.Parse(r, &req); err != nil { if err := httpx.Parse(r, &req); err != nil {
httpx.Error(w, err) httpx.Error(w, err)
return return
}{{end}} }
l := logic.New{{.LogicType}}(r.Context(), ctx) {{end}}l := {{.LogicName}}.New{{.LogicType}}(r.Context(), ctx)
{{if .HasResp}}resp, {{end}}err := l.{{.Call}}({{if .HasRequest}}req{{end}}) {{if .HasResp}}resp, {{end}}err := l.{{.Call}}({{if .HasRequest}}req{{end}})
if err != nil { if err != nil {
httpx.Error(w, err) httpx.Error(w, err)
@@ -38,27 +42,45 @@ func {{.HandlerName}}(ctx *svc.ServiceContext) http.HandlerFunc {
} }
} }
` `
)
type handlerInfo struct { type handlerInfo struct {
PkgName string
ImportPackages string ImportPackages string
HandlerName string HandlerName string
RequestType string RequestType string
LogicName string
LogicType string LogicType string
Call string Call string
HasResp bool HasResp bool
HasRequest bool HasRequest bool
After1_1_10 bool
} }
func genHandler(dir, rootPkg string, cfg *config.Config, group spec.Group, route spec.Route) error { func genHandler(dir, rootPkg string, cfg *config.Config, group spec.Group, route spec.Route) error {
handler := getHandlerName(route) handler := getHandlerName(route)
if getHandlerFolderPath(group, route) != handlerDir { handlerPath := getHandlerFolderPath(group, route)
pkgName := handlerPath[strings.LastIndex(handlerPath, "/")+1:]
logicName := defaultLogicPackage
if handlerPath != handlerDir {
handler = strings.Title(handler) handler = strings.Title(handler)
logicName = pkgName
}
parentPkg, err := getParentPackage(dir)
if err != nil {
return err
} }
goctlVersion := version.GetGoctlVersion()
// todo(anqiansong): This will be removed after a certain number of production versions of goctl (probably 5)
after1_1_10 := version.IsVersionGreaterThan(goctlVersion, "1.1.10")
return doGenToFile(dir, handler, cfg, group, route, handlerInfo{ return doGenToFile(dir, handler, cfg, group, route, handlerInfo{
ImportPackages: genHandlerImports(group, route, rootPkg), PkgName: pkgName,
ImportPackages: genHandlerImports(group, route, parentPkg),
HandlerName: handler, HandlerName: handler,
After1_1_10: after1_1_10,
RequestType: util.Title(route.RequestTypeName()), RequestType: util.Title(route.RequestTypeName()),
LogicName: logicName,
LogicType: strings.Title(getLogicName(route)), LogicType: strings.Title(getLogicName(route)),
Call: strings.Title(strings.TrimSuffix(handler, "Handler")), Call: strings.Title(strings.TrimSuffix(handler, "Handler")),
HasResp: len(route.ResponseTypeName()) > 0, HasResp: len(route.ResponseTypeName()) > 0,
@@ -105,7 +127,12 @@ func genHandlerImports(group spec.Group, route spec.Route, parentPkg string) str
if len(route.RequestTypeName()) > 0 { if len(route.RequestTypeName()) > 0 {
imports = append(imports, fmt.Sprintf("\"%s\"\n", util.JoinPackages(parentPkg, typesDir))) imports = append(imports, fmt.Sprintf("\"%s\"\n", util.JoinPackages(parentPkg, typesDir)))
} }
imports = append(imports, fmt.Sprintf("\"%s/rest/httpx\"", vars.ProjectOpenSourceURL))
currentVersion := version.GetGoctlVersion()
// todo(anqiansong): This will be removed after a certain number of production versions of goctl (probably 5)
if !version.IsVersionGreaterThan(currentVersion, "1.1.10") {
imports = append(imports, fmt.Sprintf("\"%s/rest/httpx\"", vars.ProjectOpenSourceURL))
}
return strings.Join(imports, "\n\t") return strings.Join(imports, "\n\t")
} }
@@ -126,6 +153,7 @@ func getHandlerFolderPath(group spec.Group, route spec.Route) string {
return handlerDir return handlerDir
} }
} }
folder = strings.TrimPrefix(folder, "/") folder = strings.TrimPrefix(folder, "/")
folder = strings.TrimSuffix(folder, "/") folder = strings.TrimSuffix(folder, "/")
return path.Join(handlerDir, folder) return path.Join(handlerDir, folder)

View File

@@ -12,7 +12,7 @@ import (
"github.com/tal-tech/go-zero/tools/goctl/vars" "github.com/tal-tech/go-zero/tools/goctl/vars"
) )
const logicTemplate = `package logic const logicTemplate = `package {{.pkgName}}
import ( import (
{{.imports}} {{.imports}}
@@ -78,15 +78,17 @@ func genLogicByRoute(dir, rootPkg string, cfg *config.Config, group spec.Group,
requestString = "req " + requestGoTypeName(route, typesPacket) requestString = "req " + requestGoTypeName(route, typesPacket)
} }
subDir := getLogicFolderPath(group, route)
return genFile(fileGenConfig{ return genFile(fileGenConfig{
dir: dir, dir: dir,
subdir: getLogicFolderPath(group, route), subdir: subDir,
filename: goFile + ".go", filename: goFile + ".go",
templateName: "logicTemplate", templateName: "logicTemplate",
category: category, category: category,
templateFile: logicTemplateFile, templateFile: logicTemplateFile,
builtinTemplate: logicTemplate, builtinTemplate: logicTemplate,
data: map[string]string{ data: map[string]string{
"pkgName": subDir[strings.LastIndex(subDir, "/")+1:],
"imports": imports, "imports": imports,
"logic": strings.Title(logic), "logic": strings.Title(logic),
"function": strings.Title(strings.TrimSuffix(logic, "Logic")), "function": strings.Title(strings.TrimSuffix(logic, "Logic")),

View File

@@ -41,14 +41,16 @@ func main() {
func genMain(dir, rootPkg string, cfg *config.Config, api *spec.ApiSpec) error { func genMain(dir, rootPkg string, cfg *config.Config, api *spec.ApiSpec) error {
name := strings.ToLower(api.Service.Name) name := strings.ToLower(api.Service.Name)
if strings.HasSuffix(name, "-api") {
name = strings.ReplaceAll(name, "-api", "")
}
filename, err := format.FileNamingFormat(cfg.NamingFormat, name) filename, err := format.FileNamingFormat(cfg.NamingFormat, name)
if err != nil { if err != nil {
return err return err
} }
configName := filename
if strings.HasSuffix(filename, "-api") {
filename = strings.ReplaceAll(filename, "-api", "")
}
return genFile(fileGenConfig{ return genFile(fileGenConfig{
dir: dir, dir: dir,
subdir: "", subdir: "",
@@ -59,7 +61,7 @@ func genMain(dir, rootPkg string, cfg *config.Config, api *spec.ApiSpec) error {
builtinTemplate: mainTemplate, builtinTemplate: mainTemplate,
data: map[string]string{ data: map[string]string{
"importPackages": genMainImports(rootPkg), "importPackages": genMainImports(rootPkg),
"serviceName": api.Service.Name, "serviceName": configName,
}, },
}) })
} }

View File

@@ -45,7 +45,7 @@ func (v *ApiVisitor) VisitApi(ctx *api.ApiContext) interface{} {
func (v *ApiVisitor) acceptService(root, final *Api) { func (v *ApiVisitor) acceptService(root, final *Api) {
for _, service := range root.Service { for _, service := range root.Service {
if _, ok := final.serviceM[service.ServiceApi.Name.Text()]; !ok && len(final.serviceM) > 0 { if _, ok := final.serviceM[service.ServiceApi.Name.Text()]; !ok && len(final.serviceM) > 0 {
v.panic(service.ServiceApi.Name, fmt.Sprintf("mutiple service declaration")) v.panic(service.ServiceApi.Name, "multiple service declaration")
} }
v.duplicateServerItemCheck(service) v.duplicateServerItemCheck(service)
@@ -75,11 +75,11 @@ func (v *ApiVisitor) acceptService(root, final *Api) {
} }
if handlerExpr == nil { if handlerExpr == nil {
v.panic(route.Route.Method, fmt.Sprintf("mismtached handler")) v.panic(route.Route.Method, "mismatched handler")
} }
if handlerExpr.Text() == "" { if handlerExpr.Text() == "" {
v.panic(handlerExpr, fmt.Sprintf("mismtached handler")) v.panic(handlerExpr, "mismatched handler")
} }
if _, ok := final.handlerM[handlerExpr.Text()]; ok { if _, ok := final.handlerM[handlerExpr.Text()]; ok {
@@ -119,7 +119,7 @@ func (v *ApiVisitor) acceptInfo(root, final *Api) {
if root.Info != nil { if root.Info != nil {
infoM := map[string]PlaceHolder{} infoM := map[string]PlaceHolder{}
if final.Info != nil { if final.Info != nil {
v.panic(root.Info.Info, fmt.Sprintf("mutiple info declaration")) v.panic(root.Info.Info, "multiple info declaration")
} }
for _, value := range root.Info.Kvs { for _, value := range root.Info.Kvs {
@@ -147,7 +147,7 @@ func (v *ApiVisitor) acceptImport(root, final *Api) {
func (v *ApiVisitor) acceptSyntax(root, final *Api) { func (v *ApiVisitor) acceptSyntax(root, final *Api) {
if root.Syntax != nil { if root.Syntax != nil {
if final.Syntax != nil { if final.Syntax != nil {
v.panic(root.Syntax.Syntax, fmt.Sprintf("mutiple syntax declaration")) v.panic(root.Syntax.Syntax, "multiple syntax declaration")
} }
final.Syntax = root.Syntax final.Syntax = root.Syntax

View File

@@ -104,6 +104,7 @@ func (v *ApiVisitor) newExprWithTerminalNode(node antlr.TerminalNode) *defaultEx
if node == nil { if node == nil {
return nil return nil
} }
token := node.GetSymbol() token := node.GetSymbol()
return v.newExprWithToken(token) return v.newExprWithToken(token)
} }
@@ -132,6 +133,7 @@ func (v *ApiVisitor) newExprWithText(text string, line, column, start, stop int)
instance.column = column instance.column = column
instance.start = start instance.start = start
instance.stop = stop instance.stop = stop
return instance return instance
} }
@@ -193,11 +195,7 @@ func (e *defaultExpr) Stop() int {
func (e *defaultExpr) Equal(expr Expr) bool { func (e *defaultExpr) Equal(expr Expr) bool {
if e == nil { if e == nil {
if expr != nil { return expr == nil
return false
}
return true
} }
if expr == nil { if expr == nil {
@@ -252,8 +250,7 @@ func EqualDoc(spec1, spec2 Spec) bool {
} }
func (v *ApiVisitor) getDoc(t TokenStream) []Expr { func (v *ApiVisitor) getDoc(t TokenStream) []Expr {
list := v.getHiddenTokensToLeft(t, api.COMEMNTS, false) return v.getHiddenTokensToLeft(t, api.COMEMNTS, false)
return list
} }
func (v *ApiVisitor) getComment(t TokenStream) Expr { func (v *ApiVisitor) getComment(t TokenStream) Expr {
@@ -277,13 +274,9 @@ func (v *ApiVisitor) getComment(t TokenStream) Expr {
func (v *ApiVisitor) getHiddenTokensToLeft(t TokenStream, channel int, containsCommentOfDefaultChannel bool) []Expr { func (v *ApiVisitor) getHiddenTokensToLeft(t TokenStream, channel int, containsCommentOfDefaultChannel bool) []Expr {
ct := t.GetParser().GetTokenStream().(*antlr.CommonTokenStream) ct := t.GetParser().GetTokenStream().(*antlr.CommonTokenStream)
tokens := ct.GetHiddenTokensToLeft(t.GetStart().GetTokenIndex(), channel) tokens := ct.GetHiddenTokensToLeft(t.GetStart().GetTokenIndex(), channel)
var tmp []antlr.Token
for _, each := range tokens {
tmp = append(tmp, each)
}
var list []Expr var list []Expr
for _, each := range tmp { for _, each := range tokens {
if !containsCommentOfDefaultChannel { if !containsCommentOfDefaultChannel {
index := each.GetTokenIndex() - 1 index := each.GetTokenIndex() - 1

View File

@@ -64,9 +64,8 @@ func (p parser) convert2Spec() error {
} }
func (p parser) fillInfo() { func (p parser) fillInfo() {
properties := make(map[string]string, 0) properties := make(map[string]string)
if p.ast.Info != nil { if p.ast.Info != nil {
p.spec.Info = spec.Info{}
for _, kv := range p.ast.Info.Kvs { for _, kv := range p.ast.Info.Kvs {
properties[kv.Key.Text()] = kv.Value.Text() properties[kv.Key.Text()] = kv.Value.Text()
} }
@@ -258,7 +257,7 @@ func (p parser) fillService() error {
route.ResponseType = p.astTypeToSpec(astRoute.Route.Reply.Name) route.ResponseType = p.astTypeToSpec(astRoute.Route.Reply.Name)
} }
if astRoute.AtDoc != nil { if astRoute.AtDoc != nil {
properties := make(map[string]string, 0) properties := make(map[string]string)
for _, kv := range astRoute.AtDoc.Kv { for _, kv := range astRoute.AtDoc.Kv {
properties[kv.Key.Text()] = kv.Value.Text() properties[kv.Key.Text()] = kv.Value.Text()
} }
@@ -290,7 +289,7 @@ func (p parser) fillService() error {
func (p parser) fillRouteAtServer(astRoute *ast.ServiceRoute, route *spec.Route) error { func (p parser) fillRouteAtServer(astRoute *ast.ServiceRoute, route *spec.Route) error {
if astRoute.AtServer != nil { if astRoute.AtServer != nil {
properties := make(map[string]string, 0) properties := make(map[string]string)
for _, kv := range astRoute.AtServer.Kv { for _, kv := range astRoute.AtServer.Kv {
properties[kv.Key.Text()] = kv.Value.Text() properties[kv.Key.Text()] = kv.Value.Text()
} }
@@ -314,7 +313,7 @@ func (p parser) fillRouteAtServer(astRoute *ast.ServiceRoute, route *spec.Route)
func (p parser) fillAtServer(item *ast.Service, group *spec.Group) { func (p parser) fillAtServer(item *ast.Service, group *spec.Group) {
if item.AtServer != nil { if item.AtServer != nil {
properties := make(map[string]string, 0) properties := make(map[string]string)
for _, kv := range item.AtServer.Kv { for _, kv := range item.AtServer.Kv {
properties[kv.Key.Text()] = kv.Value.Text() properties[kv.Key.Text()] = kv.Value.Text()
} }

View File

@@ -5,10 +5,8 @@ import (
"strings" "strings"
) )
const ( // DefaultFormat defines a default naming style
// DefaultFormat defines a default naming style const DefaultFormat = "gozero"
DefaultFormat = "gozero"
)
// Config defines the file naming style // Config defines the file naming style
type Config struct { type Config struct {

View File

@@ -1,95 +0,0 @@
package configgen
import (
"errors"
"fmt"
"os"
"os/exec"
"path/filepath"
"strings"
"text/template"
"github.com/logrusorgru/aurora"
"github.com/tal-tech/go-zero/tools/goctl/util"
"github.com/urfave/cli"
)
const configTemplate = `package main
import (
"io/ioutil"
"os"
"{{.import}}"
"github.com/ghodss/yaml"
)
func main() {
var c config.Config
template, err := yaml.Marshal(c)
if err != nil {
panic(err)
}
err = ioutil.WriteFile("config.yaml", template, os.ModePerm)
if err != nil {
panic(err)
}
}
`
// GenConfigCommand provides the entry of goctl config
func GenConfigCommand(c *cli.Context) error {
path, err := filepath.Abs(c.String("path"))
if err != nil {
return errors.New("abs failed: " + c.String("path"))
}
goModPath, found := util.FindGoModPath(path)
if !found {
return errors.New("go mod not initial")
}
path = strings.TrimSuffix(path, "/config.go")
location := filepath.Join(path, "tmp")
err = os.MkdirAll(location, os.ModePerm)
if err != nil {
return err
}
goPath := filepath.Join(location, "config.go")
fp, err := os.Create(goPath)
if err != nil {
return err
}
defer fp.Close()
defer os.RemoveAll(location)
t := template.Must(template.New("template").Parse(configTemplate))
if err := t.Execute(fp, map[string]string{
"import": filepath.Dir(goModPath),
}); err != nil {
return err
}
gen := exec.Command("go", "run", "config.go")
gen.Dir = filepath.Dir(goPath)
gen.Stderr = os.Stderr
gen.Stdout = os.Stdout
err = gen.Run()
if err != nil {
panic(err)
}
path, err = os.Getwd()
if err != nil {
panic(err)
}
err = os.Rename(filepath.Dir(goPath)+"/config.yaml", path+"/config.yaml")
if err != nil {
panic(err)
}
fmt.Println(aurora.Green("Done."))
return nil
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,15 @@
package errorx
import (
"errors"
"testing"
"github.com/stretchr/testify/assert"
)
func TestWrap(t *testing.T) {
err := errors.New("foo")
err = Wrap(err)
_, ok := err.(*GoctlError)
assert.True(t, ok)
}

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