[VOL-2758] [VOL-2759] Write default loglevel to KV store on Pod startup
Change-Id: Ie8972a61a24173939de99e8d348a6df02ae7d23c
diff --git a/VERSION b/VERSION
index 7003379..6795d4d 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-3.0.21
+3.0.22
diff --git a/pkg/config/configmanager.go b/pkg/config/configmanager.go
index e85cfa7..57d79e5 100644
--- a/pkg/config/configmanager.go
+++ b/pkg/config/configmanager.go
@@ -211,6 +211,25 @@
}
}
+// Retrieves value of a specific config key. Value of key is returned in String format
+func (c *ComponentConfig) Retrieve(ctx context.Context, configKey string) (string, error) {
+ key := c.makeConfigPath() + "/" + configKey
+
+ log.Debugw("retrieving-config", log.Fields{"key": key})
+
+ if kvpair, err := c.cManager.backend.Get(ctx, key); err != nil {
+ return "", err
+ } else {
+ if kvpair == nil {
+ return "", fmt.Errorf("config-key-does-not-exist : %s", key)
+ }
+
+ value := strings.Trim(fmt.Sprintf("%s", kvpair.Value), "\"")
+ log.Debugw("retrieved-config", log.Fields{"key": key, "value": value})
+ return value, nil
+ }
+}
+
func (c *ComponentConfig) RetrieveAll(ctx context.Context) (map[string]string, error) {
key := c.makeConfigPath()
@@ -237,7 +256,7 @@
func (c *ComponentConfig) Save(ctx context.Context, configKey string, configValue string) error {
key := c.makeConfigPath() + "/" + configKey
- log.Debugw("saving-key", log.Fields{"key": key, "value": configValue})
+ log.Debugw("saving-config", log.Fields{"key": key, "value": configValue})
//save the data for update config
if err := c.cManager.backend.Put(ctx, key, configValue); err != nil {
@@ -250,7 +269,7 @@
//construct key using makeConfigPath
key := c.makeConfigPath() + "/" + configKey
- log.Debugw("deleting-key", log.Fields{"key": key})
+ log.Debugw("deleting-config", log.Fields{"key": key})
//delete the config
if err := c.cManager.backend.Delete(ctx, key); err != nil {
return err
diff --git a/pkg/config/logcontroller.go b/pkg/config/logcontroller.go
index 5579e04..65927e6 100644
--- a/pkg/config/logcontroller.go
+++ b/pkg/config/logcontroller.go
@@ -14,8 +14,10 @@
* limitations under the License.
*/
-// Package Config provides dynamic logging configuration for specific Voltha component type implemented using backend.The package can be used in following manner
-// Any Voltha component type can start dynamic logging by starting goroutine of ProcessLogConfigChange after starting kvClient for the component.
+// Package Config provides dynamic logging configuration for specific Voltha component with loglevel lookup
+// from etcd kvstore implemented using backend.
+// Any Voltha component can start utilizing dynamic logging by starting goroutine of StartLogLevelConfigProcessing after
+// starting kvClient for the component.
package config
@@ -30,9 +32,9 @@
)
const (
- defaultLogLevelKey = "default" // kvstore key containing default loglevel
- globalConfigRootNode = "global" // Root Node in kvstore containing global config
- // that is applicable; unless overridden by individual component
+ defaultLogLevelKey = "default" // kvstore key containing default loglevel
+ globalConfigRootNode = "global" // Root Node in kvstore containing global config
+ initialGlobalDefaultLogLevelValue = "WARN" // Hard-coded Global Default loglevel pushed at PoD startup
)
// ComponentLogController represents a Configuration for Logging Config of specific Voltha component type
@@ -72,8 +74,10 @@
}
-// ProcessLogConfigChange initialize component config and global config
-func ProcessLogConfigChange(cm *ConfigManager, ctx context.Context) {
+// StartLogLevelConfigProcessing initialize component config and global config
+// Then, it persists initial default Loglevels into Config Store before
+// starting the loading and processing of all Log Configuration
+func StartLogLevelConfigProcessing(cm *ConfigManager, ctx context.Context) {
cc, err := NewComponentLogController(cm)
if err != nil {
log.Errorw("unable-to-construct-component-log-controller-instance-for-log-config-monitoring", log.Fields{"error": err})
@@ -86,9 +90,36 @@
cc.componentNameConfig = cm.InitComponentConfig(cc.ComponentName, ConfigTypeLogLevel)
log.Debugw("component-log-config", log.Fields{"cc-component-name-config": cc.componentNameConfig})
+ cc.persistInitialDefaultLogConfigs(ctx)
+
cc.processLogConfig(ctx)
}
+// Method to persist Global default loglevel into etcd, if not set yet
+// It also checks and set Component default loglevel into etcd with initial loglevel set from command line
+func (c *ComponentLogController) persistInitialDefaultLogConfigs(ctx context.Context) {
+
+ _, err := c.GlobalConfig.Retrieve(ctx, defaultLogLevelKey)
+ if err != nil {
+ log.Debugw("failed-to-retrieve-global-default-log-config-at-startup", log.Fields{"error": err})
+
+ err = c.GlobalConfig.Save(ctx, defaultLogLevelKey, initialGlobalDefaultLogLevelValue)
+ if err != nil {
+ log.Errorw("failed-to-persist-global-default-log-config-at-startup", log.Fields{"error": err, "loglevel": initialGlobalDefaultLogLevelValue})
+ }
+ }
+
+ _, err = c.componentNameConfig.Retrieve(ctx, defaultLogLevelKey)
+ if err != nil {
+ log.Debugw("failed-to-retrieve-component-default-log-config-at-startup", log.Fields{"error": err})
+
+ err = c.componentNameConfig.Save(ctx, defaultLogLevelKey, c.initialLogLevel)
+ if err != nil {
+ log.Errorw("failed-to-persist-component-default-log-config-at-startup", log.Fields{"error": err, "loglevel": c.initialLogLevel})
+ }
+ }
+}
+
// ProcessLogConfig will first load and apply log config and then start waiting on component config and global config
// channels for any changes. Event channel will be recieved from backend for valid change type
// Then data for componentn log config and global log config will be retrieved from backend and stored in updatedLogConfig in precedence order
@@ -163,21 +194,24 @@
func (c *ComponentLogController) getGlobalLogConfig(ctx context.Context) (string, error) {
- globalDefaultLogLevel := ""
- globalLogConfig, err := c.GlobalConfig.RetrieveAll(ctx)
+ globalDefaultLogLevel, err := c.GlobalConfig.Retrieve(ctx, defaultLogLevelKey)
if err != nil {
return "", err
}
- if globalLevel, ok := globalLogConfig[defaultLogLevelKey]; ok {
- if _, err := log.StringToLogLevel(globalLevel); err != nil {
- log.Warnw("unsupported-loglevel-config-defined-at-global-context-package-name", log.Fields{"log-level": globalLevel})
- } else {
- globalDefaultLogLevel = globalLevel
- }
+ // Handle edge cases when global default loglevel is deleted directly from etcd or set to a invalid value
+ // We should use hard-coded initial default value in such cases
+ if globalDefaultLogLevel == "" {
+ log.Warn("global-default-loglevel-not-found-in-config-store")
+ globalDefaultLogLevel = initialGlobalDefaultLogLevelValue
}
- log.Debugw("retrieved-global-log-config", log.Fields{"global-log-config": globalLogConfig})
+ if _, err := log.StringToLogLevel(globalDefaultLogLevel); err != nil {
+ log.Warnw("unsupported-loglevel-config-defined-at-global-default", log.Fields{"log-level": globalDefaultLogLevel})
+ globalDefaultLogLevel = initialGlobalDefaultLogLevelValue
+ }
+
+ log.Debugw("retrieved-global-default-loglevel", log.Fields{"level": globalDefaultLogLevel})
return globalDefaultLogLevel, nil
}
@@ -201,14 +235,10 @@
}
// if default loglevel is not configured for the component, component should use
- // - default loglevel configured at global level, if set
+ // default loglevel configured at global level
if effectiveDefaultLogLevel == "" {
effectiveDefaultLogLevel = globalDefaultLogLevel
}
- // - else, use initial loglevel which component was started with (set from helm chart)
- if effectiveDefaultLogLevel == "" {
- effectiveDefaultLogLevel = c.initialLogLevel
- }
componentLogConfig[defaultLogLevelKey] = effectiveDefaultLogLevel
@@ -226,7 +256,7 @@
func (c *ComponentLogController) buildUpdatedLogConfig(ctx context.Context) (map[string]string, error) {
globalLogLevel, err := c.getGlobalLogConfig(ctx)
if err != nil {
- return nil, err
+ log.Errorw("unable-to-retrieve-global-log-config", log.Fields{"err": err})
}
componentLogConfig, err := c.getComponentLogConfig(ctx, globalLogLevel)