Repository: Unleash/unleash-client-go (go)

Issue:
infinitely blocked in metrics.count with gitlab
### Describe the bug

I am using Gitlab as unleash API, and I came across an error, where a request for an API-call against my microservice was timed out, since it never leaves the isEnabled func. After debugging I found out, that the metrics count in the defer is blocking infinitely.
https://github.com/Unleash/unleash-client-go/blob/v3/client.go#L243
Further it was really hard to figure this out as it is in the defer. I know, that I can disable the metrics, and that`s my fix for it, but imho this should not block. It should return an error instead or panic, but it was really hard to figure this out.

### Steps to reproduce the bug

_No response_

### Expected behavior

No blocking

### Logs, error output, etc.

_No response_

### Screenshots

_No response_

### Additional context

_No response_

### Unleash version

3.8.0

### Subscription type

None

### Hosting type

None

### SDK information (language and version)

Go

Pull request:
fix: default to a noop listener to avoid hanging on channel messages
## About the changes

Defaults to register a NoopListener if no listener has been added

Closes #139

## Discussion points

Should this also actually listen to the individual channels? I have commented that part out and seems to work without it but I'm unsure if this has longer term effects

Patch:
diff --git a/README.md b/README.md
index 07242e0..ea4862b 100644
--- a/README.md
+++ b/README.md
@@ -245,6 +245,15 @@ unleash.IsEnabled("someToggle", unleash.WithContext(ctx), unleash.WithResolver(r
 
 ## Development
 
+To override dependency on unleash-client-go github repository to a local development folder (for instance when building a local test-app for the SDK),  
+you can add the following to your apps `go.mod`:
+
+```mod
+    replace github.com/Unleash/unleash-client-go/v3 => ../unleash-client-go/
+```
+
+
+
 ## Steps to release
 
 - Update the clientVersion in `client.go`
diff --git a/client.go b/client.go
index 5b2bd2e..32617cc 100644
--- a/client.go
+++ b/client.go
@@ -112,20 +112,22 @@ func NewClient(options ...ConfigOption) (*Client, error) {
 		AppName:     uc.options.appName,
 	}
 
-	if uc.options.listener != nil {
-		if eListener, ok := uc.options.listener.(ErrorListener); ok {
-			uc.errorListener = eListener
-		}
-		if rListener, ok := uc.options.listener.(RepositoryListener); ok {
-			uc.repositoryListener = rListener
-		}
-		if mListener, ok := uc.options.listener.(MetricListener); ok {
-			uc.metricsListener = mListener
-		}
-		defer func() {
-			go uc.sync()
-		}()
+	if uc.options.listener == nil {
+		uc.options.listener = &NoopListener{}
+	}
+
+	if eListener, ok := uc.options.listener.(ErrorListener); ok {
+		uc.errorListener = eListener
+	}
+	if rListener, ok := uc.options.listener.(RepositoryListener); ok {
+		uc.repositoryListener = rListener
+	}
+	if mListener, ok := uc.options.listener.(MetricListener); ok {
+		uc.metricsListener = mListener
 	}
+	defer func() {
+		go uc.sync()
+	}()
 
 	if uc.options.url == "" {
 		return nil, fmt.Errorf("Unleash server URL missing")
diff --git a/nooplistener.go b/nooplistener.go
new file mode 100644
index 0000000..64cf432
--- /dev/null
+++ b/nooplistener.go
@@ -0,0 +1,28 @@
+package unleash
+
+// NoopListener is an implementation of all of the listener interfaces that discards
+// all messages. It's added if no other listener is added to drain the channels and as
+// an example of implementing the listener interfaces.
+type NoopListener struct{}
+
+func (l NoopListener) OnError(err error) {
+}
+
+func (l NoopListener) OnWarning(warning error) {
+}
+
+// The repository is ready.
+func (l NoopListener) OnReady() {
+}
+
+// The feature is queried.
+func (l NoopListener) OnCount(name string, enabled bool) {
+}
+
+// The server has uploaded metrics.
+func (l NoopListener) OnSent(payload MetricsData) {
+}
+
+// The client has registered.
+func (l NoopListener) OnRegistered(payload ClientData) {
+}


Test patch:
diff --git a/nooplistener_test.go b/nooplistener_test.go
new file mode 100644
index 0000000..9bc0f36
--- /dev/null
+++ b/nooplistener_test.go
@@ -0,0 +1,24 @@
+package unleash
+
+import (
+	"net/http"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func Test_defaultsToNoopListener(t *testing.T) {
+	result := Initialize(
+		WithAppName("my-application"),
+		WithUrl("http://localhost:4242"),
+		WithCustomHeaders(http.Header{"Authorization": {"*:development.code"}}),
+	)
+
+	if result != nil {
+		t.Fail()
+	}
+	res := IsEnabled("test", WithFallback(false))
+	assert.Equal(t, false, res)
+
+	assert.IsType(t, &NoopListener{}, defaultClient.errorListener)
+}