From 211edf5d7545bcb5cd741bad6145ccc4e261bcd3 Mon Sep 17 00:00:00 2001 From: James Bardin Date: Sat, 17 Oct 2020 09:38:18 -0400 Subject: [PATCH] use hclog as the default logger Inject hclog as the default logger in the main binary. --- internal/logging/logging.go | 54 ++++++++++++++++++++----------------- main.go | 13 +-------- plugin/client.go | 8 ++---- terraform/context.go | 5 ++++ 4 files changed, 37 insertions(+), 43 deletions(-) diff --git a/internal/logging/logging.go b/internal/logging/logging.go index 75627cf02..089f41af3 100644 --- a/internal/logging/logging.go +++ b/internal/logging/logging.go @@ -1,12 +1,15 @@ package logging import ( + "fmt" "io" "io/ioutil" "log" "os" "strings" "syscall" + + "github.com/hashicorp/go-hclog" ) // These are the environmental variables that determine if we log, and if @@ -19,39 +22,38 @@ const ( // ValidLevels are the log level names that Terraform recognizes. var ValidLevels = []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 = ioutil.Discard +// logger is the global hclog logger +var logger hclog.Logger +func init() { + logOutput := io.Writer(os.Stderr) logLevel := CurrentLogLevel() if logLevel == "" { - return + logOutput = ioutil.Discard } - logOutput = os.Stderr if logPath := os.Getenv(EnvLogFile); logPath != "" { - var err error - logOutput, err = os.OpenFile(logPath, syscall.O_CREAT|syscall.O_RDWR|syscall.O_APPEND, 0666) + f, err := os.OpenFile(logPath, syscall.O_CREAT|syscall.O_RDWR|syscall.O_APPEND, 0666) if err != nil { - return nil, err + fmt.Fprintf(os.Stderr, "Error opening log file: %v\n", err) + } else { + logOutput = f } } - if logLevel == "TRACE" { - // Just pass through logs directly then, without any level filtering at all. - return logOutput, nil - } + logger = hclog.New(&hclog.LoggerOptions{ + Level: hclog.LevelFromString(logLevel), + Output: logOutput, + }) +} - // Otherwise we'll use our level filter, which is a heuristic-based - // best effort thing that is not totally reliable but helps to reduce - // the volume of logs in some cases. - logOutput = &LevelFilter{ - Levels: ValidLevels, - MinLevel: LogLevel(logLevel), - Writer: logOutput, - } +// LogOutput determines where we should send logs (if anywhere) and the log level. +func LogOutput() (logOutput io.Writer, err error) { + return logger.StandardWriter(&hclog.StandardLoggerOptions{InferLevels: true}), nil +} - return logOutput, nil +func HCLogger() hclog.Logger { + return logger } // SetOutput checks for a log destination with LogOutput, and calls @@ -67,20 +69,22 @@ func SetOutput() { out = ioutil.Discard } + // the hclog logger will add the prefix info + log.SetFlags(0) + log.SetPrefix("") log.SetOutput(out) } // CurrentLogLevel returns the current log level string based the environment vars func CurrentLogLevel() string { - envLevel := os.Getenv(EnvLog) + envLevel := strings.ToUpper(os.Getenv(EnvLog)) if envLevel == "" { return "" } logLevel := "TRACE" if isValidLogLevel(envLevel) { - // allow following for better ux: info, Info or INFO - logLevel = strings.ToUpper(envLevel) + logLevel = envLevel } else { log.Printf("[WARN] Invalid log level: %q. Defaulting to level: TRACE. Valid levels are: %+v", envLevel, ValidLevels) @@ -100,7 +104,7 @@ func IsDebugOrHigher() bool { func isValidLogLevel(level string) bool { for _, l := range ValidLevels { - if strings.ToUpper(level) == string(l) { + if level == string(l) { return true } } diff --git a/main.go b/main.go index 28e8b169a..e87a90231 100644 --- a/main.go +++ b/main.go @@ -19,7 +19,6 @@ import ( "github.com/hashicorp/terraform/command/cliconfig" "github.com/hashicorp/terraform/command/format" "github.com/hashicorp/terraform/httpclient" - "github.com/hashicorp/terraform/internal/logging" "github.com/hashicorp/terraform/version" "github.com/mattn/go-colorable" "github.com/mattn/go-shellwords" @@ -37,8 +36,6 @@ const ( ) func main() { - // Override global prefix set by go-dynect during init() - log.SetPrefix("") os.Exit(realMain()) } @@ -51,13 +48,6 @@ func realMain() int { } if !panicwrap.Wrapped(&wrapConfig) { - // Determine where logs should go in general (requested by the user) - logWriter, err := logging.LogOutput() - if err != nil { - fmt.Fprintf(os.Stderr, "Couldn't setup log output: %s", err) - return 1 - } - // We always send logs to a temporary file that we use in case // there is a panic. Otherwise, we delete it. logTempFile, err := ioutil.TempFile("", "terraform-log") @@ -76,7 +66,7 @@ func realMain() int { // Create the configuration for panicwrap and wrap our executable wrapConfig.Handler = panicHandler(logTempFile) - wrapConfig.Writer = io.MultiWriter(logTempFile, logWriter) + wrapConfig.Writer = os.Stderr wrapConfig.Stdout = outW wrapConfig.IgnoreSignals = ignoreSignals wrapConfig.ForwardSignals = forwardSignals @@ -122,7 +112,6 @@ func init() { func wrappedMain() int { var err error - log.SetOutput(os.Stderr) log.Printf( "[INFO] Terraform version: %s %s %s", Version, VersionPrerelease, GitCommit) diff --git a/plugin/client.go b/plugin/client.go index f20f913f8..66621fe10 100644 --- a/plugin/client.go +++ b/plugin/client.go @@ -4,8 +4,8 @@ import ( "os" "os/exec" - hclog "github.com/hashicorp/go-hclog" plugin "github.com/hashicorp/go-plugin" + "github.com/hashicorp/terraform/internal/logging" "github.com/hashicorp/terraform/plugin/discovery" ) @@ -17,11 +17,7 @@ var enableAutoMTLS = os.Getenv("TF_DISABLE_PLUGIN_TLS") == "" // ClientConfig returns a configuration object that can be used to instantiate // a client for the plugin described by the given metadata. func ClientConfig(m discovery.PluginMeta) *plugin.ClientConfig { - logger := hclog.New(&hclog.LoggerOptions{ - Name: "plugin", - Level: hclog.Trace, - Output: os.Stderr, - }) + logger := logging.HCLogger() return &plugin.ClientConfig{ Cmd: exec.Command(m.Path), diff --git a/terraform/context.go b/terraform/context.go index ec25b9e6a..44d6ec894 100644 --- a/terraform/context.go +++ b/terraform/context.go @@ -10,6 +10,7 @@ import ( "github.com/hashicorp/terraform/addrs" "github.com/hashicorp/terraform/configs" "github.com/hashicorp/terraform/instances" + "github.com/hashicorp/terraform/internal/logging" "github.com/hashicorp/terraform/lang" "github.com/hashicorp/terraform/plans" "github.com/hashicorp/terraform/providers" @@ -20,6 +21,10 @@ import ( "github.com/zclconf/go-cty/cty" ) +func init() { + logging.SetOutput() +} + // InputMode defines what sort of input will be asked for when Input // is called on Context. type InputMode byte