github.com/hashicorp/terraform-plugin-sdk@v1.17.2/helper/logging/logging.go (about) 1 package logging 2 3 import ( 4 "io" 5 "io/ioutil" 6 "log" 7 "os" 8 "strings" 9 "syscall" 10 11 "github.com/hashicorp/logutils" 12 testing "github.com/mitchellh/go-testing-interface" 13 ) 14 15 // These are the environmental variables that determine if we log, and if 16 // we log whether or not the log should go to a file. 17 const ( 18 EnvLog = "TF_LOG" // Set to True 19 EnvLogFile = "TF_LOG_PATH" // Set to a file 20 ) 21 22 var ValidLevels = []logutils.LogLevel{"TRACE", "DEBUG", "INFO", "WARN", "ERROR"} 23 24 // LogOutput determines where we should send logs (if anywhere) and the log level. 25 func LogOutput() (logOutput io.Writer, err error) { 26 logOutput = ioutil.Discard 27 28 logLevel := LogLevel() 29 if logLevel == "" { 30 return 31 } 32 33 logOutput = os.Stderr 34 if logPath := os.Getenv(EnvLogFile); logPath != "" { 35 var err error 36 logOutput, err = os.OpenFile(logPath, syscall.O_CREAT|syscall.O_RDWR|syscall.O_APPEND, 0666) 37 if err != nil { 38 return nil, err 39 } 40 } 41 42 // This was the default since the beginning 43 logOutput = &logutils.LevelFilter{ 44 Levels: ValidLevels, 45 MinLevel: logutils.LogLevel(logLevel), 46 Writer: logOutput, 47 } 48 49 return 50 } 51 52 // SetTestOutput is equivalent to SetOutput, but declares itself a test 53 // helper so it doesn't show up as the source of errors when testing. 54 func SetTestOutput(t testing.T) { 55 setOutput(t) 56 } 57 58 // SetOutput checks for a log destination with LogOutput, and calls 59 // log.SetOutput with the result. If LogOutput returns nil, SetOutput uses 60 // ioutil.Discard. Any error from LogOutout is fatal. 61 func SetOutput() { 62 setOutput(nil) 63 } 64 65 func setOutput(t testing.T) { 66 if t != nil { 67 t.Helper() 68 } 69 out, err := LogOutput() 70 if err != nil { 71 log.Fatal(err) 72 } 73 74 if out == nil { 75 out = ioutil.Discard 76 } 77 78 log.SetOutput(out) 79 } 80 81 // LogLevel returns the current log level string based the environment vars 82 func LogLevel() string { 83 envLevel := os.Getenv(EnvLog) 84 if envLevel == "" { 85 return "" 86 } 87 88 logLevel := "TRACE" 89 if isValidLogLevel(envLevel) { 90 // allow following for better ux: info, Info or INFO 91 logLevel = strings.ToUpper(envLevel) 92 } else { 93 log.Printf("[WARN] Invalid log level: %q. Defaulting to level: TRACE. Valid levels are: %+v", 94 envLevel, ValidLevels) 95 } 96 97 return logLevel 98 } 99 100 // IsDebugOrHigher returns whether or not the current log level is debug or trace 101 func IsDebugOrHigher() bool { 102 level := string(LogLevel()) 103 return level == "DEBUG" || level == "TRACE" 104 } 105 106 func isValidLogLevel(level string) bool { 107 for _, l := range ValidLevels { 108 if strings.ToUpper(level) == string(l) { 109 return true 110 } 111 } 112 113 return false 114 }