github.com/mier85/go-sensor@v1.30.1-0.20220920111756-9bf41b3bc7e0/logger/logger.go (about)

     1  // (c) Copyright IBM Corp. 2021
     2  // (c) Copyright Instana Inc. 2020
     3  
     4  package logger
     5  
     6  import (
     7  	"fmt"
     8  	"log"
     9  	"os"
    10  	"strings"
    11  	"sync"
    12  )
    13  
    14  // Valid log levels to be used with (*logger.Logger).SetLevel()
    15  const (
    16  	ErrorLevel Level = iota
    17  	WarnLevel
    18  	InfoLevel
    19  	DebugLevel
    20  )
    21  
    22  // DefaultPrefix is the default log prefix used by Logger
    23  const DefaultPrefix = "instana: "
    24  
    25  // Level defines the minimum logging level for logger.Log
    26  type Level uint8
    27  
    28  // Less returns whether the log level is less than the given one in logical order:
    29  // ErrorLevel > WarnLevel > InfoLevel > DebugLevel
    30  func (lvl Level) Less(other Level) bool {
    31  	return uint8(lvl) > uint8(other)
    32  }
    33  
    34  // String returns the log line label for this level
    35  func (lvl Level) String() string {
    36  	switch lvl {
    37  	case DebugLevel:
    38  		return "DEBUG"
    39  	case InfoLevel:
    40  		return "INFO"
    41  	case WarnLevel:
    42  		return "WARN"
    43  	case ErrorLevel:
    44  		return "ERROR"
    45  	default:
    46  		return "UNKNOWN"
    47  	}
    48  }
    49  
    50  // Printer is used by logger.Log instance to print out a log message
    51  type Printer interface {
    52  	Print(a ...interface{})
    53  }
    54  
    55  // Logger is a configurable leveled logger used by Instana's Go sensor. It follows the same interface
    56  // as github.com/sirupsen/logrus.Logger and go.uber.org/zap.SugaredLogger
    57  type Logger struct {
    58  	p Printer
    59  
    60  	mu     sync.Mutex
    61  	lvl    Level
    62  	prefix string
    63  }
    64  
    65  // New initializes a new instance of Logger that uses provided printer as a backend to
    66  // output the log messages. The stdlib log.Logger satisfies logger.Printer interface:
    67  //
    68  // 	logger := logger.New(logger.WarnLevel, log.New(os.Stderr, "instana:", log.LstdFlags))
    69  // 	logger.SetLevel(logger.WarnLevel)
    70  //
    71  // 	logger.Debug("this is a debug message") // won't be printed
    72  // 	logger.Error("this is an  message") // ... while this one will
    73  //
    74  // In case  there is no printer provided, logger.Logger will use a new instance of log.Logger
    75  // initialized with log.Lstdflags that writes to os.Stderr:
    76  //
    77  // 	log.New(os.Stderr, "", log.Lstdflags)
    78  //
    79  // The default logging level for a new logger instance is logger.ErrorLevel.
    80  func New(printer Printer) *Logger {
    81  	if printer == nil {
    82  		printer = log.New(os.Stderr, "", log.LstdFlags)
    83  	}
    84  
    85  	l := &Logger{
    86  		p:      printer,
    87  		prefix: DefaultPrefix,
    88  	}
    89  
    90  	setInstanaLogLevel(l)
    91  
    92  	return l
    93  }
    94  
    95  func setInstanaLogLevel(l *Logger) {
    96  	instanaLogLevelEnvVar := os.Getenv("INSTANA_LOG_LEVEL")
    97  
    98  	envVarLogLevel := map[string]Level{
    99  		"error": ErrorLevel,
   100  		"info":  InfoLevel,
   101  		"warn":  WarnLevel,
   102  		"debug": DebugLevel,
   103  	}
   104  
   105  	if value, ok := envVarLogLevel[strings.ToLower(instanaLogLevelEnvVar)]; ok {
   106  		l.SetLevel(value)
   107  	} else {
   108  		l.SetLevel(ErrorLevel)
   109  	}
   110  }
   111  
   112  // SetLevel changes the log level for this logger instance. In case there is an INSTANA_DEBUG env variable set,
   113  // the provided log level will be overridden with DebugLevel.
   114  func (l *Logger) SetLevel(level Level) {
   115  	if _, ok := os.LookupEnv("INSTANA_DEBUG"); ok {
   116  		if level != DebugLevel {
   117  			defer l.Info(
   118  				"INSTANA_DEBUG env variable is set, the log level has been set to ",
   119  				DebugLevel,
   120  				" instead of requested ",
   121  				level,
   122  			)
   123  		}
   124  		level = DebugLevel
   125  	}
   126  
   127  	l.mu.Lock()
   128  	defer l.mu.Unlock()
   129  
   130  	l.lvl = level
   131  }
   132  
   133  // SetPrefix sets the label that will be used as a prefix for each log line
   134  func (l *Logger) SetPrefix(prefix string) {
   135  	l.mu.Lock()
   136  	defer l.mu.Unlock()
   137  
   138  	l.prefix = prefix
   139  }
   140  
   141  // Debug appends a debug message to the log
   142  func (l *Logger) Debug(v ...interface{}) {
   143  	if l.lvl < DebugLevel {
   144  		return
   145  	}
   146  
   147  	l.print(DebugLevel, v)
   148  }
   149  
   150  // Info appends an info message to the log
   151  func (l *Logger) Info(v ...interface{}) {
   152  	if l.lvl < InfoLevel {
   153  		return
   154  	}
   155  
   156  	l.print(InfoLevel, v)
   157  }
   158  
   159  // Warn appends a warning message to the log
   160  func (l *Logger) Warn(v ...interface{}) {
   161  	if l.lvl < WarnLevel {
   162  		return
   163  	}
   164  
   165  	l.print(WarnLevel, v)
   166  }
   167  
   168  // Error appends an error message to the log
   169  func (l *Logger) Error(v ...interface{}) {
   170  	if l.lvl < ErrorLevel {
   171  		return
   172  	}
   173  
   174  	l.print(ErrorLevel, v)
   175  }
   176  
   177  func (l *Logger) print(lvl Level, v []interface{}) {
   178  	l.p.Print(l.prefix, lvl.String(), ": ", fmt.Sprint(v...))
   179  }