Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v0.1.10 alignment #7

Merged
merged 7 commits into from
Nov 23, 2023
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
# Changelog

## [0.1.10](https://github.com/furan917/MageComm/compare/v0.1.9...v0.1.10) (2023-11-23)


### Bug Fixes

* log formatting + add disallow override file option to config ([544767e](https://github.com/furan917/MageComm/commit/544767eb153363ee7707b6ceb30ca8cf432cfa99))
* magerun command now handles config override correctly ([66eb5ea](https://github.com/furan917/MageComm/commit/66eb5eaad38b6dfaa885061779aa3218ccf162d5))
* small fix for graceful interupts + some whitespacing fixes ([229a649](https://github.com/furan917/MageComm/commit/229a649443ffa8da1dd849ff26231e7ede389885))

## [0.1.9](https://github.com/furan917/MageComm/compare/v0.1.8...v0.1.9) (2023-10-11)


Expand Down
17 changes: 12 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@ As this is an akoova specific fork, we will be using akoova specific tag nomencl

## Beta
Currently this tool is in beta, and is not recommended for production use.
Tested commands: RMQ based magerun command publishing, message listening, cat all supported archive types


## Installation

Expand All @@ -37,6 +35,7 @@ Download the latest release from the [releases page](https://github.com/furan917

example config.yml:
```
disallow_configfile_overwrite: true
magecomm_log_path: /var/log/magecomm.log
magecomm_log_level: warn
magecomm_max_operational_cpu_limit: 80
Expand Down Expand Up @@ -79,6 +78,7 @@ magecomm_required_magerun_command_args:
example config.json:
```
{
"disallow_configfile_overwrite": true,
"magecomm_log_path": "/var/log/magecomm.log",
"magecomm_log_level": "warn",
"magecomm_max_operational_cpu_limit": 80,
Expand Down Expand Up @@ -132,11 +132,14 @@ example config.json:
### Global Flags

- `--debug`: Enable debug mode
- `--config`: Path to overwrite config file, argument can be disabled by default config file

e.g
`magecomm --debug listen`
`magecomm --debug magerun cache:clean`
`magecomm --debug cat path/to/archive.tar.gz /path/to/file.txt`
`magecomm --config=/custom/config/path.json magerun indexer:status`
`magecomm --config=/custom/config/path.json --debug magerun indexer:reindex`

### Commands

Expand All @@ -158,11 +161,15 @@ e.g

## Configuration

The tool can be configured using a yaml or json config file at `/etc/magecomm/`(unix) / `%APPDATA%\magecomm\`(windows) or by environment variables.
lowercase for file based config, uppercase for ENV.
The tool can be configured using a yaml or json config file at `/etc/magecomm/` (unix) | `%APPDATA%\magecomm\` (windows), or using `--config=/custom/config/path.json` before the command e.g. `magecomm --config=... magerun`, or by ENV variables.
Magecomm has a fallback strategy of, config file -> ENV -> default values

_You can disable by the config override argument by placing `disallow_configfile_overwrite: true` in the default config file_

The tool supports slack command run notifications via Webhook or App integration
The tool can also supports slack command run notifications via Webhook or App integration

## Config Options
_All caps for envs, lowercase for config file_
- `MAGECOMM_LOG_PATH`: Path to log file, default: SYSLOG
- `MAGECOMM_LOG_LEVEL`: Log level, default: WARN, options (TRACE, DEBUG, INFO, WARN, ERROR, FATAL, PANIC)
- `MAGECOMM_MAX_OPERATIONAL_CPU_LIMIT`: Maximum CPU limit of system before we defer processing messages, default: 80
Expand Down
13 changes: 9 additions & 4 deletions cmd/listen.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,17 @@ var ListenCmd = &cobra.Command{
return fmt.Errorf("error creating listener: %s", err)
}

// Create a channel to handle program termination or interruption signals so we can kill any connections if needed
//Create a channel to handle program termination or interruption signals so we can kill any connections if needed
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM)
go listener.ListenToService(queueNames)
<-sigChan
listener.Close()
go func() {
<-sigChan
logger.Infof("Received interruption signal. Shutting down gracefully...")
listener.Close()
os.Exit(0)
}()

listener.ListenToService(queueNames)

return nil
},
Expand Down
44 changes: 33 additions & 11 deletions cmd/magerun.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,9 @@ var MagerunCmd = &cobra.Command{
//empty pre run to stop execution of parent RootCmd pre run
},
RunE: func(cmd *cobra.Command, args []string) error {

// handle global arguments (e.g. --config, --debug) as root command cannot due to DisableFlagParsing
var globalArguments = handleGlobalArguments(args)
magerunArgs := args[len(globalArguments):]

if len(magerunArgs) < 1 {
return fmt.Errorf("no command provided")
}
Expand Down Expand Up @@ -99,26 +97,50 @@ func initializeModuleWhichRequireConfig() {

func handleGlobalArguments(args []string) []string {
// Replicates RootCmd.PersistentPreRunE as it is not usable when DisableFlagParsing is set to true
// global Arg handling must be done manually
var globalArguments []string
var overrideFilePath string
for _, arg := range args {
var enableDebugLogging bool

//Note arguments between start and magerun command.
for i, arg := range args {
if strings.HasPrefix(arg, "--") {
globalArguments = append(globalArguments, arg)

if strings.HasPrefix(arg, "--config") {
// Catch both --config /file/path and --config=/file/path
overrideFilePath = strings.TrimPrefix(arg, "--config=")
overrideFilePath = strings.TrimPrefix(arg, "--config ")
//if arg is --debug then flag debug to be enabled after configuration step
if arg == "--debug" {
enableDebugLogging = true
}
if strings.HasPrefix(arg, "--debug") {
logger.EnableDebugMode()

//if arg is --config then configure
if strings.HasPrefix(arg, "--config") {
var configPath string
if strings.Contains(arg, "=") {
configPath = strings.Split(arg, "=")[1]
} else {
//ensure next argument is config path
if len(args) > i+1 && !strings.HasPrefix(args[i+1], "--") {
configPath = args[i+1]
//Ensure we remove the config path from args to avoid breaking early
args = append(args[:i+1], args[i+2:]...)
}
}
if configPath == "" {
logger.Warnf("No config file path provided with argument, using default config file path")
}

overrideFilePath = strings.Trim(configPath, `"'`)
}
}
if !strings.HasPrefix(arg, "--") {
} else {
//We have reached the magerun command, so exit loop
break
}
}

if enableDebugLogging {
logger.EnableDebugMode()
}

config_manager.Configure(overrideFilePath)
initializeModuleWhichRequireConfig()

Expand Down
77 changes: 51 additions & 26 deletions config_manager/base_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,49 +105,74 @@ func getDefault(key string) string {
}

func Configure(overrideFile string) {
if overrideFile != "" {
viper.SetConfigFile(overrideFile)
} else {
// Set base folder and file name of config file
viper.SetConfigName("config")
if runtime.GOOS == "windows" {
viper.AddConfigPath(os.Getenv("APPDATA") + "\\magecomm\\")
} else {
viper.AddConfigPath("/etc/magecomm/")
}
// Search for json config file first, then fallback to yaml
viper.SetConfigType("json")
if err := viper.ReadInConfig(); err != nil {
viper.SetConfigType("yaml")
}
overrideFile = strings.TrimSpace(overrideFile)
overrideFile = strings.Trim(overrideFile, `'"`)
defaultConfigError := configureDefaultsConfig()
disallowOverwrite := viper.GetBool("disallow_configfile_overwrite")

if disallowOverwrite && overrideFile != "" {
logger.Warnf("Config file overwriting is disallowed, ignoring passed in config file")
}

err := viper.ReadInConfig()
if err != nil {
// If the configuration file does not exist, warn user that env vars will be used
var configFileNotFoundError viper.ConfigFileNotFoundError
if errors.As(err, &configFileNotFoundError) {
logger.Infof("No config file found, reading fully from env vars, this is less secure")
} else {
logger.Warnf("Failed to read the config file, reading from ENV vars, this is less secure: %v", err)
return
if !disallowOverwrite && overrideFile != "" {
viper.Reset()
viper.SetConfigFile(overrideFile)
err := viper.ReadInConfig()
if err != nil {
if defaultConfigError == nil {
logger.Warnf("Failed to read the config file, reapplying default config")
err := configureDefaultsConfig()
if err != nil {
// We checked for this above, so this should never happen
}
} else {
logger.Warnf("Failed to read the both the override and default config file, defaulting to env variable reading")
}
}
}

if logPath := GetValue(ConfigLogPath); logPath != "" {
logger.ConfigureLogPath(logPath)
logger.Infof("Logging to file: %s", logPath)
}

if logLevel := GetValue(ConfigLogLevel); logLevel != "" {
logger.SetLogLevel(logLevel)
logger.Infof("Logging level set to: %s", logLevel)
}

configName := viper.ConfigFileUsed()
logger.Infof("Using config file: %s", configName)
}

func configureDefaultsConfig() error {
viper.Reset()

viper.SetConfigName("config")
if runtime.GOOS == "windows" {
viper.AddConfigPath(os.Getenv("APPDATA") + "\\magecomm\\")
} else {
viper.AddConfigPath("/etc/magecomm/")
}
// Search for json config file first, then fallback to yaml
viper.SetConfigType("json")
if err := viper.ReadInConfig(); err != nil {
viper.SetConfigType("yaml")
}
err := viper.ReadInConfig()
if err != nil {
// If the configuration file does not exist, warn user that env vars will be used
var configFileNotFoundError viper.ConfigFileNotFoundError
if errors.As(err, &configFileNotFoundError) {
logger.Infof("No default config file found, reading fully from env vars, this is less secure")
return err
} else {
logger.Warnf("Failed to read the default config file, reading from ENV vars, this is less secure: %v", err)
return err
}
}

return nil
}

func GetBoolValue(key string) bool {
value := GetValue(key)
for _, v := range trueValues {
Expand Down
51 changes: 33 additions & 18 deletions logger/logger.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package logger

// This package is used to log messages easily It is a wrapper around the logrus package.
// This package is used to Log messages easily It is a wrapper around the logrus package.

import (
"github.com/sirupsen/logrus"
Expand All @@ -19,14 +19,17 @@ const (
PanicLevel = logrus.PanicLevel
)

var Log *logrus.Logger
var (
Log *logrus.Logger
debugFlagSet bool
)

func init() {
logrus.SetFormatter(&logrus.TextFormatter{
Log = logrus.StandardLogger()
Log.SetFormatter(&logrus.TextFormatter{
FullTimestamp: true,
})
logrus.SetLevel(logrus.WarnLevel)
Log = logrus.StandardLogger()
Log.SetLevel(logrus.WarnLevel)
}

func ConfigureLogPath(logFile string) {
Expand All @@ -37,18 +40,23 @@ func ConfigureLogPath(logFile string) {

if _, err := os.Stat(logFile); os.IsNotExist(err) {
if err := createLogFile(logFile); err != nil {
Log.Errorf("Unable to create log file, please contact your system administrator")
Log.Errorf("Unable to create Log file, please contact your system administrator")
}
}

file, err := os.OpenFile(logFile, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0755)
if err != nil {
logrus.SetOutput(os.Stdout)
Log.Errorf("Unable to open log file, printing to stdout, please contact your system administrator")
Log.SetOutput(os.Stdout)
Log.Errorf("Unable to open Log file, printing to stdout, please contact your system administrator")
return
}

logrus.SetOutput(file)
//Log.SetFormatter(&logrus.JSONFormatter{})
Log.SetFormatter(&logrus.TextFormatter{
FullTimestamp: true,
})
Log.SetOutput(file)
Log.Infof("Logging to file: %s", file.Name())
}

func createLogFile(logFile string) error {
Expand All @@ -58,24 +66,31 @@ func createLogFile(logFile string) error {
}
defer func(file *os.File) {
if err := file.Close(); err != nil {
Log.Fatal("Unable to close log file, please contact your system administrator")
Log.Fatal("Unable to close Log file, please contact your system administrator")
}
}(file)
return nil
}

func EnableDebugMode() {
SetLogLevel(logrus.DebugLevel.String())
debugFlagSet = true
}

func SetLogLevel(level string) {
if debugFlagSet {
Log.Info("Debug mode enabled by flag, ignoring log level configuration")
return
}

logrusLevel, err := logrus.ParseLevel(strings.ToLower(level))
if err != nil {
logrus.Warnf("Invalid log level: %s, defaulting to %s", level, logrus.WarnLevel.String())
Log.Warnf("Invalid Log level: %s, defaulting to %s", level, logrus.WarnLevel.String())
logrusLevel = logrus.WarnLevel
}

logrus.SetLevel(logrusLevel)
Log.SetLevel(logrusLevel)
Log.Infof("Log level set to %s", logrusLevel)
}

func Trace(args ...interface{}) {
Expand Down Expand Up @@ -111,25 +126,25 @@ func Tracef(format string, args ...interface{}) {
}

func Debugf(format string, args ...interface{}) {
logrus.Debugf(format, args...)
Log.Debugf(format, args...)
}

func Infof(format string, args ...interface{}) {
logrus.Infof(format, args...)
Log.Infof(format, args...)
}

func Warnf(format string, args ...interface{}) {
logrus.Warnf(format, args...)
Log.Warnf(format, args...)
}

func Errorf(format string, args ...interface{}) {
logrus.Errorf(format, args...)
Log.Errorf(format, args...)
}

func Fatalf(format string, args ...interface{}) {
logrus.Fatalf(format, args...)
Log.Fatalf(format, args...)
}

func Panicf(format string, args ...interface{}) {
logrus.Panicf(format, args...)
Log.Panicf(format, args...)
}
Loading