Repository: zeromicro/go-zero
Pull request #3201 (2023-05-04 05:53:27)

api imports take the form of relative paths
api导入采用相对路径的方式 ，但是因为没有命名空间或者工作空间之概念，所以还是类型这些还是不能重复，只是把文件的导入方式改为了相对路径

codecov[bot]: ## [Codecov](https://app.codecov.io/gh/zeromicro/go-zero/pull/3201?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None) Report
> Merging [#3201](https://app.codecov.io/gh/zeromicro/go-zero/pull/3201?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None) (0058621) into [master](https://app.codecov.io/gh/zeromicro/go-zero/commit/fe97fab274ae6343ed1ff334f92555f3153fb718?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None) (fe97fab) will **increase** coverage by `0.01%`.
> The diff coverage is `n/a`.


[see 2 files with indirect coverage changes](https://app.codecov.io/gh/zeromicro/go-zero/pull/3201/indirect-changes?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None)


Patch:
diff --git a/core/discov/internal/registry.go b/core/discov/internal/registry.go
index a4b3c38f..97dd97aa 100644
--- a/core/discov/internal/registry.go
+++ b/core/discov/internal/registry.go
@@ -337,13 +337,11 @@ func (c *cluster) watchConnState(cli EtcdClient) {
 // DialClient dials an etcd cluster with given endpoints.
 func DialClient(endpoints []string) (EtcdClient, error) {
 	cfg := clientv3.Config{
-		Endpoints:            endpoints,
-		AutoSyncInterval:     autoSyncInterval,
-		DialTimeout:          DialTimeout,
-		DialKeepAliveTime:    dialKeepAliveTime,
-		DialKeepAliveTimeout: DialTimeout,
-		RejectOldCluster:     true,
-		PermitWithoutStream:  true,
+		Endpoints:           endpoints,
+		AutoSyncInterval:    autoSyncInterval,
+		DialTimeout:         DialTimeout,
+		RejectOldCluster:    true,
+		PermitWithoutStream: true,
 	}
 	if account, ok := GetAccount(endpoints); ok {
 		cfg.Username = account.User
diff --git a/core/discov/internal/vars.go b/core/discov/internal/vars.go
index 77360b49..8abf7890 100644
--- a/core/discov/internal/vars.go
+++ b/core/discov/internal/vars.go
@@ -9,7 +9,6 @@ const (
 	autoSyncInterval   = time.Minute
 	coolDownInterval   = time.Second
 	dialTimeout        = 5 * time.Second
-	dialKeepAliveTime  = 5 * time.Second
 	requestTimeout     = 3 * time.Second
 	endpointsSeparator = ","
 )
diff --git a/core/logx/richlogger.go b/core/logx/richlogger.go
index 6f2a826d..0357e397 100644
--- a/core/logx/richlogger.go
+++ b/core/logx/richlogger.go
@@ -65,7 +65,7 @@ func (l *richLogger) Errorf(format string, v ...any) {
 }
 
 func (l *richLogger) Errorv(v any) {
-	l.err(fmt.Sprint(v))
+	l.err(v)
 }
 
 func (l *richLogger) Errorw(msg string, fields ...LogField) {
diff --git a/core/rescue/recover.go b/core/rescue/recover.go
index 7cde054e..b9361b7c 100644
--- a/core/rescue/recover.go
+++ b/core/rescue/recover.go
@@ -1,6 +1,11 @@
 package rescue
 
-import "github.com/zeromicro/go-zero/core/logx"
+import (
+	"context"
+	"runtime/debug"
+
+	"github.com/zeromicro/go-zero/core/logx"
+)
 
 // Recover is used with defer to do cleanup on panics.
 // Use it like:
@@ -15,3 +20,14 @@ func Recover(cleanups ...func()) {
 		logx.ErrorStack(p)
 	}
 }
+
+// RecoverCtx is used with defer to do cleanup on panics.
+func RecoverCtx(ctx context.Context, cleanups ...func()) {
+	for _, cleanup := range cleanups {
+		cleanup()
+	}
+
+	if p := recover(); p != nil {
+		logx.WithContext(ctx).Errorf("%+v\n%s", p, debug.Stack())
+	}
+}
diff --git a/core/stat/metrics.go b/core/stat/metrics.go
index f0efe1e9..5b0809b9 100644
--- a/core/stat/metrics.go
+++ b/core/stat/metrics.go
@@ -141,7 +141,7 @@ func (c *metricsContainer) Execute(v any) {
 			report.Median = float32(medianTask.Duration) / float32(time.Millisecond)
 			tenPercent := fiftyPercent / 5
 			if tenPercent > 0 {
-				top10pTasks := topK(tasks, tenPercent)
+				top10pTasks := topK(top50pTasks, tenPercent)
 				task90th := top10pTasks[0]
 				report.Top90th = float32(task90th.Duration) / float32(time.Millisecond)
 				onePercent := tenPercent / 10
@@ -163,7 +163,7 @@ func (c *metricsContainer) Execute(v any) {
 					report.Top99p9th = mostDuration
 				}
 			} else {
-				mostDuration := getTopDuration(tasks)
+				mostDuration := getTopDuration(top50pTasks)
 				report.Top90th = mostDuration
 				report.Top99th = mostDuration
 				report.Top99p9th = mostDuration
diff --git a/core/threading/routines.go b/core/threading/routines.go
index 900dcb3b..a165992f 100644
--- a/core/threading/routines.go
+++ b/core/threading/routines.go
@@ -2,6 +2,7 @@ package threading
 
 import (
 	"bytes"
+	"context"
 	"runtime"
 	"strconv"
 
@@ -13,6 +14,11 @@ func GoSafe(fn func()) {
 	go RunSafe(fn)
 }
 
+// GoSafeCtx runs the given fn using another goroutine, recovers if fn panics with ctx.
+func GoSafeCtx(ctx context.Context, fn func()) {
+	go RunSafeCtx(ctx, fn)
+}
+
 // RoutineId is only for debug, never use it in production.
 func RoutineId() uint64 {
 	b := make([]byte, 64)
@@ -31,3 +37,10 @@ func RunSafe(fn func()) {
 
 	fn()
 }
+
+// RunSafeCtx runs the given fn, recovers if fn panics with ctx.
+func RunSafeCtx(ctx context.Context, fn func()) {
+	defer rescue.RecoverCtx(ctx)
+
+	fn()
+}
diff --git a/core/trace/agent.go b/core/trace/agent.go
index 939c1d9e..9b293e45 100644
--- a/core/trace/agent.go
+++ b/core/trace/agent.go
@@ -71,17 +71,29 @@ func createExporter(c Config) (sdktrace.SpanExporter, error) {
 		// endpoint can not reach.
 		// If the connection not dial success, the global otel ErrorHandler will catch error
 		// when reporting data like other exporters.
-		return otlptracegrpc.New(
-			context.Background(),
+		opts := []otlptracegrpc.Option{
 			otlptracegrpc.WithInsecure(),
 			otlptracegrpc.WithEndpoint(c.Endpoint),
+		}
+		if len(c.OtlpHeaders) > 0 {
+			opts = append(opts, otlptracegrpc.WithHeaders(c.OtlpHeaders))
+		}
+		return otlptracegrpc.New(
+			context.Background(),
+			opts...,
 		)
 	case kindOtlpHttp:
 		// Not support flexible configuration now.
-		return otlptracehttp.New(
-			context.Background(),
+		opts := []otlptracehttp.Option{
 			otlptracehttp.WithInsecure(),
 			otlptracehttp.WithEndpoint(c.Endpoint),
+		}
+		if len(c.OtlpHeaders) > 0 {
+			opts = append(opts, otlptracehttp.WithHeaders(c.OtlpHeaders))
+		}
+		return otlptracehttp.New(
+			context.Background(),
+			opts...,
 		)
 	default:
 		return nil, fmt.Errorf("unknown exporter: %s", c.Batcher)
diff --git a/core/trace/config.go b/core/trace/config.go
index 83c62c3c..9423f97c 100644
--- a/core/trace/config.go
+++ b/core/trace/config.go
@@ -9,4 +9,8 @@ type Config struct {
 	Endpoint string  `json:",optional"`
 	Sampler  float64 `json:",default=1.0"`
 	Batcher  string  `json:",default=jaeger,options=jaeger|zipkin|otlpgrpc|otlphttp"`
+	// OtlpHeaders represents the headers for OTLP gRPC or HTTP transport.
+	// For example:
+	//  uptrace-dsn: 'http://project2_secret_token@localhost:14317/2'
+	OtlpHeaders map[string]string `json:",optional"`
 }
diff --git a/go.mod b/go.mod
index d11c140f..2b764a15 100644
--- a/go.mod
+++ b/go.mod
@@ -6,7 +6,6 @@ require (
 	github.com/DATA-DOG/go-sqlmock v1.5.0
 	github.com/alicebob/miniredis/v2 v2.30.2
 	github.com/fatih/color v1.15.0
-	github.com/felixge/fgprof v0.9.3
 	github.com/fullstorydev/grpcurl v1.8.7
 	github.com/go-redis/redis/v8 v8.11.5
 	github.com/go-sql-driver/mysql v1.7.1
@@ -23,7 +22,7 @@ require (
 	github.com/stretchr/testify v1.8.2
 	go.etcd.io/etcd/api/v3 v3.5.8
 	go.etcd.io/etcd/client/v3 v3.5.8
-	go.mongodb.org/mongo-driver v1.11.4
+	go.mongodb.org/mongo-driver v1.11.6
 	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,11 +32,11 @@ 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.9.0
-	golang.org/x/sys v0.7.0
+	golang.org/x/net v0.10.0
+	golang.org/x/sys v0.8.0
 	golang.org/x/time v0.3.0
-	google.golang.org/genproto v0.0.0-20230123190316-2c411cf9d197
-	google.golang.org/grpc v1.54.0
+	google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4
+	google.golang.org/grpc v1.55.0
 	google.golang.org/protobuf v1.30.0
 	gopkg.in/cheggaaa/pb.v1 v1.0.28
 	gopkg.in/h2non/gock.v1 v1.1.2
@@ -69,7 +68,6 @@ 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/h2non/parth v0.0.0-20190131123155-b4df798d6542 // indirect
 	github.com/jackc/pgpassfile v1.0.0 // indirect
@@ -106,9 +104,9 @@ require (
 	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.5.0 // indirect
+	golang.org/x/oauth2 v0.6.0 // indirect
 	golang.org/x/sync v0.1.0 // indirect
-	golang.org/x/term v0.7.0 // indirect
+	golang.org/x/term v0.8.0 // indirect
 	golang.org/x/text v0.9.0 // indirect
 	google.golang.org/appengine v1.6.7 // indirect
 	gopkg.in/inf.v0 v0.9.1 // indirect
diff --git a/go.sum b/go.sum
index b5cce472..404d97e6 100644
--- a/go.sum
+++ b/go.sum
@@ -89,8 +89,6 @@ github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.
 github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
 github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
 github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
-github.com/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.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
 github.com/fullstorydev/grpcurl v1.8.7 h1:xJWosq3BQovQ4QrdPO72OrPiWuGgEsxY8ldYsJbPrqI=
 github.com/fullstorydev/grpcurl v1.8.7/go.mod h1:pVtM4qe3CMoLaIzYS8uvTuDj2jVYmXqMUkZeijnXp/E=
@@ -120,8 +118,8 @@ github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69
 github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
 github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
 github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
-github.com/golang/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ=
 github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4=
+github.com/golang/glog v1.1.0 h1:/d3pCKDPWNnvIWe0vVUpNP32qc8U3PDVxySP/y360qE=
 github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
 github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
 github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
@@ -183,8 +181,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=
@@ -200,7 +196,6 @@ github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplb
 github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
 github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
 github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
-github.com/ianlancetaylor/demangle v0.0.0-20210905161508-09a460cdf81d/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w=
 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=
@@ -327,8 +322,8 @@ go.etcd.io/etcd/client/pkg/v3 v3.5.8 h1:tPp9YRn/UBFAHdhOQUII9eUs7aOK35eulpMhX4YB
 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=
-go.mongodb.org/mongo-driver v1.11.4 h1:4ayjakA013OdpGyL2K3ZqylTac/rMjrJOMZ1EHizXas=
-go.mongodb.org/mongo-driver v1.11.4/go.mod h1:PTSz5yu21bkT/wXpkS7WR5f0ddqw5quethTUn9WM+2g=
+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.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=
@@ -433,16 +428,16 @@ golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81R
 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.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-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.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
+golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
 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.5.0 h1:HuArIo48skDwlrvM3sEdHXElYslAMsf3KwRkkW4MC4s=
-golang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I=
+golang.org/x/oauth2 v0.6.0 h1:Lh8GPgSKBfWSwFvtuWOfeI3aAAnbXTSutYxJiOJFgIw=
+golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw=
 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=
@@ -488,13 +483,12 @@ 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-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.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
-golang.org/x/sys v0.7.0/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/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.8.0 h1:n5xxQn2i3PC0yLAbjTpNT85q/Kgzcr2gIoX9OrJUols=
+golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
 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=
@@ -613,8 +607,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-20230123190316-2c411cf9d197 h1:BwjeHhu4HS48EZmu1nS7flldBIDPC3qn+HqaSQ1K4x8=
-google.golang.org/genproto v0.0.0-20230123190316-2c411cf9d197/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=
+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/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=
@@ -633,8 +627,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.54.0 h1:EhTqbhiYeixwWQtAEZAxmV9MGqcjEU2mFx52xCzNyag=
-google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g=
+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/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=
diff --git a/internal/devserver/server.go b/internal/devserver/server.go
index 6f34413f..4b34f56c 100644
--- a/internal/devserver/server.go
+++ b/internal/devserver/server.go
@@ -7,7 +7,6 @@ import (
 	"net/http/pprof"
 	"sync"
 
-	"github.com/felixge/fgprof"
 	"github.com/prometheus/client_golang/prometheus/promhttp"
 	"github.com/zeromicro/go-zero/core/logx"
 	"github.com/zeromicro/go-zero/core/prometheus"
@@ -49,7 +48,6 @@ func (s *Server) addRoutes() {
 	}
 	// pprof
 	if s.config.EnablePprof {
-		s.handleFunc("/debug/fgprof", fgprof.Handler().(http.HandlerFunc))
 		s.handleFunc("/debug/pprof/", pprof.Index)
 		s.handleFunc("/debug/pprof/cmdline", pprof.Cmdline)
 		s.handleFunc("/debug/pprof/profile", pprof.Profile)
diff --git a/rest/engine.go b/rest/engine.go
index 5f2ffd91..a206b3ce 100644
--- a/rest/engine.go
+++ b/rest/engine.go
@@ -136,7 +136,7 @@ func (ng *engine) buildChainWithNativeMiddlewares(fr featuredRoutes, route Route
 		chn = chn.Append(ng.getLogHandler())
 	}
 	if ng.conf.Middlewares.Prometheus {
-		chn = chn.Append(handler.PrometheusHandler(route.Path))
+		chn = chn.Append(handler.PrometheusHandler(route.Path, route.Method))
 	}
 	if ng.conf.Middlewares.MaxConns {
 		chn = chn.Append(handler.MaxConnsHandler(ng.conf.MaxConns))
diff --git a/rest/handler/prometheushandler.go b/rest/handler/prometheushandler.go
index fcafa0a1..c1aa7ae7 100644
--- a/rest/handler/prometheushandler.go
+++ b/rest/handler/prometheushandler.go
@@ -18,7 +18,7 @@ var (
 		Subsystem: "requests",
 		Name:      "duration_ms",
 		Help:      "http server requests duration(ms).",
-		Labels:    []string{"path"},
+		Labels:    []string{"path", "method"},
 		Buckets:   []float64{5, 10, 25, 50, 100, 250, 500, 1000},
 	})
 
@@ -27,19 +27,19 @@ var (
 		Subsystem: "requests",
 		Name:      "code_total",
 		Help:      "http server requests error count.",
-		Labels:    []string{"path", "code"},
+		Labels:    []string{"path", "code", "method"},
 	})
 )
 
 // PrometheusHandler returns a middleware that reports stats to prometheus.
-func PrometheusHandler(path string) func(http.Handler) http.Handler {
+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}
 			defer func() {
-				metricServerReqDur.Observe(int64(timex.Since(startTime)/time.Millisecond), path)
-				metricServerReqCodeTotal.Inc(path, strconv.Itoa(cw.Code))
+				metricServerReqDur.Observe(int64(timex.Since(startTime)/time.Millisecond), path, method)
+				metricServerReqCodeTotal.Inc(path, strconv.Itoa(cw.Code), method)
 			}()
 
 			next.ServeHTTP(cw, r)
diff --git a/rest/handler/timeouthandler.go b/rest/handler/timeouthandler.go
index ec34180a..52d82a80 100644
--- a/rest/handler/timeouthandler.go
+++ b/rest/handler/timeouthandler.go
@@ -127,6 +127,12 @@ type timeoutWriter struct {
 
 var _ http.Pusher = (*timeoutWriter)(nil)
 
+func (tw *timeoutWriter) Flush() {
+	if flusher, ok := tw.w.(http.Flusher); ok {
+		flusher.Flush()
+	}
+}
+
 func (tw *timeoutWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
 	if hijacked, ok := tw.w.(http.Hijacker); ok {
 		return hijacked.Hijack()
diff --git a/tools/goctl/api/apigen/gen.go b/tools/goctl/api/apigen/gen.go
index b0022623..1e77c578 100644
--- a/tools/goctl/api/apigen/gen.go
+++ b/tools/goctl/api/apigen/gen.go
@@ -8,7 +8,7 @@ import (
 	"path/filepath"
 	"strings"
 
-	"github.com/logrusorgru/aurora"
+	"github.com/gookit/color"
 	"github.com/spf13/cobra"
 	"github.com/zeromicro/go-zero/tools/goctl/util"
 	"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
@@ -73,6 +73,6 @@ func CreateApiTemplate(_ *cobra.Command, _ []string) error {
 		return err
 	}
 
-	fmt.Println(aurora.Green("Done."))
+	fmt.Println(color.Green.Render("Done."))
 	return nil
 }
diff --git a/tools/goctl/api/dartgen/gendata.go b/tools/goctl/api/dartgen/gendata.go
index 08ca1354..7894cfb3 100644
--- a/tools/goctl/api/dartgen/gendata.go
+++ b/tools/goctl/api/dartgen/gendata.go
@@ -45,8 +45,10 @@ class {{.Name}} {
 		return {{.Name}}(
 			{{range .Members}}
 				{{lowCamelCase .Name}}: {{appendNullCoalescing .}}
-					{{if isDirectType .Type.Name}}
+					{{if isAtomicType .Type.Name}}
 						m['{{getPropertyFromMember .}}'] {{appendDefaultEmptyValue .Type.Name}}
+					{{else if isAtomicListType .Type.Name}}
+						m['{{getPropertyFromMember .}}']?.cast<{{getCoreType .Type.Name}}>() {{appendDefaultEmptyValue .Type.Name}}
 					{{else if isClassListType .Type.Name}}
 						((m['{{getPropertyFromMember .}}'] {{appendDefaultEmptyValue .Type.Name}}) as List<dynamic>).map((i) => {{getCoreType .Type.Name}}.fromJson(i)).toList()
 					{{else}}
diff --git a/tools/goctl/api/dartgen/genvars.go b/tools/goctl/api/dartgen/genvars.go
index ac1b0fac..64cce8c5 100644
--- a/tools/goctl/api/dartgen/genvars.go
+++ b/tools/goctl/api/dartgen/genvars.go
@@ -2,7 +2,6 @@ package dartgen
 
 import (
 	"fmt"
-	"io/ioutil"
 	"os"
 )
 
@@ -83,7 +82,7 @@ func genVars(dir string, isLegacy bool, scheme string, hostname string) error {
 	}
 
 	if !fileExists(dir + "vars.dart") {
-		err = ioutil.WriteFile(dir+"vars.dart", []byte(fmt.Sprintf(`const serverHost='%s://%s';`, scheme, hostname)), 0o644)
+		err = os.WriteFile(dir+"vars.dart", []byte(fmt.Sprintf(`const serverHost='%s://%s';`, scheme, hostname)), 0o644)
 		if err != nil {
 			return err
 		}
@@ -94,7 +93,7 @@ func genVars(dir string, isLegacy bool, scheme string, hostname string) error {
 		if isLegacy {
 			tpl = varTemplate
 		}
-		err = ioutil.WriteFile(dir+"kv.dart", []byte(tpl), 0o644)
+		err = os.WriteFile(dir+"kv.dart", []byte(tpl), 0o644)
 		if err != nil {
 			return err
 		}
diff --git a/tools/goctl/api/dartgen/util.go b/tools/goctl/api/dartgen/util.go
index 0847057d..79d94e80 100644
--- a/tools/goctl/api/dartgen/util.go
+++ b/tools/goctl/api/dartgen/util.go
@@ -71,7 +71,11 @@ func isListType(s string) bool {
 }
 
 func isClassListType(s string) bool {
-	return strings.HasPrefix(s, "List<") && !isAtomicType(getCoreType(s))
+	return isListType(s) && !isAtomicType(getCoreType(s))
+}
+
+func isAtomicListType(s string) bool {
+	return isListType(s) && isAtomicType(getCoreType(s))
 }
 
 func isListItemsNullable(s string) bool {
diff --git a/tools/goctl/api/dartgen/vars.go b/tools/goctl/api/dartgen/vars.go
index 233a889c..3dcff8e7 100644
--- a/tools/goctl/api/dartgen/vars.go
+++ b/tools/goctl/api/dartgen/vars.go
@@ -6,8 +6,10 @@ var funcMap = template.FuncMap{
 	"getBaseName":                     getBaseName,
 	"getPropertyFromMember":           getPropertyFromMember,
 	"isDirectType":                    isDirectType,
+	"isAtomicType":                    isAtomicType,
 	"isNumberType":                    isNumberType,
 	"isClassListType":                 isClassListType,
+	"isAtomicListType":                isAtomicListType,
 	"isListItemsNullable":             isListItemsNullable,
 	"isNullableType":                  isNullableType,
 	"appendNullCoalescing":            appendNullCoalescing,
diff --git a/tools/goctl/api/gogen/gen.go b/tools/goctl/api/gogen/gen.go
index 74489872..6f568fe5 100644
--- a/tools/goctl/api/gogen/gen.go
+++ b/tools/goctl/api/gogen/gen.go
@@ -11,7 +11,7 @@ import (
 	"sync"
 	"time"
 
-	"github.com/logrusorgru/aurora"
+	"github.com/gookit/color"
 	"github.com/spf13/cobra"
 	"github.com/zeromicro/go-zero/core/logx"
 	apiformat "github.com/zeromicro/go-zero/tools/goctl/api/format"
@@ -109,7 +109,7 @@ func DoGenProject(apiFile, dir, style string) error {
 		return err
 	}
 
-	fmt.Println(aurora.Green("Done."))
+	fmt.Println(color.Green.Render("Done."))
 	return nil
 }
 
@@ -152,14 +152,14 @@ func sweep() error {
 			seconds, err := strconv.ParseInt(timestamp, 10, 64)
 			if err != nil {
 				// print error and ignore
-				fmt.Println(aurora.Red(fmt.Sprintf("sweep ignored file: %s", fpath)))
+				fmt.Println(color.Red.Sprintf("sweep ignored file: %s", fpath))
 				return nil
 			}
 
 			tm := time.Unix(seconds, 0)
 			if tm.Before(keepTime) {
 				if err := os.RemoveAll(fpath); err != nil {
-					fmt.Println(aurora.Red(fmt.Sprintf("failed to remove file: %s", fpath)))
+					fmt.Println(color.Red.Sprintf("failed to remove file: %s", fpath))
 					return err
 				}
 			}
diff --git a/tools/goctl/api/javagen/gen.go b/tools/goctl/api/javagen/gen.go
index 34103b75..bf001e67 100644
--- a/tools/goctl/api/javagen/gen.go
+++ b/tools/goctl/api/javagen/gen.go
@@ -5,7 +5,7 @@ import (
 	"fmt"
 	"strings"
 
-	"github.com/logrusorgru/aurora"
+	"github.com/gookit/color"
 	"github.com/spf13/cobra"
 	"github.com/zeromicro/go-zero/core/logx"
 	"github.com/zeromicro/go-zero/tools/goctl/api/parser"
@@ -45,6 +45,6 @@ func JavaCommand(_ *cobra.Command, _ []string) error {
 	logx.Must(genPacket(dir, packetName, api))
 	logx.Must(genComponents(dir, packetName, api))
 
-	fmt.Println(aurora.Green("Done."))
+	fmt.Println(color.Green.Render("Done."))
 	return nil
 }
diff --git a/tools/goctl/api/parser/g4/ast/apiparser.go b/tools/goctl/api/parser/g4/ast/apiparser.go
index 4b416976..890ba002 100644
--- a/tools/goctl/api/parser/g4/ast/apiparser.go
+++ b/tools/goctl/api/parser/g4/ast/apiparser.go
@@ -19,7 +19,6 @@ type (
 		linePrefix               string
 		debug                    bool
 		log                      console.Console
-		src                      string
 		skipCheckTypeDeclaration bool
 		handlerMap               map[string]PlaceHolder
 		routeMap                 map[string]PlaceHolder
@@ -88,30 +87,29 @@ func (p *Parser) Parse(filename string) (*Api, error) {
 		return nil, err
 	}
 
-	p.src = abs
 	data, err := p.readContent(filename)
 	if err != nil {
 		return nil, err
 	}
 
-	p.importStatck.push(p.src)
+	p.importStatck.push(abs)
 	return p.parse(filename, data)
 }
 
 // ParseContent is used to parse the api from the specified content
 func (p *Parser) ParseContent(content string, filename ...string) (*Api, error) {
-	var f string
+	var f, abs string
 	if len(filename) > 0 {
 		f = filename[0]
-		abs, err := filepath.Abs(f)
+		a, err := filepath.Abs(f)
 		if err != nil {
 			return nil, err
 		}
 
-		p.src = abs
+		abs = a
 	}
 
-	p.importStatck.push(p.src)
+	p.importStatck.push(abs)
 	return p.parse(f, content)
 }
 
@@ -127,7 +125,7 @@ func (p *Parser) parse(filename, content string) (*Api, error) {
 	apiAstList = append(apiAstList, root)
 	p.storeVerificationInfo(root)
 	p.syntax = root.Syntax
-	impApiAstList, err := p.invokeImportedApi(root.Import)
+	impApiAstList, err := p.invokeImportedApi(filename, root.Import)
 	if err != nil {
 		return nil, err
 	}
@@ -144,10 +142,10 @@ func (p *Parser) parse(filename, content string) (*Api, error) {
 	return allApi, nil
 }
 
-func (p *Parser) invokeImportedApi(imports []*ImportExpr) ([]*Api, error) {
+func (p *Parser) invokeImportedApi(filename string, imports []*ImportExpr) ([]*Api, error) {
 	var apiAstList []*Api
 	for _, imp := range imports {
-		dir := filepath.Dir(p.src)
+		dir := filepath.Dir(filename)
 		impPath := strings.ReplaceAll(imp.Value.Text(), "\"", "")
 		if !filepath.IsAbs(impPath) {
 			impPath = filepath.Join(dir, impPath)
@@ -178,7 +176,7 @@ func (p *Parser) invokeImportedApi(imports []*ImportExpr) ([]*Api, error) {
 		}
 		p.storeVerificationInfo(nestedApi)
 		apiAstList = append(apiAstList, nestedApi)
-		list, err := p.invokeImportedApi(nestedApi.Import)
+		list, err := p.invokeImportedApi(impPath, nestedApi.Import)
 		p.importStatck.pop()
 		apiAstList = append(apiAstList, list...)
 
diff --git a/tools/goctl/api/tsgen/gen.go b/tools/goctl/api/tsgen/gen.go
index ddad72ac..34732b67 100644
--- a/tools/goctl/api/tsgen/gen.go
+++ b/tools/goctl/api/tsgen/gen.go
@@ -4,7 +4,7 @@ import (
 	"errors"
 	"fmt"
 
-	"github.com/logrusorgru/aurora"
+	"github.com/gookit/color"
 	"github.com/spf13/cobra"
 	"github.com/zeromicro/go-zero/core/logx"
 	"github.com/zeromicro/go-zero/tools/goctl/api/parser"
@@ -45,7 +45,7 @@ func TsCommand(_ *cobra.Command, _ []string) error {
 
 	api, err := parser.Parse(apiFile)
 	if err != nil {
-		fmt.Println(aurora.Red("Failed"))
+		fmt.Println(color.Red.Render("Failed"))
 		return err
 	}
 
@@ -59,6 +59,6 @@ func TsCommand(_ *cobra.Command, _ []string) error {
 	logx.Must(genHandler(dir, webAPI, caller, api, unwrapAPI))
 	logx.Must(genComponents(dir, api))
 
-	fmt.Println(aurora.Green("Done."))
+	fmt.Println(color.Green.Render("Done."))
 	return nil
 }
diff --git a/tools/goctl/api/tsgen/util.go b/tools/goctl/api/tsgen/util.go
index 5d211717..eb737afa 100644
--- a/tools/goctl/api/tsgen/util.go
+++ b/tools/goctl/api/tsgen/util.go
@@ -114,7 +114,7 @@ func primitiveType(tp string) (string, bool) {
 	switch tp {
 	case "string":
 		return "string", true
-	case "int", "int8", "int32", "int64", "uint", "uint8", "uint16", "uint32", "uint64":
+	case "int", "int8","int16", "int32", "int64", "uint", "uint8", "uint16", "uint32", "uint64":
 		return "number", true
 	case "float", "float32", "float64":
 		return "number", true
diff --git a/tools/goctl/api/validate/validate.go b/tools/goctl/api/validate/validate.go
index 2660e28e..cb893c80 100644
--- a/tools/goctl/api/validate/validate.go
+++ b/tools/goctl/api/validate/validate.go
@@ -4,7 +4,7 @@ import (
 	"errors"
 	"fmt"
 
-	"github.com/logrusorgru/aurora"
+	"github.com/gookit/color"
 	"github.com/spf13/cobra"
 	"github.com/zeromicro/go-zero/tools/goctl/api/parser"
 )
@@ -27,7 +27,7 @@ func GoValidateApi(_ *cobra.Command, _ []string) error {
 
 	err = spec.Validate()
 	if err == nil {
-		fmt.Println(aurora.Green("api format ok"))
+		fmt.Println(color.Green.Render("api format ok"))
 	}
 	return err
 }
diff --git a/tools/goctl/cmd/root.go b/tools/goctl/cmd/root.go
index 870ecd1b..c19b9c7b 100644
--- a/tools/goctl/cmd/root.go
+++ b/tools/goctl/cmd/root.go
@@ -8,7 +8,7 @@ import (
 	"strings"
 	"text/template"
 
-	"github.com/logrusorgru/aurora"
+	"github.com/gookit/color"
 	"github.com/spf13/cobra"
 	"github.com/withfig/autocomplete-tools/integrations/cobra"
 	"github.com/zeromicro/go-zero/tools/goctl/api"
@@ -44,7 +44,7 @@ var (
 func Execute() {
 	os.Args = supportGoStdFlag(os.Args)
 	if err := rootCmd.Execute(); err != nil {
-		fmt.Println(aurora.Red(err.Error()))
+		fmt.Println(color.Red.Render(err.Error()))
 		os.Exit(codeFailure)
 	}
 }
diff --git a/tools/goctl/cmd/usage.go b/tools/goctl/cmd/usage.go
index 9daa3dcc..ff17bead 100644
--- a/tools/goctl/cmd/usage.go
+++ b/tools/goctl/cmd/usage.go
@@ -2,53 +2,40 @@ package cmd
 
 import (
 	"fmt"
-	"runtime"
 
-	"github.com/logrusorgru/aurora"
-	"github.com/zeromicro/go-zero/tools/goctl/vars"
+	"github.com/gookit/color"
 )
 
 var colorRender = []func(v any) string{
 	func(v any) string {
-		return aurora.BrightRed(v).String()
+		return color.LightRed.Render(v)
 	},
 	func(v any) string {
-		return aurora.BrightGreen(v).String()
+		return color.LightGreen.Render(v)
 	},
 	func(v any) string {
-		return aurora.BrightYellow(v).String()
+		return color.LightYellow.Render(v)
 	},
 	func(v any) string {
-		return aurora.BrightBlue(v).String()
+		return color.LightBlue.Render(v)
 	},
 	func(v any) string {
-		return aurora.BrightMagenta(v).String()
+		return color.LightMagenta.Render(v)
 	},
 	func(v any) string {
-		return aurora.BrightCyan(v).String()
+		return color.LightCyan.Render(v)
 	},
 }
 
 func blue(s string) string {
-	if runtime.GOOS == vars.OsWindows {
-		return s
-	}
-
-	return aurora.BrightBlue(s).String()
+	return color.LightBlue.Render(s)
 }
 
 func green(s string) string {
-	if runtime.GOOS == vars.OsWindows {
-		return s
-	}
-
-	return aurora.BrightGreen(s).String()
+	return color.LightGreen.Render(s)
 }
 
 func rainbow(s string) string {
-	if runtime.GOOS == vars.OsWindows {
-		return s
-	}
 	s0 := s[0]
 	return colorRender[int(s0)%(len(colorRender)-1)](s)
 }
diff --git a/tools/goctl/docker/docker.go b/tools/goctl/docker/docker.go
index 15ad115a..3859697a 100644
--- a/tools/goctl/docker/docker.go
+++ b/tools/goctl/docker/docker.go
@@ -9,7 +9,7 @@ import (
 	"strings"
 	"text/template"
 
-	"github.com/logrusorgru/aurora"
+	"github.com/gookit/color"
 	"github.com/spf13/cobra"
 	"github.com/zeromicro/go-zero/tools/goctl/util"
 	"github.com/zeromicro/go-zero/tools/goctl/util/env"
@@ -42,7 +42,7 @@ type Docker struct {
 func dockerCommand(_ *cobra.Command, _ []string) (err error) {
 	defer func() {
 		if err == nil {
-			fmt.Println(aurora.Green("Done."))
+			fmt.Println(color.Green.Render("Done."))
 		}
 	}()
 
diff --git a/tools/goctl/go.mod b/tools/goctl/go.mod
index c8829157..b709681e 100644
--- a/tools/goctl/go.mod
+++ b/tools/goctl/go.mod
@@ -7,8 +7,8 @@ require (
 	github.com/emicklei/proto v1.11.2
 	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/logrusorgru/aurora v2.0.3+incompatible
 	github.com/spf13/cobra v1.7.0
 	github.com/spf13/pflag v1.0.5
 	github.com/stretchr/testify v1.8.2
@@ -17,7 +17,7 @@ require (
 	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.54.0
+	google.golang.org/grpc v1.55.0
 	google.golang.org/protobuf v1.30.0
 )
 
@@ -56,6 +56,7 @@ require (
 	github.com/jackc/pgx/v5 v5.3.1 // 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
 	github.com/mailru/easyjson v0.7.7 // indirect
 	github.com/mattn/go-colorable v0.1.13 // indirect
 	github.com/mattn/go-isatty v0.0.17 // indirect
@@ -71,6 +72,7 @@ require (
 	github.com/prometheus/common v0.42.0 // indirect
 	github.com/prometheus/procfs v0.9.0 // 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
@@ -91,12 +93,12 @@ require (
 	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.5.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/time v0.3.0 // indirect
 	google.golang.org/appengine v1.6.7 // indirect
-	google.golang.org/genproto v0.0.0-20230123190316-2c411cf9d197 // indirect
+	google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // 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
diff --git a/tools/goctl/go.sum b/tools/goctl/go.sum
index fa1b679b..85694bd7 100644
--- a/tools/goctl/go.sum
+++ b/tools/goctl/go.sum
@@ -119,8 +119,8 @@ github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5x
 github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
 github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
 github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
-github.com/golang/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ=
 github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4=
+github.com/golang/glog v1.1.0 h1:/d3pCKDPWNnvIWe0vVUpNP32qc8U3PDVxySP/y360qE=
 github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
 github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
 github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
@@ -185,6 +185,8 @@ github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+
 github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
 github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
 github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
+github.com/gookit/color v1.5.3 h1:twfIhZs4QLCtimkP7MOxlF3A0U/5cDPseRT9M/+2SCE=
+github.com/gookit/color v1.5.3/go.mod h1:NUzwzeehUfl7GIb36pqId+UGmRfQcU/WiiyTTeNjHtE=
 github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
 github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks=
 github.com/grpc-ecosystem/grpc-gateway/v2 v2.15.0 h1:1JYBfzqrWPcCclBwxFCPAou9n+q86mfnu7NAeHfte7A=
@@ -286,6 +288,8 @@ github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ
 github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
 github.com/withfig/autocomplete-tools/integrations/cobra v1.2.1 h1:+dBg5k7nuTE38VVdoroRsT0Z88fmvdYrI2EjzJst35I=
 github.com/withfig/autocomplete-tools/integrations/cobra v1.2.1/go.mod h1:nmuySobZb4kFgFy6BptpXp/BBw+xFSyvVPP6auoJB4k=
+github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 h1:QldyIu/L63oPpyvQmHgvgickp1Yw510KJOqX7H24mg8=
+github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs=
 github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
@@ -414,8 +418,8 @@ golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4Iltr
 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.5.0 h1:HuArIo48skDwlrvM3sEdHXElYslAMsf3KwRkkW4MC4s=
-golang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I=
+golang.org/x/oauth2 v0.6.0 h1:Lh8GPgSKBfWSwFvtuWOfeI3aAAnbXTSutYxJiOJFgIw=
+golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw=
 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=
@@ -580,8 +584,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-20230123190316-2c411cf9d197 h1:BwjeHhu4HS48EZmu1nS7flldBIDPC3qn+HqaSQ1K4x8=
-google.golang.org/genproto v0.0.0-20230123190316-2c411cf9d197/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=
+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/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=
@@ -598,8 +602,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.54.0 h1:EhTqbhiYeixwWQtAEZAxmV9MGqcjEU2mFx52xCzNyag=
-google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g=
+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/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=
diff --git a/tools/goctl/kube/kube.go b/tools/goctl/kube/kube.go
index 03ba2028..c3b13263 100644
--- a/tools/goctl/kube/kube.go
+++ b/tools/goctl/kube/kube.go
@@ -6,7 +6,7 @@ import (
 	"fmt"
 	"text/template"
 
-	"github.com/logrusorgru/aurora"
+	"github.com/gookit/color"
 	"github.com/spf13/cobra"
 	"github.com/zeromicro/go-zero/tools/goctl/util"
 	"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
@@ -111,7 +111,7 @@ func deploymentCommand(_ *cobra.Command, _ []string) error {
 		return err
 	}
 
-	fmt.Println(aurora.Green("Done."))
+	fmt.Println(color.Green.Render("Done."))
 	return nil
 }
 
diff --git a/tools/goctl/migrate/migrate.go b/tools/goctl/migrate/migrate.go
index f6c5bcfb..4eee9459 100644
--- a/tools/goctl/migrate/migrate.go
+++ b/tools/goctl/migrate/migrate.go
@@ -8,18 +8,15 @@ import (
 	"go/parser"
 	"go/token"
 	"io/fs"
-	"io/ioutil"
 	"os"
 	"path/filepath"
-	"runtime"
 	"strings"
 	"time"
 
-	"github.com/logrusorgru/aurora"
+	"github.com/gookit/color"
 	"github.com/spf13/cobra"
 	"github.com/zeromicro/go-zero/tools/goctl/util/console"
 	"github.com/zeromicro/go-zero/tools/goctl/util/ctx"
-	"github.com/zeromicro/go-zero/tools/goctl/vars"
 )
 
 const defaultMigrateVersion = "v1.3.0"
@@ -165,7 +162,7 @@ func writeFile(pkgs []*ast.Package, verbose bool) error {
 				return fmt.Errorf("[rewriteImport] format file %s error: %w", filename, err)
 			}
 
-			err = ioutil.WriteFile(filename, w.Bytes(), os.ModePerm)
+			err = os.WriteFile(filename, w.Bytes(), os.ModePerm)
 			if err != nil {
 				return fmt.Errorf("[rewriteImport] write file %s error: %w", filename, err)
 			}
@@ -246,10 +243,7 @@ It's recommended to use the replacement package, do you want to replace?
 ['Y' for yes, 'N' for no, 'A' for all, 'I' for ignore]: `,
 		deprecated, replacement)
 
-	if runtime.GOOS != vars.OsWindows {
-		msg = aurora.Yellow(msg).String()
-	}
-	fmt.Print(msg)
+	fmt.Print(color.Yellow.Render(msg))
 
 	for {
 		var in string
diff --git a/tools/goctl/migrate/version.go b/tools/goctl/migrate/version.go
index de6b8fb0..37a4eec0 100644
--- a/tools/goctl/migrate/version.go
+++ b/tools/goctl/migrate/version.go
@@ -2,7 +2,7 @@ package migrate
 
 import (
 	"fmt"
-	"io/ioutil"
+	"io"
 	"net/http"
 	"strings"
 	"time"
@@ -34,7 +34,7 @@ func getLatest(repo string, verbose bool) ([]string, error) {
 			continue
 		}
 		defer resp.Body.Close()
-		data, err := ioutil.ReadAll(resp.Body)
+		data, err := io.ReadAll(resp.Body)
 		if err != nil {
 			log(err)
 			continue
diff --git a/tools/goctl/model/sql/command/migrationnotes/v1.3.4.go b/tools/goctl/model/sql/command/migrationnotes/v1.3.4.go
index 0f5cb759..dc9df2c5 100644
--- a/tools/goctl/model/sql/command/migrationnotes/v1.3.4.go
+++ b/tools/goctl/model/sql/command/migrationnotes/v1.3.4.go
@@ -2,7 +2,7 @@ package migrationnotes
 
 import (
 	"fmt"
-	"io/ioutil"
+	"os"
 	"strings"
 )
 
@@ -24,7 +24,7 @@ func migrateBefore1_3_4(dir, style string) error {
 }
 
 func needShow1_3_4(dir, style string) (bool, error) {
-	files, err := ioutil.ReadDir(dir)
+	files, err := os.ReadDir(dir)
 	if err != nil {
 		return false, nil
 	}
diff --git a/tools/goctl/model/sql/gen/gen.go b/tools/goctl/model/sql/gen/gen.go
index 5b7bfea3..34a07517 100644
--- a/tools/goctl/model/sql/gen/gen.go
+++ b/tools/goctl/model/sql/gen/gen.go
@@ -3,7 +3,6 @@ package gen
 import (
 	"bytes"
 	"fmt"
-	"io/ioutil"
 	"os"
 	"path/filepath"
 	"strings"
@@ -168,7 +167,7 @@ func (g *defaultGenerator) createFile(modelList map[string]*codeTuple) error {
 
 		name := util.SafeString(modelFilename) + "_gen.go"
 		filename := filepath.Join(dirAbs, name)
-		err = ioutil.WriteFile(filename, []byte(codes.modelCode), os.ModePerm)
+		err = os.WriteFile(filename, []byte(codes.modelCode), os.ModePerm)
 		if err != nil {
 			return err
 		}
@@ -179,7 +178,7 @@ func (g *defaultGenerator) createFile(modelList map[string]*codeTuple) error {
 			g.Warning("%s already exists, ignored.", name)
 			continue
 		}
-		err = ioutil.WriteFile(filename, []byte(codes.modelCustomCode), os.ModePerm)
+		err = os.WriteFile(filename, []byte(codes.modelCustomCode), os.ModePerm)
 		if err != nil {
 			return err
 		}
diff --git a/tools/goctl/model/sql/util/matcher.go b/tools/goctl/model/sql/util/matcher.go
index b7e84e05..5824426f 100644
--- a/tools/goctl/model/sql/util/matcher.go
+++ b/tools/goctl/model/sql/util/matcher.go
@@ -1,7 +1,7 @@
 package util
 
 import (
-	"io/ioutil"
+	"os"
 	"path/filepath"
 )
 
@@ -13,7 +13,7 @@ func MatchFiles(in string) ([]string, error) {
 		return nil, err
 	}
 
-	files, err := ioutil.ReadDir(abs)
+	files, err := os.ReadDir(abs)
 	if err != nil {
 		return nil, err
 	}
diff --git a/tools/goctl/pkg/parser/api/format/format.go b/tools/goctl/pkg/parser/api/format/format.go
index e7b3aa72..128580c7 100644
--- a/tools/goctl/pkg/parser/api/format/format.go
+++ b/tools/goctl/pkg/parser/api/format/format.go
@@ -3,14 +3,14 @@ package format
 import (
 	"bytes"
 	"io"
-	"io/ioutil"
+	"os"
 
 	"github.com/zeromicro/go-zero/tools/goctl/pkg/parser/api/parser"
 )
 
 // File formats the api file.
 func File(filename string) error {
-	data, err := ioutil.ReadFile(filename)
+	data, err := os.ReadFile(filename)
 	if err != nil {
 		return err
 	}
@@ -18,7 +18,7 @@ func File(filename string) error {
 	if err := Source(data, buffer); err != nil {
 		return err
 	}
-	return ioutil.WriteFile(filename, buffer.Bytes(), 0666)
+	return os.WriteFile(filename, buffer.Bytes(), 0666)
 }
 
 // Source formats the api source.
diff --git a/tools/goctl/pkg/parser/api/scanner/scanner.go b/tools/goctl/pkg/parser/api/scanner/scanner.go
index 802684c6..35a9332d 100644
--- a/tools/goctl/pkg/parser/api/scanner/scanner.go
+++ b/tools/goctl/pkg/parser/api/scanner/scanner.go
@@ -4,8 +4,8 @@ import (
 	"bytes"
 	"errors"
 	"fmt"
-	"io/ioutil"
 	"log"
+	"os"
 	"path/filepath"
 	"strings"
 
@@ -647,7 +647,7 @@ func NewScanner(filename string, src interface{}) (*Scanner, error) {
 }
 
 func readData(filename string, src interface{}) ([]byte, error) {
-	data, err := ioutil.ReadFile(filename)
+	data, err := os.ReadFile(filename)
 	if err == nil {
 		return data, nil
 	}
diff --git a/tools/goctl/plugin/plugin.go b/tools/goctl/plugin/plugin.go
index 321d6132..cf10685b 100644
--- a/tools/goctl/plugin/plugin.go
+++ b/tools/goctl/plugin/plugin.go
@@ -6,7 +6,6 @@ import (
 	"errors"
 	"fmt"
 	"io"
-	"io/ioutil"
 	"net/http"
 	"os"
 	"os/exec"
@@ -171,7 +170,7 @@ func downloadFile(filepath, url string) error {
 // NewPlugin returns contextual resources when written in other languages
 func NewPlugin() (*Plugin, error) {
 	var plugin Plugin
-	content, err := ioutil.ReadAll(os.Stdin)
+	content, err := io.ReadAll(os.Stdin)
 	if err != nil {
 		return nil, err
 	}
diff --git a/tools/goctl/quickstart/micro.go b/tools/goctl/quickstart/micro.go
index 4d73af8e..ad776440 100644
--- a/tools/goctl/quickstart/micro.go
+++ b/tools/goctl/quickstart/micro.go
@@ -2,7 +2,7 @@ package quickstart
 
 import (
 	_ "embed"
-	"io/ioutil"
+	"os"
 	"path/filepath"
 
 	"github.com/zeromicro/go-zero/core/logx"
@@ -38,7 +38,7 @@ func initRPCProto() error {
 
 	protoFilename := filepath.Join(zrpcWorkDir, protoName)
 	rpcBytes := []byte(protocContent)
-	return ioutil.WriteFile(protoFilename, rpcBytes, 0o666)
+	return os.WriteFile(protoFilename, rpcBytes, 0o666)
 }
 
 type micro struct{}
@@ -55,7 +55,7 @@ func (m micro) mustStartRPCProject() {
 	arg := "goctl rpc protoc " + protoName + " --go_out=. --go-grpc_out=. --zrpc_out=. --verbose"
 	execCommand(zrpcWorkDir, arg)
 	etcFile := filepath.Join(zrpcWorkDir, "etc", "greet.yaml")
-	logx.Must(ioutil.WriteFile(etcFile, []byte(rpcEtcContent), 0o666))
+	logx.Must(os.WriteFile(etcFile, []byte(rpcEtcContent), 0o666))
 }
 
 func (m micro) start() {
diff --git a/tools/goctl/quickstart/mono.go b/tools/goctl/quickstart/mono.go
index 4710b1b3..5d04bf5d 100644
--- a/tools/goctl/quickstart/mono.go
+++ b/tools/goctl/quickstart/mono.go
@@ -2,7 +2,7 @@ package quickstart
 
 import (
 	_ "embed"
-	"io/ioutil"
+	"os"
 	"path/filepath"
 
 	"github.com/zeromicro/go-zero/core/logx"
@@ -35,7 +35,7 @@ func initAPIFlags() error {
 
 	apiFilename := filepath.Join(apiWorkDir, "greet.api")
 	apiBytes := []byte(apiContent)
-	if err := ioutil.WriteFile(apiFilename, apiBytes, 0o666); err != nil {
+	if err := os.WriteFile(apiFilename, apiBytes, 0o666); err != nil {
 		return err
 	}
 
@@ -59,7 +59,7 @@ func (m mono) createAPIProject() {
 	log.Debug(">> Generating quickstart api project...")
 	logx.Must(gogen.GoCommand(nil, nil))
 	etcFile := filepath.Join(apiWorkDir, "etc", "greet.yaml")
-	logx.Must(ioutil.WriteFile(etcFile, []byte(apiEtcContent), 0o666))
+	logx.Must(os.WriteFile(etcFile, []byte(apiEtcContent), 0o666))
 	logicFile := filepath.Join(apiWorkDir, "internal", "logic", "pinglogic.go")
 	svcFile := filepath.Join(apiWorkDir, "internal", "svc", "servicecontext.go")
 	configPath := filepath.Join(apiWorkDir, "internal", "config")
diff --git a/tools/goctl/rpc/generator/genconfig.go b/tools/goctl/rpc/generator/genconfig.go
index a81a07a8..2af78496 100644
--- a/tools/goctl/rpc/generator/genconfig.go
+++ b/tools/goctl/rpc/generator/genconfig.go
@@ -2,7 +2,6 @@ package generator
 
 import (
 	_ "embed"
-	"io/ioutil"
 	"os"
 	"path/filepath"
 
@@ -36,5 +35,5 @@ func (g *Generator) GenConfig(ctx DirContext, _ parser.Proto, cfg *conf.Config)
 		return err
 	}
 
-	return ioutil.WriteFile(fileName, []byte(text), os.ModePerm)
+	return os.WriteFile(fileName, []byte(text), os.ModePerm)
 }
diff --git a/tools/goctl/rpc/generator/mkdir.go b/tools/goctl/rpc/generator/mkdir.go
index 2e8526fb..a92d2d8f 100644
--- a/tools/goctl/rpc/generator/mkdir.go
+++ b/tools/goctl/rpc/generator/mkdir.go
@@ -1,6 +1,7 @@
 package generator
 
 import (
+	"github.com/zeromicro/go-zero/tools/goctl/util/format"
 	"path/filepath"
 	"strings"
 
@@ -56,7 +57,7 @@ type (
 	}
 )
 
-func mkdir(ctx *ctx.ProjectContext, proto parser.Proto, _ *conf.Config, c *ZRpcContext) (DirContext,
+func mkdir(ctx *ctx.ProjectContext, proto parser.Proto, conf *conf.Config, c *ZRpcContext) (DirContext,
 	error) {
 	inner := make(map[string]Dir)
 	etcDir := filepath.Join(ctx.WorkDir, "etc")
@@ -90,8 +91,12 @@ func mkdir(ctx *ctx.ProjectContext, proto parser.Proto, _ *conf.Config, c *ZRpcC
 		callDir := filepath.Join(ctx.WorkDir,
 			strings.ToLower(stringx.From(proto.Service[0].Name).ToCamel()))
 		if strings.EqualFold(proto.Service[0].Name, filepath.Base(proto.GoPackage)) {
-			callDir = filepath.Join(ctx.WorkDir,
-				strings.ToLower(stringx.From(proto.Service[0].Name+"_client").ToCamel()))
+			var err error
+			clientDir, err = format.FileNamingFormat(conf.NamingFormat, proto.Service[0].Name+"_client")
+			if err != nil {
+				return nil, err
+			}
+			callDir = filepath.Join(ctx.WorkDir, clientDir)
 		}
 		inner[call] = Dir{
 			Filename: callDir,
diff --git a/tools/goctl/tpl/templates.go b/tools/goctl/tpl/templates.go
index 2171f08b..9357eb00 100644
--- a/tools/goctl/tpl/templates.go
+++ b/tools/goctl/tpl/templates.go
@@ -4,7 +4,7 @@ import (
 	"fmt"
 	"path/filepath"
 
-	"github.com/logrusorgru/aurora"
+	"github.com/gookit/color"
 	"github.com/spf13/cobra"
 	"github.com/zeromicro/go-zero/core/errorx"
 	"github.com/zeromicro/go-zero/tools/goctl/api/apigen"
@@ -70,8 +70,8 @@ func genTemplates(_ *cobra.Command, _ []string) error {
 		return err
 	}
 
-	fmt.Printf("Templates are generated in %s, %s\n", aurora.Green(abs),
-		aurora.Red("edit on your risk!"))
+	fmt.Printf("Templates are generated in %s, %s\n", color.Green.Render(abs),
+		color.Red.Render("edit on your risk!"))
 
 	return nil
 }
@@ -116,7 +116,7 @@ func cleanTemplates(_ *cobra.Command, _ []string) error {
 		return err
 	}
 
-	fmt.Printf("%s\n", aurora.Green("templates are cleaned!"))
+	fmt.Printf("%s\n", color.Green.Render("templates are cleaned!"))
 	return nil
 }
 
@@ -131,7 +131,7 @@ func updateTemplates(_ *cobra.Command, _ []string) (err error) {
 
 	defer func() {
 		if err == nil {
-			fmt.Println(aurora.Green(fmt.Sprintf("%s template are update!", category)).String())
+			fmt.Println(color.Green.Sprintf("%s template are update!", category))
 		}
 	}()
 	switch category {
@@ -170,7 +170,7 @@ func revertTemplates(_ *cobra.Command, _ []string) (err error) {
 
 	defer func() {
 		if err == nil {
-			fmt.Println(aurora.Green(fmt.Sprintf("%s template are reverted!", filename)).String())
+			fmt.Println(color.Green.Sprintf("%s template are reverted!", filename))
 		}
 	}()
 	switch category {
diff --git a/tools/goctl/util/console/console.go b/tools/goctl/util/console/console.go
index 8e758583..9647d8f7 100644
--- a/tools/goctl/util/console/console.go
+++ b/tools/goctl/util/console/console.go
@@ -3,10 +3,8 @@ package console
 import (
 	"fmt"
 	"os"
-	"runtime"
 
-	"github.com/logrusorgru/aurora"
-	"github.com/zeromicro/go-zero/tools/goctl/vars"
+	"github.com/gookit/color"
 )
 
 type (
@@ -63,32 +61,28 @@ func (c *colorConsole) Debug(format string, a ...any) {
 	if !c.enable {
 		return
 	}
-	msg := fmt.Sprintf(format, a...)
-	println(aurora.BrightCyan(msg))
+	println(color.LightCyan.Sprintf(format, a...))
 }
 
 func (c *colorConsole) Success(format string, a ...any) {
 	if !c.enable {
 		return
 	}
-	msg := fmt.Sprintf(format, a...)
-	println(aurora.BrightGreen(msg))
+	println(color.LightGreen.Sprintf(format, a...))
 }
 
 func (c *colorConsole) Warning(format string, a ...any) {
 	if !c.enable {
 		return
 	}
-	msg := fmt.Sprintf(format, a...)
-	println(aurora.BrightYellow(msg))
+	println(color.LightYellow.Sprintf(format, a...))
 }
 
 func (c *colorConsole) Error(format string, a ...any) {
 	if !c.enable {
 		return
 	}
-	msg := fmt.Sprintf(format, a...)
-	println(aurora.BrightRed(msg))
+	println(color.LightRed.Sprintf(format, a...))
 }
 
 func (c *colorConsole) Fatalln(format string, a ...any) {
@@ -126,8 +120,7 @@ func (i *ideaConsole) Info(format string, a ...any) {
 }
 
 func (i *ideaConsole) Debug(format string, a ...any) {
-	msg := fmt.Sprintf(format, a...)
-	fmt.Println(aurora.BrightCyan(msg))
+	fmt.Println(color.LightCyan.Sprintf(format, a...))
 }
 
 func (i *ideaConsole) Success(format string, a ...any) {
@@ -161,17 +154,6 @@ func (i *ideaConsole) Must(err error) {
 }
 
 func println(msg any) {
-	value, ok := msg.(aurora.Value)
-	if !ok {
-		fmt.Println(msg)
-	}
-
-	goos := runtime.GOOS
-	if goos == vars.OsWindows {
-		fmt.Println(value.Value())
-		return
-	}
-
 	fmt.Println(msg)
 }
 
diff --git a/tools/goctl/util/pathx/file.go b/tools/goctl/util/pathx/file.go
index 5b1c62fc..3121a19f 100644
--- a/tools/goctl/util/pathx/file.go
+++ b/tools/goctl/util/pathx/file.go
@@ -6,13 +6,13 @@ import (
 	"encoding/hex"
 	"fmt"
 	"io"
-	"io/ioutil"
+	"io/fs"
 	"log"
 	"os"
 	"path/filepath"
 	"strings"
 
-	"github.com/logrusorgru/aurora"
+	"github.com/gookit/color"
 	"github.com/zeromicro/go-zero/tools/goctl/internal/version"
 )
 
@@ -58,7 +58,7 @@ func RemoveOrQuit(filename string) error {
 	}
 
 	fmt.Printf("%s exists, overwrite it?\nEnter to overwrite or Ctrl-C to cancel...",
-		aurora.BgRed(aurora.Bold(filename)))
+		color.New(color.BgRed, color.Bold).Render(filename))
 	bufio.NewReader(os.Stdin).ReadBytes('\n')
 
 	return os.Remove(filename)
@@ -145,9 +145,20 @@ 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)
-		fs, _ := ioutil.ReadDir(beforeTemplateDir)
+		entries, err := os.ReadDir(beforeTemplateDir)
+		if err != nil {
+			return "", err
+		}
+		infos := make([]fs.FileInfo, 0, len(entries))
+		for _, entry := range entries {
+			info, err := entry.Info()
+			if err != nil {
+				return "", err
+			}
+			infos = append(infos, info)
+		}
 		var hasContent bool
-		for _, e := range fs {
+		for _, e := range infos {
 			if e.Size() > 0 {
 				hasContent = true
 			}
@@ -256,7 +267,7 @@ func createTemplate(file, content string, force bool) error {
 
 // MustTempDir creates a temporary directory.
 func MustTempDir() string {
-	dir, err := ioutil.TempDir("", "")
+	dir, err := os.MkdirTemp("", "")
 	if err != nil {
 		log.Fatalln(err)
 	}
diff --git a/tools/goctl/util/templatex.go b/tools/goctl/util/templatex.go
index 981a6af6..726544c5 100644
--- a/tools/goctl/util/templatex.go
+++ b/tools/goctl/util/templatex.go
@@ -3,7 +3,7 @@ package util
 import (
 	"bytes"
 	goformat "go/format"
-	"io/ioutil"
+	"os"
 	"regexp"
 	"text/template"
 
@@ -50,7 +50,7 @@ func (t *DefaultTemplate) SaveTo(data any, path string, forceUpdate bool) error
 		return err
 	}
 
-	return ioutil.WriteFile(path, output.Bytes(), regularPerm)
+	return os.WriteFile(path, output.Bytes(), regularPerm)
 }
 
 // Execute returns the codes after the template executed
diff --git a/zrpc/client.go b/zrpc/client.go
index 06ff3671..b0ad08a4 100644
--- a/zrpc/client.go
+++ b/zrpc/client.go
@@ -11,8 +11,6 @@ import (
 	"google.golang.org/grpc/keepalive"
 )
 
-const defaultClientKeepaliveTime = 20 * time.Second
-
 var (
 	// WithDialOption is an alias of internal.WithDialOption.
 	WithDialOption = internal.WithDialOption
@@ -95,12 +93,6 @@ func NewClientWithTarget(target string, opts ...ClientOption) (Client, error) {
 		Timeout:    true,
 	}
 
-	opts = append([]ClientOption{
-		WithDialOption(grpc.WithKeepaliveParams(keepalive.ClientParameters{
-			Time: defaultClientKeepaliveTime,
-		})),
-	}, opts...)
-
 	return internal.NewClient(target, middlewares, opts...)
 }
 
diff --git a/zrpc/internal/client.go b/zrpc/internal/client.go
index 37de599a..0d01ae99 100644
--- a/zrpc/internal/client.go
+++ b/zrpc/internal/client.go
@@ -48,8 +48,7 @@ type (
 )
 
 // NewClient returns a Client.
-func NewClient(target string, middlewares ClientMiddlewaresConf,
-	opts ...ClientOption) (Client, error) {
+func NewClient(target string, middlewares ClientMiddlewaresConf, opts ...ClientOption) (Client, error) {
 	cli := client{
 		middlewares: middlewares,
 	}


Test patch:
diff --git a/core/logx/logtest/logtest.go b/core/logx/logtest/logtest.go
index 6e583840..27f817e6 100644
--- a/core/logx/logtest/logtest.go
+++ b/core/logx/logtest/logtest.go
@@ -46,7 +46,6 @@ func (b *Buffer) Bytes() []byte {
 func (b *Buffer) Content() string {
 	var m map[string]interface{}
 	if err := json.Unmarshal(b.buf.Bytes(), &m); err != nil {
-		b.t.Error(err)
 		return ""
 	}
 
@@ -59,12 +58,8 @@ func (b *Buffer) Content() string {
 	case string:
 		return val
 	default:
-		bs, err := json.Marshal(content)
-		if err != nil {
-			b.t.Error(err)
-			return ""
-		}
-
+		// err is impossible to be not nil, unmarshaled from b.buf.Bytes()
+		bs, _ := json.Marshal(content)
 		return string(bs)
 	}
 }
diff --git a/core/logx/logtest/logtest_test.go b/core/logx/logtest/logtest_test.go
index da7c3f79..9b0d55ac 100644
--- a/core/logx/logtest/logtest_test.go
+++ b/core/logx/logtest/logtest_test.go
@@ -14,6 +14,8 @@ func TestCollector(t *testing.T) {
 	logx.Info(input)
 	assert.Equal(t, input, c.Content())
 	assert.Contains(t, c.String(), input)
+	c.Reset()
+	assert.Empty(t, c.Bytes())
 }
 
 func TestPanicOnFatal(t *testing.T) {
@@ -21,8 +23,22 @@ func TestPanicOnFatal(t *testing.T) {
 	Discard(t)
 	logx.Info(input)
 
+	PanicOnFatal(t)
 	PanicOnFatal(t)
 	assert.Panics(t, func() {
 		logx.Must(errors.New("foo"))
 	})
 }
+
+func TestCollectorContent(t *testing.T) {
+	const input = "hello"
+	c := NewCollector(t)
+	c.buf.WriteString(input)
+	assert.Empty(t, c.Content())
+	c.Reset()
+	c.buf.WriteString(`{}`)
+	assert.Empty(t, c.Content())
+	c.Reset()
+	c.buf.WriteString(`{"content":1}`)
+	assert.Equal(t, "1", c.Content())
+}
diff --git a/core/logx/richlogger_test.go b/core/logx/richlogger_test.go
index b629c537..11f7dfcb 100644
--- a/core/logx/richlogger_test.go
+++ b/core/logx/richlogger_test.go
@@ -66,6 +66,9 @@ func TestTraceDebug(t *testing.T) {
 	l.WithDuration(time.Second).Debugv(testlog)
 	validate(t, w.String(), true, true)
 	w.Reset()
+	l.WithDuration(time.Second).Debugv(testobj)
+	validateContentType(t, w.String(), map[string]any{}, true, true)
+	w.Reset()
 	l.WithDuration(time.Second).Debugw(testlog, Field("foo", "bar"))
 	validate(t, w.String(), true, true)
 	assert.True(t, strings.Contains(w.String(), "foo"), w.String())
@@ -103,6 +106,9 @@ func TestTraceError(t *testing.T) {
 	l.WithDuration(time.Second).Errorv(testlog)
 	validate(t, w.String(), true, true)
 	w.Reset()
+	l.WithDuration(time.Second).Errorv(testobj)
+	validateContentType(t, w.String(), map[string]any{}, true, true)
+	w.Reset()
 	l.WithDuration(time.Second).Errorw(testlog, Field("basket", "ball"))
 	validate(t, w.String(), true, true)
 	assert.True(t, strings.Contains(w.String(), "basket"), w.String())
@@ -137,6 +143,9 @@ func TestTraceInfo(t *testing.T) {
 	l.WithDuration(time.Second).Infov(testlog)
 	validate(t, w.String(), true, true)
 	w.Reset()
+	l.WithDuration(time.Second).Infov(testobj)
+	validateContentType(t, w.String(), map[string]any{}, true, true)
+	w.Reset()
 	l.WithDuration(time.Second).Infow(testlog, Field("basket", "ball"))
 	validate(t, w.String(), true, true)
 	assert.True(t, strings.Contains(w.String(), "basket"), w.String())
@@ -173,6 +182,9 @@ func TestTraceInfoConsole(t *testing.T) {
 	w.Reset()
 	l.WithDuration(time.Second).Infov(testlog)
 	validate(t, w.String(), true, true)
+	w.Reset()
+	l.WithDuration(time.Second).Infov(testobj)
+	validateContentType(t, w.String(), map[string]any{}, true, true)
 }
 
 func TestTraceSlow(t *testing.T) {
@@ -204,6 +216,9 @@ func TestTraceSlow(t *testing.T) {
 	l.WithDuration(time.Second).Slowv(testlog)
 	validate(t, w.String(), true, true)
 	w.Reset()
+	l.WithDuration(time.Second).Slowv(testobj)
+	validateContentType(t, w.String(), map[string]any{}, true, true)
+	w.Reset()
 	l.WithDuration(time.Second).Sloww(testlog, Field("basket", "ball"))
 	validate(t, w.String(), true, true)
 	assert.True(t, strings.Contains(w.String(), "basket"), w.String())
@@ -311,8 +326,32 @@ func validate(t *testing.T, body string, expectedTrace, expectedSpan bool) {
 	assert.Equal(t, expectedSpan, len(val.Span) > 0, body)
 }
 
+func validateContentType(t *testing.T, body string, expectedType any, expectedTrace, expectedSpan bool) {
+	var val mockValue
+	dec := json.NewDecoder(strings.NewReader(body))
+
+	for {
+		var doc mockValue
+		err := dec.Decode(&doc)
+		if err == io.EOF {
+			// all done
+			break
+		}
+		if err != nil {
+			continue
+		}
+
+		val = doc
+	}
+
+	assert.IsType(t, expectedType, val.Content, body)
+	assert.Equal(t, expectedTrace, len(val.Trace) > 0, body)
+	assert.Equal(t, expectedSpan, len(val.Span) > 0, body)
+}
+
 type mockValue struct {
-	Trace string `json:"trace"`
-	Span  string `json:"span"`
-	Foo   string `json:"foo"`
+	Trace   string `json:"trace"`
+	Span    string `json:"span"`
+	Foo     string `json:"foo"`
+	Content any    `json:"content"`
 }
diff --git a/core/logx/syslog_test.go b/core/logx/syslog_test.go
index 8591f16c..eb6d757a 100644
--- a/core/logx/syslog_test.go
+++ b/core/logx/syslog_test.go
@@ -12,6 +12,8 @@ import (
 
 const testlog = "Stay hungry, stay foolish."
 
+var testobj = map[string]any{"foo": "bar"}
+
 func TestCollectSysLog(t *testing.T) {
 	CollectSysLog()
 	content := getContent(captureOutput(func() {
diff --git a/core/mr/mapreduce_test.go b/core/mr/mapreduce_test.go
index 00418cc8..60b1427c 100644
--- a/core/mr/mapreduce_test.go
+++ b/core/mr/mapreduce_test.go
@@ -3,7 +3,7 @@ package mr
 import (
 	"context"
 	"errors"
-	"io/ioutil"
+	"io"
 	"log"
 	"runtime"
 	"sync/atomic"
@@ -17,7 +17,7 @@ import (
 var errDummy = errors.New("dummy")
 
 func init() {
-	log.SetOutput(ioutil.Discard)
+	log.SetOutput(io.Discard)
 }
 
 func TestFinish(t *testing.T) {
diff --git a/core/rescue/recover_test.go b/core/rescue/recover_test.go
index fa4cd33c..07816054 100644
--- a/core/rescue/recover_test.go
+++ b/core/rescue/recover_test.go
@@ -1,6 +1,7 @@
 package rescue
 
 import (
+	"context"
 	"sync/atomic"
 	"testing"
 
@@ -25,3 +26,17 @@ func TestRescue(t *testing.T) {
 	})
 	assert.Equal(t, int32(5), atomic.LoadInt32(&count))
 }
+
+func TestRescueCtx(t *testing.T) {
+	var count int32
+	assert.NotPanics(t, func() {
+		defer RecoverCtx(context.Background(), func() {
+			atomic.AddInt32(&count, 2)
+		}, func() {
+			atomic.AddInt32(&count, 3)
+		})
+
+		panic("hello")
+	})
+	assert.Equal(t, int32(5), atomic.LoadInt32(&count))
+}
diff --git a/core/threading/routines_test.go b/core/threading/routines_test.go
index 6a12dca0..30a524ee 100644
--- a/core/threading/routines_test.go
+++ b/core/threading/routines_test.go
@@ -1,12 +1,15 @@
 package threading
 
 import (
+	"bytes"
+	"context"
 	"io"
 	"log"
 	"testing"
 
 	"github.com/stretchr/testify/assert"
 	"github.com/zeromicro/go-zero/core/lang"
+	"github.com/zeromicro/go-zero/core/logx"
 )
 
 func TestRoutineId(t *testing.T) {
@@ -34,3 +37,51 @@ func TestRunSafe(t *testing.T) {
 	<-ch
 	i++
 }
+
+func TestRunSafeCtx(t *testing.T) {
+	var buf bytes.Buffer
+	logx.SetWriter(logx.NewWriter(&buf))
+	ctx := context.Background()
+	ch := make(chan lang.PlaceholderType)
+
+	i := 0
+
+	defer func() {
+		assert.Equal(t, 1, i)
+	}()
+
+	go RunSafeCtx(ctx, func() {
+		defer func() {
+			ch <- lang.Placeholder
+		}()
+
+		panic("panic")
+	})
+
+	<-ch
+	i++
+}
+
+func TestGoSafeCtx(t *testing.T) {
+	var buf bytes.Buffer
+	logx.SetWriter(logx.NewWriter(&buf))
+	ctx := context.Background()
+	ch := make(chan lang.PlaceholderType)
+
+	i := 0
+
+	defer func() {
+		assert.Equal(t, 1, i)
+	}()
+
+	GoSafeCtx(ctx, func() {
+		defer func() {
+			ch <- lang.Placeholder
+		}()
+
+		panic("panic")
+	})
+
+	<-ch
+	i++
+}
diff --git a/core/trace/agent_test.go b/core/trace/agent_test.go
index 853fa6ba..a3871a42 100644
--- a/core/trace/agent_test.go
+++ b/core/trace/agent_test.go
@@ -36,14 +36,20 @@ func TestStartAgent(t *testing.T) {
 		Batcher:  "otlp",
 	}
 	c5 := Config{
-		Name:     "grpc",
+		Name:     "otlpgrpc",
 		Endpoint: endpoint3,
 		Batcher:  kindOtlpGrpc,
+		OtlpHeaders: map[string]string{
+			"uptrace-dsn": "http://project2_secret_token@localhost:14317/2",
+		},
 	}
 	c6 := Config{
 		Name:     "otlphttp",
 		Endpoint: endpoint4,
 		Batcher:  kindOtlpHttp,
+		OtlpHeaders: map[string]string{
+			"uptrace-dsn": "http://project2_secret_token@localhost:14318/2",
+		},
 	}
 	c7 := Config{
 		Name:     "UDP",
diff --git a/rest/handler/prometheushandler_test.go b/rest/handler/prometheushandler_test.go
index ce7551e8..c0c1dec2 100644
--- a/rest/handler/prometheushandler_test.go
+++ b/rest/handler/prometheushandler_test.go
@@ -10,7 +10,7 @@ import (
 )
 
 func TestPromMetricHandler_Disabled(t *testing.T) {
-	promMetricHandler := PrometheusHandler("/user/login")
+	promMetricHandler := PrometheusHandler("/user/login", http.MethodGet)
 	handler := promMetricHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 		w.WriteHeader(http.StatusOK)
 	}))
@@ -26,7 +26,7 @@ func TestPromMetricHandler_Enabled(t *testing.T) {
 		Host: "localhost",
 		Path: "/",
 	})
-	promMetricHandler := PrometheusHandler("/user/login")
+	promMetricHandler := PrometheusHandler("/user/login", http.MethodGet)
 	handler := promMetricHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 		w.WriteHeader(http.StatusOK)
 	}))
diff --git a/rest/handler/timeouthandler_test.go b/rest/handler/timeouthandler_test.go
index 3fd8bdd2..acbda030 100644
--- a/rest/handler/timeouthandler_test.go
+++ b/rest/handler/timeouthandler_test.go
@@ -164,6 +164,24 @@ func TestTimeoutHijack(t *testing.T) {
 	})
 }
 
+func TestTimeoutFlush(t *testing.T) {
+	timeoutHandler := TimeoutHandler(time.Minute)
+	handler := timeoutHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		flusher, ok := w.(http.Flusher)
+		if !ok {
+			http.Error(w, "Streaming unsupported!", http.StatusInternalServerError)
+			return
+		}
+
+		flusher.Flush()
+	}))
+
+	req := httptest.NewRequest(http.MethodGet, "http://localhost", http.NoBody)
+	resp := httptest.NewRecorder()
+	handler.ServeHTTP(resp, req)
+	assert.Equal(t, http.StatusOK, resp.Code)
+}
+
 func TestTimeoutPusher(t *testing.T) {
 	handler := &timeoutWriter{
 		w: mockedPusher{},
diff --git a/tools/goctl/api/format/format_test.go b/tools/goctl/api/format/format_test.go
index 786ac42b..da49bf1c 100644
--- a/tools/goctl/api/format/format_test.go
+++ b/tools/goctl/api/format/format_test.go
@@ -3,7 +3,6 @@ package format
 import (
 	"fmt"
 	"io/fs"
-	"io/ioutil"
 	"os"
 	"path"
 	"testing"
@@ -71,11 +70,11 @@ func Test_apiFormatReader_issue1721(t *testing.T) {
 	require.NoError(t, err)
 
 	importedFilename := path.Join(dir, "foo.api")
-	err = ioutil.WriteFile(importedFilename, []byte{}, fs.ModePerm)
+	err = os.WriteFile(importedFilename, []byte{}, fs.ModePerm)
 	require.NoError(t, err)
 
 	filename := path.Join(subDir, "bar.api")
-	err = ioutil.WriteFile(filename, []byte(fmt.Sprintf(`import "%s"`, importedFilename)), 0o644)
+	err = os.WriteFile(filename, []byte(fmt.Sprintf(`import "%s"`, importedFilename)), 0o644)
 	require.NoError(t, err)
 
 	f, err := os.Open(filename)
diff --git a/tools/goctl/api/parser/g4/ast/apiparser_test.go b/tools/goctl/api/parser/g4/ast/apiparser_test.go
index f873f397..71d73650 100644
--- a/tools/goctl/api/parser/g4/ast/apiparser_test.go
+++ b/tools/goctl/api/parser/g4/ast/apiparser_test.go
@@ -1,7 +1,6 @@
 package ast
 
 import (
-	"io/ioutil"
 	"os"
 	"path/filepath"
 	"testing"
@@ -25,13 +24,13 @@ func Test_ImportCycle(t *testing.T) {
 	defer os.RemoveAll(dir)
 
 	mainPath := filepath.Join(dir, mainFilename)
-	err = ioutil.WriteFile(mainPath, []byte(mainSrc), 0o777)
+	err = os.WriteFile(mainPath, []byte(mainSrc), 0o777)
 	require.NoError(t, err)
 	subAPath := filepath.Join(dir, subAFilename)
-	err = ioutil.WriteFile(subAPath, []byte(subASrc), 0o777)
+	err = os.WriteFile(subAPath, []byte(subASrc), 0o777)
 	require.NoError(t, err)
 	subBPath := filepath.Join(dir, subBFilename)
-	err = ioutil.WriteFile(subBPath, []byte(subBSrc), 0o777)
+	err = os.WriteFile(subBPath, []byte(subBSrc), 0o777)
 	require.NoError(t, err)
 
 	_, err = NewParser().Parse(mainPath)
@@ -55,13 +54,13 @@ func Test_MultiImportedShouldAllowed(t *testing.T) {
 	defer os.RemoveAll(dir)
 
 	mainPath := filepath.Join(dir, mainFilename)
-	err = ioutil.WriteFile(mainPath, []byte(mainSrc), 0o777)
+	err = os.WriteFile(mainPath, []byte(mainSrc), 0o777)
 	require.NoError(t, err)
 	subAPath := filepath.Join(dir, subAFilename)
-	err = ioutil.WriteFile(subAPath, []byte(subASrc), 0o777)
+	err = os.WriteFile(subAPath, []byte(subASrc), 0o777)
 	require.NoError(t, err)
 	subBPath := filepath.Join(dir, subBFilename)
-	err = ioutil.WriteFile(subBPath, []byte(subBSrc), 0o777)
+	err = os.WriteFile(subBPath, []byte(subBSrc), 0o777)
 	require.NoError(t, err)
 
 	_, err = NewParser().Parse(mainPath)
@@ -84,13 +83,13 @@ func Test_RedundantDeclarationShouldNotBeAllowed(t *testing.T) {
 	defer os.RemoveAll(dir)
 
 	mainPath := filepath.Join(dir, mainFilename)
-	err = ioutil.WriteFile(mainPath, []byte(mainSrc), 0o777)
+	err = os.WriteFile(mainPath, []byte(mainSrc), 0o777)
 	require.NoError(t, err)
 	subAPath := filepath.Join(dir, subAFilename)
-	err = ioutil.WriteFile(subAPath, []byte(subASrc), 0o777)
+	err = os.WriteFile(subAPath, []byte(subASrc), 0o777)
 	require.NoError(t, err)
 	subBPath := filepath.Join(dir, subBFilename)
-	err = ioutil.WriteFile(subBPath, []byte(subBSrc), 0o777)
+	err = os.WriteFile(subBPath, []byte(subBSrc), 0o777)
 	require.NoError(t, err)
 
 	_, err = NewParser().Parse(mainPath)
diff --git a/tools/goctl/api/parser/g4/test/apiparser_test.go b/tools/goctl/api/parser/g4/test/apiparser_test.go
index 764ef1fd..e00ba69a 100644
--- a/tools/goctl/api/parser/g4/test/apiparser_test.go
+++ b/tools/goctl/api/parser/g4/test/apiparser_test.go
@@ -2,7 +2,6 @@ package test
 
 import (
 	"fmt"
-	"io/ioutil"
 	"os"
 	"path/filepath"
 	"testing"
@@ -120,7 +119,7 @@ func TestApiParser(t *testing.T) {
 
 	t.Run("nestedImport", func(t *testing.T) {
 		file := filepath.Join(pathx.MustTempDir(), "foo.api")
-		err := ioutil.WriteFile(file, []byte(nestedAPIImport), os.ModePerm)
+		err := os.WriteFile(file, []byte(nestedAPIImport), os.ModePerm)
 		if err != nil {
 			return
 		}
@@ -150,7 +149,7 @@ func TestApiParser(t *testing.T) {
 
 	t.Run("ambiguousSyntax", func(t *testing.T) {
 		file := filepath.Join(pathx.MustTempDir(), "foo.api")
-		err := ioutil.WriteFile(file, []byte(ambiguousSyntax), os.ModePerm)
+		err := os.WriteFile(file, []byte(ambiguousSyntax), os.ModePerm)
 		if err != nil {
 			return
 		}
@@ -164,7 +163,7 @@ func TestApiParser(t *testing.T) {
 
 	t.Run("ambiguousSyntax", func(t *testing.T) {
 		file := filepath.Join(pathx.MustTempDir(), "foo.api")
-		err := ioutil.WriteFile(file, []byte(ambiguousSyntax), os.ModePerm)
+		err := os.WriteFile(file, []byte(ambiguousSyntax), os.ModePerm)
 		if err != nil {
 			return
 		}
@@ -178,7 +177,7 @@ func TestApiParser(t *testing.T) {
 
 	t.Run("ambiguousService", func(t *testing.T) {
 		file := filepath.Join(pathx.MustTempDir(), "foo.api")
-		err := ioutil.WriteFile(file, []byte(ambiguousService), os.ModePerm)
+		err := os.WriteFile(file, []byte(ambiguousService), os.ModePerm)
 		if err != nil {
 			return
 		}
@@ -208,7 +207,7 @@ func TestApiParser(t *testing.T) {
 		assert.Error(t, err)
 
 		file := filepath.Join(pathx.MustTempDir(), "foo.api")
-		err = ioutil.WriteFile(file, []byte(duplicateHandler), os.ModePerm)
+		err = os.WriteFile(file, []byte(duplicateHandler), os.ModePerm)
 		if err != nil {
 			return
 		}
@@ -237,7 +236,7 @@ func TestApiParser(t *testing.T) {
 		assert.Error(t, err)
 
 		file := filepath.Join(pathx.MustTempDir(), "foo.api")
-		err = ioutil.WriteFile(file, []byte(duplicateRoute), os.ModePerm)
+		err = os.WriteFile(file, []byte(duplicateRoute), os.ModePerm)
 		if err != nil {
 			return
 		}
@@ -261,7 +260,7 @@ func TestApiParser(t *testing.T) {
 		assert.Error(t, err)
 
 		file := filepath.Join(pathx.MustTempDir(), "foo.api")
-		err = ioutil.WriteFile(file, []byte(duplicateType), os.ModePerm)
+		err = os.WriteFile(file, []byte(duplicateType), os.ModePerm)
 		if err != nil {
 			return
 		}
diff --git a/tools/goctl/compare/testdata/testdata.go b/tools/goctl/compare/testdata/testdata.go
index b2092641..c11b3d0a 100644
--- a/tools/goctl/compare/testdata/testdata.go
+++ b/tools/goctl/compare/testdata/testdata.go
@@ -2,14 +2,13 @@ package testdata
 
 import (
 	"fmt"
-	"io/ioutil"
 	"log"
 	"os"
 	"os/exec"
 	"path/filepath"
 	"strings"
 
-	"github.com/logrusorgru/aurora"
+	"github.com/gookit/color"
 	"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
 )
 
@@ -34,7 +33,7 @@ func (f File) execute(goctl string) error {
 	}
 	printCommand := strings.ReplaceAll(fmt.Sprintf("cd %s && %s", printDir, f.Cmd), "goctl", filepath.Base(goctl))
 	command := strings.ReplaceAll(fmt.Sprintf("cd %s && %s", dir, f.Cmd), "goctl", goctl)
-	fmt.Println(aurora.BrightGreen(printCommand))
+	fmt.Println(color.LightGreen.Render(printCommand))
 	cmd := exec.Command("sh", "-c", command)
 	cmd.Env = os.Environ()
 	cmd.Stdout = os.Stdout
@@ -78,7 +77,7 @@ func mustGetTestData(baseDir string) (Files, Files) {
 			return data, nil
 		}
 
-		return data, ioutil.WriteFile(fp, []byte(data.Content), os.ModePerm)
+		return data, os.WriteFile(fp, []byte(data.Content), os.ModePerm)
 	}
 	oldDir := filepath.Join(baseDir, "old_fs")
 	newDir := filepath.Join(baseDir, "new_fs")
@@ -106,10 +105,10 @@ func MustRun(baseDir string) {
 	must(err)
 	goctlNew, err := exec.LookPath("goctl")
 	must(err)
-	fmt.Println(aurora.BrightBlue("========================goctl.old======================="))
+	fmt.Println(color.LightBlue.Render("========================goctl.old======================="))
 	must(oldFiles.execute(goctlOld))
 	fmt.Println()
-	fmt.Println(aurora.BrightBlue("========================goctl.new======================="))
+	fmt.Println(color.LightBlue.Render("========================goctl.new======================="))
 	must(newFiles.execute(goctlNew))
 }
 
diff --git a/tools/goctl/model/mongo/generate/generate_test.go b/tools/goctl/model/mongo/generate/generate_test.go
index 3586b60a..2ea6c758 100644
--- a/tools/goctl/model/mongo/generate/generate_test.go
+++ b/tools/goctl/model/mongo/generate/generate_test.go
@@ -1,7 +1,7 @@
 package generate
 
 import (
-	"io/ioutil"
+	"os"
 	"path/filepath"
 	"testing"
 
@@ -22,7 +22,7 @@ func TestDo(t *testing.T) {
 
 		tempDir := pathx.MustTempDir()
 		typesfile := filepath.Join(tempDir, "types.go")
-		err = ioutil.WriteFile(typesfile, []byte(testTypes), 0o666)
+		err = os.WriteFile(typesfile, []byte(testTypes), 0o666)
 		assert.Nil(t, err)
 
 		err = Do(&Context{
@@ -38,7 +38,7 @@ func TestDo(t *testing.T) {
 	t.Run("missing config", func(t *testing.T) {
 		tempDir := t.TempDir()
 		typesfile := filepath.Join(tempDir, "types.go")
-		err := ioutil.WriteFile(typesfile, []byte(testTypes), 0o666)
+		err := os.WriteFile(typesfile, []byte(testTypes), 0o666)
 		assert.Nil(t, err)
 
 		err = Do(&Context{
@@ -54,7 +54,7 @@ func TestDo(t *testing.T) {
 		cfg := &config.Config{NamingFormat: "foo"}
 		tempDir := t.TempDir()
 		typesfile := filepath.Join(tempDir, "types.go")
-		err := ioutil.WriteFile(typesfile, []byte(testTypes), 0o666)
+		err := os.WriteFile(typesfile, []byte(testTypes), 0o666)
 		assert.Nil(t, err)
 
 		err = Do(&Context{
diff --git a/tools/goctl/model/sql/command/command_test.go b/tools/goctl/model/sql/command/command_test.go
index 330a6630..fa85e6e8 100644
--- a/tools/goctl/model/sql/command/command_test.go
+++ b/tools/goctl/model/sql/command/command_test.go
@@ -2,7 +2,6 @@ package command
 
 import (
 	_ "embed"
-	"io/ioutil"
 	"os"
 	"path/filepath"
 	"sort"
@@ -76,12 +75,12 @@ func TestFromDDl(t *testing.T) {
 	user1Sql := filepath.Join(tempDir, "user1.sql")
 	user2Sql := filepath.Join(tempDir, "user2.sql")
 
-	err = ioutil.WriteFile(user1Sql, []byte(sql), os.ModePerm)
+	err = os.WriteFile(user1Sql, []byte(sql), os.ModePerm)
 	if err != nil {
 		return
 	}
 
-	err = ioutil.WriteFile(user2Sql, []byte(sql), os.ModePerm)
+	err = os.WriteFile(user2Sql, []byte(sql), os.ModePerm)
 	if err != nil {
 		return
 	}
diff --git a/tools/goctl/model/sql/command/migrationnotes/v1.3.4_test.go b/tools/goctl/model/sql/command/migrationnotes/v1.3.4_test.go
index 4d77bbfc..80642833 100644
--- a/tools/goctl/model/sql/command/migrationnotes/v1.3.4_test.go
+++ b/tools/goctl/model/sql/command/migrationnotes/v1.3.4_test.go
@@ -2,7 +2,6 @@ package migrationnotes
 
 import (
 	"io/fs"
-	"io/ioutil"
 	"os"
 	"path"
 	"path/filepath"
@@ -18,15 +17,15 @@ func Test_needShow1_3_4(t *testing.T) {
 
 	dir1 := path.Join(root, "dir1")
 	require.NoError(t, os.Mkdir(dir1, fs.ModePerm))
-	ioutil.WriteFile(filepath.Join(dir1, "foo_gen.go"), nil, fs.ModePerm)
+	os.WriteFile(filepath.Join(dir1, "foo_gen.go"), nil, fs.ModePerm)
 
 	dir2 := path.Join(root, "dir2")
 	require.NoError(t, os.Mkdir(dir2, fs.ModePerm))
-	ioutil.WriteFile(filepath.Join(dir2, "foomodel.go"), nil, fs.ModePerm)
+	os.WriteFile(filepath.Join(dir2, "foomodel.go"), nil, fs.ModePerm)
 
 	dir3 := path.Join(root, "dir3")
 	require.NoError(t, os.Mkdir(dir3, fs.ModePerm))
-	ioutil.WriteFile(filepath.Join(dir3, "irrelevant.go"), nil, fs.ModePerm)
+	os.WriteFile(filepath.Join(dir3, "irrelevant.go"), nil, fs.ModePerm)
 
 	type args struct {
 		dir   string
diff --git a/tools/goctl/model/sql/gen/gen_test.go b/tools/goctl/model/sql/gen/gen_test.go
index 48d1060d..676e044c 100644
--- a/tools/goctl/model/sql/gen/gen_test.go
+++ b/tools/goctl/model/sql/gen/gen_test.go
@@ -3,7 +3,6 @@ package gen
 import (
 	"database/sql"
 	_ "embed"
-	"io/ioutil"
 	"os"
 	"path"
 	"path/filepath"
@@ -30,7 +29,7 @@ func TestCacheModel(t *testing.T) {
 	_ = Clean()
 
 	sqlFile := filepath.Join(pathx.MustTempDir(), "tmp.sql")
-	err := ioutil.WriteFile(sqlFile, []byte(source), 0o777)
+	err := os.WriteFile(sqlFile, []byte(source), 0o777)
 	assert.Nil(t, err)
 
 	dir := filepath.Join(pathx.MustTempDir(), "./testmodel")
@@ -65,7 +64,7 @@ func TestNamingModel(t *testing.T) {
 	_ = Clean()
 
 	sqlFile := filepath.Join(pathx.MustTempDir(), "tmp.sql")
-	err := ioutil.WriteFile(sqlFile, []byte(source), 0o777)
+	err := os.WriteFile(sqlFile, []byte(source), 0o777)
 	assert.Nil(t, err)
 
 	dir, _ := filepath.Abs("./testmodel")
@@ -103,7 +102,7 @@ func TestFolderName(t *testing.T) {
 	_ = Clean()
 
 	sqlFile := filepath.Join(pathx.MustTempDir(), "tmp.sql")
-	err := ioutil.WriteFile(sqlFile, []byte(source), 0o777)
+	err := os.WriteFile(sqlFile, []byte(source), 0o777)
 	assert.Nil(t, err)
 
 	dir, _ := filepath.Abs("./testmodel")
@@ -179,7 +178,7 @@ func Test_genPublicModel(t *testing.T) {
 	defer os.RemoveAll(dir)
 
 	modelFilename := filepath.Join(modelDir, "foo.sql")
-	err = ioutil.WriteFile(modelFilename, []byte(source), 0o777)
+	err = os.WriteFile(modelFilename, []byte(source), 0o777)
 	require.NoError(t, err)
 
 	g, err := NewDefaultGenerator(modelDir, &config.Config{
diff --git a/tools/goctl/model/sql/parser/parser_test.go b/tools/goctl/model/sql/parser/parser_test.go
index 0d205287..3f67a81d 100644
--- a/tools/goctl/model/sql/parser/parser_test.go
+++ b/tools/goctl/model/sql/parser/parser_test.go
@@ -2,7 +2,7 @@ package parser
 
 import (
 	_ "embed"
-	"io/ioutil"
+	"os"
 	"path/filepath"
 	"testing"
 
@@ -15,7 +15,7 @@ import (
 
 func TestParsePlainText(t *testing.T) {
 	sqlFile := filepath.Join(pathx.MustTempDir(), "tmp.sql")
-	err := ioutil.WriteFile(sqlFile, []byte("plain text"), 0o777)
+	err := os.WriteFile(sqlFile, []byte("plain text"), 0o777)
 	assert.Nil(t, err)
 
 	_, err = Parse(sqlFile, "go_zero", false)
@@ -24,7 +24,7 @@ func TestParsePlainText(t *testing.T) {
 
 func TestParseSelect(t *testing.T) {
 	sqlFile := filepath.Join(pathx.MustTempDir(), "tmp.sql")
-	err := ioutil.WriteFile(sqlFile, []byte("select * from user"), 0o777)
+	err := os.WriteFile(sqlFile, []byte("select * from user"), 0o777)
 	assert.Nil(t, err)
 
 	tables, err := Parse(sqlFile, "go_zero", false)
@@ -37,7 +37,7 @@ var user string
 
 func TestParseCreateTable(t *testing.T) {
 	sqlFile := filepath.Join(pathx.MustTempDir(), "tmp.sql")
-	err := ioutil.WriteFile(sqlFile, []byte(user), 0o777)
+	err := os.WriteFile(sqlFile, []byte(user), 0o777)
 	assert.Nil(t, err)
 
 	tables, err := Parse(sqlFile, "go_zero", false)
diff --git a/tools/goctl/pkg/parser/api/parser/analyzer_test.go b/tools/goctl/pkg/parser/api/parser/analyzer_test.go
index 28266f32..de4193b6 100644
--- a/tools/goctl/pkg/parser/api/parser/analyzer_test.go
+++ b/tools/goctl/pkg/parser/api/parser/analyzer_test.go
@@ -3,7 +3,7 @@ package parser
 import (
 	"bytes"
 	"fmt"
-	"io/ioutil"
+	"os"
 	"path/filepath"
 	"strings"
 	"testing"
@@ -18,7 +18,7 @@ func Test_Parse(t *testing.T) {
 		assert.Nil(t, err)
 	})
 	t.Run("invalid", func(t *testing.T) {
-		data, err := ioutil.ReadFile("./testdata/invalid.api")
+		data, err := os.ReadFile("./testdata/invalid.api")
 		assert.NoError(t, err)
 		splits := bytes.Split(data, []byte("-----"))
 		var testFile []string
@@ -29,7 +29,7 @@ func Test_Parse(t *testing.T) {
 				continue
 			}
 			filename := filepath.Join(t.TempDir(), fmt.Sprintf("invalid%d.api", idx))
-			err := ioutil.WriteFile(filename, split, 0666)
+			err := os.WriteFile(filename, split, 0666)
 			assert.NoError(t, err)
 			testFile = append(testFile, filename)
 		}
diff --git a/tools/goctl/rpc/generator/genpb_test.go b/tools/goctl/rpc/generator/genpb_test.go
index 04f7fcf8..9ed939a4 100644
--- a/tools/goctl/rpc/generator/genpb_test.go
+++ b/tools/goctl/rpc/generator/genpb_test.go
@@ -1,7 +1,6 @@
 package generator
 
 import (
-	"io/ioutil"
 	"os"
 	"os/exec"
 	"path/filepath"
@@ -14,7 +13,7 @@ import (
 func Test_findPbFile(t *testing.T) {
 	dir := t.TempDir()
 	protoFile := filepath.Join(dir, "greet.proto")
-	err := ioutil.WriteFile(protoFile, []byte(`
+	err := os.WriteFile(protoFile, []byte(`
 syntax = "proto3";
 
 package greet;
diff --git a/tools/goctl/util/pathx/file_test.go b/tools/goctl/util/pathx/file_test.go
index 7505fe49..99833e39 100644
--- a/tools/goctl/util/pathx/file_test.go
+++ b/tools/goctl/util/pathx/file_test.go
@@ -1,7 +1,6 @@
 package pathx
 
 import (
-	"io/ioutil"
 	"os"
 	"path/filepath"
 	"testing"
@@ -23,7 +22,7 @@ func TestGetTemplateDir(t *testing.T) {
 			return
 		}
 		tempFile := filepath.Join(dir, "bar.txt")
-		err = ioutil.WriteFile(tempFile, []byte("foo"), os.ModePerm)
+		err = os.WriteFile(tempFile, []byte("foo"), os.ModePerm)
 		if err != nil {
 			return
 		}
@@ -79,7 +78,7 @@ func TestGetGoctlHome(t *testing.T) {
 	t.Run("goctl_is_file", func(t *testing.T) {
 		tmpFile := filepath.Join(t.TempDir(), "a.tmp")
 		backupTempFile := tmpFile + ".old"
-		err := ioutil.WriteFile(tmpFile, nil, 0o666)
+		err := os.WriteFile(tmpFile, nil, 0o666)
 		if err != nil {
 			return
 		}
diff --git a/tools/goctl/util/pathx/path_test.go b/tools/goctl/util/pathx/path_test.go
index 67b5a4b5..0b7c2a82 100644
--- a/tools/goctl/util/pathx/path_test.go
+++ b/tools/goctl/util/pathx/path_test.go
@@ -1,7 +1,6 @@
 package pathx
 
 import (
-	"io/ioutil"
 	"os"
 	"path/filepath"
 	"testing"
@@ -10,9 +9,9 @@ import (
 )
 
 func TestReadLink(t *testing.T) {
-	dir, err := ioutil.TempDir("", "go-zero")
+	dir, err := os.CreateTemp("", "go-zero")
 	assert.Nil(t, err)
-	symLink := filepath.Join(dir, "test")
+	symLink := filepath.Join(dir.Name(), "test")
 	pwd, err := os.Getwd()
 	assertError(err, t)