Repository: nacos-group/nacos-sdk-go (go)

Issue:
Create multiple clients and the logger will be overwritten
Create multiple clients, each with a different logging parameter, and the global logger takes effect with the last client setting。

We need to discuss whether it is better to set up the global logger only once, or if each client has a different logger？

```
func InitLogger(config Config) (err error) {
	logLevel := getLogLevel(config.Level)
	encoder := getEncoder()
	writer, err := getWriter(config.OutputPath, config.RotationTime, config.MaxAge)
	if err != nil {
		return
	}
	core := zapcore.NewCore(zapcore.NewConsoleEncoder(encoder), zapcore.AddSync(writer), logLevel)
	zaplogger := zap.New(core, zap.AddCallerSkip(1))
	logger = &NacosLogger{zaplogger.Sugar()}
	return
}
```

Pull request:
fix the logger data race
fix logger data race 


Fixes #148 
@sanxun0325 

Patch:
diff --git a/README.md b/README.md
index 6f10315..900f255 100644
--- a/README.md
+++ b/README.md
@@ -72,7 +72,7 @@ clientConfig := constant.ClientConfig{
 	LogLevel:            "debug",
 }
 //Another way of create clientConfig
-clientConfig := constant.NewClientConfig(
+clientConfig := *constant.NewClientConfig(
     constant.WithNamespaceId("e525eafa-f7d7-4029-83d9-008937f9d468"),
     constant.WithTimeoutMs(5000),
     constant.WithNotLoadCacheAtStart(true),
@@ -114,18 +114,33 @@ serverConfigs := []constant.ServerConfig{
     ),
 }
 
-
 // Create naming client for service discovery
-namingClient, err := clients.CreateNamingClient(map[string]interface{}{
+_, _ := clients.CreateNamingClient(map[string]interface{}{
 	"serverConfigs": serverConfigs,
 	"clientConfig":  clientConfig,
 })
 
 // Create config client for dynamic configuration
-configClient, err := clients.CreateConfigClient(map[string]interface{}{
+_, _ := clients.CreateConfigClient(map[string]interface{}{
 	"serverConfigs": serverConfigs,
 	"clientConfig":  clientConfig,
 })
+
+// Another way of create naming client for service discovery (recommend)
+namingClient, err := clients.NewNamingClient(
+    vo.NacosClientParam{
+        ClientConfig:  &clientConfig,
+        ServerConfigs: serverConfigs,
+    },
+)
+
+// Another way of create config client for dynamic configuration (recommend)
+configClient, err := clients.NewConfigClient(
+    vo.NacosClientParam{
+        ClientConfig:  &clientConfig,
+        ServerConfigs: serverConfigs,
+    },
+)
     
 ```
 
diff --git a/README_CN.md b/README_CN.md
index d5673f1..0eb71c5 100644
--- a/README_CN.md
+++ b/README_CN.md
@@ -73,7 +73,7 @@ clientConfig := constant.ClientConfig{
 } 
 
 //创建clientConfig的另一种方式
-clientConfig := constant.NewClientConfig(
+clientConfig := *constant.NewClientConfig(
     constant.WithNamespaceId("e525eafa-f7d7-4029-83d9-008937f9d468"),
     constant.WithTimeoutMs(5000),
     constant.WithNotLoadCacheAtStart(true),
@@ -117,17 +117,32 @@ serverConfigs := []constant.ServerConfig{
 }
 
 // 创建服务发现客户端
-namingClient, err := clients.CreateNamingClient(map[string]interface{}{
+_, _ := clients.CreateNamingClient(map[string]interface{}{
 	"serverConfigs": serverConfigs,
 	"clientConfig":  clientConfig,
 })
 
 // 创建动态配置客户端
-configClient, err := clients.CreateConfigClient(map[string]interface{}{
+_, _ := clients.CreateConfigClient(map[string]interface{}{
 	"serverConfigs": serverConfigs,
 	"clientConfig":  clientConfig,
 })
-    
+
+// 创建服务发现客户端的另一种方式 (推荐)
+namingClient, err := clients.NewNamingClient(
+    vo.NacosClientParam{
+        ClientConfig:  &clientConfig,
+        ServerConfigs: serverConfigs,
+    },
+)
+
+// 创建动态配置客户端的另一种方式 (推荐)
+configClient, err := clients.NewConfigClient(
+    vo.NacosClientParam{
+        ClientConfig:  &clientConfig,
+        ServerConfigs: serverConfigs,
+    },
+)
 ```
 
 
diff --git a/clients/client_factory.go b/clients/client_factory.go
index 0bb1508..bc8fba9 100644
--- a/clients/client_factory.go
+++ b/clients/client_factory.go
@@ -24,15 +24,26 @@ import (
 	"github.com/nacos-group/nacos-sdk-go/clients/naming_client"
 	"github.com/nacos-group/nacos-sdk-go/common/constant"
 	"github.com/nacos-group/nacos-sdk-go/common/http_agent"
+	"github.com/nacos-group/nacos-sdk-go/vo"
 )
 
 // CreateConfigClient use to create config client
 func CreateConfigClient(properties map[string]interface{}) (iClient config_client.IConfigClient, err error) {
-	nacosClient, err := setConfig(properties)
+	param := getConfigParam(properties)
+	return NewConfigClient(param)
+}
+
+//CreateNamingClient use to create a nacos naming client
+func CreateNamingClient(properties map[string]interface{}) (iClient naming_client.INamingClient, err error) {
+	param := getConfigParam(properties)
+	return NewNamingClient(param)
+}
+
+func NewConfigClient(param vo.NacosClientParam) (iClient config_client.IConfigClient, err error) {
+	nacosClient, err := setConfig(param)
 	if err != nil {
 		return
 	}
-	nacosClient.SetHttpAgent(&http_agent.HttpAgent{})
 	config, err := config_client.NewConfigClient(nacosClient)
 	if err != nil {
 		return
@@ -41,13 +52,11 @@ func CreateConfigClient(properties map[string]interface{}) (iClient config_clien
 	return
 }
 
-//CreateNamingClient use to create a nacos naming client
-func CreateNamingClient(properties map[string]interface{}) (iClient naming_client.INamingClient, err error) {
-	nacosClient, err := setConfig(properties)
+func NewNamingClient(param vo.NacosClientParam) (iClient naming_client.INamingClient, err error) {
+	nacosClient, err := setConfig(param)
 	if err != nil {
 		return
 	}
-	nacosClient.SetHttpAgent(&http_agent.HttpAgent{})
 	naming, err := naming_client.NewNamingClient(nacosClient)
 	if err != nil {
 		return
@@ -56,38 +65,53 @@ func CreateNamingClient(properties map[string]interface{}) (iClient naming_clien
 	return
 }
 
-func setConfig(properties map[string]interface{}) (iClient nacos_client.INacosClient, err error) {
-	client := nacos_client.NacosClient{}
+func getConfigParam(properties map[string]interface{}) (param vo.NacosClientParam) {
+
 	if clientConfigTmp, exist := properties[constant.KEY_CLIENT_CONFIG]; exist {
 		if clientConfig, ok := clientConfigTmp.(constant.ClientConfig); ok {
-			err = client.SetClientConfig(clientConfig)
-			if err != nil {
-				return nil, err
-			}
+			param.ClientConfig = &clientConfig
 		}
-	} else {
-		_ = client.SetClientConfig(constant.ClientConfig{
-			TimeoutMs:    10 * 1000,
-			BeatInterval: 5 * 1000,
-		})
 	}
 	if serverConfigTmp, exist := properties[constant.KEY_SERVER_CONFIGS]; exist {
 		if serverConfigs, ok := serverConfigTmp.([]constant.ServerConfig); ok {
-			err = client.SetServerConfig(serverConfigs)
-			if err != nil {
-				return nil, err
-			}
+			param.ServerConfigs = serverConfigs
 		}
+	}
+	return
+}
+
+func setConfig(param vo.NacosClientParam) (iClient nacos_client.INacosClient, err error) {
+	client := &nacos_client.NacosClient{}
+	if param.ClientConfig == nil {
+		// default clientConfig
+		_ = client.SetClientConfig(constant.ClientConfig{
+			TimeoutMs:    10 * 1000,
+			BeatInterval: 5 * 1000,
+		})
 	} else {
+		err = client.SetClientConfig(*param.ClientConfig)
+		if err != nil {
+			return nil, err
+		}
+	}
+
+	if len(param.ServerConfigs) == 0 {
 		clientConfig, _ := client.GetClientConfig()
 		if len(clientConfig.Endpoint) <= 0 {
 			err = errors.New("server configs not found in properties")
-			return
+			return nil, err
+		}
+		_ = client.SetServerConfig([]constant.ServerConfig{})
+	} else {
+		err = client.SetServerConfig(param.ServerConfigs)
+		if err != nil {
+			return nil, err
 		}
-		client.SetServerConfig([]constant.ServerConfig{})
 	}
 
-	iClient = &client
-
+	if _, _err := client.GetHttpAgent(); _err != nil {
+		_ = client.SetHttpAgent(&http_agent.HttpAgent{})
+	}
+	iClient = client
 	return
 }
diff --git a/common/logger/logger.go b/common/logger/logger.go
index 15f597a..3df7462 100644
--- a/common/logger/logger.go
+++ b/common/logger/logger.go
@@ -20,6 +20,7 @@ import (
 	"io"
 	"os"
 	"path/filepath"
+	"sync"
 	"time"
 
 	rotatelogs "github.com/lestrrat/go-file-rotatelogs"
@@ -29,7 +30,8 @@ import (
 )
 
 var (
-	logger Logger
+	logger  Logger
+	logLock sync.RWMutex
 )
 
 var levelMap = map[string]zapcore.Level{
@@ -79,20 +81,28 @@ func init() {
 	}
 	zapLoggerConfig.EncoderConfig = zapLoggerEncoderConfig
 	zapLogger, _ := zapLoggerConfig.Build(zap.AddCallerSkip(1))
-	logger = &NacosLogger{zapLogger.Sugar()}
+	SetLogger(&NacosLogger{zapLogger.Sugar()})
 }
 
+// InitLogger is init global logger for nacos
 func InitLogger(config Config) (err error) {
+	logLock.Lock()
+	defer logLock.Unlock()
+	logger, err = InitNacosLogger(config)
+	return
+}
+
+// InitNacosLogger is init nacos default logger
+func InitNacosLogger(config Config) (Logger, error) {
 	logLevel := getLogLevel(config.Level)
 	encoder := getEncoder()
 	writer, err := getWriter(config.OutputPath, config.RotationTime, config.MaxAge)
 	if err != nil {
-		return
+		return nil, err
 	}
 	core := zapcore.NewCore(zapcore.NewConsoleEncoder(encoder), zapcore.AddSync(writer), logLevel)
 	zaplogger := zap.New(core, zap.AddCallerSkip(1))
-	logger = &NacosLogger{zaplogger.Sugar()}
-	return
+	return &NacosLogger{zaplogger.Sugar()}, nil
 }
 
 func getLogLevel(level string) zapcore.Level {
@@ -132,9 +142,13 @@ func getWriter(outputPath string, rotateTime string, maxAge int64) (writer io.Wr
 
 //SetLogger sets logger for sdk
 func SetLogger(log Logger) {
+	logLock.Lock()
+	defer logLock.Unlock()
 	logger = log
 }
 
 func GetLogger() Logger {
+	logLock.RLock()
+	defer logLock.RUnlock()
 	return logger
 }
diff --git a/common/logger/logging.go b/common/logger/logging.go
index a122802..1d92a5b 100644
--- a/common/logger/logging.go
+++ b/common/logger/logging.go
@@ -18,40 +18,40 @@ package logger
 
 // Info is info level
 func Info(args ...interface{}) {
-	logger.Info(args...)
+	GetLogger().Info(args...)
 }
 
 // Warn is warning level
 func Warn(args ...interface{}) {
-	logger.Warn(args...)
+	GetLogger().Warn(args...)
 }
 
 // Error is error level
 func Error(args ...interface{}) {
-	logger.Error(args...)
+	GetLogger().Error(args...)
 }
 
 // Debug is debug level
 func Debug(args ...interface{}) {
-	logger.Debug(args...)
+	GetLogger().Debug(args...)
 }
 
 // Infof is format info level
 func Infof(fmt string, args ...interface{}) {
-	logger.Infof(fmt, args...)
+	GetLogger().Infof(fmt, args...)
 }
 
 // Warnf is format warning level
 func Warnf(fmt string, args ...interface{}) {
-	logger.Warnf(fmt, args...)
+	GetLogger().Warnf(fmt, args...)
 }
 
 // Errorf is format error level
 func Errorf(fmt string, args ...interface{}) {
-	logger.Errorf(fmt, args...)
+	GetLogger().Errorf(fmt, args...)
 }
 
 // Debugf is format debug level
 func Debugf(fmt string, args ...interface{}) {
-	logger.Debugf(fmt, args...)
+	GetLogger().Debugf(fmt, args...)
 }
diff --git a/example/config/main.go b/example/config/main.go
index 1205e2c..0a29a75 100644
--- a/example/config/main.go
+++ b/example/config/main.go
@@ -52,7 +52,7 @@ func main() {
 		LogLevel:            "debug",
 	}
 	//or a more graceful way to create ClientConfig
-	_ = constant.NewClientConfig(
+	_ = *constant.NewClientConfig(
 		constant.WithNamespaceId("e525eafa-f7d7-4029-83d9-008937f9d468"),
 		constant.WithTimeoutMs(5000),
 		constant.WithNotLoadCacheAtStart(true),
@@ -63,10 +63,13 @@ func main() {
 		constant.WithLogLevel("debug"),
 	)
 
-	client, err := clients.CreateConfigClient(map[string]interface{}{
-		"serverConfigs": sc,
-		"clientConfig":  cc,
-	})
+	// a more graceful way to create config client
+	client, err := clients.NewConfigClient(
+		vo.NacosClientParam{
+			ClientConfig:  &cc,
+			ServerConfigs: sc,
+		},
+	)
 
 	if err != nil {
 		panic(err)
diff --git a/example/service/main.go b/example/service/main.go
index 9c096a7..c717e12 100644
--- a/example/service/main.go
+++ b/example/service/main.go
@@ -50,7 +50,7 @@ func main() {
 		LogLevel:            "debug",
 	}
 	//or a more graceful way to create ClientConfig
-	_ = constant.NewClientConfig(
+	_ = *constant.NewClientConfig(
 		constant.WithNamespaceId("e525eafa-f7d7-4029-83d9-008937f9d468"),
 		constant.WithTimeoutMs(5000),
 		constant.WithNotLoadCacheAtStart(true),
@@ -61,10 +61,13 @@ func main() {
 		constant.WithLogLevel("debug"),
 	)
 
-	client, err := clients.CreateNamingClient(map[string]interface{}{
-		"serverConfigs": sc,
-		"clientConfig":  cc,
-	})
+	// a more graceful way to create naming client
+	client, err := clients.NewNamingClient(
+		vo.NacosClientParam{
+			ClientConfig:  &cc,
+			ServerConfigs: sc,
+		},
+	)
 
 	if err != nil {
 		panic(err)
diff --git a/vo/client_param.go b/vo/client_param.go
new file mode 100644
index 0000000..cbe27d7
--- /dev/null
+++ b/vo/client_param.go
@@ -0,0 +1,8 @@
+package vo
+
+import "github.com/nacos-group/nacos-sdk-go/common/constant"
+
+type NacosClientParam struct {
+	ClientConfig  *constant.ClientConfig  // optional
+	ServerConfigs []constant.ServerConfig // optional
+}


Test patch:
diff --git a/clients/client_factory_test.go b/clients/client_factory_test.go
new file mode 100644
index 0000000..72538f5
--- /dev/null
+++ b/clients/client_factory_test.go
@@ -0,0 +1,55 @@
+package clients
+
+import (
+	"reflect"
+	"testing"
+
+	"github.com/nacos-group/nacos-sdk-go/common/constant"
+	"github.com/nacos-group/nacos-sdk-go/vo"
+	"github.com/stretchr/testify/assert"
+)
+
+func TestSetConfigClient(t *testing.T) {
+
+	sc := []constant.ServerConfig{
+		*constant.NewServerConfig(
+			"console.nacos.io",
+			80,
+			constant.WithScheme("http"),
+			constant.WithContextPath("/nacos")),
+	}
+
+	cc := *constant.NewClientConfig(
+		constant.WithNamespaceId("e525eafa-f7d7-4029-83d9-008937f9d468"),
+		constant.WithTimeoutMs(5000),
+		constant.WithNotLoadCacheAtStart(true),
+		constant.WithLogDir("/tmp/nacos/log"),
+		constant.WithCacheDir("/tmp/nacos/cache"),
+		constant.WithRotateTime("1h"),
+		constant.WithMaxAge(3),
+		constant.WithLogLevel("debug"),
+	)
+
+	t.Run("setConfig_error", func(t *testing.T) {
+		nacosClient, err := setConfig(vo.NacosClientParam{})
+		assert.Nil(t, nacosClient)
+		assert.Equal(t, "server configs not found in properties", err.Error())
+	})
+
+	t.Run("setConfig_normal", func(t *testing.T) {
+		// use map params setConfig
+		param := getConfigParam(map[string]interface{}{
+			"serverConfigs": sc,
+			"clientConfig":  cc,
+		})
+		nacosClientFromMap, err := setConfig(param)
+		assert.Nil(t, err)
+		nacosClientFromStruct, err := setConfig(vo.NacosClientParam{
+			ClientConfig:  &cc,
+			ServerConfigs: sc,
+		})
+		assert.Nil(t, err)
+		assert.True(t, reflect.DeepEqual(nacosClientFromMap, nacosClientFromStruct))
+	})
+
+}
diff --git a/clients/config_client/config_client_test.go b/clients/config_client/config_client_test.go
index d1900a8..fb161cd 100644
--- a/clients/config_client/config_client_test.go
+++ b/clients/config_client/config_client_test.go
@@ -20,6 +20,7 @@ import (
 	"errors"
 	"fmt"
 	"net/http"
+	"runtime"
 	"strconv"
 	"testing"
 	"time"
@@ -35,6 +36,8 @@ import (
 	"github.com/stretchr/testify/assert"
 )
 
+var goVersion = runtime.Version()
+
 var clientConfigTest = constant.ClientConfig{
 	TimeoutMs:      10000,
 	ListenInterval: 20000,
@@ -62,24 +65,35 @@ var clientConfigWithOptions = constant.NewClientConfig(
 	constant.WithNotLoadCacheAtStart(true),
 )
 
+var (
+	dataIdKey                         = goVersion + "dataId"
+	configNoChangeKey                 = goVersion + "ConfigNoChange"
+	multipleClientsKey                = goVersion + "MultipleClients"
+	multipleClientsMultipleConfigsKey = goVersion + "MultipleClientsMultipleConfig"
+	cancelOneKey                      = goVersion + "CancelOne"
+	cancelOne1Key                     = goVersion + "CancelOne1"
+	cancelListenConfigKey             = goVersion + "cancel_listen_config"
+	specialSymbolKey                  = goVersion + "special_symbol"
+)
+
 var configParamMapTest = map[string]string{
-	"dataId": "dataId",
+	"dataId": dataIdKey,
 	"group":  "group",
 }
 
 var configParamTest = vo.ConfigParam{
-	DataId: "dataId",
+	DataId: dataIdKey,
 	Group:  "group",
 }
 
 var localConfigTest = vo.ConfigParam{
-	DataId:  "dataId",
+	DataId:  dataIdKey,
 	Group:   "group",
 	Content: "content",
 }
 
 var localConfigMapTest = map[string]string{
-	"dataId":  "dataId",
+	"dataId":  dataIdKey,
 	"group":   "group",
 	"content": "content",
 }
@@ -136,7 +150,7 @@ func Test_GetConfig(t *testing.T) {
 
 	client := createConfigClientTest()
 	success, err := client.PublishConfig(vo.ConfigParam{
-		DataId:  "dataId",
+		DataId:  dataIdKey,
 		Group:   "group",
 		Content: "hello world!222222"})
 
@@ -144,7 +158,7 @@ func Test_GetConfig(t *testing.T) {
 	assert.True(t, success)
 
 	content, err := client.GetConfig(vo.ConfigParam{
-		DataId: "dataId",
+		DataId: dataIdKey,
 		Group:  "group"})
 
 	assert.Nil(t, err)
@@ -258,7 +272,7 @@ func Test_PublishConfigWithoutDataId(t *testing.T) {
 func Test_PublishConfigWithoutGroup(t *testing.T) {
 	client := createConfigClientTest()
 	_, err := client.PublishConfig(vo.ConfigParam{
-		DataId:  "dataId",
+		DataId:  dataIdKey,
 		Group:   "",
 		Content: "content",
 	})
@@ -268,7 +282,7 @@ func Test_PublishConfigWithoutGroup(t *testing.T) {
 func Test_PublishConfigWithoutContent(t *testing.T) {
 	client := createConfigClientTest()
 	_, err := client.PublishConfig(vo.ConfigParam{
-		DataId:  "dataId",
+		DataId:  dataIdKey,
 		Group:   "group",
 		Content: "",
 	})
@@ -280,7 +294,7 @@ func Test_PublishConfig(t *testing.T) {
 	client := createConfigClientTest()
 
 	success, err := client.PublishConfig(vo.ConfigParam{
-		DataId:  "dataId",
+		DataId:  dataIdKey,
 		Group:   "group",
 		Content: "hello world2!"})
 
@@ -329,7 +343,7 @@ func Test_DeleteConfig(t *testing.T) {
 	client := createConfigClientTest()
 
 	success, err := client.PublishConfig(vo.ConfigParam{
-		DataId:  "dataId",
+		DataId:  dataIdKey,
 		Group:   "group",
 		Content: "hello world!"})
 
@@ -337,7 +351,7 @@ func Test_DeleteConfig(t *testing.T) {
 	assert.True(t, success)
 
 	success, err = client.DeleteConfig(vo.ConfigParam{
-		DataId: "dataId",
+		DataId: dataIdKey,
 		Group:  "group"})
 
 	assert.Nil(t, err)
@@ -393,7 +407,7 @@ func Test_DeleteConfigWithoutDataId(t *testing.T) {
 func Test_DeleteConfigWithoutGroup(t *testing.T) {
 	client := createConfigClientTest()
 	success, err := client.DeleteConfig(vo.ConfigParam{
-		DataId: "dataId",
+		DataId: dataIdKey,
 		Group:  "",
 	})
 	assert.NotNil(t, err)
@@ -453,7 +467,7 @@ func TestListen(t *testing.T) {
 	// ListenConfig no change
 	t.Run("TestListenConfigNoChange", func(t *testing.T) {
 		client := createConfigClientTest()
-		key := util.GetConfigCacheKey("ConfigNoChange", localConfigTest.Group, clientConfigTest.NamespaceId)
+		key := util.GetConfigCacheKey(configNoChangeKey, localConfigTest.Group, clientConfigTest.NamespaceId)
 		cache.WriteConfigToFile(key, client.configCacheDir, localConfigTest.Content)
 		var err error
 		var success bool
@@ -461,7 +475,7 @@ func TestListen(t *testing.T) {
 
 		go func() {
 			err = client.ListenConfig(vo.ConfigParam{
-				DataId: "ConfigNoChange",
+				DataId: configNoChangeKey,
 				Group:  localConfigTest.Group,
 				OnChange: func(namespace, group, dataId, data string) {
 					content = "data"
@@ -473,7 +487,7 @@ func TestListen(t *testing.T) {
 		time.Sleep(2 * time.Second)
 
 		success, err = client.PublishConfig(vo.ConfigParam{
-			DataId:  "ConfigNoChange",
+			DataId:  configNoChangeKey,
 			Group:   localConfigTest.Group,
 			Content: localConfigTest.Content})
 
@@ -485,7 +499,7 @@ func TestListen(t *testing.T) {
 	t.Run("TestListenConfigWithMultipleClients", func(t *testing.T) {
 		ch := make(chan string)
 		listenConfigParam := vo.ConfigParam{
-			DataId: "MultipleClients",
+			DataId: multipleClientsKey,
 			Group:  localConfigTest.Group,
 			OnChange: func(namespace, group, dataId, data string) {
 				fmt.Println("group:" + group + ", dataId:" + dataId + ", data:" + data)
@@ -501,7 +515,7 @@ func TestListen(t *testing.T) {
 		client1.ListenConfig(listenConfigParam)
 
 		success, err := client.PublishConfig(vo.ConfigParam{
-			DataId:  "MultipleClients",
+			DataId:  multipleClientsKey,
 			Group:   localConfigTest.Group,
 			Content: localConfigTest.Content})
 
@@ -520,7 +534,7 @@ func TestListen(t *testing.T) {
 	t.Run("TestListenConfigWithMultipleClientsMultipleConfig", func(t *testing.T) {
 		ch := make(chan string)
 		listenConfigParam := vo.ConfigParam{
-			DataId: "MultipleClientsMultipleConfig",
+			DataId: multipleClientsMultipleConfigsKey,
 			Group:  localConfigTest.Group,
 			OnChange: func(namespace, group, dataId, data string) {
 				fmt.Println("group:" + group + ", dataId:" + dataId + ", data:" + data)
@@ -536,7 +550,7 @@ func TestListen(t *testing.T) {
 		client1.ListenConfig(listenConfigParam)
 
 		success, err := client.PublishConfig(vo.ConfigParam{
-			DataId:  "MultipleClientsMultipleConfig",
+			DataId:  multipleClientsMultipleConfigsKey,
 			Group:   localConfigTest.Group,
 			Content: localConfigTest.Content})
 
@@ -562,7 +576,7 @@ func TestCancelListenConfig(t *testing.T) {
 		var success bool
 		var context string
 		listenConfigParam := vo.ConfigParam{
-			DataId: "CancelOne",
+			DataId: cancelOneKey,
 			Group:  "group",
 			OnChange: func(namespace, group, dataId, data string) {
 				fmt.Println("group:" + group + ", dataId:" + dataId + ", data:" + data)
@@ -570,7 +584,7 @@ func TestCancelListenConfig(t *testing.T) {
 		}
 
 		listenConfigParam1 := vo.ConfigParam{
-			DataId: "CancelOne1",
+			DataId: cancelOne1Key,
 			Group:  "group1",
 			OnChange: func(namespace, group, dataId, data string) {
 				fmt.Println("group1:" + group + ", dataId1:" + dataId + ", data:" + data)
@@ -589,14 +603,14 @@ func TestCancelListenConfig(t *testing.T) {
 		for i := 1; i <= 5; i++ {
 			go func() {
 				success, err = client.PublishConfig(vo.ConfigParam{
-					DataId:  "CancelOne",
+					DataId:  cancelOneKey,
 					Group:   "group",
 					Content: "abcd" + strconv.Itoa(i)})
 			}()
 
 			go func() {
 				success, err = client.PublishConfig(vo.ConfigParam{
-					DataId:  "CancelOne1",
+					DataId:  cancelOne1Key,
 					Group:   "group1",
 					Content: "abcd" + strconv.Itoa(i)})
 			}()
@@ -620,7 +634,7 @@ func TestCancelListenConfig(t *testing.T) {
 		key := util.GetConfigCacheKey(localConfigTest.DataId, localConfigTest.Group, clientConfigTest.NamespaceId)
 		cache.WriteConfigToFile(key, client.configCacheDir, "")
 		listenConfigParam := vo.ConfigParam{
-			DataId: "cancel_listen_config",
+			DataId: cancelListenConfigKey,
 			Group:  localConfigTest.Group,
 			OnChange: func(namespace, group, dataId, data string) {
 				fmt.Println("group:" + group + ", dataId:" + dataId + ", data:" + data)
@@ -633,7 +647,7 @@ func TestCancelListenConfig(t *testing.T) {
 			assert.Nil(t, err)
 		}()
 		success, err := client.PublishConfig(vo.ConfigParam{
-			DataId:  "cancel_listen_config",
+			DataId:  cancelListenConfigKey,
 			Group:   localConfigTest.Group,
 			Content: localConfigTest.Content})
 		assert.Nil(t, err)
@@ -647,7 +661,7 @@ func TestCancelListenConfig(t *testing.T) {
 		client.CancelListenConfig(listenConfigParam)
 
 		success, err = client.PublishConfig(vo.ConfigParam{
-			DataId:  "cancel_listen_config",
+			DataId:  cancelListenConfigKey,
 			Group:   localConfigTest.Group,
 			Content: "abcd"})
 		assert.Nil(t, err)
@@ -662,7 +676,7 @@ func TestGetConfigWithSpecialSymbol(t *testing.T) {
 
 	client := createConfigClientTest()
 	success, err := client.PublishConfig(vo.ConfigParam{
-		DataId:  "special_symbol",
+		DataId:  specialSymbolKey,
 		Group:   localConfigTest.Group,
 		Content: contentStr})
 
@@ -670,7 +684,7 @@ func TestGetConfigWithSpecialSymbol(t *testing.T) {
 	assert.True(t, success)
 
 	content, err := client.GetConfig(vo.ConfigParam{
-		DataId: "special_symbol",
+		DataId: specialSymbolKey,
 		Group:  localConfigTest.Group})
 
 	assert.Nil(t, err)
diff --git a/common/logger/logger_test.go b/common/logger/logger_test.go
index d067837..b16c357 100644
--- a/common/logger/logger_test.go
+++ b/common/logger/logger_test.go
@@ -17,11 +17,16 @@
 package logger
 
 import (
+	"sync"
 	"testing"
 
 	"github.com/stretchr/testify/assert"
 )
 
+func reset() {
+	SetLogger(nil)
+}
+
 func TestInitLogger(t *testing.T) {
 	config := Config{
 		Level:        "degug",
@@ -31,4 +36,113 @@ func TestInitLogger(t *testing.T) {
 	}
 	err := InitLogger(config)
 	assert.NoError(t, err)
+	reset()
+}
+
+func TestGetLogger(t *testing.T) {
+	// not yet init get default log
+	log := GetLogger()
+	config := Config{
+		Level:        "degug",
+		OutputPath:   "/tmp/nacos",
+		RotationTime: "1h",
+		MaxAge:       2,
+	}
+	_ = InitLogger(config)
+	// after init logger
+	log2 := GetLogger()
+	assert.NotEqual(t, log, log2)
+
+	// the secend init logger
+	config.Level = "info"
+	_ = InitLogger(config)
+	log3 := GetLogger()
+	assert.NotEqual(t, log2, log3)
+	reset()
+}
+
+func TestSetLogger(t *testing.T) {
+	// not yet init get default log
+	log := GetLogger()
+	log1 := &mockLogger{}
+	SetLogger(log1)
+
+	// after set logger
+	log2 := GetLogger()
+	assert.NotEqual(t, log, log2)
+	assert.Equal(t, log1, log2)
+
+	config := Config{
+		Level:        "degug",
+		OutputPath:   "/tmp/nacos",
+		RotationTime: "1h",
+		MaxAge:       2,
+	}
+	_ = InitLogger(config)
+	// after init logger
+	log3 := GetLogger()
+	assert.NotEqual(t, log2, log3)
+	reset()
+}
+
+func TestRaceLogger(t *testing.T) {
+	wg := sync.WaitGroup{}
+	for i := 0; i < 100; i++ {
+		wg.Add(3)
+		go func() {
+			defer wg.Done()
+			SetLogger(&mockLogger{})
+		}()
+		go func() {
+			defer wg.Done()
+			_ = GetLogger()
+		}()
+		go func() {
+			defer wg.Done()
+			config := Config{
+				Level:        "degug",
+				OutputPath:   "/tmp/nacos",
+				RotationTime: "1h",
+				MaxAge:       2,
+			}
+			_ = InitLogger(config)
+		}()
+	}
+	wg.Wait()
+	reset()
+}
+
+type mockLogger struct {
+}
+
+func (m mockLogger) Info(args ...interface{}) {
+	panic("implement me")
+}
+
+func (m mockLogger) Warn(args ...interface{}) {
+	panic("implement me")
+}
+
+func (m mockLogger) Error(args ...interface{}) {
+	panic("implement me")
+}
+
+func (m mockLogger) Debug(args ...interface{}) {
+	panic("implement me")
+}
+
+func (m mockLogger) Infof(fmt string, args ...interface{}) {
+	panic("implement me")
+}
+
+func (m mockLogger) Warnf(fmt string, args ...interface{}) {
+	panic("implement me")
+}
+
+func (m mockLogger) Errorf(fmt string, args ...interface{}) {
+	panic("implement me")
+}
+
+func (m mockLogger) Debugf(fmt string, args ...interface{}) {
+	panic("implement me")
 }