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  }