2015-12-08 01:10:30 +01:00
package logging
2014-05-31 01:07:26 +02:00
import (
2020-10-17 15:38:18 +02:00
"fmt"
2014-05-31 01:07:26 +02:00
"io"
2015-12-08 01:10:30 +01:00
"io/ioutil"
2015-10-01 21:45:12 +02:00
"log"
2014-05-31 01:07:26 +02:00
"os"
2015-10-01 21:45:12 +02:00
"strings"
2016-10-18 22:08:23 +02:00
"syscall"
2020-10-17 15:38:18 +02:00
"github.com/hashicorp/go-hclog"
2014-05-31 01:07:26 +02:00
)
// These are the environmental variables that determine if we log, and if
// we log whether or not the log should go to a file.
2015-10-01 21:45:12 +02:00
const (
EnvLog = "TF_LOG" // Set to True
EnvLogFile = "TF_LOG_PATH" // Set to a file
)
2014-05-31 01:07:26 +02:00
2019-12-05 20:13:37 +01:00
// ValidLevels are the log level names that Terraform recognizes.
var ValidLevels = [ ] LogLevel { "TRACE" , "DEBUG" , "INFO" , "WARN" , "ERROR" }
2015-10-01 21:45:12 +02:00
2020-10-17 15:38:18 +02:00
// logger is the global hclog logger
var logger hclog . Logger
2016-03-14 17:17:05 +01:00
2020-10-17 15:38:18 +02:00
func init ( ) {
2020-10-17 15:57:03 +02:00
logger = NewHCLogger ( "" )
}
// 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
}
// HCLogger returns the default global loggers
func HCLogger ( ) hclog . Logger {
return logger
}
// NewHCLogger returns a new hclog.Logger instance with the given name
func NewHCLogger ( name string ) hclog . Logger {
2020-10-17 15:38:18 +02:00
logOutput := io . Writer ( os . Stderr )
2019-12-05 20:13:37 +01:00
logLevel := CurrentLogLevel ( )
2016-03-14 17:17:05 +01:00
if logLevel == "" {
2020-10-17 15:38:18 +02:00
logOutput = ioutil . Discard
2015-10-01 21:45:12 +02:00
}
if logPath := os . Getenv ( EnvLogFile ) ; logPath != "" {
2020-10-17 15:38:18 +02:00
f , err := os . OpenFile ( logPath , syscall . O_CREAT | syscall . O_RDWR | syscall . O_APPEND , 0666 )
2015-10-01 21:45:12 +02:00
if err != nil {
2020-10-17 15:38:18 +02:00
fmt . Fprintf ( os . Stderr , "Error opening log file: %v\n" , err )
} else {
logOutput = f
2014-05-31 01:07:26 +02:00
}
}
2020-10-17 15:57:03 +02:00
return hclog . New ( & hclog . LoggerOptions {
Name : name ,
2020-10-17 15:38:18 +02:00
Level : hclog . LevelFromString ( logLevel ) ,
Output : logOutput ,
} )
}
2019-12-05 21:19:22 +01:00
2016-08-01 23:16:22 +02:00
// SetOutput checks for a log destination with LogOutput, and calls
// log.SetOutput with the result. If LogOutput returns nil, SetOutput uses
// ioutil.Discard. Any error from LogOutout is fatal.
func SetOutput ( ) {
out , err := LogOutput ( )
if err != nil {
log . Fatal ( err )
}
if out == nil {
out = ioutil . Discard
}
2020-10-17 15:38:18 +02:00
// the hclog logger will add the prefix info
log . SetFlags ( 0 )
log . SetPrefix ( "" )
2016-08-01 23:16:22 +02:00
log . SetOutput ( out )
}
2019-12-05 20:13:37 +01:00
// CurrentLogLevel returns the current log level string based the environment vars
func CurrentLogLevel ( ) string {
2020-10-17 15:38:18 +02:00
envLevel := strings . ToUpper ( os . Getenv ( EnvLog ) )
2016-03-14 17:17:05 +01:00
if envLevel == "" {
return ""
}
logLevel := "TRACE"
2015-10-01 21:45:12 +02:00
if isValidLogLevel ( envLevel ) {
2020-10-17 15:38:18 +02:00
logLevel = envLevel
2015-10-01 21:45:12 +02:00
} else {
log . Printf ( "[WARN] Invalid log level: %q. Defaulting to level: TRACE. Valid levels are: %+v" ,
2017-10-14 15:35:36 +02:00
envLevel , ValidLevels )
2015-10-01 21:45:12 +02:00
}
2019-12-05 20:49:11 +01:00
if logLevel != "TRACE" {
log . Printf ( "[WARN] Log levels other than TRACE are currently unreliable, and are supported only for backward compatibility.\n Use TF_LOG=TRACE to see Terraform's internal logs.\n ----" )
}
2015-10-01 21:45:12 +02:00
2016-03-14 17:17:05 +01:00
return logLevel
}
2015-10-01 21:45:12 +02:00
2016-03-14 17:17:05 +01:00
// IsDebugOrHigher returns whether or not the current log level is debug or trace
func IsDebugOrHigher ( ) bool {
2019-12-05 20:13:37 +01:00
level := string ( CurrentLogLevel ( ) )
2016-03-14 17:17:05 +01:00
return level == "DEBUG" || level == "TRACE"
2014-05-31 01:07:26 +02:00
}
2015-10-01 21:45:12 +02:00
func isValidLogLevel ( level string ) bool {
2017-10-14 15:35:36 +02:00
for _ , l := range ValidLevels {
2020-10-17 15:38:18 +02:00
if level == string ( l ) {
2015-10-01 21:45:12 +02:00
return true
}
}
return false
}