Compare commits
58 Commits
v1.5.3
...
tools/goct
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
57644420ed | ||
|
|
b245159417 | ||
|
|
c26ea17669 | ||
|
|
a7daff3587 | ||
|
|
6719d06146 | ||
|
|
0c6eaeda9f | ||
|
|
b9c0c0f8b5 | ||
|
|
77da459165 | ||
|
|
13cdbdc98b | ||
|
|
e8c1e6e09b | ||
|
|
f1171e01f2 | ||
|
|
61e562d0c7 | ||
|
|
b71453985c | ||
|
|
31b9ba19a2 | ||
|
|
3170afd57b | ||
|
|
03e365a5d8 | ||
|
|
7d4fce9588 | ||
|
|
916cea858f | ||
|
|
a86942d532 | ||
|
|
f76c70ea9a | ||
|
|
4cbfdb3d74 | ||
|
|
aefa6dfb50 | ||
|
|
9047029475 | ||
|
|
f296c182f7 | ||
|
|
40e7a4cd07 | ||
|
|
92e5819e91 | ||
|
|
8d23ab158b | ||
|
|
bcccfab824 | ||
|
|
f7e701a634 | ||
|
|
7c2d8e5cc2 | ||
|
|
5b622d6265 | ||
|
|
c5510a4e1b | ||
|
|
2a33b74b35 | ||
|
|
45bb547a81 | ||
|
|
f5f5261556 | ||
|
|
b176d5d434 | ||
|
|
92f6c48349 | ||
|
|
71e8230e65 | ||
|
|
018fa8e0a0 | ||
|
|
979fe9718a | ||
|
|
f998803131 | ||
|
|
1262266ac2 | ||
|
|
9c32bf8478 | ||
|
|
37ec7f6443 | ||
|
|
2fdc4dfc0f | ||
|
|
4b2a6ba3de | ||
|
|
7fa3f10f22 | ||
|
|
4a29a0b642 | ||
|
|
a62745a152 | ||
|
|
28314326e7 | ||
|
|
f6bdb6e1de | ||
|
|
efa6940001 | ||
|
|
da81d8f774 | ||
|
|
fd84b27bdc | ||
|
|
6b4d0d89c0 | ||
|
|
d61a55f779 | ||
|
|
8ef4164209 | ||
|
|
50e29e2075 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -12,6 +12,7 @@
|
||||
|
||||
# ignore
|
||||
**/.idea
|
||||
**/.vscode
|
||||
**/.DS_Store
|
||||
**/logs
|
||||
**/adhoc
|
||||
|
||||
40
core/logx/fs.go
Normal file
40
core/logx/fs.go
Normal file
@@ -0,0 +1,40 @@
|
||||
package logx
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
)
|
||||
|
||||
var fileSys realFileSystem
|
||||
|
||||
type (
|
||||
fileSystem interface {
|
||||
Close(closer io.Closer) error
|
||||
Copy(writer io.Writer, reader io.Reader) (int64, error)
|
||||
Create(name string) (*os.File, error)
|
||||
Open(name string) (*os.File, error)
|
||||
Remove(name string) error
|
||||
}
|
||||
|
||||
realFileSystem struct{}
|
||||
)
|
||||
|
||||
func (fs realFileSystem) Close(closer io.Closer) error {
|
||||
return closer.Close()
|
||||
}
|
||||
|
||||
func (fs realFileSystem) Copy(writer io.Writer, reader io.Reader) (int64, error) {
|
||||
return io.Copy(writer, reader)
|
||||
}
|
||||
|
||||
func (fs realFileSystem) Create(name string) (*os.File, error) {
|
||||
return os.Create(name)
|
||||
}
|
||||
|
||||
func (fs realFileSystem) Open(name string) (*os.File, error) {
|
||||
return os.Open(name)
|
||||
}
|
||||
|
||||
func (fs realFileSystem) Remove(name string) error {
|
||||
return os.Remove(name)
|
||||
}
|
||||
@@ -68,22 +68,30 @@ func Close() error {
|
||||
|
||||
// Debug writes v into access log.
|
||||
func Debug(v ...any) {
|
||||
writeDebug(fmt.Sprint(v...))
|
||||
if shallLog(DebugLevel) {
|
||||
writeDebug(fmt.Sprint(v...))
|
||||
}
|
||||
}
|
||||
|
||||
// Debugf writes v with format into access log.
|
||||
func Debugf(format string, v ...any) {
|
||||
writeDebug(fmt.Sprintf(format, v...))
|
||||
if shallLog(DebugLevel) {
|
||||
writeDebug(fmt.Sprintf(format, v...))
|
||||
}
|
||||
}
|
||||
|
||||
// Debugv writes v into access log with json content.
|
||||
func Debugv(v any) {
|
||||
writeDebug(v)
|
||||
if shallLog(DebugLevel) {
|
||||
writeDebug(v)
|
||||
}
|
||||
}
|
||||
|
||||
// Debugw writes msg along with fields into access log.
|
||||
func Debugw(msg string, fields ...LogField) {
|
||||
writeDebug(msg, fields...)
|
||||
if shallLog(DebugLevel) {
|
||||
writeDebug(msg, fields...)
|
||||
}
|
||||
}
|
||||
|
||||
// Disable disables the logging.
|
||||
@@ -99,35 +107,47 @@ func DisableStat() {
|
||||
|
||||
// Error writes v into error log.
|
||||
func Error(v ...any) {
|
||||
writeError(fmt.Sprint(v...))
|
||||
if shallLog(ErrorLevel) {
|
||||
writeError(fmt.Sprint(v...))
|
||||
}
|
||||
}
|
||||
|
||||
// Errorf writes v with format into error log.
|
||||
func Errorf(format string, v ...any) {
|
||||
writeError(fmt.Errorf(format, v...).Error())
|
||||
if shallLog(ErrorLevel) {
|
||||
writeError(fmt.Errorf(format, v...).Error())
|
||||
}
|
||||
}
|
||||
|
||||
// ErrorStack writes v along with call stack into error log.
|
||||
func ErrorStack(v ...any) {
|
||||
// there is newline in stack string
|
||||
writeStack(fmt.Sprint(v...))
|
||||
if shallLog(ErrorLevel) {
|
||||
// there is newline in stack string
|
||||
writeStack(fmt.Sprint(v...))
|
||||
}
|
||||
}
|
||||
|
||||
// ErrorStackf writes v along with call stack in format into error log.
|
||||
func ErrorStackf(format string, v ...any) {
|
||||
// there is newline in stack string
|
||||
writeStack(fmt.Sprintf(format, v...))
|
||||
if shallLog(ErrorLevel) {
|
||||
// there is newline in stack string
|
||||
writeStack(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 any) {
|
||||
writeError(v)
|
||||
if shallLog(ErrorLevel) {
|
||||
writeError(v)
|
||||
}
|
||||
}
|
||||
|
||||
// Errorw writes msg along with fields into error log.
|
||||
func Errorw(msg string, fields ...LogField) {
|
||||
writeError(msg, fields...)
|
||||
if shallLog(ErrorLevel) {
|
||||
writeError(msg, fields...)
|
||||
}
|
||||
}
|
||||
|
||||
// Field returns a LogField for the given key and value.
|
||||
@@ -170,22 +190,30 @@ func Field(key string, value any) LogField {
|
||||
|
||||
// Info writes v into access log.
|
||||
func Info(v ...any) {
|
||||
writeInfo(fmt.Sprint(v...))
|
||||
if shallLog(InfoLevel) {
|
||||
writeInfo(fmt.Sprint(v...))
|
||||
}
|
||||
}
|
||||
|
||||
// Infof writes v with format into access log.
|
||||
func Infof(format string, v ...any) {
|
||||
writeInfo(fmt.Sprintf(format, v...))
|
||||
if shallLog(InfoLevel) {
|
||||
writeInfo(fmt.Sprintf(format, v...))
|
||||
}
|
||||
}
|
||||
|
||||
// Infov writes v into access log with json content.
|
||||
func Infov(v any) {
|
||||
writeInfo(v)
|
||||
if shallLog(InfoLevel) {
|
||||
writeInfo(v)
|
||||
}
|
||||
}
|
||||
|
||||
// Infow writes msg along with fields into access log.
|
||||
func Infow(msg string, fields ...LogField) {
|
||||
writeInfo(msg, fields...)
|
||||
if shallLog(InfoLevel) {
|
||||
writeInfo(msg, fields...)
|
||||
}
|
||||
}
|
||||
|
||||
// Must checks if err is nil, otherwise logs the error and exits.
|
||||
@@ -194,7 +222,7 @@ func Must(err error) {
|
||||
return
|
||||
}
|
||||
|
||||
msg := err.Error()
|
||||
msg := fmt.Sprintf("%+v\n\n%s", err.Error(), debug.Stack())
|
||||
log.Print(msg)
|
||||
getWriter().Severe(msg)
|
||||
|
||||
@@ -269,42 +297,58 @@ func SetUp(c LogConf) (err error) {
|
||||
|
||||
// Severe writes v into severe log.
|
||||
func Severe(v ...any) {
|
||||
writeSevere(fmt.Sprint(v...))
|
||||
if shallLog(SevereLevel) {
|
||||
writeSevere(fmt.Sprint(v...))
|
||||
}
|
||||
}
|
||||
|
||||
// Severef writes v with format into severe log.
|
||||
func Severef(format string, v ...any) {
|
||||
writeSevere(fmt.Sprintf(format, v...))
|
||||
if shallLog(SevereLevel) {
|
||||
writeSevere(fmt.Sprintf(format, v...))
|
||||
}
|
||||
}
|
||||
|
||||
// Slow writes v into slow log.
|
||||
func Slow(v ...any) {
|
||||
writeSlow(fmt.Sprint(v...))
|
||||
if shallLog(ErrorLevel) {
|
||||
writeSlow(fmt.Sprint(v...))
|
||||
}
|
||||
}
|
||||
|
||||
// Slowf writes v with format into slow log.
|
||||
func Slowf(format string, v ...any) {
|
||||
writeSlow(fmt.Sprintf(format, v...))
|
||||
if shallLog(ErrorLevel) {
|
||||
writeSlow(fmt.Sprintf(format, v...))
|
||||
}
|
||||
}
|
||||
|
||||
// Slowv writes v into slow log with json content.
|
||||
func Slowv(v any) {
|
||||
writeSlow(v)
|
||||
if shallLog(ErrorLevel) {
|
||||
writeSlow(v)
|
||||
}
|
||||
}
|
||||
|
||||
// Sloww writes msg along with fields into slow log.
|
||||
func Sloww(msg string, fields ...LogField) {
|
||||
writeSlow(msg, fields...)
|
||||
if shallLog(ErrorLevel) {
|
||||
writeSlow(msg, fields...)
|
||||
}
|
||||
}
|
||||
|
||||
// Stat writes v into stat log.
|
||||
func Stat(v ...any) {
|
||||
writeStat(fmt.Sprint(v...))
|
||||
if shallLogStat() && shallLog(InfoLevel) {
|
||||
writeStat(fmt.Sprint(v...))
|
||||
}
|
||||
}
|
||||
|
||||
// Statf writes v with format into stat log.
|
||||
func Statf(format string, v ...any) {
|
||||
writeStat(fmt.Sprintf(format, v...))
|
||||
if shallLogStat() && shallLog(InfoLevel) {
|
||||
writeStat(fmt.Sprintf(format, v...))
|
||||
}
|
||||
}
|
||||
|
||||
// WithCooldownMillis customizes logging on writing call stack interval.
|
||||
@@ -429,44 +473,58 @@ func shallLogStat() bool {
|
||||
return atomic.LoadUint32(&disableStat) == 0
|
||||
}
|
||||
|
||||
// writeDebug writes v into debug log.
|
||||
// Not checking shallLog here is for performance consideration.
|
||||
// If we check shallLog here, the fmt.Sprint might be called even if the log level is not enabled.
|
||||
// The caller should check shallLog before calling this function.
|
||||
func writeDebug(val any, fields ...LogField) {
|
||||
if shallLog(DebugLevel) {
|
||||
getWriter().Debug(val, addCaller(fields...)...)
|
||||
}
|
||||
getWriter().Debug(val, addCaller(fields...)...)
|
||||
}
|
||||
|
||||
// writeError writes v into error log.
|
||||
// Not checking shallLog here is for performance consideration.
|
||||
// If we check shallLog here, the fmt.Sprint might be called even if the log level is not enabled.
|
||||
// The caller should check shallLog before calling this function.
|
||||
func writeError(val any, fields ...LogField) {
|
||||
if shallLog(ErrorLevel) {
|
||||
getWriter().Error(val, addCaller(fields...)...)
|
||||
}
|
||||
getWriter().Error(val, addCaller(fields...)...)
|
||||
}
|
||||
|
||||
// writeInfo writes v into info log.
|
||||
// Not checking shallLog here is for performance consideration.
|
||||
// If we check shallLog here, the fmt.Sprint might be called even if the log level is not enabled.
|
||||
// The caller should check shallLog before calling this function.
|
||||
func writeInfo(val any, fields ...LogField) {
|
||||
if shallLog(InfoLevel) {
|
||||
getWriter().Info(val, addCaller(fields...)...)
|
||||
}
|
||||
getWriter().Info(val, addCaller(fields...)...)
|
||||
}
|
||||
|
||||
// writeSevere writes v into severe log.
|
||||
// Not checking shallLog here is for performance consideration.
|
||||
// If we check shallLog here, the fmt.Sprint might be called even if the log level is not enabled.
|
||||
// The caller should check shallLog before calling this function.
|
||||
func writeSevere(msg string) {
|
||||
if shallLog(SevereLevel) {
|
||||
getWriter().Severe(fmt.Sprintf("%s\n%s", msg, string(debug.Stack())))
|
||||
}
|
||||
getWriter().Severe(fmt.Sprintf("%s\n%s", msg, string(debug.Stack())))
|
||||
}
|
||||
|
||||
// writeSlow writes v into slow log.
|
||||
// Not checking shallLog here is for performance consideration.
|
||||
// If we check shallLog here, the fmt.Sprint might be called even if the log level is not enabled.
|
||||
// The caller should check shallLog before calling this function.
|
||||
func writeSlow(val any, fields ...LogField) {
|
||||
if shallLog(ErrorLevel) {
|
||||
getWriter().Slow(val, addCaller(fields...)...)
|
||||
}
|
||||
getWriter().Slow(val, addCaller(fields...)...)
|
||||
}
|
||||
|
||||
// writeStack writes v into stack log.
|
||||
// Not checking shallLog here is for performance consideration.
|
||||
// If we check shallLog here, the fmt.Sprint might be called even if the log level is not enabled.
|
||||
// The caller should check shallLog before calling this function.
|
||||
func writeStack(msg string) {
|
||||
if shallLog(ErrorLevel) {
|
||||
getWriter().Stack(fmt.Sprintf("%s\n%s", msg, string(debug.Stack())))
|
||||
}
|
||||
getWriter().Stack(fmt.Sprintf("%s\n%s", msg, string(debug.Stack())))
|
||||
}
|
||||
|
||||
// writeStat writes v into stat log.
|
||||
// Not checking shallLog here is for performance consideration.
|
||||
// If we check shallLog here, the fmt.Sprint might be called even if the log level is not enabled.
|
||||
// The caller should check shallLog before calling this function.
|
||||
func writeStat(msg string) {
|
||||
if shallLogStat() && shallLog(InfoLevel) {
|
||||
getWriter().Stat(msg, addCaller()...)
|
||||
}
|
||||
getWriter().Stat(msg, addCaller()...)
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"compress/gzip"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"path"
|
||||
@@ -406,7 +405,7 @@ func (l *RotateLogger) write(v []byte) {
|
||||
func compressLogFile(file string) {
|
||||
start := time.Now()
|
||||
Infof("compressing log file: %s", file)
|
||||
if err := gzipFile(file); err != nil {
|
||||
if err := gzipFile(file, fileSys); err != nil {
|
||||
Errorf("compress error: %s", err)
|
||||
} else {
|
||||
Infof("compressed log file: %s, took %s", file, time.Since(start))
|
||||
@@ -421,25 +420,37 @@ func getNowDateInRFC3339Format() string {
|
||||
return time.Now().Format(fileTimeFormat)
|
||||
}
|
||||
|
||||
func gzipFile(file string) error {
|
||||
in, err := os.Open(file)
|
||||
func gzipFile(file string, fsys fileSystem) (err error) {
|
||||
in, err := fsys.Open(file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer in.Close()
|
||||
defer func() {
|
||||
if e := fsys.Close(in); e != nil {
|
||||
Errorf("failed to close file: %s, error: %v", file, e)
|
||||
}
|
||||
if err == nil {
|
||||
// only remove the original file when compression is successful
|
||||
err = fsys.Remove(file)
|
||||
}
|
||||
}()
|
||||
|
||||
out, err := os.Create(fmt.Sprintf("%s%s", file, gzipExt))
|
||||
out, err := fsys.Create(fmt.Sprintf("%s%s", file, gzipExt))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer out.Close()
|
||||
defer func() {
|
||||
e := fsys.Close(out)
|
||||
if err == nil {
|
||||
err = e
|
||||
}
|
||||
}()
|
||||
|
||||
w := gzip.NewWriter(out)
|
||||
if _, err = io.Copy(w, in); err != nil {
|
||||
return err
|
||||
} else if err = w.Close(); err != nil {
|
||||
if _, err = fsys.Copy(w, in); err != nil {
|
||||
// failed to copy, no need to close w
|
||||
return err
|
||||
}
|
||||
|
||||
return os.Remove(file)
|
||||
return fsys.Close(w)
|
||||
}
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
package logx
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"sync/atomic"
|
||||
"syscall"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -429,6 +432,70 @@ func TestRotateLoggerWithSizeLimitRotateRuleWrite(t *testing.T) {
|
||||
logger.write([]byte(`baz`))
|
||||
}
|
||||
|
||||
func TestGzipFile(t *testing.T) {
|
||||
err := errors.New("any error")
|
||||
|
||||
t.Run("gzip file open failed", func(t *testing.T) {
|
||||
fsys := &fakeFileSystem{
|
||||
openFn: func(name string) (*os.File, error) {
|
||||
return nil, err
|
||||
},
|
||||
}
|
||||
assert.ErrorIs(t, err, gzipFile("any", fsys))
|
||||
assert.False(t, fsys.Removed())
|
||||
})
|
||||
|
||||
t.Run("gzip file create failed", func(t *testing.T) {
|
||||
fsys := &fakeFileSystem{
|
||||
createFn: func(name string) (*os.File, error) {
|
||||
return nil, err
|
||||
},
|
||||
}
|
||||
assert.ErrorIs(t, err, gzipFile("any", fsys))
|
||||
assert.False(t, fsys.Removed())
|
||||
})
|
||||
|
||||
t.Run("gzip file copy failed", func(t *testing.T) {
|
||||
fsys := &fakeFileSystem{
|
||||
copyFn: func(writer io.Writer, reader io.Reader) (int64, error) {
|
||||
return 0, err
|
||||
},
|
||||
}
|
||||
assert.ErrorIs(t, err, gzipFile("any", fsys))
|
||||
assert.False(t, fsys.Removed())
|
||||
})
|
||||
|
||||
t.Run("gzip file last close failed", func(t *testing.T) {
|
||||
var called int32
|
||||
fsys := &fakeFileSystem{
|
||||
closeFn: func(closer io.Closer) error {
|
||||
if atomic.AddInt32(&called, 1) > 2 {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
assert.NoError(t, gzipFile("any", fsys))
|
||||
assert.True(t, fsys.Removed())
|
||||
})
|
||||
|
||||
t.Run("gzip file remove failed", func(t *testing.T) {
|
||||
fsys := &fakeFileSystem{
|
||||
removeFn: func(name string) error {
|
||||
return err
|
||||
},
|
||||
}
|
||||
assert.Error(t, err, gzipFile("any", fsys))
|
||||
assert.True(t, fsys.Removed())
|
||||
})
|
||||
|
||||
t.Run("gzip file everything ok", func(t *testing.T) {
|
||||
fsys := &fakeFileSystem{}
|
||||
assert.NoError(t, gzipFile("any", fsys))
|
||||
assert.True(t, fsys.Removed())
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkRotateLogger(b *testing.B) {
|
||||
filename := "./test.log"
|
||||
filename2 := "./test2.log"
|
||||
@@ -480,3 +547,53 @@ func BenchmarkRotateLogger(b *testing.B) {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
type fakeFileSystem struct {
|
||||
removed int32
|
||||
closeFn func(closer io.Closer) error
|
||||
copyFn func(writer io.Writer, reader io.Reader) (int64, error)
|
||||
createFn func(name string) (*os.File, error)
|
||||
openFn func(name string) (*os.File, error)
|
||||
removeFn func(name string) error
|
||||
}
|
||||
|
||||
func (f *fakeFileSystem) Close(closer io.Closer) error {
|
||||
if f.closeFn != nil {
|
||||
return f.closeFn(closer)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *fakeFileSystem) Copy(writer io.Writer, reader io.Reader) (int64, error) {
|
||||
if f.copyFn != nil {
|
||||
return f.copyFn(writer, reader)
|
||||
}
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
func (f *fakeFileSystem) Create(name string) (*os.File, error) {
|
||||
if f.createFn != nil {
|
||||
return f.createFn(name)
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (f *fakeFileSystem) Open(name string) (*os.File, error) {
|
||||
if f.openFn != nil {
|
||||
return f.openFn(name)
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (f *fakeFileSystem) Remove(name string) error {
|
||||
atomic.AddInt32(&f.removed, 1)
|
||||
|
||||
if f.removeFn != nil {
|
||||
return f.removeFn(name)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *fakeFileSystem) Removed() bool {
|
||||
return atomic.LoadInt32(&f.removed) > 0
|
||||
}
|
||||
|
||||
@@ -176,7 +176,12 @@ func (u *Unmarshaler) fillSlice(fieldType reflect.Type, value reflect.Value, map
|
||||
switch dereffedBaseKind {
|
||||
case reflect.Struct:
|
||||
target := reflect.New(dereffedBaseType)
|
||||
if err := u.Unmarshal(ithValue.(map[string]any), target.Interface()); err != nil {
|
||||
val, ok := ithValue.(map[string]any)
|
||||
if !ok {
|
||||
return errTypeMismatch
|
||||
}
|
||||
|
||||
if err := u.Unmarshal(val, target.Interface()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -613,7 +618,7 @@ func (u *Unmarshaler) processFieldPrimitiveWithJSONNumber(fieldType reflect.Type
|
||||
|
||||
target.SetFloat(fValue)
|
||||
default:
|
||||
return newTypeMismatchError(fullName)
|
||||
return newTypeMismatchErrorWithHint(fullName, typeKind.String(), value.Type().String())
|
||||
}
|
||||
|
||||
SetValue(fieldType, value, target)
|
||||
@@ -1049,6 +1054,11 @@ func newTypeMismatchError(name string) error {
|
||||
return fmt.Errorf("type mismatch for field %q", name)
|
||||
}
|
||||
|
||||
func newTypeMismatchErrorWithHint(name, expectType, actualType string) error {
|
||||
return fmt.Errorf("type mismatch for field %q, expect %q, actual %q",
|
||||
name, expectType, actualType)
|
||||
}
|
||||
|
||||
func readKeys(key string) []string {
|
||||
cacheKeysLock.Lock()
|
||||
keys, ok := cacheKeys[key]
|
||||
|
||||
@@ -3,6 +3,7 @@ package mapping
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
@@ -557,6 +558,15 @@ func TestUnmarshalIntWithString(t *testing.T) {
|
||||
var in inner
|
||||
assert.Error(t, UnmarshalKey(m, &in))
|
||||
})
|
||||
|
||||
t.Run("invalid options", func(t *testing.T) {
|
||||
type Value struct {
|
||||
Name string `key:"name,options="`
|
||||
}
|
||||
|
||||
var v Value
|
||||
assert.Error(t, UnmarshalKey(emptyMap, &v))
|
||||
})
|
||||
}
|
||||
|
||||
func TestUnmarshalBoolSliceRequired(t *testing.T) {
|
||||
@@ -675,28 +685,54 @@ func TestUnmarshalFloatSliceWithDefault(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestUnmarshalStringSliceWithDefault(t *testing.T) {
|
||||
type inner struct {
|
||||
Strs []string `key:"strs,default=[foo,bar,woo]"`
|
||||
Strps []*string `key:"strs,default=[foo,bar,woo]"`
|
||||
Strpps []**string `key:"strs,default=[foo,bar,woo]"`
|
||||
}
|
||||
|
||||
var in inner
|
||||
if assert.NoError(t, UnmarshalKey(nil, &in)) {
|
||||
assert.ElementsMatch(t, []string{"foo", "bar", "woo"}, in.Strs)
|
||||
|
||||
var ss []string
|
||||
for _, s := range in.Strps {
|
||||
ss = append(ss, *s)
|
||||
t.Run("slice with default", func(t *testing.T) {
|
||||
type inner struct {
|
||||
Strs []string `key:"strs,default=[foo,bar,woo]"`
|
||||
Strps []*string `key:"strs,default=[foo,bar,woo]"`
|
||||
Strpps []**string `key:"strs,default=[foo,bar,woo]"`
|
||||
}
|
||||
assert.ElementsMatch(t, []string{"foo", "bar", "woo"}, ss)
|
||||
|
||||
var sss []string
|
||||
for _, s := range in.Strpps {
|
||||
sss = append(sss, **s)
|
||||
var in inner
|
||||
if assert.NoError(t, UnmarshalKey(nil, &in)) {
|
||||
assert.ElementsMatch(t, []string{"foo", "bar", "woo"}, in.Strs)
|
||||
|
||||
var ss []string
|
||||
for _, s := range in.Strps {
|
||||
ss = append(ss, *s)
|
||||
}
|
||||
assert.ElementsMatch(t, []string{"foo", "bar", "woo"}, ss)
|
||||
|
||||
var sss []string
|
||||
for _, s := range in.Strpps {
|
||||
sss = append(sss, **s)
|
||||
}
|
||||
assert.ElementsMatch(t, []string{"foo", "bar", "woo"}, sss)
|
||||
}
|
||||
assert.ElementsMatch(t, []string{"foo", "bar", "woo"}, sss)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("slice with default on errors", func(t *testing.T) {
|
||||
type (
|
||||
holder struct {
|
||||
Chan []chan int
|
||||
}
|
||||
|
||||
inner struct {
|
||||
Strs []holder `key:"strs,default=[foo,bar,woo]"`
|
||||
}
|
||||
)
|
||||
|
||||
var in inner
|
||||
assert.Error(t, UnmarshalKey(nil, &in))
|
||||
})
|
||||
|
||||
t.Run("slice with default on errors", func(t *testing.T) {
|
||||
type inner struct {
|
||||
Strs []complex64 `key:"strs,default=[foo,bar,woo]"`
|
||||
}
|
||||
|
||||
var in inner
|
||||
assert.Error(t, UnmarshalKey(nil, &in))
|
||||
})
|
||||
}
|
||||
|
||||
func TestUnmarshalStringSliceWithDefaultHasSpaces(t *testing.T) {
|
||||
@@ -1327,25 +1363,71 @@ func TestUnmarshalStructOptionalDependsNotErrorDetails(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestUnmarshalStructOptionalDependsNotNested(t *testing.T) {
|
||||
type address struct {
|
||||
Optional string `key:",optional"`
|
||||
OptionalDepends string `key:",optional=!Optional"`
|
||||
}
|
||||
type combo struct {
|
||||
Name string `key:"name,optional"`
|
||||
Address address `key:"address"`
|
||||
}
|
||||
type inner struct {
|
||||
Name string `key:"name"`
|
||||
Combo combo `key:"combo"`
|
||||
}
|
||||
t.Run("mutal optionals", func(t *testing.T) {
|
||||
type address struct {
|
||||
Optional string `key:",optional"`
|
||||
OptionalDepends string `key:",optional=!Optional"`
|
||||
}
|
||||
type combo struct {
|
||||
Name string `key:"name,optional"`
|
||||
Address address `key:"address"`
|
||||
}
|
||||
type inner struct {
|
||||
Name string `key:"name"`
|
||||
Combo combo `key:"combo"`
|
||||
}
|
||||
|
||||
m := map[string]any{
|
||||
"name": "kevin",
|
||||
}
|
||||
m := map[string]any{
|
||||
"name": "kevin",
|
||||
}
|
||||
|
||||
var in inner
|
||||
assert.Error(t, UnmarshalKey(m, &in))
|
||||
var in inner
|
||||
assert.Error(t, UnmarshalKey(m, &in))
|
||||
})
|
||||
|
||||
t.Run("bad format", func(t *testing.T) {
|
||||
type address struct {
|
||||
Optional string `key:",optional"`
|
||||
OptionalDepends string `key:",optional=!Optional=abcd"`
|
||||
}
|
||||
type combo struct {
|
||||
Name string `key:"name,optional"`
|
||||
Address address `key:"address"`
|
||||
}
|
||||
type inner struct {
|
||||
Name string `key:"name"`
|
||||
Combo combo `key:"combo"`
|
||||
}
|
||||
|
||||
m := map[string]any{
|
||||
"name": "kevin",
|
||||
}
|
||||
|
||||
var in inner
|
||||
assert.Error(t, UnmarshalKey(m, &in))
|
||||
})
|
||||
|
||||
t.Run("invalid option", func(t *testing.T) {
|
||||
type address struct {
|
||||
Optional string `key:",optional"`
|
||||
OptionalDepends string `key:",opt=abcd"`
|
||||
}
|
||||
type combo struct {
|
||||
Name string `key:"name,optional"`
|
||||
Address address `key:"address"`
|
||||
}
|
||||
type inner struct {
|
||||
Name string `key:"name"`
|
||||
Combo combo `key:"combo"`
|
||||
}
|
||||
|
||||
m := map[string]any{
|
||||
"name": "kevin",
|
||||
}
|
||||
|
||||
var in inner
|
||||
assert.Error(t, UnmarshalKey(m, &in))
|
||||
})
|
||||
}
|
||||
|
||||
func TestUnmarshalStructOptionalNestedDifferentKey(t *testing.T) {
|
||||
@@ -3855,20 +3937,37 @@ func TestUnmarshalValuer(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestUnmarshal_EnvString(t *testing.T) {
|
||||
type Value struct {
|
||||
Name string `key:"name,env=TEST_NAME_STRING"`
|
||||
}
|
||||
t.Run("valid env", func(t *testing.T) {
|
||||
type Value struct {
|
||||
Name string `key:"name,env=TEST_NAME_STRING"`
|
||||
}
|
||||
|
||||
const (
|
||||
envName = "TEST_NAME_STRING"
|
||||
envVal = "this is a name"
|
||||
)
|
||||
t.Setenv(envName, envVal)
|
||||
const (
|
||||
envName = "TEST_NAME_STRING"
|
||||
envVal = "this is a name"
|
||||
)
|
||||
t.Setenv(envName, envVal)
|
||||
|
||||
var v Value
|
||||
if assert.NoError(t, UnmarshalKey(emptyMap, &v)) {
|
||||
assert.Equal(t, envVal, v.Name)
|
||||
}
|
||||
var v Value
|
||||
if assert.NoError(t, UnmarshalKey(emptyMap, &v)) {
|
||||
assert.Equal(t, envVal, v.Name)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("invalid env", func(t *testing.T) {
|
||||
type Value struct {
|
||||
Name string `key:"name,env=TEST_NAME_STRING=invalid"`
|
||||
}
|
||||
|
||||
const (
|
||||
envName = "TEST_NAME_STRING"
|
||||
envVal = "this is a name"
|
||||
)
|
||||
t.Setenv(envName, envVal)
|
||||
|
||||
var v Value
|
||||
assert.Error(t, UnmarshalKey(emptyMap, &v))
|
||||
})
|
||||
}
|
||||
|
||||
func TestUnmarshal_EnvStringOverwrite(t *testing.T) {
|
||||
@@ -4044,20 +4143,22 @@ func TestUnmarshal_EnvDurationBadValue(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestUnmarshal_EnvWithOptions(t *testing.T) {
|
||||
type Value struct {
|
||||
Name string `key:"name,env=TEST_NAME_ENV_OPTIONS_MATCH,options=[abc,123,xyz]"`
|
||||
}
|
||||
t.Run("valid options", func(t *testing.T) {
|
||||
type Value struct {
|
||||
Name string `key:"name,env=TEST_NAME_ENV_OPTIONS_MATCH,options=[abc,123,xyz]"`
|
||||
}
|
||||
|
||||
const (
|
||||
envName = "TEST_NAME_ENV_OPTIONS_MATCH"
|
||||
envVal = "123"
|
||||
)
|
||||
t.Setenv(envName, envVal)
|
||||
const (
|
||||
envName = "TEST_NAME_ENV_OPTIONS_MATCH"
|
||||
envVal = "123"
|
||||
)
|
||||
t.Setenv(envName, envVal)
|
||||
|
||||
var v Value
|
||||
if assert.NoError(t, UnmarshalKey(emptyMap, &v)) {
|
||||
assert.Equal(t, envVal, v.Name)
|
||||
}
|
||||
var v Value
|
||||
if assert.NoError(t, UnmarshalKey(emptyMap, &v)) {
|
||||
assert.Equal(t, envVal, v.Name)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestUnmarshal_EnvWithOptionsWrongValueBool(t *testing.T) {
|
||||
@@ -4881,6 +4982,34 @@ func TestUnmarshaler_Unmarshal(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
// TestUnmarshalerProcessFieldPrimitiveWithJSONNumber test the number type check.
|
||||
func TestUnmarshalerProcessFieldPrimitiveWithJSONNumber(t *testing.T) {
|
||||
t.Run("wrong type", func(t *testing.T) {
|
||||
expectValue := "1"
|
||||
realValue := 1
|
||||
fieldType := reflect.TypeOf(expectValue)
|
||||
value := reflect.ValueOf(&realValue) // pass a pointer to the value
|
||||
v := json.Number(expectValue)
|
||||
m := NewUnmarshaler("field")
|
||||
err := m.processFieldPrimitiveWithJSONNumber(fieldType, value.Elem(), v,
|
||||
&fieldOptionsWithContext{}, "field")
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, `type mismatch for field "field", expect "string", actual "int"`, err.Error())
|
||||
})
|
||||
|
||||
t.Run("right type", func(t *testing.T) {
|
||||
expectValue := int64(1)
|
||||
realValue := int64(1)
|
||||
fieldType := reflect.TypeOf(expectValue)
|
||||
value := reflect.ValueOf(&realValue) // pass a pointer to the value
|
||||
v := json.Number(strconv.FormatInt(expectValue, 10))
|
||||
m := NewUnmarshaler("field")
|
||||
err := m.processFieldPrimitiveWithJSONNumber(fieldType, value.Elem(), v,
|
||||
&fieldOptionsWithContext{}, "field")
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestGetValueWithChainedKeys(t *testing.T) {
|
||||
t.Run("no key", func(t *testing.T) {
|
||||
_, ok := getValueWithChainedKeys(nil, []string{})
|
||||
|
||||
@@ -372,8 +372,6 @@ func parseOption(fieldOpts *fieldOptions, fieldName, option string) error {
|
||||
default:
|
||||
return fmt.Errorf("field %q has wrong optional", fieldName)
|
||||
}
|
||||
case option == optionalOption:
|
||||
fieldOpts.Optional = true
|
||||
case strings.HasPrefix(option, optionsOption):
|
||||
val, err := parseProperty(fieldName, optionsOption, option)
|
||||
if err != nil {
|
||||
|
||||
@@ -241,7 +241,8 @@ func TestValidatePtrWithZeroValue(t *testing.T) {
|
||||
|
||||
func TestSetValueNotSettable(t *testing.T) {
|
||||
var i int
|
||||
assert.NotNil(t, setValueFromString(reflect.Int, reflect.ValueOf(i), "1"))
|
||||
assert.Error(t, setValueFromString(reflect.Int, reflect.ValueOf(i), "1"))
|
||||
assert.Error(t, validateAndSetValue(reflect.Int, reflect.ValueOf(i), "1", nil))
|
||||
}
|
||||
|
||||
func TestParseKeyAndOptionsErrors(t *testing.T) {
|
||||
@@ -300,3 +301,36 @@ func TestSetValueFormatErrors(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateValueRange(t *testing.T) {
|
||||
t.Run("float", func(t *testing.T) {
|
||||
assert.NoError(t, validateValueRange(1.2, nil))
|
||||
})
|
||||
|
||||
t.Run("float number range", func(t *testing.T) {
|
||||
assert.NoError(t, validateNumberRange(1.2, nil))
|
||||
})
|
||||
|
||||
t.Run("bad float", func(t *testing.T) {
|
||||
assert.Error(t, validateValueRange("a", &fieldOptionsWithContext{
|
||||
Range: &numberRange{},
|
||||
}))
|
||||
})
|
||||
|
||||
t.Run("bad float validate", func(t *testing.T) {
|
||||
var v struct {
|
||||
Foo float32
|
||||
}
|
||||
assert.Error(t, validateAndSetValue(reflect.Int, reflect.ValueOf(&v).Elem().Field(0),
|
||||
"1", &fieldOptionsWithContext{
|
||||
Range: &numberRange{
|
||||
left: 2,
|
||||
right: 3,
|
||||
},
|
||||
}))
|
||||
})
|
||||
}
|
||||
|
||||
func TestSetMatchedPrimitiveValue(t *testing.T) {
|
||||
assert.Error(t, setMatchedPrimitiveValue(reflect.Func, reflect.ValueOf(2), "1"))
|
||||
}
|
||||
|
||||
@@ -574,6 +574,7 @@ func TestMapReduceWithContext(t *testing.T) {
|
||||
cancel()
|
||||
}
|
||||
writer.Write(i)
|
||||
time.Sleep(time.Millisecond)
|
||||
}, func(pipe <-chan int, cancel func(error)) {
|
||||
for item := range pipe {
|
||||
i := item
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
//go:build windows
|
||||
|
||||
package proc
|
||||
|
||||
func dumpGoroutines() {
|
||||
}
|
||||
@@ -18,7 +18,11 @@ const (
|
||||
debugLevel = 2
|
||||
)
|
||||
|
||||
func dumpGoroutines() {
|
||||
type creator interface {
|
||||
Create(name string) (file *os.File, err error)
|
||||
}
|
||||
|
||||
func dumpGoroutines(ctor creator) {
|
||||
command := path.Base(os.Args[0])
|
||||
pid := syscall.Getpid()
|
||||
dumpFile := path.Join(os.TempDir(), fmt.Sprintf("%s-%d-goroutines-%s.dump",
|
||||
@@ -26,10 +30,16 @@ func dumpGoroutines() {
|
||||
|
||||
logx.Infof("Got dump goroutine signal, printing goroutine profile to %s", dumpFile)
|
||||
|
||||
if f, err := os.Create(dumpFile); err != nil {
|
||||
if f, err := ctor.Create(dumpFile); err != nil {
|
||||
logx.Errorf("Failed to dump goroutine profile, error: %v", err)
|
||||
} else {
|
||||
defer f.Close()
|
||||
pprof.Lookup(goroutineProfile).WriteTo(f, debugLevel)
|
||||
}
|
||||
}
|
||||
|
||||
type fileCreator struct{}
|
||||
|
||||
func (fc fileCreator) Create(name string) (file *os.File, err error) {
|
||||
return os.Create(name)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
//go:build linux || darwin
|
||||
|
||||
package proc
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
@@ -9,7 +13,29 @@ import (
|
||||
)
|
||||
|
||||
func TestDumpGoroutines(t *testing.T) {
|
||||
buf := logtest.NewCollector(t)
|
||||
dumpGoroutines()
|
||||
assert.True(t, strings.Contains(buf.String(), ".dump"))
|
||||
t.Run("real file", func(t *testing.T) {
|
||||
buf := logtest.NewCollector(t)
|
||||
dumpGoroutines(fileCreator{})
|
||||
assert.True(t, strings.Contains(buf.String(), ".dump"))
|
||||
})
|
||||
|
||||
t.Run("fake file", func(t *testing.T) {
|
||||
const msg = "any message"
|
||||
buf := logtest.NewCollector(t)
|
||||
err := errors.New(msg)
|
||||
dumpGoroutines(fakeCreator{
|
||||
file: &os.File{},
|
||||
err: err,
|
||||
})
|
||||
assert.True(t, strings.Contains(buf.String(), msg))
|
||||
})
|
||||
}
|
||||
|
||||
type fakeCreator struct {
|
||||
file *os.File
|
||||
err error
|
||||
}
|
||||
|
||||
func (fc fakeCreator) Create(name string) (file *os.File, err error) {
|
||||
return fc.file, fc.err
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ func init() {
|
||||
v := <-signals
|
||||
switch v {
|
||||
case syscall.SIGUSR1:
|
||||
dumpGoroutines()
|
||||
dumpGoroutines(fileCreator{})
|
||||
case syscall.SIGUSR2:
|
||||
if profiler == nil {
|
||||
profiler = StartProfile()
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
//go:build linux || darwin
|
||||
|
||||
package proc
|
||||
|
||||
import (
|
||||
|
||||
@@ -2,6 +2,7 @@ package queue
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"math"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
@@ -39,7 +40,7 @@ func TestQueue(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestQueue_Broadcast(t *testing.T) {
|
||||
producer := newMockedProducer(rounds)
|
||||
producer := newMockedProducer(math.MaxInt32)
|
||||
consumer := newMockedConsumer()
|
||||
consumer.wait.Add(consumers)
|
||||
q := NewQueue(func() (Producer, error) {
|
||||
@@ -51,14 +52,14 @@ func TestQueue_Broadcast(t *testing.T) {
|
||||
q.SetName("mockqueue")
|
||||
q.SetNumConsumer(consumers)
|
||||
q.SetNumProducer(1)
|
||||
q.Broadcast("message")
|
||||
go func() {
|
||||
producer.wait.Wait()
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
q.Stop()
|
||||
}()
|
||||
q.Start()
|
||||
go q.Start()
|
||||
time.Sleep(time.Millisecond * 50)
|
||||
q.Broadcast("message")
|
||||
consumer.wait.Wait()
|
||||
assert.Equal(t, int32(rounds), atomic.LoadInt32(&consumer.count))
|
||||
assert.Equal(t, int32(consumers), atomic.LoadInt32(&consumer.events))
|
||||
}
|
||||
|
||||
|
||||
@@ -171,11 +171,11 @@ func add(nd *node, route string, item any) error {
|
||||
token := route[:i]
|
||||
children := nd.getChildren(token)
|
||||
if child, ok := children[token]; ok {
|
||||
if child != nil {
|
||||
return add(child, route[i+1:], item)
|
||||
if child == nil {
|
||||
return errInvalidState
|
||||
}
|
||||
|
||||
return errInvalidState
|
||||
return add(child, route[i+1:], item)
|
||||
}
|
||||
|
||||
child := newNode(nil)
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
|
||||
type mockedRoute struct {
|
||||
route string
|
||||
value int
|
||||
value any
|
||||
}
|
||||
|
||||
func TestSearch(t *testing.T) {
|
||||
@@ -187,6 +187,12 @@ func TestSearchInvalidItem(t *testing.T) {
|
||||
assert.Equal(t, errEmptyItem, err)
|
||||
}
|
||||
|
||||
func TestSearchInvalidState(t *testing.T) {
|
||||
nd := newNode("0")
|
||||
nd.children[0]["1"] = nil
|
||||
assert.Error(t, add(nd, "1/2", "2"))
|
||||
}
|
||||
|
||||
func BenchmarkSearchTree(b *testing.B) {
|
||||
const (
|
||||
avgLen = 1000
|
||||
|
||||
@@ -68,7 +68,7 @@ func (sg *ServiceGroup) doStart() {
|
||||
|
||||
for i := range sg.services {
|
||||
service := sg.services[i]
|
||||
routineGroup.RunSafe(func() {
|
||||
routineGroup.Run(func() {
|
||||
service.Start()
|
||||
})
|
||||
}
|
||||
|
||||
@@ -14,30 +14,6 @@ var (
|
||||
done = make(chan struct{})
|
||||
)
|
||||
|
||||
type mockedService struct {
|
||||
quit chan struct{}
|
||||
multiplier int
|
||||
}
|
||||
|
||||
func newMockedService(multiplier int) *mockedService {
|
||||
return &mockedService{
|
||||
quit: make(chan struct{}),
|
||||
multiplier: multiplier,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *mockedService) Start() {
|
||||
mutex.Lock()
|
||||
number *= s.multiplier
|
||||
mutex.Unlock()
|
||||
done <- struct{}{}
|
||||
<-s.quit
|
||||
}
|
||||
|
||||
func (s *mockedService) Stop() {
|
||||
close(s.quit)
|
||||
}
|
||||
|
||||
func TestServiceGroup(t *testing.T) {
|
||||
multipliers := []int{2, 3, 5, 7}
|
||||
want := 1
|
||||
@@ -126,3 +102,27 @@ type mockedStarter struct {
|
||||
func (s mockedStarter) Start() {
|
||||
s.fn()
|
||||
}
|
||||
|
||||
type mockedService struct {
|
||||
quit chan struct{}
|
||||
multiplier int
|
||||
}
|
||||
|
||||
func newMockedService(multiplier int) *mockedService {
|
||||
return &mockedService{
|
||||
quit: make(chan struct{}),
|
||||
multiplier: multiplier,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *mockedService) Start() {
|
||||
mutex.Lock()
|
||||
number *= s.multiplier
|
||||
mutex.Unlock()
|
||||
done <- struct{}{}
|
||||
<-s.quit
|
||||
}
|
||||
|
||||
func (s *mockedService) Stop() {
|
||||
close(s.quit)
|
||||
}
|
||||
|
||||
@@ -219,6 +219,7 @@ func parseUints(val string) ([]uint64, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var sets []uint64
|
||||
ints := make(map[uint64]lang.PlaceholderType)
|
||||
cols := strings.Split(val, ",")
|
||||
for _, r := range cols {
|
||||
@@ -239,7 +240,10 @@ func parseUints(val string) ([]uint64, error) {
|
||||
}
|
||||
|
||||
for i := min; i <= max; i++ {
|
||||
ints[i] = lang.Placeholder
|
||||
if _, ok := ints[i]; !ok {
|
||||
ints[i] = lang.Placeholder
|
||||
sets = append(sets, i)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
v, err := parseUint(r)
|
||||
@@ -247,19 +251,17 @@ func parseUints(val string) ([]uint64, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ints[v] = lang.Placeholder
|
||||
if _, ok := ints[v]; !ok {
|
||||
ints[v] = lang.Placeholder
|
||||
sets = append(sets, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var sets []uint64
|
||||
for k := range ints {
|
||||
sets = append(sets, k)
|
||||
}
|
||||
|
||||
return sets, nil
|
||||
}
|
||||
|
||||
// runningInUserNS detects whether we are currently running in an user namespace.
|
||||
// runningInUserNS detects whether we are currently running in a user namespace.
|
||||
func runningInUserNS() bool {
|
||||
nsOnce.Do(func() {
|
||||
file, err := os.Open("/proc/self/uid_map")
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -25,3 +26,46 @@ func TestCgroupV1(t *testing.T) {
|
||||
assert.Error(t, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseUint(t *testing.T) {
|
||||
tests := []struct {
|
||||
input string
|
||||
want uint64
|
||||
err error
|
||||
}{
|
||||
{"0", 0, nil},
|
||||
{"123", 123, nil},
|
||||
{"-1", 0, nil},
|
||||
{"-18446744073709551616", 0, nil},
|
||||
{"foo", 0, fmt.Errorf("cgroup: bad int format: foo")},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
got, err := parseUint(tt.input)
|
||||
assert.Equal(t, tt.err, err)
|
||||
assert.Equal(t, tt.want, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseUints(t *testing.T) {
|
||||
tests := []struct {
|
||||
input string
|
||||
want []uint64
|
||||
err error
|
||||
}{
|
||||
{"", nil, nil},
|
||||
{"1,2,3", []uint64{1, 2, 3}, nil},
|
||||
{"1-3", []uint64{1, 2, 3}, nil},
|
||||
{"1-3,5,7-9", []uint64{1, 2, 3, 5, 7, 8, 9}, nil},
|
||||
{"foo", nil, fmt.Errorf("cgroup: bad int format: foo")},
|
||||
{"1-bar", nil, fmt.Errorf("cgroup: bad int list format: 1-bar")},
|
||||
{"bar-3", nil, fmt.Errorf("cgroup: bad int list format: bar-3")},
|
||||
{"3-1", nil, fmt.Errorf("cgroup: bad int list format: 3-1")},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
got, err := parseUints(tt.input)
|
||||
assert.Equal(t, tt.err, err)
|
||||
assert.Equal(t, tt.want, got)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,6 +97,9 @@ func (cc CachedConn) Exec(exec ExecFn, keys ...string) (sql.Result, error) {
|
||||
}
|
||||
|
||||
// ExecCtx runs given exec on given keys, and returns execution result.
|
||||
// If DB operation succeeds, it will delete cache with given keys,
|
||||
// if DB operation fails, it will return nil result and non-nil error,
|
||||
// if DB operation succeeds but cache deletion fails, it will return result and non-nil error.
|
||||
func (cc CachedConn) ExecCtx(ctx context.Context, exec ExecCtxFn, keys ...string) (
|
||||
sql.Result, error) {
|
||||
res, err := exec(ctx, cc.db)
|
||||
@@ -104,11 +107,7 @@ func (cc CachedConn) ExecCtx(ctx context.Context, exec ExecCtxFn, keys ...string
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := cc.DelCacheCtx(ctx, keys...); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return res, nil
|
||||
return res, cc.DelCacheCtx(ctx, keys...)
|
||||
}
|
||||
|
||||
// ExecNoCache runs exec with given sql statement, without affecting cache.
|
||||
|
||||
@@ -471,31 +471,33 @@ func TestCachedConnExec(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCachedConnExecDropCache(t *testing.T) {
|
||||
r, err := miniredis.Run()
|
||||
assert.Nil(t, err)
|
||||
defer fx.DoWithTimeout(func() error {
|
||||
r.Close()
|
||||
return nil
|
||||
}, time.Second)
|
||||
t.Run("drop cache", func(t *testing.T) {
|
||||
r, err := miniredis.Run()
|
||||
assert.Nil(t, err)
|
||||
defer fx.DoWithTimeout(func() error {
|
||||
r.Close()
|
||||
return nil
|
||||
}, time.Second)
|
||||
|
||||
const (
|
||||
key = "user"
|
||||
value = "any"
|
||||
)
|
||||
var conn trackedConn
|
||||
c := NewNodeConn(&conn, redis.New(r.Addr()), cache.WithExpiry(time.Second*30))
|
||||
assert.Nil(t, c.SetCache(key, value))
|
||||
_, err = c.Exec(func(conn sqlx.SqlConn) (result sql.Result, e error) {
|
||||
return conn.Exec("delete from user_table where id='kevin'")
|
||||
}, key)
|
||||
assert.Nil(t, err)
|
||||
assert.True(t, conn.execValue)
|
||||
_, err = r.Get(key)
|
||||
assert.Exactly(t, miniredis.ErrKeyNotFound, err)
|
||||
_, err = c.Exec(func(conn sqlx.SqlConn) (result sql.Result, e error) {
|
||||
return nil, errors.New("foo")
|
||||
}, key)
|
||||
assert.NotNil(t, err)
|
||||
const (
|
||||
key = "user"
|
||||
value = "any"
|
||||
)
|
||||
var conn trackedConn
|
||||
c := NewNodeConn(&conn, redis.New(r.Addr()), cache.WithExpiry(time.Second*30))
|
||||
assert.Nil(t, c.SetCache(key, value))
|
||||
_, err = c.Exec(func(conn sqlx.SqlConn) (result sql.Result, e error) {
|
||||
return conn.Exec("delete from user_table where id='kevin'")
|
||||
}, key)
|
||||
assert.Nil(t, err)
|
||||
assert.True(t, conn.execValue)
|
||||
_, err = r.Get(key)
|
||||
assert.Exactly(t, miniredis.ErrKeyNotFound, err)
|
||||
_, err = c.Exec(func(conn sqlx.SqlConn) (result sql.Result, e error) {
|
||||
return nil, errors.New("foo")
|
||||
}, key)
|
||||
assert.NotNil(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestCachedConn_SetCacheWithExpire(t *testing.T) {
|
||||
|
||||
@@ -32,7 +32,5 @@ func mysqlAcceptable(err error) bool {
|
||||
}
|
||||
|
||||
func withMysqlAcceptable() SqlOption {
|
||||
return func(conn *commonSqlConn) {
|
||||
conn.accept = mysqlAcceptable
|
||||
}
|
||||
return WithAcceptable(mysqlAcceptable)
|
||||
}
|
||||
|
||||
@@ -399,3 +399,11 @@ func (s statement) QueryRowsPartialCtx(ctx context.Context, v any, args ...any)
|
||||
return unmarshalRows(v, rows, false)
|
||||
}, s.query, args...)
|
||||
}
|
||||
|
||||
// WithAcceptable returns a SqlOption that setting the acceptable function.
|
||||
// acceptable is the func to check if the error can be accepted.
|
||||
func WithAcceptable(acceptable func(err error) bool) SqlOption {
|
||||
return func(conn *commonSqlConn) {
|
||||
conn.accept = acceptable
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,7 +42,8 @@ func (manager *ResourceManager) Close() error {
|
||||
}
|
||||
|
||||
// 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.singleFlight.Do(key, func() (any, error) {
|
||||
manager.lock.RLock()
|
||||
resource, ok := manager.resources[key]
|
||||
|
||||
@@ -9,25 +9,44 @@ import (
|
||||
)
|
||||
|
||||
func TestTimeoutLimit(t *testing.T) {
|
||||
limit := NewTimeoutLimit(2)
|
||||
assert.Nil(t, limit.Borrow(time.Millisecond*200))
|
||||
assert.Nil(t, limit.Borrow(time.Millisecond*200))
|
||||
var wait1, wait2, wait3 sync.WaitGroup
|
||||
wait1.Add(1)
|
||||
wait2.Add(1)
|
||||
wait3.Add(1)
|
||||
go func() {
|
||||
wait1.Wait()
|
||||
wait2.Done()
|
||||
assert.Nil(t, limit.Return())
|
||||
wait3.Done()
|
||||
}()
|
||||
wait1.Done()
|
||||
wait2.Wait()
|
||||
assert.Nil(t, limit.Borrow(time.Second))
|
||||
wait3.Wait()
|
||||
assert.Equal(t, ErrTimeout, limit.Borrow(time.Millisecond*100))
|
||||
assert.Nil(t, limit.Return())
|
||||
assert.Nil(t, limit.Return())
|
||||
assert.Equal(t, ErrLimitReturn, limit.Return())
|
||||
tests := []struct {
|
||||
name string
|
||||
interval time.Duration
|
||||
}{
|
||||
{
|
||||
name: "no wait",
|
||||
},
|
||||
{
|
||||
name: "wait",
|
||||
interval: time.Millisecond * 100,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
test := test
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
limit := NewTimeoutLimit(2)
|
||||
assert.Nil(t, limit.Borrow(time.Millisecond*200))
|
||||
assert.Nil(t, limit.Borrow(time.Millisecond*200))
|
||||
var wait1, wait2, wait3 sync.WaitGroup
|
||||
wait1.Add(1)
|
||||
wait2.Add(1)
|
||||
wait3.Add(1)
|
||||
go func() {
|
||||
wait1.Wait()
|
||||
wait2.Done()
|
||||
time.Sleep(test.interval)
|
||||
assert.Nil(t, limit.Return())
|
||||
wait3.Done()
|
||||
}()
|
||||
wait1.Done()
|
||||
wait2.Wait()
|
||||
assert.Nil(t, limit.Borrow(time.Second))
|
||||
wait3.Wait()
|
||||
assert.Equal(t, ErrTimeout, limit.Borrow(time.Millisecond*100))
|
||||
assert.Nil(t, limit.Return())
|
||||
assert.Nil(t, limit.Return())
|
||||
assert.Equal(t, ErrLimitReturn, limit.Return())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
37
go.mod
37
go.mod
@@ -4,7 +4,7 @@ go 1.18
|
||||
|
||||
require (
|
||||
github.com/DATA-DOG/go-sqlmock v1.5.0
|
||||
github.com/alicebob/miniredis/v2 v2.30.3
|
||||
github.com/alicebob/miniredis/v2 v2.30.4
|
||||
github.com/fatih/color v1.15.0
|
||||
github.com/fullstorydev/grpcurl v1.8.7
|
||||
github.com/go-redis/redis/v8 v8.11.5
|
||||
@@ -13,16 +13,16 @@ require (
|
||||
github.com/golang/mock v1.6.0
|
||||
github.com/golang/protobuf v1.5.3
|
||||
github.com/google/uuid v1.3.0
|
||||
github.com/jackc/pgx/v5 v5.3.1
|
||||
github.com/jackc/pgx/v5 v5.4.2
|
||||
github.com/jhump/protoreflect v1.15.1
|
||||
github.com/olekukonko/tablewriter v0.0.5
|
||||
github.com/pelletier/go-toml/v2 v2.0.8
|
||||
github.com/prometheus/client_golang v1.15.1
|
||||
github.com/pelletier/go-toml/v2 v2.0.9
|
||||
github.com/prometheus/client_golang v1.16.0
|
||||
github.com/spaolacci/murmur3 v1.1.0
|
||||
github.com/stretchr/testify v1.8.4
|
||||
go.etcd.io/etcd/api/v3 v3.5.9
|
||||
go.etcd.io/etcd/client/v3 v3.5.9
|
||||
go.mongodb.org/mongo-driver v1.11.6
|
||||
go.mongodb.org/mongo-driver v1.12.0
|
||||
go.opentelemetry.io/otel v1.14.0
|
||||
go.opentelemetry.io/otel/exporters/jaeger v1.14.0
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.14.0
|
||||
@@ -33,12 +33,12 @@ require (
|
||||
go.opentelemetry.io/otel/trace v1.14.0
|
||||
go.uber.org/automaxprocs v1.5.2
|
||||
go.uber.org/goleak v1.2.1
|
||||
golang.org/x/net v0.10.0
|
||||
golang.org/x/sys v0.8.0
|
||||
golang.org/x/net v0.12.0
|
||||
golang.org/x/sys v0.10.0
|
||||
golang.org/x/time v0.3.0
|
||||
google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4
|
||||
google.golang.org/grpc v1.55.0
|
||||
google.golang.org/protobuf v1.30.0
|
||||
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1
|
||||
google.golang.org/grpc v1.56.2
|
||||
google.golang.org/protobuf v1.31.0
|
||||
gopkg.in/cheggaaa/pb.v1 v1.0.28
|
||||
gopkg.in/h2non/gock.v1 v1.1.2
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
@@ -86,15 +86,14 @@ require (
|
||||
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/openzipkin/zipkin-go v0.4.1 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/prometheus/client_model v0.3.0 // indirect
|
||||
github.com/prometheus/common v0.42.0 // indirect
|
||||
github.com/prometheus/procfs v0.9.0 // indirect
|
||||
github.com/prometheus/procfs v0.10.1 // indirect
|
||||
github.com/rivo/uniseg v0.2.0 // indirect
|
||||
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
|
||||
github.com/xdg-go/scram v1.1.1 // indirect
|
||||
github.com/xdg-go/stringprep v1.0.3 // indirect
|
||||
github.com/xdg-go/scram v1.1.2 // indirect
|
||||
github.com/xdg-go/stringprep v1.0.4 // indirect
|
||||
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect
|
||||
github.com/yuin/gopher-lua v1.1.0 // indirect
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.9 // indirect
|
||||
@@ -104,11 +103,11 @@ require (
|
||||
go.uber.org/atomic v1.10.0 // indirect
|
||||
go.uber.org/multierr v1.9.0 // indirect
|
||||
go.uber.org/zap v1.24.0 // indirect
|
||||
golang.org/x/crypto v0.6.0 // indirect
|
||||
golang.org/x/oauth2 v0.6.0 // indirect
|
||||
golang.org/x/sync v0.1.0 // indirect
|
||||
golang.org/x/term v0.8.0 // indirect
|
||||
golang.org/x/text v0.9.0 // indirect
|
||||
golang.org/x/crypto v0.11.0 // indirect
|
||||
golang.org/x/oauth2 v0.7.0 // indirect
|
||||
golang.org/x/sync v0.2.0 // indirect
|
||||
golang.org/x/term v0.10.0 // indirect
|
||||
golang.org/x/text v0.11.0 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
|
||||
89
go.sum
89
go.sum
@@ -38,8 +38,8 @@ github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a h1:HbKu58rmZpUGpz5+4FfNmIU+FmZg2P3Xaj2v2bfNWmk=
|
||||
github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc=
|
||||
github.com/alicebob/miniredis/v2 v2.30.3 h1:hrqDB4cHFSHQf4gO3xu6YKQg8PqJpNjLYsQAFYHstqw=
|
||||
github.com/alicebob/miniredis/v2 v2.30.3/go.mod h1:b25qWj4fCEsBeAAR2mlb0ufImGC6uH3VlUfb/HS5zKg=
|
||||
github.com/alicebob/miniredis/v2 v2.30.4 h1:8S4/o1/KoUArAGbGwPxcwf0krlzceva2XVOSchFS7Eo=
|
||||
github.com/alicebob/miniredis/v2 v2.30.4/go.mod h1:b25qWj4fCEsBeAAR2mlb0ufImGC6uH3VlUfb/HS5zKg=
|
||||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
@@ -200,8 +200,8 @@ github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsI
|
||||
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=
|
||||
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
|
||||
github.com/jackc/pgx/v5 v5.3.1 h1:Fcr8QJ1ZeLi5zsPZqQeUZhNhxfkkKBOgJuYkJHoBOtU=
|
||||
github.com/jackc/pgx/v5 v5.3.1/go.mod h1:t3JDKnCBlYIc0ewLF0Q7B8MXmoIaBOZj/ic7iHozM/8=
|
||||
github.com/jackc/pgx/v5 v5.4.2 h1:u1gmGDwbdRUZiwisBm/Ky2M14uQyUP65bG8+20nnyrg=
|
||||
github.com/jackc/pgx/v5 v5.4.2/go.mod h1:q6iHT8uDNXWiFNOlRqJzBTaSH3+2xCXkokxHZC5qWFY=
|
||||
github.com/jhump/gopoet v0.0.0-20190322174617-17282ff210b3/go.mod h1:me9yfT6IJSlOL3FCfrg+L6yzUEZ+5jW6WHt4Sk+UPUI=
|
||||
github.com/jhump/gopoet v0.1.0/go.mod h1:me9yfT6IJSlOL3FCfrg+L6yzUEZ+5jW6WHt4Sk+UPUI=
|
||||
github.com/jhump/goprotoc v0.5.0/go.mod h1:VrbvcYrQOrTi3i0Vf+m+oqQWk9l72mjkJCYo7UvLHRQ=
|
||||
@@ -259,22 +259,21 @@ github.com/onsi/ginkgo/v2 v2.7.0 h1:/XxtEV3I3Eif/HobnVx9YmJgk8ENdRsuUmM+fLCFNow=
|
||||
github.com/onsi/gomega v1.26.0 h1:03cDLK28U6hWvCAns6NeydX3zIm4SF3ci69ulidS32Q=
|
||||
github.com/openzipkin/zipkin-go v0.4.1 h1:kNd/ST2yLLWhaWrkgchya40TJabe8Hioj9udfPcEO5A=
|
||||
github.com/openzipkin/zipkin-go v0.4.1/go.mod h1:qY0VqDSN1pOBN94dBc6w2GJlWLiovAyg7Qt6/I9HecM=
|
||||
github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ=
|
||||
github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4=
|
||||
github.com/pelletier/go-toml/v2 v2.0.9 h1:uH2qQXheeefCCkuBBSLi7jCiSmj3VRh2+Goq2N7Xxu0=
|
||||
github.com/pelletier/go-toml/v2 v2.0.9/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g=
|
||||
github.com/prometheus/client_golang v1.15.1 h1:8tXpTmJbyH5lydzFPoxSIJ0J46jdh3tylbvM1xCv0LI=
|
||||
github.com/prometheus/client_golang v1.15.1/go.mod h1:e9yaBhRPU2pPNsZwE+JdQl0KEt1N9XgF6zxWmaC0xOk=
|
||||
github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8=
|
||||
github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4=
|
||||
github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w=
|
||||
github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM=
|
||||
github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc=
|
||||
github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI=
|
||||
github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY=
|
||||
github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+PymziUAg=
|
||||
github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM=
|
||||
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||
@@ -292,22 +291,18 @@ github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpE
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4=
|
||||
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
||||
github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
|
||||
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
|
||||
github.com/xdg-go/scram v1.1.1 h1:VOMT+81stJgXW3CpHyqHN3AXDYIMsx56mEFrB37Mb/E=
|
||||
github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g=
|
||||
github.com/xdg-go/stringprep v1.0.3 h1:kdwGpVNwPFtjs98xCGkHjQtGKh86rDcRZN17QEMCOIs=
|
||||
github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8=
|
||||
github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY=
|
||||
github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4=
|
||||
github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8=
|
||||
github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM=
|
||||
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA=
|
||||
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
|
||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
@@ -315,6 +310,7 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
|
||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
github.com/yuin/gopher-lua v1.1.0 h1:BojcDhfyDWgU2f2TOzYK/g5p2gxMrku8oupLDqlnSqE=
|
||||
github.com/yuin/gopher-lua v1.1.0/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw=
|
||||
go.etcd.io/etcd/api/v3 v3.5.9 h1:4wSsluwyTbGGmyjJktOf3wFQoTBIURXHnq9n/G/JQHs=
|
||||
@@ -323,8 +319,8 @@ go.etcd.io/etcd/client/pkg/v3 v3.5.9 h1:oidDC4+YEuSIQbsR94rY9gur91UPL6DnxDCIYd2I
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.9/go.mod h1:y+CzeSmkMpWN2Jyu1npecjB9BBnABxGM4pN8cGuJeL4=
|
||||
go.etcd.io/etcd/client/v3 v3.5.9 h1:r5xghnU7CwbUxD/fbUtRyJGaYNfDun8sp/gTr1hew6E=
|
||||
go.etcd.io/etcd/client/v3 v3.5.9/go.mod h1:i/Eo5LrZ5IKqpbtpPDuaUnDOUv471oDg8cjQaUr2MbA=
|
||||
go.mongodb.org/mongo-driver v1.11.6 h1:XM7G6PjiGAO5betLF13BIa5TlLUUE3uJ/2Ox3Lz1K+o=
|
||||
go.mongodb.org/mongo-driver v1.11.6/go.mod h1:G9TgswdsWjX4tmDA5zfs2+6AEPpYJwqblyjsfuh8oXY=
|
||||
go.mongodb.org/mongo-driver v1.12.0 h1:aPx33jmn/rQuJXPQLZQ8NtfPQG8CaqgLThFtqRb0PiE=
|
||||
go.mongodb.org/mongo-driver v1.12.0/go.mod h1:AZkxhPnFJUoH7kZlFkVKucV20K387miPfm7oimrSmK0=
|
||||
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=
|
||||
@@ -368,9 +364,10 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc=
|
||||
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
|
||||
golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA=
|
||||
golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio=
|
||||
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=
|
||||
@@ -402,6 +399,7 @@ golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzB
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@@ -429,18 +427,20 @@ golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81R
|
||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50=
|
||||
golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.6.0 h1:Lh8GPgSKBfWSwFvtuWOfeI3aAAnbXTSutYxJiOJFgIw=
|
||||
golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw=
|
||||
golang.org/x/oauth2 v0.7.0 h1:qe6s0zUXlPX80/dITx3440hWZ7GwMwgDDyrSGTPJG/g=
|
||||
golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -451,8 +451,9 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI=
|
||||
golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@@ -486,12 +487,15 @@ golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA=
|
||||
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.8.0 h1:n5xxQn2i3PC0yLAbjTpNT85q/Kgzcr2gIoX9OrJUols=
|
||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.10.0 h1:3R7pNqamzBraeqj/Tj8qt1aQ2HpmlC+Cx/qL/7hn4/c=
|
||||
golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
@@ -500,8 +504,10 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4=
|
||||
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
@@ -550,6 +556,7 @@ golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc
|
||||
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@@ -610,8 +617,8 @@ google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6D
|
||||
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||
google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA=
|
||||
google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s=
|
||||
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A=
|
||||
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU=
|
||||
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=
|
||||
@@ -630,8 +637,8 @@ google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQ
|
||||
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
|
||||
google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
|
||||
google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
|
||||
google.golang.org/grpc v1.55.0 h1:3Oj82/tFSCeUrRTg/5E/7d/W5A1tj6Ky1ABAuZuv5ag=
|
||||
google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8=
|
||||
google.golang.org/grpc v1.56.2 h1:fVRFRnXvU+x6C4IlHZewvJOVHoOv1TUuQyoRsYnB4bI=
|
||||
google.golang.org/grpc v1.56.2/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
@@ -646,8 +653,8 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
|
||||
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
|
||||
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
||||
@@ -53,6 +53,19 @@ func TestComboHealthManager(t *testing.T) {
|
||||
assert.True(t, chm.IsReady())
|
||||
})
|
||||
|
||||
t.Run("is ready verbose", func(t *testing.T) {
|
||||
chm := newComboHealthManager()
|
||||
hm := NewHealthManager(probeName)
|
||||
|
||||
assert.True(t, chm.IsReady())
|
||||
chm.addProbe(hm)
|
||||
assert.False(t, chm.IsReady())
|
||||
hm.MarkReady()
|
||||
assert.True(t, chm.IsReady())
|
||||
assert.Contains(t, chm.verboseInfo(), probeName)
|
||||
assert.Contains(t, chm.verboseInfo(), "is ready")
|
||||
})
|
||||
|
||||
t.Run("concurrent add probes", func(t *testing.T) {
|
||||
chm := newComboHealthManager()
|
||||
|
||||
|
||||
@@ -17,14 +17,6 @@
|
||||
|
||||
<a href="https://www.producthunt.com/posts/go-zero?utm_source=badge-featured&utm_medium=badge&utm_souce=badge-go-zero" target="_blank"><img src="https://api.producthunt.com/widgets/embed-image/v1/featured.svg?post_id=334030&theme=light" alt="go-zero - A web & rpc framework written in Go. | Product Hunt" style="width: 250px; height: 54px;" width="250" height="54" /></a>
|
||||
|
||||
> ***注意:***
|
||||
>
|
||||
> 从 v1.3.0 之前版本升级请执行以下命令:
|
||||
>
|
||||
> `GOPROXY=https://goproxy.cn/,direct go install github.com/zeromicro/go-zero/tools/goctl@latest`
|
||||
>
|
||||
> `goctl migrate —verbose —version v1.5.2`
|
||||
|
||||
## 0. go-zero 介绍
|
||||
|
||||
go-zero(收录于 CNCF 云原生技术全景图:[https://landscape.cncf.io/?selected=go-zero](https://landscape.cncf.io/?selected=go-zero))是一个集成了各种工程实践的 web 和 rpc 框架。通过弹性设计保障了大并发服务端的稳定性,经受了充分的实战检验。
|
||||
@@ -302,6 +294,7 @@ go-zero 已被许多公司用于生产部署,接入场景如在线教育、电
|
||||
>90. 元匠科技
|
||||
>91. 宁波甬风信息科技有限公司
|
||||
>92. 深圳市万佳安物联科技股份有限公司
|
||||
>93. 武侯区编程之美软件开发工作室
|
||||
|
||||
如果贵公司也已使用 go-zero,欢迎在 [登记地址](https://github.com/zeromicro/go-zero/issues/602) 登记,仅仅为了推广,不做其它用途。
|
||||
|
||||
|
||||
11
readme.md
11
readme.md
@@ -102,17 +102,6 @@ Run the following command under your project:
|
||||
```shell
|
||||
go get -u github.com/zeromicro/go-zero
|
||||
```
|
||||
## Upgrade
|
||||
|
||||
To upgrade from versions eariler than v1.3.0, run the following commands.
|
||||
|
||||
```shell
|
||||
go install github.com/zeromicro/go-zero/tools/goctl@latest
|
||||
```
|
||||
|
||||
```shell
|
||||
goctl migrate —verbose —version v1.5.2
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ func BreakerHandler(method, path string, metrics *stat.Metrics) func(http.Handle
|
||||
return
|
||||
}
|
||||
|
||||
cw := &response.WithCodeResponseWriter{Writer: w}
|
||||
cw := response.NewWithCodeResponseWriter(w)
|
||||
defer func() {
|
||||
if cw.Code < http.StatusInternalServerError {
|
||||
promise.Accept()
|
||||
|
||||
@@ -3,7 +3,6 @@ package handler
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
@@ -37,14 +36,11 @@ func LogHandler(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
timer := utils.NewElapsedTimer()
|
||||
logs := new(internal.LogCollector)
|
||||
lrw := response.WithCodeResponseWriter{
|
||||
Writer: w,
|
||||
Code: http.StatusOK,
|
||||
}
|
||||
lrw := response.NewWithCodeResponseWriter(w)
|
||||
|
||||
var dup io.ReadCloser
|
||||
r.Body, dup = iox.DupReadCloser(r.Body)
|
||||
next.ServeHTTP(&lrw, r.WithContext(context.WithValue(r.Context(), internal.LogContext, logs)))
|
||||
next.ServeHTTP(lrw, r.WithContext(internal.WithLogCollector(r.Context(), logs)))
|
||||
r.Body = dup
|
||||
logBrief(r, lrw.Code, timer, logs)
|
||||
})
|
||||
@@ -55,7 +51,8 @@ type detailLoggedResponseWriter struct {
|
||||
buf *bytes.Buffer
|
||||
}
|
||||
|
||||
func newDetailLoggedResponseWriter(writer *response.WithCodeResponseWriter, buf *bytes.Buffer) *detailLoggedResponseWriter {
|
||||
func newDetailLoggedResponseWriter(writer *response.WithCodeResponseWriter,
|
||||
buf *bytes.Buffer) *detailLoggedResponseWriter {
|
||||
return &detailLoggedResponseWriter{
|
||||
writer: writer,
|
||||
buf: buf,
|
||||
@@ -94,15 +91,13 @@ func DetailedLogHandler(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
timer := utils.NewElapsedTimer()
|
||||
var buf bytes.Buffer
|
||||
lrw := newDetailLoggedResponseWriter(&response.WithCodeResponseWriter{
|
||||
Writer: w,
|
||||
Code: http.StatusOK,
|
||||
}, &buf)
|
||||
rw := response.NewWithCodeResponseWriter(w)
|
||||
lrw := newDetailLoggedResponseWriter(rw, &buf)
|
||||
|
||||
var dup io.ReadCloser
|
||||
r.Body, dup = iox.DupReadCloser(r.Body)
|
||||
logs := new(internal.LogCollector)
|
||||
next.ServeHTTP(lrw, r.WithContext(context.WithValue(r.Context(), internal.LogContext, logs)))
|
||||
next.ServeHTTP(lrw, r.WithContext(internal.WithLogCollector(r.Context(), logs)))
|
||||
r.Body = dup
|
||||
logDetails(r, lrw, timer, logs)
|
||||
})
|
||||
|
||||
@@ -2,6 +2,7 @@ package handler
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
@@ -22,7 +23,7 @@ func TestLogHandler(t *testing.T) {
|
||||
for _, logHandler := range handlers {
|
||||
req := httptest.NewRequest(http.MethodGet, "http://localhost", http.NoBody)
|
||||
handler := logHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
r.Context().Value(internal.LogContext).(*internal.LogCollector).Append("anything")
|
||||
internal.LogCollectorFromContext(r.Context()).Append("anything")
|
||||
w.Header().Set("X-Test", "test")
|
||||
w.WriteHeader(http.StatusServiceUnavailable)
|
||||
_, err := w.Write([]byte("content"))
|
||||
@@ -49,7 +50,7 @@ func TestLogHandlerVeryLong(t *testing.T) {
|
||||
|
||||
req := httptest.NewRequest(http.MethodPost, "http://localhost", &buf)
|
||||
handler := LogHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
r.Context().Value(internal.LogContext).(*internal.LogCollector).Append("anything")
|
||||
internal.LogCollectorFromContext(r.Context()).Append("anything")
|
||||
_, _ = io.Copy(io.Discard, r.Body)
|
||||
w.Header().Set("X-Test", "test")
|
||||
w.WriteHeader(http.StatusServiceUnavailable)
|
||||
@@ -88,18 +89,23 @@ func TestLogHandlerSlow(t *testing.T) {
|
||||
func TestDetailedLogHandler_Hijack(t *testing.T) {
|
||||
resp := httptest.NewRecorder()
|
||||
writer := &detailLoggedResponseWriter{
|
||||
writer: &response.WithCodeResponseWriter{
|
||||
Writer: resp,
|
||||
},
|
||||
writer: response.NewWithCodeResponseWriter(resp),
|
||||
}
|
||||
assert.NotPanics(t, func() {
|
||||
_, _, _ = writer.Hijack()
|
||||
})
|
||||
|
||||
writer = &detailLoggedResponseWriter{
|
||||
writer: &response.WithCodeResponseWriter{
|
||||
Writer: mockedHijackable{resp},
|
||||
},
|
||||
writer: response.NewWithCodeResponseWriter(resp),
|
||||
}
|
||||
assert.NotPanics(t, func() {
|
||||
_, _, _ = writer.Hijack()
|
||||
})
|
||||
|
||||
writer = &detailLoggedResponseWriter{
|
||||
writer: response.NewWithCodeResponseWriter(mockedHijackable{
|
||||
ResponseRecorder: resp,
|
||||
}),
|
||||
}
|
||||
assert.NotPanics(t, func() {
|
||||
_, _, _ = writer.Hijack()
|
||||
@@ -133,6 +139,13 @@ func TestWrapStatusCodeWithColor(t *testing.T) {
|
||||
assert.Equal(t, "503", wrapStatusCode(http.StatusServiceUnavailable))
|
||||
}
|
||||
|
||||
func TestDumpRequest(t *testing.T) {
|
||||
const errMsg = "error"
|
||||
r := httptest.NewRequest(http.MethodGet, "http://localhost", http.NoBody)
|
||||
r.Body = mockedReadCloser{errMsg: errMsg}
|
||||
assert.Equal(t, errMsg, dumpRequest(r))
|
||||
}
|
||||
|
||||
func BenchmarkLogHandler(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
|
||||
@@ -146,3 +159,15 @@ func BenchmarkLogHandler(b *testing.B) {
|
||||
handler.ServeHTTP(resp, req)
|
||||
}
|
||||
}
|
||||
|
||||
type mockedReadCloser struct {
|
||||
errMsg string
|
||||
}
|
||||
|
||||
func (m mockedReadCloser) Read(p []byte) (n int, err error) {
|
||||
return 0, errors.New(m.errMsg)
|
||||
}
|
||||
|
||||
func (m mockedReadCloser) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ func PrometheusHandler(path, method string) func(http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
startTime := timex.Now()
|
||||
cw := &response.WithCodeResponseWriter{Writer: w}
|
||||
cw := response.NewWithCodeResponseWriter(w)
|
||||
defer func() {
|
||||
metricServerReqDur.Observe(timex.Since(startTime).Milliseconds(), path, method)
|
||||
metricServerReqCodeTotal.Inc(path, strconv.Itoa(cw.Code), method)
|
||||
|
||||
@@ -41,7 +41,7 @@ func SheddingHandler(shedder load.Shedder, metrics *stat.Metrics) func(http.Hand
|
||||
return
|
||||
}
|
||||
|
||||
cw := &response.WithCodeResponseWriter{Writer: w}
|
||||
cw := response.NewWithCodeResponseWriter(w)
|
||||
defer func() {
|
||||
if cw.Code == http.StatusServiceUnavailable {
|
||||
promise.Fail()
|
||||
|
||||
@@ -67,9 +67,10 @@ func (h *timeoutHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
r = r.WithContext(ctx)
|
||||
done := make(chan struct{})
|
||||
tw := &timeoutWriter{
|
||||
w: w,
|
||||
h: make(http.Header),
|
||||
req: r,
|
||||
w: w,
|
||||
h: make(http.Header),
|
||||
req: r,
|
||||
code: http.StatusOK,
|
||||
}
|
||||
panicChan := make(chan any, 1)
|
||||
go func() {
|
||||
@@ -91,10 +92,12 @@ func (h *timeoutHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
for k, vv := range tw.h {
|
||||
dst[k] = vv
|
||||
}
|
||||
if !tw.wroteHeader {
|
||||
tw.code = http.StatusOK
|
||||
|
||||
// We don't need to write header 200, because it's written by default.
|
||||
// If we write it again, it will cause a warning: `http: superfluous response.WriteHeader call`.
|
||||
if tw.code != http.StatusOK {
|
||||
w.WriteHeader(tw.code)
|
||||
}
|
||||
w.WriteHeader(tw.code)
|
||||
w.Write(tw.wbuf.Bytes())
|
||||
case <-ctx.Done():
|
||||
tw.mu.Lock()
|
||||
@@ -127,12 +130,29 @@ type timeoutWriter struct {
|
||||
|
||||
var _ http.Pusher = (*timeoutWriter)(nil)
|
||||
|
||||
// Flush implements the Flusher interface.
|
||||
func (tw *timeoutWriter) Flush() {
|
||||
if flusher, ok := tw.w.(http.Flusher); ok {
|
||||
flusher.Flush()
|
||||
flusher, ok := tw.w.(http.Flusher)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
header := tw.w.Header()
|
||||
for k, v := range tw.h {
|
||||
header[k] = v
|
||||
}
|
||||
|
||||
tw.w.Write(tw.wbuf.Bytes())
|
||||
tw.wbuf.Reset()
|
||||
flusher.Flush()
|
||||
}
|
||||
|
||||
// Header returns the underline temporary http.Header.
|
||||
func (tw *timeoutWriter) Header() http.Header {
|
||||
return tw.h
|
||||
}
|
||||
|
||||
// Hijack implements the Hijacker interface.
|
||||
func (tw *timeoutWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
||||
if hijacked, ok := tw.w.(http.Hijacker); ok {
|
||||
return hijacked.Hijack()
|
||||
@@ -141,14 +161,12 @@ func (tw *timeoutWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
||||
return nil, nil, errors.New("server doesn't support hijacking")
|
||||
}
|
||||
|
||||
// Header returns the underline temporary http.Header.
|
||||
func (tw *timeoutWriter) Header() http.Header { return tw.h }
|
||||
|
||||
// Push implements the Pusher interface.
|
||||
func (tw *timeoutWriter) Push(target string, opts *http.PushOptions) error {
|
||||
if pusher, ok := tw.w.(http.Pusher); ok {
|
||||
return pusher.Push(target, opts)
|
||||
}
|
||||
|
||||
return http.ErrNotSupported
|
||||
}
|
||||
|
||||
@@ -165,6 +183,7 @@ func (tw *timeoutWriter) Write(p []byte) (int, error) {
|
||||
if !tw.wroteHeader {
|
||||
tw.writeHeaderLocked(http.StatusOK)
|
||||
}
|
||||
|
||||
return tw.wbuf.Write(p)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -12,6 +16,66 @@ import (
|
||||
"github.com/zeromicro/go-zero/rest/internal/response"
|
||||
)
|
||||
|
||||
func TestTimeoutWriteFlushOutput(t *testing.T) {
|
||||
t.Run("flusher", func(t *testing.T) {
|
||||
timeoutHandler := TimeoutHandler(1000 * time.Millisecond)
|
||||
handler := timeoutHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "text/event-stream; charset=utf-8")
|
||||
flusher, ok := w.(http.Flusher)
|
||||
if !ok {
|
||||
http.Error(w, "Flushing not supported", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
for i := 1; i <= 5; i++ {
|
||||
fmt.Fprint(w, strconv.Itoa(i)+" cats\n\n")
|
||||
flusher.Flush()
|
||||
time.Sleep(time.Millisecond)
|
||||
}
|
||||
}))
|
||||
req := httptest.NewRequest(http.MethodGet, "http://localhost", http.NoBody)
|
||||
resp := httptest.NewRecorder()
|
||||
handler.ServeHTTP(resp, req)
|
||||
scanner := bufio.NewScanner(resp.Body)
|
||||
var cats int
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
if strings.Contains(line, "cats") {
|
||||
cats++
|
||||
}
|
||||
}
|
||||
if err := scanner.Err(); err != nil {
|
||||
cats = 0
|
||||
}
|
||||
assert.Equal(t, 5, cats)
|
||||
})
|
||||
|
||||
t.Run("writer", func(t *testing.T) {
|
||||
recorder := httptest.NewRecorder()
|
||||
timeoutHandler := TimeoutHandler(1000 * time.Millisecond)
|
||||
handler := timeoutHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "text/event-stream; charset=utf-8")
|
||||
flusher, ok := w.(http.Flusher)
|
||||
if !ok {
|
||||
http.Error(w, "Flushing not supported", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
for i := 1; i <= 5; i++ {
|
||||
fmt.Fprint(w, strconv.Itoa(i)+" cats\n\n")
|
||||
flusher.Flush()
|
||||
time.Sleep(time.Millisecond)
|
||||
assert.Empty(t, recorder.Body.String())
|
||||
}
|
||||
}))
|
||||
req := httptest.NewRequest(http.MethodGet, "http://localhost", http.NoBody)
|
||||
resp := mockedResponseWriter{recorder}
|
||||
handler.ServeHTTP(resp, req)
|
||||
assert.Equal(t, "1 cats\n\n2 cats\n\n3 cats\n\n4 cats\n\n5 cats\n\n",
|
||||
recorder.Body.String())
|
||||
})
|
||||
}
|
||||
|
||||
func TestTimeout(t *testing.T) {
|
||||
timeoutHandler := TimeoutHandler(time.Millisecond)
|
||||
handler := timeoutHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -36,6 +100,18 @@ func TestWithinTimeout(t *testing.T) {
|
||||
assert.Equal(t, http.StatusOK, resp.Code)
|
||||
}
|
||||
|
||||
func TestWithinTimeoutBadCode(t *testing.T) {
|
||||
timeoutHandler := TimeoutHandler(time.Second)
|
||||
handler := timeoutHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
}))
|
||||
|
||||
req := httptest.NewRequest(http.MethodGet, "http://localhost", http.NoBody)
|
||||
resp := httptest.NewRecorder()
|
||||
handler.ServeHTTP(resp, req)
|
||||
assert.Equal(t, http.StatusInternalServerError, resp.Code)
|
||||
}
|
||||
|
||||
func TestWithTimeoutTimedout(t *testing.T) {
|
||||
timeoutHandler := TimeoutHandler(time.Millisecond)
|
||||
handler := timeoutHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -144,9 +220,7 @@ func TestTimeoutHijack(t *testing.T) {
|
||||
resp := httptest.NewRecorder()
|
||||
|
||||
writer := &timeoutWriter{
|
||||
w: &response.WithCodeResponseWriter{
|
||||
Writer: resp,
|
||||
},
|
||||
w: response.NewWithCodeResponseWriter(resp),
|
||||
}
|
||||
|
||||
assert.NotPanics(t, func() {
|
||||
@@ -154,9 +228,7 @@ func TestTimeoutHijack(t *testing.T) {
|
||||
})
|
||||
|
||||
writer = &timeoutWriter{
|
||||
w: &response.WithCodeResponseWriter{
|
||||
Writer: mockedHijackable{resp},
|
||||
},
|
||||
w: response.NewWithCodeResponseWriter(mockedHijackable{resp}),
|
||||
}
|
||||
|
||||
assert.NotPanics(t, func() {
|
||||
@@ -210,9 +282,7 @@ func TestTimeoutWriter_Hijack(t *testing.T) {
|
||||
func TestTimeoutWroteTwice(t *testing.T) {
|
||||
c := logtest.NewCollector(t)
|
||||
writer := &timeoutWriter{
|
||||
w: &response.WithCodeResponseWriter{
|
||||
Writer: httptest.NewRecorder(),
|
||||
},
|
||||
w: response.NewWithCodeResponseWriter(httptest.NewRecorder()),
|
||||
h: make(http.Header),
|
||||
req: httptest.NewRequest(http.MethodGet, "http://localhost", http.NoBody),
|
||||
}
|
||||
@@ -238,3 +308,19 @@ func (m mockedPusher) WriteHeader(_ int) {
|
||||
func (m mockedPusher) Push(_ string, _ *http.PushOptions) error {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
type mockedResponseWriter struct {
|
||||
http.ResponseWriter
|
||||
}
|
||||
|
||||
func (m mockedResponseWriter) Header() http.Header {
|
||||
return m.ResponseWriter.Header()
|
||||
}
|
||||
|
||||
func (m mockedResponseWriter) Write(bytes []byte) (int, error) {
|
||||
return m.ResponseWriter.Write(bytes)
|
||||
}
|
||||
|
||||
func (m mockedResponseWriter) WriteHeader(statusCode int) {
|
||||
m.ResponseWriter.WriteHeader(statusCode)
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ func TraceHandler(serviceName, path string, opts ...TraceOption) func(http.Handl
|
||||
// convenient for tracking error messages
|
||||
propagator.Inject(spanCtx, propagation.HeaderCarrier(w.Header()))
|
||||
|
||||
trw := &response.WithCodeResponseWriter{Writer: w, Code: http.StatusOK}
|
||||
trw := response.NewWithCodeResponseWriter(w)
|
||||
next.ServeHTTP(trw, r.WithContext(spanCtx))
|
||||
|
||||
span.SetAttributes(semconv.HTTPAttributesFromHTTPStatusCode(trw.Code)...)
|
||||
|
||||
@@ -13,37 +13,24 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
errorHandler func(error) (int, any)
|
||||
errorHandlerCtx func(context.Context, error) (int, any)
|
||||
lock sync.RWMutex
|
||||
errorHandler func(context.Context, error) (int, any)
|
||||
errorLock sync.RWMutex
|
||||
okHandler func(context.Context, any) any
|
||||
okLock sync.RWMutex
|
||||
)
|
||||
|
||||
// Error writes err into w.
|
||||
func Error(w http.ResponseWriter, err error, fns ...func(w http.ResponseWriter, err error)) {
|
||||
lock.RLock()
|
||||
handler := errorHandler
|
||||
lock.RUnlock()
|
||||
|
||||
doHandleError(w, err, handler, WriteJson, fns...)
|
||||
doHandleError(w, err, buildErrorHandler(context.Background()), WriteJson, fns...)
|
||||
}
|
||||
|
||||
// ErrorCtx writes err into w.
|
||||
func ErrorCtx(ctx context.Context, w http.ResponseWriter, err error,
|
||||
fns ...func(w http.ResponseWriter, err error)) {
|
||||
lock.RLock()
|
||||
handlerCtx := errorHandlerCtx
|
||||
lock.RUnlock()
|
||||
|
||||
var handler func(error) (int, any)
|
||||
if handlerCtx != nil {
|
||||
handler = func(err error) (int, any) {
|
||||
return handlerCtx(ctx, err)
|
||||
}
|
||||
}
|
||||
writeJson := func(w http.ResponseWriter, code int, v any) {
|
||||
WriteJsonCtx(ctx, w, code, v)
|
||||
}
|
||||
doHandleError(w, err, handler, writeJson, fns...)
|
||||
doHandleError(w, err, buildErrorHandler(ctx), writeJson, fns...)
|
||||
}
|
||||
|
||||
// Ok writes HTTP 200 OK into w.
|
||||
@@ -53,26 +40,51 @@ func Ok(w http.ResponseWriter) {
|
||||
|
||||
// OkJson writes v into w with 200 OK.
|
||||
func OkJson(w http.ResponseWriter, v any) {
|
||||
okLock.RLock()
|
||||
handler := okHandler
|
||||
okLock.RUnlock()
|
||||
if handler != nil {
|
||||
v = handler(context.Background(), v)
|
||||
}
|
||||
WriteJson(w, http.StatusOK, v)
|
||||
}
|
||||
|
||||
// OkJsonCtx writes v into w with 200 OK.
|
||||
func OkJsonCtx(ctx context.Context, w http.ResponseWriter, v any) {
|
||||
okLock.RLock()
|
||||
handlerCtx := okHandler
|
||||
okLock.RUnlock()
|
||||
if handlerCtx != nil {
|
||||
v = handlerCtx(ctx, v)
|
||||
}
|
||||
WriteJsonCtx(ctx, w, http.StatusOK, v)
|
||||
}
|
||||
|
||||
// SetErrorHandler sets the error handler, which is called on calling Error.
|
||||
// Notice: SetErrorHandler and SetErrorHandlerCtx set the same error handler.
|
||||
// Keeping both SetErrorHandler and SetErrorHandlerCtx is for backward compatibility.
|
||||
func SetErrorHandler(handler func(error) (int, any)) {
|
||||
lock.Lock()
|
||||
defer lock.Unlock()
|
||||
errorHandler = handler
|
||||
errorLock.Lock()
|
||||
defer errorLock.Unlock()
|
||||
errorHandler = func(_ context.Context, err error) (int, any) {
|
||||
return handler(err)
|
||||
}
|
||||
}
|
||||
|
||||
// SetErrorHandlerCtx sets the error handler, which is called on calling Error.
|
||||
// Notice: SetErrorHandler and SetErrorHandlerCtx set the same error handler.
|
||||
// Keeping both SetErrorHandler and SetErrorHandlerCtx is for backward compatibility.
|
||||
func SetErrorHandlerCtx(handlerCtx func(context.Context, error) (int, any)) {
|
||||
lock.Lock()
|
||||
defer lock.Unlock()
|
||||
errorHandlerCtx = handlerCtx
|
||||
errorLock.Lock()
|
||||
defer errorLock.Unlock()
|
||||
errorHandler = handlerCtx
|
||||
}
|
||||
|
||||
// SetOkHandler sets the response handler, which is called on calling OkJson and OkJsonCtx.
|
||||
func SetOkHandler(handler func(context.Context, any) any) {
|
||||
okLock.Lock()
|
||||
defer okLock.Unlock()
|
||||
okHandler = handler
|
||||
}
|
||||
|
||||
// WriteJson writes v as json string into w with code.
|
||||
@@ -89,6 +101,21 @@ func WriteJsonCtx(ctx context.Context, w http.ResponseWriter, code int, v any) {
|
||||
}
|
||||
}
|
||||
|
||||
func buildErrorHandler(ctx context.Context) func(error) (int, any) {
|
||||
errorLock.RLock()
|
||||
handlerCtx := errorHandler
|
||||
errorLock.RUnlock()
|
||||
|
||||
var handler func(error) (int, any)
|
||||
if handlerCtx != nil {
|
||||
handler = func(err error) (int, any) {
|
||||
return handlerCtx(ctx, err)
|
||||
}
|
||||
}
|
||||
|
||||
return handler
|
||||
}
|
||||
|
||||
func doHandleError(w http.ResponseWriter, err error, handler func(error) (int, any),
|
||||
writeJson func(w http.ResponseWriter, code int, v any),
|
||||
fns ...func(w http.ResponseWriter, err error)) {
|
||||
|
||||
@@ -3,6 +3,7 @@ package httpx
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"testing"
|
||||
@@ -80,14 +81,14 @@ func TestError(t *testing.T) {
|
||||
headers: make(map[string][]string),
|
||||
}
|
||||
if test.errorHandler != nil {
|
||||
lock.RLock()
|
||||
errorLock.RLock()
|
||||
prev := errorHandler
|
||||
lock.RUnlock()
|
||||
errorLock.RUnlock()
|
||||
SetErrorHandler(test.errorHandler)
|
||||
defer func() {
|
||||
lock.Lock()
|
||||
errorLock.Lock()
|
||||
errorHandler = prev
|
||||
lock.Unlock()
|
||||
errorLock.Unlock()
|
||||
}()
|
||||
}
|
||||
Error(&w, errors.New(test.input))
|
||||
@@ -129,13 +130,71 @@ func TestOk(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestOkJson(t *testing.T) {
|
||||
w := tracedResponseWriter{
|
||||
headers: make(map[string][]string),
|
||||
}
|
||||
msg := message{Name: "anyone"}
|
||||
OkJson(&w, msg)
|
||||
assert.Equal(t, http.StatusOK, w.code)
|
||||
assert.Equal(t, "{\"name\":\"anyone\"}", w.builder.String())
|
||||
t.Run("no handler", func(t *testing.T) {
|
||||
w := tracedResponseWriter{
|
||||
headers: make(map[string][]string),
|
||||
}
|
||||
msg := message{Name: "anyone"}
|
||||
OkJson(&w, msg)
|
||||
assert.Equal(t, http.StatusOK, w.code)
|
||||
assert.Equal(t, "{\"name\":\"anyone\"}", w.builder.String())
|
||||
})
|
||||
|
||||
t.Run("with handler", func(t *testing.T) {
|
||||
okLock.RLock()
|
||||
prev := okHandler
|
||||
okLock.RUnlock()
|
||||
t.Cleanup(func() {
|
||||
okLock.Lock()
|
||||
okHandler = prev
|
||||
okLock.Unlock()
|
||||
})
|
||||
|
||||
SetOkHandler(func(_ context.Context, v interface{}) any {
|
||||
return fmt.Sprintf("hello %s", v.(message).Name)
|
||||
})
|
||||
w := tracedResponseWriter{
|
||||
headers: make(map[string][]string),
|
||||
}
|
||||
msg := message{Name: "anyone"}
|
||||
OkJson(&w, msg)
|
||||
assert.Equal(t, http.StatusOK, w.code)
|
||||
assert.Equal(t, `"hello anyone"`, w.builder.String())
|
||||
})
|
||||
}
|
||||
|
||||
func TestOkJsonCtx(t *testing.T) {
|
||||
t.Run("no handler", func(t *testing.T) {
|
||||
w := tracedResponseWriter{
|
||||
headers: make(map[string][]string),
|
||||
}
|
||||
msg := message{Name: "anyone"}
|
||||
OkJsonCtx(context.Background(), &w, msg)
|
||||
assert.Equal(t, http.StatusOK, w.code)
|
||||
assert.Equal(t, "{\"name\":\"anyone\"}", w.builder.String())
|
||||
})
|
||||
|
||||
t.Run("with handler", func(t *testing.T) {
|
||||
okLock.RLock()
|
||||
prev := okHandler
|
||||
okLock.RUnlock()
|
||||
t.Cleanup(func() {
|
||||
okLock.Lock()
|
||||
okHandler = prev
|
||||
okLock.Unlock()
|
||||
})
|
||||
|
||||
SetOkHandler(func(_ context.Context, v interface{}) any {
|
||||
return fmt.Sprintf("hello %s", v.(message).Name)
|
||||
})
|
||||
w := tracedResponseWriter{
|
||||
headers: make(map[string][]string),
|
||||
}
|
||||
msg := message{Name: "anyone"}
|
||||
OkJsonCtx(context.Background(), &w, msg)
|
||||
assert.Equal(t, http.StatusOK, w.code)
|
||||
assert.Equal(t, `"hello anyone"`, w.builder.String())
|
||||
})
|
||||
}
|
||||
|
||||
func TestWriteJsonTimeout(t *testing.T) {
|
||||
@@ -275,14 +334,14 @@ func TestErrorCtx(t *testing.T) {
|
||||
headers: make(map[string][]string),
|
||||
}
|
||||
if test.errorHandlerCtx != nil {
|
||||
lock.RLock()
|
||||
prev := errorHandlerCtx
|
||||
lock.RUnlock()
|
||||
errorLock.RLock()
|
||||
prev := errorHandler
|
||||
errorLock.RUnlock()
|
||||
SetErrorHandlerCtx(test.errorHandlerCtx)
|
||||
defer func() {
|
||||
lock.Lock()
|
||||
errorLock.Lock()
|
||||
test.errorHandlerCtx = prev
|
||||
lock.Unlock()
|
||||
errorLock.Unlock()
|
||||
}()
|
||||
}
|
||||
ErrorCtx(context.Background(), &w, errors.New(test.input))
|
||||
|
||||
@@ -2,6 +2,7 @@ package internal
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"sync"
|
||||
@@ -10,13 +11,32 @@ import (
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
// LogContext is a context key.
|
||||
var LogContext = contextKey("request_logs")
|
||||
// logContextKey is a context key.
|
||||
var logContextKey = contextKey("request_logs")
|
||||
|
||||
// A LogCollector is used to collect logs.
|
||||
type LogCollector struct {
|
||||
Messages []string
|
||||
lock sync.Mutex
|
||||
type (
|
||||
// LogCollector is used to collect logs.
|
||||
LogCollector struct {
|
||||
Messages []string
|
||||
lock sync.Mutex
|
||||
}
|
||||
|
||||
contextKey string
|
||||
)
|
||||
|
||||
// WithLogCollector returns a new context with LogCollector.
|
||||
func WithLogCollector(ctx context.Context, lc *LogCollector) context.Context {
|
||||
return context.WithValue(ctx, logContextKey, lc)
|
||||
}
|
||||
|
||||
// LogCollectorFromContext returns LogCollector from ctx.
|
||||
func LogCollectorFromContext(ctx context.Context) *LogCollector {
|
||||
val := ctx.Value(logContextKey)
|
||||
if val == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return val.(*LogCollector)
|
||||
}
|
||||
|
||||
// Append appends msg into log context.
|
||||
@@ -73,9 +93,9 @@ func Infof(r *http.Request, format string, v ...any) {
|
||||
}
|
||||
|
||||
func appendLog(r *http.Request, message string) {
|
||||
logs := r.Context().Value(LogContext)
|
||||
logs := LogCollectorFromContext(r.Context())
|
||||
if logs != nil {
|
||||
logs.(*LogCollector).Append(message)
|
||||
logs.Append(message)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,9 +110,3 @@ func formatf(r *http.Request, format string, v ...any) string {
|
||||
func formatWithReq(r *http.Request, v string) string {
|
||||
return fmt.Sprintf("(%s - %s) %s", r.RequestURI, httpx.GetRemoteAddr(r), v)
|
||||
}
|
||||
|
||||
type contextKey string
|
||||
|
||||
func (c contextKey) String() string {
|
||||
return "rest/internal context key " + string(c)
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ import (
|
||||
func TestInfo(t *testing.T) {
|
||||
collector := new(LogCollector)
|
||||
req := httptest.NewRequest(http.MethodGet, "http://localhost", http.NoBody)
|
||||
req = req.WithContext(context.WithValue(req.Context(), LogContext, collector))
|
||||
req = req.WithContext(WithLogCollector(req.Context(), collector))
|
||||
Info(req, "first")
|
||||
Infof(req, "second %s", "third")
|
||||
val := collector.Flush()
|
||||
@@ -35,7 +35,10 @@ func TestError(t *testing.T) {
|
||||
assert.True(t, strings.Contains(val, "third"))
|
||||
}
|
||||
|
||||
func TestContextKey_String(t *testing.T) {
|
||||
val := contextKey("foo")
|
||||
assert.True(t, strings.Contains(val.String(), "foo"))
|
||||
func TestLogCollectorContext(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
assert.Nil(t, LogCollectorFromContext(ctx))
|
||||
collector := new(LogCollector)
|
||||
ctx = WithLogCollector(ctx, collector)
|
||||
assert.Equal(t, collector, LogCollectorFromContext(ctx))
|
||||
}
|
||||
|
||||
@@ -13,6 +13,20 @@ type WithCodeResponseWriter struct {
|
||||
Code int
|
||||
}
|
||||
|
||||
// NewWithCodeResponseWriter returns a WithCodeResponseWriter.
|
||||
// If writer is already a WithCodeResponseWriter, it returns writer directly.
|
||||
func NewWithCodeResponseWriter(writer http.ResponseWriter) *WithCodeResponseWriter {
|
||||
switch w := writer.(type) {
|
||||
case *WithCodeResponseWriter:
|
||||
return w
|
||||
default:
|
||||
return &WithCodeResponseWriter{
|
||||
Writer: writer,
|
||||
Code: http.StatusOK,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Flush flushes the response writer.
|
||||
func (w *WithCodeResponseWriter) Flush() {
|
||||
if flusher, ok := w.Writer.(http.Flusher); ok {
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
func TestWithCodeResponseWriter(t *testing.T) {
|
||||
req := httptest.NewRequest(http.MethodGet, "http://localhost", http.NoBody)
|
||||
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
cw := &WithCodeResponseWriter{Writer: w}
|
||||
cw := NewWithCodeResponseWriter(w)
|
||||
|
||||
cw.Header().Set("X-Test", "test")
|
||||
cw.WriteHeader(http.StatusServiceUnavailable)
|
||||
@@ -34,9 +34,7 @@ func TestWithCodeResponseWriter(t *testing.T) {
|
||||
|
||||
func TestWithCodeResponseWriter_Hijack(t *testing.T) {
|
||||
resp := httptest.NewRecorder()
|
||||
writer := &WithCodeResponseWriter{
|
||||
Writer: resp,
|
||||
}
|
||||
writer := NewWithCodeResponseWriter(NewWithCodeResponseWriter(resp))
|
||||
assert.NotPanics(t, func() {
|
||||
writer.Hijack()
|
||||
})
|
||||
|
||||
1
tools/goctl/.gitignore
vendored
1
tools/goctl/.gitignore
vendored
@@ -1 +0,0 @@
|
||||
.vscode
|
||||
@@ -8,22 +8,22 @@ require (
|
||||
github.com/fatih/structtag v1.2.0
|
||||
github.com/go-sql-driver/mysql v1.7.1
|
||||
github.com/gookit/color v1.5.3
|
||||
github.com/iancoleman/strcase v0.2.0
|
||||
github.com/iancoleman/strcase v0.3.0
|
||||
github.com/spf13/cobra v1.7.0
|
||||
github.com/spf13/pflag v1.0.5
|
||||
github.com/stretchr/testify v1.8.4
|
||||
github.com/withfig/autocomplete-tools/integrations/cobra v1.2.1
|
||||
github.com/zeromicro/antlr v0.0.1
|
||||
github.com/zeromicro/ddl-parser v1.0.4
|
||||
github.com/zeromicro/go-zero v1.5.2
|
||||
golang.org/x/text v0.9.0
|
||||
google.golang.org/grpc v1.55.0
|
||||
google.golang.org/protobuf v1.30.0
|
||||
github.com/zeromicro/ddl-parser v1.0.5
|
||||
github.com/zeromicro/go-zero v1.5.4
|
||||
golang.org/x/text v0.11.0
|
||||
google.golang.org/grpc v1.56.2
|
||||
google.golang.org/protobuf v1.31.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a // indirect
|
||||
github.com/alicebob/miniredis/v2 v2.30.2 // indirect
|
||||
github.com/alicebob/miniredis/v2 v2.30.4 // indirect
|
||||
github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20210521184019-c5ad59b459ec // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.2.0 // indirect
|
||||
@@ -34,7 +34,6 @@ require (
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.9.0 // indirect
|
||||
github.com/fatih/color v1.15.0 // indirect
|
||||
github.com/felixge/fgprof v0.9.3 // indirect
|
||||
github.com/fsnotify/fsnotify v1.6.0 // indirect
|
||||
github.com/go-logr/logr v1.2.3 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
@@ -48,12 +47,11 @@ require (
|
||||
github.com/google/gnostic v0.5.7-v3refs // indirect
|
||||
github.com/google/go-cmp v0.5.9 // indirect
|
||||
github.com/google/gofuzz v1.2.0 // indirect
|
||||
github.com/google/pprof v0.0.0-20211214055906-6f57359322fd // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.15.0 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
|
||||
github.com/jackc/pgx/v5 v5.3.1 // indirect
|
||||
github.com/jackc/pgx/v5 v5.4.2 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/logrusorgru/aurora v2.0.3+incompatible // indirect
|
||||
@@ -65,24 +63,25 @@ require (
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/openzipkin/zipkin-go v0.4.1 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.0.7 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.0.9 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/prometheus/client_golang v1.15.0 // indirect
|
||||
github.com/prometheus/client_golang v1.16.0 // indirect
|
||||
github.com/prometheus/client_model v0.3.0 // indirect
|
||||
github.com/prometheus/common v0.42.0 // indirect
|
||||
github.com/prometheus/procfs v0.9.0 // indirect
|
||||
github.com/prometheus/procfs v0.10.1 // indirect
|
||||
github.com/spaolacci/murmur3 v1.1.0 // indirect
|
||||
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect
|
||||
github.com/yuin/gopher-lua v1.1.0 // indirect
|
||||
go.etcd.io/etcd/api/v3 v3.5.8 // indirect
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.8 // indirect
|
||||
go.etcd.io/etcd/client/v3 v3.5.8 // indirect
|
||||
go.etcd.io/etcd/api/v3 v3.5.9 // indirect
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.9 // indirect
|
||||
go.etcd.io/etcd/client/v3 v3.5.9 // indirect
|
||||
go.opentelemetry.io/otel v1.14.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/jaeger v1.14.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.14.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.14.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.14.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.14.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.14.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/zipkin v1.14.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk v1.14.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.14.0 // indirect
|
||||
@@ -91,14 +90,14 @@ require (
|
||||
go.uber.org/automaxprocs v1.5.2 // indirect
|
||||
go.uber.org/multierr v1.9.0 // indirect
|
||||
go.uber.org/zap v1.24.0 // indirect
|
||||
golang.org/x/crypto v0.6.0 // indirect
|
||||
golang.org/x/net v0.9.0 // indirect
|
||||
golang.org/x/oauth2 v0.6.0 // indirect
|
||||
golang.org/x/sys v0.7.0 // indirect
|
||||
golang.org/x/term v0.7.0 // indirect
|
||||
golang.org/x/crypto v0.11.0 // indirect
|
||||
golang.org/x/net v0.12.0 // indirect
|
||||
golang.org/x/oauth2 v0.7.0 // indirect
|
||||
golang.org/x/sys v0.10.0 // indirect
|
||||
golang.org/x/term v0.10.0 // indirect
|
||||
golang.org/x/time v0.3.0 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect
|
||||
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
|
||||
@@ -38,8 +38,8 @@ github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a h1:HbKu58rmZpUGpz5+4FfNmIU+FmZg2P3Xaj2v2bfNWmk=
|
||||
github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc=
|
||||
github.com/alicebob/miniredis/v2 v2.30.2 h1:lc1UAUT9ZA7h4srlfBmBt2aorm5Yftk9nBjxz7EyY9I=
|
||||
github.com/alicebob/miniredis/v2 v2.30.2/go.mod h1:b25qWj4fCEsBeAAR2mlb0ufImGC6uH3VlUfb/HS5zKg=
|
||||
github.com/alicebob/miniredis/v2 v2.30.4 h1:8S4/o1/KoUArAGbGwPxcwf0krlzceva2XVOSchFS7Eo=
|
||||
github.com/alicebob/miniredis/v2 v2.30.4/go.mod h1:b25qWj4fCEsBeAAR2mlb0ufImGC6uH3VlUfb/HS5zKg=
|
||||
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/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY=
|
||||
@@ -91,8 +91,6 @@ github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
|
||||
github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
|
||||
github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4=
|
||||
github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94=
|
||||
github.com/felixge/fgprof v0.9.3 h1:VvyZxILNuCiUCSXtPtYmmtGvb65nqXh2QFWc0Wpf2/g=
|
||||
github.com/felixge/fgprof v0.9.3/go.mod h1:RdbpDgzqYVh/T9fPELJyV7EYJuHB55UTEULNun8eiPw=
|
||||
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
|
||||
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
@@ -178,8 +176,6 @@ github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hf
|
||||
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20211214055906-6f57359322fd h1:1FjCyPC+syAzJ5/2S8fqdZK1R22vvA0J7JZKcuOIQ7Y=
|
||||
github.com/google/pprof v0.0.0-20211214055906-6f57359322fd/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||
@@ -194,18 +190,17 @@ github.com/grpc-ecosystem/grpc-gateway/v2 v2.15.0/go.mod h1:YDZoGHuwE+ov0c8smSH4
|
||||
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/iancoleman/strcase v0.2.0 h1:05I4QRnGpI0m37iZQRuskXh+w77mr6Z41lwQzuHLwW0=
|
||||
github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=
|
||||
github.com/iancoleman/strcase v0.3.0 h1:nTXanmYxhfFAMjZL34Ov6gkzEsSJZ5DbhxWjvSASxEI=
|
||||
github.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20210905161508-09a460cdf81d/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w=
|
||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
||||
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=
|
||||
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
|
||||
github.com/jackc/pgx/v5 v5.3.1 h1:Fcr8QJ1ZeLi5zsPZqQeUZhNhxfkkKBOgJuYkJHoBOtU=
|
||||
github.com/jackc/pgx/v5 v5.3.1/go.mod h1:t3JDKnCBlYIc0ewLF0Q7B8MXmoIaBOZj/ic7iHozM/8=
|
||||
github.com/jackc/pgx/v5 v5.4.2 h1:u1gmGDwbdRUZiwisBm/Ky2M14uQyUP65bG8+20nnyrg=
|
||||
github.com/jackc/pgx/v5 v5.4.2/go.mod h1:q6iHT8uDNXWiFNOlRqJzBTaSH3+2xCXkokxHZC5qWFY=
|
||||
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||
@@ -246,21 +241,21 @@ github.com/onsi/ginkgo/v2 v2.7.0 h1:/XxtEV3I3Eif/HobnVx9YmJgk8ENdRsuUmM+fLCFNow=
|
||||
github.com/onsi/gomega v1.26.0 h1:03cDLK28U6hWvCAns6NeydX3zIm4SF3ci69ulidS32Q=
|
||||
github.com/openzipkin/zipkin-go v0.4.1 h1:kNd/ST2yLLWhaWrkgchya40TJabe8Hioj9udfPcEO5A=
|
||||
github.com/openzipkin/zipkin-go v0.4.1/go.mod h1:qY0VqDSN1pOBN94dBc6w2GJlWLiovAyg7Qt6/I9HecM=
|
||||
github.com/pelletier/go-toml/v2 v2.0.7 h1:muncTPStnKRos5dpVKULv2FVd4bMOhNePj9CjgDb8Us=
|
||||
github.com/pelletier/go-toml/v2 v2.0.7/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek=
|
||||
github.com/pelletier/go-toml/v2 v2.0.9 h1:uH2qQXheeefCCkuBBSLi7jCiSmj3VRh2+Goq2N7Xxu0=
|
||||
github.com/pelletier/go-toml/v2 v2.0.9/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g=
|
||||
github.com/prometheus/client_golang v1.15.0 h1:5fCgGYogn0hFdhyhLbw7hEsWxufKtY9klyvdNfFlFhM=
|
||||
github.com/prometheus/client_golang v1.15.0/go.mod h1:e9yaBhRPU2pPNsZwE+JdQl0KEt1N9XgF6zxWmaC0xOk=
|
||||
github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8=
|
||||
github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4=
|
||||
github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w=
|
||||
github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM=
|
||||
github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc=
|
||||
github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI=
|
||||
github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY=
|
||||
github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+PymziUAg=
|
||||
github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM=
|
||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
||||
@@ -299,16 +294,16 @@ github.com/yuin/gopher-lua v1.1.0 h1:BojcDhfyDWgU2f2TOzYK/g5p2gxMrku8oupLDqlnSqE
|
||||
github.com/yuin/gopher-lua v1.1.0/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw=
|
||||
github.com/zeromicro/antlr v0.0.1 h1:CQpIn/dc0pUjgGQ81y98s/NGOm2Hfru2NNio2I9mQgk=
|
||||
github.com/zeromicro/antlr v0.0.1/go.mod h1:nfpjEwFR6Q4xGDJMcZnCL9tEfQRgszMwu3rDz2Z+p5M=
|
||||
github.com/zeromicro/ddl-parser v1.0.4 h1:fzU0ZNfV/a6T/WO8TvZZeJE9hmdt3qHvVUsW1X9SGJQ=
|
||||
github.com/zeromicro/ddl-parser v1.0.4/go.mod h1:ISU/8NuPyEpl9pa17Py9TBPetMjtsiHrb9f5XGiYbo8=
|
||||
github.com/zeromicro/go-zero v1.5.2 h1:vpMlZacCMtgdtYzKI3OMyhS6mZ9UQctiAh0J7gIq31I=
|
||||
github.com/zeromicro/go-zero v1.5.2/go.mod h1:ndCd1nMMAdEMZgPfdm1fpavHUdBW0ykB6ckCRaSG10w=
|
||||
go.etcd.io/etcd/api/v3 v3.5.8 h1:Zf44zJszoU7zRV0X/nStPenegNXoFDWcB/MwrJbA+L4=
|
||||
go.etcd.io/etcd/api/v3 v3.5.8/go.mod h1:uyAal843mC8uUVSLWz6eHa/d971iDGnCRpmKd2Z+X8k=
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.8 h1:tPp9YRn/UBFAHdhOQUII9eUs7aOK35eulpMhX4YBd+M=
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.8/go.mod h1:y+CzeSmkMpWN2Jyu1npecjB9BBnABxGM4pN8cGuJeL4=
|
||||
go.etcd.io/etcd/client/v3 v3.5.8 h1:B6ngTKZSWWowHEoaucOKHQR/AtZKaoHLiUpWxOLG4l4=
|
||||
go.etcd.io/etcd/client/v3 v3.5.8/go.mod h1:idZYIPVkttBJBiRigkB5EM0MmEyx8jcl18zCV3F5noc=
|
||||
github.com/zeromicro/ddl-parser v1.0.5 h1:LaVqHdzMTjasua1yYpIYaksxKqRzFrEukj2Wi2EbWaQ=
|
||||
github.com/zeromicro/ddl-parser v1.0.5/go.mod h1:ISU/8NuPyEpl9pa17Py9TBPetMjtsiHrb9f5XGiYbo8=
|
||||
github.com/zeromicro/go-zero v1.5.4 h1:kRvcYuxcHOkUZvg7887KQl77Qv4klGL7MqGkTBgkpS8=
|
||||
github.com/zeromicro/go-zero v1.5.4/go.mod h1:x/aUyLmSwRECvOyjOf+lhwThBOilJIY+s3slmPAeboA=
|
||||
go.etcd.io/etcd/api/v3 v3.5.9 h1:4wSsluwyTbGGmyjJktOf3wFQoTBIURXHnq9n/G/JQHs=
|
||||
go.etcd.io/etcd/api/v3 v3.5.9/go.mod h1:uyAal843mC8uUVSLWz6eHa/d971iDGnCRpmKd2Z+X8k=
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.9 h1:oidDC4+YEuSIQbsR94rY9gur91UPL6DnxDCIYd2IGsE=
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.9/go.mod h1:y+CzeSmkMpWN2Jyu1npecjB9BBnABxGM4pN8cGuJeL4=
|
||||
go.etcd.io/etcd/client/v3 v3.5.9 h1:r5xghnU7CwbUxD/fbUtRyJGaYNfDun8sp/gTr1hew6E=
|
||||
go.etcd.io/etcd/client/v3 v3.5.9/go.mod h1:i/Eo5LrZ5IKqpbtpPDuaUnDOUv471oDg8cjQaUr2MbA=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
@@ -326,6 +321,8 @@ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.14.0 h1:ap+y8
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.14.0/go.mod h1:5w41DY6S9gZrbjuq6Y+753e96WfPha5IcsOSZTtullM=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.14.0 h1:3jAYbRHQAqzLjd9I4tzxwJ8Pk/N6AqBcF6m1ZHrxG94=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.14.0/go.mod h1:+N7zNjIJv4K+DeX67XXET0P+eIciESgaFDBqh+ZJFS4=
|
||||
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.14.0 h1:sEL90JjOO/4yhquXl5zTAkLLsZ5+MycAgX99SDsxGc8=
|
||||
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.14.0/go.mod h1:oCslUcizYdpKYyS9e8srZEqM6BB8fq41VJBjLAE6z1w=
|
||||
go.opentelemetry.io/otel/exporters/zipkin v1.14.0 h1:reEVE1upBF9tcujgvSqLJS0SrI7JQPaTKP4s4rymnSs=
|
||||
go.opentelemetry.io/otel/exporters/zipkin v1.14.0/go.mod h1:RcjvOAcvhzcufQP8aHmzRw1gE9g/VEZufDdo2w+s4sk=
|
||||
go.opentelemetry.io/otel/sdk v1.14.0 h1:PDCppFRDq8A1jL9v6KMI6dYesaq+DFcDZvjsoGvxGzY=
|
||||
@@ -349,8 +346,8 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc=
|
||||
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
|
||||
golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA=
|
||||
golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio=
|
||||
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=
|
||||
@@ -410,16 +407,16 @@ golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81R
|
||||
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-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM=
|
||||
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
|
||||
golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50=
|
||||
golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.6.0 h1:Lh8GPgSKBfWSwFvtuWOfeI3aAAnbXTSutYxJiOJFgIw=
|
||||
golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw=
|
||||
golang.org/x/oauth2 v0.7.0 h1:qe6s0zUXlPX80/dITx3440hWZ7GwMwgDDyrSGTPJG/g=
|
||||
golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -460,22 +457,21 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
|
||||
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA=
|
||||
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.7.0 h1:BEvjmm5fURWqcfbSKTdpkDXYBrUS1c0m8agp14W48vQ=
|
||||
golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
|
||||
golang.org/x/term v0.10.0 h1:3R7pNqamzBraeqj/Tj8qt1aQ2HpmlC+Cx/qL/7hn4/c=
|
||||
golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4=
|
||||
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
@@ -584,8 +580,8 @@ google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6D
|
||||
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||
google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA=
|
||||
google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s=
|
||||
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A=
|
||||
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU=
|
||||
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=
|
||||
@@ -602,8 +598,8 @@ google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTp
|
||||
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
|
||||
google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
|
||||
google.golang.org/grpc v1.55.0 h1:3Oj82/tFSCeUrRTg/5E/7d/W5A1tj6Ky1ABAuZuv5ag=
|
||||
google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8=
|
||||
google.golang.org/grpc v1.56.2 h1:fVRFRnXvU+x6C4IlHZewvJOVHoOv1TUuQyoRsYnB4bI=
|
||||
google.golang.org/grpc v1.56.2/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
@@ -617,8 +613,8 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
|
||||
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
|
||||
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
||||
@@ -226,7 +226,8 @@
|
||||
"home": "{{.global.home}}",
|
||||
"remote": "{{.global.remote}}",
|
||||
"branch": "{{.global.branch}}",
|
||||
"verbose": "Enable log output"
|
||||
"verbose": "Enable log output",
|
||||
"client": "Whether to generate rpc client"
|
||||
},
|
||||
"template": {
|
||||
"short": "Generate proto template",
|
||||
@@ -243,7 +244,8 @@
|
||||
"home": "{{.global.home}}",
|
||||
"remote": "{{.global.remote}}",
|
||||
"branch": "{{.global.branch}}",
|
||||
"verbose": "Enable log output"
|
||||
"verbose": "Enable log output",
|
||||
"client": "Whether to generate rpc client"
|
||||
}
|
||||
},
|
||||
"template": {
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
)
|
||||
|
||||
// BuildVersion is the version of goctl.
|
||||
const BuildVersion = "1.5.3"
|
||||
const BuildVersion = "1.5.4"
|
||||
|
||||
var tag = map[string]int{"pre-alpha": 0, "alpha": 1, "pre-bata": 2, "beta": 3, "released": 4, "": 5}
|
||||
|
||||
|
||||
@@ -30,5 +30,6 @@ CREATE TABLE `student`
|
||||
) DEFAULT NULL,
|
||||
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`update_time` timestamp NULL DEFAULT NULL,
|
||||
`delete_time` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`type`) USING BTREE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
|
||||
|
||||
@@ -324,7 +324,7 @@ func ConvertDataType(table *model.Table, strict bool) (*Table, error) {
|
||||
if len(each) == 1 {
|
||||
one := each[0]
|
||||
if one.Name == table.PrimaryKey.Name {
|
||||
log.Warning("[ConvertDataType]: table q%, duplicate unique index with primary key: %q", table.Table, one.Name)
|
||||
log.Warning("[ConvertDataType]: table %q, duplicate unique index with primary key: %q", table.Table, one.Name)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,8 @@ CREATE TABLE `test_user`
|
||||
名',
|
||||
`create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP comment '创建\r时间',
|
||||
`update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
`delete_time` timestamp NULL DEFAULT NULL,
|
||||
`delete_at` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `mobile_unique` (`mobile`),
|
||||
UNIQUE KEY `class_name_unique` (`class`,`name`),
|
||||
|
||||
@@ -219,9 +219,7 @@ func transferTokenNode(node *TokenNode, opt ...tokenNodeOption) *TokenNode {
|
||||
}
|
||||
}
|
||||
if !option.ignoreLeadingComment {
|
||||
for _, v := range node.LeadingCommentGroup {
|
||||
result.LeadingCommentGroup = append(result.LeadingCommentGroup, v)
|
||||
}
|
||||
result.LeadingCommentGroup = append(result.LeadingCommentGroup, node.LeadingCommentGroup...)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -44,6 +44,8 @@ var (
|
||||
VarBoolVerbose bool
|
||||
// VarBoolMultiple describes whether support generating multiple rpc services or not.
|
||||
VarBoolMultiple bool
|
||||
// VarBoolClient describes whether to generate rpc client
|
||||
VarBoolClient bool
|
||||
)
|
||||
|
||||
// RPCNew is to generate rpc greet service, this greet service can speed
|
||||
@@ -88,6 +90,7 @@ func RPCNew(_ *cobra.Command, args []string) error {
|
||||
ctx.IsGooglePlugin = true
|
||||
ctx.Output = filepath.Dir(src)
|
||||
ctx.ProtocCmd = fmt.Sprintf("protoc -I=%s %s --go_out=%s --go-grpc_out=%s", filepath.Dir(src), filepath.Base(src), filepath.Dir(src), filepath.Dir(src))
|
||||
ctx.IsGenClient = VarBoolClient
|
||||
|
||||
grpcOptList := VarStringSliceGoGRPCOpt
|
||||
if len(grpcOptList) > 0 {
|
||||
|
||||
@@ -102,6 +102,7 @@ func ZRPC(_ *cobra.Command, args []string) error {
|
||||
ctx.IsGooglePlugin = isGooglePlugin
|
||||
ctx.Output = zrpcOut
|
||||
ctx.ProtocCmd = strings.Join(protocArgs, " ")
|
||||
ctx.IsGenClient = VarBoolClient
|
||||
g := generator.NewGenerator(style, verbose)
|
||||
return g.Generate(&ctx)
|
||||
}
|
||||
|
||||
@@ -43,6 +43,7 @@ func init() {
|
||||
newCmdFlags.BoolVarP(&cli.VarBoolVerbose, "verbose", "v")
|
||||
newCmdFlags.MarkHidden("go_opt")
|
||||
newCmdFlags.MarkHidden("go-grpc_opt")
|
||||
newCmdFlags.BoolVarPWithDefaultValue(&cli.VarBoolClient, "client", "c", true)
|
||||
|
||||
protocCmdFlags.BoolVarP(&cli.VarBoolMultiple, "multiple", "m")
|
||||
protocCmdFlags.StringSliceVar(&cli.VarStringSliceGoOut, "go_out")
|
||||
@@ -63,6 +64,7 @@ func init() {
|
||||
protocCmdFlags.MarkHidden("go-grpc_opt")
|
||||
protocCmdFlags.MarkHidden("plugin")
|
||||
protocCmdFlags.MarkHidden("proto_path")
|
||||
protocCmdFlags.BoolVarPWithDefaultValue(&cli.VarBoolClient, "client", "c", true)
|
||||
|
||||
templateCmdFlags.StringVar(&cli.VarStringOutput, "o")
|
||||
templateCmdFlags.StringVar(&cli.VarStringHome, "home")
|
||||
|
||||
@@ -28,6 +28,8 @@ type ZRpcContext struct {
|
||||
Output string
|
||||
// Multiple is the flag to indicate whether the proto file is generated in multiple mode.
|
||||
Multiple bool
|
||||
// Whether to generate rpc client
|
||||
IsGenClient bool
|
||||
}
|
||||
|
||||
// Generate generates a rpc service, through the proto file,
|
||||
@@ -100,7 +102,9 @@ func (g *Generator) Generate(zctx *ZRpcContext) error {
|
||||
return err
|
||||
}
|
||||
|
||||
err = g.GenCall(dirCtx, proto, g.cfg, zctx)
|
||||
if zctx.IsGenClient {
|
||||
err = g.GenCall(dirCtx, proto, g.cfg, zctx)
|
||||
}
|
||||
|
||||
console.NewColorConsole().MarkDone()
|
||||
|
||||
|
||||
@@ -87,6 +87,7 @@ func mkdir(ctx *ctx.ProjectContext, proto parser.Proto, conf *conf.Config, c *ZR
|
||||
return filepath.ToSlash(pkg), nil
|
||||
}
|
||||
|
||||
var callClientDir string
|
||||
if !c.Multiple {
|
||||
callDir := filepath.Join(ctx.WorkDir,
|
||||
strings.ToLower(stringx.From(proto.Service[0].Name).ToCamel()))
|
||||
@@ -98,23 +99,18 @@ func mkdir(ctx *ctx.ProjectContext, proto parser.Proto, conf *conf.Config, c *ZR
|
||||
}
|
||||
callDir = filepath.Join(ctx.WorkDir, clientDir)
|
||||
}
|
||||
inner[call] = Dir{
|
||||
Filename: callDir,
|
||||
Package: filepath.ToSlash(filepath.Join(ctx.Path,
|
||||
strings.TrimPrefix(callDir, ctx.Dir))),
|
||||
Base: filepath.Base(callDir),
|
||||
GetChildPackage: func(childPath string) (string, error) {
|
||||
return getChildPackage(callDir, childPath)
|
||||
},
|
||||
}
|
||||
callClientDir = callDir
|
||||
} else {
|
||||
callClientDir = clientDir
|
||||
}
|
||||
if c.IsGenClient {
|
||||
inner[call] = Dir{
|
||||
Filename: clientDir,
|
||||
Filename: callClientDir,
|
||||
Package: filepath.ToSlash(filepath.Join(ctx.Path,
|
||||
strings.TrimPrefix(clientDir, ctx.Dir))),
|
||||
Base: filepath.Base(clientDir),
|
||||
strings.TrimPrefix(callClientDir, ctx.Dir))),
|
||||
Base: filepath.Base(callClientDir),
|
||||
GetChildPackage: func(childPath string) (string, error) {
|
||||
return getChildPackage(clientDir, childPath)
|
||||
return getChildPackage(callClientDir, childPath)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package ctx
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
@@ -76,26 +77,44 @@ func getRealModule(workDir string, execRun execx.RunFunc) (*Module, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
modules, err := decodePackages(strings.NewReader(data))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, m := range modules {
|
||||
if strings.HasPrefix(workDir, m.Dir) {
|
||||
realDir, err := pathx.ReadLink(m.Dir)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read go.mod, dir: %s, error: %w", m.Dir, err)
|
||||
}
|
||||
|
||||
if strings.HasPrefix(workDir, realDir) {
|
||||
return &m, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, errors.New("no matched module")
|
||||
}
|
||||
|
||||
func decodePackages(rc io.Reader) ([]Module, error) {
|
||||
func decodePackages(reader io.Reader) ([]Module, error) {
|
||||
br := bufio.NewReader(reader)
|
||||
if _, err := br.ReadSlice('{'); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := br.UnreadByte(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var modules []Module
|
||||
decoder := json.NewDecoder(rc)
|
||||
decoder := json.NewDecoder(br)
|
||||
for decoder.More() {
|
||||
var m Module
|
||||
if err := decoder.Decode(&m); err != nil {
|
||||
return nil, fmt.Errorf("invalid module: %v", err)
|
||||
}
|
||||
|
||||
modules = append(modules, m)
|
||||
}
|
||||
|
||||
|
||||
@@ -3,9 +3,11 @@ package ctx
|
||||
import (
|
||||
"bytes"
|
||||
"go/build"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -110,3 +112,90 @@ func Test_getRealModule(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDecodePackages(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
data io.Reader
|
||||
want []Module
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "single module",
|
||||
data: strings.NewReader(`{
|
||||
"Path":"foo",
|
||||
"Dir":"/home/foo",
|
||||
"GoMod":"/home/foo/go.mod",
|
||||
"GoVersion":"go1.16"}`),
|
||||
want: []Module{
|
||||
{
|
||||
Path: "foo",
|
||||
Dir: "/home/foo",
|
||||
GoMod: "/home/foo/go.mod",
|
||||
GoVersion: "go1.16",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "go work multiple modules",
|
||||
data: strings.NewReader(`
|
||||
{
|
||||
"Path":"foo",
|
||||
"Dir":"/home/foo",
|
||||
"GoMod":"/home/foo/go.mod",
|
||||
"GoVersion":"go1.18"
|
||||
}
|
||||
{
|
||||
"Path":"bar",
|
||||
"Dir":"/home/bar",
|
||||
"GoMod":"/home/bar/go.mod",
|
||||
"GoVersion":"go1.18"
|
||||
}`),
|
||||
want: []Module{
|
||||
{
|
||||
Path: "foo",
|
||||
Dir: "/home/foo",
|
||||
GoMod: "/home/foo/go.mod",
|
||||
GoVersion: "go1.18",
|
||||
},
|
||||
{
|
||||
Path: "bar",
|
||||
Dir: "/home/bar",
|
||||
GoMod: "/home/bar/go.mod",
|
||||
GoVersion: "go1.18",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "There are extra characters at the beginning",
|
||||
data: strings.NewReader(`Active code page: 65001
|
||||
{
|
||||
"Path":"foo",
|
||||
"Dir":"/home/foo",
|
||||
"GoMod":"/home/foo/go.mod",
|
||||
"GoVersion":"go1.18"
|
||||
}`),
|
||||
want: []Module{
|
||||
{
|
||||
Path: "foo",
|
||||
Dir: "/home/foo",
|
||||
GoMod: "/home/foo/go.mod",
|
||||
GoVersion: "go1.18",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result, err := decodePackages(tt.data)
|
||||
if err != nil {
|
||||
t.Errorf("decodePackages() error %v,wantErr = %v", err, tt.wantErr)
|
||||
}
|
||||
if !reflect.DeepEqual(result, tt.want) {
|
||||
t.Errorf("decodePackages() = %v,want %v", result, tt.want)
|
||||
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,15 +145,12 @@ func GetTemplateDir(category string) (string, error) {
|
||||
// backward compatible, it will be removed in the feature
|
||||
// backward compatible start.
|
||||
beforeTemplateDir := filepath.Join(home, version.GetGoctlVersion(), category)
|
||||
entries, err := os.ReadDir(beforeTemplateDir)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
entries, _ := os.ReadDir(beforeTemplateDir)
|
||||
infos := make([]fs.FileInfo, 0, len(entries))
|
||||
for _, entry := range entries {
|
||||
info, err := entry.Info()
|
||||
if err != nil {
|
||||
return "", err
|
||||
continue
|
||||
}
|
||||
infos = append(infos, info)
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package zrpc
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/conf"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
"github.com/zeromicro/go-zero/zrpc/internal"
|
||||
"github.com/zeromicro/go-zero/zrpc/internal/auth"
|
||||
@@ -85,15 +86,14 @@ func NewClient(c RpcClientConf, options ...ClientOption) (Client, error) {
|
||||
|
||||
// NewClientWithTarget returns a Client with connecting to given target.
|
||||
func NewClientWithTarget(target string, opts ...ClientOption) (Client, error) {
|
||||
middlewares := ClientMiddlewaresConf{
|
||||
Trace: true,
|
||||
Duration: true,
|
||||
Prometheus: true,
|
||||
Breaker: true,
|
||||
Timeout: true,
|
||||
var config RpcClientConf
|
||||
if err := conf.FillDefault(&config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return internal.NewClient(target, middlewares, opts...)
|
||||
config.Target = target
|
||||
|
||||
return NewClient(config, opts...)
|
||||
}
|
||||
|
||||
// Conn returns the underlying grpc.ClientConn.
|
||||
|
||||
@@ -215,3 +215,15 @@ func TestNewClientWithError(t *testing.T) {
|
||||
)
|
||||
assert.NotNil(t, err)
|
||||
}
|
||||
|
||||
func TestNewClientWithTarget(t *testing.T) {
|
||||
_, err := NewClientWithTarget("",
|
||||
WithDialOption(grpc.WithTransportCredentials(insecure.NewCredentials())),
|
||||
WithDialOption(grpc.WithContextDialer(dialer())),
|
||||
WithUnaryClientInterceptor(func(ctx context.Context, method string, req, reply any,
|
||||
cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
|
||||
return invoker(ctx, method, req, reply, cc, opts...)
|
||||
}))
|
||||
|
||||
assert.NotNil(t, err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user