Browse Source

clientv3: fix race when setting grpc Logger

grpc only permits SetLogger on init()
Anthony Romano 9 years ago
parent
commit
161bc5e19c
2 changed files with 68 additions and 11 deletions
  1. 4 11
      clientv3/client.go
  2. 64 0
      clientv3/logger.go

+ 4 - 11
clientv3/client.go

@@ -28,15 +28,12 @@ import (
 	"golang.org/x/net/context"
 	"golang.org/x/net/context"
 	"google.golang.org/grpc"
 	"google.golang.org/grpc"
 	"google.golang.org/grpc/credentials"
 	"google.golang.org/grpc/credentials"
-	"google.golang.org/grpc/grpclog"
 )
 )
 
 
 var (
 var (
 	ErrNoAvailableEndpoints = errors.New("etcdclient: no available endpoints")
 	ErrNoAvailableEndpoints = errors.New("etcdclient: no available endpoints")
 )
 )
 
 
-type Logger grpclog.Logger
-
 // Client provides and manages an etcd v3 client session.
 // Client provides and manages an etcd v3 client session.
 type Client struct {
 type Client struct {
 	Cluster
 	Cluster
@@ -54,8 +51,6 @@ type Client struct {
 
 
 	ctx    context.Context
 	ctx    context.Context
 	cancel context.CancelFunc
 	cancel context.CancelFunc
-
-	logger Logger
 }
 }
 
 
 // EndpointDialer is a policy for choosing which endpoint to dial next
 // EndpointDialer is a policy for choosing which endpoint to dial next
@@ -190,13 +185,11 @@ func newClient(cfg *Config) (*Client, error) {
 	client.Watcher = NewWatcher(client)
 	client.Watcher = NewWatcher(client)
 	client.Auth = NewAuth(client)
 	client.Auth = NewAuth(client)
 	client.Maintenance = &maintenance{c: client}
 	client.Maintenance = &maintenance{c: client}
-	if cfg.Logger == nil {
-		client.logger = log.New(ioutil.Discard, "", 0)
-		// disable client side grpc by default
-		grpclog.SetLogger(log.New(ioutil.Discard, "", 0))
+	if cfg.Logger != nil {
+		logger.Set(cfg.Logger)
 	} else {
 	} else {
-		client.logger = cfg.Logger
-		grpclog.SetLogger(cfg.Logger)
+		// disable client side grpc by default
+		logger.Set(log.New(ioutil.Discard, "", 0))
 	}
 	}
 
 
 	return client, nil
 	return client, nil

+ 64 - 0
clientv3/logger.go

@@ -0,0 +1,64 @@
+// Copyright 2016 CoreOS, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package clientv3
+
+import (
+	"log"
+	"os"
+	"sync"
+
+	"google.golang.org/grpc/grpclog"
+)
+
+type Logger grpclog.Logger
+
+var (
+	logger settableLogger
+)
+
+type settableLogger struct {
+	l  grpclog.Logger
+	mu sync.RWMutex
+}
+
+func init() {
+	// use go's standard logger by default like grpc
+	logger.mu.Lock()
+	logger.l = log.New(os.Stderr, "", log.LstdFlags)
+	grpclog.SetLogger(&logger)
+	logger.mu.Unlock()
+}
+
+func (s *settableLogger) Set(l Logger) {
+	s.mu.Lock()
+	logger.l = l
+	s.mu.Unlock()
+}
+
+func (s *settableLogger) Get() Logger {
+	s.mu.RLock()
+	l := logger.l
+	s.mu.RUnlock()
+	return l
+}
+
+// implement the grpclog.Logger interface
+
+func (s *settableLogger) Fatal(args ...interface{})                 { s.Get().Fatal(args...) }
+func (s *settableLogger) Fatalf(format string, args ...interface{}) { s.Get().Fatalf(format, args...) }
+func (s *settableLogger) Fatalln(args ...interface{})               { s.Get().Fatalln(args...) }
+func (s *settableLogger) Print(args ...interface{})                 { s.Get().Print(args...) }
+func (s *settableLogger) Printf(format string, args ...interface{}) { s.Get().Printf(format, args...) }
+func (s *settableLogger) Println(args ...interface{})               { s.Get().Println(args...) }