@@ 32,6 32,7 @@ import (
"github.com/spf13/viper"
"go.uber.org/zap"
+ "go.uber.org/zap/zapcore"
)
// This struct contains all the fields required for sending a notification.
@@ 91,19 92,20 @@ type ValidConfigurationOptions struct {
// This function initializes the ValidConfigurationOptions data structure, which will be
// used by the configuration sanity checker down the road, to make sure that everything
// is nice and shiny.
-func initializeValidConfigurationOptions(ValidConfigurationOptions *ValidConfigurationOptions, logger *zap.SugaredLogger) {
+func initializeValidConfigurationOptions(ValidConfigurationOptions *ValidConfigurationOptions) {
ValidConfigurationOptions.possibleLogLevels = []string{"debug", "info", "warning", "error", "fatal", "panic"}
}
// This function stores and applies the defaults of the application.
// It's called first to initialize the defaults, then config file and the lastly the flags
// Can change these defaults.
-func applyDefaultConfiguration(runtimeConfiguration *RuntimeConfiguration, notificationToSend *Notification, logger *zap.SugaredLogger) {
+func applyDefaultConfiguration(runtimeConfiguration *RuntimeConfiguration, notificationToSend *Notification) {
// Get the notificationTitle first. We will use it for message titles, as default
notificationTitle, err := os.Hostname()
if err != nil {
- logger.Warnf("Encountered an error while obtaining hostname, will use \"Nudge\" instead.")
+ // Since logger is not up when we call this function, we'll use Println here.
+ fmt.Println("Encountered an error while obtaining hostname, will use \"Nudge\" instead.")
notificationTitle = "Nudge"
}
@@ 117,10 119,10 @@ func applyDefaultConfiguration(runtimeConfiguration *RuntimeConfiguration, notif
// Let's set defaults for the application itself, again where it makes sense.
applicationName := strings.Split(os.Args[0], "/")
runtimeConfiguration.applicationName = applicationName[len(applicationName)-1]
- runtimeConfiguration.version = "0.1.0"
+ runtimeConfiguration.version = "0.2.0a20230729"
runtimeConfiguration.dryrun = false
runtimeConfiguration.logfilePaths = []string{"stdout"}
- runtimeConfiguration.logLevel = "info"
+ runtimeConfiguration.logLevel = "warning"
}
// This function reads the configuration file and applies it to relevant data structures.
@@ 293,6 295,30 @@ func applyFlags(setFlags *[]string, flagStorage *FlagStorage, runtimeConfigurati
logger.Debugf("Application of flags is completed, returning.")
}
+/*
+ * This function returns the appropriate Zap level for configuring the logger on the fly.
+ * As a precaution, this function returns a sane default (INFO) if the supplied level
+ * makes no sense.
+ */
+func getZapLoggerLevel(logLevel *string) zap.AtomicLevel {
+ switch *logLevel {
+ case "debug", "DEBUG":
+ return zap.NewAtomicLevelAt(zapcore.DebugLevel)
+ case "info", "INFO":
+ return zap.NewAtomicLevelAt(zapcore.InfoLevel)
+ case "warning", "WARNING":
+ return zap.NewAtomicLevelAt(zapcore.WarnLevel)
+ case "error", "ERROR":
+ return zap.NewAtomicLevelAt(zapcore.ErrorLevel)
+ case "fatal", "FATAL":
+ return zap.NewAtomicLevelAt(zapcore.FatalLevel)
+ case "panic", "PANIC":
+ return zap.NewAtomicLevelAt(zapcore.PanicLevel)
+ default:
+ return zap.NewAtomicLevel()
+ }
+}
+
// This function checks configuration sanity when called, and creates warnings or errors depending on the situation.
// This function also called just before sending the notification, hence it handles showing help, creating warnings and other
// related user interfacing notifications.
@@ 393,9 419,24 @@ func main() {
// Since there's no easy way to check whether a flag is set, I need a list of set flags.
var setFlags []string
+ // Start by applying default configuration before building things up.
+ // Start with initializing valid configuration space.
+ initializeValidConfigurationOptions(&validConfigurationOptions)
+
+ // Next, apply the defaults:
+ applyDefaultConfiguration(&runtimeConfiguration, ¬ificationToSend)
+
// TODO: Prettify logger with some stylistic configuration here.
// Relevant documentation is here: https://pkg.go.dev/go.uber.org/zap#hdr-Configuring_Zap
-
+ /*
+ * To be able to ship 0.2 as quickly as possible, Zap will be configured as follows:
+ * 1- Create a good enough configuration with JSON based on system defaults.
+ * 2- Build Zap with that configuration.
+ * 3- Reconfigure Zap after parsing all the options and creating the final runtime
+ * configuration.
+ *
+ * XXX: This JSON config part will be replaced with a programmatic block later.
+ */
zapDefaultConfigJSON := []byte(`{
"level": "debug",
"encoding": "console",
@@ 410,11 451,14 @@ func main() {
}
}`)
- var cfg zap.Config
- if err := json.Unmarshal(zapDefaultConfigJSON, &cfg); err != nil {
+ var zapDefaultConfig zap.Config
+ if err := json.Unmarshal(zapDefaultConfigJSON, &zapDefaultConfig); err != nil {
panic(err)
}
- logger := zap.Must(cfg.Build())
+
+ // Let's change the logger's logging level before building the logger.
+ zapDefaultConfig.Level = getZapLoggerLevel(&runtimeConfiguration.logLevel)
+ logger := zap.Must(zapDefaultConfig.Build())
defer logger.Sync() // Make sure that we sync when we exit.
@@ 422,12 466,6 @@ func main() {
sugaredLogger := logger.Sugar()
sugaredLogger.Debugf("Logger is up.")
- // Start with initializing valid configuration space.
- initializeValidConfigurationOptions(&validConfigurationOptions, sugaredLogger)
-
- // Next, apply the defaults:
- applyDefaultConfiguration(&runtimeConfiguration, ¬ificationToSend, sugaredLogger)
-
// Then let's see what we have at hand (options, parameters, flags).
// Flags are parsed first, stored in a secondary config area.
// This allows us to override config file with flags more gracefully.
@@ 444,6 482,10 @@ func main() {
flag.Visit(func(setFlag *flag.Flag) {
setFlags = append(setFlags, setFlag.Name)
})
+
+ // Run all the configuration checks and issue relevant warnings or errors.
+ // TODO: Is here the best place to call this? Take a look before releasing.
+ checkConfigurationSanity(¬ificationToSend, &runtimeConfiguration, &validConfigurationOptions, sugaredLogger)
// Then I can apply the set flags.
applyFlags(&setFlags, &flagStorage, &runtimeConfiguration, ¬ificationToSend, sugaredLogger)
@@ 457,15 499,12 @@ func main() {
// If no message is given, let's print help and exit.
if notificationToSend.messageBody == "" {
- sugaredLogger.Errorf("No message body specified, exiting.")
- sugaredLogger.Errorf("Usage: %s [OPTIONS] message", runtimeConfiguration.applicationName)
+ sugaredLogger.Debugf("No message body specified, exiting.")
+ fmt.Printf("Usage: %s [OPTIONS] message\n", runtimeConfiguration.applicationName)
flag.PrintDefaults()
os.Exit(1)
}
- // Run all the configuration checks and issue relevant warnings or errors.
- checkConfigurationSanity(¬ificationToSend, &runtimeConfiguration, &validConfigurationOptions, sugaredLogger)
-
// Show the current state of the code.
printState(&runtimeConfiguration, ¬ificationToSend, sugaredLogger)
@@ 473,6 512,6 @@ func main() {
if runtimeConfiguration.dryrun == false {
sendNotification(¬ificationToSend, &runtimeConfiguration)
} else {
- sugaredLogger.Infow("Not sending the notification since in dry run mode.")
+ sugaredLogger.Warnf("Not sending the notification since in dry run mode.")
}
}