func UpdateLevelFromConfigMap(logger *zap.SugaredLogger, atomicLevel zap.AtomicLevel,
	levelKey string) func(configMap *corev1.ConfigMap) {
	return func(configMap *corev1.ConfigMap) {
		loggingConfig, err := NewConfigFromConfigMap(configMap)
		if err != nil {
			logger.Errorw("Failed to parse the logging configmap. Previous config map will be used.", zap.Error(err))
			return
		}
		level := loggingConfig.LoggingLevel[levelKey]
		if atomicLevel.Level() != level {
			logger.Infof("Updating logging level for %v from %v to %v.", levelKey, atomicLevel.Level(), level)
			atomicLevel.SetLevel(level)
		}
	}
}
UpdateLevelFromConfigMap returns a helper func that can be used to update the logging level
when a config map is updated
package logging
import (
	"encoding/json"
	"errors"
	"fmt"
	"os"
	"strings"
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
	corev1 "k8s.io/api/core/v1"
	"github.com/knative/pkg/changeset"
	"github.com/knative/pkg/logging/logkey"
)
const ConfigMapNameEnv = "CONFIG_LOGGING_NAME"
func NewLogger(configJSON string, levelOverride string, opts ...zap.Option) (*zap.SugaredLogger, zap.AtomicLevel) {
	logger, atomicLevel, err := newLoggerFromConfig(configJSON, levelOverride, opts)
	if err == nil {
		return enrichLoggerWithCommitID(logger.Sugar()), atomicLevel
	}
	loggingCfg := zap.NewProductionConfig()
	if len(levelOverride) > 0 {
		if level, err := levelFromString(levelOverride); err == nil {
			loggingCfg.Level = zap.NewAtomicLevelAt(*level)
		}
	}
	logger, err2 := loggingCfg.Build(opts...)
	if err2 != nil {
		panic(err2)
	}
	return enrichLoggerWithCommitID(logger.Named("fallback-logger").Sugar()), loggingCfg.Level
}
func enrichLoggerWithCommitID(logger *zap.SugaredLogger) *zap.SugaredLogger {
	commmitID, err := changeset.Get()
	if err == nil {
		return logger.With(zap.String(logkey.GitHubCommitID, commmitID))
	}
	logger.Warnf("Fetch GitHub commit ID from kodata failed: %v", err)
	return logger
}
func NewLoggerFromConfig(config *Config, name string, opts ...zap.Option) (*zap.SugaredLogger, zap.AtomicLevel) {
	logger, level := NewLogger(config.LoggingConfig, config.LoggingLevel[name].String(), opts...)
	return logger.Named(name), level
}
func newLoggerFromConfig(configJSON string, levelOverride string, opts []zap.Option) (*zap.Logger, zap.AtomicLevel, error) {
	if len(configJSON) == 0 {
		return nil, zap.AtomicLevel{}, errors.New("empty logging configuration")
	}
	var loggingCfg zap.Config
	if err := json.Unmarshal([]byte(configJSON), &loggingCfg); err != nil {
		return nil, zap.AtomicLevel{}, err
	}
	if len(levelOverride) > 0 {
		if level, err := levelFromString(levelOverride); err == nil {
			loggingCfg.Level = zap.NewAtomicLevelAt(*level)
		}
	}
	logger, err := loggingCfg.Build(opts...)
	if err != nil {
		return nil, zap.AtomicLevel{}, err
	}
	logger.Info("Successfully created the logger.", zap.String(logkey.JSONConfig, configJSON))
	logger.Sugar().Infof("Logging level set to %v", loggingCfg.Level)
	return logger, loggingCfg.Level, nil
}
type Config struct {
	LoggingConfig string
	LoggingLevel  map[string]zapcore.Level
}
const defaultZLC = `{
  "level": "info",
  "development": false,
  "outputPaths": ["stdout"],
  "errorOutputPaths": ["stderr"],
  "encoding": "json",
  "encoderConfig": {
    "timeKey": "ts",
    "levelKey": "level",
    "nameKey": "logger",
    "callerKey": "caller",
    "messageKey": "msg",
    "stacktraceKey": "stacktrace",
    "lineEnding": "",
    "levelEncoder": "",
    "timeEncoder": "iso8601",
    "durationEncoder": "",
    "callerEncoder": ""
  }
}`
func NewConfigFromMap(data map[string]string) (*Config, error) {
	lc := &Config{}
	if zlc, ok := data["zap-logger-config"]; ok {
		lc.LoggingConfig = zlc
	} else {
		lc.LoggingConfig = defaultZLC
	}
	lc.LoggingLevel = make(map[string]zapcore.Level)
	for k, v := range data {
		if component := strings.TrimPrefix(k, "loglevel."); component != k && component != "" {
			if len(v) > 0 {
				level, err := levelFromString(v)
				if err != nil {
					return nil, err
				}
				lc.LoggingLevel[component] = *level
			}
		}
	}
	return lc, nil
}
func NewConfigFromConfigMap(configMap *corev1.ConfigMap) (*Config, error) {
	return NewConfigFromMap(configMap.Data)
}
func levelFromString(level string) (*zapcore.Level, error) {
	var zapLevel zapcore.Level
	if err := zapLevel.UnmarshalText([]byte(level)); err != nil {
		return nil, fmt.Errorf("invalid logging level: %v", level)
	}
	return &zapLevel, nil
}