log.go
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 14 package log 15 16 import ( 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. 32 var setSyslogFormatter func(logger, string, string) error 33 34 // setEventlogFormatter is nil if the target OS does not support Eventlog (i.e., is not Windows). 35 var setEventlogFormatter func(logger, string, bool) error 36 37 func setJSONFormatter() { 38 origLogger.Formatter = &logrus.JSONFormatter{} 39 } 40 41 type loggerSettings struct { 42 level string 43 format string 44 } 45 46 func (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) 57 func 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. 70 type 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 97 type logger struct { 98 entry *logrus.Entry 99 } 100 101 func (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. 106 func (l logger) Debug(args ...interface{}) { 107 l.sourced().Debug(args...) 108 } 109 110 // Debug logs a message at level Debug on the standard logger. 111 func (l logger) Debugln(args ...interface{}) { 112 l.sourced().Debugln(args...) 113 } 114 115 // Debugf logs a message at level Debug on the standard logger. 116 func (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. 121 func (l logger) Info(args ...interface{}) { 122 l.sourced().Info(args...) 123 } 124 125 // Info logs a message at level Info on the standard logger. 126 func (l logger) Infoln(args ...interface{}) { 127 l.sourced().Infoln(args...) 128 } 129 130 // Infof logs a message at level Info on the standard logger. 131 func (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. 136 func (l logger) Warn(args ...interface{}) { 137 l.sourced().Warn(args...) 138 } 139 140 // Warn logs a message at level Warn on the standard logger. 141 func (l logger) Warnln(args ...interface{}) { 142 l.sourced().Warnln(args...) 143 } 144 145 // Warnf logs a message at level Warn on the standard logger. 146 func (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. 151 func (l logger) Error(args ...interface{}) { 152 l.sourced().Error(args...) 153 } 154 155 // Error logs a message at level Error on the standard logger. 156 func (l logger) Errorln(args ...interface{}) { 157 l.sourced().Errorln(args...) 158 } 159 160 // Errorf logs a message at level Error on the standard logger. 161 func (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. 166 func (l logger) Fatal(args ...interface{}) { 167 l.sourced().Fatal(args...) 168 } 169 170 // Fatal logs a message at level Fatal on the standard logger. 171 func (l logger) Fatalln(args ...interface{}) { 172 l.sourced().Fatalln(args...) 173 } 174 175 // Fatalf logs a message at level Fatal on the standard logger. 176 func (l logger) Fatalf(format string, args ...interface{}) { 177 l.sourced().Fatalf(format, args...) 178 } 179 180 func (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 190 func (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. 234 func (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 246 var origLogger = logrus.New() 247 var baseLogger = logger{entry: logrus.NewEntry(origLogger)} 248 249 // Base returns the default Logger logging to 250 func Base() Logger { 251 return baseLogger 252 } 253 254 // NewLogger returns a new Logger logging to out. 255 func 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. 262 func 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. 269 func 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. 274 func Debug(args ...interface{}) { 275 baseLogger.sourced().Debug(args...) 276 } 277 278 // Debugln logs a message at level Debug on the standard logger. 279 func Debugln(args ...interface{}) { 280 baseLogger.sourced().Debugln(args...) 281 } 282 283 // Debugf logs a message at level Debug on the standard logger. 284 func 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. 289 func Info(args ...interface{}) { 290 baseLogger.sourced().Info(args...) 291 } 292 293 // Infoln logs a message at level Info on the standard logger. 294 func Infoln(args ...interface{}) { 295 baseLogger.sourced().Infoln(args...) 296 } 297 298 // Infof logs a message at level Info on the standard logger. 299 func 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. 304 func Warn(args ...interface{}) { 305 baseLogger.sourced().Warn(args...) 306 } 307 308 // Warnln logs a message at level Warn on the standard logger. 309 func Warnln(args ...interface{}) { 310 baseLogger.sourced().Warnln(args...) 311 } 312 313 // Warnf logs a message at level Warn on the standard logger. 314 func 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. 319 func Error(args ...interface{}) { 320 baseLogger.sourced().Error(args...) 321 } 322 323 // Errorln logs a message at level Error on the standard logger. 324 func Errorln(args ...interface{}) { 325 baseLogger.sourced().Errorln(args...) 326 } 327 328 // Errorf logs a message at level Error on the standard logger. 329 func 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. 334 func Fatal(args ...interface{}) { 335 baseLogger.sourced().Fatal(args...) 336 } 337 338 // Fatalln logs a message at level Fatal on the standard logger. 339 func Fatalln(args ...interface{}) { 340 baseLogger.sourced().Fatalln(args...) 341 } 342 343 // Fatalf logs a message at level Fatal on the standard logger. 344 func Fatalf(format string, args ...interface{}) { 345 baseLogger.sourced().Fatalf(format, args...) 346 } 347 348 // AddHook adds hook to Prometheus' original logger. 349 func AddHook(hook logrus.Hook) { 350 origLogger.Hooks.Add(hook) 351 } 352 353 type errorLogWriter struct{} 354 355 func (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. 362 func NewErrorLogger() *log.Logger { 363 return log.New(&errorLogWriter{}, "", 0) 364 }