github.com/IBM-Cloud/bluemix-go@v0.0.0-20240423071914-9e96525baef4/trace/trace.go (about)

     1  package trace
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"log"
     7  	"os"
     8  	"regexp"
     9  	"strings"
    10  )
    11  
    12  //Printer ...
    13  type Printer interface {
    14  	Print(v ...interface{})
    15  	Printf(format string, v ...interface{})
    16  	Println(v ...interface{})
    17  }
    18  
    19  //Closer ...
    20  type Closer interface {
    21  	Close() error
    22  }
    23  
    24  //PrinterCloser ...
    25  type PrinterCloser interface {
    26  	Printer
    27  	Closer
    28  }
    29  
    30  //NullLogger ...
    31  type NullLogger struct{}
    32  
    33  func (l *NullLogger) Print(v ...interface{})                 {}
    34  func (l *NullLogger) Printf(format string, v ...interface{}) {}
    35  func (l *NullLogger) Println(v ...interface{})               {}
    36  
    37  type loggerImpl struct {
    38  	*log.Logger
    39  	c io.WriteCloser
    40  }
    41  
    42  func (loggerImpl *loggerImpl) Close() error {
    43  	if loggerImpl.c != nil {
    44  		return loggerImpl.c.Close()
    45  	}
    46  	return nil
    47  }
    48  
    49  var (
    50  	stdout = os.Stdout
    51  	stderr = os.Stderr
    52  )
    53  
    54  func newLoggerImpl(out io.Writer, prefix string, flag int) *loggerImpl {
    55  	l := log.New(out, prefix, flag)
    56  	c := out.(io.WriteCloser)
    57  	return &loggerImpl{
    58  		Logger: l,
    59  		c:      c,
    60  	}
    61  }
    62  
    63  //Logger is global logger
    64  var Logger Printer = NewLogger("")
    65  
    66  // NewLogger returns a printer for the given trace setting.
    67  func NewLogger(bluemix_trace string) Printer {
    68  	switch strings.ToLower(bluemix_trace) {
    69  	case "", "false":
    70  		return new(NullLogger)
    71  	case "true":
    72  		return NewStdLogger()
    73  	default:
    74  		return NewFileLogger(bluemix_trace)
    75  	}
    76  }
    77  
    78  // NewStdLogger return a printer that writes to StdOut.
    79  func NewStdLogger() PrinterCloser {
    80  	if os.Getenv("IBMCLOUD_BLUEMIX_GO_TRACE") != "" {
    81  		return newLoggerImpl(stdout, "", 0)
    82  	}
    83  	return newLoggerImpl(stderr, "", 0)
    84  }
    85  
    86  // NewFileLogger return a printer that writes to the given file path.
    87  func NewFileLogger(path string) PrinterCloser {
    88  	file, err := os.OpenFile(path, os.O_CREATE|os.O_RDWR|os.O_APPEND, 0644)
    89  	if err != nil {
    90  		logger := NewStdLogger()
    91  		logger.Printf("[ERROR] An error occurred when creating log file '%s':\n%v\n\n", path, err)
    92  		return logger
    93  	}
    94  	return newLoggerImpl(file, "", 0)
    95  }
    96  
    97  // Sanitize returns a clean string with sentive user data in the input
    98  // replaced by PRIVATE_DATA_PLACEHOLDER.
    99  func Sanitize(input string) string {
   100  	re := regexp.MustCompile(`(?m)^Authorization: .*`)
   101  	sanitized := re.ReplaceAllString(input, "Authorization: "+privateDataPlaceholder())
   102  
   103  	re = regexp.MustCompile(`(?m)^X-Auth-Token: .*`)
   104  	sanitized = re.ReplaceAllString(sanitized, "X-Auth-Token: "+privateDataPlaceholder())
   105  
   106  	re = regexp.MustCompile(`(?m)^X-Auth-Refresh-Token: .*`)
   107  	sanitized = re.ReplaceAllString(sanitized, "X-Auth-Refresh-Token: "+privateDataPlaceholder())
   108  
   109  	re = regexp.MustCompile(`(?m)^X-Auth-Uaa-Token: .*`)
   110  	sanitized = re.ReplaceAllString(sanitized, "X-Auth-Uaa-Token: "+privateDataPlaceholder())
   111  
   112  	re = regexp.MustCompile(`(?m)^X-Auth-User-Token: .*`)
   113  	sanitized = re.ReplaceAllString(sanitized, "X-Auth-User-Token: "+privateDataPlaceholder())
   114  
   115  	re = regexp.MustCompile(`password=[^&]*&`)
   116  	sanitized = re.ReplaceAllString(sanitized, "password="+privateDataPlaceholder()+"&")
   117  
   118  	re = regexp.MustCompile(`refresh_token=[^&]*&`)
   119  	sanitized = re.ReplaceAllString(sanitized, "refresh_token="+privateDataPlaceholder()+"&")
   120  
   121  	re = regexp.MustCompile(`apikey=[^&]*&`)
   122  	sanitized = re.ReplaceAllString(sanitized, "apikey="+privateDataPlaceholder()+"&")
   123  
   124  	sanitized = sanitizeJSON("token", sanitized)
   125  	sanitized = sanitizeJSON("password", sanitized)
   126  	sanitized = sanitizeJSON("apikey", sanitized)
   127  	sanitized = sanitizeJSON("passcode", sanitized)
   128  
   129  	return sanitized
   130  }
   131  
   132  func sanitizeJSON(propertySubstring string, json string) string {
   133  	regex := regexp.MustCompile(fmt.Sprintf(`(?i)"([^"]*%s[^"]*)":\s*"[^\,]*"`, propertySubstring))
   134  	return regex.ReplaceAllString(json, fmt.Sprintf(`"$1":"%s"`, privateDataPlaceholder()))
   135  }
   136  
   137  // privateDataPlaceholder returns the text to replace the sentive data.
   138  func privateDataPlaceholder() string {
   139  	return "[PRIVATE DATA HIDDEN]"
   140  }