1// Copyright 2015 The Prometheus Authors 2// Licensed under the Apache License, Version 2.0 (the "License"); 3// you may not use this file except in compliance with the License. 4// You may obtain a copy of the License at 5// 6// http://www.apache.org/licenses/LICENSE-2.0 7// 8// Unless required by applicable law or agreed to in writing, software 9// distributed under the License is distributed on an "AS IS" BASIS, 10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11// See the License for the specific language governing permissions and 12// limitations under the License. 13 14package log 15 16import ( 17 "fmt" 18 "io" 19 "io/ioutil" 20 "log" 21 "net/url" 22 "os" 23 "runtime" 24 "strconv" 25 "strings" 26 27 "github.com/sirupsen/logrus" 28 "gopkg.in/alecthomas/kingpin.v2" 29) 30 31// setSyslogFormatter is nil if the target architecture does not support syslog. 32var setSyslogFormatter func(logger, string, string) error 33 34// setEventlogFormatter is nil if the target OS does not support Eventlog (i.e., is not Windows). 35var setEventlogFormatter func(logger, string, bool) error 36 37func setJSONFormatter() { 38 origLogger.Formatter = &logrus.JSONFormatter{} 39} 40 41type loggerSettings struct { 42 level string 43 format string 44} 45 46func (s *loggerSettings) apply(ctx *kingpin.ParseContext) error { 47 err := baseLogger.SetLevel(s.level) 48 if err != nil { 49 return err 50 } 51 err = baseLogger.SetFormat(s.format) 52 return err 53} 54 55// AddFlags adds the flags used by this package to the Kingpin application. 56// To use the default Kingpin application, call AddFlags(kingpin.CommandLine) 57func AddFlags(a *kingpin.Application) { 58 s := loggerSettings{} 59 a.Flag("log.level", "Only log messages with the given severity or above. Valid levels: [debug, info, warn, error, fatal]"). 60 Default(origLogger.Level.String()). 61 StringVar(&s.level) 62 defaultFormat := url.URL{Scheme: "logger", Opaque: "stderr"} 63 a.Flag("log.format", `Set the log target and format. Example: "logger:syslog?appname=bob&local=7" or "logger:stdout?json=true"`). 64 Default(defaultFormat.String()). 65 StringVar(&s.format) 66 a.Action(s.apply) 67} 68 69// Logger is the interface for loggers used in the Prometheus components. 70type Logger interface { 71 Debug(...interface{}) 72 Debugln(...interface{}) 73 Debugf(string, ...interface{}) 74 75 Info(...interface{}) 76 Infoln(...interface{}) 77 Infof(string, ...interface{}) 78 79 Warn(...interface{}) 80 Warnln(...interface{}) 81 Warnf(string, ...interface{}) 82 83 Error(...interface{}) 84 Errorln(...interface{}) 85 Errorf(string, ...interface{}) 86 87 Fatal(...interface{}) 88 Fatalln(...interface{}) 89 Fatalf(string, ...interface{}) 90 91 With(key string, value interface{}) Logger 92 93 SetFormat(string) error 94 SetLevel(string) error 95} 96 97type logger struct { 98 entry *logrus.Entry 99} 100 101func (l logger) With(key string, value interface{}) Logger { 102 return logger{l.entry.WithField(key, value)} 103} 104 105// Debug logs a message at level Debug on the standard logger. 106func (l logger) Debug(args ...interface{}) { 107 l.sourced().Debug(args...) 108} 109 110// Debug logs a message at level Debug on the standard logger. 111func (l logger) Debugln(args ...interface{}) { 112 l.sourced().Debugln(args...) 113} 114 115// Debugf logs a message at level Debug on the standard logger. 116func (l logger) Debugf(format string, args ...interface{}) { 117 l.sourced().Debugf(format, args...) 118} 119 120// Info logs a message at level Info on the standard logger. 121func (l logger) Info(args ...interface{}) { 122 l.sourced().Info(args...) 123} 124 125// Info logs a message at level Info on the standard logger. 126func (l logger) Infoln(args ...interface{}) { 127 l.sourced().Infoln(args...) 128} 129 130// Infof logs a message at level Info on the standard logger. 131func (l logger) Infof(format string, args ...interface{}) { 132 l.sourced().Infof(format, args...) 133} 134 135// Warn logs a message at level Warn on the standard logger. 136func (l logger) Warn(args ...interface{}) { 137 l.sourced().Warn(args...) 138} 139 140// Warn logs a message at level Warn on the standard logger. 141func (l logger) Warnln(args ...interface{}) { 142 l.sourced().Warnln(args...) 143} 144 145// Warnf logs a message at level Warn on the standard logger. 146func (l logger) Warnf(format string, args ...interface{}) { 147 l.sourced().Warnf(format, args...) 148} 149 150// Error logs a message at level Error on the standard logger. 151func (l logger) Error(args ...interface{}) { 152 l.sourced().Error(args...) 153} 154 155// Error logs a message at level Error on the standard logger. 156func (l logger) Errorln(args ...interface{}) { 157 l.sourced().Errorln(args...) 158} 159 160// Errorf logs a message at level Error on the standard logger. 161func (l logger) Errorf(format string, args ...interface{}) { 162 l.sourced().Errorf(format, args...) 163} 164 165// Fatal logs a message at level Fatal on the standard logger. 166func (l logger) Fatal(args ...interface{}) { 167 l.sourced().Fatal(args...) 168} 169 170// Fatal logs a message at level Fatal on the standard logger. 171func (l logger) Fatalln(args ...interface{}) { 172 l.sourced().Fatalln(args...) 173} 174 175// Fatalf logs a message at level Fatal on the standard logger. 176func (l logger) Fatalf(format string, args ...interface{}) { 177 l.sourced().Fatalf(format, args...) 178} 179 180func (l logger) SetLevel(level string) error { 181 lvl, err := logrus.ParseLevel(level) 182 if err != nil { 183 return err 184 } 185 186 l.entry.Logger.Level = lvl 187 return nil 188} 189 190func (l logger) SetFormat(format string) error { 191 u, err := url.Parse(format) 192 if err != nil { 193 return err 194 } 195 if u.Scheme != "logger" { 196 return fmt.Errorf("invalid scheme %s", u.Scheme) 197 } 198 jsonq := u.Query().Get("json") 199 if jsonq == "true" { 200 setJSONFormatter() 201 } 202 203 switch u.Opaque { 204 case "syslog": 205 if setSyslogFormatter == nil { 206 return fmt.Errorf("system does not support syslog") 207 } 208 appname := u.Query().Get("appname") 209 facility := u.Query().Get("local") 210 return setSyslogFormatter(l, appname, facility) 211 case "eventlog": 212 if setEventlogFormatter == nil { 213 return fmt.Errorf("system does not support eventlog") 214 } 215 name := u.Query().Get("name") 216 debugAsInfo := false 217 debugAsInfoRaw := u.Query().Get("debugAsInfo") 218 if parsedDebugAsInfo, err := strconv.ParseBool(debugAsInfoRaw); err == nil { 219 debugAsInfo = parsedDebugAsInfo 220 } 221 return setEventlogFormatter(l, name, debugAsInfo) 222 case "stdout": 223 l.entry.Logger.Out = os.Stdout 224 case "stderr": 225 l.entry.Logger.Out = os.Stderr 226 default: 227 return fmt.Errorf("unsupported logger %q", u.Opaque) 228 } 229 return nil 230} 231 232// sourced adds a source field to the logger that contains 233// the file name and line where the logging happened. 234func (l logger) sourced() *logrus.Entry { 235 _, file, line, ok := runtime.Caller(2) 236 if !ok { 237 file = "<???>" 238 line = 1 239 } else { 240 slash := strings.LastIndex(file, "/") 241 file = file[slash+1:] 242 } 243 return l.entry.WithField("source", fmt.Sprintf("%s:%d", file, line)) 244} 245 246var origLogger = logrus.New() 247var baseLogger = logger{entry: logrus.NewEntry(origLogger)} 248 249// Base returns the default Logger logging to 250func Base() Logger { 251 return baseLogger 252} 253 254// NewLogger returns a new Logger logging to out. 255func NewLogger(w io.Writer) Logger { 256 l := logrus.New() 257 l.Out = w 258 return logger{entry: logrus.NewEntry(l)} 259} 260 261// NewNopLogger returns a logger that discards all log messages. 262func NewNopLogger() Logger { 263 l := logrus.New() 264 l.Out = ioutil.Discard 265 return logger{entry: logrus.NewEntry(l)} 266} 267 268// With adds a field to the logger. 269func With(key string, value interface{}) Logger { 270 return baseLogger.With(key, value) 271} 272 273// Debug logs a message at level Debug on the standard logger. 274func Debug(args ...interface{}) { 275 baseLogger.sourced().Debug(args...) 276} 277 278// Debugln logs a message at level Debug on the standard logger. 279func Debugln(args ...interface{}) { 280 baseLogger.sourced().Debugln(args...) 281} 282 283// Debugf logs a message at level Debug on the standard logger. 284func Debugf(format string, args ...interface{}) { 285 baseLogger.sourced().Debugf(format, args...) 286} 287 288// Info logs a message at level Info on the standard logger. 289func Info(args ...interface{}) { 290 baseLogger.sourced().Info(args...) 291} 292 293// Infoln logs a message at level Info on the standard logger. 294func Infoln(args ...interface{}) { 295 baseLogger.sourced().Infoln(args...) 296} 297 298// Infof logs a message at level Info on the standard logger. 299func Infof(format string, args ...interface{}) { 300 baseLogger.sourced().Infof(format, args...) 301} 302 303// Warn logs a message at level Warn on the standard logger. 304func Warn(args ...interface{}) { 305 baseLogger.sourced().Warn(args...) 306} 307 308// Warnln logs a message at level Warn on the standard logger. 309func Warnln(args ...interface{}) { 310 baseLogger.sourced().Warnln(args...) 311} 312 313// Warnf logs a message at level Warn on the standard logger. 314func Warnf(format string, args ...interface{}) { 315 baseLogger.sourced().Warnf(format, args...) 316} 317 318// Error logs a message at level Error on the standard logger. 319func Error(args ...interface{}) { 320 baseLogger.sourced().Error(args...) 321} 322 323// Errorln logs a message at level Error on the standard logger. 324func Errorln(args ...interface{}) { 325 baseLogger.sourced().Errorln(args...) 326} 327 328// Errorf logs a message at level Error on the standard logger. 329func Errorf(format string, args ...interface{}) { 330 baseLogger.sourced().Errorf(format, args...) 331} 332 333// Fatal logs a message at level Fatal on the standard logger. 334func Fatal(args ...interface{}) { 335 baseLogger.sourced().Fatal(args...) 336} 337 338// Fatalln logs a message at level Fatal on the standard logger. 339func Fatalln(args ...interface{}) { 340 baseLogger.sourced().Fatalln(args...) 341} 342 343// Fatalf logs a message at level Fatal on the standard logger. 344func Fatalf(format string, args ...interface{}) { 345 baseLogger.sourced().Fatalf(format, args...) 346} 347 348// AddHook adds hook to Prometheus' original logger. 349func AddHook(hook logrus.Hook) { 350 origLogger.Hooks.Add(hook) 351} 352 353type errorLogWriter struct{} 354 355func (errorLogWriter) Write(b []byte) (int, error) { 356 baseLogger.sourced().Error(string(b)) 357 return len(b), nil 358} 359 360// NewErrorLogger returns a log.Logger that is meant to be used 361// in the ErrorLog field of an http.Server to log HTTP server errors. 362func NewErrorLogger() *log.Logger { 363 return log.New(&errorLogWriter{}, "", 0) 364} 365