Repository: cloudwego/hertz
Pull request #356 (2022-11-08 13:19:28)

feat: distinguish between global and local transporter
#### What type of PR is this?
feat

#### Check the PR title.
- [x] This PR title match the format: \<type\>(optional scope): \<description\>
- [x] The description of this PR title is user-oriented and clear enough for others to understand.


#### (Optional) Translate the PR title into Chinese.
server 区分局部和全局 transporter

#### (Optional) More detail description for this PR(en: English/zh: Chinese).
<!--
Provide more detailed info for review. If it is a perf type PR, perf data is suggested to give.
-->
en: change transporter of the hertz instance with option will not effect global transporter, vice versa. Avoid potential problems affecting other instances by modifying the transporter.
zh(optional): 修改 hertz 实例的 transporter 不会影响全局默认的 transporter，反之亦然；避免潜在的因为修改 transporter 导致影响到其他实例的问题。

#### Which issue(s) this PR fixes:
None

codecov[bot]: # [Codecov](https://codecov.io/gh/cloudwego/hertz/pull/356?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudwego) Report
Base: **66.12**% // Head: **66.59**% // Increases project coverage by **`+0.46%`** :tada:
> Coverage data is based on head [(`dc02486`)](https://codecov.io/gh/cloudwego/hertz/pull/356?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudwego) compared to base [(`7f8d710`)](https://codecov.io/gh/cloudwego/hertz/commit/7f8d710cd0543ccd6dc342cea6089ee992a53329?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudwego).
> Patch coverage: 75.00% of modified lines in pull request are covered.

> :exclamation: Current head dc02486 differs from pull request most recent head ec8ee2c. Consider uploading reports for the commit ec8ee2c to get more accurate results

<details><summary>Additional details and impacted files</summary>


```diff
@@             Coverage Diff             @@
##           develop     #356      +/-   ##
===========================================
+ Coverage    66.12%   66.59%   +0.46%     
===========================================
  Files           85       89       +4     
  Lines         8319     8507     +188     
===========================================
+ Hits          5501     5665     +164     
- Misses        2460     2480      +20     
- Partials       358      362       +4     
```


| [Impacted Files](https://codecov.io/gh/cloudwego/hertz/pull/356?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudwego) | Coverage Δ | |
|---|---|---|
| [pkg/common/config/option.go](https://codecov.io/gh/cloudwego/hertz/pull/356/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudwego#diff-cGtnL2NvbW1vbi9jb25maWcvb3B0aW9uLmdv) | `100.00% <ø> (ø)` | |
| [pkg/route/engine.go](https://codecov.io/gh/cloudwego/hertz/pull/356/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudwego#diff-cGtnL3JvdXRlL2VuZ2luZS5nbw==) | `62.63% <71.42%> (+0.57%)` | :arrow_up: |
| [pkg/app/server/option.go](https://codecov.io/gh/cloudwego/hertz/pull/356/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudwego#diff-cGtnL2FwcC9zZXJ2ZXIvb3B0aW9uLmdv) | `96.63% <100.00%> (ø)` | |
| [pkg/common/hlog/log.go](https://codecov.io/gh/cloudwego/hertz/pull/356/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudwego#diff-cGtnL2NvbW1vbi9obG9nL2xvZy5nbw==) | `100.00% <0.00%> (ø)` | |
| [pkg/common/hlog/system.go](https://codecov.io/gh/cloudwego/hertz/pull/356/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudwego#diff-cGtnL2NvbW1vbi9obG9nL3N5c3RlbS5nbw==) | `85.96% <0.00%> (ø)` | |
| [pkg/common/hlog/default.go](https://codecov.io/gh/cloudwego/hertz/pull/356/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudwego#diff-cGtnL2NvbW1vbi9obG9nL2RlZmF1bHQuZ28=) | `83.83% <0.00%> (ø)` | |
| [pkg/common/hlog/hlog.go](https://codecov.io/gh/cloudwego/hertz/pull/356/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudwego#diff-cGtnL2NvbW1vbi9obG9nL2hsb2cuZ28=) | `80.00% <0.00%> (ø)` | |
| [pkg/route/tree.go](https://codecov.io/gh/cloudwego/hertz/pull/356/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudwego#diff-cGtnL3JvdXRlL3RyZWUuZ28=) | `96.68% <0.00%> (+0.01%)` | :arrow_up: |
| [pkg/common/compress/compress.go](https://codecov.io/gh/cloudwego/hertz/pull/356/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudwego#diff-cGtnL2NvbW1vbi9jb21wcmVzcy9jb21wcmVzcy5nbw==) | `83.80% <0.00%> (+4.76%)` | :arrow_up: |

Help us with your feedback. Take ten seconds to tell us [how you rate us](https://about.codecov.io/nps?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudwego). Have a feature suggestion? [Share it here.](https://app.codecov.io/gh/feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudwego)

</details>

[:umbrella: View full report at Codecov](https://codecov.io/gh/cloudwego/hertz/pull/356?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudwego).   
:loudspeaker: Do you have feedback about the report comment? [Let us know in this issue](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudwego).


Patch:
diff --git a/pkg/app/server/option.go b/pkg/app/server/option.go
index fc913e4..9447734 100644
--- a/pkg/app/server/option.go
+++ b/pkg/app/server/option.go
@@ -27,7 +27,6 @@ import (
 	"github.com/cloudwego/hertz/pkg/common/tracer/stats"
 	"github.com/cloudwego/hertz/pkg/network"
 	"github.com/cloudwego/hertz/pkg/network/standard"
-	"github.com/cloudwego/hertz/pkg/route"
 )
 
 // WithKeepAliveTimeout sets keep-alive timeout.
@@ -216,7 +215,7 @@ func WithExitWaitTime(timeout time.Duration) config.Option {
 // NOTE: If a tls server is started, it won't accept non-tls request.
 func WithTLS(cfg *tls.Config) config.Option {
 	return config.Option{F: func(o *config.Options) {
-		route.SetTransporter(standard.NewTransporter)
+		o.TransporterNewer = standard.NewTransporter
 		o.TLS = cfg
 	}}
 }
@@ -231,7 +230,7 @@ func WithListenConfig(l *net.ListenConfig) config.Option {
 // WithTransport sets which network library to use.
 func WithTransport(transporter func(options *config.Options) network.Transporter) config.Option {
 	return config.Option{F: func(o *config.Options) {
-		route.SetTransporter(transporter)
+		o.TransporterNewer = transporter
 	}}
 }
 
diff --git a/pkg/common/config/option.go b/pkg/common/config/option.go
index cd69716..15037f0 100644
--- a/pkg/common/config/option.go
+++ b/pkg/common/config/option.go
@@ -22,6 +22,7 @@ import (
 	"time"
 
 	"github.com/cloudwego/hertz/pkg/app/server/registry"
+	"github.com/cloudwego/hertz/pkg/network"
 )
 
 // Option is the only struct that can be used to set Options.
@@ -68,11 +69,15 @@ type Options struct {
 	TraceLevel                   interface{}
 	ListenConfig                 *net.ListenConfig
 
+	// TransporterNewer is the function to create a transporter.
+	TransporterNewer func(opt *Options) network.Transporter
+
 	// Registry is used for service registry.
 	Registry registry.Registry
 	// RegistryInfo is base info used for service registry.
 	RegistryInfo *registry.Info
 	// Enable automatically HTML template reloading mechanism.
+
 	AutoReloadRender bool
 	// If AutoReloadInterval is set to 0(default).
 	// The HTML template will reload according to files' changing event
diff --git a/pkg/route/engine.go b/pkg/route/engine.go
index 45ae38f..8a272a8 100644
--- a/pkg/route/engine.go
+++ b/pkg/route/engine.go
@@ -76,6 +76,8 @@ import (
 	"github.com/cloudwego/hertz/pkg/protocol/suite"
 )
 
+const unknownTransporterName = "unknown"
+
 var (
 	defaultTransporter = standard.NewTransporter
 
@@ -199,15 +201,35 @@ func (engine *Engine) GetOptions() *config.Options {
 	return engine.options
 }
 
+// SetTransporter only sets the global default value for the transporter.
+// Use WithTransporter during engine creation to set the transporter for the engine.
 func SetTransporter(transporter func(options *config.Options) network.Transporter) {
 	defaultTransporter = transporter
 }
 
+func (engine *Engine) GetTransporterName() (tName string) {
+	return getTransporterName(engine.transport)
+}
+
+func getTransporterName(transporter network.Transporter) (tName string) {
+	defer func() {
+		err := recover()
+		if err != nil || tName == "" {
+			tName = unknownTransporterName
+		}
+	}()
+	t := reflect.ValueOf(transporter).Type().String()
+	tName = strings.Split(strings.TrimPrefix(t, "*"), ".")[0]
+	return tName
+}
+
+// Deprecated: This only get the global default transporter - may not be the real one used by the engine.
+// Use engine.GetTransporterName for the real transporter used.
 func GetTransporterName() (tName string) {
 	defer func() {
 		err := recover()
-		if err != nil {
-			tName = "unknown"
+		if err != nil || tName == "" {
+			tName = unknownTransporterName
 		}
 	}()
 	fName := runtime.FuncForPC(reflect.ValueOf(defaultTransporter).Pointer()).Name()
@@ -363,7 +385,7 @@ func (engine *Engine) alpnEnable() bool {
 }
 
 func (engine *Engine) listenAndServe() error {
-	hlog.SystemLogger().Infof("Using network library=%s", GetTransporterName())
+	hlog.SystemLogger().Infof("Using network library=%s", engine.GetTransporterName())
 	return engine.transport.ListenAndServe(engine.onData)
 }
 
@@ -520,6 +542,9 @@ func NewEngine(opt *config.Options) *Engine {
 		enableTrace:     true,
 		options:         opt,
 	}
+	if opt.TransporterNewer != nil {
+		engine.transport = opt.TransporterNewer(opt)
+	}
 	engine.RouterGroup.engine = engine
 
 	traceLevel := initTrace(engine)


Test patch:
diff --git a/pkg/route/engine_test.go b/pkg/route/engine_test.go
index 9b99180..f3007ac 100644
--- a/pkg/route/engine_test.go
+++ b/pkg/route/engine_test.go
@@ -64,13 +64,33 @@ import (
 )
 
 func TestNew_Engine(t *testing.T) {
+	defaultTransporter = standard.NewTransporter
 	opt := config.NewOptions([]config.Option{})
 	router := NewEngine(opt)
+	assert.DeepEqual(t, "standard", router.GetTransporterName())
 	assert.DeepEqual(t, "/", router.basePath)
 	assert.DeepEqual(t, router.engine, router)
 	assert.DeepEqual(t, 0, len(router.Handlers))
 }
 
+func TestNew_Engine_WithTransporter(t *testing.T) {
+	defaultTransporter = netpoll.NewTransporter
+	opt := config.NewOptions([]config.Option{})
+	router := NewEngine(opt)
+	assert.DeepEqual(t, "netpoll", router.GetTransporterName())
+
+	defaultTransporter = netpoll.NewTransporter
+	opt.TransporterNewer = standard.NewTransporter
+	router = NewEngine(opt)
+	assert.DeepEqual(t, "standard", router.GetTransporterName())
+	assert.DeepEqual(t, "netpoll", GetTransporterName())
+}
+
+func TestGetTransporterName(t *testing.T) {
+	name := getTransporterName(&fakeTransporter{})
+	assert.DeepEqual(t, "route", name)
+}
+
 func TestEngineUnescape(t *testing.T) {
 	e := NewEngine(config.NewOptions(nil))
 
@@ -524,3 +544,20 @@ func (m *mockConn) WriteBinary(b []byte) (n int, err error) {
 func (m *mockConn) Flush() error {
 	panic("implement me")
 }
+
+type fakeTransporter struct{}
+
+func (f *fakeTransporter) Close() error {
+	// TODO implement me
+	panic("implement me")
+}
+
+func (f *fakeTransporter) Shutdown(ctx context.Context) error {
+	// TODO implement me
+	panic("implement me")
+}
+
+func (f *fakeTransporter) ListenAndServe(onData network.OnData) error {
+	// TODO implement me
+	panic("implement me")
+}