From 3e0927a6e4f644ba08fa743a5b15fba090acace8 Mon Sep 17 00:00:00 2001 From: Luke Wahlmeier Date: Mon, 18 Mar 2019 01:07:52 -0600 Subject: [PATCH 1/6] refactored logging --- main.go | 5 +++- pkg/aws/aws.go | 12 +++++--- pkg/kubernetes/kubeconfig.go | 16 +++++----- pkg/kubernetes/kubernetes.go | 31 ++++++------------- pkg/log/logger.go | 26 ++++++++-------- pkg/pagerduty/pagerduty.go | 14 ++++----- pkg/prometheus/prometheus.go | 34 +++++++-------------- pkg/slack/slack.go | 34 +++++++-------------- pkg/stimlog/stimlog.go | 58 ++++++++++++++++++++++++++++++++++++ pkg/vault/auth.go | 12 ++++---- pkg/vault/status.go | 18 +++++------ pkg/vault/vault.go | 11 +++++-- stim/aws.go | 3 +- stim/kubernetes.go | 2 +- stim/prometheus.go | 2 +- stim/slack.go | 2 +- stim/stim.go | 23 +++++++------- stim/vault.go | 3 +- stimpacks/aws/aws.go | 6 ++-- stimpacks/aws/command.go | 1 + 20 files changed, 170 insertions(+), 143 deletions(-) create mode 100644 pkg/stimlog/stimlog.go diff --git a/main.go b/main.go index 27f44f7..5ab9ff5 100644 --- a/main.go +++ b/main.go @@ -3,6 +3,8 @@ package main import ( "github.com/readytalk/stim/stim" "github.com/readytalk/stim/stimpacks/aws" + "github.com/readytalk/stim/stimpacks/discover" + "github.com/readytalk/stim/stimpacks/env" "github.com/readytalk/stim/stimpacks/kubernetes" "github.com/readytalk/stim/stimpacks/pagerduty" "github.com/readytalk/stim/stimpacks/slack" @@ -12,12 +14,13 @@ import ( func main() { stim := stim.New() - // stim.AddStimpack(discover.New()) + stim.AddStimpack(discover.New()) stim.AddStimpack(aws.New()) stim.AddStimpack(kubernetes.New()) stim.AddStimpack(pagerduty.New()) stim.AddStimpack(slack.New()) stim.AddStimpack(vault.New()) stim.AddStimpack(version.New()) + stim.AddStimpack(env.New()) stim.Execute() } diff --git a/pkg/aws/aws.go b/pkg/aws/aws.go index dc177d3..ef79c63 100644 --- a/pkg/aws/aws.go +++ b/pkg/aws/aws.go @@ -1,7 +1,7 @@ package aws import ( - "github.com/readytalk/stim/pkg/log" + "github.com/readytalk/stim/pkg/stimlog" // "github.com/aws/aws-sdk-go/aws" // "github.com/aws/aws-sdk-go/aws/awserr" // "github.com/aws/aws-sdk-go/aws/session" @@ -13,7 +13,7 @@ import ( type Aws struct { // client *slack.Client config *Config - log log.Logger + log *stimlog.StimLogger } type Config struct { @@ -21,12 +21,16 @@ type Config struct { } // New builds a client from the provided config -func New(config *Config) (*Aws, error) { +func New(config *Config, sl *stimlog.StimLogger) (*Aws, error) { // client := slack.New(config.Token) s := &Aws{config: config} - + if sl != nil { + s.log = sl + } else { + s.log = stimlog.GetLogger() + } return s, nil } diff --git a/pkg/kubernetes/kubeconfig.go b/pkg/kubernetes/kubeconfig.go index 1688378..d147a7d 100644 --- a/pkg/kubernetes/kubeconfig.go +++ b/pkg/kubernetes/kubeconfig.go @@ -43,7 +43,7 @@ func (k *Kubernetes) modifyKubeconfig(o *KubeConfigOptions) error { return err } - k.Debug("Kubernetes config modified...") + k.log.Debug("Kubernetes config modified...") return nil @@ -53,10 +53,10 @@ func (k *Kubernetes) modifyKubeconfigCluster(kubeConfig *clientcmdapi.Config, o stanza, exists := kubeConfig.Clusters[o.ClusterName] if !exists { - k.Debug("Kubernetes cluster `" + o.ClusterName + "` not found in config, creating...") + k.log.Debug("Kubernetes cluster `" + o.ClusterName + "` not found in config, creating...") stanza = clientcmdapi.NewCluster() } else { - k.Debug("Kubernetes cluster `" + o.ClusterName + "` found, modifying...") + k.log.Debug("Kubernetes cluster `" + o.ClusterName + "` found, modifying...") } stanza.Server = o.ClusterServer @@ -71,10 +71,10 @@ func (k *Kubernetes) modifyKubeconfigAuth(kubeConfig *clientcmdapi.Config, o *Ku stanza, exists := kubeConfig.AuthInfos[o.AuthName] if !exists { - k.Debug("Kubernetes auth `" + o.AuthName + "` not found in config, creating...") + k.log.Debug("Kubernetes auth `" + o.AuthName + "` not found in config, creating...") stanza = clientcmdapi.NewAuthInfo() } else { - k.Debug("Kubernetes auth `" + o.AuthName + "` found, modifying...") + k.log.Debug("Kubernetes auth `" + o.AuthName + "` found, modifying...") } stanza.Token = o.AuthToken @@ -86,10 +86,10 @@ func (k *Kubernetes) modifyKubeconfigContext(kubeConfig *clientcmdapi.Config, o stanza, exists := kubeConfig.Contexts[o.ContextName] if !exists { - k.Debug("Kubernetes context `" + o.ContextName + "` not found in config, creating...") + k.log.Debug("Kubernetes context `" + o.ContextName + "` not found in config, creating...") stanza = clientcmdapi.NewContext() } else { - k.Debug("Kubernetes context `" + o.ContextName + "` found, modifying...") + k.log.Debug("Kubernetes context `" + o.ContextName + "` found, modifying...") } stanza.Cluster = o.ClusterName @@ -99,7 +99,7 @@ func (k *Kubernetes) modifyKubeconfigContext(kubeConfig *clientcmdapi.Config, o if o.ContextSetCurrent { kubeConfig.CurrentContext = o.ContextName - k.Debug("Kubernetes current-context set to `" + o.ContextName + "`") + k.log.Debug("Kubernetes current-context set to `" + o.ContextName + "`") } } diff --git a/pkg/kubernetes/kubernetes.go b/pkg/kubernetes/kubernetes.go index 628597d..3d6c11e 100644 --- a/pkg/kubernetes/kubernetes.go +++ b/pkg/kubernetes/kubernetes.go @@ -1,14 +1,14 @@ package kubernetes import ( - "fmt" + "github.com/readytalk/stim/pkg/stimlog" "k8s.io/client-go/tools/clientcmd" ) type Kubernetes struct { // client *api.Client config *Config - + log *stimlog.StimLogger // This allows us to read/write the kube config // It takes into account KUBECONFIG env var for setting the location configAccess clientcmd.ConfigAccess @@ -16,31 +16,18 @@ type Kubernetes struct { type Config struct { // Address string - Logger -} -type Logger interface { - Debug(args ...interface{}) - Info(args ...interface{}) } -func (k *Kubernetes) Debug(message string) { - if k.config.Logger != nil { - k.config.Debug(message) - } -} +func New(kconf *Config, sl *stimlog.StimLogger) (*Kubernetes, error) { -func (k *Kubernetes) Info(message string) { - if k.config.Logger != nil { - k.config.Info(message) + k := &Kubernetes{config: kconf} + + if sl != nil { + k.log = sl } else { - fmt.Println(message) + k.log = stimlog.GetLogger() } -} - -func New(config *Config) (*Kubernetes, error) { - - k := &Kubernetes{config: config} return k, nil } @@ -49,7 +36,7 @@ func (k *Kubernetes) SetKubeconfig(kubeConfigOptions *KubeConfigOptions) error { // configAccess is used by subcommands and methods in this package to load and modify the appropriate config files k.configAccess = clientcmd.NewDefaultPathOptions() - k.Debug("Using kubeconfig file: " + k.configAccess.GetDefaultFilename()) + k.log.Debug("Using kubeconfig file: " + k.configAccess.GetDefaultFilename()) err := k.modifyKubeconfig(kubeConfigOptions) if err != nil { diff --git a/pkg/log/logger.go b/pkg/log/logger.go index 1ec4156..3c98166 100644 --- a/pkg/log/logger.go +++ b/pkg/log/logger.go @@ -1,5 +1,9 @@ package log +import ( + "fmt" +) + // Logger is a interface for creating standard logging calls. // This will enable depended code log.Debug("Woot") // Avoid all other packages from declaring their own loggers @@ -10,28 +14,24 @@ type Logger interface { Fatal(...interface{}) } -var logger Logger +type Level uint32 -// SetLogger takes a structured logger to interface with. -// After the logger is setup it will be available across your packages -// If SetLogger is not used Debug will not create output -func SetLogger(givenLogger Logger) { - logger = givenLogger -} +const ( + WarnLevel Level = 10 + FatalLevel Level = 20 + DebugLevel Level = 50 +) -// Debug logs a message at level Debug on the standard logger. func Debug(message ...interface{}) { - if logger != nil { - logger.Debug(message...) - } + fmt.Println(message) } // Warn logs a message at level Warn on the standard logger. func Warn(message ...interface{}) { - logger.Warn(message...) + fmt.Println(message) } // Fatal logs a message at level Fatal on the standard logger then the process will exit with status set to 1. func Fatal(message ...interface{}) { - logger.Fatal(message...) + fmt.Println(message) } diff --git a/pkg/pagerduty/pagerduty.go b/pkg/pagerduty/pagerduty.go index 33be047..45e7c9b 100644 --- a/pkg/pagerduty/pagerduty.go +++ b/pkg/pagerduty/pagerduty.go @@ -2,17 +2,18 @@ package pagerduty import ( "errors" - pdApi "github.com/PagerDuty/go-pagerduty" - "github.com/readytalk/stim/pkg/log" - "github.com/readytalk/stim/pkg/utils" "os" "strings" + + pdApi "github.com/PagerDuty/go-pagerduty" + "github.com/readytalk/stim/pkg/stimlog" + "github.com/readytalk/stim/pkg/utils" ) // Pagerduty is the main object type Pagerduty struct { client *pdApi.Client - log log.Logger + log *stimlog.StimLogger } // Event contains the required and optional fields to sent an event @@ -30,12 +31,11 @@ type Event struct { } // New returns a new Pagerduty "instance" -func New(apiKey string, givenLog log.Logger) *Pagerduty { +func New(apiKey string, givenLog *stimlog.StimLogger) *Pagerduty { // Initialize client client := pdApi.NewClient(apiKey) - p := &Pagerduty{client: client} - log.SetLogger(givenLog) + p := &Pagerduty{client: client, log: givenLog} return p } diff --git a/pkg/prometheus/prometheus.go b/pkg/prometheus/prometheus.go index 98f5d74..9bef575 100644 --- a/pkg/prometheus/prometheus.go +++ b/pkg/prometheus/prometheus.go @@ -2,10 +2,11 @@ package prometheus import ( "context" - "fmt" + "time" + "github.com/prometheus/client_golang/api" "github.com/prometheus/client_golang/api/prometheus/v1" - "time" + "github.com/readytalk/stim/pkg/stimlog" ) type Prometheus struct { @@ -13,33 +14,14 @@ type Prometheus struct { config *Config context context.Context API v1.API + log *stimlog.StimLogger } type Config struct { Address string - Logger -} - -type Logger interface { - Debug(args ...interface{}) - Info(args ...interface{}) } -func (p *Prometheus) Debug(message string) { - if p.config.Logger != nil { - p.config.Debug(message) - } -} - -func (p *Prometheus) Info(message string) { - if p.config.Logger != nil { - p.config.Info(message) - } else { - fmt.Println(message) - } -} - -func New(config *Config) (*Prometheus, error) { +func New(config *Config, sl *stimlog.StimLogger) (*Prometheus, error) { apiConfig := api.Config{Address: config.Address} client, err := api.NewClient(apiConfig) @@ -50,7 +32,11 @@ func New(config *Config) (*Prometheus, error) { api := v1.NewAPI(client) p := &Prometheus{client: &client, API: api, context: context.Background()} - + if sl != nil { + p.log = sl + } else { + p.log = stimlog.GetLogger() + } return p, nil } diff --git a/pkg/slack/slack.go b/pkg/slack/slack.go index b8dcd0e..225cc86 100644 --- a/pkg/slack/slack.go +++ b/pkg/slack/slack.go @@ -2,20 +2,21 @@ package slack import ( "errors" - "fmt" + "github.com/nlopes/slack" + "github.com/readytalk/stim/pkg/stimlog" ) // Slack is the main object type Slack struct { client *slack.Client + log *stimlog.StimLogger config *Config } // Config contains information about setting up a new slack client type Config struct { Token string - Logger } // Message contains information about a slack message @@ -26,32 +27,17 @@ type Message struct { IconUrl string } -// Logger is an interface for passing a custom logger to be used by this package -type Logger interface { - Debug(args ...interface{}) - Info(args ...interface{}) -} - -func (s *Slack) debug(message string) { - if s.config.Logger != nil { - s.config.Debug(message) - } -} - -func (s *Slack) info(message string) { - if s.config.Logger != nil { - s.config.Info(message) - } else { - fmt.Println(message) - } -} - // New builds a slack client from the provided config -func New(config *Config) (*Slack, error) { +func New(config *Config, sl *stimlog.StimLogger) (*Slack, error) { client := slack.New(config.Token) s := &Slack{config: config, client: client} + if sl != nil { + s.log = sl + } else { + s.log = stimlog.GetLogger() + } return s, nil } @@ -112,7 +98,7 @@ func (s *Slack) PostMessage(msg *Message) error { return err } - s.debug("Slack message successfully sent at " + timestamp + " to channel " + msg.Channel + " (" + channelId + ")") + s.log.Debug("Slack message successfully sent at " + timestamp + " to channel " + msg.Channel + " (" + channelId + ")") return nil } diff --git a/pkg/stimlog/stimlog.go b/pkg/stimlog/stimlog.go new file mode 100644 index 0000000..b5a7b7a --- /dev/null +++ b/pkg/stimlog/stimlog.go @@ -0,0 +1,58 @@ +package stimlog + +import ( + "github.com/readytalk/stim/pkg/log" + logurs "github.com/sirupsen/logrus" +) + +type StimLogger struct { + setLogger log.Logger + currentLevel log.Level +} + +var cl *StimLogger = &StimLogger{ + setLogger: logurs.New(), + currentLevel: log.WarnLevel, +} + +func GetLogger() *StimLogger { + return cl +} + +// SetLogger takes a structured logger to interface with. +// After the logger is setup it will be available across your packages +// If SetLogger is not used Debug will not create output +func (stimLogger *StimLogger) SetLogger(givenLogger log.Logger) { + stimLogger.setLogger = givenLogger +} + +func (stimLogger *StimLogger) SetLevel(level log.Level) { + stimLogger.currentLevel = level +} + +// Debug logs a message at level Debug on the standard logger. +func (stimLogger *StimLogger) Debug(message ...interface{}) { + if stimLogger.currentLevel >= log.DebugLevel { + if stimLogger.setLogger != nil { + stimLogger.setLogger.Debug(message...) + } + } +} + +// Warn logs a message at level Warn on the standard logger. +func (stimLogger *StimLogger) Warn(message ...interface{}) { + if stimLogger.currentLevel >= log.WarnLevel { + if stimLogger.setLogger != nil { + stimLogger.setLogger.Warn(message...) + } + } +} + +// Fatal logs a message at level Fatal on the standard logger then the process will exit with status set to 1. +func (stimLogger *StimLogger) Fatal(message ...interface{}) { + if stimLogger.currentLevel >= log.FatalLevel { + if stimLogger.setLogger != nil { + stimLogger.setLogger.Fatal(message...) + } + } +} diff --git a/pkg/vault/auth.go b/pkg/vault/auth.go index 464444e..cedd430 100644 --- a/pkg/vault/auth.go +++ b/pkg/vault/auth.go @@ -2,7 +2,6 @@ package vault import ( "github.com/hashicorp/vault/command/token" - "github.com/readytalk/stim/pkg/log" "golang.org/x/crypto/ssh/terminal" "bufio" @@ -16,10 +15,9 @@ import ( // Login will authenticate the user with Vault // Will detect if user needs to re-login func (v *Vault) Login() error { - // get the token from the user's environment if v.client.Token() != "" { - log.Debug("Reading token from environment 'VAULT_TOKEN'") + v.log.Debug("Reading token from environment 'VAULT_TOKEN'") } else { // If no environment token set // Reading token from user's dot file v.tokenHelper = token.InternalTokenHelper{} @@ -29,7 +27,7 @@ func (v *Vault) Login() error { } if token != "" { - log.Debug("Reading token from: " + v.tokenHelper.Path()) + v.log.Debug("Reading token from: " + v.tokenHelper.Path()) v.client.SetToken(token) } } @@ -38,7 +36,7 @@ func (v *Vault) Login() error { // If not, prompt for login isTokenValid := v.isCurrentTokenValid() if isTokenValid == false { - log.Debug("No valid tokens found, need to login") + v.log.Debug("No valid tokens found, need to login") err := v.userLogin() if err != nil { return err @@ -87,7 +85,7 @@ func (v *Vault) userLogin() error { "password": password, }) if err != nil { - log.Debug("Do you have a bad username or password?") + v.log.Debug("Do you have a bad username or password?") return err } v.client.SetToken(secret.Auth.ClientToken) @@ -105,7 +103,7 @@ func (v *Vault) userLogin() error { } // spew.Dump(secret) entityID := secret.Data["entity_id"].(string) - log.Debug("Vault entity ID: ", entityID) + v.log.Debug("Vault entity ID: ", entityID) v.newLogin = true // Set if we had to prompt user for a login diff --git a/pkg/vault/status.go b/pkg/vault/status.go index e2e4a61..7eaa5c7 100644 --- a/pkg/vault/status.go +++ b/pkg/vault/status.go @@ -1,8 +1,6 @@ package vault import ( - "github.com/readytalk/stim/pkg/log" - "strconv" "time" ) @@ -13,14 +11,14 @@ func (v *Vault) isVaultHealthy() (bool, error) { return false, err } - log.Debug("Vault server info from (" + v.client.Address() + ")") - log.Debug(" Initialized: " + strconv.FormatBool(result.Initialized)) - log.Debug(" Sealed: " + strconv.FormatBool(result.Sealed)) - log.Debug(" Standby: " + strconv.FormatBool(result.Standby)) - log.Debug(" Version: " + result.Version) - log.Debug(" ClusterName: " + result.ClusterName) - log.Debug(" ClusterID: " + result.ClusterID) - log.Debug(" ServerTime: (" + strconv.FormatInt(result.ServerTimeUTC, 10) + ") " + time.Unix(result.ServerTimeUTC, 0).UTC().String()) + v.log.Debug("Vault server info from (" + v.client.Address() + ")") + v.log.Debug(" Initialized: " + strconv.FormatBool(result.Initialized)) + v.log.Debug(" Sealed: " + strconv.FormatBool(result.Sealed)) + v.log.Debug(" Standby: " + strconv.FormatBool(result.Standby)) + v.log.Debug(" Version: " + result.Version) + v.log.Debug(" ClusterName: " + result.ClusterName) + v.log.Debug(" ClusterID: " + result.ClusterID) + v.log.Debug(" ServerTime: (" + strconv.FormatInt(result.ServerTimeUTC, 10) + ") " + time.Unix(result.ServerTimeUTC, 0).UTC().String()) return true, nil } diff --git a/pkg/vault/vault.go b/pkg/vault/vault.go index 166ac12..c25f1c2 100644 --- a/pkg/vault/vault.go +++ b/pkg/vault/vault.go @@ -4,6 +4,7 @@ import ( "github.com/hashicorp/vault/api" "github.com/hashicorp/vault/command/token" "github.com/readytalk/stim/pkg/log" + "github.com/readytalk/stim/pkg/stimlog" "errors" "time" @@ -14,6 +15,7 @@ type Vault struct { config *Config tokenHelper token.InternalTokenHelper newLogin bool + log *stimlog.StimLogger } type Config struct { @@ -21,18 +23,21 @@ type Config struct { Address string Username string Timeout time.Duration - Log log.Logger InitialTokenDuration time.Duration } -func New(config *Config) (*Vault, error) { +func New(config *Config, givenLogger *stimlog.StimLogger) (*Vault, error) { // Ensure that the Vault address is set if config.Address == "" { return nil, errors.New("Vault address not set") } v := &Vault{config: config} - log.SetLogger(config.Log) + if givenLogger != nil { + v.log = givenLogger + } else { + v.log = stimlog.GetLogger() + } if v.config.Timeout == 0 { v.config.Timeout = time.Second * 10 // No need to wait over a minite from default diff --git a/stim/aws.go b/stim/aws.go index 76164ff..918948a 100644 --- a/stim/aws.go +++ b/stim/aws.go @@ -6,14 +6,13 @@ import ( func (stim *Stim) Aws() *aws.Aws { stim.log.Debug("Stim-Aws: Creating") - // vault = stim.Vault() // token, err := vault.GetSecretKey("secret/slack/stimbot", "apikey") // if err != nil { // stim.log.Fatal(err) // } - a, err := aws.New(&aws.Config{}) + a, err := aws.New(&aws.Config{}, stim.log) if err != nil { stim.log.Fatal("Stim-Aws: Error Initializaing: ", err) } diff --git a/stim/kubernetes.go b/stim/kubernetes.go index 86e1ad8..6986262 100644 --- a/stim/kubernetes.go +++ b/stim/kubernetes.go @@ -7,7 +7,7 @@ import ( func (stim *Stim) Kubernetes() *kubernetes.Kubernetes { stim.log.Debug("Stim-Kubernetes: Creating") - k, err := kubernetes.New(&kubernetes.Config{Logger: stim.log}) + k, err := kubernetes.New(&kubernetes.Config{}, stim.log) if err != nil { stim.log.Fatal("Stim-Kubernetes: Error Initializaing: ", err) } diff --git a/stim/prometheus.go b/stim/prometheus.go index d28aa3b..84f4619 100644 --- a/stim/prometheus.go +++ b/stim/prometheus.go @@ -10,7 +10,7 @@ func (stim *Stim) Prometheus() *prometheus.Prometheus { address := stim.GetConfig("prometheus.address") stim.log.Debug("Stim-Prometheus: Using Address ", address) - p, err := prometheus.New(&prometheus.Config{Address: address}) + p, err := prometheus.New(&prometheus.Config{Address: address}, stim.log) if err != nil { stim.log.Fatal("Stim-Prometheus: Error Initializaing: ", err) } diff --git a/stim/slack.go b/stim/slack.go index 117d159..37321ee 100644 --- a/stim/slack.go +++ b/stim/slack.go @@ -13,7 +13,7 @@ func (stim *Stim) Slack() *slack.Slack { stim.log.Fatal(err) } - s, err := slack.New(&slack.Config{Token: token, Logger: stim.log}) + s, err := slack.New(&slack.Config{Token: token}, stim.log) if err != nil { stim.log.Fatal("Stim-Slack: Error Initializaing: ", err) } diff --git a/stim/stim.go b/stim/stim.go index e2dc4c9..42c7a72 100644 --- a/stim/stim.go +++ b/stim/stim.go @@ -1,12 +1,13 @@ package stim import ( + "os" + "os/user" + + "github.com/readytalk/stim/pkg/stimlog" "github.com/readytalk/stim/pkg/vault" - "github.com/sirupsen/logrus" "github.com/spf13/cobra" "github.com/spf13/viper" - "os" - "os/user" ) var version string @@ -14,22 +15,20 @@ var version string type Stim struct { config *viper.Viper rootCmd *cobra.Command - log *logrus.Logger + log *stimlog.StimLogger stimpacks []*Stimpack version string vault *vault.Vault } -var stim *Stim +var stim *Stim = &Stim{} func New() *Stim { - // Create - stim := &Stim{} - // Initialize logger - stim.log = logrus.New() + stim.log = stimlog.GetLogger() + stim.log.Debug("test1") // Initialize viper (config) stim.config = viper.New() @@ -45,6 +44,10 @@ func New() *Stim { return stim } +func (stim *Stim) GetLogger() *stimlog.StimLogger { + return stim.log +} + func (stim *Stim) Execute() { cobra.OnInitialize(stim.commandInit) err := stim.rootCmd.Execute() @@ -57,7 +60,7 @@ func (stim *Stim) commandInit() { // Set log level, this is done as early as possible so we can start using it if stim.GetConfigBool("verbose") == true { - stim.log.SetLevel(logrus.DebugLevel) + // stim.log.SetLevel(logrus.DebugLevel) stim.log.Debug("Stim version: ", stim.version) stim.log.Debug("Debug log level set") } diff --git a/stim/vault.go b/stim/vault.go index fdcfe2a..550aee4 100644 --- a/stim/vault.go +++ b/stim/vault.go @@ -35,10 +35,9 @@ func (stim *Stim) Vault() *vault.Vault { vault, err := vault.New(&vault.Config{ Address: stim.GetConfig("vault-address"), // Default is 127.0.0.1 Noprompt: stim.GetConfigBool("noprompt") == false && stim.IsAutomated(), - Log: stim.log, // Pass in the global logger object Username: username, // If set in the configs, pass in user InitialTokenDuration: timeInDuration, - }) + }, stim.log) if err != nil { stim.log.Fatal("Stim-Vault: Error Initializaing: ", err) } diff --git a/stimpacks/aws/aws.go b/stimpacks/aws/aws.go index 3b0be30..3cb9f3d 100644 --- a/stimpacks/aws/aws.go +++ b/stimpacks/aws/aws.go @@ -1,7 +1,7 @@ package aws import ( - "github.com/readytalk/stim/pkg/log" + "github.com/readytalk/stim/pkg/stimlog" vault "github.com/readytalk/stim/pkg/vault" "github.com/readytalk/stim/stim" ) @@ -10,12 +10,12 @@ type Aws struct { name string stim *stim.Stim vault *vault.Vault - Log log.Logger + log *stimlog.StimLogger } func New() *Aws { aws := &Aws{name: "aws"} - log.SetLogger(aws.Log) + aws.log = stimlog.GetLogger() return aws } diff --git a/stimpacks/aws/command.go b/stimpacks/aws/command.go index cc1ea39..508b751 100644 --- a/stimpacks/aws/command.go +++ b/stimpacks/aws/command.go @@ -8,6 +8,7 @@ import ( func (a *Aws) BindStim(stim *stim.Stim) { a.stim = stim + a.log = stim.GetLogger() } func (a *Aws) Command(viper *viper.Viper) *cobra.Command { From bc2c1fad555128ecdfc13858124ba4ccfd10d257 Mon Sep 17 00:00:00 2001 From: Luke Wahlmeier Date: Mon, 18 Mar 2019 22:49:30 -0600 Subject: [PATCH 2/6] comment out discover --- main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.go b/main.go index 5ab9ff5..1fdb403 100644 --- a/main.go +++ b/main.go @@ -14,7 +14,7 @@ import ( func main() { stim := stim.New() - stim.AddStimpack(discover.New()) +// stim.AddStimpack(discover.New()) stim.AddStimpack(aws.New()) stim.AddStimpack(kubernetes.New()) stim.AddStimpack(pagerduty.New()) From 08b28180dacf900ec50ec28ee75c34e5296a8cd5 Mon Sep 17 00:00:00 2001 From: Luke Wahlmeier Date: Mon, 18 Mar 2019 22:50:11 -0600 Subject: [PATCH 3/6] comment out discover --- main.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/main.go b/main.go index 1fdb403..a6c9e43 100644 --- a/main.go +++ b/main.go @@ -3,8 +3,6 @@ package main import ( "github.com/readytalk/stim/stim" "github.com/readytalk/stim/stimpacks/aws" - "github.com/readytalk/stim/stimpacks/discover" - "github.com/readytalk/stim/stimpacks/env" "github.com/readytalk/stim/stimpacks/kubernetes" "github.com/readytalk/stim/stimpacks/pagerduty" "github.com/readytalk/stim/stimpacks/slack" @@ -21,6 +19,5 @@ func main() { stim.AddStimpack(slack.New()) stim.AddStimpack(vault.New()) stim.AddStimpack(version.New()) - stim.AddStimpack(env.New()) stim.Execute() } From 37d5b482d66dc0c12d7b737f1c85eb5d890b7159 Mon Sep 17 00:00:00 2001 From: Luke Wahlmeier Date: Tue, 26 Mar 2019 23:02:25 -0600 Subject: [PATCH 4/6] updated logger, fixed singleton creation for stim/logger --- pkg/log/logger.go | 8 ------- pkg/stimlog/stimlog.go | 47 +++++++++++++++++++++++++++++++++--------- stim/rootcmd.go | 6 +++--- stim/stim.go | 41 +++++++++++++++++++----------------- 4 files changed, 62 insertions(+), 40 deletions(-) diff --git a/pkg/log/logger.go b/pkg/log/logger.go index 3c98166..78db988 100644 --- a/pkg/log/logger.go +++ b/pkg/log/logger.go @@ -14,14 +14,6 @@ type Logger interface { Fatal(...interface{}) } -type Level uint32 - -const ( - WarnLevel Level = 10 - FatalLevel Level = 20 - DebugLevel Level = 50 -) - func Debug(message ...interface{}) { fmt.Println(message) } diff --git a/pkg/stimlog/stimlog.go b/pkg/stimlog/stimlog.go index b5a7b7a..23be315 100644 --- a/pkg/stimlog/stimlog.go +++ b/pkg/stimlog/stimlog.go @@ -1,22 +1,48 @@ package stimlog import ( + "sync" + "github.com/readytalk/stim/pkg/log" logurs "github.com/sirupsen/logrus" ) +// StimLogger this struct is a generic logger used by stim packages type StimLogger struct { setLogger log.Logger - currentLevel log.Level + currentLevel Level } -var cl *StimLogger = &StimLogger{ - setLogger: logurs.New(), - currentLevel: log.WarnLevel, -} +// Level is the Level of logging set in stim +type Level uint32 + +const ( + //FatalLevel this is used to log an error that will cause fatal problems in the program + FatalLevel Level = 0 + //WarnLevel is logging for interesting events that need to be known about but are not crazy + WarnLevel Level = 20 + //DebugLevel is used to debugging certain calls in Stim to see what is going on, usually only used for development + DebugLevel Level = 50 +) +var logger *StimLogger + +//GetLogger gets a logger for logging in stim. func GetLogger() *StimLogger { - return cl + if logger == nil { + mu := sync.Mutex{} + mu.Lock() + if logger == nil { + lg := logurs.New() + logger = &StimLogger{ + setLogger: lg, + currentLevel: WarnLevel, + } + //We set logurs to debug since we are handling the filtering + lg.SetLevel(logurs.DebugLevel) + } + } + return logger } // SetLogger takes a structured logger to interface with. @@ -26,13 +52,14 @@ func (stimLogger *StimLogger) SetLogger(givenLogger log.Logger) { stimLogger.setLogger = givenLogger } -func (stimLogger *StimLogger) SetLevel(level log.Level) { +// SetLevel sets the StimLogger log level. +func (stimLogger *StimLogger) SetLevel(level Level) { stimLogger.currentLevel = level } // Debug logs a message at level Debug on the standard logger. func (stimLogger *StimLogger) Debug(message ...interface{}) { - if stimLogger.currentLevel >= log.DebugLevel { + if stimLogger.currentLevel >= DebugLevel { if stimLogger.setLogger != nil { stimLogger.setLogger.Debug(message...) } @@ -41,7 +68,7 @@ func (stimLogger *StimLogger) Debug(message ...interface{}) { // Warn logs a message at level Warn on the standard logger. func (stimLogger *StimLogger) Warn(message ...interface{}) { - if stimLogger.currentLevel >= log.WarnLevel { + if stimLogger.currentLevel >= WarnLevel { if stimLogger.setLogger != nil { stimLogger.setLogger.Warn(message...) } @@ -50,7 +77,7 @@ func (stimLogger *StimLogger) Warn(message ...interface{}) { // Fatal logs a message at level Fatal on the standard logger then the process will exit with status set to 1. func (stimLogger *StimLogger) Fatal(message ...interface{}) { - if stimLogger.currentLevel >= log.FatalLevel { + if stimLogger.currentLevel >= FatalLevel { if stimLogger.setLogger != nil { stimLogger.setLogger.Fatal(message...) } diff --git a/stim/rootcmd.go b/stim/rootcmd.go index d7235e0..21e90cb 100644 --- a/stim/rootcmd.go +++ b/stim/rootcmd.go @@ -6,7 +6,7 @@ import ( "github.com/spf13/viper" ) -func (stim *Stim) rootCommand(viper *viper.Viper) *cobra.Command { +func initRootCommand(viper *viper.Viper) *cobra.Command { homeDir, err := homedir.Dir() var cmd = &cobra.Command{ @@ -32,8 +32,8 @@ func (stim *Stim) rootCommand(viper *viper.Viper) *cobra.Command { } } else { //TODO: we need to fix this for windows - stim.config.SetDefault("config-file", homeDir+"/.stim/config.yaml") - stim.config.SetDefault("homedir", homeDir) + viper.SetDefault("config-file", homeDir+"/.stim/config.yaml") + viper.SetDefault("homedir", homeDir) } return cmd diff --git a/stim/stim.go b/stim/stim.go index 42c7a72..7164ce1 100644 --- a/stim/stim.go +++ b/stim/stim.go @@ -3,6 +3,7 @@ package stim import ( "os" "os/user" + "sync" "github.com/readytalk/stim/pkg/stimlog" "github.com/readytalk/stim/pkg/vault" @@ -10,8 +11,6 @@ import ( "github.com/spf13/viper" ) -var version string - type Stim struct { config *viper.Viper rootCmd *cobra.Command @@ -21,29 +20,32 @@ type Stim struct { vault *vault.Vault } -var stim *Stim = &Stim{} +var version string +var stim *Stim +//New gets the Stim struct, which is treated like a singleton so you will get the same one +//as everywhere when this is called func New() *Stim { - - // Initialize logger - stim.log = stimlog.GetLogger() - - stim.log.Debug("test1") - // Initialize viper (config) - stim.config = viper.New() - - // Set version for local testing if not set by build system - if version == "" { - stim.version = "local" - } else { - stim.version = version + if stim == nil { + mu := sync.Mutex{} + mu.Lock() + if stim == nil { + // Set version for local testing if not set by build system + lv := "local" + if version != "" { + lv = version + } + log := stimlog.GetLogger() + config := viper.New() + root := initRootCommand(config) + stim = &Stim{log: log, config: config, rootCmd: root, version: lv} + } + mu.Unlock() } - - stim.rootCmd = stim.rootCommand(stim.config) - return stim } +//GetLogger for Stim func (stim *Stim) GetLogger() *stimlog.StimLogger { return stim.log } @@ -61,6 +63,7 @@ func (stim *Stim) commandInit() { // Set log level, this is done as early as possible so we can start using it if stim.GetConfigBool("verbose") == true { // stim.log.SetLevel(logrus.DebugLevel) + stim.log.SetLevel(stimlog.DebugLevel) stim.log.Debug("Stim version: ", stim.version) stim.log.Debug("Debug log level set") } From 94f9b0609b23fb66bc498c7dcce082b45e33be68 Mon Sep 17 00:00:00 2001 From: Luke Wahlmeier Date: Fri, 12 Apr 2019 16:08:53 -0600 Subject: [PATCH 5/6] refactored how logging works, again --- pkg/aws/aws.go | 14 ++++++++++---- pkg/kubernetes/kubernetes.go | 13 +++++++++---- pkg/log/logger.go | 29 ----------------------------- pkg/pagerduty/pagerduty.go | 13 +++++++++---- pkg/prometheus/prometheus.go | 14 ++++++++++---- pkg/slack/slack.go | 14 ++++++++++---- pkg/stimlog/stimlog.go | 35 ++++++++++++++++++++++++----------- pkg/vault/aws.go | 3 +-- pkg/vault/vault.go | 10 +++++----- stim/stim.go | 4 ++-- stimpacks/aws/aws.go | 2 +- stimpacks/aws/login.go | 3 +-- 12 files changed, 82 insertions(+), 72 deletions(-) delete mode 100644 pkg/log/logger.go diff --git a/pkg/aws/aws.go b/pkg/aws/aws.go index ef79c63..95447f4 100644 --- a/pkg/aws/aws.go +++ b/pkg/aws/aws.go @@ -13,21 +13,27 @@ import ( type Aws struct { // client *slack.Client config *Config - log *stimlog.StimLogger + log Logger } type Config struct { Token string } +type Logger interface { + Debug(...interface{}) + Warn(...interface{}) + Fatal(...interface{}) +} + // New builds a client from the provided config -func New(config *Config, sl *stimlog.StimLogger) (*Aws, error) { +func New(config *Config, log Logger) (*Aws, error) { // client := slack.New(config.Token) s := &Aws{config: config} - if sl != nil { - s.log = sl + if log != nil { + s.log = log } else { s.log = stimlog.GetLogger() } diff --git a/pkg/kubernetes/kubernetes.go b/pkg/kubernetes/kubernetes.go index 3d6c11e..b64e32c 100644 --- a/pkg/kubernetes/kubernetes.go +++ b/pkg/kubernetes/kubernetes.go @@ -8,7 +8,7 @@ import ( type Kubernetes struct { // client *api.Client config *Config - log *stimlog.StimLogger + log Logger // This allows us to read/write the kube config // It takes into account KUBECONFIG env var for setting the location configAccess clientcmd.ConfigAccess @@ -16,15 +16,20 @@ type Kubernetes struct { type Config struct { // Address string +} +type Logger interface { + Debug(...interface{}) + Warn(...interface{}) + Fatal(...interface{}) } -func New(kconf *Config, sl *stimlog.StimLogger) (*Kubernetes, error) { +func New(kconf *Config, log Logger) (*Kubernetes, error) { k := &Kubernetes{config: kconf} - if sl != nil { - k.log = sl + if log != nil { + k.log = log } else { k.log = stimlog.GetLogger() } diff --git a/pkg/log/logger.go b/pkg/log/logger.go deleted file mode 100644 index 78db988..0000000 --- a/pkg/log/logger.go +++ /dev/null @@ -1,29 +0,0 @@ -package log - -import ( - "fmt" -) - -// Logger is a interface for creating standard logging calls. -// This will enable depended code log.Debug("Woot") -// Avoid all other packages from declaring their own loggers -// This strategy enables simple change of the backend logger -type Logger interface { - Debug(...interface{}) - Warn(...interface{}) - Fatal(...interface{}) -} - -func Debug(message ...interface{}) { - fmt.Println(message) -} - -// Warn logs a message at level Warn on the standard logger. -func Warn(message ...interface{}) { - fmt.Println(message) -} - -// Fatal logs a message at level Fatal on the standard logger then the process will exit with status set to 1. -func Fatal(message ...interface{}) { - fmt.Println(message) -} diff --git a/pkg/pagerduty/pagerduty.go b/pkg/pagerduty/pagerduty.go index 45e7c9b..ef4d273 100644 --- a/pkg/pagerduty/pagerduty.go +++ b/pkg/pagerduty/pagerduty.go @@ -6,14 +6,13 @@ import ( "strings" pdApi "github.com/PagerDuty/go-pagerduty" - "github.com/readytalk/stim/pkg/stimlog" "github.com/readytalk/stim/pkg/utils" ) // Pagerduty is the main object type Pagerduty struct { client *pdApi.Client - log *stimlog.StimLogger + log Logger } // Event contains the required and optional fields to sent an event @@ -30,12 +29,18 @@ type Event struct { DedupKey string } +type Logger interface { + Debug(...interface{}) + Warn(...interface{}) + Fatal(...interface{}) +} + // New returns a new Pagerduty "instance" -func New(apiKey string, givenLog *stimlog.StimLogger) *Pagerduty { +func New(apiKey string, log Logger) *Pagerduty { // Initialize client client := pdApi.NewClient(apiKey) - p := &Pagerduty{client: client, log: givenLog} + p := &Pagerduty{client: client, log: log} return p } diff --git a/pkg/prometheus/prometheus.go b/pkg/prometheus/prometheus.go index 9bef575..cd075d9 100644 --- a/pkg/prometheus/prometheus.go +++ b/pkg/prometheus/prometheus.go @@ -14,14 +14,20 @@ type Prometheus struct { config *Config context context.Context API v1.API - log *stimlog.StimLogger + log Logger } type Config struct { Address string } -func New(config *Config, sl *stimlog.StimLogger) (*Prometheus, error) { +type Logger interface { + Debug(...interface{}) + Warn(...interface{}) + Fatal(...interface{}) +} + +func New(config *Config, log Logger) (*Prometheus, error) { apiConfig := api.Config{Address: config.Address} client, err := api.NewClient(apiConfig) @@ -32,8 +38,8 @@ func New(config *Config, sl *stimlog.StimLogger) (*Prometheus, error) { api := v1.NewAPI(client) p := &Prometheus{client: &client, API: api, context: context.Background()} - if sl != nil { - p.log = sl + if log != nil { + p.log = log } else { p.log = stimlog.GetLogger() } diff --git a/pkg/slack/slack.go b/pkg/slack/slack.go index 225cc86..3c0830f 100644 --- a/pkg/slack/slack.go +++ b/pkg/slack/slack.go @@ -10,7 +10,7 @@ import ( // Slack is the main object type Slack struct { client *slack.Client - log *stimlog.StimLogger + log Logger config *Config } @@ -27,14 +27,20 @@ type Message struct { IconUrl string } +type Logger interface { + Debug(...interface{}) + Warn(...interface{}) + Fatal(...interface{}) +} + // New builds a slack client from the provided config -func New(config *Config, sl *stimlog.StimLogger) (*Slack, error) { +func New(config *Config, log Logger) (*Slack, error) { client := slack.New(config.Token) s := &Slack{config: config, client: client} - if sl != nil { - s.log = sl + if log != nil { + s.log = log } else { s.log = stimlog.GetLogger() } diff --git a/pkg/stimlog/stimlog.go b/pkg/stimlog/stimlog.go index 23be315..8603e8a 100644 --- a/pkg/stimlog/stimlog.go +++ b/pkg/stimlog/stimlog.go @@ -3,13 +3,26 @@ package stimlog import ( "sync" - "github.com/readytalk/stim/pkg/log" logurs "github.com/sirupsen/logrus" ) +type Logger interface { + Debug(...interface{}) + Warn(...interface{}) + Fatal(...interface{}) +} + // StimLogger this struct is a generic logger used by stim packages -type StimLogger struct { - setLogger log.Logger +type StimLogger interface { + Debug(...interface{}) + Warn(...interface{}) + Fatal(...interface{}) + SetLogger(Logger) + SetLevel(Level) +} + +type stimLogger struct { + setLogger Logger currentLevel Level } @@ -25,16 +38,16 @@ const ( DebugLevel Level = 50 ) -var logger *StimLogger +var logger *stimLogger //GetLogger gets a logger for logging in stim. -func GetLogger() *StimLogger { +func GetLogger() StimLogger { if logger == nil { mu := sync.Mutex{} mu.Lock() if logger == nil { lg := logurs.New() - logger = &StimLogger{ + logger = &stimLogger{ setLogger: lg, currentLevel: WarnLevel, } @@ -48,17 +61,17 @@ func GetLogger() *StimLogger { // SetLogger takes a structured logger to interface with. // After the logger is setup it will be available across your packages // If SetLogger is not used Debug will not create output -func (stimLogger *StimLogger) SetLogger(givenLogger log.Logger) { +func (stimLogger *stimLogger) SetLogger(givenLogger Logger) { stimLogger.setLogger = givenLogger } // SetLevel sets the StimLogger log level. -func (stimLogger *StimLogger) SetLevel(level Level) { +func (stimLogger *stimLogger) SetLevel(level Level) { stimLogger.currentLevel = level } // Debug logs a message at level Debug on the standard logger. -func (stimLogger *StimLogger) Debug(message ...interface{}) { +func (stimLogger *stimLogger) Debug(message ...interface{}) { if stimLogger.currentLevel >= DebugLevel { if stimLogger.setLogger != nil { stimLogger.setLogger.Debug(message...) @@ -67,7 +80,7 @@ func (stimLogger *StimLogger) Debug(message ...interface{}) { } // Warn logs a message at level Warn on the standard logger. -func (stimLogger *StimLogger) Warn(message ...interface{}) { +func (stimLogger *stimLogger) Warn(message ...interface{}) { if stimLogger.currentLevel >= WarnLevel { if stimLogger.setLogger != nil { stimLogger.setLogger.Warn(message...) @@ -76,7 +89,7 @@ func (stimLogger *StimLogger) Warn(message ...interface{}) { } // Fatal logs a message at level Fatal on the standard logger then the process will exit with status set to 1. -func (stimLogger *StimLogger) Fatal(message ...interface{}) { +func (stimLogger *stimLogger) Fatal(message ...interface{}) { if stimLogger.currentLevel >= FatalLevel { if stimLogger.setLogger != nil { stimLogger.setLogger.Fatal(message...) diff --git a/pkg/vault/aws.go b/pkg/vault/aws.go index 6ea3b3c..130ce5b 100644 --- a/pkg/vault/aws.go +++ b/pkg/vault/aws.go @@ -2,7 +2,6 @@ package vault import ( "github.com/hashicorp/vault/api" - "github.com/readytalk/stim/pkg/log" "errors" ) @@ -20,7 +19,7 @@ func (v *Vault) AWScredentials(account string, role string, sts bool) (*api.Secr credType = "sts" } path := "/" + account + "/" + credType + "/" + role - log.Debug("Getting AWS credentials via path: ", path) + v.log.Debug("Getting AWS credentials via path: ", path) secret, err := v.GetSecret(path) if err != nil { diff --git a/pkg/vault/vault.go b/pkg/vault/vault.go index b029940..aba85cc 100644 --- a/pkg/vault/vault.go +++ b/pkg/vault/vault.go @@ -1,11 +1,11 @@ package vault import ( + "time" + "github.com/hashicorp/vault/api" "github.com/hashicorp/vault/command/token" - "github.com/readytalk/stim/pkg/log" "github.com/readytalk/stim/pkg/stimlog" - "time" ) type Vault struct { @@ -13,7 +13,7 @@ type Vault struct { config *Config tokenHelper token.InternalTokenHelper newLogin bool - log *stimlog.StimLogger + log stimlog.Logger } type Config struct { @@ -24,7 +24,7 @@ type Config struct { InitialTokenDuration time.Duration } -func New(config *Config, givenLogger *stimlog.StimLogger) (*Vault, error) { +func New(config *Config, givenLogger stimlog.Logger) (*Vault, error) { v := &Vault{config: config} if givenLogger != nil { @@ -65,7 +65,7 @@ func New(config *Config, givenLogger *stimlog.StimLogger) (*Vault, error) { // If user wants, extend the token timeout if v.IsNewLogin() { if v.config.InitialTokenDuration > 0 { - log.Debug("Token duration set to: ", v.config.InitialTokenDuration) + v.log.Debug("Token duration set to: ", v.config.InitialTokenDuration) _, err = v.client.Auth().Token().RenewSelf(int(v.config.InitialTokenDuration)) if err != nil { return nil, err diff --git a/stim/stim.go b/stim/stim.go index 7164ce1..da597a1 100644 --- a/stim/stim.go +++ b/stim/stim.go @@ -14,7 +14,7 @@ import ( type Stim struct { config *viper.Viper rootCmd *cobra.Command - log *stimlog.StimLogger + log stimlog.StimLogger stimpacks []*Stimpack version string vault *vault.Vault @@ -46,7 +46,7 @@ func New() *Stim { } //GetLogger for Stim -func (stim *Stim) GetLogger() *stimlog.StimLogger { +func (stim *Stim) GetLogger() stimlog.StimLogger { return stim.log } diff --git a/stimpacks/aws/aws.go b/stimpacks/aws/aws.go index 3cb9f3d..49b7399 100644 --- a/stimpacks/aws/aws.go +++ b/stimpacks/aws/aws.go @@ -10,7 +10,7 @@ type Aws struct { name string stim *stim.Stim vault *vault.Vault - log *stimlog.StimLogger + log stimlog.StimLogger } func New() *Aws { diff --git a/stimpacks/aws/login.go b/stimpacks/aws/login.go index 0f5a5d2..422f9e2 100644 --- a/stimpacks/aws/login.go +++ b/stimpacks/aws/login.go @@ -2,7 +2,6 @@ package aws import ( "github.com/hashicorp/vault/api" - "github.com/readytalk/stim/pkg/log" "github.com/skratchdot/open-golang/open" "encoding/json" @@ -27,7 +26,7 @@ func (a *Aws) Login() error { if err != nil { return err } - log.Debug("Account: ", account, " Role: ", role) + a.log.Debug("Account: ", account, " Role: ", role) envSource := a.stim.GetConfigBool("env-source") stsLogin := a.stim.GetConfigBool("aws-web") From c9b3f3929499c16e64a4f05b2d75df2472e0e2fd Mon Sep 17 00:00:00 2001 From: Luke Wahlmeier Date: Fri, 12 Apr 2019 21:43:11 -0600 Subject: [PATCH 6/6] moved to custom logger, added logfile support --- pkg/aws/aws.go | 7 +- pkg/kubernetes/kubernetes.go | 8 +- pkg/prometheus/prometheus.go | 7 +- pkg/slack/slack.go | 7 +- pkg/stimlog/stimlog.go | 199 ++++++++++++++++++++++++++++++++--- pkg/vault/vault.go | 14 ++- stim/aws.go | 2 +- stim/config.go | 15 ++- stim/kubernetes.go | 2 +- stim/prometheus.go | 2 +- stim/slack.go | 2 +- stim/stim.go | 19 +++- stim/vault.go | 3 +- 13 files changed, 245 insertions(+), 42 deletions(-) diff --git a/pkg/aws/aws.go b/pkg/aws/aws.go index 95447f4..1bc3e1f 100644 --- a/pkg/aws/aws.go +++ b/pkg/aws/aws.go @@ -18,6 +18,7 @@ type Aws struct { type Config struct { Token string + Log Logger } type Logger interface { @@ -27,13 +28,13 @@ type Logger interface { } // New builds a client from the provided config -func New(config *Config, log Logger) (*Aws, error) { +func New(config *Config) (*Aws, error) { // client := slack.New(config.Token) s := &Aws{config: config} - if log != nil { - s.log = log + if config.Log != nil { + s.log = config.Log } else { s.log = stimlog.GetLogger() } diff --git a/pkg/kubernetes/kubernetes.go b/pkg/kubernetes/kubernetes.go index b64e32c..ee9262d 100644 --- a/pkg/kubernetes/kubernetes.go +++ b/pkg/kubernetes/kubernetes.go @@ -15,7 +15,7 @@ type Kubernetes struct { } type Config struct { - // Address string + Log Logger } type Logger interface { @@ -24,12 +24,12 @@ type Logger interface { Fatal(...interface{}) } -func New(kconf *Config, log Logger) (*Kubernetes, error) { +func New(kconf *Config) (*Kubernetes, error) { k := &Kubernetes{config: kconf} - if log != nil { - k.log = log + if kconf.Log != nil { + k.log = kconf.Log } else { k.log = stimlog.GetLogger() } diff --git a/pkg/prometheus/prometheus.go b/pkg/prometheus/prometheus.go index cd075d9..cdcb5d7 100644 --- a/pkg/prometheus/prometheus.go +++ b/pkg/prometheus/prometheus.go @@ -19,6 +19,7 @@ type Prometheus struct { type Config struct { Address string + Log Logger } type Logger interface { @@ -27,7 +28,7 @@ type Logger interface { Fatal(...interface{}) } -func New(config *Config, log Logger) (*Prometheus, error) { +func New(config *Config) (*Prometheus, error) { apiConfig := api.Config{Address: config.Address} client, err := api.NewClient(apiConfig) @@ -38,8 +39,8 @@ func New(config *Config, log Logger) (*Prometheus, error) { api := v1.NewAPI(client) p := &Prometheus{client: &client, API: api, context: context.Background()} - if log != nil { - p.log = log + if config.Log != nil { + p.log = config.Log } else { p.log = stimlog.GetLogger() } diff --git a/pkg/slack/slack.go b/pkg/slack/slack.go index 3c0830f..6a36a4b 100644 --- a/pkg/slack/slack.go +++ b/pkg/slack/slack.go @@ -17,6 +17,7 @@ type Slack struct { // Config contains information about setting up a new slack client type Config struct { Token string + Log Logger } // Message contains information about a slack message @@ -34,13 +35,13 @@ type Logger interface { } // New builds a slack client from the provided config -func New(config *Config, log Logger) (*Slack, error) { +func New(config *Config) (*Slack, error) { client := slack.New(config.Token) s := &Slack{config: config, client: client} - if log != nil { - s.log = log + if config.Log != nil { + s.log = config.Log } else { s.log = stimlog.GetLogger() } diff --git a/pkg/stimlog/stimlog.go b/pkg/stimlog/stimlog.go index 8603e8a..ea0f596 100644 --- a/pkg/stimlog/stimlog.go +++ b/pkg/stimlog/stimlog.go @@ -1,8 +1,13 @@ package stimlog import ( + "fmt" + "os" + "strings" "sync" + "time" + "github.com/cornelk/hashmap" logurs "github.com/sirupsen/logrus" ) @@ -15,31 +20,63 @@ type Logger interface { // StimLogger this struct is a generic logger used by stim packages type StimLogger interface { Debug(...interface{}) + Verbose(...interface{}) + Info(...interface{}) Warn(...interface{}) Fatal(...interface{}) SetLogger(Logger) SetLevel(Level) -} - -type stimLogger struct { - setLogger Logger - currentLevel Level + SetDateFormat(string) + AddLogFile(string, Level) error + ForceFlush(bool) } // Level is the Level of logging set in stim -type Level uint32 +type Level int32 const ( + defaultLevel Level = -1 //FatalLevel this is used to log an error that will cause fatal problems in the program FatalLevel Level = 0 //WarnLevel is logging for interesting events that need to be known about but are not crazy - WarnLevel Level = 20 + WarnLevel Level = 20 + InfoLevel Level = 30 + VerboseLevel Level = 40 //DebugLevel is used to debugging certain calls in Stim to see what is going on, usually only used for development DebugLevel Level = 50 ) +type logFile struct { + path string + logLevel Level + fp *os.File +} + +type logMessage struct { + logLevel Level + msg string +} + +type stimLogger struct { + setLogger Logger + currentLevel Level + highestLevel Level + dateFMT string + logfiles hashmap.HashMap + logQueue chan *logMessage + forceFlush bool +} + var logger *stimLogger +const debugMsg = "[ DEBUG ]" +const warnMsg = "[ WARN ]" +const fatalMsg = "[ FATAL ]" +const infoMsg = "[ INFO ]" +const verboseMsg = "[VERBOSE]" +const dateFMT = "2006-01-02 15:04:05.9999999" +const subSTR = "{}" + //GetLogger gets a logger for logging in stim. func GetLogger() StimLogger { if logger == nil { @@ -48,16 +85,105 @@ func GetLogger() StimLogger { if logger == nil { lg := logurs.New() logger = &stimLogger{ - setLogger: lg, + // setLogger: lg, currentLevel: WarnLevel, + highestLevel: WarnLevel, + dateFMT: dateFMT, + logQueue: make(chan *logMessage, 20), + logfiles: hashmap.HashMap{}, } //We set logurs to debug since we are handling the filtering lg.SetLevel(logurs.DebugLevel) + logger.AddLogFile("STDOUT", defaultLevel) + go logger.writeLogQueue() + mu.Unlock() } } return logger } +func (stimLogger *stimLogger) AddLogFile(file string, logLevel Level) error { + var fp *os.File + var err error + if file == "STDOUT" { + fp = os.Stdout + } else if file == "STDERR" { + fp = os.Stderr + } else { + fp, err = os.OpenFile(file, os.O_RDWR|os.O_CREATE, 0750) + if err != nil { + return err + } + fs, err := fp.Stat() + if err != nil { + return err + } + fp.Seek(fs.Size(), 0) + } + if logLevel > stimLogger.highestLevel { + stimLogger.highestLevel = logLevel + } + stimLogger.logfiles.Set(file, &logFile{path: file, logLevel: logLevel, fp: fp}) + return nil +} + +func (stimLogger *stimLogger) writeLogQueue() { + for { + logmsg := <-stimLogger.logQueue + stimLogger.writeLogs(logmsg) + } +} + +func (stimLogger *stimLogger) writeLogs(lm *logMessage) { + for kv := range stimLogger.logfiles.Iter() { + lgr := kv.Value.(*logFile) + if lgr.logLevel >= lm.logLevel || (lgr.logLevel == defaultLevel && stimLogger.currentLevel >= lm.logLevel) { + lgr.fp.WriteString(lm.msg) + if stimLogger.forceFlush { + lgr.fp.Sync() + } + } + } +} + +func (stimLogger *stimLogger) formatAndLog(ll Level, level string, args ...interface{}) { + stimLogger.logQueue <- stimLogger.formatString(ll, level, args...) +} + +func (stimLogger *stimLogger) formatString(ll Level, level string, args ...interface{}) *logMessage { + var msg string + switch args[0].(type) { + case string: + msg = args[0].(string) + default: + return nil + } + subs := strings.Split(msg, subSTR) + var sb strings.Builder + sb.WriteString(time.Now().Format(dateFMT)) + sb.WriteString("\t") + sb.WriteString(level) + sb.WriteString("\t") + for i, v := range subs { + v = strings.Replace(v, "{{", "{", -1) + v = strings.Replace(v, "}}", "}", -1) + sb.WriteString(v) + if i < len(args)-1 { + sb.WriteString(fmt.Sprintf("%v", args[i+1])) + } + } + sb.WriteString("\n") + return &logMessage{msg: sb.String(), logLevel: ll} +} + +func (stimLogger *stimLogger) ForceFlush(ff bool) { + stimLogger.forceFlush = ff +} + +func (stimLogger *stimLogger) SetDateFormat(string) { + +} + // SetLogger takes a structured logger to interface with. // After the logger is setup it will be available across your packages // If SetLogger is not used Debug will not create output @@ -72,8 +198,29 @@ func (stimLogger *stimLogger) SetLevel(level Level) { // Debug logs a message at level Debug on the standard logger. func (stimLogger *stimLogger) Debug(message ...interface{}) { - if stimLogger.currentLevel >= DebugLevel { - if stimLogger.setLogger != nil { + if stimLogger.highestLevel >= DebugLevel { + if stimLogger.setLogger == nil { + if stimLogger.forceFlush { + stimLogger.writeLogs(stimLogger.formatString(DebugLevel, debugMsg, message...)) + } else { + stimLogger.formatAndLog(DebugLevel, debugMsg, message...) + } + } else { + stimLogger.setLogger.Debug(message...) + } + } +} + +// Debug logs a message at level Debug on the standard logger. +func (stimLogger *stimLogger) Verbose(message ...interface{}) { + if stimLogger.highestLevel >= VerboseLevel { + if stimLogger.setLogger == nil { + if stimLogger.forceFlush { + stimLogger.writeLogs(stimLogger.formatString(VerboseLevel, verboseMsg, message...)) + } else { + stimLogger.formatAndLog(VerboseLevel, verboseMsg, message...) + } + } else { stimLogger.setLogger.Debug(message...) } } @@ -81,18 +228,42 @@ func (stimLogger *stimLogger) Debug(message ...interface{}) { // Warn logs a message at level Warn on the standard logger. func (stimLogger *stimLogger) Warn(message ...interface{}) { - if stimLogger.currentLevel >= WarnLevel { - if stimLogger.setLogger != nil { + if stimLogger.highestLevel >= WarnLevel { + if stimLogger.setLogger == nil { + if stimLogger.forceFlush { + stimLogger.writeLogs(stimLogger.formatString(WarnLevel, warnMsg, message...)) + } else { + stimLogger.formatAndLog(WarnLevel, warnMsg, message...) + } + } else { stimLogger.setLogger.Warn(message...) } } } +// Warn logs a message at level Warn on the standard logger. +func (stimLogger *stimLogger) Info(message ...interface{}) { + if stimLogger.highestLevel >= InfoLevel { + if stimLogger.setLogger == nil { + if stimLogger.forceFlush { + stimLogger.writeLogs(stimLogger.formatString(InfoLevel, infoMsg, message...)) + } else { + stimLogger.formatAndLog(InfoLevel, infoMsg, message...) + } + } else { + stimLogger.setLogger.Debug(message...) + } + } +} + // Fatal logs a message at level Fatal on the standard logger then the process will exit with status set to 1. func (stimLogger *stimLogger) Fatal(message ...interface{}) { - if stimLogger.currentLevel >= FatalLevel { - if stimLogger.setLogger != nil { + if stimLogger.highestLevel >= FatalLevel { + if stimLogger.setLogger == nil { + stimLogger.writeLogs(stimLogger.formatString(FatalLevel, fatalMsg, message...)) + } else { stimLogger.setLogger.Fatal(message...) } + os.Exit(5) } } diff --git a/pkg/vault/vault.go b/pkg/vault/vault.go index aba85cc..27fa3cf 100644 --- a/pkg/vault/vault.go +++ b/pkg/vault/vault.go @@ -13,7 +13,7 @@ type Vault struct { config *Config tokenHelper token.InternalTokenHelper newLogin bool - log stimlog.Logger + log Logger } type Config struct { @@ -22,13 +22,19 @@ type Config struct { Username string Timeout time.Duration InitialTokenDuration time.Duration + Log Logger } -func New(config *Config, givenLogger stimlog.Logger) (*Vault, error) { +type Logger interface { + Debug(...interface{}) + Warn(...interface{}) + Fatal(...interface{}) +} +func New(config *Config) (*Vault, error) { v := &Vault{config: config} - if givenLogger != nil { - v.log = givenLogger + if config.Log != nil { + v.log = config.Log } else { v.log = stimlog.GetLogger() } diff --git a/stim/aws.go b/stim/aws.go index 918948a..2fdacd5 100644 --- a/stim/aws.go +++ b/stim/aws.go @@ -12,7 +12,7 @@ func (stim *Stim) Aws() *aws.Aws { // stim.log.Fatal(err) // } - a, err := aws.New(&aws.Config{}, stim.log) + a, err := aws.New(&aws.Config{Log: stim.log}) if err != nil { stim.log.Fatal("Stim-Aws: Error Initializaing: ", err) } diff --git a/stim/config.go b/stim/config.go index e81902b..2413ca4 100644 --- a/stim/config.go +++ b/stim/config.go @@ -3,10 +3,11 @@ package stim import ( "github.com/mitchellh/go-homedir" - yaml "gopkg.in/yaml.v2" "io/ioutil" "os" "path" + + yaml "gopkg.in/yaml.v2" ) func (stim *Stim) Get(configKey string) interface{} { @@ -74,15 +75,23 @@ func (stim *Stim) UpdateConfigFileKey(key string, value string) error { return nil } +func (stim *Stim) GetStimPath() (string, error) { + home, err := homedir.Dir() + if err != nil { + return "", err + } + return home + "/.stim/", nil +} + // CreateConfigFile will create the stim config file if it doesn't exist // Used the frist time this code is ran so sub functions do not get errors when // writting to the config. func (stim *Stim) CreateConfigFile() (string, error) { - home, err := homedir.Dir() + home, err := stim.GetStimPath() if err != nil { return "", err } - stimConfigFile := home + "/.stim/config.yaml" + stimConfigFile := home + "config.yaml" dir, _ := path.Split(stimConfigFile) err = stim.CreateDirIfNotExist(dir) diff --git a/stim/kubernetes.go b/stim/kubernetes.go index 6986262..7f7a6b3 100644 --- a/stim/kubernetes.go +++ b/stim/kubernetes.go @@ -7,7 +7,7 @@ import ( func (stim *Stim) Kubernetes() *kubernetes.Kubernetes { stim.log.Debug("Stim-Kubernetes: Creating") - k, err := kubernetes.New(&kubernetes.Config{}, stim.log) + k, err := kubernetes.New(&kubernetes.Config{Log: stim.log}) if err != nil { stim.log.Fatal("Stim-Kubernetes: Error Initializaing: ", err) } diff --git a/stim/prometheus.go b/stim/prometheus.go index 84f4619..502819f 100644 --- a/stim/prometheus.go +++ b/stim/prometheus.go @@ -10,7 +10,7 @@ func (stim *Stim) Prometheus() *prometheus.Prometheus { address := stim.GetConfig("prometheus.address") stim.log.Debug("Stim-Prometheus: Using Address ", address) - p, err := prometheus.New(&prometheus.Config{Address: address}, stim.log) + p, err := prometheus.New(&prometheus.Config{Address: address, Log: stim.log}) if err != nil { stim.log.Fatal("Stim-Prometheus: Error Initializaing: ", err) } diff --git a/stim/slack.go b/stim/slack.go index 37321ee..0b969fc 100644 --- a/stim/slack.go +++ b/stim/slack.go @@ -13,7 +13,7 @@ func (stim *Stim) Slack() *slack.Slack { stim.log.Fatal(err) } - s, err := slack.New(&slack.Config{Token: token}, stim.log) + s, err := slack.New(&slack.Config{Token: token, Log: stim.log}) if err != nil { stim.log.Fatal("Stim-Slack: Error Initializaing: ", err) } diff --git a/stim/stim.go b/stim/stim.go index da597a1..3ca72b3 100644 --- a/stim/stim.go +++ b/stim/stim.go @@ -59,17 +59,30 @@ func (stim *Stim) Execute() { func (stim *Stim) commandInit() { // Load a config file (if present) loadConfigErr := stim.loadConfigFile() - + if !stim.GetConfigBool("disableLogFile") { + lfp := stim.GetConfig("logFilePath") + if lfp == "" { + sh, err := stim.GetStimPath() + if err != nil { + stim.log.Warn("Could not find") + } else { + lfp = sh + "stim.log" + } + } + if lfp != "" { + stim.log.AddLogFile(lfp, stimlog.DebugLevel) + } + } // Set log level, this is done as early as possible so we can start using it if stim.GetConfigBool("verbose") == true { // stim.log.SetLevel(logrus.DebugLevel) stim.log.SetLevel(stimlog.DebugLevel) - stim.log.Debug("Stim version: ", stim.version) + stim.log.Debug("Stim version: {}", stim.version) stim.log.Debug("Debug log level set") } if loadConfigErr == nil { - stim.log.Debug("Using config file: ", stim.config.ConfigFileUsed()) + stim.log.Debug("Using config file: {}", stim.config.ConfigFileUsed()) } else { stim.log.Warn("Issue loading config file use -verbose for more info") stim.log.Debug(loadConfigErr) diff --git a/stim/vault.go b/stim/vault.go index 1be4160..e8b065b 100644 --- a/stim/vault.go +++ b/stim/vault.go @@ -37,7 +37,8 @@ func (stim *Stim) Vault() *vault.Vault { Noprompt: stim.GetConfigBool("noprompt") == false && stim.IsAutomated(), Username: username, // If set in the configs, pass in user InitialTokenDuration: timeInDuration, - }, stim.log) + Log: stim.log, + }) if err != nil { stim.log.Fatal(err) }