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 }