github.com/muhammadn/cortex@v1.9.1-0.20220510110439-46bb7000d03d/pkg/util/log/log.go (about)

     1  package log
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  
     7  	"github.com/go-kit/log"
     8  	kitlog "github.com/go-kit/log"
     9  	"github.com/go-kit/log/level"
    10  	"github.com/prometheus/client_golang/prometheus"
    11  	"github.com/weaveworks/common/logging"
    12  	"github.com/weaveworks/common/server"
    13  )
    14  
    15  var (
    16  	// Logger is a shared go-kit logger.
    17  	// TODO: Change all components to take a non-global logger via their constructors.
    18  	// Prefer accepting a non-global logger as an argument.
    19  	Logger = kitlog.NewNopLogger()
    20  
    21  	logMessages = prometheus.NewCounterVec(prometheus.CounterOpts{
    22  		Name: "log_messages_total",
    23  		Help: "Total number of log messages.",
    24  	}, []string{"level"})
    25  
    26  	supportedLevels = []level.Value{
    27  		level.DebugValue(),
    28  		level.InfoValue(),
    29  		level.WarnValue(),
    30  		level.ErrorValue(),
    31  	}
    32  )
    33  
    34  func init() {
    35  	prometheus.MustRegister(logMessages)
    36  }
    37  
    38  // InitLogger initialises the global gokit logger (util_log.Logger) and overrides the
    39  // default logger for the server.
    40  func InitLogger(cfg *server.Config) {
    41  	l, err := NewPrometheusLogger(cfg.LogLevel, cfg.LogFormat)
    42  	if err != nil {
    43  		panic(err)
    44  	}
    45  
    46  	// when use util_log.Logger, skip 3 stack frames.
    47  	Logger = log.With(l, "caller", log.Caller(3))
    48  
    49  	// cfg.Log wraps log function, skip 4 stack frames to get caller information.
    50  	// this works in go 1.12, but doesn't work in versions earlier.
    51  	// it will always shows the wrapper function generated by compiler
    52  	// marked <autogenerated> in old versions.
    53  	cfg.Log = logging.GoKit(log.With(l, "caller", log.Caller(4)))
    54  }
    55  
    56  // PrometheusLogger exposes Prometheus counters for each of go-kit's log levels.
    57  type PrometheusLogger struct {
    58  	logger log.Logger
    59  }
    60  
    61  // NewPrometheusLogger creates a new instance of PrometheusLogger which exposes
    62  // Prometheus counters for various log levels.
    63  func NewPrometheusLogger(l logging.Level, format logging.Format) (log.Logger, error) {
    64  	logger := log.NewLogfmtLogger(log.NewSyncWriter(os.Stderr))
    65  	if format.String() == "json" {
    66  		logger = log.NewJSONLogger(log.NewSyncWriter(os.Stderr))
    67  	}
    68  	logger = level.NewFilter(logger, LevelFilter(l.String()))
    69  
    70  	// Initialise counters for all supported levels:
    71  	for _, level := range supportedLevels {
    72  		logMessages.WithLabelValues(level.String())
    73  	}
    74  
    75  	logger = &PrometheusLogger{
    76  		logger: logger,
    77  	}
    78  
    79  	// return a Logger without caller information, shouldn't use directly
    80  	logger = log.With(logger, "ts", log.DefaultTimestampUTC)
    81  	return logger, nil
    82  }
    83  
    84  // Log increments the appropriate Prometheus counter depending on the log level.
    85  func (pl *PrometheusLogger) Log(kv ...interface{}) error {
    86  	pl.logger.Log(kv...)
    87  	l := "unknown"
    88  	for i := 1; i < len(kv); i += 2 {
    89  		if v, ok := kv[i].(level.Value); ok {
    90  			l = v.String()
    91  			break
    92  		}
    93  	}
    94  	logMessages.WithLabelValues(l).Inc()
    95  	return nil
    96  }
    97  
    98  // CheckFatal prints an error and exits with error code 1 if err is non-nil
    99  func CheckFatal(location string, err error) {
   100  	if err != nil {
   101  		logger := level.Error(Logger)
   102  		if location != "" {
   103  			logger = log.With(logger, "msg", "error "+location)
   104  		}
   105  		// %+v gets the stack trace from errors using github.com/pkg/errors
   106  		logger.Log("err", fmt.Sprintf("%+v", err))
   107  		os.Exit(1)
   108  	}
   109  }
   110  
   111  // TODO(dannyk): remove once weaveworks/common updates to go-kit/log
   112  //                                     -> we can then revert to using Level.Gokit
   113  func LevelFilter(l string) level.Option {
   114  	switch l {
   115  	case "debug":
   116  		return level.AllowDebug()
   117  	case "info":
   118  		return level.AllowInfo()
   119  	case "warn":
   120  		return level.AllowWarn()
   121  	case "error":
   122  		return level.AllowError()
   123  	default:
   124  		return level.AllowAll()
   125  	}
   126  }