This is a quick note on how to change the log output level in Terraform.
- Introduction
- Outputting DEBUG-Level Logs in Terraform
- Setting Log Levels Separately for Terraform and Providers
- Appendix: Reading Terraform's Source Code
- Conclusion
- References
Introduction
When troubleshooting, logs are an important source of information.
If the default logs don't provide enough details, increasing the log level can be helpful.
In this post, I’ll summarize how to change the log level in Terraform, and also take a quick look at the relevant source code.
Note: This article was translated from my original post.
Outputting DEBUG-Level Logs in Terraform
To change the log level in Terraform, set the environment variable TF_LOG
.
Ref. Terraform | HashiCorp Developer
For example, to output DEBUG-level logs during terraform plan
, set TF_LOG
to DEBUG
:
# Set TF_LOG only for this command TF_LOG=DEBUG terraform plan # Set TF_LOG and then run the command export TF_LOG=DEBUG terraform plan
You can set the following log levels with TF_LOG
:
TRACE
DEBUG
INFO
WARN
ERROR
Choose the appropriate level depending on how much information you need.
Setting Log Levels Separately for Terraform and Providers
You can set different log levels for Terraform itself and for the provider.
To set the log level for Terraform, use the environment variable TF_LOG_CORE
.
To set the log level for the provider, use TF_LOG_PROVIDER
:
# Set Terraform log level to DEBUG and run plan TF_LOG_CORE=DEBUG terraform plan # Set Provider log level to DEBUG and run plan TF_LOG_PROVIDER=DEBUG terraform plan
Both TF_LOG_CORE
and TF_LOG_PROVIDER
support the same log levels as TF_LOG
:
TRACE
DEBUG
INFO
WARN
ERROR
Appendix: Reading Terraform's Source Code
Let’s also take a look at the part of the Terraform source code that handles log level settings.
// newHCLogger returns a new hclog.Logger instance with the given name func newHCLogger(name string) hclog.Logger { logOutput := io.Writer(os.Stderr) logLevel, json := globalLogLevel() if logPath := os.Getenv(envLogFile); logPath != "" { f, err := os.OpenFile(logPath, syscall.O_CREAT|syscall.O_RDWR|syscall.O_APPEND, 0666) if err != nil { fmt.Fprintf(os.Stderr, "Error opening log file: %v\n", err) } else { logOutput = f } } return hclog.NewInterceptLogger(&hclog.LoggerOptions{ Name: name, Level: logLevel, Output: logOutput, IndependentLevels: true, JSONFormat: json, }) } // NewLogger returns a new logger based in the current global logger, with the // given name appended. func NewLogger(name string) hclog.Logger { if name == "" { panic("logger name required") } return &logPanicWrapper{ Logger: logger.Named(name), } } // NewProviderLogger returns a logger for the provider plugin, possibly with a // different log level from the global logger. func NewProviderLogger(prefix string) hclog.Logger { l := &logPanicWrapper{ Logger: logger.Named(prefix + "provider"), } level := providerLogLevel() logger.Debug("created provider logger", "level", level) l.SetLevel(level) return l } // CurrentLogLevel returns the current log level string based the environment vars func CurrentLogLevel() string { ll, _ := globalLogLevel() return strings.ToUpper(ll.String()) } func providerLogLevel() hclog.Level { providerEnvLevel := strings.ToUpper(os.Getenv(envLogProvider)) if providerEnvLevel == "" { providerEnvLevel = strings.ToUpper(os.Getenv(envLog)) } return parseLogLevel(providerEnvLevel) } func globalLogLevel() (hclog.Level, bool) { var json bool envLevel := strings.ToUpper(os.Getenv(envLog)) if envLevel == "" { envLevel = strings.ToUpper(os.Getenv(envLogCore)) } if envLevel == "JSON" { json = true } return parseLogLevel(envLevel), json }
As you can see, the global log level is retrieved via globalLogLevel
and passed to newHCLogger
, while the provider log level is retrieved with providerLogLevel
and used in NewProviderLogger
.
The valid log levels are defined here:
// ValidLevels are the log level names that Terraform recognizes. ValidLevels = []string{"TRACE", "DEBUG", "INFO", "WARN", "ERROR", "OFF"}
Since strings.ToUpper
is used when parsing log level values, capitalization doesn’t matter.
Conclusion
That’s it for how to change the log output level in Terraform.
Just knowing this can help you troubleshoot faster. It’s worth adding to your toolbox.
[Related Articles]