[VOL-1414] Update voltha CLI to support dynamic logging. This
update also cleans up the log library as well as remove XPON
from the CLI.
Change-Id: Ife44abdcca7ac078f29db297d94a4b96f66b1514
diff --git a/common/log/log.go b/common/log/log.go
index 0128b7d..408158a 100644
--- a/common/log/log.go
+++ b/common/log/log.go
@@ -125,7 +125,7 @@
parent *zp.Logger
}
-func parseAtomicLevel(l int) zp.AtomicLevel {
+func intToAtomicLevel(l int) zp.AtomicLevel {
switch l {
case DebugLevel:
return zp.NewAtomicLevelAt(zc.DebugLevel)
@@ -143,12 +143,12 @@
return zp.NewAtomicLevelAt(zc.ErrorLevel)
}
-func parseLevel(l int) zc.Level {
+func intToLevel(l int) zc.Level {
switch l {
case DebugLevel:
return zc.DebugLevel
case InfoLevel:
- return InfoLevel
+ return zc.InfoLevel
case WarnLevel:
return zc.WarnLevel
case ErrorLevel:
@@ -161,9 +161,28 @@
return zc.ErrorLevel
}
+func levelToInt(l zc.Level) int {
+ switch l {
+ case zc.DebugLevel:
+ return DebugLevel
+ case zc.InfoLevel:
+ return InfoLevel
+ case zc.WarnLevel:
+ return WarnLevel
+ case zc.ErrorLevel:
+ return ErrorLevel
+ case zc.PanicLevel:
+ return PanicLevel
+ case FatalLevel:
+ return FatalLevel
+ }
+ return ErrorLevel
+}
+
+
func getDefaultConfig(outputType string, level int, defaultFields Fields) zp.Config {
return zp.Config{
- Level: parseAtomicLevel(level),
+ Level: intToAtomicLevel(level),
Encoding: outputType,
Development: true,
OutputPaths: []string{"stdout"},
@@ -210,14 +229,23 @@
//instead of using the publicly available functions in this log package then a number of functionalities will not
// be available to it, notably log tracing with filename.functionname.linenumber annotation.
//
-func AddPackage(outputType string, level int, defaultFields Fields) (Logger, error) {
+// pkgNames parameter should be used for testing only as this function detects the caller's package.
+func AddPackage(outputType string, level int, defaultFields Fields, pkgNames ...string) (Logger, error) {
if cfgs == nil {
cfgs = make(map[string]zp.Config)
}
if loggers == nil {
loggers = make(map[string]*logger)
}
- pkgName, _, _, _ := getCallerInfo()
+
+ var pkgName string
+ for _, name := range pkgNames {
+ pkgName = name
+ break
+ }
+ if pkgName == "" {
+ pkgName, _, _, _ = getCallerInfo()
+ }
if _, exist := loggers[pkgName]; exist {
return loggers[pkgName], nil
@@ -294,60 +322,7 @@
return loggers[pkgName], nil
}
-//SetPackageLogLevel dynamically sets the log level of a given package to level. This is typically invoked at an
-// application level during debugging
-func SetPackageLogLevel(packageName string, level int) {
- // Get proper config
- if cfg, ok := cfgs[packageName]; ok {
- switch level {
- case DebugLevel:
- cfg.Level.SetLevel(zc.DebugLevel)
- case InfoLevel:
- cfg.Level.SetLevel(zc.InfoLevel)
- case WarnLevel:
- cfg.Level.SetLevel(zc.WarnLevel)
- case ErrorLevel:
- cfg.Level.SetLevel(zc.ErrorLevel)
- case PanicLevel:
- cfg.Level.SetLevel(zc.PanicLevel)
- case FatalLevel:
- cfg.Level.SetLevel(zc.FatalLevel)
- default:
- cfg.Level.SetLevel(zc.ErrorLevel)
- }
- }
-}
-
-//SetAllLogLevel sets the log level of all registered packages to level
-func SetAllLogLevel(level int) {
- // Get proper config
- for _, cfg := range cfgs {
- switch level {
- case DebugLevel:
- cfg.Level.SetLevel(zc.DebugLevel)
- case InfoLevel:
- cfg.Level.SetLevel(zc.InfoLevel)
- case WarnLevel:
- cfg.Level.SetLevel(zc.WarnLevel)
- case ErrorLevel:
- cfg.Level.SetLevel(zc.ErrorLevel)
- case PanicLevel:
- cfg.Level.SetLevel(zc.PanicLevel)
- case FatalLevel:
- cfg.Level.SetLevel(zc.FatalLevel)
- default:
- cfg.Level.SetLevel(zc.ErrorLevel)
- }
- }
-}
-
-//SetLogLevel sets the log level for the logger corresponding to the caller's package
-func SetLogLevel(level int) error {
- pkgName, _, _, _ := getCallerInfo()
- if _, exist := cfgs[pkgName]; !exist {
- return errors.New(fmt.Sprint("unregistered-package-%s", pkgName))
- }
- cfg := cfgs[pkgName]
+func setLevel(cfg zp.Config, level int) {
switch level {
case DebugLevel:
cfg.Level.SetLevel(zc.DebugLevel)
@@ -364,6 +339,41 @@
default:
cfg.Level.SetLevel(zc.ErrorLevel)
}
+}
+
+//SetPackageLogLevel dynamically sets the log level of a given package to level. This is typically invoked at an
+// application level during debugging
+func SetPackageLogLevel(packageName string, level int) {
+ // Get proper config
+ if cfg, ok := cfgs[packageName]; ok {
+ setLevel(cfg, level)
+ }
+}
+
+//SetAllLogLevel sets the log level of all registered packages to level
+func SetAllLogLevel(level int) {
+ // Get proper config
+ for _, cfg := range cfgs {
+ setLevel(cfg, level)
+ }
+}
+
+//GetPackageLogLevel returns the current log level of a package.
+func GetPackageLogLevel(packageName string) (int, error) {
+ if cfg, ok := cfgs[packageName]; ok {
+ return levelToInt(cfg.Level.Level()), nil
+ }
+ return 0, errors.New(fmt.Sprintf("unknown-package-%s", packageName))
+}
+
+//SetLogLevel sets the log level for the logger corresponding to the caller's package
+func SetLogLevel(level int) error {
+ pkgName, _, _, _ := getCallerInfo()
+ if _, exist := cfgs[pkgName]; !exist {
+ return errors.New(fmt.Sprintf("unregistered-package-%s", pkgName))
+ }
+ cfg := cfgs[pkgName]
+ setLevel(cfg, level)
return nil
}
@@ -593,7 +603,7 @@
// V reports whether verbosity level l is at least the requested verbose level.
func (l logger) V(level int) bool {
- return l.parent.Core().Enabled(parseLevel(level))
+ return l.parent.Core().Enabled(intToLevel(level))
}
// With returns a logger initialized with the key-value pairs
diff --git a/common/log/log_test.go b/common/log/log_test.go
index 68d6ba3..88794b2 100644
--- a/common/log/log_test.go
+++ b/common/log/log_test.go
@@ -16,7 +16,6 @@
package log
import (
- "github.com/opencord/voltha-go/common/log"
"github.com/stretchr/testify/assert"
"google.golang.org/grpc/grpclog"
"testing"
@@ -26,17 +25,17 @@
Prerequite: Start the kafka/zookeeper containers.
*/
-var testLogger log.Logger
+var testLogger Logger
func TestInit(t *testing.T) {
var err error
- testLogger, err = log.AddPackage(log.JSON, log.ErrorLevel, nil)
+ testLogger, err = AddPackage(JSON, ErrorLevel, nil)
assert.NotNil(t, testLogger)
assert.Nil(t, err)
}
func verifyLogLevel(t *testing.T, minimumLevel int) {
- log.SetAllLogLevel(minimumLevel)
+ SetAllLogLevel(minimumLevel)
var success bool
for i := 0; i < 6; i++ {
success = testLogger.V(i)
@@ -60,19 +59,47 @@
}
func TestUpdateAllLoggers(t *testing.T) {
- err := log.UpdateAllLoggers(log.Fields{"update": "update"})
+ err := UpdateAllLoggers(Fields{"update": "update"})
assert.Nil(t, err)
}
func TestUpdateLoggers(t *testing.T) {
- testLogger, err := log.UpdateLogger(log.Fields{"update": "update"})
+ testLogger, err := UpdateLogger(Fields{"update": "update"})
assert.Nil(t, err)
assert.NotNil(t, testLogger)
}
func TestUseAsGrpcLoggerV2(t *testing.T) {
var grpcLogger grpclog.LoggerV2
- thisLogger, _ := log.AddPackage(log.JSON, log.ErrorLevel, nil)
+ thisLogger, _ := AddPackage(JSON, ErrorLevel, nil)
grpcLogger = thisLogger
assert.NotNil(t, grpcLogger)
}
+
+func TestUpdateLogLevel(t *testing.T) {
+ // Let's create a bunch of logger each with a separate package
+ myLoggers := make(map[string]Logger)
+ pkgNames := []string{"/rw_core/core", "/db/model", "/kafka"}
+ for _, name := range pkgNames {
+ myLoggers[name], _ = AddPackage(JSON, ErrorLevel, nil, []string{name}...)
+ }
+ //Test updates to log levels
+ levels := []int{0, 1, 2, 3, 4, 5}
+ for _, expectedLevel := range levels {
+ for _, name := range pkgNames {
+ SetPackageLogLevel(name, expectedLevel)
+ l, err := GetPackageLogLevel(name)
+ assert.Nil(t, err)
+ assert.Equal(t, l, expectedLevel)
+ }
+ }
+ //Test set all package level
+ for _, expectedLevel := range levels {
+ SetAllLogLevel(expectedLevel)
+ for _, name := range pkgNames {
+ l, err := GetPackageLogLevel(name)
+ assert.Nil(t, err)
+ assert.Equal(t, l, expectedLevel)
+ }
+ }
+}
diff --git a/python/cli/main.py b/python/cli/main.py
index 00ea702..0fc9b5b 100755
--- a/python/cli/main.py
+++ b/python/cli/main.py
@@ -156,6 +156,41 @@
while self.history:
self.history.pop()
+ @options([
+ make_option('-p', '--package', action="store", dest='package',
+ help="Package Name"),
+ make_option('-l', '--level', action='store', dest='level'),
+ ])
+ def do_log(self, line, opts):
+
+ def logLevel(level):
+ switcher= {
+ "DEBUG": 0,
+ "INFO":1,
+ "WARNING":2,
+ "ERROR":3,
+ "CRITICAL":4,
+ "FATAL":5
+ }
+ return switcher.get(level, 3)
+
+ if opts.level is None:
+ return
+
+ stub = self.get_stub()
+ kw = dict()
+ if opts.package:
+ kw['package_name'] = "github.com/opencord/voltha-go/" + opts.package
+
+ kw['level'] = logLevel(opts.level.upper())
+
+ try:
+ logging = voltha_pb2.Logging(**kw)
+ stub.UpdateLogLevel(logging)
+ self.poutput('success')
+ except Exception as e:
+ self.poutput('Exception - {})'.format(e))
+
def do_launch(self, line):
"""If Voltha is not running yet, launch it"""
raise NotImplementedError('not implemented yet')
@@ -267,21 +302,6 @@
if d.startswith(text)]
return completions
- def do_xpon(self, line):
- """xpon <optional> [device_ID] - Enter xpon level command mode"""
- device_id = line.strip()
- if device_id:
- stub = self.get_stub()
- try:
- res = stub.GetDevice(voltha_pb2.ID(id=device_id))
- except Exception:
- self.poutput(
- self.colorize('Error: ', 'red') + 'No device id ' +
- self.colorize(device_id, 'blue') + ' is found')
- return
- sub = XponCli(self.get_channel, device_id)
- sub.cmdloop()
-
def do_omci(self, line):
"""omci <device_ID> - Enter OMCI level command mode"""
diff --git a/rw_core/core/grpc_nbi_api_handler.go b/rw_core/core/grpc_nbi_api_handler.go
index 0cb9a14..d11c420 100644
--- a/rw_core/core/grpc_nbi_api_handler.go
+++ b/rw_core/core/grpc_nbi_api_handler.go
@@ -128,9 +128,13 @@
}
func (handler *APIHandler) UpdateLogLevel(ctx context.Context, logging *voltha.Logging) (*empty.Empty, error) {
- log.Debugw("UpdateLogLevel-request", log.Fields{"newloglevel": logging.Level, "intval": int(logging.Level)})
+ log.Debugw("UpdateLogLevel-request", log.Fields{"package": logging.PackageName, "intval": int(logging.Level)})
out := new(empty.Empty)
- log.SetPackageLogLevel(logging.PackageName, int(logging.Level))
+ if logging.PackageName == "" {
+ log.SetAllLogLevel(int(logging.Level))
+ } else {
+ log.SetPackageLogLevel(logging.PackageName, int(logging.Level))
+ }
return out, nil
}