From 0090c063e8c29d8af226b00bffd31e8eb3b35f77 Mon Sep 17 00:00:00 2001 From: Fatih Arslan Date: Thu, 1 Oct 2015 22:45:12 +0300 Subject: [PATCH 1/2] log: support for user defined log levels This PR brings support for better log level handling. Terraform logs are already written in the form which can be understood by the module https://github.com/hashicorp/logutils . The TF_LOG environment variable now accepts a log level. Users can pass levels in the form of "info", "Info" or "INFO" If an invalid log level is passed, we print a warning but still continue, for backward compatibility with the old TF_LOG=1 style. --- log.go | 61 ++++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 49 insertions(+), 12 deletions(-) diff --git a/log.go b/log.go index 70046b34772f..1077c3e55846 100644 --- a/log.go +++ b/log.go @@ -2,28 +2,65 @@ package main import ( "io" + "log" "os" + "strings" + + "github.com/hashicorp/logutils" ) // These are the environmental variables that determine if we log, and if // we log whether or not the log should go to a file. -const EnvLog = "TF_LOG" //Set to True -const EnvLogFile = "TF_LOG_PATH" //Set to a file +const ( + EnvLog = "TF_LOG" // Set to True + EnvLogFile = "TF_LOG_PATH" // Set to a file +) -// logOutput determines where we should send logs (if anywhere). +var validLevels = []logutils.LogLevel{"TRACE", "DEBUG", "INFO", "WARN", "ERROR"} + +// logOutput determines where we should send logs (if anywhere) and the log level. func logOutput() (logOutput io.Writer, err error) { logOutput = nil - if os.Getenv(EnvLog) != "" { - logOutput = os.Stderr - - if logPath := os.Getenv(EnvLogFile); logPath != "" { - var err error - logOutput, err = os.Create(logPath) - if err != nil { - return nil, err - } + envLevel := os.Getenv(EnvLog) + if envLevel == "" { + return + } + + logOutput = os.Stderr + if logPath := os.Getenv(EnvLogFile); logPath != "" { + var err error + logOutput, err = os.Create(logPath) + if err != nil { + return nil, err } } + // This was the default since the beginning + logLevel := logutils.LogLevel("TRACE") + + if isValidLogLevel(envLevel) { + // allow following for better ux: info, Info or INFO + logLevel = logutils.LogLevel(strings.ToUpper(envLevel)) + } else { + log.Printf("[WARN] Invalid log level: %q. Defaulting to level: TRACE. Valid levels are: %+v", + envLevel, validLevels) + } + + logOutput = &logutils.LevelFilter{ + Levels: validLevels, + MinLevel: logLevel, + Writer: logOutput, + } + return } + +func isValidLogLevel(level string) bool { + for _, l := range validLevels { + if strings.ToUpper(level) == string(l) { + return true + } + } + + return false +} From 8173cd25bb69b4f0be7bf1a15105d5b1d0c08860 Mon Sep 17 00:00:00 2001 From: Martin Atkins Date: Sun, 11 Oct 2015 10:45:33 -0700 Subject: [PATCH 2/2] Demote some log lines to DEBUG. Now that we support log line filtering (as of 0090c063) it's good to be a bit more fussy about what log levels are assigned to different things. Here we make a few things that are implementation details log as DEBUG, and prevent spurious errors from EvalValidateCount where it was returning an empty EvalValidateError rather than nil when everything was okay. --- config_unix.go | 2 +- plugin/client.go | 4 ++-- terraform/context.go | 2 +- terraform/eval_validate.go | 7 +++++-- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/config_unix.go b/config_unix.go index c51ea5ec4ff1..69d76278af36 100644 --- a/config_unix.go +++ b/config_unix.go @@ -33,7 +33,7 @@ func configDir() (string, error) { func homeDir() (string, error) { // First prefer the HOME environmental variable if home := os.Getenv("HOME"); home != "" { - log.Printf("Detected home directory from env var: %s", home) + log.Printf("[DEBUG] Detected home directory from env var: %s", home) return home, nil } diff --git a/plugin/client.go b/plugin/client.go index be54526c738f..8a3b03fc0a25 100644 --- a/plugin/client.go +++ b/plugin/client.go @@ -88,7 +88,7 @@ func CleanupClients() { }(client) } - log.Println("waiting for all plugin processes to complete...") + log.Println("[DEBUG] waiting for all plugin processes to complete...") wg.Wait() } @@ -326,7 +326,7 @@ func (c *Client) logStderr(r io.Reader) { c.config.Stderr.Write([]byte(line)) line = strings.TrimRightFunc(line, unicode.IsSpace) - log.Printf("%s: %s", filepath.Base(c.config.Cmd.Path), line) + log.Printf("[DEBUG] %s: %s", filepath.Base(c.config.Cmd.Path), line) } if err == io.EOF { diff --git a/terraform/context.go b/terraform/context.go index 0f567ddf244c..d91a851765e0 100644 --- a/terraform/context.go +++ b/terraform/context.go @@ -513,7 +513,7 @@ func (c *Context) releaseRun(ch chan<- struct{}) { func (c *Context) walk( graph *Graph, operation walkOperation) (*ContextGraphWalker, error) { // Walk the graph - log.Printf("[INFO] Starting graph walk: %s", operation.String()) + log.Printf("[DEBUG] Starting graph walk: %s", operation.String()) walker := &ContextGraphWalker{Context: c, Operation: operation} return walker, graph.Walk(walker) } diff --git a/terraform/eval_validate.go b/terraform/eval_validate.go index e808240a025c..53378823056e 100644 --- a/terraform/eval_validate.go +++ b/terraform/eval_validate.go @@ -49,9 +49,12 @@ func (n *EvalValidateCount) Eval(ctx EvalContext) (interface{}, error) { } RETURN: - return nil, &EvalValidateError{ - Errors: errs, + if len(errs) != 0 { + err = &EvalValidateError{ + Errors: errs, + } } + return nil, err } // EvalValidateProvider is an EvalNode implementation that validates