github.com/yankunsam/loki/v2@v2.6.3-0.20220817130409-389df5235c27/pkg/util/log/log.go (about)

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