Skip to content

Commit 842f46a

Browse files
committed
[FAB-2351] Add revert to peer startup log levels
This change adds the mechanism to store the module map at the end at the end of peer startup and adds a method to revert all modules to those levels. It can be called from CLI using 'peer logging revertlevels'. This CR follows https://gerrit.hyperledger.org/r/#/c/7281/. A future CR will update all peer code to use flogging.MustGetLogger instead of logging.MustGetLogger to enable these new features. Change-Id: I297c22b625041e34ebf3a9795ed3b673a63b3212 Signed-off-by: Will Lahti <[email protected]>
1 parent 118f82f commit 842f46a

File tree

10 files changed

+267
-64
lines changed

10 files changed

+267
-64
lines changed

common/flogging/logging.go

+54-6
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,11 @@ var (
3737

3838
defaultOutput *os.File
3939

40-
modules map[string]string // Holds the map of all modules and their respective log level
41-
lock sync.Mutex
40+
modules map[string]string // Holds the map of all modules and their respective log level
41+
peerStartModules map[string]string
42+
43+
lock sync.RWMutex
44+
once sync.Once
4245

4346
// IsSetLevelByRegExpEnabled allows the setting of log levels using a regular
4447
// expression, instead of one module at a time, when set to true.
@@ -56,7 +59,7 @@ func init() {
5659
func Reset() {
5760
IsSetLevelByRegExpEnabled = false // redundant since the default for booleans is `false` but added for clarity
5861
modules = make(map[string]string)
59-
lock = sync.Mutex{}
62+
lock = sync.RWMutex{}
6063

6164
defaultOutput = os.Stderr
6265
InitBackend(SetFormat(defaultFormat), defaultOutput)
@@ -98,16 +101,20 @@ func GetModuleLevel(module string) string {
98101
// regular expression. Can be used to dynamically change the log level for the
99102
// module.
100103
func SetModuleLevel(moduleRegExp string, level string) (string, error) {
101-
var re *regexp.Regexp
104+
return setModuleLevel(moduleRegExp, level, false)
105+
}
102106

107+
func setModuleLevel(moduleRegExp string, level string, revert bool) (string, error) {
108+
109+
var re *regexp.Regexp
103110
logLevel, err := logging.LogLevel(level)
104111
if err != nil {
105112
logger.Warningf("Invalid logging level '%s' - ignored", level)
106113
} else {
107114
// TODO This check is here to preserve the old functionality until all
108115
// other packages switch to `flogging.MustGetLogger` (from
109116
// `logging.MustGetLogger`).
110-
if !IsSetLevelByRegExpEnabled {
117+
if !IsSetLevelByRegExpEnabled || revert {
111118
logging.SetLevel(logging.Level(logLevel), moduleRegExp)
112119
logger.Debugf("Module '%s' logger enabled for log level '%s'", moduleRegExp, logLevel)
113120
} else {
@@ -123,7 +130,7 @@ func SetModuleLevel(moduleRegExp string, level string) (string, error) {
123130
if re.MatchString(module) {
124131
logging.SetLevel(logging.Level(logLevel), module)
125132
modules[module] = logLevel.String()
126-
logger.Infof("Module '%s' logger enabled for log level '%s'", module, logLevel)
133+
logger.Debugf("Module '%s' logger enabled for log level '%s'", module, logLevel)
127134
}
128135
}
129136
}
@@ -185,3 +192,44 @@ func InitFromSpec(spec string) string {
185192
logging.SetLevel(levelAll, "") // set the logging level for all modules
186193
return levelAll.String()
187194
}
195+
196+
// SetPeerStartupModulesMap saves the modules and their log levels.
197+
// this function should only be called at the end of peer startup.
198+
func SetPeerStartupModulesMap() {
199+
lock.Lock()
200+
defer lock.Unlock()
201+
202+
once.Do(func() {
203+
peerStartModules = make(map[string]string)
204+
for k, v := range modules {
205+
peerStartModules[k] = v
206+
}
207+
})
208+
}
209+
210+
// GetPeerStartupLevel returns the peer startup level for the specified module.
211+
// It will return an empty string if the input parameter is empty or the module
212+
// is not found
213+
func GetPeerStartupLevel(module string) string {
214+
if module != "" {
215+
if level, ok := peerStartModules[module]; ok {
216+
return level
217+
}
218+
}
219+
220+
return ""
221+
}
222+
223+
// RevertToPeerStartupLevels reverts the log levels for all modules to the level
224+
// defined at the end of peer startup.
225+
func RevertToPeerStartupLevels() error {
226+
lock.RLock()
227+
defer lock.RUnlock()
228+
for key := range peerStartModules {
229+
_, err := setModuleLevel(key, peerStartModules[key], true)
230+
if err != nil {
231+
return err
232+
}
233+
}
234+
return nil
235+
}

common/flogging/logging_test.go

+35-25
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ type testCase struct {
3333
expectedLevels []string
3434
modules []string
3535
withRegEx bool
36+
revert bool
3637
shouldErr bool
3738
}
3839

@@ -46,22 +47,24 @@ func TestSetModuleLevel(t *testing.T) {
4647
var tc []testCase
4748

4849
tc = append(tc,
49-
testCase{"Valid", []string{"a", "warning"}, []string{"WARNING"}, []string{"a"}, false, false},
50+
testCase{"Valid", []string{"a", "warning"}, []string{"WARNING"}, []string{"a"}, false, false, false},
5051
// Same as before
51-
testCase{"Invalid", []string{"a", "foo"}, []string{"WARNING"}, []string{"a"}, false, false},
52+
testCase{"Invalid", []string{"a", "foo"}, []string{"WARNING"}, []string{"a"}, false, false, false},
5253
// Tests with regular expressions
5354
testCase{"RegexModuleWithSubmodule", []string{"foo", "warning"}, []string{"WARNING", "WARNING", flogging.DefaultLevel()},
54-
[]string{"foo", "foo/bar", "baz"}, true, false},
55+
[]string{"foo", "foo/bar", "baz"}, true, false, false},
5556
// Set the level for modules that contain "foo" or "baz"
5657
testCase{"RegexOr", []string{"foo|baz", "debug"}, []string{"DEBUG", "DEBUG", "DEBUG", flogging.DefaultLevel()},
57-
[]string{"foo", "foo/bar", "baz", "random"}, true, false},
58+
[]string{"foo", "foo/bar", "baz", "random"}, true, false, false},
5859
// Set the level for modules that end with "bar"
5960
testCase{"RegexSuffix", []string{"bar$", "error"}, []string{"ERROR", flogging.DefaultLevel()},
60-
[]string{"foo/bar", "bar/baz"}, true, false},
61+
[]string{"foo/bar", "bar/baz"}, true, false, false},
6162
testCase{"RegexComplex", []string{"^[a-z]+\\/[a-z]+#.+$", "warning"}, []string{flogging.DefaultLevel(), flogging.DefaultLevel(), "WARNING", "WARNING", "WARNING"},
62-
[]string{"gossip/util", "orderer/util", "gossip/gossip#0.0.0.0:7051", "gossip/conn#-1", "orderer/conn#0.0.0.0:7051"}, true, false},
63+
[]string{"gossip/util", "orderer/util", "gossip/gossip#0.0.0.0:7051", "gossip/conn#-1", "orderer/conn#0.0.0.0:7051"}, true, false, false},
6364
testCase{"RegexInvalid", []string{"(", "warning"}, []string{flogging.DefaultLevel()},
64-
[]string{"foo"}, true, true},
65+
[]string{"foo"}, true, false, true},
66+
testCase{"RevertLevels", []string{"revertmodule1", "warning", "revertmodule2", "debug"}, []string{"WARNING", "DEBUG", "DEBUG"},
67+
[]string{"revertmodule1", "revertmodule2", "revertmodule2/submodule"}, true, true, false},
6568
)
6669

6770
assert := assert.New(t)
@@ -72,26 +75,33 @@ func TestSetModuleLevel(t *testing.T) {
7275
for j := 0; j < len(tc[i].modules); j++ {
7376
flogging.MustGetLogger(tc[i].modules[j])
7477
}
78+
if tc[i].revert {
79+
flogging.SetPeerStartupModulesMap()
80+
}
7581
flogging.IsSetLevelByRegExpEnabled = true // enable for call below
7682
}
77-
78-
_, err := flogging.SetModuleLevel(tc[i].args[0], tc[i].args[1])
79-
if tc[i].shouldErr {
80-
assert.NotNil(err, "Should have returned an error")
83+
for k := 0; k < len(tc[i].args); k = k + 2 {
84+
_, err := flogging.SetModuleLevel(tc[i].args[k], tc[i].args[k+1])
85+
if tc[i].shouldErr {
86+
assert.NotNil(err, "Should have returned an error")
87+
}
8188
}
82-
for k := 0; k < len(tc[i].expectedLevels); k++ {
83-
assert.Equal(tc[i].expectedLevels[k], flogging.GetModuleLevel(tc[i].modules[k]))
89+
for l := 0; l < len(tc[i].expectedLevels); l++ {
90+
assert.Equal(tc[i].expectedLevels[l], flogging.GetModuleLevel(tc[i].modules[l]))
91+
}
92+
if tc[i].revert {
93+
flogging.RevertToPeerStartupLevels()
94+
for m := 0; m < len(tc[i].modules); m++ {
95+
assert.Equal(flogging.GetPeerStartupLevel(tc[i].modules[m]), flogging.GetModuleLevel(tc[i].modules[m]))
96+
}
8497
}
85-
8698
if tc[i].withRegEx {
8799
// Force reset (a) in case the next test is non-regex, (b) so as
88100
// to reset the modules map and reuse module names.
89101
flogging.Reset()
90-
91102
}
92103
})
93104
}
94-
95105
}
96106

97107
func TestInitFromSpec(t *testing.T) {
@@ -120,25 +130,25 @@ func TestInitFromSpec(t *testing.T) {
120130
// MODULES
121131

122132
tc = append(tc,
123-
testCase{"SingleModuleLevel", []string{"a=info"}, []string{"INFO"}, []string{"a"}, false, false},
124-
testCase{"MultipleModulesMultipleLevels", []string{"a=info:b=debug"}, []string{"INFO", "DEBUG"}, []string{"a", "b"}, false, false},
125-
testCase{"MultipleModulesSameLevel", []string{"a,b=warning"}, []string{"WARNING", "WARNING"}, []string{"a", "b"}, false, false},
133+
testCase{"SingleModuleLevel", []string{"a=info"}, []string{"INFO"}, []string{"a"}, false, false, false},
134+
testCase{"MultipleModulesMultipleLevels", []string{"a=info:b=debug"}, []string{"INFO", "DEBUG"}, []string{"a", "b"}, false, false, false},
135+
testCase{"MultipleModulesSameLevel", []string{"a,b=warning"}, []string{"WARNING", "WARNING"}, []string{"a", "b"}, false, false, false},
126136
)
127137

128138
// MODULES + DEFAULT
129139

130140
tc = append(tc,
131-
testCase{"GlobalDefaultAndSingleModuleLevel", []string{"info:a=warning"}, []string{"INFO", "WARNING"}, []string{"", "a"}, false, false},
132-
testCase{"SingleModuleLevelAndGlobalDefaultAtEnd", []string{"a=warning:info"}, []string{"WARNING", "INFO"}, []string{"a", ""}, false, false},
141+
testCase{"GlobalDefaultAndSingleModuleLevel", []string{"info:a=warning"}, []string{"INFO", "WARNING"}, []string{"", "a"}, false, false, false},
142+
testCase{"SingleModuleLevelAndGlobalDefaultAtEnd", []string{"a=warning:info"}, []string{"WARNING", "INFO"}, []string{"a", ""}, false, false, false},
133143
)
134144

135145
// INVALID INPUT
136146

137147
tc = append(tc,
138-
testCase{"InvalidLevel", []string{"foo"}, []string{flogging.DefaultLevel()}, []string{""}, false, false},
139-
testCase{"InvalidLevelForSingleModule", []string{"a=foo"}, []string{flogging.DefaultLevel()}, []string{""}, false, false},
140-
testCase{"EmptyModuleEqualsLevel", []string{"=warning"}, []string{flogging.DefaultLevel()}, []string{""}, false, false},
141-
testCase{"InvalidModuleSyntax", []string{"a=b=c"}, []string{flogging.DefaultLevel()}, []string{""}, false, false},
148+
testCase{"InvalidLevel", []string{"foo"}, []string{flogging.DefaultLevel()}, []string{""}, false, false, false},
149+
testCase{"InvalidLevelForSingleModule", []string{"a=foo"}, []string{flogging.DefaultLevel()}, []string{""}, false, false, false},
150+
testCase{"EmptyModuleEqualsLevel", []string{"=warning"}, []string{flogging.DefaultLevel()}, []string{""}, false, false, false},
151+
testCase{"InvalidModuleSyntax", []string{"a=b=c"}, []string{flogging.DefaultLevel()}, []string{""}, false, false, false},
142152
)
143153

144154
assert := assert.New(t)

core/admin.go

+8
Original file line numberDiff line numberDiff line change
@@ -94,3 +94,11 @@ func (*ServerAdmin) SetModuleLogLevel(ctx context.Context, request *pb.LogLevelR
9494
logResponse := &pb.LogLevelResponse{LogModule: request.LogModule, LogLevel: logLevelString}
9595
return logResponse, err
9696
}
97+
98+
// RevertLogLevels reverts the log levels for all modules to the level
99+
// defined at the end of peer startup.
100+
func (*ServerAdmin) RevertLogLevels(context.Context, *empty.Empty) (*empty.Empty, error) {
101+
err := flogging.RevertToPeerStartupLevels()
102+
103+
return &empty.Empty{}, err
104+
}

peer/clilogging/common.go

+11-5
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,17 @@ import (
2525

2626
func checkLoggingCmdParams(cmd *cobra.Command, args []string) error {
2727
var err error
28-
29-
// check that at least one parameter is passed in
30-
if len(args) == 0 {
31-
err = errors.ErrorWithCallstack("Logging", "NoParameters", "No parameters provided.")
32-
return err
28+
if cmd.Name() == "revertlevels" {
29+
if len(args) > 0 {
30+
err = errors.ErrorWithCallstack("Logging", "ExtraParameters", "More parameters than necessary were provided. Expected 0, received %d.", len(args))
31+
return err
32+
}
33+
} else {
34+
// check that at least one parameter is passed in
35+
if len(args) == 0 {
36+
err = errors.ErrorWithCallstack("Logging", "NoParameters", "No parameters provided.")
37+
return err
38+
}
3339
}
3440

3541
if cmd.Name() == "setlevel" {

peer/clilogging/logging.go

+1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ var logger = logging.MustGetLogger("loggingCmd")
3232
func Cmd() *cobra.Command {
3333
loggingCmd.AddCommand(getLevelCmd())
3434
loggingCmd.AddCommand(setLevelCmd())
35+
loggingCmd.AddCommand(revertLevelsCmd())
3536

3637
return loggingCmd
3738
}

peer/clilogging/logging_test.go

+26-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ func TestGetLevel(t *testing.T) {
3939
err := checkLoggingCmdParams(getLevelCmd(), args)
4040

4141
if err != nil {
42-
t.FailNow()
42+
t.Fatal(err)
4343
}
4444
}
4545

@@ -93,6 +93,31 @@ func TestSetLevel(t *testing.T) {
9393
err := checkLoggingCmdParams(setLevelCmd(), args)
9494

9595
if err != nil {
96+
t.Fatal(err)
97+
}
98+
}
99+
100+
// TestRevertLevels tests the parameter checking for revertlevels, which
101+
// should return a nil error when zero parameters are provided
102+
func TestRevertLevels(t *testing.T) {
103+
var args []string
104+
105+
err := checkLoggingCmdParams(revertLevelsCmd(), args)
106+
107+
if err != nil {
108+
t.Fatal(err)
109+
}
110+
}
111+
112+
// TestRevertLevels_extraParameter tests the parameter checking for setlevel, which
113+
// should return an error when any amount of parameters are provided
114+
func TestRevertLevels_extraParameter(t *testing.T) {
115+
args := make([]string, 1)
116+
args[0] = "extraparameter"
117+
118+
err := checkLoggingCmdParams(revertLevelsCmd(), args)
119+
120+
if err == nil {
96121
t.FailNow()
97122
}
98123
}

peer/clilogging/revertlevels.go

+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
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 clilogging
18+
19+
import (
20+
"golang.org/x/net/context"
21+
22+
"github.com/golang/protobuf/ptypes/empty"
23+
"github.com/hyperledger/fabric/peer/common"
24+
25+
"github.com/spf13/cobra"
26+
)
27+
28+
func revertLevelsCmd() *cobra.Command {
29+
return loggingRevertLevelsCmd
30+
}
31+
32+
var loggingRevertLevelsCmd = &cobra.Command{
33+
Use: "revertlevels",
34+
Short: "Reverts the logging levels to the levels at the end of peer startup.",
35+
Long: `Reverts the logging levels to the levels at the end of peer startup`,
36+
Run: func(cmd *cobra.Command, args []string) {
37+
revertLevels(cmd, args)
38+
},
39+
}
40+
41+
func revertLevels(cmd *cobra.Command, args []string) (err error) {
42+
err = checkLoggingCmdParams(cmd, args)
43+
44+
if err != nil {
45+
logger.Warningf("Error: %s", err)
46+
} else {
47+
adminClient, err := common.GetAdminClient()
48+
if err != nil {
49+
logger.Warningf("%s", err)
50+
return err
51+
}
52+
53+
_, err = adminClient.RevertLogLevels(context.Background(), &empty.Empty{})
54+
55+
if err != nil {
56+
logger.Warningf("%s", err)
57+
return err
58+
}
59+
logger.Info("Log levels reverted to the levels at the end of peer startup.")
60+
}
61+
return err
62+
}

peer/node/start.go

+8
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import (
3030

3131
genesisconfig "github.com/hyperledger/fabric/common/configtx/tool/localconfig"
3232
"github.com/hyperledger/fabric/common/configtx/tool/provisional"
33+
"github.com/hyperledger/fabric/common/flogging"
3334
"github.com/hyperledger/fabric/common/localmsp"
3435
"github.com/hyperledger/fabric/common/util"
3536
"github.com/hyperledger/fabric/core"
@@ -264,6 +265,13 @@ func serve(args []string) error {
264265
common.SetLogLevelFromViper("error")
265266
common.SetLogLevelFromViper("msp")
266267

268+
// TODO This check is here to preserve the old functionality until all
269+
// other packages switch to `flogging.MustGetLogger` (from
270+
// `logging.MustGetLogger`).
271+
if flogging.IsSetLevelByRegExpEnabled {
272+
flogging.SetPeerStartupModulesMap()
273+
}
274+
267275
// Block until grpc server exits
268276
return <-serve
269277
}

0 commit comments

Comments
 (0)