Skip to content

Commit 806ee13

Browse files
committed
[FAB-2734] Make gRPC logging configurable
The gRPC library has built in logging but does not support leveled logging. The logging can be very noisy (e.g. when trying to connect to a remote endpoint which is down) but also very useful (e.g. for TLS errors). The gossip component currently effectively disables the gRPC logs which makes it difficult to debug. This change adds the ability to turn gRPC logging on or off. The implementation is as follows: - implement a custom logger which wraps calls to flogging and uses module name "grpc" - only logs at the debug level (except for fatal log messages) - explicit configuration provided in core.yaml using logging.grpc inline with other modules Change-Id: I78af0fbb6aed2bfb2ed1e6713c7e966d8d21b60c Signed-off-by: Gari Singh <[email protected]>
1 parent 16cb17a commit 806ee13

File tree

6 files changed

+136
-8
lines changed

6 files changed

+136
-8
lines changed

common/flogging/grpclogger.go

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/*
2+
Copyright IBM Corp. 2017 All Rights Reserved.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package flogging
18+
19+
import (
20+
"github.com/op/go-logging"
21+
"google.golang.org/grpc/grpclog"
22+
)
23+
24+
const GRPCModuleID = "grpc"
25+
26+
func initgrpclogger() {
27+
glogger := MustGetLogger(GRPCModuleID)
28+
grpclog.SetLogger(&grpclogger{glogger})
29+
}
30+
31+
// grpclogger implements the standard Go logging interface and wraps the
32+
// logger provided by the flogging package. This is required in order to
33+
// replace the default log used by the grpclog package.
34+
type grpclogger struct {
35+
logger *logging.Logger
36+
}
37+
38+
func (g *grpclogger) Fatal(args ...interface{}) {
39+
g.logger.Fatal(args...)
40+
}
41+
42+
func (g *grpclogger) Fatalf(format string, args ...interface{}) {
43+
g.logger.Fatalf(format, args...)
44+
}
45+
46+
func (g *grpclogger) Fatalln(args ...interface{}) {
47+
g.logger.Fatal(args...)
48+
}
49+
50+
// NOTE: grpclog does not support leveled logs so for now use DEBUG
51+
func (g *grpclogger) Print(args ...interface{}) {
52+
g.logger.Debug(args...)
53+
}
54+
55+
func (g *grpclogger) Printf(format string, args ...interface{}) {
56+
g.logger.Debugf(format, args...)
57+
}
58+
59+
func (g *grpclogger) Println(args ...interface{}) {
60+
g.logger.Debug(args...)
61+
}

common/flogging/grpclogger_test.go

+72
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/*
2+
Copyright IBM Corp. 2017 All Rights Reserved.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package flogging
18+
19+
import (
20+
"testing"
21+
22+
"github.com/op/go-logging"
23+
"github.com/stretchr/testify/assert"
24+
"google.golang.org/grpc/grpclog"
25+
)
26+
27+
// from go-logging memory_test.go
28+
func MemoryRecordN(b *logging.MemoryBackend, n int) *logging.Record {
29+
node := b.Head()
30+
for i := 0; i < n; i++ {
31+
if node == nil {
32+
break
33+
}
34+
node = node.Next()
35+
}
36+
if node == nil {
37+
return nil
38+
}
39+
return node.Record
40+
}
41+
42+
func TestGRPCLogger(t *testing.T) {
43+
initgrpclogger()
44+
backend := logging.NewMemoryBackend(3)
45+
logging.SetBackend(backend)
46+
logging.SetLevel(defaultLevel, "")
47+
SetModuleLevel(GRPCModuleID, "DEBUG")
48+
messages := []string{"print test", "printf test", "println test"}
49+
grpclog.Print(messages[0])
50+
grpclog.Printf(messages[1])
51+
grpclog.Println(messages[2])
52+
53+
for i, message := range messages {
54+
assert.Equal(t, message, MemoryRecordN(backend, i).Message())
55+
t.Log(MemoryRecordN(backend, i).Message())
56+
}
57+
58+
// now make sure there's no logging at a level other than DEBUG
59+
SetModuleLevel(GRPCModuleID, "INFO")
60+
messages2 := []string{"print test2", "printf test2", "println test2"}
61+
grpclog.Print(messages2[0])
62+
grpclog.Printf(messages2[1])
63+
grpclog.Println(messages2[2])
64+
65+
// should still be messages not messages2
66+
for i, message := range messages {
67+
assert.Equal(t, message, MemoryRecordN(backend, i).Message())
68+
t.Log(MemoryRecordN(backend, i).Message())
69+
}
70+
// reset flogging
71+
Reset()
72+
}

common/flogging/logging.go

+1
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ var (
4747
func init() {
4848
logger = logging.MustGetLogger(pkgLogID)
4949
Reset()
50+
initgrpclogger()
5051
}
5152

5253
// Reset sets to logging to the defaults defined in this package.

gossip/util/logging.go

-7
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,10 @@ limitations under the License.
1717
package util
1818

1919
import (
20-
"io/ioutil"
21-
"log"
2220
"sync"
2321

2422
"github.com/hyperledger/fabric/common/flogging"
2523
"github.com/op/go-logging"
26-
"google.golang.org/grpc/grpclog"
2724
)
2825

2926
// Module names for logger initialization.
@@ -45,10 +42,6 @@ var lock = sync.Mutex{}
4542
// defaultTestSpec is the default logging level for gossip tests
4643
var defaultTestSpec = "WARNING"
4744

48-
func init() {
49-
grpclog.SetLogger(log.New(ioutil.Discard, "", 0))
50-
}
51-
5245
// GetLogger returns a logger for given gossip module and peerID
5346
func GetLogger(module string, peerID string) *logging.Logger {
5447
if peerID != "" {

peer/node/start.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,7 @@ func serve(args []string) error {
274274

275275
// set the logging level for specific modules defined via environment
276276
// variables or core.yaml
277-
overrideLogModules := []string{"msp", "gossip", "ledger", "cauthdsl", "policies"}
277+
overrideLogModules := []string{"msp", "gossip", "ledger", "cauthdsl", "policies", "grpc"}
278278
for _, module := range overrideLogModules {
279279
err = common.SetLogLevelFromViper(module)
280280
if err != nil {

sampleconfig/core.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ logging:
3131
ledger: info
3232
msp: warning
3333
policies: warning
34+
grpc: error
3435

3536
format: '%{color}%{time:2006-01-02 15:04:05.000 MST} [%{module}] %{shortfunc} -> %{level:.4s} %{id:03x}%{color:reset} %{message}'
3637

0 commit comments

Comments
 (0)