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 }